Compare commits

..

No commits in common. "d098d9a6bf518a5a23208f30914a9b2f5e42bba0" and "81c8851ac8170a31e47b2d1fb0b4caedc730bb10" have entirely different histories.

69 changed files with 755 additions and 1327 deletions

View File

@ -1 +0,0 @@
2.4.1

View File

@ -1,2 +0,0 @@
new_version.sh
.latest_version

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2023 WYATT GROUP * Copyright (C) 2022 WYATT GROUP
* Please see the AUTHORS file for details. * Please see the AUTHORS file for details.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify

View File

@ -20,18 +20,10 @@
![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](https://wyattapp.io) and [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](https://wyattapp.io) and [Wyatt Studio](https://wyatt-studio.fr). For more information, see the complete list of options in **lib/analysis_options.2.4.0.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).
## Adding Wyatt Analysis to your project
Using CLI:
```sh
dart pub add wyatt_analysis:2.4.1 --dev --hosted-url=https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
```
## Usage ## Usage
To use the lints, add a dependency in your `pubspec.yaml` : To use the lints, add a dependency in your `pubspec.yaml` :
@ -39,7 +31,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.0
``` ```
Then, add an include in `analysis_options.yaml` : Then, add an include in `analysis_options.yaml` :
@ -57,13 +49,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.0.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.0.yaml
``` ```
## Suppressing Lints ## Suppressing Lints
@ -117,11 +109,10 @@ To indicate your project is using `wyatt_analysis` → [![style: wyatt analysis]
When you want to create a new version of the plugin. Before any modification, execute the following command to create new files: When you want to create a new version of the plugin. Before any modification, execute the following command to create new files:
```sh ```sh
./new_version.sh <new_version> ./new_version.sh <previous_version> <new_version>
``` ```
> Where `<previous_version>` is 2.4.0
The previous version is automatically detected thanks to the `.latest_version` file.
So `.latest_version` needs to be versioned!
## Notes ## Notes

View File

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

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

View File

@ -14,4 +14,5 @@
# 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.0.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.0';

View File

@ -18,12 +18,20 @@
usage=" usage="
usage: usage:
$(basename "$0") <new_version> -- create new analyzer files. $(basename "$0") <previous_version> <new_version> -- create new analyzer files.
where: where:
previous_version: last version, for example \`2.3.0\`
new_version: new version, for example \`2.4.0\`" new_version: new version, for example \`2.4.0\`"
new=$1 old=$1
new=$2
if [ -z "$old" ]; then
echo "previous_version cannot be null"
echo "${usage}"
exit 1
fi
if [ -z "$new" ]; then if [ -z "$new" ]; then
echo "new_version cannot be null" echo "new_version cannot be null"
@ -35,19 +43,6 @@ SCRIPT_PATH="${BASH_SOURCE:-$0}"
ABS_SCRIPT_PATH="$(realpath "${SCRIPT_PATH}")" ABS_SCRIPT_PATH="$(realpath "${SCRIPT_PATH}")"
ABS_DIRECTORY="$(dirname "${ABS_SCRIPT_PATH}")" ABS_DIRECTORY="$(dirname "${ABS_SCRIPT_PATH}")"
LATEST_VERSION="${ABS_DIRECTORY}/.latest_version"
# Read latest version
if [ -e "$LATEST_VERSION" ]; then
old=$(cat "$LATEST_VERSION")
echo "> latest package version is: $old"
echo "> new package version is: $new"
else
echo "latest version is not set"
echo "create a file named \`.latest_version\` in the root of the project"
exit 1
fi
LIB="${ABS_DIRECTORY}/lib/wyatt_analysis.dart" LIB="${ABS_DIRECTORY}/lib/wyatt_analysis.dart"
OPTIONS="${ABS_DIRECTORY}/lib/analysis_options.yaml" OPTIONS="${ABS_DIRECTORY}/lib/analysis_options.yaml"
OLD_OPTIONS="${ABS_DIRECTORY}/lib/analysis_options.${old}.yaml" OLD_OPTIONS="${ABS_DIRECTORY}/lib/analysis_options.${old}.yaml"
@ -57,7 +52,6 @@ OPTIONS_FLUTTER="${ABS_DIRECTORY}/lib/analysis_options.flutter.yaml"
OLD_OPTIONS_FLUTTER="${ABS_DIRECTORY}/lib/analysis_options.flutter.${old}.yaml" OLD_OPTIONS_FLUTTER="${ABS_DIRECTORY}/lib/analysis_options.flutter.${old}.yaml"
NEW_OPTIONS_FLUTTER="${ABS_DIRECTORY}/lib/analysis_options.flutter.${new}.yaml" NEW_OPTIONS_FLUTTER="${ABS_DIRECTORY}/lib/analysis_options.flutter.${new}.yaml"
if [ ! -e "$OLD_OPTIONS" ]; then if [ ! -e "$OLD_OPTIONS" ]; then
echo "analysis_options.${old}.yaml doesn't exists" echo "analysis_options.${old}.yaml doesn't exists"
echo "${usage}" echo "${usage}"
@ -97,7 +91,7 @@ sed -e "s/${old}/${new}/g" "README.md" > tempfile.tmp
mv -f tempfile.tmp "README.md" mv -f tempfile.tmp "README.md"
echo " echo "
# Copyright (C) 2023 WYATT GROUP # Copyright (C) 2022 WYATT GROUP
# Please see the AUTHORS file for details. # Please see the AUTHORS file for details.
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@ -117,7 +111,7 @@ include: package:wyatt_analysis/analysis_options.${new}.yaml
" > "${OPTIONS}" " > "${OPTIONS}"
echo " echo "
# Copyright (C) 2023 WYATT GROUP # Copyright (C) 2022 WYATT GROUP
# Please see the AUTHORS file for details. # Please see the AUTHORS file for details.
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@ -136,7 +130,4 @@ echo "
include: package:wyatt_analysis/analysis_options.flutter.${new}.yaml include: package:wyatt_analysis/analysis_options.flutter.${new}.yaml
" > "${OPTIONS_FLUTTER}" " > "${OPTIONS_FLUTTER}"
# Update latest version
echo "${new}" > "$LATEST_VERSION"
exit 0 exit 0

View File

@ -22,4 +22,4 @@ version: 2.4.0
publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: '>=2.12.0 <3.0.0'

View File

@ -1,15 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart'; import 'package:wyatt_bloc_layout/wyatt_bloc_layout.dart';
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
part 'custom_app_bar.g.dart'; part 'custom_app_bar.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class CustomAppBar extends TopAppBarComponent with $CustomAppBarCWMixin { class CustomAppBar extends AppBarComponent with $CustomAppBarCWMixin {
const CustomAppBar({super.title}); const CustomAppBar({super.title});
@override @override
Widget build(BuildContext context) => AppBar( Widget build(BuildContext context) => AppBar(
title: Text(title?.data ?? 'Title'), title: Text(title?.text ?? 'Title'),
); );
} }

View File

@ -6,85 +6,22 @@ part of 'custom_app_bar.dart';
// ComponentCopyWithGenerator // ComponentCopyWithGenerator
// ************************************************************************** // **************************************************************************
class $CustomAppBarCWProxyImpl implements $TopAppBarComponentCWProxy { class $CustomAppBarCWProxyImpl implements $AppBarComponentCWProxy {
const $CustomAppBarCWProxyImpl(this._value); const $CustomAppBarCWProxyImpl(this._value);
final CustomAppBar _value; final CustomAppBar _value;
@override @override
CustomAppBar title(TextWrapper? title) => this(title: title); CustomAppBar title(TextWrapper? title) => this(title: title);
@override @override
CustomAppBar centerTitle(bool? centerTitle) => this(centerTitle: centerTitle);
@override
CustomAppBar shape(ShapeBorder? shape) => this(shape: shape);
@override
CustomAppBar systemOverlayStyle(SystemUiOverlayStyle? systemOverlayStyle) =>
this(systemOverlayStyle: systemOverlayStyle);
@override
CustomAppBar automaticallyImplyLeading(bool? automaticallyImplyLeading) =>
this(automaticallyImplyLeading: automaticallyImplyLeading);
@override
CustomAppBar flexibleSpace(Widget? flexibleSpace) =>
this(flexibleSpace: flexibleSpace);
@override
CustomAppBar bottom(PreferredSizeWidget? bottom) => this(bottom: bottom);
@override
CustomAppBar elevation(double? elevation) => this(elevation: elevation);
@override
CustomAppBar scrolledUnderElevation(double? scrolledUnderElevation) =>
this(scrolledUnderElevation: scrolledUnderElevation);
@override
CustomAppBar shadowColor(Color? shadowColor) =>
this(shadowColor: shadowColor);
@override
CustomAppBar surfaceTintColor(Color? surfaceTintColor) =>
this(surfaceTintColor: surfaceTintColor);
@override
CustomAppBar backgroundColor(MultiColor? backgroundColor) =>
this(backgroundColor: backgroundColor);
@override
CustomAppBar iconTheme(IconThemeData? iconTheme) =>
this(iconTheme: iconTheme);
@override
CustomAppBar primary(bool? primary) => this(primary: primary);
@override
CustomAppBar excludeHeaderSemantics(bool? excludeHeaderSemantics) =>
this(excludeHeaderSemantics: excludeHeaderSemantics);
@override
CustomAppBar toolbarHeight(double? toolbarHeight) =>
this(toolbarHeight: toolbarHeight);
@override
CustomAppBar leadingWidth(double? leadingWidth) =>
this(leadingWidth: leadingWidth);
@override
CustomAppBar leading(Widget? leading) => this(leading: leading); CustomAppBar leading(Widget? leading) => this(leading: leading);
@override @override
CustomAppBar actions(List<Widget>? actions) => this(actions: actions); CustomAppBar actions(List<Widget>? actions) => this(actions: actions);
@override @override
CustomAppBar expandedWidget(List<Widget>? expandedWidget) =>
this(expandedWidget: expandedWidget);
@override
CustomAppBar key(Key? key) => this(key: key); CustomAppBar key(Key? key) => this(key: key);
@override @override
CustomAppBar call({ CustomAppBar call({
TextWrapper? title, TextWrapper? title,
bool? centerTitle,
ShapeBorder? shape,
SystemUiOverlayStyle? systemOverlayStyle,
bool? automaticallyImplyLeading,
Widget? flexibleSpace,
PreferredSizeWidget? bottom,
double? elevation,
double? scrolledUnderElevation,
Color? shadowColor,
Color? surfaceTintColor,
MultiColor? backgroundColor,
IconThemeData? iconTheme,
bool? primary,
bool? excludeHeaderSemantics,
double? toolbarHeight,
double? leadingWidth,
Widget? leading, Widget? leading,
List<Widget>? actions, List<Widget>? actions,
List<Widget>? expandedWidget,
Key? key, Key? key,
}) => }) =>
CustomAppBar( CustomAppBar(
@ -93,6 +30,6 @@ class $CustomAppBarCWProxyImpl implements $TopAppBarComponentCWProxy {
} }
mixin $CustomAppBarCWMixin on Component { mixin $CustomAppBarCWMixin on Component {
$TopAppBarComponentCWProxy get copyWith => $AppBarComponentCWProxy get copyWith =>
$CustomAppBarCWProxyImpl(this as CustomAppBar); $CustomAppBarCWProxyImpl(this as CustomAppBar);
} }

View File

@ -12,6 +12,6 @@ class CustomErrorWidget extends ErrorWidgetComponent
@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(error?.text ?? 'Error')),
); );
} }

View File

@ -15,19 +15,18 @@
// 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:flutter/services.dart';
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'custom_top_bar_example.g.dart'; part 'custom_app_bar_example.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class CustomTopAppBarExample extends TopAppBarComponent class CustomAppBarExample extends AppBarComponent
with $CustomTopAppBarExampleCWMixin { with $CustomAppBarExampleCWMixin {
const CustomTopAppBarExample({super.title, super.key}); const CustomAppBarExample({super.title, super.key});
@override @override
Widget build(BuildContext context) => AppBar( Widget build(BuildContext context) => AppBar(
title: Text(super.title?.data ?? ''), title: Text(super.title?.text ?? ''),
); );
} }

View File

@ -0,0 +1,36 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'custom_app_bar_example.dart';
// **************************************************************************
// ComponentCopyWithGenerator
// **************************************************************************
class $CustomAppBarExampleCWProxyImpl implements $AppBarComponentCWProxy {
const $CustomAppBarExampleCWProxyImpl(this._value);
final CustomAppBarExample _value;
@override
CustomAppBarExample title(String? title) => this(title: title);
@override
CustomAppBarExample leading(Widget? leading) => this(leading: leading);
@override
CustomAppBarExample actions(List<Widget>? actions) => this(actions: actions);
@override
CustomAppBarExample key(Key? key) => this(key: key);
@override
CustomAppBarExample call({
String? title,
Widget? leading,
List<Widget>? actions,
Key? key,
}) =>
CustomAppBarExample(
title: title ?? _value.title,
key: key ?? _value.key,
);
}
mixin $CustomAppBarExampleCWMixin on Component {
$AppBarComponentCWProxy get copyWith =>
$CustomAppBarExampleCWProxyImpl(this as CustomAppBarExample);
}

View File

@ -1,106 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'custom_top_bar_example.dart';
// **************************************************************************
// ComponentCopyWithGenerator
// **************************************************************************
class $CustomTopAppBarExampleCWProxyImpl implements $TopAppBarComponentCWProxy {
const $CustomTopAppBarExampleCWProxyImpl(this._value);
final CustomTopAppBarExample _value;
@override
CustomTopAppBarExample title(TextWrapper? title) => this(title: title);
@override
CustomTopAppBarExample centerTitle(bool? centerTitle) =>
this(centerTitle: centerTitle);
@override
CustomTopAppBarExample shape(ShapeBorder? shape) => this(shape: shape);
@override
CustomTopAppBarExample systemOverlayStyle(
SystemUiOverlayStyle? systemOverlayStyle) =>
this(systemOverlayStyle: systemOverlayStyle);
@override
CustomTopAppBarExample automaticallyImplyLeading(
bool? automaticallyImplyLeading) =>
this(automaticallyImplyLeading: automaticallyImplyLeading);
@override
CustomTopAppBarExample flexibleSpace(Widget? flexibleSpace) =>
this(flexibleSpace: flexibleSpace);
@override
CustomTopAppBarExample bottom(PreferredSizeWidget? bottom) =>
this(bottom: bottom);
@override
CustomTopAppBarExample elevation(double? elevation) =>
this(elevation: elevation);
@override
CustomTopAppBarExample scrolledUnderElevation(
double? scrolledUnderElevation) =>
this(scrolledUnderElevation: scrolledUnderElevation);
@override
CustomTopAppBarExample shadowColor(Color? shadowColor) =>
this(shadowColor: shadowColor);
@override
CustomTopAppBarExample surfaceTintColor(Color? surfaceTintColor) =>
this(surfaceTintColor: surfaceTintColor);
@override
CustomTopAppBarExample backgroundColor(MultiColor? backgroundColor) =>
this(backgroundColor: backgroundColor);
@override
CustomTopAppBarExample iconTheme(IconThemeData? iconTheme) =>
this(iconTheme: iconTheme);
@override
CustomTopAppBarExample primary(bool? primary) => this(primary: primary);
@override
CustomTopAppBarExample excludeHeaderSemantics(bool? excludeHeaderSemantics) =>
this(excludeHeaderSemantics: excludeHeaderSemantics);
@override
CustomTopAppBarExample toolbarHeight(double? toolbarHeight) =>
this(toolbarHeight: toolbarHeight);
@override
CustomTopAppBarExample leadingWidth(double? leadingWidth) =>
this(leadingWidth: leadingWidth);
@override
CustomTopAppBarExample leading(Widget? leading) => this(leading: leading);
@override
CustomTopAppBarExample actions(List<Widget>? actions) =>
this(actions: actions);
@override
CustomTopAppBarExample expandedWidget(List<Widget>? expandedWidget) =>
this(expandedWidget: expandedWidget);
@override
CustomTopAppBarExample key(Key? key) => this(key: key);
@override
CustomTopAppBarExample call({
TextWrapper? title,
bool? centerTitle,
ShapeBorder? shape,
SystemUiOverlayStyle? systemOverlayStyle,
bool? automaticallyImplyLeading,
Widget? flexibleSpace,
PreferredSizeWidget? bottom,
double? elevation,
double? scrolledUnderElevation,
Color? shadowColor,
Color? surfaceTintColor,
MultiColor? backgroundColor,
IconThemeData? iconTheme,
bool? primary,
bool? excludeHeaderSemantics,
double? toolbarHeight,
double? leadingWidth,
Widget? leading,
List<Widget>? actions,
List<Widget>? expandedWidget,
Key? key,
}) =>
CustomTopAppBarExample(
title: title ?? _value.title,
key: key ?? _value.key,
);
}
mixin $CustomTopAppBarExampleCWMixin on Component {
$TopAppBarComponentCWProxy get copyWith =>
$CustomTopAppBarExampleCWProxyImpl(this as CustomTopAppBarExample);
}

View File

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
/// Defines standard UI control states
enum ControlState { enum ControlState {
/// When the control is disabled and un-clickable /// When the control is disabled and un-clickable
disabled, disabled,

View File

@ -15,5 +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 './control_state.dart'; export './control_state.dart';
export './extra_state.dart';
export './status_state.dart'; export './status_state.dart';

View File

@ -1,35 +0,0 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
/// Defines extra UI control states that can
/// be combined with [ControlState]
enum ExtraState {
/// When the control is selected
selected,
/// When the control is invalid
invalid,
/// When the control is freezed
/// Useful to prevent user from changing the control state
freezed;
bool isSelected() => this == ExtraState.selected;
bool isInvalid() => this == ExtraState.invalid;
bool isFreezed() => this == ExtraState.freezed;
}

View File

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/foundation.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
abstract class ButtonComponent extends Component { abstract class ButtonComponent extends Component {
@ -27,7 +26,6 @@ abstract class ButtonComponent extends Component {
this.selectedStyle, this.selectedStyle,
this.invalidStyle, this.invalidStyle,
this.onPressed, this.onPressed,
this.disabled,
super.themeResolver, super.themeResolver,
super.key, super.key,
}); });
@ -53,12 +51,6 @@ abstract class ButtonComponent extends Component {
/// Style of this button in invalid state /// Style of this button in invalid state
final ButtonStyle<dynamic>? invalidStyle; final ButtonStyle<dynamic>? invalidStyle;
/// Callback on button press, /// Callback on button press
///
/// [ControlState] is passed as argument and can be used to determine if the
/// button was pressed in disabled state or not.
final void Function(ControlState state)? onPressed; final void Function(ControlState state)? onPressed;
/// Current state of this button
final ValueNotifier<bool>? disabled;
} }

View File

@ -36,7 +36,6 @@ abstract class FileSelectionButtonComponent extends ButtonComponent
super.selectedStyle, super.selectedStyle,
super.invalidStyle, super.invalidStyle,
super.onPressed, super.onPressed,
super.disabled,
super.themeResolver, super.themeResolver,
super.key, super.key,
}); });

View File

@ -22,7 +22,6 @@ abstract class $FileSelectionButtonComponentCWProxy {
FileSelectionButtonComponent invalidStyle(ButtonStyle<dynamic>? invalidStyle); FileSelectionButtonComponent invalidStyle(ButtonStyle<dynamic>? invalidStyle);
FileSelectionButtonComponent onPressed( FileSelectionButtonComponent onPressed(
void Function(ControlState)? onPressed); void Function(ControlState)? onPressed);
FileSelectionButtonComponent disabled(ValueNotifier<bool>? disabled);
FileSelectionButtonComponent themeResolver( FileSelectionButtonComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver); ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
FileSelectionButtonComponent key(Key? key); FileSelectionButtonComponent key(Key? key);
@ -39,7 +38,6 @@ abstract class $FileSelectionButtonComponentCWProxy {
ButtonStyle<dynamic>? selectedStyle, ButtonStyle<dynamic>? selectedStyle,
ButtonStyle<dynamic>? invalidStyle, ButtonStyle<dynamic>? invalidStyle,
void Function(ControlState)? onPressed, void Function(ControlState)? onPressed,
ValueNotifier<bool>? disabled,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}); });

View File

@ -34,7 +34,6 @@ abstract class FlatButtonComponent extends ButtonComponent
super.focusedStyle, super.focusedStyle,
super.tappedStyle, super.tappedStyle,
super.onPressed, super.onPressed,
super.disabled,
super.themeResolver, super.themeResolver,
super.key, super.key,
}); });

View File

@ -17,7 +17,6 @@ abstract class $FlatButtonComponentCWProxy {
FlatButtonComponent focusedStyle(ButtonStyle<dynamic>? focusedStyle); FlatButtonComponent focusedStyle(ButtonStyle<dynamic>? focusedStyle);
FlatButtonComponent tappedStyle(ButtonStyle<dynamic>? tappedStyle); FlatButtonComponent tappedStyle(ButtonStyle<dynamic>? tappedStyle);
FlatButtonComponent onPressed(void Function(ControlState)? onPressed); FlatButtonComponent onPressed(void Function(ControlState)? onPressed);
FlatButtonComponent disabled(ValueNotifier<bool>? disabled);
FlatButtonComponent themeResolver( FlatButtonComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver); ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
FlatButtonComponent key(Key? key); FlatButtonComponent key(Key? key);
@ -32,7 +31,6 @@ abstract class $FlatButtonComponentCWProxy {
ButtonStyle<dynamic>? focusedStyle, ButtonStyle<dynamic>? focusedStyle,
ButtonStyle<dynamic>? tappedStyle, ButtonStyle<dynamic>? tappedStyle,
void Function(ControlState)? onPressed, void Function(ControlState)? onPressed,
ValueNotifier<bool>? disabled,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}); });

View File

@ -31,7 +31,6 @@ abstract class SimpleIconButtonComponent extends ButtonComponent
super.focusedStyle, super.focusedStyle,
super.tappedStyle, super.tappedStyle,
super.onPressed, super.onPressed,
super.disabled,
super.themeResolver, super.themeResolver,
super.key, super.key,
}); });

View File

@ -14,7 +14,6 @@ abstract class $SimpleIconButtonComponentCWProxy {
SimpleIconButtonComponent focusedStyle(ButtonStyle<dynamic>? focusedStyle); SimpleIconButtonComponent focusedStyle(ButtonStyle<dynamic>? focusedStyle);
SimpleIconButtonComponent tappedStyle(ButtonStyle<dynamic>? tappedStyle); SimpleIconButtonComponent tappedStyle(ButtonStyle<dynamic>? tappedStyle);
SimpleIconButtonComponent onPressed(void Function(ControlState)? onPressed); SimpleIconButtonComponent onPressed(void Function(ControlState)? onPressed);
SimpleIconButtonComponent disabled(ValueNotifier<bool>? disabled);
SimpleIconButtonComponent themeResolver( SimpleIconButtonComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver); ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
SimpleIconButtonComponent key(Key? key); SimpleIconButtonComponent key(Key? key);
@ -26,7 +25,6 @@ abstract class $SimpleIconButtonComponentCWProxy {
ButtonStyle<dynamic>? focusedStyle, ButtonStyle<dynamic>? focusedStyle,
ButtonStyle<dynamic>? tappedStyle, ButtonStyle<dynamic>? tappedStyle,
void Function(ControlState)? onPressed, void Function(ControlState)? onPressed,
ValueNotifier<bool>? disabled,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}); });

View File

@ -34,7 +34,6 @@ abstract class SymbolButtonComponent extends ButtonComponent
super.tappedStyle, super.tappedStyle,
super.selectedStyle, super.selectedStyle,
super.onPressed, super.onPressed,
super.disabled,
super.themeResolver, super.themeResolver,
super.key, super.key,
}); });

View File

@ -17,7 +17,6 @@ abstract class $SymbolButtonComponentCWProxy {
SymbolButtonComponent tappedStyle(ButtonStyle<dynamic>? tappedStyle); SymbolButtonComponent tappedStyle(ButtonStyle<dynamic>? tappedStyle);
SymbolButtonComponent selectedStyle(ButtonStyle<dynamic>? selectedStyle); SymbolButtonComponent selectedStyle(ButtonStyle<dynamic>? selectedStyle);
SymbolButtonComponent onPressed(void Function(ControlState)? onPressed); SymbolButtonComponent onPressed(void Function(ControlState)? onPressed);
SymbolButtonComponent disabled(ValueNotifier<bool>? disabled);
SymbolButtonComponent themeResolver( SymbolButtonComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver); ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
SymbolButtonComponent key(Key? key); SymbolButtonComponent key(Key? key);
@ -32,7 +31,6 @@ abstract class $SymbolButtonComponentCWProxy {
ButtonStyle<dynamic>? tappedStyle, ButtonStyle<dynamic>? tappedStyle,
ButtonStyle<dynamic>? selectedStyle, ButtonStyle<dynamic>? selectedStyle,
void Function(ControlState)? onPressed, void Function(ControlState)? onPressed,
ValueNotifier<bool>? disabled,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}); });

View File

@ -19,7 +19,8 @@ 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_widget_component.dart';
export './loader/loader.dart'; export './loader_component.dart';
export './loader_style.dart';
export './loading_widget_component.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';

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 'dart:ui';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
class LoaderStyle extends ThemeStyle<LoaderStyle> {
const LoaderStyle({
this.colors,
this.stroke,
});
/// Merges non-null `b` attributes in `a`
static LoaderStyle? merge(
LoaderStyle? a,
LoaderStyle? b,
) {
if (b == null) {
return a?.copyWith();
}
if (a == null) {
return b.copyWith();
}
return a.copyWith(
colors: b.colors,
stroke: b.stroke,
);
}
/// Used for interpolation.
static LoaderStyle? lerp(
LoaderStyle? a,
LoaderStyle? b,
double t,
) {
if (a == null || b == null) {
return null;
}
// b.copyWith to return b attributes even if they are not lerped
return b.copyWith(
colors: MultiColor.lerp(a.colors, b.colors, t),
stroke: lerpDouble(a.stroke, b.stroke, t),
);
}
/// Gradient colors from start to end.
final MultiColor? colors;
/// Loader stroke width
final double? stroke;
@override
LoaderStyle? mergeWith(LoaderStyle? other) => LoaderStyle.merge(this, other);
@override
LoaderStyle copyWith({
MultiColor? colors,
double? stroke,
}) =>
LoaderStyle(
colors: colors ?? this.colors,
stroke: stroke ?? this.stroke,
);
@override
String toString() => 'LoaderStyle($colors, $stroke)';
}

View File

@ -16,3 +16,4 @@
export 'parser.dart'; export 'parser.dart';
export 'rich_text_builder_component.dart'; export 'rich_text_builder_component.dart';
export 'rich_text_builder_style.dart';

View File

@ -28,6 +28,7 @@ abstract class RichTextBuilderComponent extends Component
this.parser, this.parser,
this.defaultStyle, this.defaultStyle,
this.styles, this.styles,
super.themeResolver,
super.key, super.key,
}); });

View File

@ -11,12 +11,15 @@ abstract class $RichTextBuilderComponentCWProxy {
RichTextBuilderComponent parser(RichTextParser? parser); RichTextBuilderComponent parser(RichTextParser? parser);
RichTextBuilderComponent defaultStyle(TextStyle? defaultStyle); RichTextBuilderComponent defaultStyle(TextStyle? defaultStyle);
RichTextBuilderComponent styles(Map<String, TextStyle>? styles); RichTextBuilderComponent styles(Map<String, TextStyle>? styles);
RichTextBuilderComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
RichTextBuilderComponent key(Key? key); RichTextBuilderComponent key(Key? key);
RichTextBuilderComponent call({ RichTextBuilderComponent call({
String? text, String? text,
RichTextParser? parser, RichTextParser? parser,
TextStyle? defaultStyle, TextStyle? defaultStyle,
Map<String, TextStyle>? styles, Map<String, TextStyle>? styles,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}); });
} }

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/widgets.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
class RichTextBuilderStyle extends ThemeStyle<RichTextBuilderStyle> {
const RichTextBuilderStyle({
this.defaultStyle,
this.styles,
});
/// Merges non-null `b` attributes in `a`
static RichTextBuilderStyle? merge(
RichTextBuilderStyle? a,
RichTextBuilderStyle? b,
) {
if (b == null) {
return a?.copyWith();
}
if (a == null) {
return b.copyWith();
}
return a.copyWith(
defaultStyle: b.defaultStyle,
styles: b.styles,
);
}
/// Used for interpolation.
static RichTextBuilderStyle? lerp(
RichTextBuilderStyle? a,
RichTextBuilderStyle? b,
double t,
) {
if (a == null || b == null) {
return null;
}
// b.copyWith to return b attributes even if they are not lerped
return b.copyWith(
defaultStyle: TextStyle.lerp(a.defaultStyle, b.defaultStyle, t),
styles: b.styles, // TODO(wyatt): compute lerp value of each styles
);
}
/// Default TextStyle used in this rich text component.
final TextStyle? defaultStyle;
/// Used styles in this rich text component.
final Map<String, TextStyle>? styles;
@override
RichTextBuilderStyle? mergeWith(RichTextBuilderStyle? other) =>
RichTextBuilderStyle.merge(this, other);
@override
RichTextBuilderStyle? copyWith({
TextStyle? defaultStyle,
Map<String, TextStyle>? styles,
}) =>
RichTextBuilderStyle(
defaultStyle: defaultStyle ?? this.defaultStyle,
styles: styles ?? this.styles,
);
}

View File

@ -15,23 +15,14 @@
// 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:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart'; import 'package:wyatt_ui_kit_example/theme/constants.dart';
class FileSelectionButtons extends StatefulWidget { class FileSelectionButtons extends StatelessWidget {
const FileSelectionButtons({super.key}); const FileSelectionButtons({super.key});
@override
State<FileSelectionButtons> createState() => _FileSelectionButtonsState();
}
class _FileSelectionButtonsState extends State<FileSelectionButtons> {
final _disabled = ValueNotifier(true);
final _dynamic = ValueNotifier(false);
Widget _leading() => const DecoratedBox( Widget _leading() => const DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Constants.grey2, color: Constants.grey2,
@ -57,7 +48,6 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
const Gap(20), const Gap(20),
// Default
FileSelectionButton( FileSelectionButton(
leading: _leading(), leading: _leading(),
title: const TextWrapper( title: const TextWrapper(
@ -66,99 +56,65 @@ class _FileSelectionButtonsState extends State<FileSelectionButtons> {
subTitle: const TextWrapper('Taille max: 20 Mo'), subTitle: const TextWrapper('Taille max: 20 Mo'),
), ),
const Gap(20), const Gap(20),
BlocProvider( FileSelectionButton(
create: (context) => InvalidButtonCubit()..freeze(), leading: _leading(),
child: FileSelectionButton( title: const TextWrapper(
leading: _leading(), 'Enabled',
title: const TextWrapper(
'Enabled',
),
subTitle: const TextWrapper('Subtitle'),
), ),
), subTitle: const TextWrapper('Subtitle'),
)
..bloc.enable()
..bloc.freeze(),
const Gap(20), const Gap(20),
// Using a ValueNotifier to disable the button
FileSelectionButton( FileSelectionButton(
leading: _leading(), leading: _leading(),
title: const TextWrapper( title: const TextWrapper(
'Disabled', 'Disabled',
), ),
subTitle: const TextWrapper('Subtitle'), subTitle: const TextWrapper('Subtitle'),
disabled: _disabled, )
), ..bloc.disable()
..bloc.freeze(),
const Gap(20), const Gap(20),
BlocProvider( FileSelectionButton(
create: (context) => InvalidButtonCubit()..hover(), leading: _leading(),
child: FileSelectionButton( title: const TextWrapper(
leading: _leading(), 'Hovered',
title: const TextWrapper(
'Hovered',
),
subTitle: const TextWrapper('Subtitle'),
), ),
), subTitle: const TextWrapper('Subtitle'),
)
..bloc.onMouseEnter()
..bloc.freeze(),
const Gap(20), const Gap(20),
BlocProvider( FileSelectionButton(
create: (context) => InvalidButtonCubit()..focus(), leading: _leading(),
child: FileSelectionButton( title: const TextWrapper(
leading: _leading(), 'Focused',
title: const TextWrapper(
'Focused',
),
subTitle: const TextWrapper('Subtitle'),
), ),
), subTitle: const TextWrapper('Subtitle'),
)
..bloc.onFocus()
..bloc.freeze(),
const Gap(20), const Gap(20),
BlocProvider( FileSelectionButton(
create: (context) => InvalidButtonCubit()..tap(), leading: _leading(),
child: FileSelectionButton( title: const TextWrapper(
leading: _leading(), 'Tapped',
title: const TextWrapper(
'Tapped',
),
subTitle: const TextWrapper('Subtitle'),
), ),
), subTitle: const TextWrapper('Subtitle'),
)
..bloc.onClickDown()
..bloc.freeze(),
const Gap(20), const Gap(20),
BlocProvider( FileSelectionButton(
create: (context) => InvalidButtonCubit()..invalidate(), leading: _leading(),
child: FileSelectionButton( title: const TextWrapper(
leading: _leading(), 'Invalid',
title: const TextWrapper(
'Invalid',
),
subTitle: const TextWrapper('Subtitle'),
), ),
), subTitle: const TextWrapper('Subtitle'),
const Gap(20), )
// Dynamic, disabled with ValueNotifier and invalid with BlocProvider. ..bloc.invalidate()
// Keep the state when the button is disabled. ..bloc.freeze(),
Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Enabled'),
Checkbox(
value: !_dynamic.value,
onChanged: (value) {
setState(() {
_dynamic.value = !_dynamic.value;
});
},
),
],
),
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Dynamic',
),
subTitle: const TextWrapper('Subtitle'),
disabled: _dynamic,
),
],
),
const Gap(20), const Gap(20),
], ],
); );

View File

@ -15,22 +15,13 @@
// 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:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class FlatButtons extends StatefulWidget { class FlatButtons extends StatelessWidget {
const FlatButtons({super.key}); const FlatButtons({super.key});
@override
State<FlatButtons> createState() => _FlatButtonsState();
}
class _FlatButtonsState extends State<FlatButtons> {
final _disabled = ValueNotifier(true);
final _dynamic = ValueNotifier(false);
@override @override
Widget build(BuildContext context) => Column( Widget build(BuildContext context) => Column(
children: [ children: [
@ -39,80 +30,56 @@ class _FlatButtonsState extends State<FlatButtons> {
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
const Gap(20), const Gap(20),
// Default Center(
const Center(
/// You can overwrite global textstyle of the label with [label], /// You can overwrite global textstyle of the label with [label],
/// but if you only want to override the color/gradient of the text /// but if you only want to override the color/gradient of the text
/// in a particular case you can override the style that will /// in a particular case you can override the style that will
/// be merge during the build. /// be merge during the build.
child: FlatButton( child: FlatButton(
label: TextWrapper( label: const TextWrapper(
'Voir notre savoir faire', 'Voir notre savoir faire',
), ),
), ),
), ),
const Gap(20), const Gap(20),
Center( Center(
child: BlocProvider( child: FlatButton(
create: (context) => ButtonCubit()..freeze(), label: const TextWrapper('Enabled'),
child: const FlatButton( )
label: TextWrapper('Enabled'), ..bloc.enable()
), ..bloc.freeze(),
),
), ),
const Gap(20), const Gap(20),
// Disabled with ValueNotifier
Center( Center(
child: FlatButton( child: FlatButton(
label: const TextWrapper('Disabled'), label: const TextWrapper('Disabled'),
disabled: _disabled, )
), ..bloc.disable()
..bloc.freeze(),
), ),
const Gap(20), const Gap(20),
Center( Center(
child: BlocProvider( child: FlatButton(
create: (context) => ButtonCubit()..hover(), label: const TextWrapper('Hovered'),
child: const FlatButton( )
label: TextWrapper('Hovered'), ..bloc.onMouseEnter()
), ..bloc.freeze(),
),
), ),
const Gap(20), const Gap(20),
Center( Center(
child: BlocProvider( child: FlatButton(
create: (context) => ButtonCubit()..focus(), label: const TextWrapper('Focused'),
child: const FlatButton( )
label: TextWrapper('Focused'), ..bloc.onFocus()
), ..bloc.freeze(),
),
), ),
const Gap(20), const Gap(20),
Center( Center(
child: BlocProvider( child: FlatButton(
create: (context) => ButtonCubit()..tap(), label: const TextWrapper('Tapped'),
child: const FlatButton( )
label: TextWrapper('Tapped'), ..bloc.onClickDown()
), ..bloc.freeze(),
),
),
const Gap(20),
// Dynamic, disabled with ValueNotifier and
// keep the state when the button is disabled
Row(
children: [
Checkbox(
value: !_dynamic.value,
onChanged: (value) {
setState(() {
_dynamic.value = !_dynamic.value;
});
},
),
FlatButton(
label: const TextWrapper('Dynamic'),
disabled: _dynamic,
),
],
), ),
const Gap(20), const Gap(20),
], ],

View File

@ -15,21 +15,12 @@
// 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:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class SimpleIconButtons extends StatefulWidget { class SimpleIconButtons extends StatelessWidget {
const SimpleIconButtons({super.key}); const SimpleIconButtons({super.key});
@override
State<SimpleIconButtons> createState() => _SimpleIconButtonsState();
}
class _SimpleIconButtonsState extends State<SimpleIconButtons> {
final _disabled = ValueNotifier(true);
final _dynamic = ValueNotifier(false);
@override @override
Widget build(BuildContext context) => Column( Widget build(BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -39,9 +30,8 @@ class _SimpleIconButtonsState extends State<SimpleIconButtons> {
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
const Gap(20), const Gap(20),
// Default SimpleIconButton(
const SimpleIconButton( icon: const Icon(
icon: Icon(
Icons.storm_outlined, Icons.storm_outlined,
size: 17, size: 17,
), ),
@ -52,101 +42,71 @@ class _SimpleIconButtonsState extends State<SimpleIconButtons> {
style: Theme.of(context).textTheme.labelMedium, style: Theme.of(context).textTheme.labelMedium,
), ),
const Gap(10), const Gap(10),
BlocProvider( SimpleIconButton(
create: (context) => ButtonCubit()..freeze(), icon: const Icon(
child: const SimpleIconButton( Icons.storm_outlined,
icon: Icon( size: 17,
Icons.storm_outlined,
size: 17,
),
), ),
), )
..bloc.enable()
..bloc.freeze(),
const Gap(20), const Gap(20),
Text( Text(
'Disabled', 'Disabled',
style: Theme.of(context).textTheme.labelMedium, style: Theme.of(context).textTheme.labelMedium,
), ),
const Gap(10), const Gap(10),
// Disabled using ValueNotifier
SimpleIconButton( SimpleIconButton(
icon: const Icon( icon: const Icon(
Icons.storm_outlined, Icons.storm_outlined,
size: 17, size: 17,
), ),
disabled: _disabled, )
), ..bloc.disable()
..bloc.freeze(),
const Gap(20), const Gap(20),
Text( Text(
'Hovered', 'Hovered',
style: Theme.of(context).textTheme.labelMedium, style: Theme.of(context).textTheme.labelMedium,
), ),
const Gap(10), const Gap(10),
BlocProvider( SimpleIconButton(
create: (context) => ButtonCubit()..hover(), icon: const Icon(
child: const SimpleIconButton( Icons.storm_outlined,
icon: Icon( size: 17,
Icons.storm_outlined,
size: 17,
),
), ),
), )
..bloc.onMouseEnter()
..bloc.freeze(),
const Gap(20), const Gap(20),
Text( Text(
'Focused', 'Focused',
style: Theme.of(context).textTheme.labelMedium, style: Theme.of(context).textTheme.labelMedium,
), ),
const Gap(10), const Gap(10),
BlocProvider( SimpleIconButton(
create: (context) => ButtonCubit()..focus(), icon: const Icon(
child: const SimpleIconButton( Icons.storm_outlined,
icon: Icon( size: 17,
Icons.storm_outlined,
size: 17,
),
), ),
), )
..bloc.onFocus()
..bloc.freeze(),
const Gap(20), const Gap(20),
Text( Text(
'Tapped', 'Tapped',
style: Theme.of(context).textTheme.labelMedium, style: Theme.of(context).textTheme.labelMedium,
), ),
const Gap(10), const Gap(10),
BlocProvider( SimpleIconButton(
create: (context) => ButtonCubit()..tap(), icon: const Icon(
child: const SimpleIconButton( Icons.storm_outlined,
icon: Icon( size: 17,
Icons.storm_outlined,
size: 17,
),
), ),
), )
..bloc.onClickDown()
..bloc.freeze(),
const Gap(20), const Gap(20),
Text(
'Dynamic',
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
// Dynamic, disabled with ValueNotifier and
// keep the state when the button is disabled
Row(
children: [
Checkbox(
value: !_dynamic.value,
onChanged: (value) {
setState(() {
_dynamic.value = !_dynamic.value;
});
},
),
SimpleIconButton(
icon: const Icon(
Icons.storm_outlined,
size: 17,
),
disabled: _dynamic,
),
],
),
], ],
); );
} }

View File

@ -15,23 +15,14 @@
// 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:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart'; import 'package:wyatt_ui_kit_example/theme/constants.dart';
class SymbolButtons extends StatefulWidget { class SymbolButtons extends StatelessWidget {
const SymbolButtons({super.key}); const SymbolButtons({super.key});
@override
State<SymbolButtons> createState() => _SymbolButtonsState();
}
class _SymbolButtonsState extends State<SymbolButtons> {
final _disabled = ValueNotifier(true);
final _dynamic = ValueNotifier(false);
Icon _icon(BuildContext context) => Icon( Icon _icon(BuildContext context) => Icon(
Icons.android, Icons.android,
size: 25, size: 25,
@ -54,70 +45,47 @@ class _SymbolButtonsState extends State<SymbolButtons> {
icon: _icon(context), icon: _icon(context),
), ),
const Gap(20), const Gap(20),
BlocProvider( SymbolButton(
create: (context) => SelectableButtonCubit()..freeze(), label: const TextWrapper('Enabled'),
child: SymbolButton( icon: _icon(context),
label: const TextWrapper('Enabled'), )
icon: _icon(context), ..bloc.enable()
), ..bloc.freeze(),
),
const Gap(20), const Gap(20),
// Disabled
SymbolButton( SymbolButton(
label: const TextWrapper('Disabled'), label: const TextWrapper('Disabled'),
icon: _icon(context), icon: _icon(context),
disabled: _disabled, )
), ..bloc.disable()
..bloc.freeze(),
const Gap(20), const Gap(20),
BlocProvider( SymbolButton(
create: (context) => SelectableButtonCubit()..hover(), label: const TextWrapper('Hovered'),
child: SymbolButton( icon: _icon(context),
label: const TextWrapper('Hovered'), )
icon: _icon(context), ..bloc.onMouseEnter()
), ..bloc.freeze(),
),
const Gap(20), const Gap(20),
BlocProvider( SymbolButton(
create: (context) => SelectableButtonCubit()..focus(), label: const TextWrapper('Focused'),
child: SymbolButton( icon: _icon(context),
label: const TextWrapper('Focused'), )
icon: _icon(context), ..bloc.onFocus()
), ..bloc.freeze(),
),
const Gap(20), const Gap(20),
BlocProvider( SymbolButton(
create: (context) => SelectableButtonCubit()..tap(), label: const TextWrapper('Tapped'),
child: SymbolButton( icon: _icon(context),
label: const TextWrapper('Tapped'), )
icon: _icon(context), ..bloc.onClickDown()
), ..bloc.freeze(),
),
const Gap(20), const Gap(20),
BlocProvider( SymbolButton(
create: (context) => SelectableButtonCubit()..select(), label: const TextWrapper('Selected'),
child: SymbolButton( icon: _icon(context),
label: const TextWrapper('Selected'), )
icon: _icon(context), ..bloc.select()
), ..bloc.freeze(),
),
const Gap(20),
Row(
children: [
Checkbox(
value: !_dynamic.value,
onChanged: (value) {
setState(() {
_dynamic.value = !_dynamic.value;
});
},
),
SymbolButton(
label: const TextWrapper('Dynamic'),
icon: _icon(context),
disabled: _dynamic,
),
],
),
const Gap(20), const Gap(20),
DecoratedBox( DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@ -10,7 +10,6 @@ environment:
dependencies: dependencies:
flutter: { sdk: flutter } flutter: { sdk: flutter }
flutter_bloc: ^8.1.2
flutter_localizations: { sdk: flutter } flutter_localizations: { sdk: flutter }
gap: ^2.0.1 gap: ^2.0.1

View File

@ -14,9 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
export './cubit/button_cubit.dart';
export './cubit/invalid_button_cubit.dart';
export './cubit/selectable_button_cubit.dart';
export './file_selection_button/file_selection_button.dart'; export './file_selection_button/file_selection_button.dart';
export './flat_button/flat_button.dart'; export './flat_button/flat_button.dart';
export './simple_icon_button/simple_icon_button.dart'; export './simple_icon_button/simple_icon_button.dart';

View File

@ -23,19 +23,8 @@ import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'button_state.dart'; part 'button_state.dart';
class ButtonCubit extends Cubit<ButtonState> { class ButtonCubit extends Cubit<ButtonState> {
ButtonCubit() : super(const ButtonState.initial(ControlState.normal)) { ButtonCubit() : super(const ButtonState.initial(ControlState.normal));
_previousState = state.copyWith();
}
/// The previous state of the button.
/// This is used to restore the state of the button when
/// the button is enabled again.
ButtonState? _previousState;
/// When the mouse enters the button. The button will change
/// its state to [ControlState.hovered].
///
/// If the button is disabled or freezed, this method does nothing.
FutureOr<void> onMouseEnter() async { FutureOr<void> onMouseEnter() async {
if (state.isDisabled || state.isFreezed) { if (state.isDisabled || state.isFreezed) {
return; return;
@ -43,10 +32,6 @@ class ButtonCubit extends Cubit<ButtonState> {
emit(state.copyWith(state: ControlState.hovered)); emit(state.copyWith(state: ControlState.hovered));
} }
/// When the mouse leaves the button. The button will change
/// its state to [ControlState.normal].
///
/// If the button is disabled or freezed, this method does nothing.
FutureOr<void> onMouseLeave() async { FutureOr<void> onMouseLeave() async {
if (state.isDisabled || state.isFreezed) { if (state.isDisabled || state.isFreezed) {
return; return;
@ -55,10 +40,6 @@ class ButtonCubit extends Cubit<ButtonState> {
emit(state.copyWith(state: ControlState.normal)); emit(state.copyWith(state: ControlState.normal));
} }
/// When the button is focused. The button will change
/// its state to [ControlState.focused].
///
/// If the button is disabled or freezed, this method does nothing.
FutureOr<void> onFocus() async { FutureOr<void> onFocus() async {
if (state.isDisabled || state.isFreezed) { if (state.isDisabled || state.isFreezed) {
return; return;
@ -66,10 +47,6 @@ class ButtonCubit extends Cubit<ButtonState> {
emit(state.copyWith(state: ControlState.focused)); emit(state.copyWith(state: ControlState.focused));
} }
/// When the button is unfocused. The button will change
/// its state to [ControlState.normal].
///
/// If the button is disabled or freezed, this method does nothing.
FutureOr<void> onUnfocus() async { FutureOr<void> onUnfocus() async {
if (state.isDisabled || state.isFreezed) { if (state.isDisabled || state.isFreezed) {
return; return;
@ -77,10 +54,6 @@ class ButtonCubit extends Cubit<ButtonState> {
emit(state.copyWith(state: ControlState.normal)); emit(state.copyWith(state: ControlState.normal));
} }
/// When the mouse is pressed on the button. The button will change
/// its state to [ControlState.tapped].
///
/// If the button is disabled or freezed, this method does nothing.
FutureOr<void> onClickDown() async { FutureOr<void> onClickDown() async {
if (state.isDisabled || state.isFreezed) { if (state.isDisabled || state.isFreezed) {
return; return;
@ -88,127 +61,39 @@ class ButtonCubit extends Cubit<ButtonState> {
emit(state.copyWith(state: ControlState.tapped)); emit(state.copyWith(state: ControlState.tapped));
} }
/// When the mouse is released on the button. The button will change
/// its state to [ControlState.hovered].
///
/// If the button is disabled or freezed, this method does nothing.
FutureOr<void> onClickUpIn() async { FutureOr<void> onClickUpIn() async {
if (state.isDisabled || state.isFreezed) { if (state.isDisabled) {
return; return;
} }
emit(state.copyWith(state: ControlState.hovered)); emit(state.copyWith(state: ControlState.hovered));
} }
/// When the mouse is released outside the button. The button will change
/// its state to [ControlState.normal].
///
/// If the button is disabled or freezed, this method does nothing.
FutureOr<void> onClickUpOut() async { FutureOr<void> onClickUpOut() async {
if (state.isDisabled || state.isFreezed) { if (state.isDisabled) {
return; return;
} }
emit(state.copyWith(state: ControlState.normal)); emit(state.copyWith(state: ControlState.normal));
} }
/// Programmatically change the state or extra states of the button.
FutureOr<void> setState({
ControlState? state,
List<ExtraState>? extraStates,
}) async {
emit(this.state.copyWith(state: state, extraStates: extraStates));
}
/// Disable the button.
///
/// This will remove all extra states and set
/// the state to [ControlState.disabled] and add [ExtraState.freezed].
FutureOr<void> disable() async { FutureOr<void> disable() async {
/// Save the previous state. if (state.isFreezed) {
/// copyWith() is used to make sure the previous state is not
/// affected by any changes to the current state.
_previousState = state.copyWith();
emit(
const ButtonState(
state: ControlState.disabled,
extraStates: [ExtraState.freezed],
),
);
}
/// Enable the button.
///
/// This will restore the previous state of the button.
FutureOr<void> enable() async {
if (_previousState == null) {
return; return;
} }
emit(state.copyWith(state: ControlState.disabled));
emit(_previousState!);
_previousState = null;
} }
/// Set the button to hovered state and freeze it. FutureOr<void> enable() async {
/// if (state.isFreezed) {
/// Use this method to programmatically set the button to hovered state. return;
FutureOr<void> hover() async { }
emit( emit(state.copyWith(state: ControlState.normal));
state.copyWith(
state: ControlState.hovered,
extraStates: state.extraStates + [ExtraState.freezed],
),
);
} }
/// Set the button to focused state and freeze it.
///
/// Use this method to programmatically set the button to focused state.
FutureOr<void> focus() async {
emit(
state.copyWith(
state: ControlState.focused,
extraStates: state.extraStates + [ExtraState.freezed],
),
);
}
/// Set the button to tapped state and freeze it.
///
/// Use this method to programmatically set the button to tapped state.
FutureOr<void> tap() async {
emit(
state.copyWith(
state: ControlState.tapped,
extraStates: state.extraStates + [ExtraState.freezed],
),
);
}
/// Freeze the button in its current state.
///
/// Shortcut for [setState] with extra state [ExtraState.freezed].
///
/// Use this method to programmatically freeze the button.
FutureOr<void> freeze() async { FutureOr<void> freeze() async {
emit( emit(state.copyWith(freezed: true));
state.copyWith(
extraStates: state.extraStates + [ExtraState.freezed],
),
);
} }
/// Unfreeze the button.
///
/// Shortcut for [setState] without extra state [ExtraState.freezed].
///
/// Use this method to programmatically unfreeze the button.
FutureOr<void> unfreeze() async { FutureOr<void> unfreeze() async {
emit( emit(state.copyWith(freezed: false));
state.copyWith(
extraStates: state.extraStates
.where((element) => element != ExtraState.freezed)
.toList(),
),
);
} }
} }

View File

@ -18,41 +18,54 @@
part of 'button_cubit.dart'; part of 'button_cubit.dart';
class ButtonState extends Equatable { class ButtonState extends Equatable {
const ButtonState({required this.state, required this.extraStates}); const ButtonState({
required this.state,
required this.selected,
required this.invalid,
required this.freezed,
});
const ButtonState.initial(this.state) : extraStates = const []; const ButtonState.initial(this.state)
: selected = false,
invalid = false,
freezed = false;
/// The control state of the button
final ControlState state; final ControlState state;
/// Not in control state, because a button state can be // Not in control state, because a button state can be
/// a control state + extra state // a control state + extra state
/// e.g : // e.g : hover + invalid, or selected + tapped
/// - ControlState.hover + [ExtraState.invalid] final bool selected;
/// - ControlState.tapped + [ExtraState.invalid + ExtraState.freezed] final bool invalid;
final List<ExtraState> extraStates; final bool freezed;
bool get isDisabled => state.isDisabled(); bool get isDisabled => state.isDisabled();
bool get isEnabled => state.isEnabled(); bool get isEnabled => state.isEnabled();
bool get isFocused => state.isFocused(); bool get isFocused => state.isFocused();
bool get isHovered => state.isHovered(); bool get isHovered => state.isHovered();
bool get isTapped => state.isTapped(); bool get isTapped => state.isTapped();
bool get isSelected => extraStates.contains(ExtraState.selected);
bool get isInvalid => extraStates.contains(ExtraState.invalid); // only for consistence
bool get isFreezed => extraStates.contains(ExtraState.freezed); bool get isSelected => selected;
bool get isInvalid => invalid;
bool get isFreezed => freezed;
@override @override
List<Object?> get props => [state, extraStates]; List<Object?> get props => [state, selected, invalid, freezed];
@override @override
bool? get stringify => true; bool? get stringify => true;
ButtonState copyWith({ ButtonState copyWith({
ControlState? state, ControlState? state,
List<ExtraState>? extraStates, bool? selected,
bool? invalid,
bool? freezed,
}) => }) =>
ButtonState( ButtonState(
state: state ?? this.state, state: state ?? this.state,
extraStates: extraStates ?? this.extraStates, selected: selected ?? this.selected,
invalid: invalid ?? this.invalid,
freezed: freezed ?? this.freezed,
); );
} }

View File

@ -20,29 +20,49 @@ import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart'; import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
class InvalidButtonCubit extends ButtonCubit { class InvalidButtonCubit extends ButtonCubit {
/// When the button is invalid. The button will add the @override
/// [ExtraState.invalid] to its extra states. FutureOr<void> onClickUpIn() async {
/// if (state.isDisabled || state.isFreezed) {
/// Use [validate] to remove the [ExtraState.invalid] from the extra states. return;
/// }
/// Use this method to invalidate the button programmatically.
FutureOr<void> invalidate() async {
emit(state.copyWith(extraStates: state.extraStates + [ExtraState.invalid]));
}
/// When the button is valid. The button will remove the
/// [ExtraState.invalid] from its extra states.
///
/// Use [invalidate] to add the [ExtraState.invalid] to the extra states.
///
/// Use this method to validate the button programmatically.
FutureOr<void> validate() async {
emit( emit(
state.copyWith( state.copyWith(
extraStates: state.extraStates state: ControlState.hovered,
.where((element) => element != ExtraState.invalid)
.toList(),
), ),
); );
} }
@override
FutureOr<void> onClickUpOut() async {
if (state.isDisabled || state.isFreezed) {
return;
}
emit(
state.copyWith(
state: ControlState.normal,
),
);
}
FutureOr<void> invalidate() async {
if (state.isDisabled || state.isFreezed) {
return;
}
emit(
state.copyWith(invalid: true),
);
}
FutureOr<void> fix() async {
if (state.isDisabled || state.isFreezed) {
return;
}
emit(
state.copyWith(invalid: false),
);
}
} }

View File

@ -20,32 +20,14 @@ import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart'; import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
class SelectableButtonCubit extends ButtonCubit { class SelectableButtonCubit extends ButtonCubit {
ButtonState _toggle(ButtonState state) {
if (state.isSelected) {
return state.copyWith(
extraStates: state.extraStates
.where((element) => element != ExtraState.selected)
.toList(),
);
} else {
return state.copyWith(
extraStates: state.extraStates + [ExtraState.selected],
);
}
}
/// When the mouse is released on the button, the button will
/// add the [ExtraState.selected] if it is selected, or remove
/// the [ExtraState.selected] if it is not selected.
///
/// If the button is disabled or freezed, this method does nothing.
@override @override
FutureOr<void> onClickUpIn() async { FutureOr<void> onClickUpIn() async {
if (state.isDisabled || state.isFreezed) { if (state.isDisabled || state.isFreezed) {
return; return;
} }
emit(
emit(_toggle(state).copyWith(state: ControlState.hovered)); state.copyWith(state: ControlState.hovered, selected: !state.selected),
);
} }
@override @override
@ -53,31 +35,26 @@ class SelectableButtonCubit extends ButtonCubit {
if (state.isDisabled || state.isFreezed) { if (state.isDisabled || state.isFreezed) {
return; return;
} }
emit(state.copyWith(state: ControlState.normal, selected: !state.selected));
emit(_toggle(state).copyWith(state: ControlState.normal));
} }
/// When the button is selected. The button will add the
/// [ExtraState.selected] to its extra states.
///
/// Use this method to select the button programmatically.
FutureOr<void> select() async { FutureOr<void> select() async {
if (state.isDisabled || state.isFreezed) {
return;
}
emit( emit(
state.copyWith(extraStates: state.extraStates + [ExtraState.selected]), state.copyWith(selected: true),
); );
} }
/// When the button is unselected. The button will remove the
/// [ExtraState.selected] from its extra states.
///
/// Use this method to unselect the button programmatically.
FutureOr<void> unselect() async { FutureOr<void> unselect() async {
if (state.isDisabled || state.isFreezed) {
return;
}
emit( emit(
state.copyWith( state.copyWith(selected: false),
extraStates: state.extraStates
.where((element) => element != ExtraState.selected)
.toList(),
),
); );
} }
} }

View File

@ -1,35 +0,0 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/foundation.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
/// A class that listens to the state of a [ValueNotifier] and
/// changes the state of a [ButtonCubit] accordingly.
abstract class StateListener {
/// Listens to the state of the [ValueNotifier] and
/// changes the state of the [ButtonCubit] accordingly.
static void listen<B extends ButtonCubit>(
ValueNotifier<bool>? state,
B bloc,
) {
if (state!.value) {
bloc.disable();
} else {
bloc.enable();
}
}
}

View File

@ -14,4 +14,23 @@
// 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 './loader_component.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ExportableBloc<T extends StateStreamableSource<Object?>>
extends StatelessWidget {
const ExportableBloc({
required this.bloc,
required this.child,
super.key,
});
final T bloc;
final Widget child;
@override
Widget build(BuildContext context) => BlocProvider<T>.value(
value: bloc,
child: child,
);
}

View File

@ -17,6 +17,8 @@
import 'package:flutter/material.dart' hide ButtonStyle; import 'package:flutter/material.dart' hide ButtonStyle;
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/invalid_button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/exportable_bloc.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_screen.dart'; import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_screen.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart'; import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart';
@ -25,7 +27,7 @@ part 'file_selection_button.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class FileSelectionButton extends FileSelectionButtonComponent class FileSelectionButton extends FileSelectionButtonComponent
with $FileSelectionButtonCWMixin { with $FileSelectionButtonCWMixin {
const FileSelectionButton({ FileSelectionButton({
super.leading, super.leading,
super.title, super.title,
super.subTitle, super.subTitle,
@ -37,12 +39,15 @@ class FileSelectionButton extends FileSelectionButtonComponent
super.selectedStyle, super.selectedStyle,
super.invalidStyle, super.invalidStyle,
super.onPressed, super.onPressed,
super.disabled,
super.mainAxisSize, super.mainAxisSize,
super.themeResolver, super.themeResolver,
super.key, super.key,
}); });
final InvalidButtonCubit _cubit = InvalidButtonCubit();
InvalidButtonCubit get bloc => _cubit;
@override @override
FileSelectionButtonStyle? get disabledStyle => FileSelectionButtonStyle? get disabledStyle =>
super.disabledStyle as FileSelectionButtonStyle?; super.disabledStyle as FileSelectionButtonStyle?;
@ -76,21 +81,23 @@ class FileSelectionButton extends FileSelectionButtonComponent
super.themeResolver as FileSelectionButtonThemeResolver?; super.themeResolver as FileSelectionButtonThemeResolver?;
@override @override
Widget build(BuildContext context) => FileSelectionButtonScreen( Widget build(BuildContext context) => ExportableBloc(
leading: leading, bloc: _cubit,
title: title, child: FileSelectionButtonScreen(
subTitle: subTitle, leading: leading,
disabledStyle: disabledStyle, title: title,
normalStyle: normalStyle, subTitle: subTitle,
hoveredStyle: hoveredStyle, disabledStyle: disabledStyle,
focusedStyle: focusedStyle, normalStyle: normalStyle,
tappedStyle: tappedStyle, hoveredStyle: hoveredStyle,
selectedStyle: selectedStyle, focusedStyle: focusedStyle,
invalidStyle: invalidStyle, tappedStyle: tappedStyle,
onPressed: onPressed, selectedStyle: selectedStyle,
disabled: disabled, invalidStyle: invalidStyle,
mainAxisSize: mainAxisSize, onPressed: onPressed,
themeResolver: themeResolver, mainAxisSize: mainAxisSize,
key: key, themeResolver: themeResolver,
key: key,
),
); );
} }

View File

@ -45,9 +45,6 @@ class $FileSelectionButtonCWProxyImpl
FileSelectionButton onPressed(void Function(ControlState)? onPressed) => FileSelectionButton onPressed(void Function(ControlState)? onPressed) =>
this(onPressed: onPressed); this(onPressed: onPressed);
@override @override
FileSelectionButton disabled(ValueNotifier<bool>? disabled) =>
this(disabled: disabled);
@override
FileSelectionButton themeResolver( FileSelectionButton themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) => ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver); this(themeResolver: themeResolver);
@ -67,7 +64,6 @@ class $FileSelectionButtonCWProxyImpl
ButtonStyle<dynamic>? selectedStyle, ButtonStyle<dynamic>? selectedStyle,
ButtonStyle<dynamic>? invalidStyle, ButtonStyle<dynamic>? invalidStyle,
void Function(ControlState)? onPressed, void Function(ControlState)? onPressed,
ValueNotifier<bool>? disabled,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}) => }) =>
@ -83,7 +79,6 @@ class $FileSelectionButtonCWProxyImpl
selectedStyle: selectedStyle ?? _value.selectedStyle, selectedStyle: selectedStyle ?? _value.selectedStyle,
invalidStyle: invalidStyle ?? _value.invalidStyle, invalidStyle: invalidStyle ?? _value.invalidStyle,
onPressed: onPressed ?? _value.onPressed, onPressed: onPressed ?? _value.onPressed,
disabled: disabled ?? _value.disabled,
mainAxisSize: mainAxisSize ?? _value.mainAxisSize, mainAxisSize: mainAxisSize ?? _value.mainAxisSize,
themeResolver: themeResolver ?? _value.themeResolver, themeResolver: themeResolver ?? _value.themeResolver,
key: key ?? _value.key, key: key ?? _value.key,

View File

@ -21,7 +21,6 @@ import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart'; import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/invalid_button_cubit.dart'; import 'package:wyatt_ui_kit/src/components/buttons/cubit/invalid_button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/state_listener.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/dotter_border_child.dart'; import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/dotter_border_child.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart'; import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart'; import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
@ -40,7 +39,6 @@ class FileSelectionButtonScreen
this.selectedStyle, this.selectedStyle,
this.invalidStyle, this.invalidStyle,
this.onPressed, this.onPressed,
this.disabled,
this.mainAxisSize, this.mainAxisSize,
this.themeResolver, this.themeResolver,
super.key, super.key,
@ -60,26 +58,11 @@ class FileSelectionButtonScreen
final FileSelectionButtonStyle? invalidStyle; final FileSelectionButtonStyle? invalidStyle;
final void Function(ControlState state)? onPressed; final void Function(ControlState state)? onPressed;
final ValueNotifier<bool>? disabled;
final FileSelectionButtonThemeResolver? themeResolver; final FileSelectionButtonThemeResolver? themeResolver;
@override @override
InvalidButtonCubit create(BuildContext context) => InvalidButtonCubit(); InvalidButtonCubit create(BuildContext context) => InvalidButtonCubit();
@override
InvalidButtonCubit init(BuildContext context, InvalidButtonCubit bloc) {
disabled?.addListener(
() => StateListener.listen<InvalidButtonCubit>(disabled, bloc),
);
/// Set the initial state depending on the disabled value
/// after adding the listener.
if (disabled?.value ?? false) {
bloc.disable();
}
return bloc;
}
/// Negotiate the theme to get a complete style. /// Negotiate the theme to get a complete style.
FileSelectionButtonStyle _resolve(BuildContext context, ButtonState state) { FileSelectionButtonStyle _resolve(BuildContext context, ButtonState state) {
final FileSelectionButtonThemeResolver resolver = themeResolver ?? final FileSelectionButtonThemeResolver resolver = themeResolver ??

View File

@ -17,6 +17,8 @@
import 'package:flutter/material.dart' hide ButtonStyle; import 'package:flutter/material.dart' hide ButtonStyle;
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/exportable_bloc.dart';
import 'package:wyatt_ui_kit/src/components/buttons/flat_button/flat_button_screen.dart'; import 'package:wyatt_ui_kit/src/components/buttons/flat_button/flat_button_screen.dart';
import 'package:wyatt_ui_kit/src/components/buttons/flat_button/flat_button_theme_resolver.dart'; import 'package:wyatt_ui_kit/src/components/buttons/flat_button/flat_button_theme_resolver.dart';
@ -24,7 +26,7 @@ part 'flat_button.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class FlatButton extends FlatButtonComponent with $FlatButtonCWMixin { class FlatButton extends FlatButtonComponent with $FlatButtonCWMixin {
const FlatButton({ FlatButton({
super.prefix, super.prefix,
super.suffix, super.suffix,
super.label, super.label,
@ -34,12 +36,15 @@ class FlatButton extends FlatButtonComponent with $FlatButtonCWMixin {
super.focusedStyle, super.focusedStyle,
super.tappedStyle, super.tappedStyle,
super.onPressed, super.onPressed,
super.disabled,
super.mainAxisSize, super.mainAxisSize,
super.themeResolver, super.themeResolver,
super.key, super.key,
}); });
final ButtonCubit _cubit = ButtonCubit();
ButtonCubit get bloc => _cubit;
@override @override
FlatButtonStyle? get disabledStyle => super.disabledStyle as FlatButtonStyle?; FlatButtonStyle? get disabledStyle => super.disabledStyle as FlatButtonStyle?;
@ -60,19 +65,21 @@ class FlatButton extends FlatButtonComponent with $FlatButtonCWMixin {
super.themeResolver as FlatButtonThemeResolver?; super.themeResolver as FlatButtonThemeResolver?;
@override @override
Widget build(BuildContext context) => FlatButtonScreen( Widget build(BuildContext context) => ExportableBloc(
prefix: prefix, bloc: _cubit,
suffix: suffix, child: FlatButtonScreen(
label: label, prefix: prefix,
disabledStyle: disabledStyle, suffix: suffix,
normalStyle: normalStyle, label: label,
hoveredStyle: hoveredStyle, disabledStyle: disabledStyle,
focusedStyle: focusedStyle, normalStyle: normalStyle,
tappedStyle: tappedStyle, hoveredStyle: hoveredStyle,
onPressed: onPressed, focusedStyle: focusedStyle,
disabled: disabled, tappedStyle: tappedStyle,
mainAxisSize: mainAxisSize, onPressed: onPressed,
themeResolver: themeResolver, mainAxisSize: mainAxisSize,
key: key, themeResolver: themeResolver,
key: key,
),
); );
} }

View File

@ -37,9 +37,6 @@ class $FlatButtonCWProxyImpl implements $FlatButtonComponentCWProxy {
FlatButton onPressed(void Function(ControlState)? onPressed) => FlatButton onPressed(void Function(ControlState)? onPressed) =>
this(onPressed: onPressed); this(onPressed: onPressed);
@override @override
FlatButton disabled(ValueNotifier<bool>? disabled) =>
this(disabled: disabled);
@override
FlatButton themeResolver( FlatButton themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) => ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver); this(themeResolver: themeResolver);
@ -57,7 +54,6 @@ class $FlatButtonCWProxyImpl implements $FlatButtonComponentCWProxy {
ButtonStyle<dynamic>? focusedStyle, ButtonStyle<dynamic>? focusedStyle,
ButtonStyle<dynamic>? tappedStyle, ButtonStyle<dynamic>? tappedStyle,
void Function(ControlState)? onPressed, void Function(ControlState)? onPressed,
ValueNotifier<bool>? disabled,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}) => }) =>
@ -71,7 +67,6 @@ class $FlatButtonCWProxyImpl implements $FlatButtonComponentCWProxy {
focusedStyle: focusedStyle ?? _value.focusedStyle, focusedStyle: focusedStyle ?? _value.focusedStyle,
tappedStyle: tappedStyle ?? _value.tappedStyle, tappedStyle: tappedStyle ?? _value.tappedStyle,
onPressed: onPressed ?? _value.onPressed, onPressed: onPressed ?? _value.onPressed,
disabled: disabled ?? _value.disabled,
mainAxisSize: mainAxisSize ?? _value.mainAxisSize, mainAxisSize: mainAxisSize ?? _value.mainAxisSize,
themeResolver: themeResolver ?? _value.themeResolver, themeResolver: themeResolver ?? _value.themeResolver,
key: key ?? _value.key, key: key ?? _value.key,

View File

@ -20,7 +20,6 @@ import 'package:gap/gap.dart';
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart'; import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/state_listener.dart';
import 'package:wyatt_ui_kit/src/components/buttons/flat_button/flat_button_theme_resolver.dart'; import 'package:wyatt_ui_kit/src/components/buttons/flat_button/flat_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart'; import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart'; import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
@ -36,7 +35,6 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
this.focusedStyle, this.focusedStyle,
this.tappedStyle, this.tappedStyle,
this.onPressed, this.onPressed,
this.disabled,
this.mainAxisSize, this.mainAxisSize,
this.themeResolver, this.themeResolver,
super.key, super.key,
@ -54,23 +52,11 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
final FlatButtonStyle? tappedStyle; final FlatButtonStyle? tappedStyle;
final void Function(ControlState state)? onPressed; final void Function(ControlState state)? onPressed;
final ValueNotifier<bool>? disabled;
final FlatButtonThemeResolver? themeResolver; final FlatButtonThemeResolver? themeResolver;
@override @override
ButtonCubit create(BuildContext context) => ButtonCubit(); ButtonCubit create(BuildContext context) => ButtonCubit();
@override
ButtonCubit init(BuildContext context, ButtonCubit bloc) {
disabled?.addListener(() => StateListener.listen(disabled, bloc));
/// Set the initial state depending on the disabled value
/// after adding the listener.
if (disabled?.value ?? false) {
bloc.disable();
}
return bloc;
}
/// Negotiate the theme to get a complete style. /// Negotiate the theme to get a complete style.
FlatButtonStyle _resolve(BuildContext context, ControlState state) { FlatButtonStyle _resolve(BuildContext context, ControlState state) {
final FlatButtonThemeResolver resolver = themeResolver ?? final FlatButtonThemeResolver resolver = themeResolver ??

View File

@ -17,6 +17,8 @@
import 'package:flutter/material.dart' hide ButtonStyle; import 'package:flutter/material.dart' hide ButtonStyle;
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/exportable_bloc.dart';
import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_button_theme_resolver.dart'; import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_screen.dart'; import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_screen.dart';
@ -25,7 +27,7 @@ part 'simple_icon_button.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class SimpleIconButton extends SimpleIconButtonComponent class SimpleIconButton extends SimpleIconButtonComponent
with $SimpleIconButtonCWMixin { with $SimpleIconButtonCWMixin {
const SimpleIconButton({ SimpleIconButton({
super.icon, super.icon,
super.disabledStyle, super.disabledStyle,
super.normalStyle, super.normalStyle,
@ -33,11 +35,14 @@ class SimpleIconButton extends SimpleIconButtonComponent
super.focusedStyle, super.focusedStyle,
super.tappedStyle, super.tappedStyle,
super.onPressed, super.onPressed,
super.disabled,
super.themeResolver, super.themeResolver,
super.key, super.key,
}); });
final ButtonCubit _cubit = ButtonCubit();
ButtonCubit get bloc => _cubit;
@override @override
SimpleIconButtonStyle? get disabledStyle => SimpleIconButtonStyle? get disabledStyle =>
super.disabledStyle as SimpleIconButtonStyle?; super.disabledStyle as SimpleIconButtonStyle?;
@ -63,16 +68,18 @@ class SimpleIconButton extends SimpleIconButtonComponent
super.themeResolver as SimpleIconButtonThemeResolver?; super.themeResolver as SimpleIconButtonThemeResolver?;
@override @override
Widget build(BuildContext context) => SimpleIconButtonScreen( Widget build(BuildContext context) => ExportableBloc(
icon: icon, bloc: _cubit,
disabledStyle: disabledStyle, child: SimpleIconButtonScreen(
normalStyle: normalStyle, icon: icon,
hoveredStyle: hoveredStyle, disabledStyle: disabledStyle,
focusedStyle: focusedStyle, normalStyle: normalStyle,
tappedStyle: tappedStyle, hoveredStyle: hoveredStyle,
onPressed: onPressed, focusedStyle: focusedStyle,
disabled: disabled, tappedStyle: tappedStyle,
themeResolver: themeResolver, onPressed: onPressed,
key: key, themeResolver: themeResolver,
key: key,
),
); );
} }

View File

@ -31,9 +31,6 @@ class $SimpleIconButtonCWProxyImpl
SimpleIconButton onPressed(void Function(ControlState)? onPressed) => SimpleIconButton onPressed(void Function(ControlState)? onPressed) =>
this(onPressed: onPressed); this(onPressed: onPressed);
@override @override
SimpleIconButton disabled(ValueNotifier<bool>? disabled) =>
this(disabled: disabled);
@override
SimpleIconButton themeResolver( SimpleIconButton themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) => ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver); this(themeResolver: themeResolver);
@ -48,7 +45,6 @@ class $SimpleIconButtonCWProxyImpl
ButtonStyle<dynamic>? focusedStyle, ButtonStyle<dynamic>? focusedStyle,
ButtonStyle<dynamic>? tappedStyle, ButtonStyle<dynamic>? tappedStyle,
void Function(ControlState)? onPressed, void Function(ControlState)? onPressed,
ValueNotifier<bool>? disabled,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}) => }) =>
@ -60,7 +56,6 @@ class $SimpleIconButtonCWProxyImpl
focusedStyle: focusedStyle ?? _value.focusedStyle, focusedStyle: focusedStyle ?? _value.focusedStyle,
tappedStyle: tappedStyle ?? _value.tappedStyle, tappedStyle: tappedStyle ?? _value.tappedStyle,
onPressed: onPressed ?? _value.onPressed, onPressed: onPressed ?? _value.onPressed,
disabled: disabled ?? _value.disabled,
themeResolver: themeResolver ?? _value.themeResolver, themeResolver: themeResolver ?? _value.themeResolver,
key: key ?? _value.key, key: key ?? _value.key,
); );

View File

@ -19,7 +19,6 @@ import 'package:flutter/services.dart';
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart'; import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/state_listener.dart';
import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_button_theme_resolver.dart'; import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart'; import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_icon.dart'; import 'package:wyatt_ui_kit/src/components/gradients/gradient_icon.dart';
@ -34,7 +33,6 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
this.focusedStyle, this.focusedStyle,
this.tappedStyle, this.tappedStyle,
this.onPressed, this.onPressed,
this.disabled,
this.themeResolver, this.themeResolver,
super.key, super.key,
}); });
@ -48,24 +46,11 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
final SimpleIconButtonStyle? tappedStyle; final SimpleIconButtonStyle? tappedStyle;
final void Function(ControlState state)? onPressed; final void Function(ControlState state)? onPressed;
final ValueNotifier<bool>? disabled;
final SimpleIconButtonThemeResolver? themeResolver; final SimpleIconButtonThemeResolver? themeResolver;
@override @override
ButtonCubit create(BuildContext context) => ButtonCubit(); ButtonCubit create(BuildContext context) => ButtonCubit();
@override
ButtonCubit init(BuildContext context, ButtonCubit bloc) {
disabled?.addListener(() => StateListener.listen(disabled, bloc));
/// Set the initial state depending on the disabled value
/// after adding the listener.
if (disabled?.value ?? false) {
bloc.disable();
}
return bloc;
}
/// Negotiate the theme to get a complete style. /// Negotiate the theme to get a complete style.
SimpleIconButtonStyle _resolve(BuildContext context, ControlState state) { SimpleIconButtonStyle _resolve(BuildContext context, ControlState state) {
final SimpleIconButtonThemeResolver resolver = themeResolver ?? final SimpleIconButtonThemeResolver resolver = themeResolver ??

View File

@ -17,14 +17,17 @@
import 'package:flutter/material.dart' hide ButtonStyle; import 'package:flutter/material.dart' hide ButtonStyle;
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/selectable_button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/exportable_bloc.dart';
import 'package:wyatt_ui_kit/src/components/buttons/symbol_button/symbol_button_screen.dart'; import 'package:wyatt_ui_kit/src/components/buttons/symbol_button/symbol_button_screen.dart';
import 'package:wyatt_ui_kit/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart'; import 'package:wyatt_ui_kit/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart';
part 'symbol_button.g.dart'; part 'symbol_button.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class SymbolButton extends SymbolButtonComponent with $SymbolButtonCWMixin { class SymbolButton extends SymbolButtonComponent
const SymbolButton({ with $SymbolButtonCWMixin{
SymbolButton({
super.icon, super.icon,
super.label, super.label,
super.disabledStyle, super.disabledStyle,
@ -36,10 +39,13 @@ class SymbolButton extends SymbolButtonComponent with $SymbolButtonCWMixin {
super.mainAxisSize, super.mainAxisSize,
super.themeResolver, super.themeResolver,
super.onPressed, super.onPressed,
super.disabled,
super.key, super.key,
}); });
final SelectableButtonCubit _cubit = SelectableButtonCubit();
SelectableButtonCubit get bloc => _cubit;
@override @override
SymbolButtonStyle? get disabledStyle => SymbolButtonStyle? get disabledStyle =>
super.disabledStyle as SymbolButtonStyle?; super.disabledStyle as SymbolButtonStyle?;
@ -67,19 +73,21 @@ class SymbolButton extends SymbolButtonComponent with $SymbolButtonCWMixin {
super.themeResolver as SymbolButtonThemeResolver?; super.themeResolver as SymbolButtonThemeResolver?;
@override @override
Widget build(BuildContext context) => SymbolButtonScreen( Widget build(BuildContext context) => ExportableBloc(
icon: icon, bloc: _cubit,
label: label, child: SymbolButtonScreen(
disabledStyle: disabledStyle, icon: icon,
normalStyle: normalStyle, label: label,
hoveredStyle: hoveredStyle, disabledStyle: disabledStyle,
focusedStyle: focusedStyle, normalStyle: normalStyle,
tappedStyle: tappedStyle, hoveredStyle: hoveredStyle,
selectedStyle: selectedStyle, focusedStyle: focusedStyle,
onPressed: onPressed, tappedStyle: tappedStyle,
disabled: disabled, selectedStyle: selectedStyle,
mainAxisSize: mainAxisSize, onPressed: onPressed,
themeResolver: themeResolver, mainAxisSize: mainAxisSize,
key: key, themeResolver: themeResolver,
key: key,
),
); );
} }

View File

@ -38,9 +38,6 @@ class $SymbolButtonCWProxyImpl implements $SymbolButtonComponentCWProxy {
SymbolButton onPressed(void Function(ControlState)? onPressed) => SymbolButton onPressed(void Function(ControlState)? onPressed) =>
this(onPressed: onPressed); this(onPressed: onPressed);
@override @override
SymbolButton disabled(ValueNotifier<bool>? disabled) =>
this(disabled: disabled);
@override
SymbolButton themeResolver( SymbolButton themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) => ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver); this(themeResolver: themeResolver);
@ -58,7 +55,6 @@ class $SymbolButtonCWProxyImpl implements $SymbolButtonComponentCWProxy {
ButtonStyle<dynamic>? tappedStyle, ButtonStyle<dynamic>? tappedStyle,
ButtonStyle<dynamic>? selectedStyle, ButtonStyle<dynamic>? selectedStyle,
void Function(ControlState)? onPressed, void Function(ControlState)? onPressed,
ValueNotifier<bool>? disabled,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}) => }) =>
@ -74,7 +70,6 @@ class $SymbolButtonCWProxyImpl implements $SymbolButtonComponentCWProxy {
mainAxisSize: mainAxisSize ?? _value.mainAxisSize, mainAxisSize: mainAxisSize ?? _value.mainAxisSize,
themeResolver: themeResolver ?? _value.themeResolver, themeResolver: themeResolver ?? _value.themeResolver,
onPressed: onPressed ?? _value.onPressed, onPressed: onPressed ?? _value.onPressed,
disabled: disabled ?? _value.disabled,
key: key ?? _value.key, key: key ?? _value.key,
); );
} }

View File

@ -21,7 +21,6 @@ import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart'; import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/selectable_button_cubit.dart'; import 'package:wyatt_ui_kit/src/components/buttons/cubit/selectable_button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/state_listener.dart';
import 'package:wyatt_ui_kit/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart'; import 'package:wyatt_ui_kit/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart'; import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart'; import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
@ -38,7 +37,6 @@ class SymbolButtonScreen
this.tappedStyle, this.tappedStyle,
this.selectedStyle, this.selectedStyle,
this.onPressed, this.onPressed,
this.disabled,
this.mainAxisSize, this.mainAxisSize,
this.themeResolver, this.themeResolver,
super.key, super.key,
@ -56,26 +54,11 @@ class SymbolButtonScreen
final SymbolButtonStyle? selectedStyle; final SymbolButtonStyle? selectedStyle;
final void Function(ControlState state)? onPressed; final void Function(ControlState state)? onPressed;
final ValueNotifier<bool>? disabled;
final SymbolButtonThemeResolver? themeResolver; final SymbolButtonThemeResolver? themeResolver;
@override @override
SelectableButtonCubit create(BuildContext context) => SelectableButtonCubit(); SelectableButtonCubit create(BuildContext context) => SelectableButtonCubit();
@override
SelectableButtonCubit init(BuildContext context, SelectableButtonCubit bloc) {
disabled?.addListener(
() => StateListener.listen<SelectableButtonCubit>(disabled, bloc),
);
/// Set the initial state depending on the disabled value
/// after adding the listener.
if (disabled?.value ?? false) {
bloc.disable();
}
return bloc;
}
/// Negotiate the theme to get a complete style. /// Negotiate the theme to get a complete style.
SymbolButtonStyle _resolve(BuildContext context, ButtonState state) { SymbolButtonStyle _resolve(BuildContext context, ButtonState state) {
final SymbolButtonThemeResolver resolver = themeResolver ?? final SymbolButtonThemeResolver resolver = themeResolver ??

View File

@ -20,6 +20,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_animate/flutter_animate.dart';
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/loader/loader_theme_resolver.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
part 'loader.g.dart'; part 'loader.g.dart';
@ -32,11 +33,30 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
super.stroke, super.stroke,
super.duration, super.duration,
super.flip, super.flip,
super.themeResolver,
super.key, super.key,
}); });
@override
LoaderThemeResolver? get themeResolver =>
super.themeResolver as LoaderThemeResolver?;
/// Negotiate the theme to get a complete style.
LoaderStyle _resolve(BuildContext context) {
final LoaderThemeResolver resolver = themeResolver ??
LoaderThemeResolver(
customStyleFn: (context, {extra}) => LoaderStyle(
colors: colors,
stroke: stroke,
),
);
return resolver.negotiate(context);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final style = _resolve(context);
final dimension = final dimension =
(radius != null) ? radius! * 2 : context.buttonTheme.height; (radius != null) ? radius! * 2 : context.buttonTheme.height;
return SizedBox.square( return SizedBox.square(
@ -44,34 +64,9 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
child: RepaintBoundary( child: RepaintBoundary(
child: CustomPaint( child: CustomPaint(
painter: _LoaderPainter( painter: _LoaderPainter(
ThemeHelper.getThemeElement<MultiColor, MultiColor>( style.colors ?? const MultiColor([]),
[
colors,
Theme.of(context).extension<LoaderThemeExtension>()?.colors,
MultiColor([
Theme.of(context).progressIndicatorTheme.color ??
context.colorScheme.primary,
context.colorScheme.onPrimary,
]),
/// This is the default value. So the final
/// value cannot be null.
const MultiColor([])
],
valueValidator: (multiColor) =>
multiColor != null && multiColor.isColor,
transform: (multiColor) => multiColor,
)!,
dimension / 2, dimension / 2,
ThemeHelper.getThemeElement<double, double>( style.stroke ?? 4,
[
stroke,
Theme.of(context).extension<LoaderThemeExtension>()?.stroke,
4,
],
valueValidator: (stroke) => stroke != null,
transform: (stroke) => stroke,
)!,
flip: flip ?? false, flip: flip ?? false,
), ),
) )

View File

@ -41,6 +41,7 @@ class $LoaderCWProxyImpl implements $LoaderComponentCWProxy {
stroke: stroke ?? _value.stroke, stroke: stroke ?? _value.stroke,
duration: duration ?? _value.duration, duration: duration ?? _value.duration,
flip: flip ?? _value.flip, flip: flip ?? _value.flip,
themeResolver: themeResolver ?? _value.themeResolver,
key: key ?? _value.key, key: key ?? _value.key,
); );
} }

View File

@ -0,0 +1,58 @@
// 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_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class LoaderThemeResolver
extends ThemeResolver<LoaderStyle, LoaderThemeExtension, void> {
const LoaderThemeResolver({
required this.customStyleFn,
});
@override
final LoaderStyle? Function(
BuildContext context, {
void extra,
}) customStyleFn;
/// Values taken from <https://api.flutter.dev/flutter/material/ElevatedButton/defaultStyleOf.html>
@override
LoaderStyle computeDefaultValue(
BuildContext context, {
void extra,
}) =>
LoaderStyle(
colors: MultiColor([
Theme.of(context).progressIndicatorTheme.color ??
context.colorScheme.primary,
context.colorScheme.onPrimary,
]),
stroke: 4,
);
@override
LoaderStyle? computeExtensionValueFn(
BuildContext context,
LoaderThemeExtension? themeExtension, {
void extra,
}) =>
LoaderStyle(
colors: themeExtension?.colors,
stroke: themeExtension?.stroke,
);
}

View File

@ -17,6 +17,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/rich_text_builder/rich_text_builder_theme_resolver.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
part 'rich_text_builder.g.dart'; part 'rich_text_builder.g.dart';
@ -29,39 +30,37 @@ class RichTextBuilder extends RichTextBuilderComponent
super.parser, super.parser,
super.defaultStyle, super.defaultStyle,
super.styles, super.styles,
super.themeResolver,
super.key, super.key,
}); });
@override
RichTextBuilderThemeResolver? get themeResolver =>
super.themeResolver as RichTextBuilderThemeResolver?;
/// Negotiate the theme to get a complete style.
RichTextBuilderStyle _resolve(BuildContext context) {
final RichTextBuilderThemeResolver resolver = themeResolver ??
RichTextBuilderThemeResolver(
customStyleFn: (context, {extra}) => RichTextBuilderStyle(
defaultStyle: defaultStyle,
styles: styles,
),
);
return resolver.negotiate(context);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final style = _resolve(context);
final RegExp regex = RegExp(r'<(.*?)>(.*?)<\/\1>'); final RegExp regex = RegExp(r'<(.*?)>(.*?)<\/\1>');
final root = RichTextNode.from( final root = RichTextNode.from(
text ?? '', text ?? '',
regex, regex,
RichTextStyleParameter( RichTextStyleParameter(
ThemeHelper.getThemeElement<TextStyle, TextStyle>( style.defaultStyle,
[ style.styles ?? {},
defaultStyle,
Theme.of(context)
.extension<RichTextBuilderThemeExtension>()
?.defaultStyle,
context.textTheme.bodyMedium,
],
valueValidator: (style) => style != null,
transform: (style) => style,
),
ThemeHelper.getThemeElement<Map<String, TextStyle>,
Map<String, TextStyle>>(
[
styles,
Theme.of(context)
.extension<RichTextBuilderThemeExtension>()
?.styles,
const <String, TextStyle>{},
],
valueValidator: (styles) => styles != null,
transform: (styles) => styles,
)!,
null, null,
), ),
); );

View File

@ -20,6 +20,10 @@ class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy {
RichTextBuilder styles(Map<String, TextStyle>? styles) => RichTextBuilder styles(Map<String, TextStyle>? styles) =>
this(styles: styles); this(styles: styles);
@override @override
RichTextBuilder themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver);
@override
RichTextBuilder key(Key? key) => this(key: key); RichTextBuilder key(Key? key) => this(key: key);
@override @override
RichTextBuilder call({ RichTextBuilder call({
@ -27,6 +31,7 @@ class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy {
RichTextParser? parser, RichTextParser? parser,
TextStyle? defaultStyle, TextStyle? defaultStyle,
Map<String, TextStyle>? styles, Map<String, TextStyle>? styles,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key, Key? key,
}) => }) =>
RichTextBuilder( RichTextBuilder(
@ -34,6 +39,7 @@ class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy {
parser: parser ?? _value.parser, parser: parser ?? _value.parser,
defaultStyle: defaultStyle ?? _value.defaultStyle, defaultStyle: defaultStyle ?? _value.defaultStyle,
styles: styles ?? _value.styles, styles: styles ?? _value.styles,
themeResolver: themeResolver ?? _value.themeResolver,
key: key ?? _value.key, key: key ?? _value.key,
); );
} }

View File

@ -0,0 +1,53 @@
// 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_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class RichTextBuilderThemeResolver extends ThemeResolver<RichTextBuilderStyle,
RichTextBuilderThemeExtension, void> {
const RichTextBuilderThemeResolver({
required this.customStyleFn,
});
/// Values taken from <https://api.flutter.dev/flutter/material/ElevatedButton/defaultStyleOf.html>
@override
RichTextBuilderStyle computeDefaultValue(
BuildContext context, {
void extra,
}) =>
RichTextBuilderStyle(
defaultStyle: context.textTheme.bodyMedium,
);
@override
final RichTextBuilderStyle? Function(
BuildContext context, {
void extra,
}) customStyleFn;
@override
RichTextBuilderStyle? computeExtensionValueFn(
BuildContext context,
RichTextBuilderThemeExtension? themeExtension, {
void extra,
}) =>
RichTextBuilderStyle(
defaultStyle: themeExtension?.defaultStyle,
styles: themeExtension?.styles,
);
}

View File

@ -5,7 +5,7 @@ import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'custom_app_bar.g.dart'; part 'custom_app_bar.g.dart';
@ComponentCopyWithExtension() @ComponentCopyWithExtension()
class CustomAppBar extends TopAppBarComponent with $CustomAppBarCWMixin { class CustomAppBar extends AppBarComponent with $CustomAppBarCWMixin {
const CustomAppBar({ const CustomAppBar({
super.title, super.title,
super.key, super.key,
@ -13,6 +13,6 @@ class CustomAppBar extends TopAppBarComponent with $CustomAppBarCWMixin {
@override @override
Widget build(BuildContext context) => AppBar( Widget build(BuildContext context) => AppBar(
title: Text(title?.data ?? ''), title: Text(title?.text ?? ''),
); );
} }

View File

@ -6,85 +6,22 @@ part of 'custom_app_bar.dart';
// ComponentCopyWithGenerator // ComponentCopyWithGenerator
// ************************************************************************** // **************************************************************************
class $CustomAppBarCWProxyImpl implements $TopAppBarComponentCWProxy { class $CustomAppBarCWProxyImpl implements $AppBarComponentCWProxy {
const $CustomAppBarCWProxyImpl(this._value); const $CustomAppBarCWProxyImpl(this._value);
final CustomAppBar _value; final CustomAppBar _value;
@override @override
CustomAppBar title(TextWrapper? title) => this(title: title); CustomAppBar title(String? title) => this(title: title);
@override
CustomAppBar centerTitle(bool? centerTitle) => this(centerTitle: centerTitle);
@override
CustomAppBar shape(ShapeBorder? shape) => this(shape: shape);
@override
CustomAppBar systemOverlayStyle(SystemUiOverlayStyle? systemOverlayStyle) =>
this(systemOverlayStyle: systemOverlayStyle);
@override
CustomAppBar automaticallyImplyLeading(bool? automaticallyImplyLeading) =>
this(automaticallyImplyLeading: automaticallyImplyLeading);
@override
CustomAppBar flexibleSpace(Widget? flexibleSpace) =>
this(flexibleSpace: flexibleSpace);
@override
CustomAppBar bottom(PreferredSizeWidget? bottom) => this(bottom: bottom);
@override
CustomAppBar elevation(double? elevation) => this(elevation: elevation);
@override
CustomAppBar scrolledUnderElevation(double? scrolledUnderElevation) =>
this(scrolledUnderElevation: scrolledUnderElevation);
@override
CustomAppBar shadowColor(Color? shadowColor) =>
this(shadowColor: shadowColor);
@override
CustomAppBar surfaceTintColor(Color? surfaceTintColor) =>
this(surfaceTintColor: surfaceTintColor);
@override
CustomAppBar backgroundColor(MultiColor? backgroundColor) =>
this(backgroundColor: backgroundColor);
@override
CustomAppBar iconTheme(IconThemeData? iconTheme) =>
this(iconTheme: iconTheme);
@override
CustomAppBar primary(bool? primary) => this(primary: primary);
@override
CustomAppBar excludeHeaderSemantics(bool? excludeHeaderSemantics) =>
this(excludeHeaderSemantics: excludeHeaderSemantics);
@override
CustomAppBar toolbarHeight(double? toolbarHeight) =>
this(toolbarHeight: toolbarHeight);
@override
CustomAppBar leadingWidth(double? leadingWidth) =>
this(leadingWidth: leadingWidth);
@override @override
CustomAppBar leading(Widget? leading) => this(leading: leading); CustomAppBar leading(Widget? leading) => this(leading: leading);
@override @override
CustomAppBar actions(List<Widget>? actions) => this(actions: actions); CustomAppBar actions(List<Widget>? actions) => this(actions: actions);
@override @override
CustomAppBar expandedWidget(List<Widget>? expandedWidget) =>
this(expandedWidget: expandedWidget);
@override
CustomAppBar key(Key? key) => this(key: key); CustomAppBar key(Key? key) => this(key: key);
@override @override
CustomAppBar call({ CustomAppBar call({
TextWrapper? title, String? title,
bool? centerTitle,
ShapeBorder? shape,
SystemUiOverlayStyle? systemOverlayStyle,
bool? automaticallyImplyLeading,
Widget? flexibleSpace,
PreferredSizeWidget? bottom,
double? elevation,
double? scrolledUnderElevation,
Color? shadowColor,
Color? surfaceTintColor,
MultiColor? backgroundColor,
IconThemeData? iconTheme,
bool? primary,
bool? excludeHeaderSemantics,
double? toolbarHeight,
double? leadingWidth,
Widget? leading, Widget? leading,
List<Widget>? actions, List<Widget>? actions,
List<Widget>? expandedWidget,
Key? key, Key? key,
}) => }) =>
CustomAppBar( CustomAppBar(
@ -94,6 +31,6 @@ class $CustomAppBarCWProxyImpl implements $TopAppBarComponentCWProxy {
} }
mixin $CustomAppBarCWMixin on Component { mixin $CustomAppBarCWMixin on Component {
$TopAppBarComponentCWProxy get copyWith => $AppBarComponentCWProxy get copyWith =>
$CustomAppBarCWProxyImpl(this as CustomAppBar); $CustomAppBarCWProxyImpl(this as CustomAppBar);
} }