debugging and cleanup

This commit is contained in:
Christien Rioux 2025-03-13 21:34:12 -04:00
parent 604ec9cfdd
commit d460a0388c
69 changed files with 2306 additions and 790 deletions

View file

@ -3,7 +3,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'scale_scheme.dart';
import 'scale_theme/scale_scheme.dart';
ChatTheme makeChatTheme(
ScaleScheme scale, ScaleConfig scaleConfig, TextTheme textTheme) =>

View file

@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'radix_generator.dart';
import 'scale_color.dart';
import 'scale_input_decorator_theme.dart';
import 'scale_scheme.dart';
import 'scale_theme.dart';
import 'scale_theme/scale_color.dart';
import 'scale_theme/scale_input_decorator_theme.dart';
import 'scale_theme/scale_scheme.dart';
import 'scale_theme/scale_theme.dart';
ScaleColor _contrastScaleColor(
{required Brightness brightness,

View file

@ -1,7 +1,4 @@
export 'chat_theme.dart';
export 'radix_generator.dart';
export 'scale_color.dart';
export 'scale_scheme.dart';
export 'scale_theme.dart';
export 'slider_tile.dart';
export 'scale_theme/scale_theme.dart';
export 'theme_preference.dart';

View file

@ -1,13 +1,14 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:radix_colors/radix_colors.dart';
import '../../tools/tools.dart';
import 'scale_color.dart';
import 'scale_input_decorator_theme.dart';
import 'scale_scheme.dart';
import 'scale_theme.dart';
import 'scale_theme/scale_color.dart';
import 'scale_theme/scale_input_decorator_theme.dart';
import 'scale_theme/scale_scheme.dart';
import 'scale_theme/scale_theme.dart';
enum RadixThemeColor {
scarlet, // red + violet + tomato
@ -571,7 +572,11 @@ RadixScheme _radixScheme(Brightness brightness, RadixThemeColor themeColor) {
TextTheme makeRadixTextTheme(Brightness brightness) {
late final TextTheme textTheme;
if (Platform.isIOS) {
if (kIsWeb) {
textTheme = (brightness == Brightness.light)
? Typography.blackHelsinki
: Typography.whiteHelsinki;
} else if (Platform.isIOS) {
textTheme = (brightness == Brightness.light)
? Typography.blackCupertino
: Typography.whiteCupertino;

View file

@ -0,0 +1,93 @@
import 'package:animated_custom_dropdown/custom_dropdown.dart';
import 'package:flutter/material.dart';
import 'scale_scheme.dart';
import 'scale_theme.dart';
class ScaleCustomDropdownTheme {
ScaleCustomDropdownTheme({
required this.decoration,
required this.closedHeaderPadding,
required this.expandedHeaderPadding,
required this.itemsListPadding,
required this.listItemPadding,
required this.disabledDecoration,
required this.textStyle,
});
final CustomDropdownDecoration decoration;
final EdgeInsets closedHeaderPadding;
final EdgeInsets expandedHeaderPadding;
final EdgeInsets itemsListPadding;
final EdgeInsets listItemPadding;
final CustomDropdownDisabledDecoration disabledDecoration;
final TextStyle textStyle;
}
extension ScaleCustomDropdownThemeExt on ScaleTheme {
ScaleCustomDropdownTheme customDropdownTheme() {
final scale = scheme.primaryScale;
final borderColor = scale.borderText;
final fillColor = scale.subtleBorder;
// final backgroundColor = config.useVisualIndicators && !selected
// ? tileColor.borderText
// : borderColor;
// final textColor = config.useVisualIndicators && !selected
// ? borderColor
// : tileColor.borderText;
// final largeTextStyle = textTheme.labelMedium!.copyWith(color: textColor);
// final smallTextStyle = textTheme.labelSmall!.copyWith(color: textColor);
final border = Border.fromBorderSide(config.useVisualIndicators
? BorderSide(width: 2, color: borderColor, strokeAlign: 0)
: BorderSide.none);
final borderRadius = BorderRadius.circular(8 * config.borderRadiusScale);
final decoration = CustomDropdownDecoration(
closedFillColor: fillColor,
expandedFillColor: fillColor,
closedShadow: [],
expandedShadow: [],
closedSuffixIcon: Icon(Icons.arrow_drop_down, color: borderColor),
expandedSuffixIcon: Icon(Icons.arrow_drop_up, color: borderColor),
prefixIcon: null,
closedBorder: border,
closedBorderRadius: borderRadius,
closedErrorBorder: null,
closedErrorBorderRadius: null,
expandedBorder: border,
expandedBorderRadius: borderRadius,
hintStyle: null,
headerStyle: null,
noResultFoundStyle: null,
errorStyle: null,
listItemStyle: null,
overlayScrollbarDecoration: null,
searchFieldDecoration: null,
listItemDecoration: null,
);
final disabledDecoration = CustomDropdownDisabledDecoration(
fillColor: null,
shadow: null,
suffixIcon: null,
prefixIcon: null,
border: null,
borderRadius: null,
headerStyle: null,
hintStyle: null,
);
return ScaleCustomDropdownTheme(
textStyle: textTheme.labelSmall!.copyWith(color: borderColor),
decoration: decoration,
closedHeaderPadding: const EdgeInsets.all(4),
expandedHeaderPadding: const EdgeInsets.all(4),
itemsListPadding: const EdgeInsets.all(4),
listItemPadding: const EdgeInsets.all(4),
disabledDecoration: disabledDecoration,
);
}
}

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'scale_scheme.dart';
import 'scale_theme.dart';
class ScaleInputDecoratorTheme extends InputDecorationTheme {
ScaleInputDecoratorTheme(
@ -25,41 +26,41 @@ class ScaleInputDecoratorTheme extends InputDecorationTheme {
final TextTheme _textTheme;
@override
TextStyle? get hintStyle => MaterialStateTextStyle.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
TextStyle? get hintStyle => WidgetStateTextStyle.resolveWith((states) {
if (states.contains(WidgetState.disabled)) {
return TextStyle(color: _scaleScheme.grayScale.border);
}
return TextStyle(color: _scaleScheme.primaryScale.border);
});
@override
Color? get fillColor => MaterialStateColor.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
return _scaleScheme.grayScale.primary.withOpacity(0.04);
Color? get fillColor => WidgetStateColor.resolveWith((states) {
if (states.contains(WidgetState.disabled)) {
return _scaleScheme.grayScale.primary.withAlpha(10);
}
return _scaleScheme.primaryScale.primary.withOpacity(0.04);
return _scaleScheme.primaryScale.primary.withAlpha(10);
});
@override
BorderSide? get activeIndicatorBorder =>
MaterialStateBorderSide.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
WidgetStateBorderSide.resolveWith((states) {
if (states.contains(WidgetState.disabled)) {
return BorderSide(
color: _scaleScheme.grayScale.border.withAlpha(0x7F));
color: _scaleScheme.grayScale.border.withAlpha(127));
}
if (states.contains(MaterialState.error)) {
if (states.contains(MaterialState.hovered)) {
if (states.contains(WidgetState.error)) {
if (states.contains(WidgetState.hovered)) {
return BorderSide(color: _scaleScheme.errorScale.hoverBorder);
}
if (states.contains(MaterialState.focused)) {
if (states.contains(WidgetState.focused)) {
return BorderSide(color: _scaleScheme.errorScale.border, width: 2);
}
return BorderSide(color: _scaleScheme.errorScale.subtleBorder);
}
if (states.contains(MaterialState.hovered)) {
if (states.contains(WidgetState.hovered)) {
return BorderSide(color: _scaleScheme.secondaryScale.hoverBorder);
}
if (states.contains(MaterialState.focused)) {
if (states.contains(WidgetState.focused)) {
return BorderSide(
color: _scaleScheme.secondaryScale.border, width: 2);
}
@ -67,25 +68,24 @@ class ScaleInputDecoratorTheme extends InputDecorationTheme {
});
@override
BorderSide? get outlineBorder =>
MaterialStateBorderSide.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
BorderSide? get outlineBorder => WidgetStateBorderSide.resolveWith((states) {
if (states.contains(WidgetState.disabled)) {
return BorderSide(
color: _scaleScheme.grayScale.border.withAlpha(0x7F));
color: _scaleScheme.grayScale.border.withAlpha(127));
}
if (states.contains(MaterialState.error)) {
if (states.contains(MaterialState.hovered)) {
if (states.contains(WidgetState.error)) {
if (states.contains(WidgetState.hovered)) {
return BorderSide(color: _scaleScheme.errorScale.hoverBorder);
}
if (states.contains(MaterialState.focused)) {
if (states.contains(WidgetState.focused)) {
return BorderSide(color: _scaleScheme.errorScale.border, width: 2);
}
return BorderSide(color: _scaleScheme.errorScale.subtleBorder);
}
if (states.contains(MaterialState.hovered)) {
if (states.contains(WidgetState.hovered)) {
return BorderSide(color: _scaleScheme.primaryScale.hoverBorder);
}
if (states.contains(MaterialState.focused)) {
if (states.contains(WidgetState.focused)) {
return BorderSide(color: _scaleScheme.primaryScale.border, width: 2);
}
return BorderSide(color: _scaleScheme.primaryScale.subtleBorder);
@ -95,51 +95,51 @@ class ScaleInputDecoratorTheme extends InputDecorationTheme {
Color? get iconColor => _scaleScheme.primaryScale.primary;
@override
Color? get prefixIconColor => MaterialStateColor.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
return _scaleScheme.primaryScale.primary.withAlpha(0x3F);
Color? get prefixIconColor => WidgetStateColor.resolveWith((states) {
if (states.contains(WidgetState.disabled)) {
return _scaleScheme.primaryScale.primary.withAlpha(127);
}
if (states.contains(MaterialState.error)) {
if (states.contains(WidgetState.error)) {
return _scaleScheme.errorScale.primary;
}
return _scaleScheme.primaryScale.primary;
});
@override
Color? get suffixIconColor => MaterialStateColor.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
return _scaleScheme.primaryScale.primary.withAlpha(0x3F);
Color? get suffixIconColor => WidgetStateColor.resolveWith((states) {
if (states.contains(WidgetState.disabled)) {
return _scaleScheme.primaryScale.primary.withAlpha(127);
}
if (states.contains(MaterialState.error)) {
if (states.contains(WidgetState.error)) {
return _scaleScheme.errorScale.primary;
}
return _scaleScheme.primaryScale.primary;
});
@override
TextStyle? get labelStyle => MaterialStateTextStyle.resolveWith((states) {
TextStyle? get labelStyle => WidgetStateTextStyle.resolveWith((states) {
final textStyle = _textTheme.bodyLarge ?? const TextStyle();
if (states.contains(MaterialState.disabled)) {
if (states.contains(WidgetState.disabled)) {
return textStyle.copyWith(
color: _scaleScheme.grayScale.border.withAlpha(0x7F));
color: _scaleScheme.grayScale.border.withAlpha(127));
}
if (states.contains(MaterialState.error)) {
if (states.contains(MaterialState.hovered)) {
if (states.contains(WidgetState.error)) {
if (states.contains(WidgetState.hovered)) {
return textStyle.copyWith(
color: _scaleScheme.errorScale.hoverBorder);
}
if (states.contains(MaterialState.focused)) {
if (states.contains(WidgetState.focused)) {
return textStyle.copyWith(
color: _scaleScheme.errorScale.hoverBorder);
}
return textStyle.copyWith(
color: _scaleScheme.errorScale.subtleBorder);
}
if (states.contains(MaterialState.hovered)) {
if (states.contains(WidgetState.hovered)) {
return textStyle.copyWith(
color: _scaleScheme.primaryScale.hoverBorder);
}
if (states.contains(MaterialState.focused)) {
if (states.contains(WidgetState.focused)) {
return textStyle.copyWith(
color: _scaleScheme.primaryScale.hoverBorder);
}
@ -150,19 +150,24 @@ class ScaleInputDecoratorTheme extends InputDecorationTheme {
TextStyle? get floatingLabelStyle => labelStyle;
@override
TextStyle? get helperStyle => MaterialStateTextStyle.resolveWith((states) {
TextStyle? get helperStyle => WidgetStateTextStyle.resolveWith((states) {
final textStyle = _textTheme.bodySmall ?? const TextStyle();
if (states.contains(MaterialState.disabled)) {
if (states.contains(WidgetState.disabled)) {
return textStyle.copyWith(
color: _scaleScheme.grayScale.border.withAlpha(0x7F));
color: _scaleScheme.grayScale.border.withAlpha(127));
}
return textStyle.copyWith(
color: _scaleScheme.secondaryScale.border.withAlpha(0x7F));
color: _scaleScheme.secondaryScale.border.withAlpha(127));
});
@override
TextStyle? get errorStyle => MaterialStateTextStyle.resolveWith((states) {
TextStyle? get errorStyle => WidgetStateTextStyle.resolveWith((states) {
final textStyle = _textTheme.bodySmall ?? const TextStyle();
return textStyle.copyWith(color: _scaleScheme.errorScale.primary);
});
}
extension ScaleInputDecoratorThemeExt on ScaleTheme {
ScaleInputDecoratorTheme inputDecoratorTheme() =>
ScaleInputDecoratorTheme(scheme, config, textTheme);
}

View file

@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'scale_scheme.dart';
export 'scale_color.dart';
export 'scale_input_decorator_theme.dart';
export 'scale_scheme.dart';
export 'scale_tile_theme.dart';
export 'scale_toast_theme.dart';
class ScaleTheme extends ThemeExtension<ScaleTheme> {
ScaleTheme({
required this.textTheme,
required this.scheme,
required this.config,
});
final TextTheme textTheme;
final ScaleScheme scheme;
final ScaleConfig config;
@override
ScaleTheme copyWith({
TextTheme? textTheme,
ScaleScheme? scheme,
ScaleConfig? config,
}) =>
ScaleTheme(
textTheme: textTheme ?? this.textTheme,
scheme: scheme ?? this.scheme,
config: config ?? this.config,
);
@override
ScaleTheme lerp(ScaleTheme? other, double t) {
if (other is! ScaleTheme) {
return this;
}
return ScaleTheme(
textTheme: TextTheme.lerp(textTheme, other.textTheme, t),
scheme: scheme.lerp(other.scheme, t),
config: config.lerp(other.config, t));
}
}

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'scale_scheme.dart';
import 'scale_theme.dart';
class ScaleTileTheme {
ScaleTileTheme(
@ -19,40 +20,7 @@ class ScaleTileTheme {
final TextStyle smallTextStyle;
}
class ScaleTheme extends ThemeExtension<ScaleTheme> {
ScaleTheme({
required this.textTheme,
required this.scheme,
required this.config,
});
final TextTheme textTheme;
final ScaleScheme scheme;
final ScaleConfig config;
@override
ScaleTheme copyWith({
TextTheme? textTheme,
ScaleScheme? scheme,
ScaleConfig? config,
}) =>
ScaleTheme(
textTheme: textTheme ?? this.textTheme,
scheme: scheme ?? this.scheme,
config: config ?? this.config,
);
@override
ScaleTheme lerp(ScaleTheme? other, double t) {
if (other is! ScaleTheme) {
return this;
}
return ScaleTheme(
textTheme: TextTheme.lerp(textTheme, other.textTheme, t),
scheme: scheme.lerp(other.scheme, t),
config: config.lerp(other.config, t));
}
extension ScaleTileThemeExt on ScaleTheme {
ScaleTileTheme tileTheme(
{bool disabled = false,
bool selected = false,

View file

@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'scale_scheme.dart';
import 'scale_theme.dart';
enum ScaleToastKind {
info,
error,
}
class ScaleToastTheme {
ScaleToastTheme(
{required this.primaryColor,
required this.backgroundColor,
required this.foregroundColor,
required this.borderSide,
required this.borderRadius,
required this.padding,
required this.icon,
required this.titleTextStyle,
required this.descriptionTextStyle});
final Color primaryColor;
final Color backgroundColor;
final Color foregroundColor;
final BorderSide? borderSide;
final BorderRadiusGeometry borderRadius;
final EdgeInsetsGeometry padding;
final Icon icon;
final TextStyle titleTextStyle;
final TextStyle descriptionTextStyle;
}
extension ScaleToastThemeExt on ScaleTheme {
ScaleToastTheme toastTheme(ScaleToastKind kind) {
final toastScaleColor = scheme.scale(ScaleKind.tertiary);
Icon icon;
switch (kind) {
case ScaleToastKind.info:
icon = const Icon(Icons.info, size: 32);
case ScaleToastKind.error:
icon = const Icon(Icons.dangerous, size: 32);
}
final primaryColor = toastScaleColor.calloutText;
final borderColor = toastScaleColor.border;
final backgroundColor = config.useVisualIndicators
? toastScaleColor.calloutText
: toastScaleColor.calloutBackground;
final textColor = config.useVisualIndicators
? toastScaleColor.calloutBackground
: toastScaleColor.calloutText;
final titleColor = config.useVisualIndicators
? toastScaleColor.calloutBackground
: toastScaleColor.calloutText;
return ScaleToastTheme(
primaryColor: primaryColor,
backgroundColor: backgroundColor,
foregroundColor: textColor,
borderSide: (config.useVisualIndicators || config.preferBorders)
? BorderSide(color: borderColor, width: 2)
: const BorderSide(color: Colors.transparent, width: 0),
borderRadius: BorderRadius.circular(12 * config.borderRadiusScale),
padding: const EdgeInsets.all(8),
icon: icon,
titleTextStyle: textTheme.labelMedium!.copyWith(color: titleColor),
descriptionTextStyle:
textTheme.labelMedium!.copyWith(color: textColor));
}
}

View file

@ -5,7 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import '../views/widget_helpers.dart';
import 'contrast_generator.dart';
import 'radix_generator.dart';
import 'scale_scheme.dart';
import 'scale_theme/scale_scheme.dart';
part 'theme_preference.freezed.dart';
part 'theme_preference.g.dart';

View file

@ -25,8 +25,12 @@ mixin _$ThemePreferences {
ColorPreference get colorPreference => throw _privateConstructorUsedError;
double get displayScale => throw _privateConstructorUsedError;
/// Serializes this ThemePreferences to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
/// Create a copy of ThemePreferences
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ThemePreferencesCopyWith<ThemePreferences> get copyWith =>
throw _privateConstructorUsedError;
}
@ -53,6 +57,8 @@ class _$ThemePreferencesCopyWithImpl<$Res, $Val extends ThemePreferences>
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ThemePreferences
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
@ -99,6 +105,8 @@ class __$$ThemePreferencesImplCopyWithImpl<$Res>
$Res Function(_$ThemePreferencesImpl) _then)
: super(_value, _then);
/// Create a copy of ThemePreferences
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
@ -162,12 +170,14 @@ class _$ThemePreferencesImpl implements _ThemePreferences {
other.displayScale == displayScale));
}
@JsonKey(ignore: true)
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType, brightnessPreference, colorPreference, displayScale);
@JsonKey(ignore: true)
/// Create a copy of ThemePreferences
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ThemePreferencesImplCopyWith<_$ThemePreferencesImpl> get copyWith =>
@ -197,8 +207,11 @@ abstract class _ThemePreferences implements ThemePreferences {
ColorPreference get colorPreference;
@override
double get displayScale;
/// Create a copy of ThemePreferences
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(ignore: true)
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ThemePreferencesImplCopyWith<_$ThemePreferencesImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View file

@ -40,7 +40,9 @@ class OptionBox extends StatelessWidget {
ElevatedButton(
onPressed: _onClick,
child: Row(mainAxisSize: MainAxisSize.min, children: [
Icon(_buttonIcon, size: 24).paddingLTRB(0, 8, 8, 8),
Icon(_buttonIcon,
size: 24, color: scale.primaryScale.appText)
.paddingLTRB(0, 8, 8, 8),
Text(textAlign: TextAlign.center, _buttonText)
])).paddingLTRB(0, 12, 0, 0).toCenter()
]).paddingAll(12))

View file

@ -14,17 +14,22 @@ class StyledScaffold extends StatelessWidget {
final enableBorder = !isMobileSize(context);
final scaffold = clipBorder(
clipEnabled: enableBorder,
borderEnabled: scaleConfig.useVisualIndicators,
borderRadius: 16 * scaleConfig.borderRadiusScale,
borderColor: scale.primaryScale.border,
child: Scaffold(appBar: appBar, body: body, key: key))
.paddingAll(enableBorder ? 32 : 0);
var scaffold = clipBorder(
clipEnabled: enableBorder,
borderEnabled: scaleConfig.useVisualIndicators,
borderRadius: 16 * scaleConfig.borderRadiusScale,
borderColor: scale.primaryScale.border,
child: Scaffold(appBar: appBar, body: body, key: key));
if (!scaleConfig.useVisualIndicators) {
scaffold = scaffold.withShadow(
offset: const Offset(0, 16),
shadowColor: scale.primaryScale.primary.withAlpha(0x3F).darken(60));
}
return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: scaffold);
child: scaffold.paddingAll(enableBorder ? 32 : 0));
}
////////////////////////////////////////////////////////////////////////////

View file

@ -8,6 +8,7 @@ export 'pop_control.dart';
export 'recovery_key_widget.dart';
export 'responsive.dart';
export 'scanner_error_widget.dart';
export 'slider_tile.dart';
export 'styled_alert.dart';
export 'styled_dialog.dart';
export 'styled_scaffold.dart';

View file

@ -500,24 +500,26 @@ const grayColorFilter = ColorFilter.matrix(<double>[
0,
]);
Widget clipBorder({
Container clipBorder({
required bool clipEnabled,
required bool borderEnabled,
required double borderRadius,
required Color borderColor,
required Widget child,
}) =>
ClipRRect(
borderRadius: clipEnabled
? BorderRadius.circular(borderRadius)
: BorderRadius.zero,
child: DecoratedBox(
decoration: BoxDecoration(boxShadow: [
if (borderEnabled) BoxShadow(color: borderColor, spreadRadius: 2)
]),
child: ClipRRect(
// ignore: avoid_unnecessary_containers, use_decorated_box
Container(
decoration: ShapeDecoration(
color: borderColor,
shape: RoundedRectangleBorder(
borderRadius: clipEnabled
? BorderRadius.circular(borderRadius)
: BorderRadius.zero,
child: child,
)).paddingAll(clipEnabled && borderEnabled ? 2 : 0));
)),
child: ClipRRect(
clipBehavior: Clip.hardEdge,
borderRadius: clipEnabled
? BorderRadius.circular(borderRadius)
: BorderRadius.zero,
child: child)
.paddingAll(clipEnabled && borderEnabled ? 2 : 0));