Compare commits

...

2 Commits

Author SHA1 Message Date
8f5e3923d6
feat(ui)!: rework theme resolver mechanism + move theme extension implementations
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-27 16:55:10 +02:00
01269027f2
feat(ui): make components more coherent + docs 2023-04-27 16:54:16 +02:00
122 changed files with 4007 additions and 2300 deletions

View File

@ -99,6 +99,12 @@ If you need specific settings, or pass parameters to your component, call `copyW
) )
``` ```
## Default implementation
To use this package, you have to create your own implementation of the components. You can check out [Wyatt UI Kit](https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_ui_kit) package for an example.
But default theme extensions (used in all implementations as fallback for styles) are available in `lib/src/domain/theme_extensions` folder.
## Development ## Development
> Common to this, and Wyatt UI Kit packages. > Common to this, and Wyatt UI Kit packages.

View File

@ -37,38 +37,67 @@ abstract class ThemeResolver<Style extends ThemeStyle<Style>, Extension,
/// {@macro theme_resolver} /// {@macro theme_resolver}
const ThemeResolver(); const ThemeResolver();
/// Compute default value from Flutter Theme or with hardcoded values. /// Compute extension value from a given extension.
Style computeDefaultValue(
BuildContext context, {
Extra? extra,
});
/// Compute custom style from context.
Style? Function(BuildContext context, {Extra? extra}) get customStyleFn;
/// Compute extension value from custom component extension.
Style? computeExtensionValueFn( Style? computeExtensionValueFn(
BuildContext context, BuildContext context,
Extension? themeExtension, { Extension? themeExtension, {
Extra? extra, Extra? extra,
}); });
/// Return the default extension containing Flutter's default values and
/// hardcoded values.
Extension? getDefaultExtension(BuildContext context);
/// Compute default value from Flutter Theme or with hardcoded values.
///
/// If no default value is found, it will throw a [FlutterError].
Style computeDefaultValue(
BuildContext context, {
Extra? extra,
}) {
final extension = getDefaultExtension(context);
if (extension == null) {
throw FlutterError('No default extension found for $Extension\n'
'Please provide a default extension in your theme using '
'`wyatt_ui_components` default extensions kit.');
}
final style = computeExtensionValueFn(context, extension, extra: extra);
if (style == null) {
throw FlutterError(
'No default style found for $Style in $Extension${extra != null ? ' with $extra' : ''}',
);
}
return style;
}
/// Compute custom style from context.
Style? Function(BuildContext context, {Extra? extra}) get customStyleFn;
/// Choose most suitable style for a given context. /// Choose most suitable style for a given context.
Style negotiate(BuildContext context, {Extra? extra}) { Style negotiate(BuildContext context, {Extra? extra}) {
// 1) Custom style passed in constructor (cannot be null) // 1) Custom style passed in constructor (cannot be null)
final style = computeDefaultValue(context, extra: extra); final style = computeDefaultValue(context, extra: extra);
return ThemeHelper.getElement<Style, Style>( return ThemeHelper.getElement<Style, Style>(
[ [
// 1) Custom style passed in constructor // 3) Default
customStyleFn(context, extra: extra), style,
// -> then, try to find better style, and merge it with the default
// 2) Theme extension // 2) Theme extension
computeExtensionValueFn( computeExtensionValueFn(
context, context,
Theme.of(context).extension<Extension>(), Theme.of(context).extension<Extension>(),
extra: extra, extra: extra,
), ),
// 3) Default
style, // -> then, try to find better style, and merge it with the one above
// 1) Custom style passed in constructor
customStyleFn(context, extra: extra),
], ],
transform: (value) => value, transform: (value) => value,
combine: (value, element) => value?.mergeWith(element), combine: (value, element) => value?.mergeWith(element),

View File

@ -0,0 +1,17 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
export 'theme_extensions/theme_extensions.dart';

View File

@ -0,0 +1,20 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
export 'file_selection_button_theme_extension_default.dart';
export 'flat_button_theme_extension_default.dart';
export 'simple_icon_button_theme_extension_default.dart';
export 'symbol_button_theme_extension_default.dart';

View File

@ -0,0 +1,81 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
/// {@template file_selection_button_theme_extension}
/// Default file selection button theme extension using Flutter's
/// default theme and opinionated defaults.
/// {@endtemplate}
class FileSelectionButtonThemeExtensionDefault
extends FileSelectionButtonThemeExtension {
/// {@macro file_selection_button_theme_extension}
const FileSelectionButtonThemeExtensionDefault({
required super.disabledStyle,
required super.focusedStyle,
required super.hoveredStyle,
required super.normalStyle,
required super.tappedStyle,
required super.selectedStyle,
required super.invalidStyle,
});
/// Creates a [FileSelectionButtonThemeExtensionDefault] given a [ThemeData]
///
/// {@macro file_selection_button_theme_extension}
factory FileSelectionButtonThemeExtensionDefault.from(ThemeData theme) {
final style = FileSelectionButtonStyle(
titleStyle: theme.textTheme.labelLarge,
subtitleStyle: theme.textTheme.labelSmall,
radius: (theme.buttonTheme.shape is RoundedRectangleBorder)
? (theme.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null,
padding: const EdgeInsets.symmetric(horizontal: 10),
foregroundColors: MultiColor.single(theme.colorScheme.onPrimary),
backgroundColors: MultiColor.single(theme.colorScheme.primary),
);
return FileSelectionButtonThemeExtensionDefault(
normalStyle: style,
focusedStyle: style,
hoveredStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.92)),
),
tappedStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.92)),
),
selectedStyle: style,
disabledStyle: style.copyWith(
foregroundColors:
MultiColor.single(theme.colorScheme.onSurface.withOpacity(0.12)),
backgroundColors:
MultiColor.single(theme.colorScheme.onSurface.withOpacity(0.38)),
),
invalidStyle: style,
);
}
/// Creates a [FileSelectionButtonThemeExtensionDefault] from a dark theme
factory FileSelectionButtonThemeExtensionDefault.dark() =>
FileSelectionButtonThemeExtensionDefault.from(ThemeData.dark());
/// Creates a [FileSelectionButtonThemeExtensionDefault] from a light theme
factory FileSelectionButtonThemeExtensionDefault.light() =>
FileSelectionButtonThemeExtensionDefault.from(ThemeData.light());
}

View File

@ -0,0 +1,78 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
/// {@template flat_button_theme_extension_default}
/// Default flat button theme extension using Flutter's default values.
/// {@endtemplate}
class FlatButtonThemeExtensionDefault extends FlatButtonThemeExtension {
/// {@macro flat_button_theme_extension_default}
const FlatButtonThemeExtensionDefault({
required super.disabledStyle,
required super.focusedStyle,
required super.hoveredStyle,
required super.normalStyle,
required super.tappedStyle,
});
/// Creates a [FlatButtonThemeExtensionDefault] given a [ThemeData]
///
/// {@macro flat_button_theme_extension_default}
factory FlatButtonThemeExtensionDefault.from(ThemeData theme) {
final backgroundColor = MultiColor.single(theme.colorScheme.primary);
final foregroundColor = MultiColor.single(theme.colorScheme.onPrimary);
final style = FlatButtonStyle(
labelStyle:
theme.textTheme.labelLarge?.copyWith(color: foregroundColor.color),
radius: (theme.buttonTheme.shape is RoundedRectangleBorder)
? (theme.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null,
padding: theme.buttonTheme.padding,
foregroundColors: foregroundColor,
backgroundColors: backgroundColor,
);
return FlatButtonThemeExtensionDefault(
normalStyle: style,
focusedStyle: style,
hoveredStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.92)),
),
tappedStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.92)),
),
disabledStyle: style.copyWith(
foregroundColors:
MultiColor.single(theme.colorScheme.onSurface.withOpacity(0.12)),
backgroundColors:
MultiColor.single(theme.colorScheme.onSurface.withOpacity(0.38)),
),
);
}
/// Creates a [FlatButtonThemeExtensionDefault] from a dark theme
factory FlatButtonThemeExtensionDefault.dark() =>
FlatButtonThemeExtensionDefault.from(ThemeData.dark());
/// Creates a [FlatButtonThemeExtensionDefault] from a light theme
factory FlatButtonThemeExtensionDefault.light() =>
FlatButtonThemeExtensionDefault.from(ThemeData.light());
}

View File

@ -0,0 +1,78 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
/// {@template simple_icon_button_theme_extension}
/// Default simple icon button theme extension using Flutter's default values.
/// {@endtemplate}
class SimpleIconButtonThemeExtensionDefault
extends SimpleIconButtonThemeExtension {
/// {@macro simple_icon_button_theme_extension}
const SimpleIconButtonThemeExtensionDefault({
required super.disabledStyle,
required super.focusedStyle,
required super.hoveredStyle,
required super.normalStyle,
required super.tappedStyle,
});
/// Creates a [SimpleIconButtonThemeExtensionDefault] given a [ThemeData]
///
/// {@macro file_selection_button_theme_extension}
factory SimpleIconButtonThemeExtensionDefault.from(ThemeData theme) {
final backgroundColor = MultiColor.single(theme.colorScheme.primary);
final foregroundColor = MultiColor.single(theme.colorScheme.onPrimary);
final style = SimpleIconButtonStyle(
dimension: theme.buttonTheme.height,
radius: (theme.buttonTheme.shape is RoundedRectangleBorder)
? (theme.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null,
padding: theme.buttonTheme.padding,
foregroundColors: foregroundColor,
backgroundColors: backgroundColor,
);
return SimpleIconButtonThemeExtensionDefault(
normalStyle: style,
focusedStyle: style,
hoveredStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.92)),
),
tappedStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.92)),
),
disabledStyle: style.copyWith(
foregroundColors:
MultiColor.single(theme.colorScheme.onSurface.withOpacity(0.12)),
backgroundColors:
MultiColor.single(theme.colorScheme.onSurface.withOpacity(0.38)),
),
);
}
/// Creates a [SimpleIconButtonThemeExtensionDefault] from a dark theme
factory SimpleIconButtonThemeExtensionDefault.dark() =>
SimpleIconButtonThemeExtensionDefault.from(ThemeData.dark());
/// Creates a [SimpleIconButtonThemeExtensionDefault] from a light theme
factory SimpleIconButtonThemeExtensionDefault.light() =>
SimpleIconButtonThemeExtensionDefault.from(ThemeData.light());
}

View File

@ -0,0 +1,84 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
/// {@template symbol_button_theme_extension}
/// Default symbol button theme extension using Flutter's default values.
/// {@endtemplate}
class SymbolButtonThemeExtensionDefault extends SymbolButtonThemeExtension {
/// {@macro flat_button_theme_extension}
const SymbolButtonThemeExtensionDefault({
required super.disabledStyle,
required super.focusedStyle,
required super.hoveredStyle,
required super.normalStyle,
required super.tappedStyle,
required super.selectedStyle,
});
/// Creates a [SymbolButtonThemeExtensionDefault] given a [ThemeData]
///
/// {@macro file_selection_button_theme_extension}
factory SymbolButtonThemeExtensionDefault.from(ThemeData theme) {
final backgroundColor = MultiColor.single(theme.colorScheme.primary);
final foregroundColor = MultiColor.single(theme.colorScheme.onPrimary);
final style = SymbolButtonStyle(
labelStyle:
theme.textTheme.labelLarge?.copyWith(color: foregroundColor.color),
dimension: theme.buttonTheme.height * 1.5,
radius: (theme.buttonTheme.shape is RoundedRectangleBorder)
? (theme.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null,
padding: theme.buttonTheme.padding,
foregroundColors: foregroundColor,
backgroundColors: backgroundColor,
);
return SymbolButtonThemeExtensionDefault(
normalStyle: style,
focusedStyle: style,
hoveredStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.92)),
),
tappedStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.92)),
),
disabledStyle: style.copyWith(
foregroundColors:
MultiColor.single(theme.colorScheme.onSurface.withOpacity(0.12)),
backgroundColors:
MultiColor.single(theme.colorScheme.onSurface.withOpacity(0.38)),
),
selectedStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.92)),
),
);
}
/// Creates a [SymbolButtonThemeExtensionDefault] from a dark theme
factory SymbolButtonThemeExtensionDefault.dark() =>
SymbolButtonThemeExtensionDefault.from(ThemeData.dark());
/// Creates a [SymbolButtonThemeExtensionDefault] from a light theme
factory SymbolButtonThemeExtensionDefault.light() =>
SymbolButtonThemeExtensionDefault.from(ThemeData.light());
}

View File

@ -0,0 +1,67 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/theme_extensions/theme_extensions.dart';
/// {@template card_theme_extension_default}
/// Default card theme extension using Flutter's default card theme and
/// opinionated defaults.
/// {@endtemplate}
class CardThemeExtensionDefault extends CardThemeExtension {
/// {@macro card_theme_extension_default}
const CardThemeExtensionDefault({
required super.radius,
required super.padding,
required super.backgroundColors,
required super.borderColors,
required super.stroke,
required super.shadow,
required super.minSize,
required super.maxSize,
required super.titleStyle,
required super.subtitleStyle,
required super.bodyStyle,
});
/// Creates a [CardThemeExtensionDefault] from a [ThemeData]
/// and opinionated defaults.
///
/// {@macro card_theme_extension_default}
factory CardThemeExtensionDefault.from(ThemeData theme) =>
CardThemeExtensionDefault(
radius: const BorderRadius.all(Radius.circular(12)),
padding: theme.cardTheme.margin,
backgroundColors: MultiColor.single(theme.cardTheme.color),
borderColors: MultiColor.single(theme.cardTheme.color),
minSize: const Size(330, 0),
maxSize: const Size(390, double.infinity),
titleStyle: theme.textTheme.titleLarge,
subtitleStyle: theme.textTheme.titleMedium,
bodyStyle: theme.textTheme.bodyMedium,
stroke: 1,
shadow: null,
);
/// Creates a [CardThemeExtensionDefault] from a dark [ThemeData]
factory CardThemeExtensionDefault.dark() =>
CardThemeExtensionDefault.from(ThemeData.dark());
/// Creates a [CardThemeExtensionDefault] from a light [ThemeData]
factory CardThemeExtensionDefault.light() =>
CardThemeExtensionDefault.from(ThemeData.light());
}

View File

@ -0,0 +1,97 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/src/domain/entities/text_inputs/text_input_style.dart';
import 'package:wyatt_ui_components/src/domain/theme_extensions/text_input_theme_extension.dart';
/// {@template text_input_theme_extension_default}
/// The default implementation of [TextInputThemeExtension].
/// {@endtemplate}
class TextInputThemeExtensionDefault extends TextInputThemeExtension {
/// {@macro text_input_theme_extension_default}
const TextInputThemeExtensionDefault({
required super.normalStyle,
required super.focusedStyle,
required super.disabledStyle,
required super.invalidStyle,
});
/// Creates a [TextInputThemeExtensionDefault] from a [ThemeData].
///
/// {@macro text_input_theme_extension_default}
factory TextInputThemeExtensionDefault.from(ThemeData theme) {
final labelStyle = theme.textTheme.labelLarge
?.copyWith(color: theme.unselectedWidgetColor);
final hintStyle = theme.textTheme.labelLarge;
final prefixStyle = theme.textTheme.bodyMedium;
final suffixStyle = theme.textTheme.bodyMedium;
final inputStyle = theme.textTheme.bodyMedium;
final iconColor = theme.colorScheme.inversePrimary;
final prefixIconColor = theme.unselectedWidgetColor;
final suffixIconColor = theme.unselectedWidgetColor;
final borderColors = theme.unselectedWidgetColor;
final style = TextInputStyle(
labelStyle: labelStyle,
hintStyle: hintStyle,
iconColor: iconColor,
prefixIconColor: prefixIconColor,
prefixStyle: prefixStyle,
suffixStyle: suffixStyle,
suffixIconColor: suffixIconColor,
borderColors: borderColors,
inputStyle: inputStyle,
);
return TextInputThemeExtensionDefault(
normalStyle: style,
focusedStyle: style.copyWith(
prefixIconColor: theme.colorScheme.primary,
suffixIconColor: theme.colorScheme.primary,
iconColor: theme.colorScheme.primary,
borderColors: theme.colorScheme.primary,
labelStyle: labelStyle?.copyWith(color: theme.colorScheme.primary),
),
disabledStyle: style.copyWith(
labelStyle: labelStyle?.copyWith(color: theme.disabledColor),
hintStyle: hintStyle?.copyWith(color: theme.disabledColor),
prefixStyle: prefixStyle?.copyWith(color: theme.disabledColor),
suffixStyle: suffixStyle?.copyWith(color: theme.disabledColor),
inputStyle: inputStyle?.copyWith(color: theme.disabledColor),
borderColors: theme.disabledColor,
prefixIconColor: theme.disabledColor,
suffixIconColor: theme.disabledColor,
),
invalidStyle: style.copyWith(
labelStyle: theme.textTheme.labelLarge
?.copyWith(color: theme.colorScheme.error),
borderColors: theme.colorScheme.error,
),
);
}
/// Creates a [TextInputThemeExtensionDefault] from a [ThemeData.light].
factory TextInputThemeExtensionDefault.light() =>
TextInputThemeExtensionDefault.from(ThemeData.light());
/// Creates a [TextInputThemeExtensionDefault] from a [ThemeData.dark].
factory TextInputThemeExtensionDefault.dark() =>
TextInputThemeExtensionDefault.from(ThemeData.dark());
}

View File

@ -0,0 +1,19 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
export 'button_theme_extension/button_theme_extension.dart';
export 'card_theme_extension_default.dart';
export 'text_input_theme_extension_default.dart';

View File

@ -15,3 +15,4 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
export './entities/entities.dart'; export './entities/entities.dart';
export './theme_extensions/theme_extensions.dart';

View File

@ -17,7 +17,11 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
/// {@template button_component}
/// A button component is a component that can be pressed.
/// {@endtemplate}
abstract class ButtonComponent extends Component { abstract class ButtonComponent extends Component {
/// {@macro button_component}
const ButtonComponent({ const ButtonComponent({
this.disabledStyle, this.disabledStyle,
this.normalStyle, this.normalStyle,

View File

@ -18,7 +18,11 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/theme_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/theme_style.dart';
/// {@template button_style}
/// Base class for button styles.
/// {@endtemplate}
abstract class ButtonStyle<T> extends ThemeStyle<T> { abstract class ButtonStyle<T> extends ThemeStyle<T> {
/// {@macro button_style}
const ButtonStyle({ const ButtonStyle({
this.radius, this.radius,
this.padding, this.padding,

View File

@ -24,10 +24,10 @@ part 'file_selection_button_component.g.dart';
abstract class FileSelectionButtonComponent extends ButtonComponent abstract class FileSelectionButtonComponent extends ButtonComponent
with CopyWithMixin<$FileSelectionButtonComponentCWProxy> { with CopyWithMixin<$FileSelectionButtonComponentCWProxy> {
const FileSelectionButtonComponent({ const FileSelectionButtonComponent({
this.mainAxisSize = MainAxisSize.min, this.mainAxisSize,
this.leading, this.leading,
this.title, this.title,
this.subTitle, this.subtitle,
super.disabledStyle, super.disabledStyle,
super.normalStyle, super.normalStyle,
super.hoveredStyle, super.hoveredStyle,
@ -64,8 +64,15 @@ abstract class FileSelectionButtonComponent extends ButtonComponent
@override @override
FileSelectionButtonStyle? get invalidStyle; FileSelectionButtonStyle? get invalidStyle;
/// The main axis size of the button
final MainAxisSize? mainAxisSize; final MainAxisSize? mainAxisSize;
/// The leading widget of the button
final Widget? leading; final Widget? leading;
/// The title of the button
final TextWrapper? title; final TextWrapper? title;
final TextWrapper? subTitle;
/// The subtitle of the button
final TextWrapper? subtitle;
} }

View File

@ -10,7 +10,7 @@ abstract class $FileSelectionButtonComponentCWProxy {
FileSelectionButtonComponent mainAxisSize(MainAxisSize? mainAxisSize); FileSelectionButtonComponent mainAxisSize(MainAxisSize? mainAxisSize);
FileSelectionButtonComponent leading(Widget? leading); FileSelectionButtonComponent leading(Widget? leading);
FileSelectionButtonComponent title(TextWrapper? title); FileSelectionButtonComponent title(TextWrapper? title);
FileSelectionButtonComponent subTitle(TextWrapper? subTitle); FileSelectionButtonComponent subtitle(TextWrapper? subtitle);
FileSelectionButtonComponent disabledStyle( FileSelectionButtonComponent disabledStyle(
ButtonStyle<dynamic>? disabledStyle); ButtonStyle<dynamic>? disabledStyle);
FileSelectionButtonComponent normalStyle(ButtonStyle<dynamic>? normalStyle); FileSelectionButtonComponent normalStyle(ButtonStyle<dynamic>? normalStyle);
@ -30,7 +30,7 @@ abstract class $FileSelectionButtonComponentCWProxy {
MainAxisSize? mainAxisSize, MainAxisSize? mainAxisSize,
Widget? leading, Widget? leading,
TextWrapper? title, TextWrapper? title,
TextWrapper? subTitle, TextWrapper? subtitle,
ButtonStyle<dynamic>? disabledStyle, ButtonStyle<dynamic>? disabledStyle,
ButtonStyle<dynamic>? normalStyle, ButtonStyle<dynamic>? normalStyle,
ButtonStyle<dynamic>? hoveredStyle, ButtonStyle<dynamic>? hoveredStyle,

View File

@ -20,10 +20,16 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template file_selection_button_style}
/// File selection button style.
///
/// This style is used for the FileSelectionButton widget.
/// {@endtemplate}
class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> { class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
/// {@macro file_selection_button_style}
const FileSelectionButtonStyle({ const FileSelectionButtonStyle({
this.title, this.titleStyle,
this.subTitle, this.subtitleStyle,
super.radius, super.radius,
super.padding, super.padding,
super.foregroundColors, super.foregroundColors,
@ -46,8 +52,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
} }
return a.copyWith( return a.copyWith(
title: b.title, titleStyle: b.titleStyle,
subTitle: b.subTitle, subtitleStyle: b.subtitleStyle,
radius: b.radius, radius: b.radius,
padding: b.padding, padding: b.padding,
foregroundColors: b.foregroundColors, foregroundColors: b.foregroundColors,
@ -69,8 +75,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
} }
// b.copyWith to return b attributes even if they are not lerped // b.copyWith to return b attributes even if they are not lerped
return b.copyWith( return b.copyWith(
title: TextStyle.lerp(a.title, b.title, t), titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
subTitle: TextStyle.lerp(a.title, b.title, t), subtitleStyle: TextStyle.lerp(a.subtitleStyle, b.subtitleStyle, t),
foregroundColors: MultiColor.lerp( foregroundColors: MultiColor.lerp(
a.foregroundColors, a.foregroundColors,
b.foregroundColors, b.foregroundColors,
@ -96,12 +102,12 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
/// Title text style /// Title text style
/// ///
/// Default to `TextTheme.labelLarge` /// Default to `TextTheme.labelLarge`
final TextStyle? title; final TextStyle? titleStyle;
/// Sub title text style /// Sub title text style
/// ///
/// Default to `TextTheme.labelSmall` /// Default to `TextTheme.labelSmall`
final TextStyle? subTitle; final TextStyle? subtitleStyle;
@override @override
FileSelectionButtonStyle? mergeWith(FileSelectionButtonStyle? other) => FileSelectionButtonStyle? mergeWith(FileSelectionButtonStyle? other) =>
@ -109,8 +115,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
@override @override
FileSelectionButtonStyle? copyWith({ FileSelectionButtonStyle? copyWith({
TextStyle? title, TextStyle? titleStyle,
TextStyle? subTitle, TextStyle? subtitleStyle,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,
MultiColor? foregroundColors, MultiColor? foregroundColors,
@ -120,8 +126,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
BoxShadow? shadow, BoxShadow? shadow,
}) => }) =>
FileSelectionButtonStyle( FileSelectionButtonStyle(
title: title ?? this.title, titleStyle: titleStyle ?? this.titleStyle,
subTitle: subTitle ?? this.subTitle, subtitleStyle: subtitleStyle ?? this.subtitleStyle,
radius: radius ?? this.radius, radius: radius ?? this.radius,
padding: padding ?? this.padding, padding: padding ?? this.padding,
foregroundColors: foregroundColors ?? this.foregroundColors, foregroundColors: foregroundColors ?? this.foregroundColors,

View File

@ -54,8 +54,15 @@ abstract class FlatButtonComponent extends ButtonComponent
@override @override
FlatButtonStyle? get tappedStyle; FlatButtonStyle? get tappedStyle;
/// The main axis size of the button.
final MainAxisSize? mainAxisSize; final MainAxisSize? mainAxisSize;
/// The prefix widget of the button.
final Widget? prefix; final Widget? prefix;
/// The suffix widget of the button.
final Widget? suffix; final Widget? suffix;
/// The label widget of the button.
final TextWrapper? label; final TextWrapper? label;
} }

View File

@ -20,9 +20,15 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template flat_button_style}
/// Flat button style.
///
/// This style is used for the FlatButton widget.
/// {@endtemplate}
class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> { class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
/// {@macro flat_button_style}
const FlatButtonStyle({ const FlatButtonStyle({
this.label, this.labelStyle,
super.radius, super.radius,
super.padding, super.padding,
super.foregroundColors, super.foregroundColors,
@ -45,7 +51,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
} }
return a.copyWith( return a.copyWith(
label: b.label, labelStyle: b.labelStyle,
radius: b.radius, radius: b.radius,
padding: b.padding, padding: b.padding,
foregroundColors: b.foregroundColors, foregroundColors: b.foregroundColors,
@ -67,7 +73,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
} }
// b.copyWith to return b attributes even if they are not lerped // b.copyWith to return b attributes even if they are not lerped
return b.copyWith( return b.copyWith(
label: TextStyle.lerp(a.label, b.label, t), labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
foregroundColors: MultiColor.lerp( foregroundColors: MultiColor.lerp(
a.foregroundColors, a.foregroundColors,
b.foregroundColors, b.foregroundColors,
@ -90,10 +96,10 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
); );
} }
/// Label text style /// labelStyle text style
/// ///
/// Default to `TextTheme.labelLarge` /// Default to `TextTheme.labelLarge`
final TextStyle? label; final TextStyle? labelStyle;
@override @override
FlatButtonStyle? mergeWith(FlatButtonStyle? other) => FlatButtonStyle? mergeWith(FlatButtonStyle? other) =>
@ -101,7 +107,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
@override @override
FlatButtonStyle? copyWith({ FlatButtonStyle? copyWith({
TextStyle? label, TextStyle? labelStyle,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,
MultiColor? foregroundColors, MultiColor? foregroundColors,
@ -111,7 +117,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
BoxShadow? shadow, BoxShadow? shadow,
}) => }) =>
FlatButtonStyle( FlatButtonStyle(
label: label ?? this.label, labelStyle: labelStyle ?? this.labelStyle,
radius: radius ?? this.radius, radius: radius ?? this.radius,
padding: padding ?? this.padding, padding: padding ?? this.padding,
foregroundColors: foregroundColors ?? this.foregroundColors, foregroundColors: foregroundColors ?? this.foregroundColors,

View File

@ -51,5 +51,6 @@ abstract class SimpleIconButtonComponent extends ButtonComponent
@override @override
SimpleIconButtonStyle? get tappedStyle; SimpleIconButtonStyle? get tappedStyle;
final Icon? icon; /// The icon to display inside the button.
final Widget? icon;
} }

View File

@ -7,7 +7,7 @@ part of 'simple_icon_button_component.dart';
// ************************************************************************** // **************************************************************************
abstract class $SimpleIconButtonComponentCWProxy { abstract class $SimpleIconButtonComponentCWProxy {
SimpleIconButtonComponent icon(Icon? icon); SimpleIconButtonComponent icon(Widget? icon);
SimpleIconButtonComponent disabledStyle(ButtonStyle<dynamic>? disabledStyle); SimpleIconButtonComponent disabledStyle(ButtonStyle<dynamic>? disabledStyle);
SimpleIconButtonComponent normalStyle(ButtonStyle<dynamic>? normalStyle); SimpleIconButtonComponent normalStyle(ButtonStyle<dynamic>? normalStyle);
SimpleIconButtonComponent hoveredStyle(ButtonStyle<dynamic>? hoveredStyle); SimpleIconButtonComponent hoveredStyle(ButtonStyle<dynamic>? hoveredStyle);
@ -19,7 +19,7 @@ abstract class $SimpleIconButtonComponentCWProxy {
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver); ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
SimpleIconButtonComponent key(Key? key); SimpleIconButtonComponent key(Key? key);
SimpleIconButtonComponent call({ SimpleIconButtonComponent call({
Icon? icon, Widget? icon,
ButtonStyle<dynamic>? disabledStyle, ButtonStyle<dynamic>? disabledStyle,
ButtonStyle<dynamic>? normalStyle, ButtonStyle<dynamic>? normalStyle,
ButtonStyle<dynamic>? hoveredStyle, ButtonStyle<dynamic>? hoveredStyle,

View File

@ -20,7 +20,13 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template simple_icon_button_style}
/// Simple icon button style.
///
/// This style is used for the SimpleIconButton widget.
/// {@endtemplate}
class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> { class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
/// {@macro simple_icon_button_style}
const SimpleIconButtonStyle({ const SimpleIconButtonStyle({
this.dimension, this.dimension,
super.radius, super.radius,

View File

@ -24,7 +24,7 @@ part 'symbol_button_component.g.dart';
abstract class SymbolButtonComponent extends ButtonComponent abstract class SymbolButtonComponent extends ButtonComponent
with CopyWithMixin<$SymbolButtonComponentCWProxy> { with CopyWithMixin<$SymbolButtonComponentCWProxy> {
const SymbolButtonComponent({ const SymbolButtonComponent({
this.mainAxisSize = MainAxisSize.min, this.mainAxisSize,
this.label, this.label,
this.icon, this.icon,
super.disabledStyle, super.disabledStyle,
@ -57,7 +57,12 @@ abstract class SymbolButtonComponent extends ButtonComponent
@override @override
SymbolButtonStyle? get selectedStyle; SymbolButtonStyle? get selectedStyle;
/// The main axis size of the button.
final MainAxisSize? mainAxisSize; final MainAxisSize? mainAxisSize;
/// The icon widget of the button.
final Widget? icon; final Widget? icon;
/// The label widget of the button.
final TextWrapper? label; final TextWrapper? label;
} }

View File

@ -20,9 +20,15 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template symbol_button_style}
/// Symbol button style.
///
/// This style is used for the SymbolButton widget.
/// {@endtemplate}
class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> { class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
/// {@macro symbol_button_style}
const SymbolButtonStyle({ const SymbolButtonStyle({
this.label, this.labelStyle,
this.dimension, this.dimension,
super.radius, super.radius,
super.padding, super.padding,
@ -46,7 +52,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
} }
return a.copyWith( return a.copyWith(
label: b.label, labelStyle: b.labelStyle,
dimension: b.dimension, dimension: b.dimension,
radius: b.radius, radius: b.radius,
padding: b.padding, padding: b.padding,
@ -69,7 +75,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
} }
// b.copyWith to return b attributes even if they are not lerped // b.copyWith to return b attributes even if they are not lerped
return b.copyWith( return b.copyWith(
label: TextStyle.lerp(a.label, b.label, t), labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
dimension: lerpDouble(a.dimension, b.dimension, t), dimension: lerpDouble(a.dimension, b.dimension, t),
foregroundColors: MultiColor.lerp( foregroundColors: MultiColor.lerp(
a.foregroundColors, a.foregroundColors,
@ -93,10 +99,10 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
); );
} }
/// Label text style /// labelStyle text style
/// ///
/// Default to `TextTheme.labelLarge` /// Default to `TextTheme.labelLarge`
final TextStyle? label; final TextStyle? labelStyle;
/// Dimension of this button (as a square) /// Dimension of this button (as a square)
/// ///
@ -109,7 +115,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
@override @override
SymbolButtonStyle? copyWith({ SymbolButtonStyle? copyWith({
TextStyle? label, TextStyle? labelStyle,
double? dimension, double? dimension,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,
@ -120,7 +126,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
BoxShadow? shadow, BoxShadow? shadow,
}) => }) =>
SymbolButtonStyle( SymbolButtonStyle(
label: label ?? this.label, labelStyle: labelStyle ?? this.labelStyle,
dimension: dimension ?? this.dimension, dimension: dimension ?? this.dimension,
radius: radius ?? this.radius, radius: radius ?? this.radius,
padding: padding ?? this.padding, padding: padding ?? this.padding,

View File

@ -18,44 +18,82 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/component.dart'; import 'package:wyatt_ui_components/src/domain/entities/component.dart';
/// {@template card_component}
/// Card component.
/// Used to display a card with a background and a shadow.
/// {@endtemplate}
abstract class CardComponent extends Component { abstract class CardComponent extends Component {
const CardComponent({ const CardComponent({
this.radius = 12, this.radius,
this.padding = 25, this.padding,
this.borderColors,
this.backgroundColors, this.backgroundColors,
this.minSize = const Size(330, 230), this.borderColors,
this.maxSize = const Size(330, 530), this.stroke,
this.shadow = const BoxShadow( this.minSize,
blurRadius: 30, this.maxSize,
offset: Offset(0, 5), this.shadow,
color: Color.fromRGBO(0, 0, 0, 0.05), this.titleStyle,
), this.subtitleStyle,
this.bodyStyle,
this.background, this.background,
super.key, super.key,
}); });
/// Card radius /// Card radius
final double? radius; ///
/// Default to `BorderRadius.all(Radius.circular(12.0))`
final BorderRadiusGeometry? radius;
/// Padding and gaps of this card /// Padding and gaps of this card
final double? padding; ///
/// Default to `Theme.cardTheme.margin`
final EdgeInsetsGeometry? padding;
/// Border gradient color (from left to right) /// Card background gradient colors (from left to right)
final MultiColor? borderColors; ///
/// Default to `Theme.cardTheme.color`
/// Card background color
final MultiColor? backgroundColors; final MultiColor? backgroundColors;
/// Minimum size for this card /// Border colors (from left to right).
final Size? minSize; ///
/// Default to `null`
final MultiColor? borderColors;
/// Maximum size for this card /// Stroke of the border
final Size? maxSize; ///
/// Default to `null`
final double? stroke;
/// Drop shadow /// Drop shadow
///
/// Default to `null`
final BoxShadow? shadow; final BoxShadow? shadow;
/// Minimum size of the card
///
/// Default to `const Size(330, double.infinity)`
final Size? minSize;
/// Maximum size of the card
///
/// Default to `const Size(double.infinity, double.infinity)`
final Size? maxSize;
/// Title text style
///
/// Default to `Theme.textTheme.titleLarge`
final TextStyle? titleStyle;
/// Subtitle text style
///
/// Default to `Theme.textTheme.titleMedium`
final TextStyle? subtitleStyle;
/// Body text style
///
/// Default to `Theme.textTheme.bodyMedium`
final TextStyle? bodyStyle;
/// Background of the card /// Background of the card
final Widget? background; final Widget? background;
} }

View File

@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
export './card_component.dart';
export './information_card_component.dart'; export './information_card_component.dart';
export './portfolio_card_component.dart'; export './portfolio_card_component.dart';
export './quote_card_component.dart'; export './quote_card_component.dart';

View File

@ -16,7 +16,6 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/domain/entities/cards/card_component.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'information_card_component.g.dart'; part 'information_card_component.g.dart';
@ -29,21 +28,40 @@ abstract class InformationCardComponent extends CardComponent
this.title, this.title,
this.subtitle, this.subtitle,
this.body, this.body,
this.axis = Axis.vertical, this.axis,
super.radius, super.radius,
super.padding, super.padding,
super.borderColors, super.borderColors,
super.backgroundColors, super.backgroundColors,
super.stroke,
super.minSize, super.minSize,
super.maxSize, super.maxSize,
super.shadow, super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background, super.background,
super.key, super.key,
}); });
/// Axis of the card
///
/// If [axis] is [Axis.horizontal] then only the first icon will be displayed.
/// Used in header of the card.
final Axis? axis; final Axis? axis;
/// Icons of the card
///
/// If [axis] is [Axis.horizontal] then only the first icon will be displayed
/// on the left side of the card and the rest will be ignored.
final List<Widget>? icons; final List<Widget>? icons;
/// Title of the card
final TextWrapper? title; final TextWrapper? title;
/// Subtitle of the card
final TextWrapper? subtitle; final TextWrapper? subtitle;
/// Body of the card
final TextWrapper? body; final TextWrapper? body;
} }

View File

@ -12,13 +12,17 @@ abstract class $InformationCardComponentCWProxy {
InformationCardComponent subtitle(TextWrapper? subtitle); InformationCardComponent subtitle(TextWrapper? subtitle);
InformationCardComponent body(TextWrapper? body); InformationCardComponent body(TextWrapper? body);
InformationCardComponent axis(Axis? axis); InformationCardComponent axis(Axis? axis);
InformationCardComponent radius(double? radius); InformationCardComponent radius(BorderRadiusGeometry? radius);
InformationCardComponent padding(double? padding); InformationCardComponent padding(EdgeInsetsGeometry? padding);
InformationCardComponent borderColors(MultiColor? borderColors); InformationCardComponent borderColors(MultiColor? borderColors);
InformationCardComponent backgroundColors(MultiColor? backgroundColors); InformationCardComponent backgroundColors(MultiColor? backgroundColors);
InformationCardComponent stroke(double? stroke);
InformationCardComponent minSize(Size? minSize); InformationCardComponent minSize(Size? minSize);
InformationCardComponent maxSize(Size? maxSize); InformationCardComponent maxSize(Size? maxSize);
InformationCardComponent shadow(BoxShadow? shadow); InformationCardComponent shadow(BoxShadow? shadow);
InformationCardComponent titleStyle(TextStyle? titleStyle);
InformationCardComponent subtitleStyle(TextStyle? subtitleStyle);
InformationCardComponent bodyStyle(TextStyle? bodyStyle);
InformationCardComponent background(Widget? background); InformationCardComponent background(Widget? background);
InformationCardComponent key(Key? key); InformationCardComponent key(Key? key);
InformationCardComponent call({ InformationCardComponent call({
@ -27,13 +31,17 @@ abstract class $InformationCardComponentCWProxy {
TextWrapper? subtitle, TextWrapper? subtitle,
TextWrapper? body, TextWrapper? body,
Axis? axis, Axis? axis,
double? radius, BorderRadiusGeometry? radius,
double? padding, EdgeInsetsGeometry? padding,
MultiColor? borderColors, MultiColor? borderColors,
MultiColor? backgroundColors, MultiColor? backgroundColors,
double? stroke,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background, Widget? background,
Key? key, Key? key,
}); });

View File

@ -16,7 +16,6 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/domain/entities/cards/card_component.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'portfolio_card_component.g.dart'; part 'portfolio_card_component.g.dart';
@ -25,9 +24,9 @@ part 'portfolio_card_component.g.dart';
abstract class PortfolioCardComponent extends CardComponent abstract class PortfolioCardComponent extends CardComponent
with CopyWithMixin<$PortfolioCardComponentCWProxy> { with CopyWithMixin<$PortfolioCardComponentCWProxy> {
const PortfolioCardComponent({ const PortfolioCardComponent({
this.secondaryBackgroundColors, this.showAssetsOnTop,
this.showImagesOnTop, this.keywords,
this.keyword, this.keywordsBackgroundColors,
this.description, this.description,
this.logo, this.logo,
this.projectName, this.projectName,
@ -38,20 +37,42 @@ abstract class PortfolioCardComponent extends CardComponent
super.padding, super.padding,
super.borderColors, super.borderColors,
super.backgroundColors, super.backgroundColors,
super.stroke,
super.minSize, super.minSize,
super.maxSize, super.maxSize,
super.shadow, super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background, super.background,
super.key, super.key,
}); });
final bool? showImagesOnTop; /// Keywords of the portfolio
final List<TextWrapper>? keyword; final List<TextWrapper>? keywords;
/// Background colors for the keywords badges
final MultiColor? keywordsBackgroundColors;
/// Assets to display
final List<Widget>? assets; final List<Widget>? assets;
final TextWrapper? description;
/// Whether to show the assets on top or on bottom
/// of the card
final bool? showAssetsOnTop;
/// Logo of the portfolio
final Widget? logo; final Widget? logo;
/// Description of the portfolio
final TextWrapper? description;
/// Name of the portfolio
final TextWrapper? projectName; final TextWrapper? projectName;
/// Subtitle of the portfolio
final TextWrapper? subtitle; final TextWrapper? subtitle;
/// Call to actions of the portfolio
final List<Widget>? ctas; final List<Widget>? ctas;
final Color? secondaryBackgroundColors;
} }

View File

@ -7,42 +7,50 @@ part of 'portfolio_card_component.dart';
// ************************************************************************** // **************************************************************************
abstract class $PortfolioCardComponentCWProxy { abstract class $PortfolioCardComponentCWProxy {
PortfolioCardComponent secondaryBackgroundColors( PortfolioCardComponent showAssetsOnTop(bool? showAssetsOnTop);
Color? secondaryBackgroundColors); PortfolioCardComponent keywords(List<TextWrapper>? keywords);
PortfolioCardComponent showImagesOnTop(bool? showImagesOnTop); PortfolioCardComponent keywordsBackgroundColors(
PortfolioCardComponent keyword(List<TextWrapper>? keyword); MultiColor? keywordsBackgroundColors);
PortfolioCardComponent description(TextWrapper? description); PortfolioCardComponent description(TextWrapper? description);
PortfolioCardComponent logo(Widget? logo); PortfolioCardComponent logo(Widget? logo);
PortfolioCardComponent projectName(TextWrapper? projectName); PortfolioCardComponent projectName(TextWrapper? projectName);
PortfolioCardComponent subtitle(TextWrapper? subtitle); PortfolioCardComponent subtitle(TextWrapper? subtitle);
PortfolioCardComponent ctas(List<Widget>? ctas); PortfolioCardComponent ctas(List<Widget>? ctas);
PortfolioCardComponent assets(List<Widget>? assets); PortfolioCardComponent assets(List<Widget>? assets);
PortfolioCardComponent radius(double? radius); PortfolioCardComponent radius(BorderRadiusGeometry? radius);
PortfolioCardComponent padding(double? padding); PortfolioCardComponent padding(EdgeInsetsGeometry? padding);
PortfolioCardComponent borderColors(MultiColor? borderColors); PortfolioCardComponent borderColors(MultiColor? borderColors);
PortfolioCardComponent backgroundColors(MultiColor? backgroundColors); PortfolioCardComponent backgroundColors(MultiColor? backgroundColors);
PortfolioCardComponent stroke(double? stroke);
PortfolioCardComponent minSize(Size? minSize); PortfolioCardComponent minSize(Size? minSize);
PortfolioCardComponent maxSize(Size? maxSize); PortfolioCardComponent maxSize(Size? maxSize);
PortfolioCardComponent shadow(BoxShadow? shadow); PortfolioCardComponent shadow(BoxShadow? shadow);
PortfolioCardComponent titleStyle(TextStyle? titleStyle);
PortfolioCardComponent subtitleStyle(TextStyle? subtitleStyle);
PortfolioCardComponent bodyStyle(TextStyle? bodyStyle);
PortfolioCardComponent background(Widget? background); PortfolioCardComponent background(Widget? background);
PortfolioCardComponent key(Key? key); PortfolioCardComponent key(Key? key);
PortfolioCardComponent call({ PortfolioCardComponent call({
Color? secondaryBackgroundColors, bool? showAssetsOnTop,
bool? showImagesOnTop, List<TextWrapper>? keywords,
List<TextWrapper>? keyword, MultiColor? keywordsBackgroundColors,
TextWrapper? description, TextWrapper? description,
Widget? logo, Widget? logo,
TextWrapper? projectName, TextWrapper? projectName,
TextWrapper? subtitle, TextWrapper? subtitle,
List<Widget>? ctas, List<Widget>? ctas,
List<Widget>? assets, List<Widget>? assets,
double? radius, BorderRadiusGeometry? radius,
double? padding, EdgeInsetsGeometry? padding,
MultiColor? borderColors, MultiColor? borderColors,
MultiColor? backgroundColors, MultiColor? backgroundColors,
double? stroke,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background, Widget? background,
Key? key, Key? key,
}); });

View File

@ -16,7 +16,6 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/domain/entities/cards/card_component.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'quote_card_component.g.dart'; part 'quote_card_component.g.dart';
@ -28,7 +27,6 @@ abstract class QuoteCardComponent extends CardComponent
this.avatar, this.avatar,
this.name, this.name,
this.subtitle, this.subtitle,
this.gradient,
this.quote, this.quote,
this.leftQuote, this.leftQuote,
this.rightQuote, this.rightQuote,
@ -36,19 +34,32 @@ abstract class QuoteCardComponent extends CardComponent
super.padding, super.padding,
super.borderColors, super.borderColors,
super.backgroundColors, super.backgroundColors,
super.stroke,
super.minSize, super.minSize,
super.maxSize, super.maxSize,
super.shadow, super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background, super.background,
super.key, super.key,
}); });
/// Avatar of the contact who wrote the quote
final Widget? avatar; final Widget? avatar;
/// Name of the contact who wrote the quote
final TextWrapper? name; final TextWrapper? name;
/// Subtitle, usually the date of the quote or the company of the contact
final TextWrapper? subtitle; final TextWrapper? subtitle;
/// Quote
final TextWrapper? quote; final TextWrapper? quote;
final Gradient? gradient; /// Left quote, usually a double quote
final Widget? leftQuote; final Widget? leftQuote;
/// Right quote, usually a double quote
final Widget? rightQuote; final Widget? rightQuote;
} }

View File

@ -10,34 +10,40 @@ abstract class $QuoteCardComponentCWProxy {
QuoteCardComponent avatar(Widget? avatar); QuoteCardComponent avatar(Widget? avatar);
QuoteCardComponent name(TextWrapper? name); QuoteCardComponent name(TextWrapper? name);
QuoteCardComponent subtitle(TextWrapper? subtitle); QuoteCardComponent subtitle(TextWrapper? subtitle);
QuoteCardComponent gradient(Gradient? gradient);
QuoteCardComponent quote(TextWrapper? quote); QuoteCardComponent quote(TextWrapper? quote);
QuoteCardComponent leftQuote(Widget? leftQuote); QuoteCardComponent leftQuote(Widget? leftQuote);
QuoteCardComponent rightQuote(Widget? rightQuote); QuoteCardComponent rightQuote(Widget? rightQuote);
QuoteCardComponent radius(double? radius); QuoteCardComponent radius(BorderRadiusGeometry? radius);
QuoteCardComponent padding(double? padding); QuoteCardComponent padding(EdgeInsetsGeometry? padding);
QuoteCardComponent borderColors(MultiColor? borderColors); QuoteCardComponent borderColors(MultiColor? borderColors);
QuoteCardComponent backgroundColors(MultiColor? backgroundColors); QuoteCardComponent backgroundColors(MultiColor? backgroundColors);
QuoteCardComponent stroke(double? stroke);
QuoteCardComponent minSize(Size? minSize); QuoteCardComponent minSize(Size? minSize);
QuoteCardComponent maxSize(Size? maxSize); QuoteCardComponent maxSize(Size? maxSize);
QuoteCardComponent shadow(BoxShadow? shadow); QuoteCardComponent shadow(BoxShadow? shadow);
QuoteCardComponent titleStyle(TextStyle? titleStyle);
QuoteCardComponent subtitleStyle(TextStyle? subtitleStyle);
QuoteCardComponent bodyStyle(TextStyle? bodyStyle);
QuoteCardComponent background(Widget? background); QuoteCardComponent background(Widget? background);
QuoteCardComponent key(Key? key); QuoteCardComponent key(Key? key);
QuoteCardComponent call({ QuoteCardComponent call({
Widget? avatar, Widget? avatar,
TextWrapper? name, TextWrapper? name,
TextWrapper? subtitle, TextWrapper? subtitle,
Gradient? gradient,
TextWrapper? quote, TextWrapper? quote,
Widget? leftQuote, Widget? leftQuote,
Widget? rightQuote, Widget? rightQuote,
double? radius, BorderRadiusGeometry? radius,
double? padding, EdgeInsetsGeometry? padding,
MultiColor? borderColors, MultiColor? borderColors,
MultiColor? backgroundColors, MultiColor? backgroundColors,
double? stroke,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background, Widget? background,
Key? key, Key? key,
}); });

View File

@ -16,7 +16,6 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/domain/entities/cards/card_component.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'skill_card_component.g.dart'; part 'skill_card_component.g.dart';
@ -25,29 +24,56 @@ part 'skill_card_component.g.dart';
abstract class SkillCardComponent extends CardComponent abstract class SkillCardComponent extends CardComponent
with CopyWithMixin<$SkillCardComponentCWProxy> { with CopyWithMixin<$SkillCardComponentCWProxy> {
const SkillCardComponent({ const SkillCardComponent({
this.icon, this.axis,
this.gradient, this.icons,
this.title, this.title,
this.subtitle,
this.description, this.description,
this.skills, this.skills,
this.leadingIcon, this.bulletColors,
this.secondaryBackgroundColors, this.bulletIcon,
super.radius, super.radius,
super.padding, super.padding,
super.borderColors, super.borderColors,
super.backgroundColors, super.backgroundColors,
super.stroke,
super.minSize, super.minSize,
super.maxSize, super.maxSize,
super.shadow, super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background, super.background,
super.key, super.key,
}); });
final Widget? icon; /// Axis of the card
final List<Color>? gradient; ///
/// If [axis] is [Axis.horizontal] then only the first icon will be displayed.
/// Used in header of the card.
final Axis? axis;
/// Icons of the card
///
/// If [axis] is [Axis.horizontal] then only the first icon will be displayed
/// on the left side of the card and the rest will be ignored.
final List<Widget>? icons;
/// Title of the card
final TextWrapper? title; final TextWrapper? title;
/// Subtitle of the card
final TextWrapper? subtitle;
/// Description of the card
final TextWrapper? description; final TextWrapper? description;
/// Skills to be displayed
final List<TextWrapper>? skills; final List<TextWrapper>? skills;
final IconData? leadingIcon;
final Color? secondaryBackgroundColors; /// Gradient of skill icons.
final MultiColor? bulletColors;
/// Icon to be displayed before each skill.
final Widget? bulletIcon;
} }

View File

@ -7,38 +7,47 @@ part of 'skill_card_component.dart';
// ************************************************************************** // **************************************************************************
abstract class $SkillCardComponentCWProxy { abstract class $SkillCardComponentCWProxy {
SkillCardComponent icon(Widget? icon); SkillCardComponent axis(Axis? axis);
SkillCardComponent gradient(List<Color>? gradient); SkillCardComponent icons(List<Widget>? icons);
SkillCardComponent title(TextWrapper? title); SkillCardComponent title(TextWrapper? title);
SkillCardComponent subtitle(TextWrapper? subtitle);
SkillCardComponent description(TextWrapper? description); SkillCardComponent description(TextWrapper? description);
SkillCardComponent skills(List<TextWrapper>? skills); SkillCardComponent skills(List<TextWrapper>? skills);
SkillCardComponent leadingIcon(IconData? leadingIcon); SkillCardComponent bulletColors(MultiColor? bulletColors);
SkillCardComponent secondaryBackgroundColors( SkillCardComponent bulletIcon(Widget? bulletIcon);
Color? secondaryBackgroundColors); SkillCardComponent radius(BorderRadiusGeometry? radius);
SkillCardComponent radius(double? radius); SkillCardComponent padding(EdgeInsetsGeometry? padding);
SkillCardComponent padding(double? padding);
SkillCardComponent borderColors(MultiColor? borderColors); SkillCardComponent borderColors(MultiColor? borderColors);
SkillCardComponent backgroundColors(MultiColor? backgroundColors); SkillCardComponent backgroundColors(MultiColor? backgroundColors);
SkillCardComponent stroke(double? stroke);
SkillCardComponent minSize(Size? minSize); SkillCardComponent minSize(Size? minSize);
SkillCardComponent maxSize(Size? maxSize); SkillCardComponent maxSize(Size? maxSize);
SkillCardComponent shadow(BoxShadow? shadow); SkillCardComponent shadow(BoxShadow? shadow);
SkillCardComponent titleStyle(TextStyle? titleStyle);
SkillCardComponent subtitleStyle(TextStyle? subtitleStyle);
SkillCardComponent bodyStyle(TextStyle? bodyStyle);
SkillCardComponent background(Widget? background); SkillCardComponent background(Widget? background);
SkillCardComponent key(Key? key); SkillCardComponent key(Key? key);
SkillCardComponent call({ SkillCardComponent call({
Widget? icon, Axis? axis,
List<Color>? gradient, List<Widget>? icons,
TextWrapper? title, TextWrapper? title,
TextWrapper? subtitle,
TextWrapper? description, TextWrapper? description,
List<TextWrapper>? skills, List<TextWrapper>? skills,
IconData? leadingIcon, MultiColor? bulletColors,
Color? secondaryBackgroundColors, Widget? bulletIcon,
double? radius, BorderRadiusGeometry? radius,
double? padding, EdgeInsetsGeometry? padding,
MultiColor? borderColors, MultiColor? borderColors,
MultiColor? backgroundColors, MultiColor? backgroundColors,
double? stroke,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background, Widget? background,
Key? key, Key? key,
}); });

View File

@ -16,17 +16,43 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
/// {@template rich_text_style_parameter}
/// Rich text style parameter used to parse the text.
/// {@endtemplate}
class RichTextStyleParameter { class RichTextStyleParameter {
/// {@macro rich_text_style_parameter}
const RichTextStyleParameter( const RichTextStyleParameter(
this.defaultStyle, this.defaultStyle,
this.definedStyle, this.definedStyle,
this.styleName, this.styleName,
); );
/// Default style to use if no style is defined.
final TextStyle? defaultStyle; final TextStyle? defaultStyle;
/// Map of defined styles. The key is the style name.
///
/// Example:
/// ```dart
/// definedStyle: {
/// 'bold': TextStyle(fontWeight: FontWeight.bold),
/// 'italic': TextStyle(fontStyle: FontStyle.italic),
/// }
/// ```
/// then, the text `This is <bold>bold</bold> and <italic>italic</italic>`
/// will be parsed and the word `bold` will be bold and the word `italic`
/// will be italic in the RichText widget.
final Map<String, TextStyle> definedStyle; final Map<String, TextStyle> definedStyle;
/// Style name to use for the text.
/// If no style is defined and no default style is defined, the text will be
/// displayed with the default style of the RichText widget.
final String? styleName; final String? styleName;
/// Returns the style to use for the given style name.
/// If no style is defined for the given style name, the default style is
/// returned. If no default style is defined, the default style of the
/// RichText widget is returned.
TextStyle get style { TextStyle get style {
if (definedStyle.containsKey(styleName)) { if (definedStyle.containsKey(styleName)) {
return definedStyle[styleName]!; return definedStyle[styleName]!;
@ -46,11 +72,47 @@ class RichTextStyleParameter {
); );
} }
/// {@template rich_text_node}
/// Rich text node.
///
/// Used as a node in the tree of the RichText widget.
/// {@endtemplate}
class RichTextNode { class RichTextNode {
RichTextNode(this.nodes); /// {@macro rich_text_node}
const RichTextNode(this.nodes);
/// List of nodes.
final List<RichTextNode> nodes; final List<RichTextNode> nodes;
/// Returns a RichTextNode from the given content.
/// If the content contains a match with the given regex, the content is
/// split into multiple nodes. If the content does not contain a match with
/// the given regex, a leaf node is returned.
///
/// Example:
/// ```dart
/// RichTextNode.from(
/// 'This is <bold>bold</bold> and <italic>italic</italic>',
/// RegExp(r'<(\w+)>(.*?)</\1>'),
/// RichTextStyleParameter(
/// TextStyle(fontWeight: FontWeight.w400),
/// {'bold': TextStyle(fontWeight: FontWeight.bold)},
/// {'italic': TextStyle(fontStyle: FontStyle.italic)},
/// ),
/// );
/// ```
/// will return a RichTextNode with 5 nodes:
/// - `This is `
/// - `<bold>bold</bold>`
/// - ` and `
/// - `<italic>italic</italic>`
/// - `` (empty string)
///
/// The first node is a leaf node with the default style of the RichText
/// widget. The second node is a node with bold paramters. The third node is
/// a leaf node with the default style of the RichText widget.
/// The fourth node is a node italic parameters. The fifth node is a
/// leaf node with the default style of the RichText widget.
static RichTextNode from( static RichTextNode from(
String content, String content,
RegExp regex, RegExp regex,
@ -88,6 +150,11 @@ class RichTextNode {
} }
} }
/// Returns an InlineSpan from the given RichTextNode.
/// The given RichTextParser is used to convert the RichTextNode to an
/// InlineSpan.
///
/// InlineSpan is used to display text in the RichText widget.
InlineSpan toInlineSpan(RichTextParser parser) { InlineSpan toInlineSpan(RichTextParser parser) {
final children = <InlineSpan>[]; final children = <InlineSpan>[];
for (final node in nodes) { for (final node in nodes) {
@ -97,10 +164,17 @@ class RichTextNode {
} }
} }
/// {@template rich_text_leaf}
/// Rich text leaf.
/// {@endtemplate}
class RichTextLeaf extends RichTextNode { class RichTextLeaf extends RichTextNode {
RichTextLeaf(this.style, this.content) : super([]); /// {@macro rich_text_leaf}
const RichTextLeaf(this.style, this.content) : super(const []);
/// Style to use for the text.
final TextStyle style; final TextStyle style;
/// Text content.
final String content; final String content;
@override @override
@ -108,13 +182,26 @@ class RichTextLeaf extends RichTextNode {
parser.nodeBuilder.call(content, style); parser.nodeBuilder.call(content, style);
} }
/// {@template rich_text_parser}
/// Rich text parser.
/// {@endtemplate}
class RichTextParser { class RichTextParser {
/// {@macro rich_text_parser}
const RichTextParser({required this.nodeBuilder}); const RichTextParser({required this.nodeBuilder});
/// Returns a default RichTextParser.
/// The default RichTextParser uses the given nodeBuilder to convert a
/// RichTextNode to an InlineSpan.
///
/// By default, the nodeBuilder returns a TextSpan with the given content
/// and style.
factory RichTextParser.defaultBuilder() => RichTextParser( factory RichTextParser.defaultBuilder() => RichTextParser(
nodeBuilder: (content, style) => TextSpan( nodeBuilder: (content, style) => TextSpan(
text: content, text: content,
style: style, style: style,
), ),
); );
/// Converts the given RichTextNode to an InlineSpan.
final InlineSpan Function(String content, TextStyle style) nodeBuilder; final InlineSpan Function(String content, TextStyle style) nodeBuilder;
} }

View File

@ -39,8 +39,8 @@ abstract class TextInputComponent extends Component
this.hint, this.hint,
this.normalStyle, this.normalStyle,
this.focusedStyle, this.focusedStyle,
this.errorStyle, this.invalidStyle,
this.disableStyle, this.disabledStyle,
this.controller, this.controller,
this.focusNode, this.focusNode,
this.keyboardType, this.keyboardType,
@ -156,10 +156,11 @@ abstract class TextInputComponent extends Component
final bool Function(String)? validator; final bool Function(String)? validator;
final String? Function(String)? onError; final String? Function(String)? onError;
// Styles
final TextInputStyle? normalStyle; final TextInputStyle? normalStyle;
final TextInputStyle? focusedStyle; final TextInputStyle? focusedStyle;
final TextInputStyle? errorStyle; final TextInputStyle? invalidStyle;
final TextInputStyle? disableStyle; final TextInputStyle? disabledStyle;
final bool? expand; final bool? expand;

View File

@ -18,8 +18,8 @@ abstract class $TextInputComponentCWProxy {
TextInputComponent hint(TextWrapper? hint); TextInputComponent hint(TextWrapper? hint);
TextInputComponent normalStyle(TextInputStyle? normalStyle); TextInputComponent normalStyle(TextInputStyle? normalStyle);
TextInputComponent focusedStyle(TextInputStyle? focusedStyle); TextInputComponent focusedStyle(TextInputStyle? focusedStyle);
TextInputComponent errorStyle(TextInputStyle? errorStyle); TextInputComponent invalidStyle(TextInputStyle? invalidStyle);
TextInputComponent disableStyle(TextInputStyle? disableStyle); TextInputComponent disabledStyle(TextInputStyle? disabledStyle);
TextInputComponent controller(TextEditingController? controller); TextInputComponent controller(TextEditingController? controller);
TextInputComponent focusNode(FocusNode? focusNode); TextInputComponent focusNode(FocusNode? focusNode);
TextInputComponent keyboardType(TextInputType? keyboardType); TextInputComponent keyboardType(TextInputType? keyboardType);
@ -96,8 +96,8 @@ abstract class $TextInputComponentCWProxy {
TextWrapper? hint, TextWrapper? hint,
TextInputStyle? normalStyle, TextInputStyle? normalStyle,
TextInputStyle? focusedStyle, TextInputStyle? focusedStyle,
TextInputStyle? errorStyle, TextInputStyle? invalidStyle,
TextInputStyle? disableStyle, TextInputStyle? disabledStyle,
TextEditingController? controller, TextEditingController? controller,
FocusNode? focusNode, FocusNode? focusNode,
TextInputType? keyboardType, TextInputType? keyboardType,

View File

@ -23,7 +23,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
this.hintStyle, this.hintStyle,
this.backgroundColors, this.backgroundColors,
this.borderColors, this.borderColors,
this.boxShadow, this.shadow,
this.radius, this.radius,
this.inputStyle, this.inputStyle,
this.iconColor, this.iconColor,
@ -44,7 +44,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
final MultiColor? backgroundColors; final MultiColor? backgroundColors;
final Color? borderColors; final Color? borderColors;
final BoxShadow? boxShadow; final BoxShadow? shadow;
final BorderRadiusGeometry? radius; final BorderRadiusGeometry? radius;
final TextStyle? inputStyle; final TextStyle? inputStyle;
@ -60,7 +60,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
hintStyle: b.hintStyle, hintStyle: b.hintStyle,
backgroundColors: b.backgroundColors, backgroundColors: b.backgroundColors,
borderColors: b.borderColors, borderColors: b.borderColors,
boxShadow: b.boxShadow, shadow: b.shadow,
radius: b.radius, radius: b.radius,
inputStyle: b.inputStyle, inputStyle: b.inputStyle,
iconColor: b.iconColor, iconColor: b.iconColor,
@ -87,7 +87,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
MultiColor.lerp(a.backgroundColors, b.backgroundColors, t), MultiColor.lerp(a.backgroundColors, b.backgroundColors, t),
radius: BorderRadiusGeometry.lerp(a.radius, b.radius, t), radius: BorderRadiusGeometry.lerp(a.radius, b.radius, t),
borderColors: Color.lerp(a.borderColors, b.borderColors, t), borderColors: Color.lerp(a.borderColors, b.borderColors, t),
boxShadow: BoxShadow.lerp(a.boxShadow, b.boxShadow, t), shadow: BoxShadow.lerp(a.shadow, b.shadow, t),
inputStyle: TextStyle.lerp(a.inputStyle, b.inputStyle, t), inputStyle: TextStyle.lerp(a.inputStyle, b.inputStyle, t),
prefixStyle: TextStyle.lerp(a.prefixStyle, b.prefixStyle, t), prefixStyle: TextStyle.lerp(a.prefixStyle, b.prefixStyle, t),
suffixStyle: TextStyle.lerp(a.suffixStyle, b.suffixStyle, t), suffixStyle: TextStyle.lerp(a.suffixStyle, b.suffixStyle, t),
@ -107,7 +107,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
TextStyle? hintStyle, TextStyle? hintStyle,
MultiColor? backgroundColors, MultiColor? backgroundColors,
Color? borderColors, Color? borderColors,
BoxShadow? boxShadow, BoxShadow? shadow,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,
TextStyle? inputStyle, TextStyle? inputStyle,
Color? iconColor, Color? iconColor,
@ -122,7 +122,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
backgroundColors: backgroundColors ?? this.backgroundColors, backgroundColors: backgroundColors ?? this.backgroundColors,
radius: radius ?? this.radius, radius: radius ?? this.radius,
borderColors: borderColors ?? this.borderColors, borderColors: borderColors ?? this.borderColors,
boxShadow: boxShadow ?? this.boxShadow, shadow: shadow ?? this.shadow,
inputStyle: inputStyle ?? this.inputStyle, inputStyle: inputStyle ?? this.inputStyle,
prefixStyle: prefixStyle ?? this.prefixStyle, prefixStyle: prefixStyle ?? this.prefixStyle,
suffixStyle: suffixStyle ?? this.suffixStyle, suffixStyle: suffixStyle ?? this.suffixStyle,

View File

@ -0,0 +1,103 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
/// {@template file_selection_button_theme_extension}
/// File selection button theme extension that extends [ThemeExtension] and
/// implements copyWith, and lerp methods so you don't have to.
/// {@endtemplate}
class FileSelectionButtonThemeExtension
extends ThemeExtension<FileSelectionButtonThemeExtension> {
/// {@macro file_selection_button_theme_extension}
const FileSelectionButtonThemeExtension({
this.disabledStyle,
this.focusedStyle,
this.hoveredStyle,
this.normalStyle,
this.tappedStyle,
this.selectedStyle,
this.invalidStyle,
});
/// Style of this button in disabled state
final FileSelectionButtonStyle? disabledStyle;
/// Style of this button in focused state
final FileSelectionButtonStyle? focusedStyle;
/// Style of this button in hovered state
final FileSelectionButtonStyle? hoveredStyle;
/// Style of this button in normal state
final FileSelectionButtonStyle? normalStyle;
/// Style of this button in tapped state
final FileSelectionButtonStyle? tappedStyle;
/// Style of this button in selected state
final FileSelectionButtonStyle? selectedStyle;
/// Style of this button in invalid state
final FileSelectionButtonStyle? invalidStyle;
@override
ThemeExtension<FileSelectionButtonThemeExtension> copyWith({
FileSelectionButtonStyle? disabledStyle,
FileSelectionButtonStyle? focusedStyle,
FileSelectionButtonStyle? hoveredStyle,
FileSelectionButtonStyle? normalStyle,
FileSelectionButtonStyle? tappedStyle,
FileSelectionButtonStyle? selectedStyle,
FileSelectionButtonStyle? invalidStyle,
}) =>
FileSelectionButtonThemeExtension(
disabledStyle: disabledStyle ?? this.disabledStyle,
focusedStyle: focusedStyle ?? this.focusedStyle,
hoveredStyle: hoveredStyle ?? this.hoveredStyle,
normalStyle: normalStyle ?? this.normalStyle,
tappedStyle: tappedStyle ?? this.tappedStyle,
selectedStyle: selectedStyle ?? this.selectedStyle,
invalidStyle: invalidStyle ?? this.invalidStyle,
);
@override
ThemeExtension<FileSelectionButtonThemeExtension> lerp(
covariant ThemeExtension<FileSelectionButtonThemeExtension>? other,
double t,
) {
if (other is! FileSelectionButtonThemeExtension) {
return this;
}
return FileSelectionButtonThemeExtension(
disabledStyle:
FileSelectionButtonStyle.lerp(disabledStyle, other.disabledStyle, t),
focusedStyle:
FileSelectionButtonStyle.lerp(focusedStyle, other.focusedStyle, t),
hoveredStyle:
FileSelectionButtonStyle.lerp(hoveredStyle, other.hoveredStyle, t),
normalStyle:
FileSelectionButtonStyle.lerp(normalStyle, other.normalStyle, t),
tappedStyle:
FileSelectionButtonStyle.lerp(tappedStyle, other.tappedStyle, t),
selectedStyle:
FileSelectionButtonStyle.lerp(selectedStyle, other.selectedStyle, t),
invalidStyle:
FileSelectionButtonStyle.lerp(invalidStyle, other.invalidStyle, t),
);
}
}

View File

@ -0,0 +1,83 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
/// {@template flat_button_theme_extension}
/// Flat button theme extension that extends [ThemeExtension] and
/// implements copyWith, and lerp methods so you don't have to.
/// {@endtemplate}
class FlatButtonThemeExtension
extends ThemeExtension<FlatButtonThemeExtension> {
/// {@macro flat_button_theme_extension}
const FlatButtonThemeExtension({
this.disabledStyle,
this.focusedStyle,
this.hoveredStyle,
this.normalStyle,
this.tappedStyle,
});
/// Style of this button in disabled state
final FlatButtonStyle? disabledStyle;
/// Style of this button in focused state
final FlatButtonStyle? focusedStyle;
/// Style of this button in hovered state
final FlatButtonStyle? hoveredStyle;
/// Style of this button in normal state
final FlatButtonStyle? normalStyle;
/// Style of this button in tapped state
final FlatButtonStyle? tappedStyle;
@override
ThemeExtension<FlatButtonThemeExtension> copyWith({
FlatButtonStyle? disabledStyle,
FlatButtonStyle? focusedStyle,
FlatButtonStyle? hoveredStyle,
FlatButtonStyle? normalStyle,
FlatButtonStyle? tappedStyle,
}) =>
FlatButtonThemeExtension(
disabledStyle: disabledStyle ?? this.disabledStyle,
focusedStyle: focusedStyle ?? this.focusedStyle,
hoveredStyle: hoveredStyle ?? this.hoveredStyle,
normalStyle: normalStyle ?? this.normalStyle,
tappedStyle: tappedStyle ?? this.tappedStyle,
);
@override
ThemeExtension<FlatButtonThemeExtension> lerp(
covariant ThemeExtension<FlatButtonThemeExtension>? other,
double t,
) {
if (other is! FlatButtonThemeExtension) {
return this;
}
return FlatButtonThemeExtension(
disabledStyle:
FlatButtonStyle.lerp(disabledStyle, other.disabledStyle, t),
focusedStyle: FlatButtonStyle.lerp(focusedStyle, other.focusedStyle, t),
hoveredStyle: FlatButtonStyle.lerp(hoveredStyle, other.hoveredStyle, t),
normalStyle: FlatButtonStyle.lerp(normalStyle, other.normalStyle, t),
tappedStyle: FlatButtonStyle.lerp(tappedStyle, other.tappedStyle, t),
);
}
}

View File

@ -16,63 +16,36 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart';
class SimpleIconButtonTheme extends SimpleIconButtonThemeExtension { /// {@template simple_icon_button_theme_extension}
const SimpleIconButtonTheme({ /// Simple icon button theme extension that extends [ThemeExtension] and
super.disabledStyle, /// implements copyWith, and lerp methods so you don't have to.
super.focusedStyle, /// {@endtemplate}
super.hoveredStyle, class SimpleIconButtonThemeExtension
super.normalStyle, extends ThemeExtension<SimpleIconButtonThemeExtension> {
super.tappedStyle, /// {@macro simple_icon_button_theme_extension}
const SimpleIconButtonThemeExtension({
this.disabledStyle,
this.focusedStyle,
this.hoveredStyle,
this.normalStyle,
this.tappedStyle,
}); });
factory SimpleIconButtonTheme.light() { /// Style of this button in disabled state
final style = SimpleIconButtonStyle( final SimpleIconButtonStyle? disabledStyle;
dimension: 30,
radius: BorderRadius.circular(5),
padding: const EdgeInsets.all(5),
foregroundColors: const MultiColor.single(Constants.dark),
backgroundColors: MultiColor.single(Constants.grey1.withOpacity(0.2)),
);
return SimpleIconButtonTheme(
normalStyle: style,
disabledStyle: style.copyWith(
foregroundColors: MultiColor.single(Constants.dark.withOpacity(0.4)),
),
hoveredStyle: style.copyWith(
backgroundColors: MultiColor.single(Constants.grey1.withOpacity(0.4)),
),
focusedStyle: style,
tappedStyle: style.copyWith(
backgroundColors: MultiColor.single(Constants.grey1.withOpacity(0.5)),
),
);
}
factory SimpleIconButtonTheme.dark() { /// Style of this button in focused state
final style = SimpleIconButtonStyle( final SimpleIconButtonStyle? focusedStyle;
dimension: 30,
radius: BorderRadius.circular(5), /// Style of this button in hovered state
padding: const EdgeInsets.all(5), final SimpleIconButtonStyle? hoveredStyle;
foregroundColors: const MultiColor.single(Constants.white),
backgroundColors: MultiColor.single(Constants.grey3.withOpacity(0.2)), /// Style of this button in normal state
); final SimpleIconButtonStyle? normalStyle;
return SimpleIconButtonTheme(
normalStyle: style, /// Style of this button in tapped state
disabledStyle: style.copyWith( final SimpleIconButtonStyle? tappedStyle;
foregroundColors: MultiColor.single(Constants.white.withOpacity(0.4)),
),
hoveredStyle: style.copyWith(
backgroundColors: MultiColor.single(Constants.grey3.withOpacity(0.4)),
),
focusedStyle: style,
tappedStyle: style.copyWith(
backgroundColors: MultiColor.single(Constants.grey3.withOpacity(0.5)),
),
);
}
@override @override
ThemeExtension<SimpleIconButtonThemeExtension> copyWith({ ThemeExtension<SimpleIconButtonThemeExtension> copyWith({
@ -82,7 +55,7 @@ class SimpleIconButtonTheme extends SimpleIconButtonThemeExtension {
SimpleIconButtonStyle? normalStyle, SimpleIconButtonStyle? normalStyle,
SimpleIconButtonStyle? tappedStyle, SimpleIconButtonStyle? tappedStyle,
}) => }) =>
SimpleIconButtonTheme( SimpleIconButtonThemeExtension(
disabledStyle: disabledStyle ?? this.disabledStyle, disabledStyle: disabledStyle ?? this.disabledStyle,
focusedStyle: focusedStyle ?? this.focusedStyle, focusedStyle: focusedStyle ?? this.focusedStyle,
hoveredStyle: hoveredStyle ?? this.hoveredStyle, hoveredStyle: hoveredStyle ?? this.hoveredStyle,
@ -95,10 +68,10 @@ class SimpleIconButtonTheme extends SimpleIconButtonThemeExtension {
covariant ThemeExtension<SimpleIconButtonThemeExtension>? other, covariant ThemeExtension<SimpleIconButtonThemeExtension>? other,
double t, double t,
) { ) {
if (other is! SimpleIconButtonTheme) { if (other is! SimpleIconButtonThemeExtension) {
return this; return this;
} }
return SimpleIconButtonTheme( return SimpleIconButtonThemeExtension(
disabledStyle: disabledStyle:
SimpleIconButtonStyle.lerp(disabledStyle, other.disabledStyle, t), SimpleIconButtonStyle.lerp(disabledStyle, other.disabledStyle, t),
focusedStyle: focusedStyle:

View File

@ -0,0 +1,91 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
/// {@template symbol_button_theme_extension}
/// Symbol button theme extension that extends [ThemeExtension] and
/// implements copyWith, and lerp methods so you don't have to.
/// {@endtemplate}
class SymbolButtonThemeExtension
extends ThemeExtension<SymbolButtonThemeExtension> {
/// {@macro symbol_button_theme_extension}
const SymbolButtonThemeExtension({
this.disabledStyle,
this.focusedStyle,
this.hoveredStyle,
this.normalStyle,
this.tappedStyle,
this.selectedStyle,
});
/// Style of this button in disabled state
final SymbolButtonStyle? disabledStyle;
/// Style of this button in focused state
final SymbolButtonStyle? focusedStyle;
/// Style of this button in hovered state
final SymbolButtonStyle? hoveredStyle;
/// Style of this button in normal state
final SymbolButtonStyle? normalStyle;
/// Style of this button in tapped state
final SymbolButtonStyle? tappedStyle;
/// Style of this button in selected state
final SymbolButtonStyle? selectedStyle;
@override
ThemeExtension<SymbolButtonThemeExtension> copyWith({
SymbolButtonStyle? disabledStyle,
SymbolButtonStyle? focusedStyle,
SymbolButtonStyle? hoveredStyle,
SymbolButtonStyle? normalStyle,
SymbolButtonStyle? tappedStyle,
SymbolButtonStyle? selectedStyle,
}) =>
SymbolButtonThemeExtension(
disabledStyle: disabledStyle ?? this.disabledStyle,
focusedStyle: focusedStyle ?? this.focusedStyle,
hoveredStyle: hoveredStyle ?? this.hoveredStyle,
normalStyle: normalStyle ?? this.normalStyle,
tappedStyle: tappedStyle ?? this.tappedStyle,
selectedStyle: selectedStyle ?? this.selectedStyle,
);
@override
ThemeExtension<SymbolButtonThemeExtension> lerp(
covariant ThemeExtension<SymbolButtonThemeExtension>? other,
double t,
) {
if (other is! SymbolButtonThemeExtension) {
return this;
}
return SymbolButtonThemeExtension(
disabledStyle:
SymbolButtonStyle.lerp(disabledStyle, other.disabledStyle, t),
focusedStyle: SymbolButtonStyle.lerp(focusedStyle, other.focusedStyle, t),
hoveredStyle: SymbolButtonStyle.lerp(hoveredStyle, other.hoveredStyle, t),
normalStyle: SymbolButtonStyle.lerp(normalStyle, other.normalStyle, t),
tappedStyle: SymbolButtonStyle.lerp(tappedStyle, other.tappedStyle, t),
selectedStyle:
SymbolButtonStyle.lerp(selectedStyle, other.selectedStyle, t),
);
}
}

View File

@ -0,0 +1,143 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
/// {@template card_theme_extension}
/// Card theme extension that extends [ThemeExtension] and
/// implements copyWith, and lerp methods so you don't have to.
/// {@endtemplate}
class CardThemeExtension extends ThemeExtension<CardThemeExtension> {
/// {@macro card_theme_extension}
const CardThemeExtension({
this.radius,
this.padding,
this.backgroundColors,
this.borderColors,
this.stroke,
this.shadow,
this.minSize,
this.maxSize,
this.titleStyle,
this.subtitleStyle,
this.bodyStyle,
});
/// Card radius
///
/// Default to `BorderRadius.all(Radius.circular(12.0))`
final BorderRadiusGeometry? radius;
/// Padding and gaps of this card
///
/// Default to `Theme.cardTheme.margin`
final EdgeInsetsGeometry? padding;
/// Card background gradient colors (from left to right)
///
/// Default to `Theme.cardTheme.color`
final MultiColor? backgroundColors;
/// Border colors (from left to right).
///
/// Default to `null`
final MultiColor? borderColors;
/// Stroke of the border
///
/// Default to `null`
final double? stroke;
/// Drop shadow
///
/// Default to `null`
final BoxShadow? shadow;
/// Minimum size of the card
///
/// Default to `const Size(330, 0)`
final Size? minSize;
/// Maximum size of the card
///
/// Default to `const Size(double.infinity, double.infinity)`
final Size? maxSize;
/// Title text style
///
/// Default to `Theme.textTheme.titleLarge`
final TextStyle? titleStyle;
/// Subtitle text style
///
/// Default to `Theme.textTheme.titleMedium`
final TextStyle? subtitleStyle;
/// Body text style
///
/// Default to `Theme.textTheme.bodyMedium`
final TextStyle? bodyStyle;
@override
ThemeExtension<CardThemeExtension> copyWith({
BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding,
MultiColor? backgroundColors,
MultiColor? borderColors,
double? stroke,
BoxShadow? shadow,
Size? minSize,
Size? maxSize,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
}) =>
CardThemeExtension(
radius: radius ?? this.radius,
padding: padding ?? this.padding,
backgroundColors: backgroundColors ?? this.backgroundColors,
borderColors: borderColors ?? this.borderColors,
stroke: stroke ?? this.stroke,
shadow: shadow ?? this.shadow,
minSize: minSize ?? this.minSize,
maxSize: maxSize ?? this.maxSize,
titleStyle: titleStyle ?? this.titleStyle,
subtitleStyle: subtitleStyle ?? this.subtitleStyle,
bodyStyle: bodyStyle ?? this.bodyStyle,
);
@override
ThemeExtension<CardThemeExtension> lerp(
covariant ThemeExtension<CardThemeExtension>? other,
double t,
) {
if (other is! CardThemeExtension) {
return this;
}
return CardThemeExtension(
radius: BorderRadiusGeometry.lerp(radius, other.radius, t),
padding: EdgeInsetsGeometry.lerp(padding, other.padding, t),
backgroundColors:
MultiColor.lerp(backgroundColors, other.backgroundColors, t),
borderColors: MultiColor.lerp(borderColors, other.borderColors, t),
shadow: BoxShadow.lerp(shadow, other.shadow, t),
bodyStyle: TextStyle.lerp(bodyStyle, other.bodyStyle, t),
titleStyle: TextStyle.lerp(titleStyle, other.titleStyle, t),
subtitleStyle: TextStyle.lerp(subtitleStyle, other.subtitleStyle, t),
);
}
}

View File

@ -0,0 +1,69 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/src/domain/entities/text_inputs/text_input_style.dart';
class TextInputThemeExtension extends ThemeExtension<TextInputThemeExtension> {
const TextInputThemeExtension({
this.normalStyle,
this.focusedStyle,
this.invalidStyle,
this.disabledStyle,
});
/// The default style for TextInputs.
final TextInputStyle? normalStyle;
/// The style for TextInputs when they are focused.
final TextInputStyle? focusedStyle;
/// The style for TextInputs when they are invalid.
final TextInputStyle? invalidStyle;
/// The style for TextInputs when they are disabled.
final TextInputStyle? disabledStyle;
@override
ThemeExtension<TextInputThemeExtension> lerp(
covariant ThemeExtension<TextInputThemeExtension>? other,
double t,
) {
if (other is! TextInputThemeExtension) {
return this;
}
return TextInputThemeExtension(
normalStyle: TextInputStyle.lerp(normalStyle, other.normalStyle, t),
focusedStyle: TextInputStyle.lerp(focusedStyle, other.focusedStyle, t),
disabledStyle: TextInputStyle.lerp(disabledStyle, other.disabledStyle, t),
invalidStyle: TextInputStyle.lerp(invalidStyle, other.invalidStyle, t),
);
}
@override
ThemeExtension<TextInputThemeExtension> copyWith({
TextInputStyle? normalStyle,
TextInputStyle? focusedStyle,
TextInputStyle? disabledStyle,
TextInputStyle? invalidStyle,
}) =>
TextInputThemeExtension(
normalStyle: normalStyle ?? this.normalStyle,
focusedStyle: focusedStyle ?? this.focusedStyle,
disabledStyle: disabledStyle ?? this.disabledStyle,
invalidStyle: invalidStyle ?? this.invalidStyle,
);
}

View File

@ -0,0 +1,19 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
export 'button_theme_extension/button_theme_extension.dart';
export 'card_theme_extension.dart';
export 'text_input_theme_extension.dart';

View File

@ -15,5 +15,6 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
export 'core/core.dart'; export 'core/core.dart';
export 'data/data.dart';
export 'domain/domain.dart'; export 'domain/domain.dart';
export 'features/features.dart'; export 'features/features.dart';

View File

@ -17,8 +17,9 @@ class Bars extends DemoPage {
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: Image.asset('assets/images/studio_logo.png'), child: Image.asset('assets/images/studio_logo.png'),
), ),
title: 'Wyatt Studio'.wrap( title: const TextWrapper(
gradientColors: const MultiColor( 'Wyatt Studio',
gradientColors: MultiColor(
[ [
Color.fromRGBO(57, 167, 254, 1), Color.fromRGBO(57, 167, 254, 1),
Color.fromRGBO(71, 94, 241, 1), Color.fromRGBO(71, 94, 241, 1),
@ -35,8 +36,9 @@ class Bars extends DemoPage {
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: Image.asset('assets/images/studio_logo.png'), child: Image.asset('assets/images/studio_logo.png'),
), ),
title: 'Wyatt Studio'.wrap( title: const TextWrapper(
gradientColors: const MultiColor( 'Wyatt Studio',
gradientColors: MultiColor(
[ [
Color.fromRGBO(57, 167, 254, 1), Color.fromRGBO(57, 167, 254, 1),
Color.fromRGBO(71, 94, 241, 1), Color.fromRGBO(71, 94, 241, 1),
@ -67,21 +69,20 @@ class Bars extends DemoPage {
padding: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 20),
child: Image.asset('assets/images/studio_long_logo.png'), child: Image.asset('assets/images/studio_long_logo.png'),
), ),
actions: [ actions: const [
Padding( Padding(
padding: padding: EdgeInsets.symmetric(horizontal: 20, vertical: 25),
const EdgeInsets.symmetric(horizontal: 20, vertical: 25),
child: FlatButton( child: FlatButton(
label: 'Estimer mon projet'.wrap(), label: TextWrapper('Estimer mon projet'),
), ),
), ),
], ],
navigationItems: [ navigationItems: const [
'ACCEUIL'.wrap(), TextWrapper('ACCUEIL'),
'VOTRE PROGRAMME'.wrap(), TextWrapper('VOTRE PROGRAMME'),
'LE STUDIO'.wrap(), TextWrapper('LE STUDIO'),
'SAVOIR FAIRE'.wrap() TextWrapper('SAVOIR FAIRE')
].whereType<TextWrapper>().toList(), ],
), ),
], ],
); );

View File

@ -63,7 +63,7 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
title: const TextWrapper( title: const TextWrapper(
'Ajouter un fichier', 'Ajouter un fichier',
), ),
subTitle: const TextWrapper('Taille max: 20 Mo'), subtitle: const TextWrapper('Taille max: 20 Mo'),
), ),
const Gap(20), const Gap(20),
BlocProvider( BlocProvider(
@ -73,7 +73,7 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
title: const TextWrapper( title: const TextWrapper(
'Enabled', 'Enabled',
), ),
subTitle: const TextWrapper('Subtitle'), subtitle: const TextWrapper('subtitle'),
), ),
), ),
const Gap(20), const Gap(20),
@ -83,7 +83,7 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
title: const TextWrapper( title: const TextWrapper(
'Disabled', 'Disabled',
), ),
subTitle: const TextWrapper('Subtitle'), subtitle: const TextWrapper('subtitle'),
disabled: _disabled, disabled: _disabled,
), ),
const Gap(20), const Gap(20),
@ -94,7 +94,7 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
title: const TextWrapper( title: const TextWrapper(
'Hovered', 'Hovered',
), ),
subTitle: const TextWrapper('Subtitle'), subtitle: const TextWrapper('subtitle'),
), ),
), ),
const Gap(20), const Gap(20),
@ -105,7 +105,7 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
title: const TextWrapper( title: const TextWrapper(
'Focused', 'Focused',
), ),
subTitle: const TextWrapper('Subtitle'), subtitle: const TextWrapper('subtitle'),
), ),
), ),
const Gap(20), const Gap(20),
@ -116,7 +116,7 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
title: const TextWrapper( title: const TextWrapper(
'Tapped', 'Tapped',
), ),
subTitle: const TextWrapper('Subtitle'), subtitle: const TextWrapper('subtitle'),
), ),
), ),
const Gap(20), const Gap(20),
@ -127,7 +127,7 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
title: const TextWrapper( title: const TextWrapper(
'Invalid', 'Invalid',
), ),
subTitle: const TextWrapper('Subtitle'), subtitle: const TextWrapper('subtitle'),
), ),
), ),
const Gap(20), const Gap(20),
@ -154,7 +154,7 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
title: const TextWrapper( title: const TextWrapper(
'Dynamic', 'Dynamic',
), ),
subTitle: const TextWrapper('Subtitle'), subtitle: const TextWrapper('subtitle'),
disabled: _dynamic, disabled: _dynamic,
), ),
], ],

View File

@ -25,8 +25,8 @@ class InformationCards extends StatelessWidget {
FlutterLogo(size: 60), FlutterLogo(size: 60),
], ],
title: TextWrapper('Flutter'), title: TextWrapper('Flutter'),
subtitle: TextWrapper.text('One single code base.'), subtitle: TextWrapper('One single code base.'),
body: TextWrapper.text( body: TextWrapper(
'Cupidatat reprehenderit aliqua eiusmod Lorem. ' 'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'Qui ipsum id ea ea nulla labore aute ullamco aute ' 'Qui ipsum id ea ea nulla labore aute ullamco aute '
'quis elit ut amet velit. Incididunt fugiat proident ' 'quis elit ut amet velit. Incididunt fugiat proident '
@ -57,22 +57,23 @@ class InformationCards extends StatelessWidget {
FlutterLogo(size: 60), FlutterLogo(size: 60),
FlutterLogo(size: 60), FlutterLogo(size: 60),
], ],
title: 'Flutter'.wrap( title: const TextWrapper(
gradientColors: const MultiColor([Colors.blue, Colors.green]), 'Flutter',
gradientColors: MultiColor([Colors.blue, Colors.green]),
), ),
subtitle: const TextWrapper.text('One single code base.'), subtitle: const TextWrapper('One single code base.'),
body: 'Cupidatat reprehenderit aliqua eiusmod Lorem. ' body: const TextWrapper(
'Qui ipsum id ea ea nulla labore aute ullamco aute ' 'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'quis elit ut amet velit. Incididunt fugiat proident ' 'Qui ipsum id ea ea nulla labore aute ullamco aute '
'proident deserunt tempor Lorem cillum qui do ' 'quis elit ut amet velit. Incididunt fugiat proident '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit ' 'proident deserunt tempor Lorem cillum qui do '
'elit sint ex cupidatat ullamco Lorem amet elit ' 'ullamco Lorem magna ipsum. Ullamco cupidatat velit '
'ipsum sunt ex voluptate. Eiusmod quis laborum velit ' 'elit sint ex cupidatat ullamco Lorem amet elit '
'excepteur eu commodo consectetur qui exercitation ' 'ipsum sunt ex voluptate. Eiusmod quis laborum velit '
'officia consequat ullamco sit adipisicing. Ullamco ' 'excepteur eu commodo consectetur qui exercitation '
'magna cupidatat Lorem nulla cupidatat voluptate ' 'officia consequat ullamco sit adipisicing. Ullamco '
'irure ex reprehenderit.' 'magna cupidatat Lorem nulla cupidatat voluptate '
.wrap(), 'irure ex reprehenderit.'),
), ),
], ],
), ),
@ -81,26 +82,26 @@ class InformationCards extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
InformationCard( const InformationCard(
icons: const [ icons: [
FlutterLogo(size: 60), FlutterLogo(size: 60),
], ],
axis: Axis.horizontal, axis: Axis.horizontal,
title: const TextWrapper.text('Flutter'), title: TextWrapper('Flutter'),
subtitle: const TextWrapper.text('One single code base.'), subtitle: TextWrapper('One single code base.'),
body: 'Cupidatat reprehenderit aliqua eiusmod Lorem. ' body: TextWrapper(
'Qui ipsum id ea ea nulla labore aute ullamco aute ' 'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'quis elit ut amet velit. Incididunt fugiat proident ' 'Qui ipsum id ea ea nulla labore aute ullamco aute '
'proident deserunt tempor Lorem cillum qui do ' 'quis elit ut amet velit. Incididunt fugiat proident '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit ' 'proident deserunt tempor Lorem cillum qui do '
'elit sint ex cupidatat ullamco Lorem amet elit ' 'ullamco Lorem magna ipsum. Ullamco cupidatat velit '
'ipsum sunt ex voluptate. Eiusmod quis laborum velit ' 'elit sint ex cupidatat ullamco Lorem amet elit '
'excepteur eu commodo consectetur qui exercitation ' 'ipsum sunt ex voluptate. Eiusmod quis laborum velit '
'officia consequat ullamco sit adipisicing. Ullamco ' 'excepteur eu commodo consectetur qui exercitation '
'magna cupidatat Lorem nulla cupidatat voluptate ' 'officia consequat ullamco sit adipisicing. Ullamco '
'irure ex reprehenderit.' 'magna cupidatat Lorem nulla cupidatat voluptate '
.wrap( 'irure ex reprehenderit.',
gradientColors: const MultiColor([ gradientColors: MultiColor([
Colors.red, Colors.red,
Colors.orange, Colors.orange,
]), ]),
@ -123,14 +124,15 @@ class InformationCards extends StatelessWidget {
FlutterLogo(size: 60), FlutterLogo(size: 60),
], ],
axis: Axis.horizontal, axis: Axis.horizontal,
title: const TextWrapper.text('Flutter'), title: const TextWrapper('Flutter'),
subtitle: 'One single code base.'.wrap( subtitle: TextWrapper(
// gradient: [Colors.blue, Colors.green], 'One single code base.',
style: const TextStyle( style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontSize: 15,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
body: const TextWrapper.text( body: const TextWrapper(
'Cupidatat reprehenderit aliqua eiusmod Lorem. ' 'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'Qui ipsum id ea ea nulla labore aute ullamco aute ' 'Qui ipsum id ea ea nulla labore aute ullamco aute '
'quis elit ut amet velit. Incididunt fugiat proident ' 'quis elit ut amet velit. Incididunt fugiat proident '

View File

@ -44,7 +44,7 @@ class PortfolioCards extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
) )
], ],
keyword: const [ keywords: const [
TextWrapper('UI Design'), TextWrapper('UI Design'),
TextWrapper('Developpement'), TextWrapper('Developpement'),
TextWrapper('Deploiement') TextWrapper('Deploiement')
@ -52,7 +52,7 @@ class PortfolioCards extends StatelessWidget {
), ),
const Gap(20), const Gap(20),
PortfolioCard( PortfolioCard(
showImagesOnTop: true, showAssetsOnTop: true,
logo: const FlutterLogo( logo: const FlutterLogo(
size: 50, size: 50,
), ),
@ -115,7 +115,7 @@ class PortfolioCards extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
) )
], ],
keyword: const [ keywords: const [
TextWrapper('UI Design'), TextWrapper('UI Design'),
TextWrapper('Developpement'), TextWrapper('Developpement'),
TextWrapper('Deploiement') TextWrapper('Deploiement')
@ -163,7 +163,7 @@ class PortfolioCards extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
) )
], ],
keyword: const [ keywords: const [
TextWrapper('UI Design'), TextWrapper('UI Design'),
TextWrapper('Developpement'), TextWrapper('Developpement'),
TextWrapper('Deploiement') TextWrapper('Deploiement')

View File

@ -33,33 +33,33 @@ class QuoteCards extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: const [
QuoteCard( QuoteCard(
quote: 'Cupidatat reprehenderit aliqua eiusmod Lorem. ' quote:
TextWrapper('Cupidatat reprehenderit aliqua eiusmod Lorem. '
'Qui ipsum id ea ea nulla labore aute ullamco aute ' 'Qui ipsum id ea ea nulla labore aute ullamco aute '
'quis elit ut amet velit. Incididunt fugiat proident ' 'quis elit ut amet velit. Incididunt fugiat proident '
'proident deserunt tempor Lorem cillum qui do ' 'proident deserunt tempor Lorem cillum qui do '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit ' 'ullamco Lorem magna ipsum. Ullamco cupidatat velit '),
.wrap(),
), ),
const Gap(20), Gap(20),
QuoteCard( QuoteCard(
quote: 'Cupidatat reprehenderit aliqua eiusmod Lorem. ' quote: TextWrapper(
'Qui ipsum id ea ea nulla labore aute ullamco aute ' 'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'quis elit ut amet velit. Incididunt fugiat proident ' 'Qui ipsum id ea ea nulla labore aute ullamco aute '
'proident deserunt tempor Lorem cillum qui do ' 'quis elit ut amet velit. Incididunt fugiat proident '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit ' 'proident deserunt tempor Lorem cillum qui do '
.wrap( 'ullamco Lorem magna ipsum. Ullamco cupidatat velit ',
gradientColors: const MultiColor([ gradientColors: MultiColor([
Colors.red, Colors.red,
Colors.orange, Colors.orange,
]), ]),
), ),
avatar: const FlutterLogo( avatar: FlutterLogo(
size: 40, size: 40,
), ),
name: 'John Doe'.wrap(), name: TextWrapper('John Doe'),
subtitle: 'Agence anonyme'.wrap(), subtitle: TextWrapper('Agence anonyme'),
), ),
], ],
), ),

View File

@ -35,58 +35,61 @@ class SkillCards extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SkillCard( SkillCard(
gradient: const [Colors.red, Colors.orange], icons: [
icon: Container( Container(
padding: const EdgeInsets.all(15), padding: const EdgeInsets.all(15),
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: Colors.white.withOpacity(0.04), color: Colors.white.withOpacity(0.04),
), ),
child: const GradientIcon( child: GradientIcon(
Icons.ac_unit_sharp, icon: Icons.ac_unit_sharp,
gradient: gradientColors:
LinearGradient(colors: [Colors.red, Colors.orange]), const MultiColor([Colors.red, Colors.orange]),
), ),
), )
title: 'Lorem Ipsum'.wrap(), ],
description: 'Cupidatat reprehenderit aliqua eiusmod Lorem. ' bulletColors: const MultiColor([Colors.red, Colors.orange]),
'Qui ipsum id ea ea nulla labore aute ullamco aute ' title: const TextWrapper('Lorem Ipsum'),
'quis elit ut amet velit. Incididunt fugiat proident ' description: const TextWrapper(
'proident deserunt tempor Lorem cillum qui do ' 'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit ' 'Qui ipsum id ea ea nulla labore aute ullamco aute '
.wrap(), 'quis elit ut amet velit. Incididunt fugiat proident '
'proident deserunt tempor Lorem cillum qui do '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit '),
skills: const [ skills: const [
TextWrapper.text('Firebase'), TextWrapper('Firebase'),
TextWrapper.text( TextWrapper(
'Qui ipsum id ea ea nulla labore aute ullamco aute ', 'Qui ipsum id ea ea nulla labore aute ullamco aute ',
), ),
], ],
), ),
const Gap(20), const Gap(20),
SkillCard( SkillCard(
gradient: const [Colors.blue, Colors.green], icons: [
icon: Container( Container(
padding: const EdgeInsets.all(15), padding: const EdgeInsets.all(15),
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: Colors.white.withOpacity(0.04), color: Colors.white.withOpacity(0.04),
),
child: const GradientIcon(
Icons.ac_unit_sharp,
gradient: LinearGradient(
colors: [Colors.blue, Colors.green],
), ),
), child: GradientIcon(
), icon: Icons.ac_unit_sharp,
title: 'Lorem Ipsum'.wrap(), gradientColors:
description: 'Cupidatat reprehenderit aliqua eiusmod Lorem. ' const MultiColor([Colors.blue, Colors.green]),
'Qui ipsum id ea ea nulla labore aute ullamco aute ' ),
'quis elit ut amet velit. Incididunt fugiat proident ' )
'proident deserunt tempor Lorem cillum qui do ' ],
'ullamco Lorem magna ipsum. Ullamco cupidatat velit ' bulletColors: const MultiColor([Colors.blue, Colors.green]),
.wrap(), title: const TextWrapper('Lorem Ipsum'),
description: const TextWrapper(
'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'Qui ipsum id ea ea nulla labore aute ullamco aute '
'quis elit ut amet velit. Incididunt fugiat proident '
'proident deserunt tempor Lorem cillum qui do '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit '),
skills: const [ skills: const [
TextWrapper.text('Firebase'), TextWrapper('Firebase'),
TextWrapper( TextWrapper(
'Qui ipsum id ea ea nulla labore aute ullamco aute ', 'Qui ipsum id ea ea nulla labore aute ullamco aute ',
gradientColors: MultiColor([ gradientColors: MultiColor([
@ -94,11 +97,11 @@ class SkillCards extends StatelessWidget {
Colors.orange, Colors.orange,
]), ]),
), ),
TextWrapper.text('Firebase'), TextWrapper('Firebase'),
TextWrapper.text('Firebase'), TextWrapper('Firebase'),
TextWrapper.text('Firebase'), TextWrapper('Firebase'),
TextWrapper.text('Firebase'), TextWrapper('Firebase'),
TextWrapper.text('Firebase'), TextWrapper('Firebase'),
], ],
), ),
], ],

View File

@ -75,7 +75,7 @@ class _TextInputsCoreState extends State<TextInputsCore> {
key: _formKey6, key: _formKey6,
controller: _controller6, controller: _controller6,
focusNode: _focusNode6, focusNode: _focusNode6,
label: 'Nom / Prénom'.wrap(), label: const TextWrapper('Nom / Prénom'),
onError: (value) => 'Erreur : ${value.length} > 5.', onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5, validator: (value) => value.length > 5,
), ),
@ -85,7 +85,7 @@ class _TextInputsCoreState extends State<TextInputsCore> {
enabled: _enable, enabled: _enable,
controller: _controller, controller: _controller,
focusNode: _focusNode, focusNode: _focusNode,
label: 'Nom / Prénom'.wrap(), label: const TextWrapper('Nom / Prénom'),
onError: (value) => 'Erreur : ${value.length} > 5.', onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5, validator: (value) => value.length > 5,
), ),
@ -105,7 +105,7 @@ class _TextInputsCoreState extends State<TextInputsCore> {
controller: _controller3, controller: _controller3,
focusNode: _focusNode3, focusNode: _focusNode3,
expand: false, expand: false,
label: 'Nom / Prénom'.wrap(), label: const TextWrapper('Nom / Prénom'),
onError: (value) => 'Erreur : ${value.length} > 5.', onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5, validator: (value) => value.length > 5,
onChanged: (value) {}, onChanged: (value) {},
@ -116,7 +116,7 @@ class _TextInputsCoreState extends State<TextInputsCore> {
expand: false, expand: false,
controller: _controller4, controller: _controller4,
focusNode: _focusNode4, focusNode: _focusNode4,
label: 'Nom / Prénom'.wrap(), label: const TextWrapper('Nom / Prénom'),
maxLines: 3, maxLines: 3,
onError: (value) => 'Erreur : ${value.length} > 5.', onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5, validator: (value) => value.length > 5,
@ -129,7 +129,7 @@ class _TextInputsCoreState extends State<TextInputsCore> {
suffixIcon: const Icon(Icons.architecture), suffixIcon: const Icon(Icons.architecture),
controller: _controller5, controller: _controller5,
focusNode: _focusNode5, focusNode: _focusNode5,
label: 'Nom / Prénom'.wrap(), label: const TextWrapper('Nom / Prénom'),
onError: (value) => 'Erreur : ${value.length} > 5.', onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5, validator: (value) => value.length > 5,
), ),

View File

@ -1,127 +0,0 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class CardTheme extends CardThemeExtension {
const CardTheme({
super.backgroundColors,
super.body,
super.borderColors,
super.secondaryBackgroundColor,
super.shadowColor,
super.subtitle,
super.title,
});
factory CardTheme.light() => CardTheme(
backgroundColors: const MultiColor.single(Color(0xFFF6F6F6)),
secondaryBackgroundColor: Colors.white,
borderColors: const MultiColor([
Color(0xFFDDE0E3),
Color(0xFFCACCD4),
]),
title: GoogleFonts.montserrat(
fontSize: 24,
fontWeight: FontWeight.w500,
color: const Color(0xFF24262A),
),
subtitle: GoogleFonts.montserrat(
fontSize: 15,
fontWeight: FontWeight.w300,
color: const Color(0xFF24262A),
),
body: GoogleFonts.montserrat(
fontSize: 12,
fontWeight: FontWeight.w300,
height: 1.7,
color: const Color(0xFF24262A),
),
);
factory CardTheme.dark() => CardTheme(
backgroundColors:
MultiColor.single(const Color(0xFFFFFFFF).withOpacity(0.04)),
secondaryBackgroundColor: const Color(0xFFFFFFFF).withOpacity(0.04),
borderColors: const MultiColor([
Color(0xFF60656A),
Color(0xFF383C40),
]),
title: GoogleFonts.montserrat(
fontSize: 24,
fontWeight: FontWeight.w500,
color: const Color(0xFFFFFFFF),
),
subtitle: GoogleFonts.montserrat(
fontSize: 15,
fontWeight: FontWeight.w300,
color: const Color(0xFFFFFFFF),
),
body: GoogleFonts.montserrat(
fontSize: 12,
fontWeight: FontWeight.w300,
height: 1.7,
color: const Color(0xFFFFFFFF),
),
);
@override
ThemeExtension<CardThemeExtension> copyWith({
MultiColor? backgroundColors,
Color? secondaryBackgroundColor,
MultiColor? borderColors,
BoxShadow? shadowColor,
TextStyle? body,
TextStyle? title,
TextStyle? subtitle,
}) =>
CardTheme(
backgroundColors: backgroundColors ?? this.backgroundColors,
secondaryBackgroundColor:
secondaryBackgroundColor ?? this.secondaryBackgroundColor,
borderColors: borderColors ?? this.borderColors,
shadowColor: shadowColor ?? this.shadowColor,
body: body ?? this.body,
title: title ?? this.title,
subtitle: subtitle ?? this.subtitle,
);
@override
ThemeExtension<CardThemeExtension> lerp(
covariant ThemeExtension<CardThemeExtension>? other,
double t,
) {
if (other is! CardTheme) {
return this;
}
return CardTheme(
backgroundColors: other.backgroundColors,
secondaryBackgroundColor: Color.lerp(
secondaryBackgroundColor,
other.secondaryBackgroundColor,
t,
),
borderColors: other.borderColors,
shadowColor: BoxShadow.lerp(shadowColor, other.shadowColor, t),
body: TextStyle.lerp(body, other.body, t),
title: TextStyle.lerp(title, other.title, t),
subtitle: TextStyle.lerp(subtitle, other.subtitle, t),
);
}
}

View File

@ -1,172 +0,0 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart';
class FileSelectionButtonTheme extends FileSelectionButtonThemeExtension {
const FileSelectionButtonTheme({
super.disabledStyle,
super.focusedStyle,
super.hoveredStyle,
super.normalStyle,
super.tappedStyle,
super.selectedStyle,
super.invalidStyle,
});
factory FileSelectionButtonTheme.light() {
final style = FileSelectionButtonStyle(
title: GoogleFonts.montserrat(
fontSize: 16,
fontWeight: FontWeight.w400,
),
subTitle: GoogleFonts.montserrat(
fontSize: 11,
fontWeight: FontWeight.w400,
),
radius: BorderRadius.circular(12),
padding: const EdgeInsets.all(13),
foregroundColors: const MultiColor.single(Constants.grey2),
backgroundColors: MultiColor.single(Constants.white.withOpacity(0.04)),
borderColors: const MultiColor(Constants.greyGradient),
stroke: 2,
);
return FileSelectionButtonTheme(
normalStyle: style,
disabledStyle: style.copyWith(
foregroundColors: MultiColor.single(Constants.grey1.withOpacity(0.4)),
backgroundColors: const MultiColor.single(Constants.white),
borderColors: MultiColor.single(Constants.grey1.withOpacity(0.4)),
),
hoveredStyle: style.copyWith(
backgroundColors: MultiColor.single(Constants.grey1.withOpacity(0.4)),
),
focusedStyle: style.copyWith(stroke: 4),
tappedStyle: style.copyWith(
backgroundColors: MultiColor.single(Constants.grey1.withOpacity(0.4)),
),
invalidStyle: style.copyWith(
subTitle: GoogleFonts.montserrat(
fontSize: 11,
fontWeight: FontWeight.w400,
color: Constants.red1,
),
borderColors: const MultiColor(Constants.redGradient),
),
// Unused
selectedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Constants.grey2),
borderColors: const MultiColor(Constants.greenGradient),
),
);
}
factory FileSelectionButtonTheme.dark() {
final style = FileSelectionButtonStyle(
title: GoogleFonts.montserrat(
fontSize: 16,
fontWeight: FontWeight.w400,
),
subTitle: GoogleFonts.montserrat(
fontSize: 11,
fontWeight: FontWeight.w400,
),
radius: BorderRadius.circular(12),
padding: const EdgeInsets.all(13),
foregroundColors: const MultiColor.single(Constants.white),
backgroundColors: MultiColor.single(Constants.white.withOpacity(0.04)),
borderColors: const MultiColor(Constants.greyGradient),
stroke: 1,
);
return FileSelectionButtonTheme(
normalStyle: style,
disabledStyle: style.copyWith(
foregroundColors: const MultiColor.single(Constants.grey1),
backgroundColors: const MultiColor.single(Constants.grey4),
),
hoveredStyle: style.copyWith(
borderColors: const MultiColor.single(Constants.white),
),
focusedStyle: style.copyWith(stroke: 3),
tappedStyle: style.copyWith(
backgroundColors: const MultiColor(Constants.greyDarkGradient),
),
invalidStyle: style.copyWith(
subTitle: GoogleFonts.montserrat(
fontSize: 11,
fontWeight: FontWeight.w400,
color: Constants.red1,
),
borderColors: const MultiColor(Constants.redGradient),
),
// Unused
selectedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Constants.white),
borderColors: const MultiColor(Constants.greenGradient),
),
);
}
@override
ThemeExtension<FileSelectionButtonThemeExtension> copyWith({
FileSelectionButtonStyle? disabledStyle,
FileSelectionButtonStyle? focusedStyle,
FileSelectionButtonStyle? hoveredStyle,
FileSelectionButtonStyle? normalStyle,
FileSelectionButtonStyle? tappedStyle,
FileSelectionButtonStyle? selectedStyle,
FileSelectionButtonStyle? invalidStyle,
}) =>
FileSelectionButtonTheme(
disabledStyle: disabledStyle ?? this.disabledStyle,
focusedStyle: focusedStyle ?? this.focusedStyle,
hoveredStyle: hoveredStyle ?? this.hoveredStyle,
normalStyle: normalStyle ?? this.normalStyle,
tappedStyle: tappedStyle ?? this.tappedStyle,
selectedStyle: selectedStyle ?? this.selectedStyle,
invalidStyle: invalidStyle ?? this.invalidStyle,
);
@override
ThemeExtension<FileSelectionButtonThemeExtension> lerp(
covariant ThemeExtension<FileSelectionButtonThemeExtension>? other,
double t,
) {
if (other is! FileSelectionButtonTheme) {
return this;
}
return FileSelectionButtonTheme(
disabledStyle:
FileSelectionButtonStyle.lerp(disabledStyle, other.disabledStyle, t),
focusedStyle:
FileSelectionButtonStyle.lerp(focusedStyle, other.focusedStyle, t),
hoveredStyle:
FileSelectionButtonStyle.lerp(hoveredStyle, other.hoveredStyle, t),
normalStyle:
FileSelectionButtonStyle.lerp(normalStyle, other.normalStyle, t),
tappedStyle:
FileSelectionButtonStyle.lerp(tappedStyle, other.tappedStyle, t),
selectedStyle:
FileSelectionButtonStyle.lerp(selectedStyle, other.selectedStyle, t),
invalidStyle:
FileSelectionButtonStyle.lerp(invalidStyle, other.invalidStyle, t),
);
}
}

View File

@ -1,153 +0,0 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart';
class FlatButtonTheme extends FlatButtonThemeExtension {
const FlatButtonTheme({
super.disabledStyle,
super.focusedStyle,
super.hoveredStyle,
super.normalStyle,
super.tappedStyle,
});
factory FlatButtonTheme.light() {
final style = FlatButtonStyle(
label: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w600,
),
radius: BorderRadius.circular(15),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor(Constants.blueGradient),
backgroundColors: const MultiColor.single(Constants.white),
borderColors: const MultiColor(Constants.blueGradient),
stroke: 3,
);
return FlatButtonTheme(
normalStyle: style,
disabledStyle: style.copyWith(
label: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Constants.blue1.withOpacity(0.4),
),
foregroundColors: MultiColor.single(Constants.blue1.withOpacity(0.4)),
backgroundColors: const MultiColor.single(Constants.white),
borderColors: MultiColor.single(Constants.blue1.withOpacity(0.4)),
stroke: 1,
),
hoveredStyle: style.copyWith(
label: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Constants.white,
),
foregroundColors: const MultiColor.single(Constants.white),
backgroundColors: const MultiColor(Constants.blueGradient),
),
focusedStyle: style.copyWith(stroke: 5),
tappedStyle: style.copyWith(
label: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Constants.white,
),
foregroundColors: const MultiColor.single(Constants.white),
backgroundColors: const MultiColor(Constants.blueDarkGradient),
borderColors: const MultiColor(Constants.blueDarkGradient),
),
);
}
factory FlatButtonTheme.dark() {
final style = FlatButtonStyle(
label: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w600,
),
radius: BorderRadius.circular(15),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor.single(Constants.white),
backgroundColors: const MultiColor.single(Constants.dark),
borderColors: const MultiColor(Constants.blueGradient),
stroke: 3,
);
return FlatButtonTheme(
normalStyle: style,
disabledStyle: style.copyWith(
label: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Constants.grey1,
),
foregroundColors: const MultiColor.single(Constants.grey1),
backgroundColors: const MultiColor.single(Constants.grey4),
borderColors: const MultiColor(Constants.greyGradient),
stroke: 1,
),
hoveredStyle: style.copyWith(
foregroundColors: const MultiColor.single(Constants.white),
backgroundColors: const MultiColor(Constants.blueGradient),
),
focusedStyle: style.copyWith(stroke: 5),
tappedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Constants.white),
backgroundColors: const MultiColor(Constants.blueDarkGradient),
borderColors: const MultiColor(Constants.blueDarkGradient),
),
);
}
@override
ThemeExtension<FlatButtonThemeExtension> copyWith({
FlatButtonStyle? disabledStyle,
FlatButtonStyle? focusedStyle,
FlatButtonStyle? hoveredStyle,
FlatButtonStyle? normalStyle,
FlatButtonStyle? tappedStyle,
}) =>
FlatButtonTheme(
disabledStyle: disabledStyle ?? this.disabledStyle,
focusedStyle: focusedStyle ?? this.focusedStyle,
hoveredStyle: hoveredStyle ?? this.hoveredStyle,
normalStyle: normalStyle ?? this.normalStyle,
tappedStyle: tappedStyle ?? this.tappedStyle,
);
@override
ThemeExtension<FlatButtonThemeExtension> lerp(
covariant ThemeExtension<FlatButtonThemeExtension>? other,
double t,
) {
if (other is! FlatButtonTheme) {
return this;
}
return FlatButtonTheme(
disabledStyle:
FlatButtonStyle.lerp(disabledStyle, other.disabledStyle, t),
focusedStyle: FlatButtonStyle.lerp(focusedStyle, other.focusedStyle, t),
hoveredStyle: FlatButtonStyle.lerp(hoveredStyle, other.hoveredStyle, t),
normalStyle: FlatButtonStyle.lerp(normalStyle, other.normalStyle, t),
tappedStyle: FlatButtonStyle.lerp(tappedStyle, other.tappedStyle, t),
);
}
}

View File

@ -1,157 +0,0 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart';
class SymbolButtonTheme extends SymbolButtonThemeExtension {
const SymbolButtonTheme({
super.disabledStyle,
super.focusedStyle,
super.hoveredStyle,
super.normalStyle,
super.tappedStyle,
super.selectedStyle,
});
factory SymbolButtonTheme.light() {
final style = SymbolButtonStyle(
label: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w400,
),
dimension: 60,
radius: BorderRadius.circular(12),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor.single(Constants.grey2),
backgroundColors: MultiColor.single(Constants.white.withOpacity(0.04)),
borderColors: const MultiColor(Constants.greyGradient),
stroke: 2,
);
return SymbolButtonTheme(
normalStyle: style,
disabledStyle: style.copyWith(
label: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Constants.grey1,
),
foregroundColors: MultiColor.single(Constants.grey1.withOpacity(0.4)),
backgroundColors: const MultiColor.single(Constants.white),
borderColors: MultiColor.single(Constants.grey1.withOpacity(0.4)),
),
hoveredStyle: style.copyWith(
backgroundColors: MultiColor.single(Constants.grey1.withOpacity(0.4)),
),
focusedStyle: style.copyWith(stroke: 4),
tappedStyle: style.copyWith(
backgroundColors: MultiColor.single(Constants.grey1.withOpacity(0.4)),
),
selectedStyle: style.copyWith(
label: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w600,
),
foregroundColors: const MultiColor.single(Constants.grey2),
borderColors: const MultiColor(Constants.greenGradient),
),
);
}
factory SymbolButtonTheme.dark() {
final style = SymbolButtonStyle(
label: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w400,
),
dimension: 60,
radius: BorderRadius.circular(12),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor.single(Constants.white),
backgroundColors: MultiColor.single(Constants.white.withOpacity(0.04)),
borderColors: const MultiColor(Constants.greyGradient),
stroke: 2,
);
return SymbolButtonTheme(
normalStyle: style,
disabledStyle: style.copyWith(
label: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Constants.grey1,
),
foregroundColors: const MultiColor.single(Constants.grey1),
backgroundColors: const MultiColor.single(Constants.grey4),
),
hoveredStyle: style.copyWith(
backgroundColors: const MultiColor(Constants.greyDarkGradient),
),
focusedStyle: style.copyWith(stroke: 4),
tappedStyle: style.copyWith(
backgroundColors: const MultiColor(Constants.greyDarkGradient),
),
selectedStyle: style.copyWith(
label: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w600,
),
foregroundColors: const MultiColor.single(Constants.white),
borderColors: const MultiColor(Constants.greenGradient),
),
);
}
@override
ThemeExtension<SymbolButtonThemeExtension> copyWith({
SymbolButtonStyle? disabledStyle,
SymbolButtonStyle? focusedStyle,
SymbolButtonStyle? hoveredStyle,
SymbolButtonStyle? normalStyle,
SymbolButtonStyle? tappedStyle,
SymbolButtonStyle? selectedStyle,
}) =>
SymbolButtonTheme(
disabledStyle: disabledStyle ?? this.disabledStyle,
focusedStyle: focusedStyle ?? this.focusedStyle,
hoveredStyle: hoveredStyle ?? this.hoveredStyle,
normalStyle: normalStyle ?? this.normalStyle,
tappedStyle: tappedStyle ?? this.tappedStyle,
selectedStyle: selectedStyle ?? this.selectedStyle,
);
@override
ThemeExtension<SymbolButtonThemeExtension> lerp(
covariant ThemeExtension<SymbolButtonThemeExtension>? other,
double t,
) {
if (other is! SymbolButtonTheme) {
return this;
}
return SymbolButtonTheme(
disabledStyle:
SymbolButtonStyle.lerp(disabledStyle, other.disabledStyle, t),
focusedStyle: SymbolButtonStyle.lerp(focusedStyle, other.focusedStyle, t),
hoveredStyle: SymbolButtonStyle.lerp(hoveredStyle, other.hoveredStyle, t),
normalStyle: SymbolButtonStyle.lerp(normalStyle, other.normalStyle, t),
tappedStyle: SymbolButtonStyle.lerp(tappedStyle, other.tappedStyle, t),
selectedStyle:
SymbolButtonStyle.lerp(selectedStyle, other.selectedStyle, t),
);
}
}

View File

@ -1,161 +0,0 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class TextInputTheme extends TextInputThemeExtension {
const TextInputTheme({
super.normalStyle,
super.focusedStyle,
super.disableStyle,
super.errorStyle,
});
factory TextInputTheme.light() => TextInputTheme(
normalStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(221, 224, 227, 1),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
),
focusedStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(60, 125, 251, 1),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
),
errorStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(244, 68, 100, 1),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(244, 68, 100, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
),
disableStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(229, 231, 235, 1),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(156, 163, 175, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(156, 163, 175, 1),
),
),
);
factory TextInputTheme.dark() => TextInputTheme(
normalStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(96, 101, 106, 1),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(204, 204, 204, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
focusedStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(60, 125, 251, 1),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(204, 204, 204, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
errorStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(244, 68, 100, 1),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(244, 68, 100, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
disableStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(96, 101, 106, 1),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(96, 101, 106, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
);
@override
ThemeExtension<TextInputThemeExtension> lerp(
covariant ThemeExtension<TextInputThemeExtension>? other,
double t,
) {
if (other is! TextInputTheme) {
return this;
}
return TextInputTheme(
normalStyle: TextInputStyle.lerp(normalStyle, other.normalStyle, t),
focusedStyle: TextInputStyle.lerp(focusedStyle, other.focusedStyle, t),
disableStyle: TextInputStyle.lerp(disableStyle, other.disableStyle, t),
errorStyle: TextInputStyle.lerp(errorStyle, other.errorStyle, t),
);
}
@override
ThemeExtension<TextInputThemeExtension> copyWith({
TextInputStyle? normalStyle,
TextInputStyle? focusedStyle,
TextInputStyle? disableStyle,
TextInputStyle? errorStyle,
}) =>
TextInputTheme(
normalStyle: normalStyle ?? this.normalStyle,
focusedStyle: focusedStyle ?? this.focusedStyle,
disableStyle: disableStyle ?? this.disableStyle,
errorStyle: errorStyle ?? this.errorStyle,
);
}

View File

@ -17,24 +17,20 @@
import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:flutter/material.dart' hide CardTheme; import 'package:flutter/material.dart' hide CardTheme;
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_kit_example/theme/card_theme.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit_example/theme/file_selection_button_theme.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/flat_button_theme.dart';
import 'package:wyatt_ui_kit_example/theme/loader_theme.dart'; import 'package:wyatt_ui_kit_example/theme/loader_theme.dart';
import 'package:wyatt_ui_kit_example/theme/rich_text_builder_theme.dart'; import 'package:wyatt_ui_kit_example/theme/rich_text_builder_theme.dart';
import 'package:wyatt_ui_kit_example/theme/simple_icon_button_theme.dart';
import 'package:wyatt_ui_kit_example/theme/symbol_button_theme.dart';
import 'package:wyatt_ui_kit_example/theme/text_input_theme.dart';
import 'package:wyatt_ui_kit_example/theme/top_bar_theme.dart'; import 'package:wyatt_ui_kit_example/theme/top_bar_theme.dart';
/// Easely switch between Material and Studio themes. /// Easely switch between Material and Studio themes.
abstract class Themes { abstract class Themes {
static int currentThemeIndex = 0; static int currentThemeIndex = 0;
static List<Set<ThemeData>> themes = [ static List<Set<ThemeData>> get themes => [
{materialLight, materialDark}, {materialLight, materialDark},
{studioLight, studioDark}, {studioLight, studioDark},
]; ];
static ThemeData lightFromTheme(int themeId) { static ThemeData lightFromTheme(int themeId) {
currentThemeIndex = themeId; currentThemeIndex = themeId;
@ -67,66 +63,114 @@ abstract class Themes {
); );
} }
static ThemeData get materialLight => ThemeData.light(); static ThemeData get materialLight => ThemeData.light().copyWith(
textTheme: GoogleFonts.robotoTextTheme(
static ThemeData get studioLight => materialLight.copyWith( ThemeData.light().textTheme,
appBarTheme: AppBarTheme(
foregroundColor: const Color(0xFF24262A),
backgroundColor: const Color(0xFFFFFFFF),
titleTextStyle: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w500,
color: const Color(0xFF24262A),
),
), ),
scaffoldBackgroundColor: Colors.white,
extensions: <ThemeExtension<dynamic>>[ extensions: <ThemeExtension<dynamic>>[
// Cards // Cards
CardTheme.light(), CardThemeExtensionDefault.light(),
// Buttons // Buttons
FlatButtonTheme.light(), FileSelectionButtonThemeExtensionDefault.light(),
SymbolButtonTheme.light(), FlatButtonThemeExtensionDefault.light(),
SimpleIconButtonTheme.light(), SimpleIconButtonThemeExtensionDefault.light(),
FileSelectionButtonTheme.light(), SymbolButtonThemeExtensionDefault.light(),
// Loader // TextInput
LoaderTheme.light(), TextInputThemeExtensionDefault.light(),
// Rich Text
RichTextBuilderTheme.light(),
TextInputTheme.light(),
TopAppBarTheme.light(),
], ],
); );
static ThemeData get materialDark => ThemeData.dark(); static ThemeData get studioLight {
final theme = ThemeData.light().copyWith(
appBarTheme: AppBarTheme(
foregroundColor: const Color(0xFF24262A),
backgroundColor: const Color(0xFFFFFFFF),
titleTextStyle: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w500,
color: const Color(0xFF24262A),
),
),
scaffoldBackgroundColor: Colors.white,
textTheme: GoogleFonts.montserratTextTheme(
ThemeData.light().textTheme,
),
);
static ThemeData get studioDark => materialDark.copyWith( return theme.copyWith(
appBarTheme: AppBarTheme( extensions: <ThemeExtension<dynamic>>[
foregroundColor: const Color(0xFFFFFFFF), // Cards
backgroundColor: const Color(0xFF383C40), CardThemeExtensionImpl.light(theme: theme),
titleTextStyle: GoogleFonts.montserrat( // Buttons
fontSize: 18, FileSelectionButtonThemeExtensionImpl.light(theme: theme),
fontWeight: FontWeight.w500, FlatButtonThemeExtensionImpl.light(theme: theme),
color: const Color(0xFFFFFFFF), SimpleIconButtonThemeExtensionImpl.light(theme: theme),
), SymbolButtonThemeExtensionImpl.light(theme: theme),
// Loader
LoaderTheme.light(),
// Rich Text
RichTextBuilderTheme.light(),
// TextInput
TextInputThemeExtensionImpl.light(theme: theme),
TopAppBarTheme.light(),
],
);
}
static ThemeData get materialDark => ThemeData.dark().copyWith(
textTheme: GoogleFonts.robotoTextTheme(
ThemeData.dark().textTheme,
), ),
drawerTheme: const DrawerThemeData(
backgroundColor: Color(0xFF383C40),
),
scaffoldBackgroundColor: const Color(0xFF383C40),
extensions: <ThemeExtension<dynamic>>[ extensions: <ThemeExtension<dynamic>>[
// Cards // Cards
CardTheme.dark(), CardThemeExtensionDefault.dark(),
// Buttons // Buttons
FlatButtonTheme.dark(), FileSelectionButtonThemeExtensionDefault.dark(),
SymbolButtonTheme.dark(), FlatButtonThemeExtensionDefault.dark(),
SimpleIconButtonTheme.dark(), SimpleIconButtonThemeExtensionDefault.dark(),
FileSelectionButtonTheme.dark(), SymbolButtonThemeExtensionDefault.dark(),
// Loader // TextInput
LoaderTheme.dark(), TextInputThemeExtensionDefault.dark(),
// Rich Text
RichTextBuilderTheme.dark(),
TextInputTheme.dark(),
TopAppBarTheme.dark(),
], ],
); );
static ThemeData get studioDark {
final theme = ThemeData.dark().copyWith(
appBarTheme: AppBarTheme(
foregroundColor: const Color(0xFFFFFFFF),
backgroundColor: const Color(0xFF2B3139),
titleTextStyle: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w500,
color: const Color(0xFFFFFFFF),
),
),
drawerTheme: const DrawerThemeData(
backgroundColor: Color(0xFF383C40),
),
scaffoldBackgroundColor: const Color(0xFF171A1E),
textTheme: GoogleFonts.montserratTextTheme(
ThemeData.dark().textTheme,
),
);
return theme.copyWith(
extensions: <ThemeExtension<dynamic>>[
// Cards
CardThemeExtensionImpl.dark(theme: theme),
// Buttons
FileSelectionButtonThemeExtensionImpl.dark(theme: theme),
FlatButtonThemeExtensionImpl.dark(theme: theme),
SimpleIconButtonThemeExtensionImpl.dark(theme: theme),
SymbolButtonThemeExtensionImpl.dark(theme: theme),
// Loader
LoaderTheme.dark(),
// Rich Text
RichTextBuilderTheme.dark(),
// TextInput
TextInputThemeExtensionImpl.dark(theme: theme),
TopAppBarTheme.dark(),
],
);
}
} }

View File

@ -8,5 +8,7 @@
<true/> <true/>
<key>com.apple.security.network.server</key> <key>com.apple.security.network.server</key>
<true/> <true/>
<key>com.apple.security.network.client</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.network.client</key> <key>com.apple.security.network.client</key>
<true/> <true/>
<key>com.apple.security.app-sandbox</key> <key>com.apple.security.app-sandbox</key>
<true/> <true/>
</dict> <key>com.apple.security.network.client</key>
<true/>
</dict>
</plist> </plist>

View File

@ -50,16 +50,16 @@ class TopAppBar extends TopAppBarComponent with $TopAppBarCWMixin {
@override @override
Widget build(BuildContext context) => DecoratedBox( Widget build(BuildContext context) => DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: ThemeHelper.getThemeElement<MultiColor, Gradient>( gradient: ThemeHelper.maybeGetElement<MultiColor, Gradient>(
[ [
backgroundColor, backgroundColor,
context.themeExtension<TopBarThemeExtension>()?.backgroundColors, context.themeExtension<TopBarThemeExtension>()?.backgroundColors,
], ],
valueValidator: (value) => value?.isGradient, valueValidator: (value) => value?.isGradient,
transform: (value) => transform: (value) =>
LinearGradientHelper.fromNullableColors(value?.colors), GradientHelper.linearFromNullableColors(value?.colors),
), ),
color: ThemeHelper.getThemeElement<MultiColor, Color>( color: ThemeHelper.maybeGetElement<MultiColor, Color>(
[ [
backgroundColor, backgroundColor,
context.themeExtension<TopBarThemeExtension>()?.backgroundColors, context.themeExtension<TopBarThemeExtension>()?.backgroundColors,
@ -82,8 +82,7 @@ class TopAppBar extends TopAppBarComponent with $TopAppBarCWMixin {
scrolledUnderElevation: scrolledUnderElevation, scrolledUnderElevation: scrolledUnderElevation,
shadowColor: shadowColor, shadowColor: shadowColor,
surfaceTintColor: surfaceTintColor, surfaceTintColor: surfaceTintColor,
iconTheme: iconTheme: ThemeHelper.getElement<IconThemeData, IconThemeData>(
ThemeHelper.getThemeElement<IconThemeData, IconThemeData>(
[ [
iconTheme, iconTheme,
context.themeExtension<TopBarThemeExtension>()?.iconTheme, context.themeExtension<TopBarThemeExtension>()?.iconTheme,
@ -95,9 +94,9 @@ class TopAppBar extends TopAppBarComponent with $TopAppBarCWMixin {
primary: primary ?? true, primary: primary ?? true,
excludeHeaderSemantics: excludeHeaderSemantics ?? false, excludeHeaderSemantics: excludeHeaderSemantics ?? false,
leadingWidth: leadingWidth, leadingWidth: leadingWidth,
title: Text( title: GradientText(
title?.data ?? '', data: title?.data ?? '',
style: ThemeHelper.getThemeElement<TextStyle, TextStyle>( style: ThemeHelper.getElement<TextStyle, TextStyle>(
[ [
context.textTheme.titleLarge, context.textTheme.titleLarge,
context.themeExtension<TopBarThemeExtension>()?.titleStyle, context.themeExtension<TopBarThemeExtension>()?.titleStyle,
@ -107,14 +106,15 @@ class TopAppBar extends TopAppBarComponent with $TopAppBarCWMixin {
combine: (p0, p1) => p0?.merge(p1), combine: (p0, p1) => p0?.merge(p1),
transform: (value) => value, transform: (value) => value,
), ),
).toGradient(gradientColors: title?.gradientColors), gradientColors: const MultiColor([]),
),
leading: leading, leading: leading,
actions: actions, actions: actions,
centerTitle: centerTitle ?? false, centerTitle: centerTitle ?? false,
), ),
if (expandedWidget != null) if (expandedWidget != null)
...ListTile.divideTiles( ...ListTile.divideTiles(
color: ThemeHelper.getThemeElement<Color, Color>( color: ThemeHelper.getElement<Color, Color>(
[ [
context context
.themeExtension<TopBarThemeExtension>() .themeExtension<TopBarThemeExtension>()

View File

@ -54,16 +54,16 @@ class TopNavigationBar extends TopNavigationBarComponent
@override @override
Widget build(BuildContext context) => DecoratedBox( Widget build(BuildContext context) => DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: ThemeHelper.getThemeElement<MultiColor, Gradient>( gradient: ThemeHelper.maybeGetElement<MultiColor, Gradient>(
[ [
backgroundColor, backgroundColor,
context.themeExtension<TopBarThemeExtension>()?.backgroundColors, context.themeExtension<TopBarThemeExtension>()?.backgroundColors,
], ],
valueValidator: (value) => value?.isGradient, valueValidator: (value) => value?.isGradient,
transform: (value) => transform: (value) =>
LinearGradientHelper.fromNullableColors(value?.colors), GradientHelper.linearFromNullableColors(value?.colors),
), ),
color: ThemeHelper.getThemeElement<MultiColor, Color>( color: ThemeHelper.maybeGetElement<MultiColor, Color>(
[ [
backgroundColor, backgroundColor,
context.themeExtension<TopBarThemeExtension>()?.backgroundColors, context.themeExtension<TopBarThemeExtension>()?.backgroundColors,
@ -85,7 +85,7 @@ class TopNavigationBar extends TopNavigationBarComponent
scrolledUnderElevation: scrolledUnderElevation, scrolledUnderElevation: scrolledUnderElevation,
shadowColor: shadowColor, shadowColor: shadowColor,
surfaceTintColor: surfaceTintColor, surfaceTintColor: surfaceTintColor,
iconTheme: ThemeHelper.getThemeElement<IconThemeData, IconThemeData>( iconTheme: ThemeHelper.getElement<IconThemeData, IconThemeData>(
[ [
iconTheme, iconTheme,
context.themeExtension<TopBarThemeExtension>()?.iconTheme, context.themeExtension<TopBarThemeExtension>()?.iconTheme,

View File

@ -33,7 +33,7 @@ class NavigationItem extends StatelessWidget {
children: [ children: [
if (selected) if (selected)
Container( Container(
height: ThemeHelper.getThemeElement<double, double>( height: ThemeHelper.getElement<double, double>(
[ [
context context
.themeExtension<TopBarThemeExtension>() .themeExtension<TopBarThemeExtension>()
@ -44,7 +44,7 @@ class NavigationItem extends StatelessWidget {
valueValidator: (value) => value != null, valueValidator: (value) => value != null,
transform: (value) => value, transform: (value) => value,
), ),
width: ThemeHelper.getThemeElement<double, double>( width: ThemeHelper.getElement<double, double>(
[ [
context context
.themeExtension<TopBarThemeExtension>() .themeExtension<TopBarThemeExtension>()
@ -57,7 +57,7 @@ class NavigationItem extends StatelessWidget {
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100), borderRadius: BorderRadius.circular(100),
color: ThemeHelper.getThemeElement<Color, Color>( color: ThemeHelper.getElement<Color, Color>(
[ [
context context
.themeExtension<TopBarThemeExtension>() .themeExtension<TopBarThemeExtension>()
@ -71,25 +71,24 @@ class NavigationItem extends StatelessWidget {
), ),
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
minWidth: ThemeHelper.getThemeElement<double, double>( minWidth: ThemeHelper.getElement<double, double>(
[ [
context context
.themeExtension<TopBarThemeExtension>() .themeExtension<TopBarThemeExtension>()
?.selectedIndicatorWidth, ?.selectedIndicatorWidth,
// TODO(wyatt): move default value // TODO(wyatt): move default value
70, 70,
], ],
valueValidator: (value) => value != null, valueValidator: (value) => value != null,
transform: (value) => value, transform: (value) => value,
) ?? ),
double.infinity,
), ),
child: SizedBox( child: SizedBox(
height: 50, height: 50,
child: Center( child: Center(
child: Text( child: Text(
item.data, item.data,
style: ThemeHelper.getThemeElement<TextStyle, TextStyle>( style: ThemeHelper.getElement<TextStyle, TextStyle>(
[ [
context.textTheme.titleMedium, context.textTheme.titleMedium,
context context

View File

@ -28,7 +28,7 @@ class FileSelectionButton extends FileSelectionButtonComponent
const FileSelectionButton({ const FileSelectionButton({
super.leading, super.leading,
super.title, super.title,
super.subTitle, super.subtitle,
super.disabledStyle, super.disabledStyle,
super.normalStyle, super.normalStyle,
super.hoveredStyle, super.hoveredStyle,
@ -79,7 +79,7 @@ class FileSelectionButton extends FileSelectionButtonComponent
Widget build(BuildContext context) => FileSelectionButtonScreen( Widget build(BuildContext context) => FileSelectionButtonScreen(
leading: leading, leading: leading,
title: title, title: title,
subTitle: subTitle, subtitle: subtitle,
disabledStyle: disabledStyle, disabledStyle: disabledStyle,
normalStyle: normalStyle, normalStyle: normalStyle,
hoveredStyle: hoveredStyle, hoveredStyle: hoveredStyle,

View File

@ -18,8 +18,8 @@ class $FileSelectionButtonCWProxyImpl
@override @override
FileSelectionButton title(TextWrapper? title) => this(title: title); FileSelectionButton title(TextWrapper? title) => this(title: title);
@override @override
FileSelectionButton subTitle(TextWrapper? subTitle) => FileSelectionButton subtitle(TextWrapper? subtitle) =>
this(subTitle: subTitle); this(subtitle: subtitle);
@override @override
FileSelectionButton disabledStyle(ButtonStyle<dynamic>? disabledStyle) => FileSelectionButton disabledStyle(ButtonStyle<dynamic>? disabledStyle) =>
this(disabledStyle: disabledStyle); this(disabledStyle: disabledStyle);
@ -58,7 +58,7 @@ class $FileSelectionButtonCWProxyImpl
MainAxisSize? mainAxisSize, MainAxisSize? mainAxisSize,
Widget? leading, Widget? leading,
TextWrapper? title, TextWrapper? title,
TextWrapper? subTitle, TextWrapper? subtitle,
ButtonStyle<dynamic>? disabledStyle, ButtonStyle<dynamic>? disabledStyle,
ButtonStyle<dynamic>? normalStyle, ButtonStyle<dynamic>? normalStyle,
ButtonStyle<dynamic>? hoveredStyle, ButtonStyle<dynamic>? hoveredStyle,
@ -74,7 +74,7 @@ class $FileSelectionButtonCWProxyImpl
FileSelectionButton( FileSelectionButton(
leading: leading ?? _value.leading, leading: leading ?? _value.leading,
title: title ?? _value.title, title: title ?? _value.title,
subTitle: subTitle ?? _value.subTitle, subtitle: subtitle ?? _value.subtitle,
disabledStyle: disabledStyle ?? _value.disabledStyle, disabledStyle: disabledStyle ?? _value.disabledStyle,
normalStyle: normalStyle ?? _value.normalStyle, normalStyle: normalStyle ?? _value.normalStyle,
hoveredStyle: hoveredStyle ?? _value.hoveredStyle, hoveredStyle: hoveredStyle ?? _value.hoveredStyle,

View File

@ -31,7 +31,7 @@ class FileSelectionButtonScreen
const FileSelectionButtonScreen({ const FileSelectionButtonScreen({
this.leading, this.leading,
this.title, this.title,
this.subTitle, this.subtitle,
this.disabledStyle, this.disabledStyle,
this.normalStyle, this.normalStyle,
this.hoveredStyle, this.hoveredStyle,
@ -46,11 +46,19 @@ class FileSelectionButtonScreen
super.key, super.key,
}); });
/// The leading widget of the button.
final Widget? leading; final Widget? leading;
/// The title widget of the button.
final TextWrapper? title; final TextWrapper? title;
final TextWrapper? subTitle;
/// The subtitle widget of the button.
final TextWrapper? subtitle;
/// The main axis size of the button.
final MainAxisSize? mainAxisSize; final MainAxisSize? mainAxisSize;
// Styles
final FileSelectionButtonStyle? disabledStyle; final FileSelectionButtonStyle? disabledStyle;
final FileSelectionButtonStyle? normalStyle; final FileSelectionButtonStyle? normalStyle;
final FileSelectionButtonStyle? hoveredStyle; final FileSelectionButtonStyle? hoveredStyle;
@ -59,8 +67,13 @@ class FileSelectionButtonScreen
final FileSelectionButtonStyle? selectedStyle; final FileSelectionButtonStyle? selectedStyle;
final FileSelectionButtonStyle? invalidStyle; final FileSelectionButtonStyle? invalidStyle;
/// The callback to be called when the button is pressed.
final void Function(ControlState state)? onPressed; final void Function(ControlState state)? onPressed;
/// The notifier to be used to disable the button.
final ValueNotifier<bool>? disabled; final ValueNotifier<bool>? disabled;
/// The theme resolver to be used to resolve the theme.
final FileSelectionButtonThemeResolver? themeResolver; final FileSelectionButtonThemeResolver? themeResolver;
@override @override
@ -198,43 +211,28 @@ class FileSelectionButtonScreen
/// ///
/// More infos in `ThemeResolver` class /// More infos in `ThemeResolver` class
if (title != null) ...[ if (title != null) ...[
Text( GradientText.fromWrapper(
title!.data, title!,
style: title!.style ?? style.title,
textAlign: title!.textAlign,
textDirection: title!.textDirection,
softWrap: title!.softWrap,
overflow: title!.overflow,
maxLines: title!.maxLines,
selectionColor: title!.selectionColor,
).toGradient(
gradientColors: style.foregroundColors, gradientColors: style.foregroundColors,
), )
], ],
/// Choose color /// Choose color
/// subTitle.style.color ?? /// subtitle.style.color ??
/// buttonStyle.subTitle.style.color ?? /// buttonStyle.subtitle.style.color ??
/// context.textTheme.subTitleLarge.color /// context.textTheme.subtitleLarge.color
/// ///
/// Choose gradient /// Choose gradient
/// subTitle.gradient ?? /// subtitle.gradient ??
/// buttonStyle.foregroundColor.colors ?? /// buttonStyle.foregroundColor.colors ??
/// null /// null
/// ///
/// More infos in `ThemeResolver` class /// More infos in `ThemeResolver` class
if (subTitle != null) ...[ if (subtitle != null) ...[
const Gap(5), const Gap(5),
Text( GradientText.fromWrapper(
subTitle!.data, subtitle!,
style: subTitle!.style ?? style.subTitle, style: style.subtitleStyle,
textAlign: title!.textAlign,
textDirection: title!.textDirection,
softWrap: title!.softWrap,
overflow: title!.overflow,
maxLines: title!.maxLines,
selectionColor: title!.selectionColor,
).toGradient(
gradientColors: style.foregroundColors, gradientColors: style.foregroundColors,
), ),
], ],

View File

@ -24,58 +24,6 @@ class FileSelectionButtonThemeResolver extends ThemeResolver<
required this.customStyleFn, required this.customStyleFn,
}); });
@override
FileSelectionButtonStyle computeDefaultValue(
BuildContext context, {
ButtonState? extra,
}) {
MultiColor backgroundColor = MultiColor.single(context.colorScheme.primary);
MultiColor foregroundColor =
MultiColor.single(context.colorScheme.onPrimary);
switch (extra?.state) {
case ControlState.disabled:
backgroundColor =
MultiColor.single(context.colorScheme.onSurface.withOpacity(0.12));
foregroundColor =
MultiColor.single(context.colorScheme.onSurface.withOpacity(0.38));
break;
case ControlState.hovered:
backgroundColor =
MultiColor.single(context.colorScheme.primary.withOpacity(0.92));
break;
case ControlState.tapped:
backgroundColor =
MultiColor.single(context.colorScheme.primary.withOpacity(0.92));
break;
case null:
case ControlState.normal:
case ControlState.focused:
break;
}
if (extra?.isInvalid ?? false) {
backgroundColor = MultiColor.single(context.colorScheme.error);
}
return FileSelectionButtonStyle(
title: context.textTheme.labelLarge,
subTitle: context.textTheme.labelSmall,
radius: (context.buttonTheme.shape is RoundedRectangleBorder)
? (context.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null,
padding: const EdgeInsets.symmetric(horizontal: 10),
foregroundColors: foregroundColor,
backgroundColors: backgroundColor,
);
}
@override
final FileSelectionButtonStyle? Function(
BuildContext context, {
ButtonState? extra,
}) customStyleFn;
@override @override
FileSelectionButtonStyle? computeExtensionValueFn( FileSelectionButtonStyle? computeExtensionValueFn(
BuildContext context, BuildContext context,
@ -96,17 +44,31 @@ class FileSelectionButtonThemeResolver extends ThemeResolver<
case ControlState.tapped: case ControlState.tapped:
style = themeExtension?.tappedStyle; style = themeExtension?.tappedStyle;
break; break;
case ControlState.normal:
case null: case null:
case ControlState.normal:
style = themeExtension?.normalStyle; style = themeExtension?.normalStyle;
break; break;
} }
if (extra?.isInvalid ?? false) {
style = themeExtension?.invalidStyle;
}
if (extra?.isSelected ?? false) { if (extra?.isSelected ?? false) {
style = themeExtension?.selectedStyle; style = themeExtension?.selectedStyle;
} }
if (extra?.isInvalid ?? false) {
style = themeExtension?.invalidStyle;
}
return style; return style;
} }
@override
FileSelectionButtonThemeExtension? getDefaultExtension(
BuildContext context,
) =>
FileSelectionButtonThemeExtensionDefault.from(Theme.of(context));
@override
final FileSelectionButtonStyle? Function(
BuildContext context, {
ButtonState? extra,
}) customStyleFn;
} }

View File

@ -208,16 +208,9 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
/// ///
/// More infos in ThemeResolver class /// More infos in ThemeResolver class
if (label != null) ...[ if (label != null) ...[
Text( GradientText.fromWrapper(
label!.data, label!,
style: label!.style ?? style.label, style: style.labelStyle,
textAlign: label!.textAlign,
textDirection: label!.textDirection,
softWrap: label!.softWrap,
overflow: label!.overflow,
maxLines: label!.maxLines,
selectionColor: label!.selectionColor,
).toGradient(
gradientColors: style.foregroundColors, gradientColors: style.foregroundColors,
) )
], ],

View File

@ -16,7 +16,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle, class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle,
FlatButtonThemeExtension, ControlState> { FlatButtonThemeExtension, ControlState> {
@ -24,73 +23,42 @@ class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle,
required this.customStyleFn, required this.customStyleFn,
}); });
/// Values taken from <https://api.flutter.dev/flutter/material/ElevatedButton/defaultStyleOf.html>
@override
FlatButtonStyle computeDefaultValue(
BuildContext context, {
ControlState? extra,
}) {
MultiColor backgroundColor = MultiColor.single(context.colorScheme.primary);
MultiColor foregroundColor =
MultiColor.single(context.colorScheme.onPrimary);
switch (extra) {
case ControlState.disabled:
backgroundColor =
MultiColor.single(context.colorScheme.onSurface.withOpacity(0.12));
foregroundColor =
MultiColor.single(context.colorScheme.onSurface.withOpacity(0.38));
break;
case ControlState.hovered:
backgroundColor =
MultiColor.single(context.colorScheme.primary.withOpacity(0.92));
break;
case ControlState.tapped:
backgroundColor =
MultiColor.single(context.colorScheme.primary.withOpacity(0.92));
break;
case null:
case ControlState.normal:
case ControlState.focused:
break;
}
return FlatButtonStyle(
label:
context.textTheme.labelLarge?.copyWith(color: foregroundColor.color),
radius: (context.buttonTheme.shape is RoundedRectangleBorder)
? (context.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null,
padding: context.buttonTheme.padding,
foregroundColors: foregroundColor,
backgroundColors: backgroundColor,
);
}
@override
final FlatButtonStyle? Function(
BuildContext context, {
ControlState? extra,
}) customStyleFn;
@override @override
FlatButtonStyle? computeExtensionValueFn( FlatButtonStyle? computeExtensionValueFn(
BuildContext context, BuildContext context,
FlatButtonThemeExtension? themeExtension, { FlatButtonThemeExtension? themeExtension, {
ControlState? extra, ControlState? extra,
}) { }) {
FlatButtonStyle? style;
switch (extra) { switch (extra) {
case ControlState.disabled: case ControlState.disabled:
return themeExtension?.disabledStyle; style = themeExtension?.disabledStyle;
break;
case ControlState.focused: case ControlState.focused:
return themeExtension?.focusedStyle; style = themeExtension?.focusedStyle;
break;
case ControlState.hovered: case ControlState.hovered:
return themeExtension?.hoveredStyle; style = themeExtension?.hoveredStyle;
break;
case ControlState.tapped: case ControlState.tapped:
return themeExtension?.tappedStyle; style = themeExtension?.tappedStyle;
case ControlState.normal: break;
case null: case null:
return themeExtension?.normalStyle; case ControlState.normal:
style = themeExtension?.normalStyle;
break;
} }
return style;
} }
@override
FlatButtonThemeExtension? getDefaultExtension(BuildContext context) =>
FlatButtonThemeExtensionDefault.from(Theme.of(context));
@override
final FlatButtonStyle? Function(
BuildContext context, {
ControlState? extra,
}) customStyleFn;
} }

View File

@ -11,7 +11,7 @@ class $SimpleIconButtonCWProxyImpl
const $SimpleIconButtonCWProxyImpl(this._value); const $SimpleIconButtonCWProxyImpl(this._value);
final SimpleIconButton _value; final SimpleIconButton _value;
@override @override
SimpleIconButton icon(Icon? icon) => this(icon: icon); SimpleIconButton icon(Widget? icon) => this(icon: icon);
@override @override
SimpleIconButton disabledStyle(ButtonStyle<dynamic>? disabledStyle) => SimpleIconButton disabledStyle(ButtonStyle<dynamic>? disabledStyle) =>
this(disabledStyle: disabledStyle); this(disabledStyle: disabledStyle);
@ -41,7 +41,7 @@ class $SimpleIconButtonCWProxyImpl
SimpleIconButton key(Key? key) => this(key: key); SimpleIconButton key(Key? key) => this(key: key);
@override @override
SimpleIconButton call({ SimpleIconButton call({
Icon? icon, Widget? icon,
ButtonStyle<dynamic>? disabledStyle, ButtonStyle<dynamic>? disabledStyle,
ButtonStyle<dynamic>? normalStyle, ButtonStyle<dynamic>? normalStyle,
ButtonStyle<dynamic>? hoveredStyle, ButtonStyle<dynamic>? hoveredStyle,

View File

@ -16,7 +16,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class SimpleIconButtonThemeResolver extends ThemeResolver<SimpleIconButtonStyle, class SimpleIconButtonThemeResolver extends ThemeResolver<SimpleIconButtonStyle,
SimpleIconButtonThemeExtension, ControlState> { SimpleIconButtonThemeExtension, ControlState> {
@ -25,70 +24,41 @@ class SimpleIconButtonThemeResolver extends ThemeResolver<SimpleIconButtonStyle,
}); });
@override @override
SimpleIconButtonStyle computeDefaultValue( SimpleIconButtonStyle? computeExtensionValueFn(
BuildContext context, { BuildContext context,
SimpleIconButtonThemeExtension? themeExtension, {
ControlState? extra, ControlState? extra,
}) { }) {
MultiColor backgroundColor = MultiColor.single(context.colorScheme.primary); SimpleIconButtonStyle? style;
MultiColor foregroundColor =
MultiColor.single(context.colorScheme.onPrimary);
switch (extra) { switch (extra) {
case ControlState.disabled: case ControlState.disabled:
backgroundColor = style = themeExtension?.disabledStyle;
MultiColor.single(context.colorScheme.onSurface.withOpacity(0.12)); break;
foregroundColor = case ControlState.focused:
MultiColor.single(context.colorScheme.onSurface.withOpacity(0.38)); style = themeExtension?.focusedStyle;
break; break;
case ControlState.hovered: case ControlState.hovered:
backgroundColor = style = themeExtension?.hoveredStyle;
MultiColor.single(context.colorScheme.primary.withOpacity(0.92));
break; break;
case ControlState.tapped: case ControlState.tapped:
backgroundColor = style = themeExtension?.tappedStyle;
MultiColor.single(context.colorScheme.primary.withOpacity(0.92));
break; break;
case null: case null:
case ControlState.normal: case ControlState.normal:
case ControlState.focused: style = themeExtension?.normalStyle;
break; break;
} }
return SimpleIconButtonStyle( return style;
dimension: context.buttonTheme.height,
radius: (context.buttonTheme.shape is RoundedRectangleBorder)
? (context.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null,
padding: EdgeInsets.zero,
foregroundColors: foregroundColor,
backgroundColors: backgroundColor,
);
} }
@override
SimpleIconButtonThemeExtension? getDefaultExtension(BuildContext context) =>
SimpleIconButtonThemeExtensionDefault.from(Theme.of(context));
@override @override
final SimpleIconButtonStyle? Function( final SimpleIconButtonStyle? Function(
BuildContext context, { BuildContext context, {
ControlState? extra, ControlState? extra,
}) customStyleFn; }) customStyleFn;
@override
SimpleIconButtonStyle? computeExtensionValueFn(
BuildContext context,
SimpleIconButtonThemeExtension? themeExtension, {
ControlState? extra,
}) {
switch (extra) {
case ControlState.disabled:
return themeExtension?.disabledStyle;
case ControlState.focused:
return themeExtension?.focusedStyle;
case ControlState.hovered:
return themeExtension?.hoveredStyle;
case ControlState.tapped:
return themeExtension?.tappedStyle;
case ControlState.normal:
case null:
return themeExtension?.normalStyle;
}
}
} }

View File

@ -18,12 +18,9 @@ import 'package:flutter/material.dart' hide ButtonStyle;
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/state_listener.dart'; import 'package:wyatt_ui_kit/src/components/buttons/cubit/state_listener.dart';
import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_button_theme_resolver.dart'; import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_icon.dart';
import 'package:wyatt_ui_kit/src/core/helpers/linear_gradient_helper.dart';
class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> { class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
const SimpleIconButtonScreen({ const SimpleIconButtonScreen({
@ -39,7 +36,7 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
super.key, super.key,
}); });
final Icon? icon; final Widget? icon;
final SimpleIconButtonStyle? disabledStyle; final SimpleIconButtonStyle? disabledStyle;
final SimpleIconButtonStyle? normalStyle; final SimpleIconButtonStyle? normalStyle;
@ -171,25 +168,23 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
/// context.buttonTheme.onPrimary /// context.buttonTheme.onPrimary
child: Builder( child: Builder(
builder: (context) { builder: (context) {
if (icon?.color != null) { if (icon != null) {
return icon!; if (icon is GradientIcon) {
} return icon!;
}
if (!(style.foregroundColors?.isGradient ?? false)) { if (icon is Icon) {
return ColorFiltered( return GradientIcon.fromIcon(
colorFilter: ColorFilter.mode( (icon as Icon?)!,
style.foregroundColors!.color, gradientColors: style.foregroundColors,
BlendMode.srcIn, );
), }
child: icon, return GradientIcon.fromWidget(
icon!,
gradientColors: style.foregroundColors,
); );
} }
return icon!.toGradient( return const SizedBox.shrink();
LinearGradientHelper.fromMultiColor(
style.foregroundColors!,
),
);
}, },
), ),
), ),

View File

@ -209,16 +209,9 @@ class SymbolButtonScreen
/// More infos in `negociate()` method /// More infos in `negociate()` method
if (label != null) ...[ if (label != null) ...[
Gap(style.padding?.horizontal ?? 10), Gap(style.padding?.horizontal ?? 10),
Text( GradientText.fromWrapper(
label!.data, label!,
style: label!.style ?? style.label, style: style.labelStyle,
textAlign: label!.textAlign,
textDirection: label!.textDirection,
softWrap: label!.softWrap,
overflow: label!.overflow,
maxLines: label!.maxLines,
selectionColor: label!.selectionColor,
).toGradient(
gradientColors: style.foregroundColors, gradientColors: style.foregroundColors,
), ),
], ],

View File

@ -24,54 +24,6 @@ class SymbolButtonThemeResolver extends ThemeResolver<SymbolButtonStyle,
required this.customStyleFn, required this.customStyleFn,
}); });
@override
SymbolButtonStyle computeDefaultValue(
BuildContext context, {
ButtonState? extra,
}) {
MultiColor backgroundColor = MultiColor.single(context.colorScheme.primary);
MultiColor foregroundColor =
MultiColor.single(context.colorScheme.onPrimary);
switch (extra?.state) {
case ControlState.disabled:
backgroundColor =
MultiColor.single(context.colorScheme.onSurface.withOpacity(0.12));
foregroundColor =
MultiColor.single(context.colorScheme.onSurface.withOpacity(0.38));
break;
case ControlState.hovered:
backgroundColor =
MultiColor.single(context.colorScheme.primary.withOpacity(0.92));
break;
case ControlState.tapped:
backgroundColor =
MultiColor.single(context.colorScheme.primary.withOpacity(0.92));
break;
case null:
case ControlState.normal:
case ControlState.focused:
break;
}
return SymbolButtonStyle(
label: context.textTheme.labelLarge,
dimension: context.buttonTheme.height * 1.5,
radius: (context.buttonTheme.shape is RoundedRectangleBorder)
? (context.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null,
padding: context.buttonTheme.padding,
foregroundColors: foregroundColor,
backgroundColors: backgroundColor,
);
}
@override
final SymbolButtonStyle? Function(
BuildContext context, {
ButtonState? extra,
}) customStyleFn;
@override @override
SymbolButtonStyle? computeExtensionValueFn( SymbolButtonStyle? computeExtensionValueFn(
BuildContext context, BuildContext context,
@ -92,15 +44,28 @@ class SymbolButtonThemeResolver extends ThemeResolver<SymbolButtonStyle,
case ControlState.tapped: case ControlState.tapped:
style = themeExtension?.tappedStyle; style = themeExtension?.tappedStyle;
break; break;
case ControlState.normal:
case null: case null:
case ControlState.normal:
style = themeExtension?.normalStyle; style = themeExtension?.normalStyle;
break; break;
} }
if (extra?.isSelected ?? false) { if (extra?.isSelected ?? false) {
style = themeExtension?.selectedStyle; style = themeExtension?.selectedStyle;
} }
return style; return style;
} }
@override
SymbolButtonThemeExtension? getDefaultExtension(
BuildContext context,
) =>
SymbolButtonThemeExtensionDefault.from(Theme.of(context));
@override
final SymbolButtonStyle? Function(
BuildContext context, {
ButtonState? extra,
}) customStyleFn;
} }

View File

@ -40,50 +40,85 @@ class InformationCard extends InformationCardComponent
super.padding, super.padding,
super.borderColors, super.borderColors,
super.backgroundColors, super.backgroundColors,
super.stroke,
super.minSize, super.minSize,
super.maxSize = const Size(330, double.infinity), super.maxSize,
super.shadow, super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background, super.background,
super.key, super.key,
}); });
@override @override
Widget build(BuildContext context) => CardWrapper( Widget build(BuildContext context) {
background: background, final themeTitleStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
padding: padding, [
backgroundColors: backgroundColors, titleStyle,
borderColors: borderColors, Theme.of(context).extension<CardThemeExtension>()?.titleStyle,
shadow: shadow, CardThemeExtensionDefault.from(Theme.of(context)).titleStyle,
maxSize: maxSize, ],
minSize: minSize, );
child: Column(
mainAxisSize: MainAxisSize.min, final themeSubtitleStyle =
children: [ ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
if (axis == Axis.horizontal) ...[ [
InformationCardHorizontalHeader( subtitleStyle,
icons: icons, Theme.of(context).extension<CardThemeExtension>()?.subtitleStyle,
axis: axis, CardThemeExtensionDefault.from(Theme.of(context)).subtitleStyle,
title: title, ],
subtitle: subtitle, );
),
] else if (axis == Axis.vertical) ...[ final themeBodyStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
InformationCardVerticalHeader( [
icons: icons, bodyStyle,
axis: axis, Theme.of(context).extension<CardThemeExtension>()?.bodyStyle,
title: title, CardThemeExtensionDefault.from(Theme.of(context)).bodyStyle,
subtitle: subtitle, ],
), );
],
if (body != null) ...[ return CardWrapper(
const Gap(_bodyTopSpacing), background: background,
CardText( padding: padding,
body!, radius: radius,
textType: TextType.body, backgroundColors: backgroundColors,
style: body!.style, borderColors: borderColors,
gradientColors: body!.gradientColors, shadow: shadow,
), stroke: stroke,
], maxSize: maxSize,
minSize: minSize,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (axis == Axis.horizontal) ...[
InformationCardHorizontalHeader(
icons: icons,
axis: axis,
title: title,
subtitle: subtitle,
titleStyle: themeTitleStyle,
subtitleStyle: themeSubtitleStyle,
),
] else ...[
InformationCardVerticalHeader(
icons: icons,
axis: axis,
title: title,
subtitle: subtitle,
titleStyle: themeTitleStyle,
subtitleStyle: themeSubtitleStyle,
),
], ],
), if (body != null) ...[
); const Gap(_bodyTopSpacing),
CardText.fromWrapper(
body!,
style: themeBodyStyle,
),
],
],
),
);
}
} }

View File

@ -20,9 +20,10 @@ class $InformationCardCWProxyImpl implements $InformationCardComponentCWProxy {
@override @override
InformationCard axis(Axis? axis) => this(axis: axis); InformationCard axis(Axis? axis) => this(axis: axis);
@override @override
InformationCard radius(double? radius) => this(radius: radius); InformationCard radius(BorderRadiusGeometry? radius) => this(radius: radius);
@override @override
InformationCard padding(double? padding) => this(padding: padding); InformationCard padding(EdgeInsetsGeometry? padding) =>
this(padding: padding);
@override @override
InformationCard borderColors(MultiColor? borderColors) => InformationCard borderColors(MultiColor? borderColors) =>
this(borderColors: borderColors); this(borderColors: borderColors);
@ -30,12 +31,22 @@ class $InformationCardCWProxyImpl implements $InformationCardComponentCWProxy {
InformationCard backgroundColors(MultiColor? backgroundColors) => InformationCard backgroundColors(MultiColor? backgroundColors) =>
this(backgroundColors: backgroundColors); this(backgroundColors: backgroundColors);
@override @override
InformationCard stroke(double? stroke) => this(stroke: stroke);
@override
InformationCard minSize(Size? minSize) => this(minSize: minSize); InformationCard minSize(Size? minSize) => this(minSize: minSize);
@override @override
InformationCard maxSize(Size? maxSize) => this(maxSize: maxSize); InformationCard maxSize(Size? maxSize) => this(maxSize: maxSize);
@override @override
InformationCard shadow(BoxShadow? shadow) => this(shadow: shadow); InformationCard shadow(BoxShadow? shadow) => this(shadow: shadow);
@override @override
InformationCard titleStyle(TextStyle? titleStyle) =>
this(titleStyle: titleStyle);
@override
InformationCard subtitleStyle(TextStyle? subtitleStyle) =>
this(subtitleStyle: subtitleStyle);
@override
InformationCard bodyStyle(TextStyle? bodyStyle) => this(bodyStyle: bodyStyle);
@override
InformationCard background(Widget? background) => InformationCard background(Widget? background) =>
this(background: background); this(background: background);
@override @override
@ -47,13 +58,17 @@ class $InformationCardCWProxyImpl implements $InformationCardComponentCWProxy {
TextWrapper? subtitle, TextWrapper? subtitle,
TextWrapper? body, TextWrapper? body,
Axis? axis, Axis? axis,
double? radius, BorderRadiusGeometry? radius,
double? padding, EdgeInsetsGeometry? padding,
MultiColor? borderColors, MultiColor? borderColors,
MultiColor? backgroundColors, MultiColor? backgroundColors,
double? stroke,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background, Widget? background,
Key? key, Key? key,
}) => }) =>
@ -67,9 +82,13 @@ class $InformationCardCWProxyImpl implements $InformationCardComponentCWProxy {
padding: padding ?? _value.padding, padding: padding ?? _value.padding,
borderColors: borderColors ?? _value.borderColors, borderColors: borderColors ?? _value.borderColors,
backgroundColors: backgroundColors ?? _value.backgroundColors, backgroundColors: backgroundColors ?? _value.backgroundColors,
stroke: stroke ?? _value.stroke,
minSize: minSize ?? _value.minSize, minSize: minSize ?? _value.minSize,
maxSize: maxSize ?? _value.maxSize, maxSize: maxSize ?? _value.maxSize,
shadow: shadow ?? _value.shadow, shadow: shadow ?? _value.shadow,
titleStyle: titleStyle ?? _value.titleStyle,
subtitleStyle: subtitleStyle ?? _value.subtitleStyle,
bodyStyle: bodyStyle ?? _value.bodyStyle,
background: background ?? _value.background, background: background ?? _value.background,
key: key ?? _value.key, key: key ?? _value.key,
); );

View File

@ -23,18 +23,33 @@ const _avatarAndTitlesSpacing = 25.0;
class InformationCardHorizontalHeader extends StatelessWidget { class InformationCardHorizontalHeader extends StatelessWidget {
const InformationCardHorizontalHeader({ const InformationCardHorizontalHeader({
this.icons,
this.axis,
this.title, this.title,
this.subtitle, this.subtitle,
this.axis, this.titleStyle,
this.icons, this.subtitleStyle,
super.key, super.key,
}); });
final TextWrapper? title; /// The icons of the card header.
final TextWrapper? subtitle;
final Axis? axis;
final List<Widget>? icons; final List<Widget>? icons;
/// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override @override
Widget build(BuildContext context) => Row( Widget build(BuildContext context) => Row(
children: [ children: [
@ -44,9 +59,11 @@ class InformationCardHorizontalHeader extends StatelessWidget {
], ],
Expanded( Expanded(
child: InformationCardTitles( child: InformationCardTitles(
axis: axis,
title: title, title: title,
subtitle: subtitle, subtitle: subtitle,
axis: axis, titleStyle: titleStyle,
subtitleStyle: subtitleStyle,
), ),
), ),
], ],

View File

@ -25,6 +25,7 @@ class InformationCardIcons extends StatelessWidget {
this.icons, this.icons,
}); });
/// The icons of the card header.
final List<Widget>? icons; final List<Widget>? icons;
@override @override

View File

@ -23,16 +23,29 @@ const _titlesLineSpacing = 5.0;
class InformationCardTitles extends StatelessWidget { class InformationCardTitles extends StatelessWidget {
const InformationCardTitles({ const InformationCardTitles({
this.axis,
this.title, this.title,
this.subtitle, this.subtitle,
this.axis, this.titleStyle,
this.subtitleStyle,
super.key, super.key,
}); });
final TextWrapper? title; /// The axis of the card header.
final TextWrapper? subtitle;
final Axis? axis; final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override @override
Widget build(BuildContext context) => Column( Widget build(BuildContext context) => Column(
crossAxisAlignment: axis == Axis.horizontal crossAxisAlignment: axis == Axis.horizontal
@ -40,20 +53,18 @@ class InformationCardTitles extends StatelessWidget {
: CrossAxisAlignment.center, : CrossAxisAlignment.center,
children: [ children: [
if (title != null) ...[ if (title != null) ...[
CardText( CardText.fromWrapper(
title!, title!,
style: titleStyle,
textType: TextType.title, textType: TextType.title,
style: title!.style,
gradientColors: title!.gradientColors,
), ),
], ],
if (subtitle != null) ...[ if (subtitle != null) ...[
const Gap(_titlesLineSpacing), const Gap(_titlesLineSpacing),
CardText( CardText.fromWrapper(
subtitle!, subtitle!,
style: subtitleStyle,
textType: TextType.subtitle, textType: TextType.subtitle,
style: subtitle!.style,
gradientColors: subtitle!.gradientColors,
), ),
], ],
], ],

View File

@ -24,18 +24,33 @@ const _avatarAndTitlesSpacing = 25.0;
class InformationCardVerticalHeader extends StatelessWidget { class InformationCardVerticalHeader extends StatelessWidget {
const InformationCardVerticalHeader({ const InformationCardVerticalHeader({
this.icons,
this.axis,
this.title, this.title,
this.subtitle, this.subtitle,
this.axis, this.titleStyle,
this.icons, this.subtitleStyle,
super.key, super.key,
}); });
final TextWrapper? title; /// The icons of the card header.
final TextWrapper? subtitle;
final Axis? axis;
final List<Widget>? icons; final List<Widget>? icons;
/// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override @override
Widget build(BuildContext context) => Column( Widget build(BuildContext context) => Column(
children: [ children: [
@ -46,9 +61,11 @@ class InformationCardVerticalHeader extends StatelessWidget {
const Gap(_avatarAndTitlesSpacing), const Gap(_avatarAndTitlesSpacing),
], ],
InformationCardTitles( InformationCardTitles(
axis: axis,
title: title, title: title,
subtitle: subtitle, subtitle: subtitle,
axis: axis, titleStyle: titleStyle,
subtitleStyle: subtitleStyle,
), ),
], ],
); );

View File

@ -25,11 +25,14 @@ import 'package:wyatt_ui_kit/src/components/cards/widgets/card_wrapper.dart';
part 'portfolio_card.g.dart'; part 'portfolio_card.g.dart';
const _spacing = 20.0;
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class PortfolioCard extends PortfolioCardComponent with $PortfolioCardCWMixin { class PortfolioCard extends PortfolioCardComponent with $PortfolioCardCWMixin {
const PortfolioCard({ const PortfolioCard({
super.showImagesOnTop, super.showAssetsOnTop,
super.keyword, super.keywords,
super.keywordsBackgroundColors,
super.description, super.description,
super.logo, super.logo,
super.projectName, super.projectName,
@ -40,79 +43,129 @@ class PortfolioCard extends PortfolioCardComponent with $PortfolioCardCWMixin {
super.padding, super.padding,
super.borderColors, super.borderColors,
super.backgroundColors, super.backgroundColors,
super.secondaryBackgroundColors, super.stroke,
super.minSize, super.minSize,
super.maxSize = const Size(330, double.infinity), super.maxSize,
super.shadow, super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background, super.background,
super.key, super.key,
}); });
@override @override
Widget build(BuildContext context) => CardWrapper( Widget build(BuildContext context) {
background: background, final themeTitleStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
padding: padding, [
backgroundColors: backgroundColors, titleStyle,
borderColors: borderColors, Theme.of(context).extension<CardThemeExtension>()?.titleStyle,
shadow: shadow, CardThemeExtensionDefault.from(Theme.of(context)).titleStyle,
maxSize: maxSize, ],
minSize: minSize, );
child: Column(
mainAxisSize: MainAxisSize.min, final themeSubtitleStyle =
children: [ ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
if (showImagesOnTop ?? false) ...[ [
if (assets != null) ...[ subtitleStyle,
PortfolioCardImages( Theme.of(context).extension<CardThemeExtension>()?.subtitleStyle,
radius: radius, CardThemeExtensionDefault.from(Theme.of(context)).subtitleStyle,
maxSize: maxSize, ],
images: assets, );
),
const Gap(20), final themeBodyStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
], [
CardText( bodyStyle,
description!, Theme.of(context).extension<CardThemeExtension>()?.bodyStyle,
textType: TextType.body, CardThemeExtensionDefault.from(Theme.of(context)).bodyStyle,
style: description!.style, ],
gradientColors: description!.gradientColors, );
),
const Gap(20), final themeBorderRadius =
PortfolioCardHeader( ThemeHelper.maybeGetElement<BorderRadiusGeometry, BorderRadiusGeometry>(
secondaryBackgroundColors: secondaryBackgroundColors, [
logo: logo, radius,
padding: padding, Theme.of(context).extension<CardThemeExtension>()?.radius,
radius: radius, CardThemeExtensionDefault.from(Theme.of(context)).radius,
projectName: projectName, ],
subtitle: subtitle, );
keyword: keyword,
), final themeMaxSize = ThemeHelper.maybeGetElement<Size, Size>(
] else ...[ [
PortfolioCardHeader( maxSize,
secondaryBackgroundColors: secondaryBackgroundColors, Theme.of(context).extension<CardThemeExtension>()?.maxSize,
logo: logo, CardThemeExtensionDefault.from(Theme.of(context)).maxSize,
padding: padding, ],
radius: radius, );
projectName: projectName,
subtitle: subtitle, return CardWrapper(
keyword: keyword, background: background,
), padding: padding,
const Gap(10), radius: radius,
if (assets != null) ...[ backgroundColors: backgroundColors,
PortfolioCardImages( borderColors: borderColors,
radius: radius, shadow: shadow,
maxSize: maxSize, stroke: stroke,
images: assets, maxSize: maxSize,
), minSize: minSize,
const Gap(20), child: Column(
], mainAxisSize: MainAxisSize.min,
CardText( children: [
description!, if (showAssetsOnTop ?? false) ...[
textType: TextType.body, if (assets != null) ...[
style: description!.style, PortfolioCardImages(
gradientColors: description!.gradientColors, assets: assets,
radius: themeBorderRadius,
maxSize: themeMaxSize,
), ),
const Gap(_spacing),
], ],
if (ctas != null) ...[const Gap(20), ...ctas!], CardText.fromWrapper(
description!,
style: themeBodyStyle,
),
const Gap(_spacing),
PortfolioCardHeader(
logo: logo,
projectName: projectName,
subtitle: subtitle,
keywords: keywords,
keywordsBackgroundColors: keywordsBackgroundColors,
titleStyle: themeTitleStyle,
subtitleStyle: themeSubtitleStyle,
keywordsStyle: themeBodyStyle,
),
] else ...[
PortfolioCardHeader(
logo: logo,
projectName: projectName,
subtitle: subtitle,
keywords: keywords,
keywordsBackgroundColors: keywordsBackgroundColors,
titleStyle: themeTitleStyle,
subtitleStyle: themeSubtitleStyle,
keywordsStyle: themeBodyStyle,
),
const Gap(10),
if (assets != null) ...[
PortfolioCardImages(
assets: assets,
radius: themeBorderRadius,
maxSize: themeMaxSize,
),
const Gap(_spacing),
],
CardText.fromWrapper(
description!,
style: themeBodyStyle,
),
], ],
), if (ctas != null)
); ...[const Gap(_spacing), ...ctas!].map(
(e) => SelectionContainer.disabled(child: e),
),
],
),
);
}
} }

View File

@ -10,13 +10,15 @@ class $PortfolioCardCWProxyImpl implements $PortfolioCardComponentCWProxy {
const $PortfolioCardCWProxyImpl(this._value); const $PortfolioCardCWProxyImpl(this._value);
final PortfolioCard _value; final PortfolioCard _value;
@override @override
PortfolioCard secondaryBackgroundColors(Color? secondaryBackgroundColors) => PortfolioCard showAssetsOnTop(bool? showAssetsOnTop) =>
this(secondaryBackgroundColors: secondaryBackgroundColors); this(showAssetsOnTop: showAssetsOnTop);
@override @override
PortfolioCard showImagesOnTop(bool? showImagesOnTop) => PortfolioCard keywords(List<TextWrapper>? keywords) =>
this(showImagesOnTop: showImagesOnTop); this(keywords: keywords);
@override @override
PortfolioCard keyword(List<TextWrapper>? keyword) => this(keyword: keyword); PortfolioCard keywordsBackgroundColors(
MultiColor? keywordsBackgroundColors) =>
this(keywordsBackgroundColors: keywordsBackgroundColors);
@override @override
PortfolioCard description(TextWrapper? description) => PortfolioCard description(TextWrapper? description) =>
this(description: description); this(description: description);
@ -32,9 +34,9 @@ class $PortfolioCardCWProxyImpl implements $PortfolioCardComponentCWProxy {
@override @override
PortfolioCard assets(List<Widget>? assets) => this(assets: assets); PortfolioCard assets(List<Widget>? assets) => this(assets: assets);
@override @override
PortfolioCard radius(double? radius) => this(radius: radius); PortfolioCard radius(BorderRadiusGeometry? radius) => this(radius: radius);
@override @override
PortfolioCard padding(double? padding) => this(padding: padding); PortfolioCard padding(EdgeInsetsGeometry? padding) => this(padding: padding);
@override @override
PortfolioCard borderColors(MultiColor? borderColors) => PortfolioCard borderColors(MultiColor? borderColors) =>
this(borderColors: borderColors); this(borderColors: borderColors);
@ -42,39 +44,55 @@ class $PortfolioCardCWProxyImpl implements $PortfolioCardComponentCWProxy {
PortfolioCard backgroundColors(MultiColor? backgroundColors) => PortfolioCard backgroundColors(MultiColor? backgroundColors) =>
this(backgroundColors: backgroundColors); this(backgroundColors: backgroundColors);
@override @override
PortfolioCard stroke(double? stroke) => this(stroke: stroke);
@override
PortfolioCard minSize(Size? minSize) => this(minSize: minSize); PortfolioCard minSize(Size? minSize) => this(minSize: minSize);
@override @override
PortfolioCard maxSize(Size? maxSize) => this(maxSize: maxSize); PortfolioCard maxSize(Size? maxSize) => this(maxSize: maxSize);
@override @override
PortfolioCard shadow(BoxShadow? shadow) => this(shadow: shadow); PortfolioCard shadow(BoxShadow? shadow) => this(shadow: shadow);
@override @override
PortfolioCard titleStyle(TextStyle? titleStyle) =>
this(titleStyle: titleStyle);
@override
PortfolioCard subtitleStyle(TextStyle? subtitleStyle) =>
this(subtitleStyle: subtitleStyle);
@override
PortfolioCard bodyStyle(TextStyle? bodyStyle) => this(bodyStyle: bodyStyle);
@override
PortfolioCard background(Widget? background) => this(background: background); PortfolioCard background(Widget? background) => this(background: background);
@override @override
PortfolioCard key(Key? key) => this(key: key); PortfolioCard key(Key? key) => this(key: key);
@override @override
PortfolioCard call({ PortfolioCard call({
Color? secondaryBackgroundColors, bool? showAssetsOnTop,
bool? showImagesOnTop, List<TextWrapper>? keywords,
List<TextWrapper>? keyword, MultiColor? keywordsBackgroundColors,
TextWrapper? description, TextWrapper? description,
Widget? logo, Widget? logo,
TextWrapper? projectName, TextWrapper? projectName,
TextWrapper? subtitle, TextWrapper? subtitle,
List<Widget>? ctas, List<Widget>? ctas,
List<Widget>? assets, List<Widget>? assets,
double? radius, BorderRadiusGeometry? radius,
double? padding, EdgeInsetsGeometry? padding,
MultiColor? borderColors, MultiColor? borderColors,
MultiColor? backgroundColors, MultiColor? backgroundColors,
double? stroke,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background, Widget? background,
Key? key, Key? key,
}) => }) =>
PortfolioCard( PortfolioCard(
showImagesOnTop: showImagesOnTop ?? _value.showImagesOnTop, showAssetsOnTop: showAssetsOnTop ?? _value.showAssetsOnTop,
keyword: keyword ?? _value.keyword, keywords: keywords ?? _value.keywords,
keywordsBackgroundColors:
keywordsBackgroundColors ?? _value.keywordsBackgroundColors,
description: description ?? _value.description, description: description ?? _value.description,
logo: logo ?? _value.logo, logo: logo ?? _value.logo,
projectName: projectName ?? _value.projectName, projectName: projectName ?? _value.projectName,
@ -85,11 +103,13 @@ class $PortfolioCardCWProxyImpl implements $PortfolioCardComponentCWProxy {
padding: padding ?? _value.padding, padding: padding ?? _value.padding,
borderColors: borderColors ?? _value.borderColors, borderColors: borderColors ?? _value.borderColors,
backgroundColors: backgroundColors ?? _value.backgroundColors, backgroundColors: backgroundColors ?? _value.backgroundColors,
secondaryBackgroundColors: stroke: stroke ?? _value.stroke,
secondaryBackgroundColors ?? _value.secondaryBackgroundColors,
minSize: minSize ?? _value.minSize, minSize: minSize ?? _value.minSize,
maxSize: maxSize ?? _value.maxSize, maxSize: maxSize ?? _value.maxSize,
shadow: shadow ?? _value.shadow, shadow: shadow ?? _value.shadow,
titleStyle: titleStyle ?? _value.titleStyle,
subtitleStyle: subtitleStyle ?? _value.subtitleStyle,
bodyStyle: bodyStyle ?? _value.bodyStyle,
background: background ?? _value.background, background: background ?? _value.background,
key: key ?? _value.key, key: key ?? _value.key,
); );

View File

@ -17,7 +17,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/information_card/widgets/information_card_titles.dart'; import 'package:wyatt_ui_kit/src/components/cards/portfolio_card/widgets/portfolio_card_titles.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
const _avatarAndTitlesSpacing = 25.0; const _avatarAndTitlesSpacing = 25.0;
@ -25,22 +25,39 @@ const _avatarAndTitlesSpacing = 25.0;
class PortfolioCardHeader extends StatelessWidget { class PortfolioCardHeader extends StatelessWidget {
const PortfolioCardHeader({ const PortfolioCardHeader({
this.logo, this.logo,
this.padding,
this.radius,
this.projectName, this.projectName,
this.subtitle, this.subtitle,
this.keyword, this.keywords,
this.secondaryBackgroundColors, this.keywordsBackgroundColors,
this.titleStyle,
this.subtitleStyle,
this.keywordsStyle,
super.key, super.key,
}); });
/// The logo of the portfolio card.
final Widget? logo; final Widget? logo;
final double? padding;
final double? radius; /// Project name of the portfolio card.
final TextWrapper? projectName; final TextWrapper? projectName;
/// Subtitle of the portfolio card.
final TextWrapper? subtitle; final TextWrapper? subtitle;
final List<TextWrapper>? keyword;
final Color? secondaryBackgroundColors; /// The keywords of the portfolio card.
final List<TextWrapper>? keywords;
/// Background colors for the keywords badges
final MultiColor? keywordsBackgroundColors;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
/// Styles the keywords of the card.
final TextStyle? keywordsStyle;
@override @override
Widget build(BuildContext context) => Column( Widget build(BuildContext context) => Column(
@ -51,10 +68,12 @@ class PortfolioCardHeader extends StatelessWidget {
if (logo != null) logo!, if (logo != null) logo!,
const Gap(_avatarAndTitlesSpacing), const Gap(_avatarAndTitlesSpacing),
Expanded( Expanded(
child: InformationCardTitles( child: PortfolioCardTitles(
axis: Axis.horizontal, axis: Axis.horizontal,
title: projectName, title: projectName,
subtitle: subtitle, subtitle: subtitle,
titleStyle: titleStyle,
subtitleStyle: subtitleStyle,
), ),
), ),
], ],
@ -62,27 +81,47 @@ class PortfolioCardHeader extends StatelessWidget {
const Gap(10), const Gap(10),
Wrap( Wrap(
children: [ children: [
if (keyword != null) if (keywords != null)
...keyword!.map( ...keywords!.map(
(word) => Container( (word) => Container(
margin: const EdgeInsets.all(3), margin: const EdgeInsets.all(3),
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),
decoration: BoxDecoration( decoration: BoxDecoration(
color: secondaryBackgroundColors ?? gradient:
ThemeHelper.maybeGetElement<MultiColor, Gradient>(
[
keywordsBackgroundColors,
Theme.of(context) Theme.of(context)
.extension<CardThemeExtension>() .extension<CardThemeExtension>()
?.secondaryBackgroundColor, ?.borderColors,
CardThemeExtensionDefault.from(Theme.of(context))
.borderColors,
],
valueValidator: (multiColor) => multiColor?.isGradient,
transform: (multiColor) =>
GradientHelper.linearFromMultiColor(multiColor!),
),
color: ThemeHelper.maybeGetElement<MultiColor, Color>(
[
keywordsBackgroundColors,
Theme.of(context)
.extension<CardThemeExtension>()
?.borderColors,
MultiColor.single(
Theme.of(context).cardTheme.surfaceTintColor,
),
CardThemeExtensionDefault.from(Theme.of(context))
.borderColors,
],
valueValidator: (multiColor) =>
multiColor != null && multiColor.isColor,
transform: (multiColor) => multiColor?.color,
),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Text( child: GradientText.fromWrapper(
word.data, word,
style: word.style ?? context.textTheme.bodySmall, style: context.textTheme.bodySmall,
textAlign: word.textAlign,
textDirection: word.textDirection,
softWrap: word.softWrap,
overflow: word.overflow,
maxLines: word.maxLines,
selectionColor: word.selectionColor,
), ),
), ),
), ),

View File

@ -19,29 +19,34 @@ import 'package:gap/gap.dart';
class PortfolioCardImages extends StatelessWidget { class PortfolioCardImages extends StatelessWidget {
const PortfolioCardImages({ const PortfolioCardImages({
this.images, this.assets,
this.radius, this.radius,
this.maxSize, this.maxSize,
super.key, super.key,
}); });
final List<Widget>? images; /// The assets to display.
final double? radius; final List<Widget>? assets;
/// The radius of the assets.
final BorderRadiusGeometry? radius;
/// The max size of the assets.
final Size? maxSize; final Size? maxSize;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final result = <Widget>[]; final result = <Widget>[];
for (final image in images ?? List<Widget>.empty()) { for (final asset in assets ?? List<Widget>.empty()) {
result.addAll([ result.addAll([
Expanded( Expanded(
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(radius ?? 0), borderRadius: radius ?? BorderRadius.zero,
child: Container( child: Container(
constraints: BoxConstraints( constraints: BoxConstraints(
maxHeight: maxSize != null ? maxSize!.width : 100, maxHeight: maxSize != null ? maxSize!.width : double.infinity,
), ),
child: image, child: asset,
), ),
), ),
), ),

View File

@ -0,0 +1,72 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
const _titlesLineSpacing = 5.0;
class PortfolioCardTitles extends StatelessWidget {
const PortfolioCardTitles({
this.axis,
this.title,
this.subtitle,
this.titleStyle,
this.subtitleStyle,
super.key,
});
/// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override
Widget build(BuildContext context) => Column(
crossAxisAlignment: axis == Axis.horizontal
? CrossAxisAlignment.start
: CrossAxisAlignment.center,
children: [
if (title != null) ...[
CardText.fromWrapper(
title!,
style: titleStyle,
textType: TextType.title,
),
],
if (subtitle != null) ...[
const Gap(_titlesLineSpacing),
CardText.fromWrapper(
subtitle!,
style: subtitleStyle,
textType: TextType.subtitle,
),
],
],
);
}

View File

@ -20,7 +20,6 @@ import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_ex
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart'; import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_wrapper.dart'; import 'package:wyatt_ui_kit/src/components/cards/widgets/card_wrapper.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
part 'quote_card.g.dart'; part 'quote_card.g.dart';
@ -30,7 +29,6 @@ class QuoteCard extends QuoteCardComponent with $QuoteCardCWMixin {
super.avatar, super.avatar,
super.name, super.name,
super.subtitle, super.subtitle,
super.gradient,
super.quote, super.quote,
super.leftQuote, super.leftQuote,
super.rightQuote, super.rightQuote,
@ -38,90 +36,109 @@ class QuoteCard extends QuoteCardComponent with $QuoteCardCWMixin {
super.padding, super.padding,
super.borderColors, super.borderColors,
super.backgroundColors, super.backgroundColors,
super.stroke,
super.minSize, super.minSize,
super.maxSize, super.maxSize,
super.shadow, super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background, super.background,
super.key, super.key,
}); });
@override @override
Widget build(BuildContext context) => CardWrapper( Widget build(BuildContext context) {
background: background, final themeTitleStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
padding: padding, [
backgroundColors: backgroundColors, titleStyle,
borderColors: borderColors, Theme.of(context).extension<CardThemeExtension>()?.titleStyle,
shadow: shadow, CardThemeExtensionDefault.from(Theme.of(context)).titleStyle,
maxSize: maxSize, ],
minSize: minSize, );
child: Column(
mainAxisSize: MainAxisSize.min, final themeSubtitleStyle =
children: [ ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
leftQuote ?? [
Align( subtitleStyle,
alignment: Alignment.topLeft, Theme.of(context).extension<CardThemeExtension>()?.subtitleStyle,
child: GradientText( CardThemeExtensionDefault.from(Theme.of(context)).subtitleStyle,
'', ],
style: GradientTextStyle.from( );
context.textTheme.titleLarge
?.copyWith(fontWeight: FontWeight.bold), final themeBodyStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
MultiColor(gradient?.colors), [
), bodyStyle,
), Theme.of(context).extension<CardThemeExtension>()?.bodyStyle,
CardThemeExtensionDefault.from(Theme.of(context)).bodyStyle,
],
);
return CardWrapper(
background: background,
padding: padding,
radius: radius,
backgroundColors: backgroundColors,
borderColors: borderColors,
shadow: shadow,
stroke: stroke,
maxSize: maxSize,
minSize: minSize,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
leftQuote ??
const Align(
alignment: Alignment.topLeft,
child: Text(
'',
), ),
if (quote != null) ...[
CardText(
quote!,
textType: TextType.body,
style: quote!.style,
gradientColors: quote!.gradientColors,
), ),
], if (quote != null) ...[
const Gap(15), CardText.fromWrapper(
rightQuote ?? quote!,
Align( style: themeBodyStyle,
alignment: Alignment.bottomRight,
child: GradientText(
'',
style: GradientTextStyle.from(
context.textTheme.titleLarge
?.copyWith(fontWeight: FontWeight.bold),
MultiColor(gradient?.colors),
),
),
),
Row(
children: [
if (avatar != null) ...[
avatar!,
const Gap(25),
],
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (name != null) ...[
CardText(
name!,
textType: TextType.body,
style: name!.style,
gradientColors: name!.gradientColors,
),
],
if (subtitle != null) ...[
CardText(
subtitle!,
textType: TextType.subtitle,
style: subtitle!.style,
gradientColors: subtitle!.gradientColors,
),
],
],
),
)
],
), ),
], ],
), const Gap(15),
); rightQuote ??
const Align(
alignment: Alignment.bottomRight,
child: Text(
'',
),
),
Row(
children: [
if (avatar != null) ...[
avatar!,
const Gap(25),
],
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (name != null) ...[
CardText.fromWrapper(
name!,
style: themeTitleStyle,
textType: TextType.title,
),
],
if (subtitle != null) ...[
CardText.fromWrapper(
subtitle!,
style: themeSubtitleStyle,
textType: TextType.subtitle,
),
],
],
),
)
],
),
],
),
);
}
} }

View File

@ -16,17 +16,15 @@ class $QuoteCardCWProxyImpl implements $QuoteCardComponentCWProxy {
@override @override
QuoteCard subtitle(TextWrapper? subtitle) => this(subtitle: subtitle); QuoteCard subtitle(TextWrapper? subtitle) => this(subtitle: subtitle);
@override @override
QuoteCard gradient(Gradient? gradient) => this(gradient: gradient);
@override
QuoteCard quote(TextWrapper? quote) => this(quote: quote); QuoteCard quote(TextWrapper? quote) => this(quote: quote);
@override @override
QuoteCard leftQuote(Widget? leftQuote) => this(leftQuote: leftQuote); QuoteCard leftQuote(Widget? leftQuote) => this(leftQuote: leftQuote);
@override @override
QuoteCard rightQuote(Widget? rightQuote) => this(rightQuote: rightQuote); QuoteCard rightQuote(Widget? rightQuote) => this(rightQuote: rightQuote);
@override @override
QuoteCard radius(double? radius) => this(radius: radius); QuoteCard radius(BorderRadiusGeometry? radius) => this(radius: radius);
@override @override
QuoteCard padding(double? padding) => this(padding: padding); QuoteCard padding(EdgeInsetsGeometry? padding) => this(padding: padding);
@override @override
QuoteCard borderColors(MultiColor? borderColors) => QuoteCard borderColors(MultiColor? borderColors) =>
this(borderColors: borderColors); this(borderColors: borderColors);
@ -34,12 +32,21 @@ class $QuoteCardCWProxyImpl implements $QuoteCardComponentCWProxy {
QuoteCard backgroundColors(MultiColor? backgroundColors) => QuoteCard backgroundColors(MultiColor? backgroundColors) =>
this(backgroundColors: backgroundColors); this(backgroundColors: backgroundColors);
@override @override
QuoteCard stroke(double? stroke) => this(stroke: stroke);
@override
QuoteCard minSize(Size? minSize) => this(minSize: minSize); QuoteCard minSize(Size? minSize) => this(minSize: minSize);
@override @override
QuoteCard maxSize(Size? maxSize) => this(maxSize: maxSize); QuoteCard maxSize(Size? maxSize) => this(maxSize: maxSize);
@override @override
QuoteCard shadow(BoxShadow? shadow) => this(shadow: shadow); QuoteCard shadow(BoxShadow? shadow) => this(shadow: shadow);
@override @override
QuoteCard titleStyle(TextStyle? titleStyle) => this(titleStyle: titleStyle);
@override
QuoteCard subtitleStyle(TextStyle? subtitleStyle) =>
this(subtitleStyle: subtitleStyle);
@override
QuoteCard bodyStyle(TextStyle? bodyStyle) => this(bodyStyle: bodyStyle);
@override
QuoteCard background(Widget? background) => this(background: background); QuoteCard background(Widget? background) => this(background: background);
@override @override
QuoteCard key(Key? key) => this(key: key); QuoteCard key(Key? key) => this(key: key);
@ -48,17 +55,20 @@ class $QuoteCardCWProxyImpl implements $QuoteCardComponentCWProxy {
Widget? avatar, Widget? avatar,
TextWrapper? name, TextWrapper? name,
TextWrapper? subtitle, TextWrapper? subtitle,
Gradient? gradient,
TextWrapper? quote, TextWrapper? quote,
Widget? leftQuote, Widget? leftQuote,
Widget? rightQuote, Widget? rightQuote,
double? radius, BorderRadiusGeometry? radius,
double? padding, EdgeInsetsGeometry? padding,
MultiColor? borderColors, MultiColor? borderColors,
MultiColor? backgroundColors, MultiColor? backgroundColors,
double? stroke,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background, Widget? background,
Key? key, Key? key,
}) => }) =>
@ -66,7 +76,6 @@ class $QuoteCardCWProxyImpl implements $QuoteCardComponentCWProxy {
avatar: avatar ?? _value.avatar, avatar: avatar ?? _value.avatar,
name: name ?? _value.name, name: name ?? _value.name,
subtitle: subtitle ?? _value.subtitle, subtitle: subtitle ?? _value.subtitle,
gradient: gradient ?? _value.gradient,
quote: quote ?? _value.quote, quote: quote ?? _value.quote,
leftQuote: leftQuote ?? _value.leftQuote, leftQuote: leftQuote ?? _value.leftQuote,
rightQuote: rightQuote ?? _value.rightQuote, rightQuote: rightQuote ?? _value.rightQuote,
@ -74,9 +83,13 @@ class $QuoteCardCWProxyImpl implements $QuoteCardComponentCWProxy {
padding: padding ?? _value.padding, padding: padding ?? _value.padding,
borderColors: borderColors ?? _value.borderColors, borderColors: borderColors ?? _value.borderColors,
backgroundColors: backgroundColors ?? _value.backgroundColors, backgroundColors: backgroundColors ?? _value.backgroundColors,
stroke: stroke ?? _value.stroke,
minSize: minSize ?? _value.minSize, minSize: minSize ?? _value.minSize,
maxSize: maxSize ?? _value.maxSize, maxSize: maxSize ?? _value.maxSize,
shadow: shadow ?? _value.shadow, shadow: shadow ?? _value.shadow,
titleStyle: titleStyle ?? _value.titleStyle,
subtitleStyle: subtitleStyle ?? _value.subtitleStyle,
bodyStyle: bodyStyle ?? _value.bodyStyle,
background: background ?? _value.background, background: background ?? _value.background,
key: key ?? _value.key, key: key ?? _value.key,
); );

View File

@ -18,68 +18,118 @@ import 'package:flutter/material.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_header.dart'; import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_horizontal_header.dart';
import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_skills.dart'; import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_skills.dart';
import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_vertical_header.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart'; import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_wrapper.dart'; import 'package:wyatt_ui_kit/src/components/cards/widgets/card_wrapper.dart';
part 'skill_card.g.dart'; part 'skill_card.g.dart';
const _bodyTopSpacing = 25.0;
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class SkillCard extends SkillCardComponent with $SkillCardCWMixin { class SkillCard extends SkillCardComponent with $SkillCardCWMixin {
const SkillCard({ const SkillCard({
super.icon, super.axis,
super.gradient, super.icons,
super.secondaryBackgroundColors,
super.title, super.title,
super.subtitle,
super.description, super.description,
super.skills, super.skills,
super.leadingIcon, super.bulletColors,
super.bulletIcon,
super.radius, super.radius,
super.padding, super.padding,
super.borderColors, super.borderColors,
super.backgroundColors, super.backgroundColors,
super.stroke,
super.minSize, super.minSize,
super.maxSize = const Size(330, double.infinity), super.maxSize,
super.shadow, super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background, super.background,
super.key, super.key,
}); });
@override @override
Widget build(BuildContext context) => CardWrapper( Widget build(BuildContext context) {
background: background, final themeTitleStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
padding: padding, [
backgroundColors: backgroundColors, titleStyle,
borderColors: borderColors, Theme.of(context).extension<CardThemeExtension>()?.titleStyle,
shadow: shadow, CardThemeExtensionDefault.from(Theme.of(context)).titleStyle,
maxSize: maxSize, ],
minSize: minSize, );
child: Column(
mainAxisSize: MainAxisSize.min, final themeSubtitleStyle =
children: [ ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
SkillCardHeader( [
secondaryBackgroundColors: secondaryBackgroundColors, subtitleStyle,
icon: icon, Theme.of(context).extension<CardThemeExtension>()?.subtitleStyle,
CardThemeExtensionDefault.from(Theme.of(context)).subtitleStyle,
],
);
final themeBodyStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
[
bodyStyle,
Theme.of(context).extension<CardThemeExtension>()?.bodyStyle,
CardThemeExtensionDefault.from(Theme.of(context)).bodyStyle,
],
);
return CardWrapper(
background: background,
padding: padding,
radius: radius,
backgroundColors: backgroundColors,
borderColors: borderColors,
shadow: shadow,
stroke: stroke,
maxSize: maxSize,
minSize: minSize,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (axis == Axis.horizontal) ...[
SkillCardHorizontalHeader(
icons: icons,
axis: axis,
title: title, title: title,
subtitle: subtitle,
titleStyle: themeTitleStyle,
subtitleStyle: themeSubtitleStyle,
),
] else ...[
SkillCardVerticalHeader(
icons: icons,
axis: axis,
title: title,
subtitle: subtitle,
titleStyle: themeTitleStyle,
subtitleStyle: themeSubtitleStyle,
), ),
const Gap(25),
if (description != null) ...[
CardText(
description!,
textType: TextType.body,
style: description!.style,
gradientColors: description!.gradientColors,
),
const Gap(25),
],
if (skills != null)
SkillCardSkills(
gradient: gradient,
skills: skills,
leadingIcon: leadingIcon,
),
], ],
), const Gap(_bodyTopSpacing),
); if (description != null) ...[
CardText.fromWrapper(
description!,
style: themeBodyStyle,
),
const Gap(_bodyTopSpacing),
],
if (skills != null)
SkillCardSkills(
skills: skills,
bulletColors: bulletColors,
bulletIcon: bulletIcon,
bodyStyle: themeBodyStyle,
),
],
),
);
}
} }

View File

@ -10,26 +10,27 @@ class $SkillCardCWProxyImpl implements $SkillCardComponentCWProxy {
const $SkillCardCWProxyImpl(this._value); const $SkillCardCWProxyImpl(this._value);
final SkillCard _value; final SkillCard _value;
@override @override
SkillCard icon(Widget? icon) => this(icon: icon); SkillCard axis(Axis? axis) => this(axis: axis);
@override @override
SkillCard gradient(List<Color>? gradient) => this(gradient: gradient); SkillCard icons(List<Widget>? icons) => this(icons: icons);
@override @override
SkillCard title(TextWrapper? title) => this(title: title); SkillCard title(TextWrapper? title) => this(title: title);
@override @override
SkillCard subtitle(TextWrapper? subtitle) => this(subtitle: subtitle);
@override
SkillCard description(TextWrapper? description) => SkillCard description(TextWrapper? description) =>
this(description: description); this(description: description);
@override @override
SkillCard skills(List<TextWrapper>? skills) => this(skills: skills); SkillCard skills(List<TextWrapper>? skills) => this(skills: skills);
@override @override
SkillCard leadingIcon(IconData? leadingIcon) => SkillCard bulletColors(MultiColor? bulletColors) =>
this(leadingIcon: leadingIcon); this(bulletColors: bulletColors);
@override @override
SkillCard secondaryBackgroundColors(Color? secondaryBackgroundColors) => SkillCard bulletIcon(Widget? bulletIcon) => this(bulletIcon: bulletIcon);
this(secondaryBackgroundColors: secondaryBackgroundColors);
@override @override
SkillCard radius(double? radius) => this(radius: radius); SkillCard radius(BorderRadiusGeometry? radius) => this(radius: radius);
@override @override
SkillCard padding(double? padding) => this(padding: padding); SkillCard padding(EdgeInsetsGeometry? padding) => this(padding: padding);
@override @override
SkillCard borderColors(MultiColor? borderColors) => SkillCard borderColors(MultiColor? borderColors) =>
this(borderColors: borderColors); this(borderColors: borderColors);
@ -37,50 +38,68 @@ class $SkillCardCWProxyImpl implements $SkillCardComponentCWProxy {
SkillCard backgroundColors(MultiColor? backgroundColors) => SkillCard backgroundColors(MultiColor? backgroundColors) =>
this(backgroundColors: backgroundColors); this(backgroundColors: backgroundColors);
@override @override
SkillCard stroke(double? stroke) => this(stroke: stroke);
@override
SkillCard minSize(Size? minSize) => this(minSize: minSize); SkillCard minSize(Size? minSize) => this(minSize: minSize);
@override @override
SkillCard maxSize(Size? maxSize) => this(maxSize: maxSize); SkillCard maxSize(Size? maxSize) => this(maxSize: maxSize);
@override @override
SkillCard shadow(BoxShadow? shadow) => this(shadow: shadow); SkillCard shadow(BoxShadow? shadow) => this(shadow: shadow);
@override @override
SkillCard titleStyle(TextStyle? titleStyle) => this(titleStyle: titleStyle);
@override
SkillCard subtitleStyle(TextStyle? subtitleStyle) =>
this(subtitleStyle: subtitleStyle);
@override
SkillCard bodyStyle(TextStyle? bodyStyle) => this(bodyStyle: bodyStyle);
@override
SkillCard background(Widget? background) => this(background: background); SkillCard background(Widget? background) => this(background: background);
@override @override
SkillCard key(Key? key) => this(key: key); SkillCard key(Key? key) => this(key: key);
@override @override
SkillCard call({ SkillCard call({
Widget? icon, Axis? axis,
List<Color>? gradient, List<Widget>? icons,
TextWrapper? title, TextWrapper? title,
TextWrapper? subtitle,
TextWrapper? description, TextWrapper? description,
List<TextWrapper>? skills, List<TextWrapper>? skills,
IconData? leadingIcon, MultiColor? bulletColors,
Color? secondaryBackgroundColors, Widget? bulletIcon,
double? radius, BorderRadiusGeometry? radius,
double? padding, EdgeInsetsGeometry? padding,
MultiColor? borderColors, MultiColor? borderColors,
MultiColor? backgroundColors, MultiColor? backgroundColors,
double? stroke,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background, Widget? background,
Key? key, Key? key,
}) => }) =>
SkillCard( SkillCard(
icon: icon ?? _value.icon, axis: axis ?? _value.axis,
gradient: gradient ?? _value.gradient, icons: icons ?? _value.icons,
secondaryBackgroundColors:
secondaryBackgroundColors ?? _value.secondaryBackgroundColors,
title: title ?? _value.title, title: title ?? _value.title,
subtitle: subtitle ?? _value.subtitle,
description: description ?? _value.description, description: description ?? _value.description,
skills: skills ?? _value.skills, skills: skills ?? _value.skills,
leadingIcon: leadingIcon ?? _value.leadingIcon, bulletColors: bulletColors ?? _value.bulletColors,
bulletIcon: bulletIcon ?? _value.bulletIcon,
radius: radius ?? _value.radius, radius: radius ?? _value.radius,
padding: padding ?? _value.padding, padding: padding ?? _value.padding,
borderColors: borderColors ?? _value.borderColors, borderColors: borderColors ?? _value.borderColors,
backgroundColors: backgroundColors ?? _value.backgroundColors, backgroundColors: backgroundColors ?? _value.backgroundColors,
stroke: stroke ?? _value.stroke,
minSize: minSize ?? _value.minSize, minSize: minSize ?? _value.minSize,
maxSize: maxSize ?? _value.maxSize, maxSize: maxSize ?? _value.maxSize,
shadow: shadow ?? _value.shadow, shadow: shadow ?? _value.shadow,
titleStyle: titleStyle ?? _value.titleStyle,
subtitleStyle: subtitleStyle ?? _value.subtitleStyle,
bodyStyle: bodyStyle ?? _value.bodyStyle,
background: background ?? _value.background, background: background ?? _value.background,
key: key ?? _value.key, key: key ?? _value.key,
); );

View File

@ -0,0 +1,71 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_titles.dart';
const _avatarAndTitlesSpacing = 25.0;
class SkillCardHorizontalHeader extends StatelessWidget {
const SkillCardHorizontalHeader({
this.icons,
this.axis,
this.title,
this.subtitle,
this.titleStyle,
this.subtitleStyle,
super.key,
});
/// The icons of the card header.
final List<Widget>? icons;
/// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override
Widget build(BuildContext context) => Row(
children: [
if (icons?.first != null) ...[
icons!.first,
const Gap(_avatarAndTitlesSpacing),
],
Expanded(
child: SkillCardTitles(
axis: axis,
title: title,
subtitle: subtitle,
titleStyle: titleStyle,
subtitleStyle: subtitleStyle,
),
),
],
);
}

View File

@ -15,27 +15,29 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:gap/gap.dart';
abstract class CardThemeExtension extends ThemeExtension<CardThemeExtension> { const _iconSpacing = 25.0;
const CardThemeExtension({
this.backgroundColors, class SkillCardIcons extends StatelessWidget {
this.secondaryBackgroundColor, const SkillCardIcons({
this.borderColors, super.key,
this.shadowColor, this.icons,
this.body,
this.title,
this.subtitle,
}); });
// Colors /// The icons of the card header.
final MultiColor? backgroundColors; final List<Widget>? icons;
final Color? secondaryBackgroundColor;
final MultiColor? borderColors;
final BoxShadow? shadowColor;
// TextStyles @override
final TextStyle? body; Widget build(BuildContext context) {
final TextStyle? title; final result = <Widget>[];
final TextStyle? subtitle; for (final widget in icons ?? List<Widget>.empty()) {
result.addAll([widget, const Gap(_iconSpacing)]);
}
result.removeLast();
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: result,
);
}
} }

View File

@ -19,19 +19,27 @@ import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart'; import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_icon.dart'; import 'package:wyatt_ui_kit/src/components/gradients/gradient_icon.dart';
import 'package:wyatt_ui_kit/src/core/helpers/linear_gradient_helper.dart';
class SkillCardSkills extends StatelessWidget { class SkillCardSkills extends StatelessWidget {
const SkillCardSkills({ const SkillCardSkills({
super.key, super.key,
this.skills, this.skills,
this.leadingIcon, this.bulletColors,
this.gradient, this.bulletIcon,
this.bodyStyle,
}); });
/// Skills to be displayed
final List<TextWrapper>? skills; final List<TextWrapper>? skills;
final IconData? leadingIcon;
final List<Color>? gradient; /// Gradient of skill icons.
final MultiColor? bulletColors;
/// Icon to be displayed before each skill.
final Widget? bulletIcon;
/// Body style of the card.
final TextStyle? bodyStyle;
@override @override
Widget build(BuildContext context) => Column( Widget build(BuildContext context) => Column(
@ -39,18 +47,22 @@ class SkillCardSkills extends StatelessWidget {
.map( .map(
(skill) => Row( (skill) => Row(
children: [ children: [
Icon( if (bulletIcon != null) ...[
leadingIcon ?? Icons.check, GradientIcon.fromWidget(
).toGradient( bulletIcon!,
LinearGradientHelper.fromNullableColors(gradient), gradientColors: bulletColors,
), ),
] else ...[
GradientIcon(
icon: Icons.check,
gradientColors: bulletColors ?? const MultiColor([]),
),
],
const Gap(10), const Gap(10),
Expanded( Expanded(
child: CardText( child: CardText.fromWrapper(
skill, skill,
textType: TextType.body, style: bodyStyle,
style: skill.style,
gradientColors: skill.gradientColors,
), ),
), ),
], ],

View File

@ -19,37 +19,54 @@ import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart'; import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
class SkillCardHeader extends StatelessWidget { const _titlesLineSpacing = 5.0;
const SkillCardHeader({
super.key, class SkillCardTitles extends StatelessWidget {
this.icon, const SkillCardTitles({
this.axis,
this.title, this.title,
this.secondaryBackgroundColors, this.subtitle,
this.titleStyle,
this.subtitleStyle,
super.key,
}); });
final Widget? icon; /// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title; final TextWrapper? title;
final Color? secondaryBackgroundColors;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override @override
Widget build(BuildContext context) => Column( Widget build(BuildContext context) => Column(
crossAxisAlignment: axis == Axis.horizontal
? CrossAxisAlignment.start
: CrossAxisAlignment.center,
children: [ children: [
if (icon != null) ...[ if (title != null) ...[
icon!, CardText.fromWrapper(
const Gap(25), title!,
style: titleStyle,
textType: TextType.title,
),
],
if (subtitle != null) ...[
const Gap(_titlesLineSpacing),
CardText.fromWrapper(
subtitle!,
style: subtitleStyle,
textType: TextType.subtitle,
),
], ],
Column(
children: [
if (title != null) ...[
CardText(
title!,
textType: TextType.title,
style: title!.style,
gradientColors: title!.gradientColors,
),
],
],
)
], ],
); );
} }

View File

@ -0,0 +1,72 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_icons.dart';
import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_titles.dart';
const _avatarAndTitlesSpacing = 25.0;
class SkillCardVerticalHeader extends StatelessWidget {
const SkillCardVerticalHeader({
this.icons,
this.axis,
this.title,
this.subtitle,
this.titleStyle,
this.subtitleStyle,
super.key,
});
/// The icons of the card header.
final List<Widget>? icons;
/// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override
Widget build(BuildContext context) => Column(
children: [
if (icons != null && icons!.isNotEmpty) ...[
SkillCardIcons(
icons: icons,
),
const Gap(_avatarAndTitlesSpacing),
],
SkillCardTitles(
axis: axis,
title: title,
subtitle: subtitle,
titleStyle: titleStyle,
subtitleStyle: subtitleStyle,
),
],
);
}

View File

@ -1,9 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// {@template card_background}
/// A widget that displays a background for a card.
/// {@endtemplate}
class CardBackground extends StatefulWidget { class CardBackground extends StatefulWidget {
/// {@macro card_background}
const CardBackground({super.key, this.background, this.cardKey}); const CardBackground({super.key, this.background, this.cardKey});
/// Background to display
final Widget? background; final Widget? background;
/// Key of the card to display the background for
final GlobalKey? cardKey; final GlobalKey? cardKey;
@override @override

View File

@ -24,46 +24,67 @@ enum TextType {
body; body;
} }
/// {@template card_text}
/// Wrapper for [GradientText] that uses the [CardThemeExtension] to
/// determine the text style to use depending on the [textType].
/// {@endtemplate}
class CardText extends StatelessWidget { class CardText extends StatelessWidget {
/// {@macro card_text}
const CardText( const CardText(
this.text, { this.text, {
required this.textType, this.textType = TextType.body,
this.style,
this.gradientColors,
super.key, super.key,
}); });
final TextWrapper text; /// Creates a [CardText] from a [TextWrapper].
///
/// The [textType] is used to determine the [CardThemeExtension] style to use.
///
/// You can also pass a [gradientColors] and [style] as fallbacks if the
/// [TextWrapper] doesn't have them.
factory CardText.fromWrapper(
TextWrapper wrapper, {
TextType textType = TextType.body,
MultiColor? gradientColors,
TextStyle? style,
}) =>
CardText(
GradientText.fromWrapper(
wrapper,
gradientColors: gradientColors,
style: style,
),
textType: textType,
);
final GradientText text;
final TextType textType; final TextType textType;
final TextStyle? style;
final MultiColor? gradientColors;
TextStyle? _getStyle(BuildContext context) { TextStyle? _getStyle(BuildContext context) {
if (style != null) { if (text.style != null) {
return style; return text.style;
} else { } else {
final cardThemeExtension = final cardThemeExtension =
Theme.of(context).extension<CardThemeExtension>(); Theme.of(context).extension<CardThemeExtension>() ??
CardThemeExtensionDefault.from(Theme.of(context));
switch (textType) { switch (textType) {
case TextType.title: case TextType.title:
return cardThemeExtension?.title ?? context.textTheme.titleLarge; return cardThemeExtension.titleStyle ??
CardThemeExtensionDefault.from(Theme.of(context)).titleStyle;
case TextType.subtitle: case TextType.subtitle:
return cardThemeExtension?.subtitle ?? context.textTheme.titleMedium; return cardThemeExtension.subtitleStyle ??
CardThemeExtensionDefault.from(Theme.of(context)).subtitleStyle;
case TextType.body: case TextType.body:
return cardThemeExtension?.body ?? context.textTheme.bodyMedium; return cardThemeExtension.bodyStyle ??
CardThemeExtensionDefault.from(Theme.of(context)).bodyStyle;
} }
} }
} }
@override @override
Widget build(BuildContext context) => Text( Widget build(BuildContext context) => text.copyWith
text.data, .call(
style: _getStyle(context), style: _getStyle(context),
textAlign: text.textAlign, )
textDirection: text.textDirection, .build(context);
softWrap: text.softWrap,
overflow: text.overflow,
maxLines: text.maxLines,
selectionColor: text.selectionColor,
).toGradient(gradientColors: gradientColors);
} }

View File

@ -19,128 +19,222 @@ import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_background.dart'; import 'package:wyatt_ui_kit/src/components/cards/widgets/card_background.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
/// {@template card_wrapper}
/// Common wrapper for all cards
/// {@endtemplate}
class CardWrapper extends StatelessWidget { class CardWrapper extends StatelessWidget {
/// {@macro card_wrapper}
CardWrapper({ CardWrapper({
required this.child, required this.child,
required this.backgroundColors, this.radius,
required this.borderColors, this.padding,
required this.shadow, this.foregroundColors,
required this.minSize, this.backgroundColors,
required this.maxSize, this.borderColors,
required this.padding, this.stroke,
required this.background, this.shadow,
this.minSize,
this.maxSize,
this.background,
super.key, super.key,
}); });
final Widget? background; /// Card radius
final Widget child; ///
/// Default to `BorderRadius.all(Radius.circular(12.0))`
final BorderRadiusGeometry? radius;
/// Padding and gaps of this card
///
/// Default to `Theme.cardTheme.margin`
final EdgeInsetsGeometry? padding;
/// Card foreground gradient colors (from left to right)
///
/// Default to `Theme.colorScheme.onPrimary`
final MultiColor? foregroundColors;
/// Card background gradient colors (from left to right)
///
/// Default to `Theme.cardTheme.color`
final MultiColor? backgroundColors; final MultiColor? backgroundColors;
/// Border colors (from left to right).
///
/// Default to `null`
final MultiColor? borderColors; final MultiColor? borderColors;
/// Stroke of the border
///
/// Default to `null`
final double? stroke;
/// Drop shadow
///
/// Default to `null`
final BoxShadow? shadow; final BoxShadow? shadow;
/// Minimum size of the card
///
/// Default to `const Size(330, double.infinity)`
final Size? minSize; final Size? minSize;
/// Maximum size of the card
///
/// Default to `const Size(double.infinity, double.infinity)`
final Size? maxSize; final Size? maxSize;
final double? padding;
/// Background of the card
final Widget? background;
final Widget child;
final GlobalKey _key = GlobalKey(); final GlobalKey _key = GlobalKey();
Widget _buildChild(Widget child) => (background != null) Widget _buildChild(BuildContext context, Widget child) {
? Stack( final themePadding =
alignment: Alignment.center, ThemeHelper.getElement<EdgeInsetsGeometry, EdgeInsetsGeometry>(
children: [ [
CardBackground( padding,
cardKey: _key, Theme.of(context).extension<CardThemeExtension>()?.padding,
background: background, CardThemeExtensionDefault.from(Theme.of(context)).padding,
), ],
Padding( );
padding: EdgeInsets.all(
padding ?? 25, return (background != null)
? Stack(
alignment: Alignment.center,
children: [
CardBackground(
cardKey: _key,
background: background,
), ),
child: child, Padding(
), padding: themePadding,
], child: child,
) ),
: Padding( ],
padding: EdgeInsets.all( )
padding ?? 25, : Padding(
), padding: themePadding,
child: child, child: child,
); );
}
List<BoxShadow> _shadow(BuildContext context) { List<BoxShadow> _shadow(BuildContext context) {
final themeShadow = ThemeHelper.getThemeElement<BoxShadow, BoxShadow>( final themeShadow = ThemeHelper.maybeGetElement<BoxShadow, BoxShadow>(
[ [
shadow, shadow,
Theme.of(context).extension<CardThemeExtension>()?.shadowColor, Theme.of(context).extension<CardThemeExtension>()?.shadow,
CardThemeExtensionDefault.from(Theme.of(context)).shadow,
], ],
valueValidator: (shadow) => shadow != null,
transform: (shadow) => shadow,
); );
return (themeShadow != null) ? [themeShadow] : []; return (themeShadow != null) ? [themeShadow] : [];
} }
@override @override
Widget build(BuildContext context) => SelectionArea( Widget build(BuildContext context) {
child: DecoratedBox( final themeBorderStroke = ThemeHelper.getElement<double, double>(
key: _key, [
decoration: BoxDecoration( stroke,
borderRadius: const BorderRadius.all(Radius.circular(12)), Theme.of(context).extension<CardThemeExtension>()?.stroke,
gradient: ThemeHelper.getThemeElement<MultiColor, Gradient>( CardThemeExtensionDefault.from(Theme.of(context)).stroke,
[ ],
backgroundColors, );
Theme.of(context)
.extension<CardThemeExtension>() final themeBorderRadius =
?.backgroundColors, ThemeHelper.getElement<BorderRadiusGeometry, BorderRadiusGeometry>(
], [
valueValidator: (multiColor) => multiColor?.isGradient, radius,
transform: (multiColor) => Theme.of(context).extension<CardThemeExtension>()?.radius,
LinearGradientHelper.fromMultiColor(multiColor!), CardThemeExtensionDefault.from(Theme.of(context)).radius
), ],
color: ThemeHelper.getThemeElement<MultiColor, Color>( );
[
backgroundColors, final themeMinSize = ThemeHelper.maybeGetElement<Size, Size>(
Theme.of(context) [
.extension<CardThemeExtension>() minSize,
?.backgroundColors, Theme.of(context).extension<CardThemeExtension>()?.minSize,
MultiColor.single(Theme.of(context).cardColor), CardThemeExtensionDefault.from(Theme.of(context)).minSize
], ],
valueValidator: (multiColor) => );
multiColor != null && multiColor.isColor,
transform: (multiColor) => multiColor?.color, final themeMaxSize = ThemeHelper.maybeGetElement<Size, Size>(
), [
border: ThemeHelper.getThemeElement<MultiColor, BoxBorder>( maxSize,
[ Theme.of(context).extension<CardThemeExtension>()?.maxSize,
borderColors, CardThemeExtensionDefault.from(Theme.of(context)).maxSize
Theme.of(context).extension<CardThemeExtension>()?.borderColors, ],
Theme.of(context) );
.extension<CardThemeExtension>()
?.backgroundColors, return SelectionArea(
], child: DecoratedBox(
valueValidator: (multiColor) => key: _key,
multiColor != null && multiColor.isColor, decoration: BoxDecoration(
transform: (multiColor) { borderRadius: themeBorderRadius,
if (multiColor!.isGradient) { gradient: ThemeHelper.maybeGetElement<MultiColor, Gradient>(
return GradientBoxBorder( [
gradient: LinearGradientHelper.fromMultiColor(multiColor), backgroundColors,
); Theme.of(context)
} .extension<CardThemeExtension>()
return Border.all( ?.backgroundColors,
color: multiColor.color, CardThemeExtensionDefault.from(Theme.of(context)).backgroundColors
); ],
}, valueValidator: (multiColor) => multiColor?.isGradient,
), transform: (multiColor) =>
boxShadow: _shadow(context), GradientHelper.linearFromMultiColor(multiColor!),
), ),
child: (minSize != null && maxSize != null) color: ThemeHelper.maybeGetElement<MultiColor, Color>(
? ConstrainedBox( [
constraints: BoxConstraints( backgroundColors,
minWidth: minSize!.width, Theme.of(context)
minHeight: minSize!.height, .extension<CardThemeExtension>()
maxWidth: maxSize!.width, ?.backgroundColors,
maxHeight: maxSize!.height, CardThemeExtensionDefault.from(Theme.of(context))
), .backgroundColors,
child: _buildChild(child), ],
) valueValidator: (multiColor) =>
: _buildChild(child), multiColor != null && multiColor.isColor,
transform: (multiColor) => multiColor?.color,
),
border: ThemeHelper.maybeGetElement<MultiColor, BoxBorder>(
[
borderColors,
Theme.of(context).extension<CardThemeExtension>()?.borderColors,
Theme.of(context)
.extension<CardThemeExtension>()
?.backgroundColors,
CardThemeExtensionDefault.from(Theme.of(context)).borderColors,
],
valueValidator: (multiColor) =>
multiColor != null && multiColor.isColor,
transform: (multiColor) {
if (multiColor!.isGradient) {
return GradientBoxBorder(
gradient: GradientHelper.linearFromMultiColor(multiColor),
width: themeBorderStroke,
);
}
return Border.all(
color: multiColor.color,
width: themeBorderStroke,
);
},
),
boxShadow: _shadow(context),
), ),
); child: (themeMinSize != null || themeMaxSize != null)
? ConstrainedBox(
constraints: BoxConstraints(
minWidth: themeMinSize?.width ?? 0,
minHeight: themeMinSize?.height ?? 0,
maxWidth: themeMaxSize?.width ?? double.infinity,
maxHeight: themeMaxSize?.height ?? double.infinity,
),
child: _buildChild(context, child),
)
: _buildChild(context, child),
),
);
}
} }

View File

@ -44,7 +44,7 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
child: RepaintBoundary( child: RepaintBoundary(
child: CustomPaint( child: CustomPaint(
painter: _LoaderPainter( painter: _LoaderPainter(
ThemeHelper.getThemeElement<MultiColor, MultiColor>( ThemeHelper.getElement<MultiColor, MultiColor>(
[ [
colors, colors,
Theme.of(context).extension<LoaderThemeExtension>()?.colors, Theme.of(context).extension<LoaderThemeExtension>()?.colors,
@ -61,9 +61,9 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
valueValidator: (multiColor) => valueValidator: (multiColor) =>
multiColor != null && multiColor.isColor, multiColor != null && multiColor.isColor,
transform: (multiColor) => multiColor, transform: (multiColor) => multiColor,
)!, ),
dimension / 2, dimension / 2,
ThemeHelper.getThemeElement<double, double>( ThemeHelper.getElement<double, double>(
[ [
stroke, stroke,
Theme.of(context).extension<LoaderThemeExtension>()?.stroke, Theme.of(context).extension<LoaderThemeExtension>()?.stroke,
@ -71,7 +71,7 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
], ],
valueValidator: (stroke) => stroke != null, valueValidator: (stroke) => stroke != null,
transform: (stroke) => stroke, transform: (stroke) => stroke,
)!, ),
flip: flip ?? false, flip: flip ?? false,
), ),
) )

Some files were not shown because too many files have changed in this diff Show More