Compare commits

...

17 Commits

Author SHA1 Message Date
2692c60743
feat(analysis): upgrade
Some checks failed
continuous-integration/drone/pr Build is failing
2023-05-03 10:38:18 +02:00
e76857f118
feat(layout)!: update layout plugins with new components system
Some checks failed
continuous-integration/drone/pr Build is failing
2023-05-02 13:32:52 +02:00
96369e24f9
feat(ui_components): make textwrapper toString useful 2023-05-02 13:32:20 +02:00
635bb329ea
style(ui_components): fix theme resolver line
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-28 18:42:13 +02:00
bfbeabe7ec
feat(ui): add pricing card
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-28 18:40:40 +02:00
01a5619dc5
feat(ui): update default extension implementation
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-28 16:08:10 +02:00
4ebb679a29
feat(ui): add animated decorated box + animate all buttons + customize duration in style 2023-04-28 15:33:26 +02:00
abd5e1b558
feat(ui): add colors and rework ComponentThemeData
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-28 14:04:55 +02:00
a024b7e70a
feat(ui_kit): update example by removing adaptative theme 2023-04-28 14:04:15 +02:00
4097a420c8
feat(ui)!: move last extensions + add extension provider
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-27 20:28:08 +02:00
8f5e3923d6
feat(ui)!: rework theme resolver mechanism + move theme extension implementations
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-27 16:55:10 +02:00
01269027f2
feat(ui): make components more coherent + docs 2023-04-27 16:54:16 +02:00
0d5109fc77
feat(ui): make gradient as component
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-26 18:15:47 +02:00
3fb4020594
feat(ui): fix, rename, rewrite some helpers 2023-04-26 18:14:00 +02:00
cef73aa62d
fix(gen): rename builder correctly 2023-04-26 18:12:10 +02:00
32cc6e8288
feat(ui_kit): make flat button fade on transition 2023-04-18 11:47:56 +02:00
2baaf5c0bb
feat(ui_kit): add more control over flat button prefix/suffix color 2023-04-18 09:33:00 +02:00
220 changed files with 7631 additions and 3322 deletions

View File

@ -1 +1 @@
2.4.1 2.4.3

View File

@ -20,7 +20,7 @@
![SDK: Dart & Flutter](https://img.shields.io/badge/SDK-Dart%20%7C%20Flutter-blue?style=flat-square) ![SDK: Dart & Flutter](https://img.shields.io/badge/SDK-Dart%20%7C%20Flutter-blue?style=flat-square)
This package provides lint rules for Dart and Flutter which are used at [Wyatt Studio](https://wyatt-studio.fr). For more information, see the complete list of options in **lib/analysis_options.2.4.1.yaml**. This package provides lint rules for Dart and Flutter which are used at [Wyatt Studio](https://wyatt-studio.fr). For more information, see the complete list of options in **lib/analysis_options.2.4.3.yaml**.
**Note**: This package was heavily inspired by [pedantic](https://github.com/dart-lang/pedantic), [Very Good Analysis](https://github.com/VeryGoodOpenSource/very_good_analysis) and the official [flutter_lints](https://pub.dev/packages/flutter_lints). **Note**: This package was heavily inspired by [pedantic](https://github.com/dart-lang/pedantic), [Very Good Analysis](https://github.com/VeryGoodOpenSource/very_good_analysis) and the official [flutter_lints](https://pub.dev/packages/flutter_lints).
@ -29,7 +29,7 @@ This package provides lint rules for Dart and Flutter which are used at [Wyatt
Using CLI: Using CLI:
```sh ```sh
dart pub add wyatt_analysis:2.4.1 --dev --hosted-url=https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ dart pub add wyatt_analysis:2.4.3 --dev --hosted-url=https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
``` ```
## Usage ## Usage
@ -39,7 +39,7 @@ To use the lints, add a dependency in your `pubspec.yaml` :
```yaml ```yaml
wyatt_analysis: wyatt_analysis:
hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
version: 2.4.1 version: 2.4.3
``` ```
Then, add an include in `analysis_options.yaml` : Then, add an include in `analysis_options.yaml` :
@ -57,13 +57,13 @@ include: package:wyatt_analysis/analysis_options.flutter.yaml
If you wish to restrict the lint version, specify a version of `analysis_options.yaml` instead: If you wish to restrict the lint version, specify a version of `analysis_options.yaml` instead:
```yaml ```yaml
include: package:wyatt_analysis/analysis_options.flutter.2.4.1.yaml include: package:wyatt_analysis/analysis_options.flutter.2.4.3.yaml
``` ```
If you just want **Dart** version: If you just want **Dart** version:
```yaml ```yaml
include: package:wyatt_analysis/analysis_options.2.4.1.yaml include: package:wyatt_analysis/analysis_options.2.4.3.yaml
``` ```
## Suppressing Lints ## Suppressing Lints

View File

@ -0,0 +1,217 @@
# 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/>.
analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
errors:
todo: ignore
close_sinks: ignore
missing_required_param: error
missing_return: error
exclude:
- lib/l10n/**
- lib/generated/**
- lib/gen/**
- lib/generated_plugin_registrant.dart
- test/.test_coverage.dart
- "**/*.g.dart"
- "**/*.freezed.dart"
linter:
rules:
- always_declare_return_types
- always_put_control_body_on_new_line
- always_put_required_named_parameters_first
- always_require_non_null_named_parameters
- always_use_package_imports
- annotate_overrides
- avoid_bool_literals_in_conditional_expressions
- avoid_catching_errors
- avoid_double_and_int_checks
- avoid_dynamic_calls
- avoid_empty_else
- avoid_equals_and_hash_code_on_mutable_classes
- avoid_escaping_inner_quotes
- avoid_field_initializers_in_const_classes
- avoid_final_parameters
- avoid_function_literals_in_foreach_calls
- avoid_init_to_null
- avoid_js_rounded_ints
- avoid_multiple_declarations_per_line
- avoid_null_checks_in_equality_operators
- avoid_positional_boolean_parameters
- avoid_private_typedef_functions
- avoid_redundant_argument_values
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_null_for_future
- avoid_returning_null_for_void
- avoid_returning_this
- avoid_setters_without_getters
- avoid_shadowing_type_parameters
- avoid_single_cascade_in_expression_statements
- avoid_slow_async_io
- avoid_type_to_string
- avoid_types_as_parameter_names
- avoid_types_on_closure_parameters
- avoid_unused_constructor_parameters
- avoid_void_async
- await_only_futures
- camel_case_extensions
- camel_case_types
- cancel_subscriptions
- cascade_invocations
- cast_nullable_to_non_nullable
- collection_methods_unrelated_type
- combinators_ordering
- comment_references
- conditional_uri_does_not_exist
- constant_identifier_names
- control_flow_in_finally
- curly_braces_in_flow_control_structures
- depend_on_referenced_packages
- deprecated_consistency
- directives_ordering
- empty_catches
- empty_constructor_bodies
- empty_statements
- eol_at_end_of_file
- exhaustive_cases
- file_names
- flutter_style_todos
- hash_and_equals
- implementation_imports
- implicit_call_tearoffs
- iterable_contains_unrelated_type
- join_return_with_assignment
- leading_newlines_in_multiline_strings
- library_names
- library_prefixes
- library_private_types_in_public_api
- lines_longer_than_80_chars
- list_remove_unrelated_type
- literal_only_boolean_expressions
- missing_whitespace_between_adjacent_strings
- no_adjacent_strings_in_list
- no_default_cases
- no_duplicate_case_values
- no_leading_underscores_for_library_prefixes
- no_leading_underscores_for_local_identifiers
- no_runtimeType_toString
- non_constant_identifier_names
- noop_primitive_operations
- null_check_on_nullable_type_parameter
- null_closures
- one_member_abstracts
- only_throw_errors
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
- parameter_assignments
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_asserts_with_message
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_constructors_over_static_methods
- prefer_contains
- prefer_equal_for_default_values
- prefer_expression_function_bodies
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
- prefer_for_elements_to_map_fromIterable
- prefer_function_declarations_over_variables
- prefer_generic_function_type_aliases
- prefer_if_elements_to_conditional_expressions
- prefer_if_null_operators
- prefer_initializing_formals
- prefer_inlined_adds
- prefer_int_literals
- prefer_interpolation_to_compose_strings
- prefer_is_empty
- prefer_is_not_empty
- prefer_is_not_operator
- prefer_iterable_whereType
- prefer_mixin
- prefer_null_aware_method_calls
- prefer_null_aware_operators
- prefer_single_quotes
- prefer_spread_collections
- prefer_typing_uninitialized_variables
- prefer_void_to_null
- provide_deprecation_message
- recursive_getters
- require_trailing_commas
- slash_for_doc_comments
- sort_constructors_first
- sort_unnamed_constructors_first
- test_types_in_equals
- throw_in_finally
- tighten_type_of_initializing_formals
- type_annotate_public_apis
- type_init_formals
- unawaited_futures
- unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- unnecessary_const
- unnecessary_constructor_name
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_late
- unnecessary_new
- unnecessary_null_aware_assignments
- unnecessary_null_checks
- unnecessary_null_in_if_null_operators
- unnecessary_nullable_for_final_variable_declarations
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_raw_strings
- unnecessary_statements
- unnecessary_string_escapes
- unnecessary_string_interpolations
- unnecessary_this
- unnecessary_to_list_in_spreads
- unrelated_type_equality_checks
- unsafe_html
- use_enums
- use_function_type_syntax_for_parameters
- use_if_null_to_convert_nulls_to_bools
- use_is_even_rather_than_modulo
- use_late_for_private_fields_and_variables
- use_named_constants
- use_raw_strings
- use_rethrow_when_possible
- use_setters_to_change_properties
- use_string_buffers
- use_string_in_part_of_directives
- use_super_parameters
- use_test_throws_matchers
- use_to_and_as_if_applicable
- valid_regexps
- void_checks

View File

@ -0,0 +1,219 @@
# 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/>.
analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
errors:
todo: ignore
close_sinks: ignore
missing_required_param: error
missing_return: error
exclude:
- lib/l10n/**
- lib/generated/**
- lib/gen/**
- lib/generated_plugin_registrant.dart
- test/.test_coverage.dart
- "**/*.g.dart"
- "**/*.freezed.dart"
linter:
rules:
- always_declare_return_types
- always_put_control_body_on_new_line
- always_put_required_named_parameters_first
- always_require_non_null_named_parameters
- always_use_package_imports
- annotate_overrides
- avoid_bool_literals_in_conditional_expressions
- avoid_catching_errors
- avoid_double_and_int_checks
- avoid_dynamic_calls
- avoid_empty_else
- avoid_equals_and_hash_code_on_mutable_classes
- avoid_escaping_inner_quotes
- avoid_field_initializers_in_const_classes
- avoid_final_parameters
- avoid_function_literals_in_foreach_calls
- avoid_init_to_null
- avoid_js_rounded_ints
- avoid_multiple_declarations_per_line
- avoid_null_checks_in_equality_operators
- avoid_positional_boolean_parameters
- avoid_private_typedef_functions
- avoid_redundant_argument_values
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_null_for_future
- avoid_returning_null_for_void
- avoid_returning_this
- avoid_setters_without_getters
- avoid_shadowing_type_parameters
- avoid_single_cascade_in_expression_statements
- avoid_slow_async_io
- avoid_type_to_string
- avoid_types_as_parameter_names
- avoid_types_on_closure_parameters
- avoid_unused_constructor_parameters
- avoid_void_async
- await_only_futures
- camel_case_extensions
- camel_case_types
- cancel_subscriptions
- cascade_invocations
- cast_nullable_to_non_nullable
- collection_methods_unrelated_type
- combinators_ordering
- comment_references
- conditional_uri_does_not_exist
- constant_identifier_names
- control_flow_in_finally
- curly_braces_in_flow_control_structures
- dangling_library_doc_comments
- depend_on_referenced_packages
- deprecated_consistency
- directives_ordering
- empty_catches
- empty_constructor_bodies
- empty_statements
- eol_at_end_of_file
- exhaustive_cases
- file_names
- flutter_style_todos
- hash_and_equals
- implementation_imports
- implicit_call_tearoffs
- iterable_contains_unrelated_type
- join_return_with_assignment
- leading_newlines_in_multiline_strings
- library_names
- library_prefixes
- library_private_types_in_public_api
- lines_longer_than_80_chars
- list_remove_unrelated_type
- literal_only_boolean_expressions
- missing_whitespace_between_adjacent_strings
- no_adjacent_strings_in_list
- no_default_cases
- no_duplicate_case_values
- no_leading_underscores_for_library_prefixes
- no_leading_underscores_for_local_identifiers
- no_runtimeType_toString
- non_constant_identifier_names
- noop_primitive_operations
- null_check_on_nullable_type_parameter
- null_closures
- one_member_abstracts
- only_throw_errors
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
- parameter_assignments
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_asserts_with_message
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_constructors_over_static_methods
- prefer_contains
- prefer_equal_for_default_values
- prefer_expression_function_bodies
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
- prefer_for_elements_to_map_fromIterable
- prefer_function_declarations_over_variables
- prefer_generic_function_type_aliases
- prefer_if_elements_to_conditional_expressions
- prefer_if_null_operators
- prefer_initializing_formals
- prefer_inlined_adds
- prefer_int_literals
- prefer_interpolation_to_compose_strings
- prefer_is_empty
- prefer_is_not_empty
- prefer_is_not_operator
- prefer_iterable_whereType
- prefer_mixin
- prefer_null_aware_method_calls
- prefer_null_aware_operators
- prefer_single_quotes
- prefer_spread_collections
- prefer_typing_uninitialized_variables
- prefer_void_to_null
- provide_deprecation_message
- recursive_getters
- require_trailing_commas
- slash_for_doc_comments
- sort_constructors_first
- sort_pub_dependencies
- sort_unnamed_constructors_first
- test_types_in_equals
- throw_in_finally
- tighten_type_of_initializing_formals
- type_annotate_public_apis
- type_init_formals
- unawaited_futures
- unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- unnecessary_const
- unnecessary_constructor_name
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_late
- unnecessary_new
- unnecessary_null_aware_assignments
- unnecessary_null_checks
- unnecessary_null_in_if_null_operators
- unnecessary_nullable_for_final_variable_declarations
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_raw_strings
- unnecessary_statements
- unnecessary_string_escapes
- unnecessary_string_interpolations
- unnecessary_this
- unnecessary_to_list_in_spreads
- unrelated_type_equality_checks
- unsafe_html
- use_enums
- use_function_type_syntax_for_parameters
- use_if_null_to_convert_nulls_to_bools
- use_is_even_rather_than_modulo
- use_late_for_private_fields_and_variables
- use_named_constants
- use_raw_strings
- use_rethrow_when_possible
- use_setters_to_change_properties
- use_string_buffers
- use_string_in_part_of_directives
- use_super_parameters
- use_test_throws_matchers
- use_to_and_as_if_applicable
- valid_regexps
- void_checks

View File

@ -0,0 +1,32 @@
# 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/>.
include: package:wyatt_analysis/analysis_options.2.4.2.yaml
linter:
rules:
- avoid_print
- avoid_unnecessary_containers
- avoid_web_libraries_in_flutter
- no_logic_in_create_state
- sized_box_for_whitespace
- sized_box_shrink_expand
- sort_child_properties_last
- use_build_context_synchronously
- use_colored_box
- use_decorated_box
- use_full_hex_values_for_flutter_colors
- use_key_in_widget_constructors

View File

@ -0,0 +1,32 @@
# 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/>.
include: package:wyatt_analysis/analysis_options.2.4.3.yaml
linter:
rules:
- avoid_print
- avoid_unnecessary_containers
- avoid_web_libraries_in_flutter
- no_logic_in_create_state
- sized_box_for_whitespace
- sized_box_shrink_expand
- sort_child_properties_last
- use_build_context_synchronously
- use_colored_box
- use_decorated_box
- use_full_hex_values_for_flutter_colors
- use_key_in_widget_constructors

View File

@ -14,4 +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/>.
include: package:wyatt_analysis/analysis_options.flutter.2.4.1.yaml include: package:wyatt_analysis/analysis_options.flutter.2.4.3.yaml

View File

@ -14,4 +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/>.
include: package:wyatt_analysis/analysis_options.2.4.1.yaml include: package:wyatt_analysis/analysis_options.2.4.3.yaml

View File

@ -18,4 +18,4 @@
/// used internally at [Wyatt Studio](https://wyatt-studio.fr). /// used internally at [Wyatt Studio](https://wyatt-studio.fr).
library wyatt_analysis; library wyatt_analysis;
const String wyattAnalysisVersion = '2.4.1'; const String wyattAnalysisVersion = '2.4.3';

View File

@ -88,6 +88,7 @@ class $CustomAppBarCWProxyImpl implements $TopAppBarComponentCWProxy {
Key? key, Key? key,
}) => }) =>
CustomAppBar( CustomAppBar(
key: key ?? _value.key,
title: title ?? _value.title, title: title ?? _value.title,
); );
} }

View File

@ -24,7 +24,9 @@ class $CustomBottomBarCWProxyImpl
int? currentIndex, int? currentIndex,
Key? key, Key? key,
}) => }) =>
CustomBottomBar(); CustomBottomBar(
key: key ?? _value.key,
);
} }
mixin $CustomBottomBarCWMixin on Component { mixin $CustomBottomBarCWMixin on Component {

View File

@ -5,13 +5,12 @@ import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'custom_error_widget.g.dart'; part 'custom_error_widget.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class CustomErrorWidget extends ErrorWidgetComponent class CustomErrorWidget extends ErrorComponent with $CustomErrorWidgetCWMixin {
with $CustomErrorWidgetCWMixin { const CustomErrorWidget({super.key, super.details});
CustomErrorWidget({super.key, super.error});
@override @override
Widget build(BuildContext context) => ColoredBox( Widget build(BuildContext context) => ColoredBox(
color: Colors.red, color: Colors.red,
child: Center(child: Text(error?.data ?? 'Error')), child: Center(child: Text(details?.data ?? 'Error')),
); );
} }

View File

@ -6,24 +6,36 @@ part of 'custom_error_widget.dart';
// ComponentCopyWithGenerator // ComponentCopyWithGenerator
// ************************************************************************** // **************************************************************************
class $CustomErrorWidgetCWProxyImpl implements $ErrorWidgetComponentCWProxy { class $CustomErrorWidgetCWProxyImpl implements $ErrorComponentCWProxy {
const $CustomErrorWidgetCWProxyImpl(this._value); const $CustomErrorWidgetCWProxyImpl(this._value);
final CustomErrorWidget _value; final CustomErrorWidget _value;
@override @override
CustomErrorWidget error(TextWrapper? error) => this(error: error); CustomErrorWidget colors(MultiColor? colors) => this(colors: colors);
@override
CustomErrorWidget message(TextWrapper? message) => this(message: message);
@override
CustomErrorWidget details(TextWrapper? details) => this(details: details);
@override
CustomErrorWidget themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver);
@override @override
CustomErrorWidget key(Key? key) => this(key: key); CustomErrorWidget key(Key? key) => this(key: key);
@override @override
CustomErrorWidget call({ CustomErrorWidget call({
TextWrapper? error, MultiColor? colors,
TextWrapper? message,
TextWrapper? details,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}) => }) =>
CustomErrorWidget( CustomErrorWidget(
error: error ?? _value.error, key: key ?? _value.key,
details: details ?? _value.details,
); );
} }
mixin $CustomErrorWidgetCWMixin on Component { mixin $CustomErrorWidgetCWMixin on Component {
$ErrorWidgetComponentCWProxy get copyWith => $ErrorComponentCWProxy get copyWith =>
$CustomErrorWidgetCWProxyImpl(this as CustomErrorWidget); $CustomErrorWidgetCWProxyImpl(this as CustomErrorWidget);
} }

View File

@ -5,11 +5,14 @@ import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'custom_loading_widget.g.dart'; part 'custom_loading_widget.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class CustomLoadingWidget extends LoadingWidgetComponent class CustomLoadingWidget extends LoaderComponent
with $CustomLoadingWidgetCWMixin { with $CustomLoadingWidgetCWMixin {
CustomLoadingWidget({super.key, super.color}); const CustomLoadingWidget({super.key, super.colors});
@override @override
Widget build(BuildContext context) => Widget build(BuildContext context) => Center(
Center(child: CircularProgressIndicator(color: color)); child: CircularProgressIndicator(
color: (colors?.isColor ?? false) ? colors!.color : Colors.blue,
),
);
} }

View File

@ -6,25 +6,42 @@ part of 'custom_loading_widget.dart';
// ComponentCopyWithGenerator // ComponentCopyWithGenerator
// ************************************************************************** // **************************************************************************
class $CustomLoadingWidgetCWProxyImpl class $CustomLoadingWidgetCWProxyImpl implements $LoaderComponentCWProxy {
implements $LoadingWidgetComponentCWProxy {
const $CustomLoadingWidgetCWProxyImpl(this._value); const $CustomLoadingWidgetCWProxyImpl(this._value);
final CustomLoadingWidget _value; final CustomLoadingWidget _value;
@override @override
CustomLoadingWidget color(Color? color) => this(color: color); CustomLoadingWidget colors(MultiColor? colors) => this(colors: colors);
@override
CustomLoadingWidget radius(double? radius) => this(radius: radius);
@override
CustomLoadingWidget stroke(double? stroke) => this(stroke: stroke);
@override
CustomLoadingWidget duration(Duration? duration) => this(duration: duration);
@override
CustomLoadingWidget flip(bool? flip) => this(flip: flip);
@override
CustomLoadingWidget themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver);
@override @override
CustomLoadingWidget key(Key? key) => this(key: key); CustomLoadingWidget key(Key? key) => this(key: key);
@override @override
CustomLoadingWidget call({ CustomLoadingWidget call({
Color? color, MultiColor? colors,
double? radius,
double? stroke,
Duration? duration,
bool? flip,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}) => }) =>
CustomLoadingWidget( CustomLoadingWidget(
color: color ?? _value.color, key: key ?? _value.key,
colors: colors ?? _value.colors,
); );
} }
mixin $CustomLoadingWidgetCWMixin on Component { mixin $CustomLoadingWidgetCWMixin on Component {
$LoadingWidgetComponentCWProxy get copyWith => $LoaderComponentCWProxy get copyWith =>
$CustomLoadingWidgetCWProxyImpl(this as CustomLoadingWidget); $CustomLoadingWidgetCWProxyImpl(this as CustomLoadingWidget);
} }

View File

@ -4,11 +4,11 @@ import 'package:bloc_layout_example/components/custom_error_widget.dart';
import 'package:bloc_layout_example/components/custom_loading_widget.dart'; import 'package:bloc_layout_example/components/custom_loading_widget.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
class AppThemeComponent { abstract class AppThemeComponent {
static ComponentThemeData get components => ComponentThemeData.raw( static const ComponentThemeData components = ComponentThemeData.raw(
appBar: const CustomAppBar(), topAppBar: CustomAppBar(),
bottomNavigationBar: const CustomBottomBar(), bottomNavigationBar: CustomBottomBar(),
loadingWidget: CustomLoadingWidget(), loader: CustomLoadingWidget(),
errorWidget: CustomErrorWidget(), error: CustomErrorWidget(),
); );
} }

View File

@ -32,7 +32,7 @@ class MyApp extends StatelessWidget {
// This widget is the root of your application. // This widget is the root of your application.
@override @override
Widget build(BuildContext context) => ComponentTheme( Widget build(BuildContext context) => ComponentTheme(
componentThemeWidget: AppThemeComponent.components, data: AppThemeComponent.components,
child: MaterialApp( child: MaterialApp(
title: 'Bloc Layout Example', title: 'Bloc Layout Example',
theme: ThemeData( theme: ThemeData(
@ -122,7 +122,7 @@ class ExampleFrameLayoutCrudConsumer
ExampleFrameLayoutCrudConsumer({super.key}) ExampleFrameLayoutCrudConsumer({super.key})
: super( : super(
customAppBar: (bar) => bar?.copyWith.title( customAppBar: (bar) => bar?.copyWith.title(
'Example Title'.wrap(), const TextWrapper('Example Title'),
), ),
); );
@ -139,7 +139,7 @@ class ExampleFrameLayoutCrudListConsumer
ExampleFrameLayoutCrudListConsumer({super.key}) ExampleFrameLayoutCrudListConsumer({super.key})
: super( : super(
customAppBar: (bar) => bar?.copyWith.title( customAppBar: (bar) => bar?.copyWith.title(
'Example Title'.wrap(), const TextWrapper('Example Title'),
), ),
); );

View File

@ -23,11 +23,12 @@ import 'package:wyatt_ui_components/wyatt_ui_components.dart';
mixin CrudMixin<Cubit extends bloc_base.Cubit<dynamic>, mixin CrudMixin<Cubit extends bloc_base.Cubit<dynamic>,
SuccessState extends CrudSuccess> { SuccessState extends CrudSuccess> {
Widget errorBuilder(BuildContext context, CrudError state) => Widget errorBuilder(BuildContext context, CrudError state) =>
context.components.errorWidget?.copyWith(error: state.message.wrap()) ?? context.components.errorComponent.call(
const SizedBox.shrink(); message: (state.message != null) ? TextWrapper(state.message!) : null,
);
Widget loadingBuilder(BuildContext context, CrudLoading state) => Widget loadingBuilder(BuildContext context, CrudLoading state) =>
context.components.loadingWidget ?? const SizedBox.shrink(); context.components.loader ?? const SizedBox.shrink();
Widget initialBuilder(BuildContext context, CrudInitial state) => Widget initialBuilder(BuildContext context, CrudInitial state) =>
const SizedBox.shrink(); const SizedBox.shrink();

View File

@ -15,7 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
/// Extension for component copy with feature /// Extension for component copy with feature
library component_copy_with_extension; library wyatt_component_copy_with_extension;
export './src/domain/domain.dart'; export './src/domain/domain.dart';
export 'src/component_copy_with_extension.dart'; export 'src/component_copy_with_extension.dart';

View File

@ -1,7 +1,7 @@
targets: targets:
$default: $default:
builders: builders:
component_copy_with_gen: wyatt_component_copy_with_gen:
enabled: true enabled: true
generate_for: generate_for:
exclude: exclude:
@ -11,9 +11,9 @@ targets:
- test/gen_* - test/gen_*
builders: builders:
component_copy_with_gen: wyatt_component_copy_with_gen:
target: ":component_copy_with_gen" target: ":wyatt_component_copy_with_gen"
import: "package:wyatt_component_copy_with_gen/component_copy_with_gen.dart" import: "package:wyatt_component_copy_with_gen/wyatt_component_copy_with_gen.dart"
builder_factories: ["componentCopyWithReporter"] builder_factories: ["componentCopyWithReporter"]
build_extensions: { ".dart": ["copy_with_extension_gen.g.part"] } build_extensions: { ".dart": ["copy_with_extension_gen.g.part"] }
auto_apply: dependents auto_apply: dependents

View File

@ -15,7 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
/// Generator for copywith method for components /// Generator for copywith method for components
library component_copy_with_gen; library wyatt_component_copy_with_gen;
export 'src/builder.dart'; export 'src/builder.dart';
export 'src/generators/component_copy_with_generator.dart'; export 'src/generators/component_copy_with_generator.dart';

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

@ -2,8 +2,8 @@ targets:
$default: $default:
builders: builders:
# Typically the builder key is just the package name, run `pub run build_runner doctor` to check your config. # Typically the builder key is just the package name, run `pub run build_runner doctor` to check your config.
wyatt_component_copy_with_gen:component_copy_with_gen: wyatt_component_copy_with_gen:wyatt_component_copy_with_gen:
generate_for: generate_for:
# Example glob for only the Dart files under `lib/models` # Example glob for only the Dart files under `lib/models`
- lib/**/*.dart - lib/**/*.dart
- example/lib/**/*.dart - example/lib/**/*.dart

View File

@ -2,13 +2,13 @@ import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_components_example/components/custom_app_bar.dart'; import 'package:wyatt_ui_components_example/components/custom_app_bar.dart';
import 'package:wyatt_ui_components_example/components/custom_bottom_bar.dart'; import 'package:wyatt_ui_components_example/components/custom_bottom_bar.dart';
import 'package:wyatt_ui_components_example/components/custom_error_widget.dart'; import 'package:wyatt_ui_components_example/components/custom_error_widget.dart';
import 'package:wyatt_ui_components_example/components/custom_loading_widget.dart'; import 'package:wyatt_ui_components_example/components/custom_loader_widget.dart';
class AppThemeComponent { class AppThemeComponent {
static ComponentThemeData get components => const ComponentThemeData.raw( static ComponentThemeData get components => const ComponentThemeData.raw(
appBar: CustomAppBar(), topAppBar: CustomAppBar(),
bottomNavigationBar: CustomBottomNavigationBar(), bottomNavigationBar: CustomBottomNavigationBar(),
errorWidget: CustomErrorWidget(), error: CustomErrorWidget(),
loadingWidget: CustomLoadingWidget(), loader: CustomLoaderWidget(),
); );
} }

View File

@ -5,13 +5,17 @@ import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'custom_error_widget.g.dart'; part 'custom_error_widget.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class CustomErrorWidget extends ErrorWidgetComponent class CustomErrorWidget extends ErrorComponent with $CustomErrorWidgetCWMixin {
with $CustomErrorWidgetCWMixin { const CustomErrorWidget({
const CustomErrorWidget({super.error, super.key}); super.colors,
super.message,
super.details,
super.key,
});
@override @override
Widget build(BuildContext context) => ColoredBox( Widget build(BuildContext context) => ColoredBox(
color: Colors.red, color: colors?.color ?? Colors.red,
child: Center(child: Text(error?.data ?? 'Error')), child: Center(child: Text(message?.data ?? 'Error')),
); );
} }

View File

@ -6,25 +6,38 @@ part of 'custom_error_widget.dart';
// ComponentCopyWithGenerator // ComponentCopyWithGenerator
// ************************************************************************** // **************************************************************************
class $CustomErrorWidgetCWProxyImpl implements $ErrorWidgetComponentCWProxy { class $CustomErrorWidgetCWProxyImpl implements $ErrorComponentCWProxy {
const $CustomErrorWidgetCWProxyImpl(this._value); const $CustomErrorWidgetCWProxyImpl(this._value);
final CustomErrorWidget _value; final CustomErrorWidget _value;
@override @override
CustomErrorWidget error(TextWrapper? error) => this(error: error); CustomErrorWidget colors(MultiColor? colors) => this(colors: colors);
@override
CustomErrorWidget message(TextWrapper? message) => this(message: message);
@override
CustomErrorWidget details(TextWrapper? details) => this(details: details);
@override
CustomErrorWidget themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver);
@override @override
CustomErrorWidget key(Key? key) => this(key: key); CustomErrorWidget key(Key? key) => this(key: key);
@override @override
CustomErrorWidget call({ CustomErrorWidget call({
TextWrapper? error, MultiColor? colors,
TextWrapper? message,
TextWrapper? details,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}) => }) =>
CustomErrorWidget( CustomErrorWidget(
error: error ?? _value.error, colors: colors ?? _value.colors,
message: message ?? _value.message,
details: details ?? _value.details,
key: key ?? _value.key, key: key ?? _value.key,
); );
} }
mixin $CustomErrorWidgetCWMixin on Component { mixin $CustomErrorWidgetCWMixin on Component {
$ErrorWidgetComponentCWProxy get copyWith => $ErrorComponentCWProxy get copyWith =>
$CustomErrorWidgetCWProxyImpl(this as CustomErrorWidget); $CustomErrorWidgetCWProxyImpl(this as CustomErrorWidget);
} }

View File

@ -2,17 +2,24 @@ import 'package:flutter/material.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';
part 'custom_loading_widget.g.dart'; part 'custom_loader_widget.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class CustomLoadingWidget extends LoadingWidgetComponent class CustomLoaderWidget extends LoaderComponent
with $CustomLoadingWidgetCWMixin { with $CustomLoaderWidgetCWMixin {
const CustomLoadingWidget({super.color, super.key}); const CustomLoaderWidget({
super.colors,
super.duration,
super.flip,
super.radius,
super.stroke,
super.key,
});
@override @override
Widget build(BuildContext context) => Center( Widget build(BuildContext context) => Center(
child: CircularProgressIndicator( child: CircularProgressIndicator(
color: color, color: colors?.color ?? Colors.blue,
), ),
); );
} }

View File

@ -0,0 +1,51 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'custom_loader_widget.dart';
// **************************************************************************
// ComponentCopyWithGenerator
// **************************************************************************
class $CustomLoaderWidgetCWProxyImpl implements $LoaderComponentCWProxy {
const $CustomLoaderWidgetCWProxyImpl(this._value);
final CustomLoaderWidget _value;
@override
CustomLoaderWidget colors(MultiColor? colors) => this(colors: colors);
@override
CustomLoaderWidget radius(double? radius) => this(radius: radius);
@override
CustomLoaderWidget stroke(double? stroke) => this(stroke: stroke);
@override
CustomLoaderWidget duration(Duration? duration) => this(duration: duration);
@override
CustomLoaderWidget flip(bool? flip) => this(flip: flip);
@override
CustomLoaderWidget themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver);
@override
CustomLoaderWidget key(Key? key) => this(key: key);
@override
CustomLoaderWidget call({
MultiColor? colors,
double? radius,
double? stroke,
Duration? duration,
bool? flip,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
}) =>
CustomLoaderWidget(
colors: colors ?? _value.colors,
duration: duration ?? _value.duration,
flip: flip ?? _value.flip,
radius: radius ?? _value.radius,
stroke: stroke ?? _value.stroke,
key: key ?? _value.key,
);
}
mixin $CustomLoaderWidgetCWMixin on Component {
$LoaderComponentCWProxy get copyWith =>
$CustomLoaderWidgetCWProxyImpl(this as CustomLoaderWidget);
}

View File

@ -1,31 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'custom_loading_widget.dart';
// **************************************************************************
// ComponentCopyWithGenerator
// **************************************************************************
class $CustomLoadingWidgetCWProxyImpl
implements $LoadingWidgetComponentCWProxy {
const $CustomLoadingWidgetCWProxyImpl(this._value);
final CustomLoadingWidget _value;
@override
CustomLoadingWidget color(Color? color) => this(color: color);
@override
CustomLoadingWidget key(Key? key) => this(key: key);
@override
CustomLoadingWidget call({
Color? color,
Key? key,
}) =>
CustomLoadingWidget(
color: color ?? _value.color,
key: key ?? _value.key,
);
}
mixin $CustomLoadingWidgetCWMixin on Component {
$LoadingWidgetComponentCWProxy get copyWith =>
$CustomLoadingWidgetCWProxyImpl(this as CustomLoadingWidget);
}

View File

@ -28,7 +28,7 @@ class MyApp extends StatelessWidget {
// This widget is the root of your application. // This widget is the root of your application.
@override @override
Widget build(BuildContext context) => ComponentTheme( Widget build(BuildContext context) => ComponentTheme(
componentThemeWidget: AppThemeComponent.components, data: AppThemeComponent.components,
child: MaterialApp( child: MaterialApp(
title: 'Wyatt Ui Components Example', title: 'Wyatt Ui Components Example',
theme: ThemeData( theme: ThemeData(
@ -48,24 +48,23 @@ class Home extends StatelessWidget {
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => Scaffold(
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size.fromHeight(60), preferredSize: const Size.fromHeight(60),
child: context.components.appBar?.copyWith child: context.components.topAppBarComponent
.title('Example title'.wrap()) ?? .title(const TextWrapper('Example title')),
const SizedBox.shrink(),
), ),
body: Column( body: Column(
children: [ children: [
Expanded( Expanded(
child: context.components.errorWidget child: context.components.errorComponent.call(
?.copyWith(error: 'Example erreur'.wrap()) ?? message: const TextWrapper('Example error'),
const SizedBox.shrink(), ),
), ),
const SizedBox( const SizedBox(
height: 10, height: 10,
), ),
Expanded( Expanded(
child: context.components.loadingWidget child: context.components.loaderComponent.call(
?.copyWith(color: Colors.green) ?? colors: const MultiColor.single(Colors.green),
const SizedBox.shrink(), ),
), ),
], ],
), ),

View File

@ -16,6 +16,5 @@
export 'enums/enums.dart'; export 'enums/enums.dart';
export 'extensions/build_context_extensions.dart'; export 'extensions/build_context_extensions.dart';
export 'extensions/string_extension.dart';
export 'mixins/copy_with_mixin.dart'; export 'mixins/copy_with_mixin.dart';
export 'utils/utils.dart'; export 'utils/utils.dart';

View File

@ -0,0 +1,38 @@
// 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 GradientHelper {
static LinearGradient? linearFromNullableColors(List<Color>? colors) =>
colors != null ? LinearGradient(colors: colors) : null;
static LinearGradient? linearFromMultiColor(MultiColor multiColor) =>
multiColor.isGradient ? LinearGradient(colors: multiColor.colors) : null;
static RadialGradient? radialFromNullableColors(List<Color>? colors) =>
colors != null ? RadialGradient(colors: colors) : null;
static RadialGradient? radialFromMultiColor(MultiColor multiColor) =>
multiColor.isGradient ? RadialGradient(colors: multiColor.colors) : null;
static SweepGradient? sweepFromNullableColors(List<Color>? colors) =>
colors != null ? SweepGradient(colors: colors) : null;
static SweepGradient? sweepFromMultiColor(MultiColor multiColor) =>
multiColor.isGradient ? SweepGradient(colors: multiColor.colors) : null;
}

View File

@ -36,15 +36,28 @@ class TextWrapper {
}); });
/// Creates a [TextWrapper] from a [Text] widget. /// Creates a [TextWrapper] from a [Text] widget.
const TextWrapper.text(this.data) TextWrapper.text(Text text)
: style = null, : data = text.data!,
style = text.style,
gradientColors = null, gradientColors = null,
textAlign = null, textAlign = text.textAlign,
textDirection = null, textDirection = text.textDirection,
softWrap = null, softWrap = text.softWrap,
overflow = null, overflow = text.overflow,
maxLines = null, maxLines = text.maxLines,
selectionColor = null; selectionColor = text.selectionColor;
/// Creates a [TextWrapper] from a [RichText] widget.
TextWrapper.rich(RichText richText)
: data = richText.text.toPlainText(),
style = richText.text.style,
gradientColors = null,
textAlign = richText.textAlign,
textDirection = richText.textDirection,
softWrap = richText.softWrap,
overflow = richText.overflow,
maxLines = richText.maxLines,
selectionColor = richText.selectionColor;
/// Text to be displayed /// Text to be displayed
final String data; final String data;
@ -108,4 +121,7 @@ class TextWrapper {
/// that, the selection color defaults to [DefaultSelectionStyle.defaultColor] /// that, the selection color defaults to [DefaultSelectionStyle.defaultColor]
/// (semi-transparent grey). /// (semi-transparent grey).
final Color? selectionColor; final Color? selectionColor;
@override
String toString() => data;
} }

View File

@ -14,35 +14,84 @@
// 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 super program. If not, see <https://www.gnu.org/licenses/>. // along with super program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
/// A helper class for getting theme elements. /// A helper class for getting theme elements.
abstract class ThemeHelper { abstract class ThemeHelper {
/// Gets a theme element from a list of styles. /// Gets a nullable theme element from a list of styles.
/// {@template getElement}
/// Styles are checked in order, and the first one that passes the /// Styles are checked in order, and the first one that passes the
/// [valueValidator] is returned. /// [valueValidator] is returned.
/// Style elements are transformed using the [transform] function. /// Style elements are transformed using the [transform] function.
/// ///
/// [styles]: A list of styles that need to be checked. /// - [styles] : A list of styles that need to be checked.
/// [transform]: A function that transforms each style element ///
/// to a [T] type. /// - [transform] : An optional function that transforms each style element
/// [valueValidator]: An optional validation function that /// to a [T] type after it passes the [valueValidator]. *(default: returns
/// determines if a style element is valid. /// element as is)*
/// [combine]: A function that combines two [P] type objects to create ///
/// a new object. /// - [valueValidator] : An optional validation function that
static T? getThemeElement<P, T>( /// determines if a style element is valid. *(default: checks if element
/// is not null)*
///
/// - [combine] : A function that combines two [P] type objects to create
/// a new object. *(default: returns the first element)*
///
/// So, if you only pass a [styles] list, the first valid style element
/// will be returned as is.
/// If you pass a [transform] function, the first valid style element
/// will be transformed to a [T] type.
/// {@endtemplate}
static T? maybeGetElement<P, T>(
List<P?>? styles, { List<P?>? styles, {
required T? Function(P?)? transform, T? Function(P?)? transform,
bool? Function(P?)? valueValidator, bool? Function(P?)? valueValidator,
P? Function(P?, P?)? combine, P? Function(P?, P?)? combine,
}) { }) {
// List of valid styles
final Iterable<P?>? validStyles = styles?.where( final Iterable<P?>? validStyles = styles?.where(
(element) => valueValidator?.call(element) ?? (element != null), (element) => valueValidator?.call(element) ?? (element != null),
); );
// tranformation function
final transformation = transform ?? (element) => element as T?;
return (validStyles?.isNotEmpty ?? false) return (validStyles?.isNotEmpty ?? false)
? transform?.call( ? transformation.call(
validStyles?.reduce( validStyles?.reduce(
(value, element) => combine?.call(value, element) ?? value, (value, element) => combine?.call(value, element) ?? value,
), ),
) )
: null; : null;
} }
/// Gets a theme element from a list of styles. Throws an exception if no
/// valid style is found.
///
/// See [maybeGetElement] for more details.
///
/// {@macro getElement}
static T getElement<P, T>(
List<P?>? styles, {
T? Function(P?)? transform,
bool? Function(P?)? valueValidator,
P? Function(P?, P?)? combine,
}) {
final result = maybeGetElement<P, T>(
styles,
transform: transform,
valueValidator: valueValidator,
combine: combine,
);
if (result == null) {
throw FlutterError(
'No valid style found.\nPlease check your theme configuration.\n'
'Searching for: $P in $styles (transform to $T)\n'
'If this value can be null, use maybeGetElement instead.',
);
}
return result;
}
} }

View File

@ -15,12 +15,25 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
class LinearGradientHelper { abstract class ThemeImporter {
static LinearGradient? fromNullableColors(List<Color>? colors) => /// Imports a [ThemeData] from either a [BuildContext] or a [ThemeData].
colors != null ? LinearGradient(colors: colors) : null; ///
/// Throws an [ArgumentError] if the type of [from] is not a [BuildContext]
/// or a [ThemeData].
static ThemeData importFrom<T>(T from) {
ThemeData theme;
static LinearGradient? fromMultiColor(MultiColor multiColor) => if (from is BuildContext) {
multiColor.isGradient ? LinearGradient(colors: multiColor.colors) : null; theme = Theme.of(from);
} else if (from is ThemeData) {
theme = from;
} else {
throw ArgumentError(
'from must be either a BuildContext or a ThemeData',
);
}
return theme;
}
} }

View File

@ -26,47 +26,82 @@ import 'package:wyatt_ui_components/src/domain/entities/theme_style.dart';
/// 1) Pass the "radius" into the constructor, `Component(radius: 12)`. /// 1) Pass the "radius" into the constructor, `Component(radius: 12)`.
/// 2) Set up a theme extension `ComponentThemeExtension(radius: 15)`. /// 2) Set up a theme extension `ComponentThemeExtension(radius: 15)`.
/// 3) Let `wyatt_ui_kit` "negotiate" and try to find a suitable style in the /// 3) Let `wyatt_ui_kit` "negotiate" and try to find a suitable style in the
/// flutter theme. /// flutter theme, or use a hardcoded value.
/// ///
/// If this negotiation phase fails, then: /// If a negotiation phase fails, it will fallback to the next one.
/// - If the value is mandatory: a hardcoded value in "wyatt_ui_kit" is chosen. ///
/// - If not, the style is simply not applied. /// This resolver uses [ThemeHelper] to negotiate and merge styles.
/// {@endtemplate} /// {@endtemplate}
abstract class ThemeResolver<S extends ThemeStyle<S>, T, E> { abstract class ThemeResolver<Style extends ThemeStyle<Style>, Extension,
Extra> {
/// {@macro theme_resolver} /// {@macro theme_resolver}
const ThemeResolver(); const ThemeResolver();
S? Function(BuildContext context, {E? extra}) get customStyleFn; /// Compute extension value from a given extension.
Style? computeExtensionValueFn(
BuildContext context,
Extension? themeExtension, {
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. /// Compute default value from Flutter Theme or with hardcoded values.
S computeDefaultValue( ///
/// If no default value is found, it will throw a [FlutterError].
Style computeDefaultValue(
BuildContext context, { BuildContext context, {
E? extra, 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.');
}
/// Compute extension value from custom component extension. final style = computeExtensionValueFn(context, extension, extra: extra);
S? computeExtensionValueFn(
BuildContext context, if (style == null) {
T? themeExtension, { throw FlutterError(
E? extra, '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.
S negotiate(BuildContext context, {E? extra}) { Style negotiate(BuildContext context, {Extra? extra}) {
// 1) Custom style passed in constructor (cannot be null)
final style = computeDefaultValue(context, extra: extra); final style = computeDefaultValue(context, extra: extra);
return ThemeHelper.getThemeElement<S, S>( return ThemeHelper.getElement<Style, Style>(
[ [
style, // 3) Default
computeExtensionValueFn( style,
context,
Theme.of(context).extension<T>(), // -> then, try to find better style, and merge it with the default
extra: extra,
), // 2) Theme extension
customStyleFn(context, extra: extra) computeExtensionValueFn(
], context,
transform: (value) => value, Theme.of(context).extension<Extension>(),
combine: (value, element) => value?.mergeWith(element), extra: extra,
) ?? ),
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,
combine: (value, element) => value?.mergeWith(element),
);
} }
} }

View File

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

View File

@ -14,12 +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/widgets.dart'; export 'theme_extensions/theme_extensions.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
extension StringExtension on String? {
TextWrapper? wrap({TextStyle? style, MultiColor? gradientColors}) =>
this != null
? TextWrapper(this!, style: style, gradientColors: gradientColors)
: null;
}

View File

@ -14,19 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart'; export 'file_selection_button_theme_extension_default.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; export 'flat_button_theme_extension_default.dart';
export 'simple_icon_button_theme_extension_default.dart';
abstract class LoaderThemeExtension export 'symbol_button_theme_extension_default.dart';
extends ThemeExtension<LoaderThemeExtension> {
const LoaderThemeExtension({
this.colors,
this.stroke,
});
/// Gradient colors from start to end.
final MultiColor? colors;
/// Loader stroke width
final double? stroke;
}

View File

@ -0,0 +1,82 @@
// 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),
animationDuration: Duration.zero,
);
return FileSelectionButtonThemeExtensionDefault(
normalStyle: style,
focusedStyle: style,
hoveredStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.80)),
),
tappedStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.75)),
),
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,79 @@
// 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,
animationDuration: Duration.zero,
);
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,79 @@
// 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: const EdgeInsets.all(5),
foregroundColors: foregroundColor,
backgroundColors: backgroundColor,
animationDuration: Duration.zero,
);
return SimpleIconButtonThemeExtensionDefault(
normalStyle: style,
focusedStyle: style,
hoveredStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.80)),
),
tappedStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.75)),
),
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,87 @@
// 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 textColor = MultiColor.single(theme.textTheme.bodyMedium?.color);
final style = SymbolButtonStyle(
labelStyle: theme.textTheme.labelLarge?.copyWith(color: textColor.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,
animationDuration: Duration.zero,
);
return SymbolButtonThemeExtensionDefault(
normalStyle: style,
focusedStyle: style,
hoveredStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.80)),
),
tappedStyle: style.copyWith(
backgroundColors:
MultiColor.single(theme.colorScheme.primary.withOpacity(0.75)),
),
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)),
borderColors: textColor,
stroke: 3,
),
);
}
/// 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 ?? const EdgeInsets.all(15),
backgroundColors: MultiColor.single(theme.cardColor),
borderColors: MultiColor.single(theme.canvasColor),
minSize: const Size(330, 0),
maxSize: const Size(390, double.infinity),
titleStyle: theme.textTheme.titleLarge,
subtitleStyle: theme.textTheme.titleMedium,
bodyStyle: theme.textTheme.bodyMedium,
stroke: 0,
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,50 @@
// 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 loader_theme_extension_default}
/// The default [LoaderThemeExtension].
/// {@endtemplate}
class LoaderThemeExtensionDefault extends LoaderThemeExtension {
/// {@macro loader_theme_extension_default}
const LoaderThemeExtensionDefault({
required super.colors,
required super.stroke,
});
/// Creates a [LoaderThemeExtensionDefault] from a [ThemeData]
/// and opinionated defaults.
///
/// {@macro card_theme_extension_default}
factory LoaderThemeExtensionDefault.from(ThemeData theme) =>
LoaderThemeExtensionDefault(
colors: MultiColor([
theme.progressIndicatorTheme.color ?? theme.colorScheme.primary,
Colors.transparent,
]),
stroke: 4,
);
/// Creates a [LoaderThemeExtensionDefault] from a dark [ThemeData]
factory LoaderThemeExtensionDefault.dark() =>
LoaderThemeExtensionDefault.from(ThemeData.dark());
/// Creates a [LoaderThemeExtensionDefault] from a light [ThemeData]
factory LoaderThemeExtensionDefault.light() =>
LoaderThemeExtensionDefault.from(ThemeData.light());
}

View File

@ -0,0 +1,73 @@
// 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/theme_extensions/rich_text_builder_theme_extension.dart';
class RichTextBuilderThemeExtensionDefault
extends RichTextBuilderThemeExtension {
const RichTextBuilderThemeExtensionDefault({
required super.defaultStyle,
required super.styles,
});
/// Creates a [RichTextBuilderThemeExtensionDefault] from a [ThemeData]
/// and opinionated defaults.
///
/// {@macro card_theme_extension_default}
factory RichTextBuilderThemeExtensionDefault.from(ThemeData theme) =>
RichTextBuilderThemeExtensionDefault(
defaultStyle: theme.textTheme.bodyMedium,
styles: {
'blue': theme.textTheme.bodyMedium?.copyWith(
color: Colors.blue,
) ??
const TextStyle(
color: Colors.blue,
),
'red': theme.textTheme.bodyMedium?.copyWith(
color: Colors.red,
) ??
const TextStyle(
color: Colors.red,
),
'green': theme.textTheme.bodyMedium?.copyWith(
color: Colors.green,
) ??
const TextStyle(
color: Colors.green,
),
'bold': theme.textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
) ??
const TextStyle(
fontWeight: FontWeight.bold,
),
'italic': theme.textTheme.bodyMedium?.copyWith(
fontStyle: FontStyle.italic,
) ??
const TextStyle(fontStyle: FontStyle.italic),
},
);
/// Creates a [RichTextBuilderThemeExtensionDefault] from a dark [ThemeData]
factory RichTextBuilderThemeExtensionDefault.dark() =>
RichTextBuilderThemeExtensionDefault.from(ThemeData.dark());
/// Creates a [RichTextBuilderThemeExtensionDefault] from a light [ThemeData]
factory RichTextBuilderThemeExtensionDefault.light() =>
RichTextBuilderThemeExtensionDefault.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,22 @@
// 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 'loader_theme_extension_default.dart';
export 'rich_text_builder_theme_extension_default.dart';
export 'text_input_theme_extension_default.dart';
export 'top_bar_theme_extension_default.dart';

View File

@ -0,0 +1,54 @@
// 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 TopBarThemeExtensionDefault extends TopBarThemeExtension {
const TopBarThemeExtensionDefault({
required super.iconTheme,
required super.backgroundColors,
required super.titleStyle,
required super.subtitleStyle,
required super.selectedIndicatorColors,
required super.selectedIndicatorSize,
required super.dividerColor,
});
/// Creates a [TopBarThemeExtensionDefault] from a [ThemeData]
/// and opinionated defaults.
///
/// {@macro card_theme_extension_default}
factory TopBarThemeExtensionDefault.from(ThemeData theme) =>
TopBarThemeExtensionDefault(
backgroundColors: MultiColor.single(theme.appBarTheme.backgroundColor),
titleStyle:
theme.appBarTheme.titleTextStyle ?? theme.textTheme.titleMedium,
subtitleStyle: theme.textTheme.bodyMedium,
selectedIndicatorColors: MultiColor.single(theme.colorScheme.primary),
selectedIndicatorSize: const Size(70, 5),
iconTheme: theme.iconTheme,
dividerColor: theme.colorScheme.onSurface.withOpacity(0.12),
);
/// Creates a [TopBarThemeExtensionDefault] from a dark [ThemeData]
factory TopBarThemeExtensionDefault.dark() =>
TopBarThemeExtensionDefault.from(ThemeData.dark());
/// Creates a [TopBarThemeExtensionDefault] from a light [ThemeData]
factory TopBarThemeExtensionDefault.light() =>
TopBarThemeExtensionDefault.from(ThemeData.light());
}

View File

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

View File

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

View File

@ -18,7 +18,11 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/theme_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/theme_style.dart';
/// {@template button_style}
/// Base class for button styles.
/// {@endtemplate}
abstract class ButtonStyle<T> extends ThemeStyle<T> { abstract class ButtonStyle<T> extends ThemeStyle<T> {
/// {@macro button_style}
const ButtonStyle({ const ButtonStyle({
this.radius, this.radius,
this.padding, this.padding,
@ -27,6 +31,7 @@ abstract class ButtonStyle<T> extends ThemeStyle<T> {
this.borderColors, this.borderColors,
this.stroke, this.stroke,
this.shadow, this.shadow,
this.animationDuration,
}); });
/// Button radius /// Button radius
@ -64,9 +69,15 @@ abstract class ButtonStyle<T> extends ThemeStyle<T> {
/// Default to `null` /// Default to `null`
final BoxShadow? shadow; final BoxShadow? shadow;
/// Animation duration
///
/// Default to `Duration.zero`
final Duration? animationDuration;
@override @override
String toString() => String toString() =>
'ButtonStyle(radius: $radius, padding: $padding, foregroundColors: ' 'ButtonStyle(radius: $radius, padding: $padding, foregroundColors: '
'$foregroundColors, backgroundColors: $backgroundColors, borderColors: ' '$foregroundColors, backgroundColors: $backgroundColors, borderColors: '
'$borderColors, stroke: $stroke, shadow: $shadow)'; '$borderColors, stroke: $stroke, shadow: $shadow, '
'animationDuration: $animationDuration)';
} }

View File

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

View File

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

View File

@ -16,14 +16,21 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template file_selection_button_style}
/// File selection button style.
///
/// This style is used for the FileSelectionButton widget.
/// {@endtemplate}
class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> { class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
/// {@macro file_selection_button_style}
const FileSelectionButtonStyle({ const FileSelectionButtonStyle({
this.title, this.titleStyle,
this.subTitle, this.subtitleStyle,
super.radius, super.radius,
super.padding, super.padding,
super.foregroundColors, super.foregroundColors,
@ -31,6 +38,7 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
super.borderColors, super.borderColors,
super.stroke, super.stroke,
super.shadow, super.shadow,
super.animationDuration,
}); });
/// Merges non-null `b` attributes in `a` /// Merges non-null `b` attributes in `a`
@ -46,8 +54,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
} }
return a.copyWith( return a.copyWith(
title: b.title, titleStyle: b.titleStyle,
subTitle: b.subTitle, subtitleStyle: b.subtitleStyle,
radius: b.radius, radius: b.radius,
padding: b.padding, padding: b.padding,
foregroundColors: b.foregroundColors, foregroundColors: b.foregroundColors,
@ -55,6 +63,7 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
borderColors: b.borderColors, borderColors: b.borderColors,
stroke: b.stroke, stroke: b.stroke,
shadow: b.shadow, shadow: b.shadow,
animationDuration: b.animationDuration,
); );
} }
@ -69,8 +78,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
} }
// b.copyWith to return b attributes even if they are not lerped // b.copyWith to return b attributes even if they are not lerped
return b.copyWith( return b.copyWith(
title: TextStyle.lerp(a.title, b.title, t), titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
subTitle: TextStyle.lerp(a.title, b.title, t), subtitleStyle: TextStyle.lerp(a.subtitleStyle, b.subtitleStyle, t),
foregroundColors: MultiColor.lerp( foregroundColors: MultiColor.lerp(
a.foregroundColors, a.foregroundColors,
b.foregroundColors, b.foregroundColors,
@ -90,18 +99,23 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t), padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t),
stroke: lerpDouble(a.stroke, b.stroke, t), stroke: lerpDouble(a.stroke, b.stroke, t),
shadow: BoxShadow.lerp(a.shadow, b.shadow, t), shadow: BoxShadow.lerp(a.shadow, b.shadow, t),
animationDuration: lerpDuration(
a.animationDuration ?? Duration.zero,
b.animationDuration ?? Duration.zero,
t,
),
); );
} }
/// Title text style /// Title text style
/// ///
/// Default to `TextTheme.labelLarge` /// Default to `TextTheme.labelLarge`
final TextStyle? title; final TextStyle? titleStyle;
/// Sub title text style /// Sub title text style
/// ///
/// Default to `TextTheme.labelSmall` /// Default to `TextTheme.labelSmall`
final TextStyle? subTitle; final TextStyle? subtitleStyle;
@override @override
FileSelectionButtonStyle? mergeWith(FileSelectionButtonStyle? other) => FileSelectionButtonStyle? mergeWith(FileSelectionButtonStyle? other) =>
@ -109,8 +123,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
@override @override
FileSelectionButtonStyle? copyWith({ FileSelectionButtonStyle? copyWith({
TextStyle? title, TextStyle? titleStyle,
TextStyle? subTitle, TextStyle? subtitleStyle,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,
MultiColor? foregroundColors, MultiColor? foregroundColors,
@ -118,10 +132,11 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
MultiColor? borderColors, MultiColor? borderColors,
double? stroke, double? stroke,
BoxShadow? shadow, BoxShadow? shadow,
Duration? animationDuration,
}) => }) =>
FileSelectionButtonStyle( FileSelectionButtonStyle(
title: title ?? this.title, titleStyle: titleStyle ?? this.titleStyle,
subTitle: subTitle ?? this.subTitle, subtitleStyle: subtitleStyle ?? this.subtitleStyle,
radius: radius ?? this.radius, radius: radius ?? this.radius,
padding: padding ?? this.padding, padding: padding ?? this.padding,
foregroundColors: foregroundColors ?? this.foregroundColors, foregroundColors: foregroundColors ?? this.foregroundColors,
@ -129,5 +144,6 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
borderColors: borderColors ?? this.borderColors, borderColors: borderColors ?? this.borderColors,
stroke: stroke ?? this.stroke, stroke: stroke ?? this.stroke,
shadow: shadow ?? this.shadow, shadow: shadow ?? this.shadow,
animationDuration: animationDuration ?? this.animationDuration,
); );
} }

View File

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

View File

@ -16,13 +16,20 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template flat_button_style}
/// Flat button style.
///
/// This style is used for the FlatButton widget.
/// {@endtemplate}
class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> { class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
/// {@macro flat_button_style}
const FlatButtonStyle({ const FlatButtonStyle({
this.label, this.labelStyle,
super.radius, super.radius,
super.padding, super.padding,
super.foregroundColors, super.foregroundColors,
@ -30,6 +37,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
super.borderColors, super.borderColors,
super.stroke, super.stroke,
super.shadow, super.shadow,
super.animationDuration,
}); });
/// Merges non-null `b` attributes in `a` /// Merges non-null `b` attributes in `a`
@ -45,7 +53,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
} }
return a.copyWith( return a.copyWith(
label: b.label, labelStyle: b.labelStyle,
radius: b.radius, radius: b.radius,
padding: b.padding, padding: b.padding,
foregroundColors: b.foregroundColors, foregroundColors: b.foregroundColors,
@ -53,6 +61,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
borderColors: b.borderColors, borderColors: b.borderColors,
stroke: b.stroke, stroke: b.stroke,
shadow: b.shadow, shadow: b.shadow,
animationDuration: b.animationDuration,
); );
} }
@ -67,7 +76,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
} }
// b.copyWith to return b attributes even if they are not lerped // b.copyWith to return b attributes even if they are not lerped
return b.copyWith( return b.copyWith(
label: TextStyle.lerp(a.label, b.label, t), labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
foregroundColors: MultiColor.lerp( foregroundColors: MultiColor.lerp(
a.foregroundColors, a.foregroundColors,
b.foregroundColors, b.foregroundColors,
@ -87,13 +96,18 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t), padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t),
stroke: lerpDouble(a.stroke, b.stroke, t), stroke: lerpDouble(a.stroke, b.stroke, t),
shadow: BoxShadow.lerp(a.shadow, b.shadow, t), shadow: BoxShadow.lerp(a.shadow, b.shadow, t),
animationDuration: lerpDuration(
a.animationDuration ?? Duration.zero,
b.animationDuration ?? Duration.zero,
t,
),
); );
} }
/// Label text style /// labelStyle text style
/// ///
/// Default to `TextTheme.labelLarge` /// Default to `TextTheme.labelLarge`
final TextStyle? label; final TextStyle? labelStyle;
@override @override
FlatButtonStyle? mergeWith(FlatButtonStyle? other) => FlatButtonStyle? mergeWith(FlatButtonStyle? other) =>
@ -101,7 +115,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
@override @override
FlatButtonStyle? copyWith({ FlatButtonStyle? copyWith({
TextStyle? label, TextStyle? labelStyle,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,
MultiColor? foregroundColors, MultiColor? foregroundColors,
@ -109,9 +123,10 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
MultiColor? borderColors, MultiColor? borderColors,
double? stroke, double? stroke,
BoxShadow? shadow, BoxShadow? shadow,
Duration? animationDuration,
}) => }) =>
FlatButtonStyle( FlatButtonStyle(
label: label ?? this.label, labelStyle: labelStyle ?? this.labelStyle,
radius: radius ?? this.radius, radius: radius ?? this.radius,
padding: padding ?? this.padding, padding: padding ?? this.padding,
foregroundColors: foregroundColors ?? this.foregroundColors, foregroundColors: foregroundColors ?? this.foregroundColors,
@ -119,5 +134,6 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
borderColors: borderColors ?? this.borderColors, borderColors: borderColors ?? this.borderColors,
stroke: stroke ?? this.stroke, stroke: stroke ?? this.stroke,
shadow: shadow ?? this.shadow, shadow: shadow ?? this.shadow,
animationDuration: animationDuration ?? this.animationDuration,
); );
} }

View File

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

View File

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

View File

@ -16,11 +16,18 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template simple_icon_button_style}
/// Simple icon button style.
///
/// This style is used for the SimpleIconButton widget.
/// {@endtemplate}
class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> { class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
/// {@macro simple_icon_button_style}
const SimpleIconButtonStyle({ const SimpleIconButtonStyle({
this.dimension, this.dimension,
super.radius, super.radius,
@ -30,6 +37,7 @@ class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
super.borderColors, super.borderColors,
super.stroke, super.stroke,
super.shadow, super.shadow,
super.animationDuration,
}); });
/// Merges non-null `b` attributes in `a` /// Merges non-null `b` attributes in `a`
@ -53,6 +61,7 @@ class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
borderColors: b.borderColors, borderColors: b.borderColors,
stroke: b.stroke, stroke: b.stroke,
shadow: b.shadow, shadow: b.shadow,
animationDuration: b.animationDuration,
); );
} }
@ -87,6 +96,11 @@ class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t), padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t),
stroke: lerpDouble(a.stroke, b.stroke, t), stroke: lerpDouble(a.stroke, b.stroke, t),
shadow: BoxShadow.lerp(a.shadow, b.shadow, t), shadow: BoxShadow.lerp(a.shadow, b.shadow, t),
animationDuration: lerpDuration(
a.animationDuration ?? Duration.zero,
b.animationDuration ?? Duration.zero,
t,
),
); );
} }
@ -109,6 +123,7 @@ class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
MultiColor? borderColors, MultiColor? borderColors,
double? stroke, double? stroke,
BoxShadow? shadow, BoxShadow? shadow,
Duration? animationDuration,
}) => }) =>
SimpleIconButtonStyle( SimpleIconButtonStyle(
dimension: dimension ?? this.dimension, dimension: dimension ?? this.dimension,
@ -119,5 +134,6 @@ class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
borderColors: borderColors ?? this.borderColors, borderColors: borderColors ?? this.borderColors,
stroke: stroke ?? this.stroke, stroke: stroke ?? this.stroke,
shadow: shadow ?? this.shadow, shadow: shadow ?? this.shadow,
animationDuration: animationDuration ?? this.animationDuration,
); );
} }

View File

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

View File

@ -16,13 +16,20 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart'; import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template symbol_button_style}
/// Symbol button style.
///
/// This style is used for the SymbolButton widget.
/// {@endtemplate}
class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> { class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
/// {@macro symbol_button_style}
const SymbolButtonStyle({ const SymbolButtonStyle({
this.label, this.labelStyle,
this.dimension, this.dimension,
super.radius, super.radius,
super.padding, super.padding,
@ -31,6 +38,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
super.borderColors, super.borderColors,
super.stroke, super.stroke,
super.shadow, super.shadow,
super.animationDuration,
}); });
/// Merges non-null `b` attributes in `a` /// Merges non-null `b` attributes in `a`
@ -46,7 +54,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
} }
return a.copyWith( return a.copyWith(
label: b.label, labelStyle: b.labelStyle,
dimension: b.dimension, dimension: b.dimension,
radius: b.radius, radius: b.radius,
padding: b.padding, padding: b.padding,
@ -55,6 +63,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
borderColors: b.borderColors, borderColors: b.borderColors,
stroke: b.stroke, stroke: b.stroke,
shadow: b.shadow, shadow: b.shadow,
animationDuration: b.animationDuration,
); );
} }
@ -69,7 +78,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
} }
// b.copyWith to return b attributes even if they are not lerped // b.copyWith to return b attributes even if they are not lerped
return b.copyWith( return b.copyWith(
label: TextStyle.lerp(a.label, b.label, t), labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
dimension: lerpDouble(a.dimension, b.dimension, t), dimension: lerpDouble(a.dimension, b.dimension, t),
foregroundColors: MultiColor.lerp( foregroundColors: MultiColor.lerp(
a.foregroundColors, a.foregroundColors,
@ -90,13 +99,18 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t), padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t),
stroke: lerpDouble(a.stroke, b.stroke, t), stroke: lerpDouble(a.stroke, b.stroke, t),
shadow: BoxShadow.lerp(a.shadow, b.shadow, t), shadow: BoxShadow.lerp(a.shadow, b.shadow, t),
animationDuration: lerpDuration(
a.animationDuration ?? Duration.zero,
b.animationDuration ?? Duration.zero,
t,
),
); );
} }
/// Label text style /// labelStyle text style
/// ///
/// Default to `TextTheme.labelLarge` /// Default to `TextTheme.labelLarge`
final TextStyle? label; final TextStyle? labelStyle;
/// Dimension of this button (as a square) /// Dimension of this button (as a square)
/// ///
@ -109,7 +123,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
@override @override
SymbolButtonStyle? copyWith({ SymbolButtonStyle? copyWith({
TextStyle? label, TextStyle? labelStyle,
double? dimension, double? dimension,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,
@ -118,9 +132,10 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
MultiColor? borderColors, MultiColor? borderColors,
double? stroke, double? stroke,
BoxShadow? shadow, BoxShadow? shadow,
Duration? animationDuration,
}) => }) =>
SymbolButtonStyle( SymbolButtonStyle(
label: label ?? this.label, labelStyle: labelStyle ?? this.labelStyle,
dimension: dimension ?? this.dimension, dimension: dimension ?? this.dimension,
radius: radius ?? this.radius, radius: radius ?? this.radius,
padding: padding ?? this.padding, padding: padding ?? this.padding,
@ -129,5 +144,6 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
borderColors: borderColors ?? this.borderColors, borderColors: borderColors ?? this.borderColors,
stroke: stroke ?? this.stroke, stroke: stroke ?? this.stroke,
shadow: shadow ?? this.shadow, shadow: shadow ?? this.shadow,
animationDuration: animationDuration ?? this.animationDuration,
); );
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,99 @@
// 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/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'pricing_card_component.g.dart';
class PricingLine {
const PricingLine({
required this.data,
this.icon,
});
final TextWrapper data;
final Widget? icon;
@override
String toString() => 'PricingLine(data: $data, icon: $icon)';
}
class Pricing {
const Pricing({
required this.price,
this.period,
this.hasAsterisk = false,
});
final TextWrapper price;
final TextWrapper? period;
/// If [hasAsterisk] is true then the price will be displayed with
/// an asterisk to emphasize that it is a special price.
final bool hasAsterisk;
}
@ComponentProxyExtension()
abstract class PricingCardComponent extends CardComponent
with CopyWithMixin<$PricingCardComponentCWProxy> {
const PricingCardComponent({
this.axis,
this.title,
this.pricing,
this.description,
this.features,
this.cta,
super.radius,
super.padding,
super.borderColors,
super.backgroundColors,
super.stroke,
super.minSize,
super.maxSize,
super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background,
super.key,
});
/// Axis of the card
///
/// If [axis] is [Axis.horizontal] then only the first icon will be displayed.
/// Used in header of the card.
final Axis? axis;
/// Title of the card
///
/// If [axis] is [Axis.vertical] then icon of the title will be displayed
/// above the title.
final PricingLine? title;
/// Pricing of the card
final Pricing? pricing;
/// Description of the card
final TextWrapper? description;
/// List of special features of the card
final List<PricingLine>? features;
/// CTA of the card
final Widget? cta;
}

View File

@ -0,0 +1,50 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'pricing_card_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $PricingCardComponentCWProxy {
PricingCardComponent axis(Axis? axis);
PricingCardComponent title(PricingLine? title);
PricingCardComponent pricing(Pricing? pricing);
PricingCardComponent description(TextWrapper? description);
PricingCardComponent features(List<PricingLine>? features);
PricingCardComponent cta(Widget? cta);
PricingCardComponent radius(BorderRadiusGeometry? radius);
PricingCardComponent padding(EdgeInsetsGeometry? padding);
PricingCardComponent borderColors(MultiColor? borderColors);
PricingCardComponent backgroundColors(MultiColor? backgroundColors);
PricingCardComponent stroke(double? stroke);
PricingCardComponent minSize(Size? minSize);
PricingCardComponent maxSize(Size? maxSize);
PricingCardComponent shadow(BoxShadow? shadow);
PricingCardComponent titleStyle(TextStyle? titleStyle);
PricingCardComponent subtitleStyle(TextStyle? subtitleStyle);
PricingCardComponent bodyStyle(TextStyle? bodyStyle);
PricingCardComponent background(Widget? background);
PricingCardComponent key(Key? key);
PricingCardComponent call({
Axis? axis,
PricingLine? title,
Pricing? pricing,
TextWrapper? description,
List<PricingLine>? features,
Widget? cta,
BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding,
MultiColor? borderColors,
MultiColor? backgroundColors,
double? stroke,
Size? minSize,
Size? maxSize,
BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background,
Key? key,
});
}

View File

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

View File

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

View File

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

View File

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

View File

@ -21,6 +21,7 @@ import 'package:wyatt_ui_components/src/core/utils/theme_resolver.dart';
/// Base class for all components. /// Base class for all components.
/// {@endtemplate} /// {@endtemplate}
abstract class Component extends StatelessWidget { abstract class Component extends StatelessWidget {
/// {@macro component}
const Component({this.themeResolver, super.key}); const Component({this.themeResolver, super.key});
/// Theme Resolver for this component /// Theme Resolver for this component

View File

@ -18,9 +18,9 @@ export './bars/bars.dart';
export './buttons/buttons.dart'; export './buttons/buttons.dart';
export './cards/cards.dart'; export './cards/cards.dart';
export './component.dart'; export './component.dart';
export './error_widget_component.dart'; export './error/error.dart';
export './gradients/gradients.dart';
export './loader/loader.dart'; export './loader/loader.dart';
export './loading_widget_component.dart';
export './rich_text_builder/rich_text_builder.dart'; export './rich_text_builder/rich_text_builder.dart';
export './text_inputs/text_inputs.dart'; export './text_inputs/text_inputs.dart';
export './theme_style.dart'; export './theme_style.dart';

View File

@ -14,4 +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/>.
export './linear_gradient_helper.dart'; export './error_component.dart';

View File

@ -14,15 +14,29 @@
// 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'; import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'error_widget_component.g.dart'; part 'error_component.g.dart';
@ComponentProxyExtension() @ComponentProxyExtension()
abstract class ErrorWidgetComponent extends Component abstract class ErrorComponent extends Component
with CopyWithMixin<$ErrorWidgetComponentCWProxy> { with CopyWithMixin<$ErrorComponentCWProxy> {
const ErrorWidgetComponent({required this.error, super.key}); const ErrorComponent({
final TextWrapper? error; this.colors,
this.message,
this.details,
super.themeResolver,
super.key,
});
/// Error message
final TextWrapper? message;
/// Details for the error component
final TextWrapper? details;
/// Colors for the error component
final MultiColor? colors;
} }

View File

@ -0,0 +1,23 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'error_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $ErrorComponentCWProxy {
ErrorComponent colors(MultiColor? colors);
ErrorComponent message(TextWrapper? message);
ErrorComponent details(TextWrapper? details);
ErrorComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
ErrorComponent key(Key? key);
ErrorComponent call({
MultiColor? colors,
TextWrapper? message,
TextWrapper? details,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
});
}

View File

@ -1,16 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'error_widget_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $ErrorWidgetComponentCWProxy {
ErrorWidgetComponent error(TextWrapper? error);
ErrorWidgetComponent key(Key? key);
ErrorWidgetComponent call({
TextWrapper? error,
Key? key,
});
}

View File

@ -14,16 +14,18 @@
// 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'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/core/mixins/copy_with_mixin.dart';
import 'package:wyatt_ui_components/src/domain/entities/component.dart'; import 'package:wyatt_ui_components/src/domain/entities/component.dart';
part 'loading_widget_component.g.dart'; /// {@template gradient_component}
/// Base class for all gradient components.
///
/// For example, text, icons, and box borders.
/// {@endtemplate}
abstract class GradientComponent extends Component {
/// {@macro gradient_component}
const GradientComponent({super.key});
@ComponentProxyExtension() /// Returns colors for the gradient.
abstract class LoadingWidgetComponent extends Component MultiColor get gradientColors;
with CopyWithMixin<$LoadingWidgetComponentCWProxy> {
const LoadingWidgetComponent({required this.color, super.key});
final Color? color;
} }

View File

@ -0,0 +1,47 @@
// 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/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'gradient_icon_component.g.dart';
@ComponentProxyExtension()
abstract class GradientIconComponent extends Icon
with CopyWithMixin<$GradientIconComponentCWProxy>
implements GradientComponent {
GradientIconComponent({
required IconData? icon,
required this.gradientColors,
super.key,
super.size,
super.fill,
super.weight,
super.grade,
super.opticalSize,
super.color,
super.shadows,
super.semanticLabel,
super.textDirection,
}) : super(icon);
@override
final MultiColor gradientColors;
@override
ThemeResolver<dynamic, dynamic, dynamic>? get themeResolver => null;
}

View File

@ -0,0 +1,36 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'gradient_icon_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $GradientIconComponentCWProxy {
GradientIconComponent icon(IconData? icon);
GradientIconComponent gradientColors(MultiColor? gradientColors);
GradientIconComponent key(Key? key);
GradientIconComponent size(double? size);
GradientIconComponent fill(double? fill);
GradientIconComponent weight(double? weight);
GradientIconComponent grade(double? grade);
GradientIconComponent opticalSize(double? opticalSize);
GradientIconComponent color(Color? color);
GradientIconComponent shadows(List<Shadow>? shadows);
GradientIconComponent semanticLabel(String? semanticLabel);
GradientIconComponent textDirection(TextDirection? textDirection);
GradientIconComponent call({
IconData? icon,
MultiColor? gradientColors,
Key? key,
double? size,
double? fill,
double? weight,
double? grade,
double? opticalSize,
Color? color,
List<Shadow>? shadows,
String? semanticLabel,
TextDirection? textDirection,
});
}

View File

@ -0,0 +1,54 @@
// 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/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/core/mixins/copy_with_mixin.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/core/utils/theme_resolver.dart';
import 'package:wyatt_ui_components/src/domain/entities/gradients/gradients.dart';
part 'gradient_text_component.g.dart';
@ComponentProxyExtension()
abstract class GradientTextComponent extends Text
with CopyWithMixin<$GradientTextComponentCWProxy>
implements GradientComponent {
const GradientTextComponent({
required String? data,
required this.gradientColors,
super.style,
super.key,
super.strutStyle,
super.textAlign,
super.textDirection,
super.locale,
super.softWrap,
super.overflow,
super.textScaleFactor,
super.maxLines,
super.semanticsLabel,
super.textWidthBasis,
super.textHeightBehavior,
super.selectionColor,
}) : super(data ?? '');
@override
final MultiColor gradientColors;
@override
ThemeResolver<dynamic, dynamic, dynamic>? get themeResolver => null;
}

View File

@ -0,0 +1,45 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'gradient_text_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $GradientTextComponentCWProxy {
GradientTextComponent data(String? data);
GradientTextComponent gradientColors(MultiColor? gradientColors);
GradientTextComponent style(TextStyle? style);
GradientTextComponent key(Key? key);
GradientTextComponent strutStyle(StrutStyle? strutStyle);
GradientTextComponent textAlign(TextAlign? textAlign);
GradientTextComponent textDirection(TextDirection? textDirection);
GradientTextComponent locale(Locale? locale);
GradientTextComponent softWrap(bool? softWrap);
GradientTextComponent overflow(TextOverflow? overflow);
GradientTextComponent textScaleFactor(double? textScaleFactor);
GradientTextComponent maxLines(int? maxLines);
GradientTextComponent semanticsLabel(String? semanticsLabel);
GradientTextComponent textWidthBasis(TextWidthBasis? textWidthBasis);
GradientTextComponent textHeightBehavior(
TextHeightBehavior? textHeightBehavior);
GradientTextComponent selectionColor(Color? selectionColor);
GradientTextComponent call({
String? data,
MultiColor? gradientColors,
TextStyle? style,
Key? key,
StrutStyle? strutStyle,
TextAlign? textAlign,
TextDirection? textDirection,
Locale? locale,
bool? softWrap,
TextOverflow? overflow,
double? textScaleFactor,
int? maxLines,
String? semanticsLabel,
TextWidthBasis? textWidthBasis,
TextHeightBehavior? textHeightBehavior,
Color? selectionColor,
});
}

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 'gradient_component.dart';
export 'gradient_icon_component.dart';
export 'gradient_text_component.dart';

View File

@ -1,16 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'loading_widget_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $LoadingWidgetComponentCWProxy {
LoadingWidgetComponent color(Color? color);
LoadingWidgetComponent key(Key? key);
LoadingWidgetComponent call({
Color? color,
Key? key,
});
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,31 +18,25 @@ import 'dart:ui';
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 LoaderTheme extends LoaderThemeExtension { class LoaderThemeExtension extends ThemeExtension<LoaderThemeExtension> {
const LoaderTheme({ const LoaderThemeExtension({
super.colors, this.colors,
super.stroke, this.stroke,
}); });
factory LoaderTheme.light() => const LoaderTheme( /// Gradient colors from start to end.
colors: MultiColor([Constants.blue1, Constants.white]), final MultiColor? colors;
stroke: 15,
);
factory LoaderTheme.dark() => const LoaderTheme( /// Loader stroke width
colors: MultiColor([Constants.blue2, Constants.grey2]), final double? stroke;
stroke: 15,
);
@override @override
ThemeExtension<LoaderThemeExtension> copyWith({ ThemeExtension<LoaderThemeExtension> copyWith({
MultiColor? colors, MultiColor? colors,
double? stroke, double? stroke,
}) => }) =>
LoaderTheme( LoaderThemeExtension(
colors: colors ?? this.colors, colors: colors ?? this.colors,
stroke: stroke ?? this.stroke, stroke: stroke ?? this.stroke,
); );
@ -52,10 +46,10 @@ class LoaderTheme extends LoaderThemeExtension {
covariant ThemeExtension<LoaderThemeExtension>? other, covariant ThemeExtension<LoaderThemeExtension>? other,
double t, double t,
) { ) {
if (other is! LoaderTheme) { if (other is! LoaderThemeExtension) {
return this; return this;
} }
return LoaderTheme( return LoaderThemeExtension(
colors: MultiColor.lerp(colors, other.colors, t), colors: MultiColor.lerp(colors, other.colors, t),
stroke: lerpDouble(stroke, other.stroke, t), stroke: lerpDouble(stroke, other.stroke, t),
); );

View File

@ -16,7 +16,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
abstract class RichTextBuilderThemeExtension class RichTextBuilderThemeExtension
extends ThemeExtension<RichTextBuilderThemeExtension> { extends ThemeExtension<RichTextBuilderThemeExtension> {
const RichTextBuilderThemeExtension({ const RichTextBuilderThemeExtension({
this.defaultStyle, this.defaultStyle,
@ -28,4 +28,28 @@ abstract class RichTextBuilderThemeExtension
/// Used styles in this rich text component. /// Used styles in this rich text component.
final Map<String, TextStyle>? styles; final Map<String, TextStyle>? styles;
@override
ThemeExtension<RichTextBuilderThemeExtension> copyWith({
TextStyle? defaultStyle,
Map<String, TextStyle>? styles,
}) =>
RichTextBuilderThemeExtension(
defaultStyle: defaultStyle ?? this.defaultStyle,
styles: styles ?? this.styles,
);
@override
ThemeExtension<RichTextBuilderThemeExtension> lerp(
covariant ThemeExtension<RichTextBuilderThemeExtension>? other,
double t,
) {
if (other is! RichTextBuilderThemeExtension) {
return this;
}
return RichTextBuilderThemeExtension(
defaultStyle: TextStyle.lerp(defaultStyle, other.defaultStyle, t),
styles: styles,
);
}
} }

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,
);
}

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