feat(ui)!: rework theme resolver mechanism + move theme extension implementations
Some checks failed
continuous-integration/drone/pr Build is failing

This commit is contained in:
Hugo Pointcheval 2023-04-27 16:55:10 +02:00
parent 01269027f2
commit 8f5e3923d6
Signed by: hugo
GPG Key ID: 3AAC487E131E00BC
92 changed files with 3303 additions and 2212 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

@ -14,28 +14,4 @@
// 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/>.
import 'package:flutter/material.dart'; export 'theme_extensions/theme_extensions.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
abstract class CardThemeExtension extends ThemeExtension<CardThemeExtension> {
const CardThemeExtension({
this.backgroundColors,
this.secondaryBackgroundColor,
this.borderColors,
this.shadowColor,
this.body,
this.title,
this.subtitle,
});
// Colors
final MultiColor? backgroundColors;
final Color? secondaryBackgroundColor;
final MultiColor? borderColors;
final BoxShadow? shadowColor;
// TextStyles
final TextStyle? body;
final TextStyle? title;
final TextStyle? subtitle;
}

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

@ -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

@ -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

@ -1,55 +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:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
class SkillCardHeader extends StatelessWidget {
const SkillCardHeader({
super.key,
this.icon,
this.title,
this.secondaryBackgroundColors,
});
final Widget? icon;
final TextWrapper? title;
final Color? secondaryBackgroundColors;
@override
Widget build(BuildContext context) => Column(
children: [
if (icon != null) ...[
icon!,
const Gap(25),
],
Column(
children: [
if (title != null) ...[
CardText(
title!,
textType: TextType.title,
style: title!.style,
gradientColors: title!.gradientColors,
),
],
],
)
],
);
}

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

@ -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,
), ),
) )

View File

@ -39,7 +39,7 @@ class RichTextBuilder extends RichTextBuilderComponent
text ?? '', text ?? '',
regex, regex,
RichTextStyleParameter( RichTextStyleParameter(
ThemeHelper.getThemeElement<TextStyle, TextStyle>( ThemeHelper.getElement<TextStyle, TextStyle>(
[ [
defaultStyle, defaultStyle,
Theme.of(context) Theme.of(context)
@ -50,8 +50,7 @@ class RichTextBuilder extends RichTextBuilderComponent
valueValidator: (style) => style != null, valueValidator: (style) => style != null,
transform: (style) => style, transform: (style) => style,
), ),
ThemeHelper.getThemeElement<Map<String, TextStyle>, ThemeHelper.getElement<Map<String, TextStyle>, Map<String, TextStyle>>(
Map<String, TextStyle>>(
[ [
styles, styles,
Theme.of(context) Theme.of(context)
@ -61,7 +60,7 @@ class RichTextBuilder extends RichTextBuilderComponent
], ],
valueValidator: (styles) => styles != null, valueValidator: (styles) => styles != null,
transform: (styles) => styles, transform: (styles) => styles,
)!, ),
null, null,
), ),
); );
@ -71,7 +70,10 @@ class RichTextBuilder extends RichTextBuilderComponent
if (style is GradientTextStyle?) { if (style is GradientTextStyle?) {
return WidgetSpan( return WidgetSpan(
child: GradientText( child: GradientText(
content, data: content,
gradientColors:
(style as GradientTextStyle?)?.gradientColors ??
const MultiColor([]),
style: style, style: style,
softWrap: true, softWrap: true,
textHeightBehavior: const TextHeightBehavior( textHeightBehavior: const TextHeightBehavior(

View File

@ -33,6 +33,13 @@ class TextInputState extends Equatable {
final String? statusMessage; final String? statusMessage;
bool get isDisabled => controlState.isDisabled();
bool get isEnabled => controlState.isEnabled();
bool get isFocused => controlState.isFocused();
bool get isHovered => controlState.isHovered();
bool get isTapped => controlState.isTapped();
bool get isInvalid => statusState == StatusState.error;
@override @override
List<Object?> get props => [controlState, statusState, statusMessage]; List<Object?> get props => [controlState, statusState, statusMessage];

View File

@ -38,8 +38,8 @@ class TextInput extends TextInputComponent with $TextInputCWMixin {
super.hint, super.hint,
super.normalStyle, super.normalStyle,
super.focusedStyle, super.focusedStyle,
super.errorStyle, super.invalidStyle,
super.disableStyle, super.disabledStyle,
super.controller, super.controller,
super.focusNode, super.focusNode,
super.keyboardType, super.keyboardType,
@ -105,8 +105,8 @@ class TextInput extends TextInputComponent with $TextInputCWMixin {
hint: hint, hint: hint,
focusedStyle: focusedStyle, focusedStyle: focusedStyle,
normalStyle: normalStyle, normalStyle: normalStyle,
errorStyle: errorStyle, invalidStyle: invalidStyle,
disableStyle: disableStyle, disabledStyle: disabledStyle,
prefixIcon: prefixIcon, prefixIcon: prefixIcon,
prefixText: prefixText, prefixText: prefixText,
suffixIcon: suffixIcon, suffixIcon: suffixIcon,

View File

@ -35,11 +35,11 @@ class $TextInputCWProxyImpl implements $TextInputComponentCWProxy {
TextInput focusedStyle(TextInputStyle? focusedStyle) => TextInput focusedStyle(TextInputStyle? focusedStyle) =>
this(focusedStyle: focusedStyle); this(focusedStyle: focusedStyle);
@override @override
TextInput errorStyle(TextInputStyle? errorStyle) => TextInput invalidStyle(TextInputStyle? invalidStyle) =>
this(errorStyle: errorStyle); this(invalidStyle: invalidStyle);
@override @override
TextInput disableStyle(TextInputStyle? disableStyle) => TextInput disabledStyle(TextInputStyle? disabledStyle) =>
this(disableStyle: disableStyle); this(disabledStyle: disabledStyle);
@override @override
TextInput controller(TextEditingController? controller) => TextInput controller(TextEditingController? controller) =>
this(controller: controller); this(controller: controller);
@ -206,8 +206,8 @@ class $TextInputCWProxyImpl implements $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,
@ -277,8 +277,8 @@ class $TextInputCWProxyImpl implements $TextInputComponentCWProxy {
hint: hint ?? _value.hint, hint: hint ?? _value.hint,
normalStyle: normalStyle ?? _value.normalStyle, normalStyle: normalStyle ?? _value.normalStyle,
focusedStyle: focusedStyle ?? _value.focusedStyle, focusedStyle: focusedStyle ?? _value.focusedStyle,
errorStyle: errorStyle ?? _value.errorStyle, invalidStyle: invalidStyle ?? _value.invalidStyle,
disableStyle: disableStyle ?? _value.disableStyle, disabledStyle: disabledStyle ?? _value.disabledStyle,
controller: controller ?? _value.controller, controller: controller ?? _value.controller,
focusNode: focusNode ?? _value.focusNode, focusNode: focusNode ?? _value.focusNode,
keyboardType: keyboardType ?? _value.keyboardType, keyboardType: keyboardType ?? _value.keyboardType,

View File

@ -40,8 +40,8 @@ class TextInputScreen extends CubitScreen<TextInputCubit, TextInputState> {
this.hint, this.hint,
this.normalStyle, this.normalStyle,
this.focusedStyle, this.focusedStyle,
this.errorStyle, this.invalidStyle,
this.disableStyle, this.disabledStyle,
this.magnifierConfiguration, this.magnifierConfiguration,
this.controller, this.controller,
this.focusNode, this.focusNode,
@ -157,8 +157,8 @@ class TextInputScreen extends CubitScreen<TextInputCubit, TextInputState> {
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 TextWrapper? label; final TextWrapper? label;
final TextWrapper? hint; final TextWrapper? hint;
@ -202,7 +202,7 @@ class TextInputScreen extends CubitScreen<TextInputCubit, TextInputState> {
textInputStyle = focusedStyle; textInputStyle = focusedStyle;
break; break;
case ControlState.disabled: case ControlState.disabled:
textInputStyle = disableStyle; textInputStyle = disabledStyle;
break; break;
case ControlState.normal: case ControlState.normal:
textInputStyle = normalStyle; textInputStyle = normalStyle;
@ -216,7 +216,7 @@ class TextInputScreen extends CubitScreen<TextInputCubit, TextInputState> {
TextInputStyle? style; TextInputStyle? style;
switch (extra?.statusState) { switch (extra?.statusState) {
case StatusState.error: case StatusState.error:
style = errorStyle; style = invalidStyle;
break; break;
case StatusState.initial: case StatusState.initial:
case StatusState.success: case StatusState.success:
@ -262,7 +262,7 @@ class TextInputScreen extends CubitScreen<TextInputCubit, TextInputState> {
child: AnimatedContainer( child: AnimatedContainer(
duration: const Duration(milliseconds: 600), duration: const Duration(milliseconds: 600),
decoration: BoxDecoration( decoration: BoxDecoration(
boxShadow: style.boxShadow != null ? [style.boxShadow!] : null, boxShadow: style.shadow != null ? [style.shadow!] : null,
gradient: style.backgroundColors?.isGradient ?? false gradient: style.backgroundColors?.isGradient ?? false
? LinearGradient(colors: style.backgroundColors!.colors) ? LinearGradient(colors: style.backgroundColors!.colors)
: null, : null,
@ -312,7 +312,7 @@ class TextInputScreen extends CubitScreen<TextInputCubit, TextInputState> {
focusNode: focusNode ?? _focusNode, focusNode: focusNode ?? _focusNode,
label: (state.statusState == StatusState.error && label: (state.statusState == StatusState.error &&
(state.statusMessage?.isNotEmpty ?? false)) (state.statusMessage?.isNotEmpty ?? false))
? state.statusMessage?.wrap() ? TextWrapper(state.statusMessage!)
: label, : label,
labelStyle: style.labelStyle, labelStyle: style.labelStyle,
) )

View File

@ -17,8 +17,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/src/components/text_inputs/cubit/text_input_cubit.dart'; import 'package:wyatt_ui_kit/src/components/text_inputs/cubit/text_input_cubit.dart';
import 'package:wyatt_ui_kit/src/core/core.dart';
import 'package:wyatt_ui_kit/src/domain/text_input_theme_extension.dart';
class TextInputThemeResolver extends ThemeResolver<TextInputStyle, class TextInputThemeResolver extends ThemeResolver<TextInputStyle,
TextInputThemeExtension, TextInputState> { TextInputThemeExtension, TextInputState> {
@ -26,130 +24,44 @@ class TextInputThemeResolver extends ThemeResolver<TextInputStyle,
required this.customStyleFn, required this.customStyleFn,
}); });
@override
final TextInputStyle? Function(
BuildContext context, {
TextInputState? extra,
}) customStyleFn;
@override
TextInputStyle computeDefaultValue(
BuildContext context, {
TextInputState? extra,
}) {
TextStyle? labelStyle = context.textTheme.labelLarge
?.copyWith(color: Theme.of(context).unselectedWidgetColor);
TextStyle? hintStyle = context.textTheme.labelLarge;
TextStyle? prefixStyle = context.textTheme.bodyMedium;
TextStyle? suffixStyle = context.textTheme.bodyMedium;
TextStyle? inputStyle = context.textTheme.bodyMedium;
Color? iconColor = context.colorScheme.inversePrimary;
Color? prefixIconColor = Theme.of(context).unselectedWidgetColor;
Color? suffixIconColor = Theme.of(context).unselectedWidgetColor;
Color? borderColors = Theme.of(context).unselectedWidgetColor;
MultiColor? backgroundColors;
BoxShadow? boxShadow;
final BorderRadiusGeometry radius = BorderRadius.circular(4);
switch (extra?.controlState) {
case ControlState.disabled:
labelStyle =
labelStyle?.copyWith(color: Theme.of(context).disabledColor);
hintStyle = hintStyle?.copyWith(color: Theme.of(context).disabledColor);
prefixStyle =
prefixStyle?.copyWith(color: Theme.of(context).disabledColor);
suffixStyle =
suffixStyle?.copyWith(color: Theme.of(context).disabledColor);
inputStyle =
inputStyle?.copyWith(color: Theme.of(context).disabledColor);
borderColors = Theme.of(context).disabledColor;
prefixIconColor = Theme.of(context).disabledColor;
suffixIconColor = Theme.of(context).disabledColor;
break;
case ControlState.focused:
prefixIconColor = context.colorScheme.primary;
suffixIconColor = context.colorScheme.primary;
iconColor = context.colorScheme.primary;
borderColors = context.colorScheme.primary;
labelStyle = labelStyle?.copyWith(color: context.colorScheme.primary);
break;
case ControlState.hovered:
case ControlState.tapped:
case ControlState.normal:
case null:
break;
}
switch (extra?.statusState) {
case StatusState.error:
labelStyle = context.textTheme.labelLarge
?.copyWith(color: context.colorScheme.error);
borderColors = context.colorScheme.error;
break;
case StatusState.initial:
case StatusState.success:
case StatusState.loading:
case null:
break;
}
return TextInputStyle(
labelStyle: labelStyle,
hintStyle: hintStyle,
iconColor: iconColor,
prefixIconColor: prefixIconColor,
prefixStyle: prefixStyle,
suffixStyle: suffixStyle,
suffixIconColor: suffixIconColor,
backgroundColors: backgroundColors,
borderColors: borderColors,
boxShadow: boxShadow,
radius: radius,
inputStyle: inputStyle,
);
}
@override @override
TextInputStyle? computeExtensionValueFn( TextInputStyle? computeExtensionValueFn(
BuildContext context, BuildContext context,
TextInputThemeExtension? themeExtension, { TextInputThemeExtension? themeExtension, {
TextInputState? extra, TextInputState? extra,
}) { }) {
TextInputStyle? textInputStyle; TextInputStyle? style;
switch (extra?.controlState) { switch (extra?.controlState) {
case ControlState.focused:
textInputStyle = themeExtension?.focusedStyle;
break;
case ControlState.disabled: case ControlState.disabled:
textInputStyle = themeExtension?.disableStyle; style = themeExtension?.disabledStyle;
break; break;
case ControlState.normal: case ControlState.focused:
textInputStyle = themeExtension?.normalStyle; style = themeExtension?.focusedStyle;
break; break;
case ControlState.hovered: case ControlState.hovered:
case ControlState.tapped: case ControlState.tapped:
case ControlState.normal:
case null: case null:
style = themeExtension?.normalStyle;
break; break;
} }
TextInputStyle? style; if (extra?.isInvalid ?? false) {
switch (extra?.statusState) { style = themeExtension?.invalidStyle;
case StatusState.error:
style = themeExtension?.errorStyle;
break;
case StatusState.initial:
case StatusState.success:
case StatusState.loading:
case null:
break;
} }
return TextInputStyle.merge(textInputStyle, style); return style;
} }
@override
TextInputThemeExtension? getDefaultExtension(
BuildContext context,
) =>
TextInputThemeExtensionDefault.from(Theme.of(context));
@override
final TextInputStyle? Function(
BuildContext context, {
TextInputState? extra,
}) customStyleFn;
} }

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_impl.dart';
export 'flat_button_theme_extension_impl.dart';
export 'simple_icon_button_theme_extension_impl.dart';
export 'symbol_button_theme_extension_impl.dart';

View File

@ -0,0 +1,141 @@
// 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';
class FileSelectionButtonThemeExtensionImpl
extends FileSelectionButtonThemeExtension {
const FileSelectionButtonThemeExtensionImpl({
super.disabledStyle,
super.focusedStyle,
super.hoveredStyle,
super.normalStyle,
super.tappedStyle,
super.selectedStyle,
super.invalidStyle,
});
factory FileSelectionButtonThemeExtensionImpl.light({ThemeData? theme}) {
theme ??= ThemeData.light();
final style = FileSelectionButtonStyle(
titleStyle: theme.textTheme.labelLarge,
subtitleStyle: theme.textTheme.labelSmall,
radius: BorderRadius.circular(12),
padding: const EdgeInsets.all(13),
foregroundColors: const MultiColor.single(Color(0xFF24262A)),
backgroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors: const MultiColor([
Color(0xFFDDE0E3),
Color(0xFFCACCD4),
]),
stroke: 2,
);
return FileSelectionButtonThemeExtensionImpl(
normalStyle: style,
disabledStyle: style.copyWith(
foregroundColors:
MultiColor.single(const Color(0xFF24262A).withOpacity(0.4)),
backgroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors:
MultiColor.single(const Color(0xFF24262A).withOpacity(0.4)),
),
hoveredStyle: style.copyWith(
backgroundColors:
MultiColor.single(const Color(0xFF24262A).withOpacity(0.4)),
),
focusedStyle: style.copyWith(stroke: 4),
tappedStyle: style.copyWith(
backgroundColors:
MultiColor.single(const Color(0xFF24262A).withOpacity(0.4)),
),
invalidStyle: style.copyWith(
subtitleStyle: theme.textTheme.labelSmall?.copyWith(
fontSize: 11,
fontWeight: FontWeight.w400,
color: const Color(0xFFF44464),
),
borderColors: const MultiColor([
Color(0xFFF44464),
Color(0xFFF44464),
]),
),
// Unused
selectedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFF24262A)),
borderColors: const MultiColor([
Color(0xFF00D16C),
Color(0xFF00D16C),
]),
),
);
}
factory FileSelectionButtonThemeExtensionImpl.dark({ThemeData? theme}) {
theme ??= ThemeData.dark();
final style = FileSelectionButtonStyle(
titleStyle: theme.textTheme.labelLarge,
subtitleStyle: theme.textTheme.labelSmall,
radius: BorderRadius.circular(12),
padding: const EdgeInsets.all(13),
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor.single(Color(0xFF24262A)),
borderColors: const MultiColor([
Color(0xFF24262A),
Color(0xFF24262A),
]),
stroke: 2,
);
return FileSelectionButtonThemeExtensionImpl(
normalStyle: style,
disabledStyle: style.copyWith(
foregroundColors:
MultiColor.single(const Color(0xFFDDE0E3).withOpacity(0.4)),
backgroundColors: const MultiColor.single(Color(0xFF24262A)),
borderColors:
MultiColor.single(const Color(0xFFDDE0E3).withOpacity(0.4)),
),
hoveredStyle: style.copyWith(
backgroundColors:
MultiColor.single(const Color(0xFFDDE0E3).withOpacity(0.4)),
),
focusedStyle: style.copyWith(stroke: 4),
tappedStyle: style.copyWith(
backgroundColors:
MultiColor.single(const Color(0xFFDDE0E3).withOpacity(0.4)),
),
invalidStyle: style.copyWith(
subtitleStyle: theme.textTheme.labelSmall?.copyWith(
fontSize: 11,
fontWeight: FontWeight.w400,
color: const Color(0xFFF44464),
),
borderColors: const MultiColor([
Color(0xFFF44464),
Color(0xFFF44464),
]),
),
// Unused
selectedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors: const MultiColor([
Color(0xFF00D16C),
Color(0xFF00D16C),
]),
),
);
}
}

View File

@ -0,0 +1,133 @@
// 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';
class FlatButtonThemeExtensionImpl extends FlatButtonThemeExtension {
const FlatButtonThemeExtensionImpl({
super.disabledStyle,
super.focusedStyle,
super.hoveredStyle,
super.normalStyle,
super.tappedStyle,
});
factory FlatButtonThemeExtensionImpl.light({ThemeData? theme}) {
theme ??= ThemeData.light();
final style = FlatButtonStyle(
labelStyle: theme.textTheme.labelLarge,
radius: BorderRadius.circular(15),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
backgroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
stroke: 3,
);
return FlatButtonThemeExtensionImpl(
normalStyle: style,
disabledStyle: style.copyWith(
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color(0xFF3C97FB).withOpacity(0.4),
),
foregroundColors:
MultiColor.single(const Color(0xFF3C97FB).withOpacity(0.4)),
backgroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors:
MultiColor.single(const Color(0xFF3C97FB).withOpacity(0.4)),
stroke: 1,
),
hoveredStyle: style.copyWith(
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color(0xFFDDE0E3),
),
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
),
focusedStyle: style.copyWith(stroke: 5),
tappedStyle: style.copyWith(
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color(0xFFDDE0E3),
),
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
borderColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
),
);
}
factory FlatButtonThemeExtensionImpl.dark({ThemeData? theme}) {
theme ??= ThemeData.dark();
final style = FlatButtonStyle(
labelStyle: theme.textTheme.labelLarge,
radius: BorderRadius.circular(15),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor.single(Color(0xFF24262A)),
borderColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
stroke: 3,
);
return FlatButtonThemeExtensionImpl(
normalStyle: style,
disabledStyle: style.copyWith(
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color(0xFF60656A),
),
foregroundColors: const MultiColor.single(Color(0xFF60656A)),
backgroundColors: const MultiColor.single(Color(0xFF33373E)),
borderColors: const MultiColor([Color(0xFF60656A), Color(0xFF383C40)]),
stroke: 1,
),
hoveredStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
),
focusedStyle: style.copyWith(stroke: 5),
tappedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
borderColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
),
);
}
}

View File

@ -0,0 +1,121 @@
// 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';
class SimpleIconButtonThemeExtensionImpl
extends SimpleIconButtonThemeExtension {
const SimpleIconButtonThemeExtensionImpl({
super.disabledStyle,
super.focusedStyle,
super.hoveredStyle,
super.normalStyle,
super.tappedStyle,
});
factory SimpleIconButtonThemeExtensionImpl.light({ThemeData? theme}) {
theme ??= ThemeData.light();
final style = SimpleIconButtonStyle(
dimension: 30,
radius: BorderRadius.circular(15),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
backgroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
stroke: 3,
);
return SimpleIconButtonThemeExtensionImpl(
normalStyle: style,
disabledStyle: style.copyWith(
foregroundColors:
MultiColor.single(const Color(0xFF3C97FB).withOpacity(0.4)),
backgroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors:
MultiColor.single(const Color(0xFF3C97FB).withOpacity(0.4)),
stroke: 1,
),
hoveredStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
),
focusedStyle: style.copyWith(stroke: 5),
tappedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
borderColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
),
);
}
factory SimpleIconButtonThemeExtensionImpl.dark({ThemeData? theme}) {
theme ??= ThemeData.dark();
final style = SimpleIconButtonStyle(
radius: BorderRadius.circular(15),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor.single(Color(0xFF24262A)),
borderColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
stroke: 3,
);
return SimpleIconButtonThemeExtensionImpl(
normalStyle: style,
disabledStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFF60656A)),
backgroundColors: const MultiColor.single(Color(0xFF33373E)),
borderColors: const MultiColor([Color(0xFF60656A), Color(0xFF383C40)]),
stroke: 1,
),
hoveredStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
),
focusedStyle: style.copyWith(stroke: 5),
tappedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
borderColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
),
);
}
}

View File

@ -0,0 +1,148 @@
// 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';
class SymbolButtonThemeExtensionImpl extends SymbolButtonThemeExtension {
const SymbolButtonThemeExtensionImpl({
super.disabledStyle,
super.focusedStyle,
super.hoveredStyle,
super.normalStyle,
super.tappedStyle,
super.selectedStyle,
});
factory SymbolButtonThemeExtensionImpl.light({ThemeData? theme}) {
theme ??= ThemeData.light();
final style = SymbolButtonStyle(
labelStyle: theme.textTheme.labelLarge,
radius: BorderRadius.circular(15),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
backgroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
stroke: 3,
);
return SymbolButtonThemeExtensionImpl(
normalStyle: style,
disabledStyle: style.copyWith(
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color(0xFF3C97FB).withOpacity(0.4),
),
foregroundColors:
MultiColor.single(const Color(0xFF3C97FB).withOpacity(0.4)),
backgroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors:
MultiColor.single(const Color(0xFF3C97FB).withOpacity(0.4)),
stroke: 1,
),
hoveredStyle: style.copyWith(
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color(0xFFDDE0E3),
),
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
),
focusedStyle: style.copyWith(stroke: 5),
tappedStyle: style.copyWith(
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color(0xFFDDE0E3),
),
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
borderColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
),
selectedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors: const MultiColor([
Color(0xFF00D16C),
Color(0xFF00D16C),
]),
),
);
}
factory SymbolButtonThemeExtensionImpl.dark({ThemeData? theme}) {
theme ??= ThemeData.dark();
final style = SymbolButtonStyle(
labelStyle: theme.textTheme.labelLarge,
radius: BorderRadius.circular(15),
padding: const EdgeInsets.all(10),
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor.single(Color(0xFF24262A)),
borderColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
stroke: 3,
);
return SymbolButtonThemeExtensionImpl(
normalStyle: style,
disabledStyle: style.copyWith(
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color(0xFF60656A),
),
foregroundColors: const MultiColor.single(Color(0xFF60656A)),
backgroundColors: const MultiColor.single(Color(0xFF33373E)),
borderColors: const MultiColor([Color(0xFF60656A), Color(0xFF383C40)]),
stroke: 1,
),
hoveredStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF3C97FB),
Color(0xFF436EF4),
]),
),
focusedStyle: style.copyWith(stroke: 5),
tappedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
backgroundColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
borderColors: const MultiColor([
Color(0xFF4B68FF),
Color(0xFF3531F5),
]),
),
selectedStyle: style.copyWith(
foregroundColors: const MultiColor.single(Color(0xFFDDE0E3)),
borderColors: const MultiColor([
Color(0xFF00D16C),
Color(0xFF00D16C),
]),
),
);
}
}

View File

@ -0,0 +1,95 @@
// 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 card_theme_extension_impl}
/// Card theme extension that implements Wyatt Theme.
/// {@endtemplate}
class CardThemeExtensionImpl extends CardThemeExtension {
/// {@macro card_theme_extension_impl}
const CardThemeExtensionImpl({
super.radius,
super.padding,
super.backgroundColors,
super.borderColors,
super.stroke,
super.shadow,
super.minSize,
super.maxSize,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
});
/// {@macro card_theme_extension_impl}
///
/// You can pass a [ThemeData] to use its text styles.
///
/// This is the default light theme.
factory CardThemeExtensionImpl.light({ThemeData? theme}) {
theme ??= ThemeData.light();
return CardThemeExtensionImpl(
radius: const BorderRadius.all(Radius.circular(12)),
padding: const EdgeInsets.all(25),
stroke: 1,
backgroundColors: const MultiColor.single(Color(0xFFF6F6F6)),
borderColors: const MultiColor([
Color(0xFFDDE0E3),
Color(0xFFCACCD4),
]),
titleStyle: theme.textTheme.titleLarge,
subtitleStyle: theme.textTheme.titleMedium,
bodyStyle: theme.textTheme.bodyMedium,
minSize: const Size(330, 0),
maxSize: const Size(390, double.infinity),
shadow: BoxShadow(
color: const Color(0xFF24262A).withOpacity(0.05),
blurRadius: 30,
offset: const Offset(0, 5),
),
);
}
/// {@macro card_theme_extension_impl}
///
/// This is the default dark theme.
factory CardThemeExtensionImpl.dark({ThemeData? theme}) {
theme ??= ThemeData.dark();
return CardThemeExtensionImpl(
radius: const BorderRadius.all(Radius.circular(12)),
padding: const EdgeInsets.all(25),
stroke: 1,
backgroundColors:
const MultiColor([Color(0xFF26292D), Color(0xFF202327)]),
borderColors: const MultiColor([
Color(0xFF60656A),
Color(0xFF383C40),
]),
titleStyle: theme.textTheme.titleLarge,
subtitleStyle: theme.textTheme.titleMedium,
bodyStyle: theme.textTheme.bodyMedium,
minSize: const Size(330, 0),
maxSize: const Size(390, double.infinity),
shadow: BoxShadow(
color: const Color(0xFF24262A).withOpacity(0.15),
blurRadius: 30,
offset: const Offset(0, 5),
),
);
}
}

View File

@ -0,0 +1,123 @@
// 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 text_input_theme_extension}
/// Text input theme extension that implements Wyatt Theme
/// {@endtemplate}
class TextInputThemeExtensionImpl extends TextInputThemeExtension {
/// {@macro text_input_theme_extension}
const TextInputThemeExtensionImpl({
super.normalStyle,
super.focusedStyle,
super.disabledStyle,
super.invalidStyle,
});
factory TextInputThemeExtensionImpl.light({ThemeData? theme}) {
theme ??= ThemeData.light();
return TextInputThemeExtensionImpl(
normalStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(221, 224, 227, 1),
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color.fromRGBO(55, 65, 81, 1),
),
inputStyle: theme.textTheme.bodyMedium?.copyWith(
color: const Color.fromRGBO(55, 65, 81, 1),
),
),
focusedStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(60, 125, 251, 1),
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color.fromRGBO(55, 65, 81, 1),
),
inputStyle: theme.textTheme.bodyMedium?.copyWith(
color: const Color.fromRGBO(55, 65, 81, 1),
),
),
invalidStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(244, 68, 100, 1),
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color.fromRGBO(244, 68, 100, 1),
),
inputStyle: theme.textTheme.bodyMedium?.copyWith(
color: const Color.fromRGBO(55, 65, 81, 1),
),
),
disabledStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(229, 231, 235, 1),
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color.fromRGBO(156, 163, 175, 1),
),
inputStyle: theme.textTheme.bodyMedium?.copyWith(
color: const Color.fromRGBO(156, 163, 175, 1),
),
),
);
}
factory TextInputThemeExtensionImpl.dark({ThemeData? theme}) {
theme ??= ThemeData.dark();
return TextInputThemeExtensionImpl(
normalStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(96, 101, 106, 1),
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color.fromRGBO(204, 204, 204, 1),
),
inputStyle: theme.textTheme.bodyMedium?.copyWith(
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
focusedStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(60, 125, 251, 1),
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color.fromRGBO(204, 204, 204, 1),
),
inputStyle: theme.textTheme.bodyMedium?.copyWith(
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
invalidStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(244, 68, 100, 1),
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color.fromRGBO(244, 68, 100, 1),
),
inputStyle: theme.textTheme.bodyMedium?.copyWith(
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
disabledStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const Color.fromRGBO(96, 101, 106, 1),
labelStyle: theme.textTheme.labelLarge?.copyWith(
color: const Color.fromRGBO(96, 101, 106, 1),
),
inputStyle: theme.textTheme.bodyMedium?.copyWith(
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
);
}
}

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_extensions/button_theme_extensions.dart';
export 'card_theme_extension_impl.dart';
export 'text_input_theme_extension_impl.dart';

View File

@ -1,52 +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:wyatt_ui_components/wyatt_ui_components.dart';
abstract class FileSelectionButtonThemeExtension
extends ThemeExtension<FileSelectionButtonThemeExtension> {
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;
}

View File

@ -1,44 +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:wyatt_ui_components/wyatt_ui_components.dart';
abstract class FlatButtonThemeExtension
extends ThemeExtension<FlatButtonThemeExtension> {
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;
}

View File

@ -1,44 +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:wyatt_ui_components/wyatt_ui_components.dart';
abstract class SimpleIconButtonThemeExtension
extends ThemeExtension<SimpleIconButtonThemeExtension> {
const SimpleIconButtonThemeExtension({
this.disabledStyle,
this.focusedStyle,
this.hoveredStyle,
this.normalStyle,
this.tappedStyle,
});
/// Style of this button in disabled state
final SimpleIconButtonStyle? disabledStyle;
/// Style of this button in focused state
final SimpleIconButtonStyle? focusedStyle;
/// Style of this button in hovered state
final SimpleIconButtonStyle? hoveredStyle;
/// Style of this button in normal state
final SimpleIconButtonStyle? normalStyle;
/// Style of this button in tapped state
final SimpleIconButtonStyle? tappedStyle;
}

View File

@ -1,48 +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:wyatt_ui_components/wyatt_ui_components.dart';
abstract class SymbolButtonThemeExtension
extends ThemeExtension<SymbolButtonThemeExtension> {
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;
}

View File

@ -14,8 +14,6 @@
// 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 './button_theme_extension/button_theme_extension.dart';
export './card_theme_extension.dart';
export './loader_theme_extension.dart'; export './loader_theme_extension.dart';
export './rich_text_builder_theme_extension.dart'; export './rich_text_builder_theme_extension.dart';
export './text_input_theme_extension.dart'; export './text_input_theme_extension.dart';

View File

@ -14,7 +14,8 @@
// 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 './components/components.dart'; export 'components/components.dart';
export './core/core.dart'; export 'core/core.dart';
export './domain/domain.dart'; export 'data/data.dart';
export './features/wyatt_component_theme_data.dart'; export 'domain/domain.dart';
export 'features/wyatt_component_theme_data.dart';

View File

@ -15,6 +15,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
/// UIKit and Design System used in Wyatt Studio. /// UIKit and Design System used in Wyatt Studio.
///
/// Built using `wyatt_ui_components`.
library wyatt_ui_kit; library wyatt_ui_kit;
export 'package:wyatt_ui_components/src/core/extensions/build_context_extensions.dart'; export 'package:wyatt_ui_components/src/core/extensions/build_context_extensions.dart';