Compare commits

..

7 Commits

69 changed files with 1326 additions and 754 deletions

View File

@ -0,0 +1 @@
2.4.1

View File

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

View File

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

View File

@ -20,10 +20,18 @@
![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.0.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.1.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).
## 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
To use the lints, add a dependency in your `pubspec.yaml` :
@ -31,7 +39,7 @@ To use the lints, add a dependency in your `pubspec.yaml` :
```yaml
wyatt_analysis:
hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
version: 2.4.0
version: 2.4.1
```
Then, add an include in `analysis_options.yaml` :
@ -49,13 +57,13 @@ include: package:wyatt_analysis/analysis_options.flutter.yaml
If you wish to restrict the lint version, specify a version of `analysis_options.yaml` instead:
```yaml
include: package:wyatt_analysis/analysis_options.flutter.2.4.0.yaml
include: package:wyatt_analysis/analysis_options.flutter.2.4.1.yaml
```
If you just want **Dart** version:
```yaml
include: package:wyatt_analysis/analysis_options.2.4.0.yaml
include: package:wyatt_analysis/analysis_options.2.4.1.yaml
```
## Suppressing Lints
@ -109,10 +117,11 @@ 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:
```sh
./new_version.sh <previous_version> <new_version>
./new_version.sh <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

View File

@ -0,0 +1,217 @@
# Copyright (C) 2023 WYATT GROUP
# Please see the AUTHORS file for details.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
errors:
todo: ignore
close_sinks: ignore
missing_required_param: error
missing_return: error
exclude:
- lib/l10n/**
- lib/generated/**
- lib/gen/**
- lib/generated_plugin_registrant.dart
- test/.test_coverage.dart
- "**/*.g.dart"
- "**/*.freezed.dart"
linter:
rules:
- always_declare_return_types
- always_put_control_body_on_new_line
- always_put_required_named_parameters_first
- always_require_non_null_named_parameters
- always_use_package_imports
- annotate_overrides
- avoid_bool_literals_in_conditional_expressions
- avoid_catching_errors
- avoid_double_and_int_checks
- avoid_dynamic_calls
- avoid_empty_else
- avoid_equals_and_hash_code_on_mutable_classes
- avoid_escaping_inner_quotes
- avoid_field_initializers_in_const_classes
- avoid_final_parameters
- avoid_function_literals_in_foreach_calls
- avoid_init_to_null
- avoid_js_rounded_ints
- avoid_multiple_declarations_per_line
- avoid_null_checks_in_equality_operators
- avoid_positional_boolean_parameters
- avoid_private_typedef_functions
- avoid_redundant_argument_values
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_null_for_future
- avoid_returning_null_for_void
- avoid_returning_this
- avoid_setters_without_getters
- avoid_shadowing_type_parameters
- avoid_single_cascade_in_expression_statements
- avoid_slow_async_io
- avoid_type_to_string
- avoid_types_as_parameter_names
- avoid_types_on_closure_parameters
- avoid_unused_constructor_parameters
- avoid_void_async
- await_only_futures
- camel_case_extensions
- camel_case_types
- cancel_subscriptions
- cascade_invocations
- cast_nullable_to_non_nullable
- collection_methods_unrelated_type
- combinators_ordering
- comment_references
- conditional_uri_does_not_exist
- constant_identifier_names
- control_flow_in_finally
- curly_braces_in_flow_control_structures
- depend_on_referenced_packages
- deprecated_consistency
- directives_ordering
- empty_catches
- empty_constructor_bodies
- empty_statements
- eol_at_end_of_file
- exhaustive_cases
- file_names
- flutter_style_todos
- hash_and_equals
- implementation_imports
- implicit_call_tearoffs
- iterable_contains_unrelated_type
- join_return_with_assignment
- leading_newlines_in_multiline_strings
- library_names
- library_prefixes
- library_private_types_in_public_api
- lines_longer_than_80_chars
- list_remove_unrelated_type
- literal_only_boolean_expressions
- missing_whitespace_between_adjacent_strings
- no_adjacent_strings_in_list
- no_default_cases
- no_duplicate_case_values
- no_leading_underscores_for_library_prefixes
- no_leading_underscores_for_local_identifiers
- no_runtimeType_toString
- non_constant_identifier_names
- noop_primitive_operations
- null_check_on_nullable_type_parameter
- null_closures
- one_member_abstracts
- only_throw_errors
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
- parameter_assignments
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_asserts_with_message
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_constructors_over_static_methods
- prefer_contains
- prefer_equal_for_default_values
- prefer_expression_function_bodies
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
- prefer_for_elements_to_map_fromIterable
- prefer_function_declarations_over_variables
- prefer_generic_function_type_aliases
- prefer_if_elements_to_conditional_expressions
- prefer_if_null_operators
- prefer_initializing_formals
- prefer_inlined_adds
- prefer_int_literals
- prefer_interpolation_to_compose_strings
- prefer_is_empty
- prefer_is_not_empty
- prefer_is_not_operator
- prefer_iterable_whereType
- prefer_mixin
- prefer_null_aware_method_calls
- prefer_null_aware_operators
- prefer_single_quotes
- prefer_spread_collections
- prefer_typing_uninitialized_variables
- prefer_void_to_null
- provide_deprecation_message
- recursive_getters
- require_trailing_commas
- slash_for_doc_comments
- sort_constructors_first
- sort_unnamed_constructors_first
- test_types_in_equals
- throw_in_finally
- tighten_type_of_initializing_formals
- type_annotate_public_apis
- type_init_formals
- unawaited_futures
- unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- unnecessary_const
- unnecessary_constructor_name
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_late
- unnecessary_new
- unnecessary_null_aware_assignments
- unnecessary_null_checks
- unnecessary_null_in_if_null_operators
- unnecessary_nullable_for_final_variable_declarations
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_raw_strings
- unnecessary_statements
- unnecessary_string_escapes
- unnecessary_string_interpolations
- unnecessary_this
- unnecessary_to_list_in_spreads
- unrelated_type_equality_checks
- unsafe_html
- use_enums
- use_function_type_syntax_for_parameters
- use_if_null_to_convert_nulls_to_bools
- use_is_even_rather_than_modulo
- use_late_for_private_fields_and_variables
- use_named_constants
- use_raw_strings
- use_rethrow_when_possible
- use_setters_to_change_properties
- use_string_buffers
- use_string_in_part_of_directives
- use_super_parameters
- use_test_throws_matchers
- use_to_and_as_if_applicable
- valid_regexps
- void_checks

View File

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

View File

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

View File

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

View File

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

View File

@ -1,16 +1,16 @@
# 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/>.
@ -22,4 +22,4 @@ version: 2.4.0
publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub
environment:
sdk: '>=2.12.0 <3.0.0'
sdk: ">=2.12.0 <3.0.0"

View File

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

View File

@ -6,22 +6,85 @@ part of 'custom_app_bar.dart';
// ComponentCopyWithGenerator
// **************************************************************************
class $CustomAppBarCWProxyImpl implements $AppBarComponentCWProxy {
class $CustomAppBarCWProxyImpl implements $TopAppBarComponentCWProxy {
const $CustomAppBarCWProxyImpl(this._value);
final CustomAppBar _value;
@override
CustomAppBar title(TextWrapper? 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
CustomAppBar leading(Widget? leading) => this(leading: leading);
@override
CustomAppBar actions(List<Widget>? actions) => this(actions: actions);
@override
CustomAppBar expandedWidget(List<Widget>? expandedWidget) =>
this(expandedWidget: expandedWidget);
@override
CustomAppBar key(Key? key) => this(key: key);
@override
CustomAppBar 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,
}) =>
CustomAppBar(
@ -30,6 +93,6 @@ class $CustomAppBarCWProxyImpl implements $AppBarComponentCWProxy {
}
mixin $CustomAppBarCWMixin on Component {
$AppBarComponentCWProxy get copyWith =>
$TopAppBarComponentCWProxy get copyWith =>
$CustomAppBarCWProxyImpl(this as CustomAppBar);
}

View File

@ -12,6 +12,6 @@ class CustomErrorWidget extends ErrorWidgetComponent
@override
Widget build(BuildContext context) => ColoredBox(
color: Colors.red,
child: Center(child: Text(error?.text ?? 'Error')),
child: Center(child: Text(error?.data ?? 'Error')),
);
}

View File

@ -1,36 +0,0 @@
// 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

@ -15,18 +15,19 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
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_ui_components/wyatt_wyatt_ui_components.dart';
part 'custom_app_bar_example.g.dart';
part 'custom_top_bar_example.g.dart';
@ComponentCopyWithExtension()
class CustomAppBarExample extends AppBarComponent
with $CustomAppBarExampleCWMixin {
const CustomAppBarExample({super.title, super.key});
class CustomTopAppBarExample extends TopAppBarComponent
with $CustomTopAppBarExampleCWMixin {
const CustomTopAppBarExample({super.title, super.key});
@override
Widget build(BuildContext context) => AppBar(
title: Text(super.title?.text ?? ''),
title: Text(super.title?.data ?? ''),
);
}

View File

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

View File

@ -15,4 +15,5 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
export './control_state.dart';
export './extra_state.dart';
export './status_state.dart';

View File

@ -0,0 +1,35 @@
// 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,6 +14,7 @@
// 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_components/wyatt_wyatt_ui_components.dart';
abstract class ButtonComponent extends Component {
@ -26,6 +27,7 @@ abstract class ButtonComponent extends Component {
this.selectedStyle,
this.invalidStyle,
this.onPressed,
this.disabled,
super.themeResolver,
super.key,
});
@ -51,6 +53,12 @@ abstract class ButtonComponent extends Component {
/// Style of this button in invalid state
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;
/// Current state of this button
final ValueNotifier<bool>? disabled;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,8 +19,7 @@ export './buttons/buttons.dart';
export './cards/cards.dart';
export './component.dart';
export './error_widget_component.dart';
export './loader_component.dart';
export './loader_style.dart';
export './loader/loader.dart';
export './loading_widget_component.dart';
export './rich_text_builder/rich_text_builder.dart';
export './text_inputs/text_inputs.dart';

View File

@ -14,23 +14,4 @@
// 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: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,
);
}
export './loader_component.dart';

View File

@ -1,82 +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 '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,4 +16,3 @@
export 'parser.dart';
export 'rich_text_builder_component.dart';
export 'rich_text_builder_style.dart';

View File

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

View File

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

View File

@ -1,79 +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/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,14 +15,23 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.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_example/theme/constants.dart';
class FileSelectionButtons extends StatelessWidget {
class FileSelectionButtons extends StatefulWidget {
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(
decoration: BoxDecoration(
color: Constants.grey2,
@ -48,6 +57,7 @@ class FileSelectionButtons extends StatelessWidget {
style: Theme.of(context).textTheme.titleMedium,
),
const Gap(20),
// Default
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
@ -56,65 +66,99 @@ class FileSelectionButtons extends StatelessWidget {
subTitle: const TextWrapper('Taille max: 20 Mo'),
),
const Gap(20),
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Enabled',
BlocProvider(
create: (context) => InvalidButtonCubit()..freeze(),
child: FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Enabled',
),
subTitle: const TextWrapper('Subtitle'),
),
subTitle: const TextWrapper('Subtitle'),
)
..bloc.enable()
..bloc.freeze(),
),
const Gap(20),
// Using a ValueNotifier to disable the button
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Disabled',
),
subTitle: const TextWrapper('Subtitle'),
)
..bloc.disable()
..bloc.freeze(),
disabled: _disabled,
),
const Gap(20),
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Hovered',
BlocProvider(
create: (context) => InvalidButtonCubit()..hover(),
child: FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Hovered',
),
subTitle: const TextWrapper('Subtitle'),
),
subTitle: const TextWrapper('Subtitle'),
)
..bloc.onMouseEnter()
..bloc.freeze(),
),
const Gap(20),
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Focused',
BlocProvider(
create: (context) => InvalidButtonCubit()..focus(),
child: FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Focused',
),
subTitle: const TextWrapper('Subtitle'),
),
subTitle: const TextWrapper('Subtitle'),
)
..bloc.onFocus()
..bloc.freeze(),
),
const Gap(20),
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Tapped',
BlocProvider(
create: (context) => InvalidButtonCubit()..tap(),
child: FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Tapped',
),
subTitle: const TextWrapper('Subtitle'),
),
subTitle: const TextWrapper('Subtitle'),
)
..bloc.onClickDown()
..bloc.freeze(),
),
const Gap(20),
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Invalid',
BlocProvider(
create: (context) => InvalidButtonCubit()..invalidate(),
child: FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Invalid',
),
subTitle: const TextWrapper('Subtitle'),
),
subTitle: const TextWrapper('Subtitle'),
)
..bloc.invalidate()
..bloc.freeze(),
),
const Gap(20),
// Dynamic, disabled with ValueNotifier and invalid with BlocProvider.
// Keep the state when the button is disabled.
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),
],
);

View File

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

View File

@ -15,12 +15,21 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class SimpleIconButtons extends StatelessWidget {
class SimpleIconButtons extends StatefulWidget {
const SimpleIconButtons({super.key});
@override
State<SimpleIconButtons> createState() => _SimpleIconButtonsState();
}
class _SimpleIconButtonsState extends State<SimpleIconButtons> {
final _disabled = ValueNotifier(true);
final _dynamic = ValueNotifier(false);
@override
Widget build(BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -30,8 +39,9 @@ class SimpleIconButtons extends StatelessWidget {
style: Theme.of(context).textTheme.titleMedium,
),
const Gap(20),
SimpleIconButton(
icon: const Icon(
// Default
const SimpleIconButton(
icon: Icon(
Icons.storm_outlined,
size: 17,
),
@ -42,71 +52,101 @@ class SimpleIconButtons extends StatelessWidget {
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
SimpleIconButton(
icon: const Icon(
Icons.storm_outlined,
size: 17,
BlocProvider(
create: (context) => ButtonCubit()..freeze(),
child: const SimpleIconButton(
icon: Icon(
Icons.storm_outlined,
size: 17,
),
),
)
..bloc.enable()
..bloc.freeze(),
),
const Gap(20),
Text(
'Disabled',
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
// Disabled using ValueNotifier
SimpleIconButton(
icon: const Icon(
Icons.storm_outlined,
size: 17,
),
)
..bloc.disable()
..bloc.freeze(),
disabled: _disabled,
),
const Gap(20),
Text(
'Hovered',
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
SimpleIconButton(
icon: const Icon(
Icons.storm_outlined,
size: 17,
BlocProvider(
create: (context) => ButtonCubit()..hover(),
child: const SimpleIconButton(
icon: Icon(
Icons.storm_outlined,
size: 17,
),
),
)
..bloc.onMouseEnter()
..bloc.freeze(),
),
const Gap(20),
Text(
'Focused',
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
SimpleIconButton(
icon: const Icon(
Icons.storm_outlined,
size: 17,
BlocProvider(
create: (context) => ButtonCubit()..focus(),
child: const SimpleIconButton(
icon: Icon(
Icons.storm_outlined,
size: 17,
),
),
)
..bloc.onFocus()
..bloc.freeze(),
),
const Gap(20),
Text(
'Tapped',
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
SimpleIconButton(
icon: const Icon(
Icons.storm_outlined,
size: 17,
BlocProvider(
create: (context) => ButtonCubit()..tap(),
child: const SimpleIconButton(
icon: Icon(
Icons.storm_outlined,
size: 17,
),
),
)
..bloc.onClickDown()
..bloc.freeze(),
),
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,14 +15,23 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.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_example/theme/constants.dart';
class SymbolButtons extends StatelessWidget {
class SymbolButtons extends StatefulWidget {
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(
Icons.android,
size: 25,
@ -45,47 +54,70 @@ class SymbolButtons extends StatelessWidget {
icon: _icon(context),
),
const Gap(20),
SymbolButton(
label: const TextWrapper('Enabled'),
icon: _icon(context),
)
..bloc.enable()
..bloc.freeze(),
BlocProvider(
create: (context) => SelectableButtonCubit()..freeze(),
child: SymbolButton(
label: const TextWrapper('Enabled'),
icon: _icon(context),
),
),
const Gap(20),
// Disabled
SymbolButton(
label: const TextWrapper('Disabled'),
icon: _icon(context),
)
..bloc.disable()
..bloc.freeze(),
disabled: _disabled,
),
const Gap(20),
SymbolButton(
label: const TextWrapper('Hovered'),
icon: _icon(context),
)
..bloc.onMouseEnter()
..bloc.freeze(),
BlocProvider(
create: (context) => SelectableButtonCubit()..hover(),
child: SymbolButton(
label: const TextWrapper('Hovered'),
icon: _icon(context),
),
),
const Gap(20),
SymbolButton(
label: const TextWrapper('Focused'),
icon: _icon(context),
)
..bloc.onFocus()
..bloc.freeze(),
BlocProvider(
create: (context) => SelectableButtonCubit()..focus(),
child: SymbolButton(
label: const TextWrapper('Focused'),
icon: _icon(context),
),
),
const Gap(20),
SymbolButton(
label: const TextWrapper('Tapped'),
icon: _icon(context),
)
..bloc.onClickDown()
..bloc.freeze(),
BlocProvider(
create: (context) => SelectableButtonCubit()..tap(),
child: SymbolButton(
label: const TextWrapper('Tapped'),
icon: _icon(context),
),
),
const Gap(20),
SymbolButton(
label: const TextWrapper('Selected'),
icon: _icon(context),
)
..bloc.select()
..bloc.freeze(),
BlocProvider(
create: (context) => SelectableButtonCubit()..select(),
child: SymbolButton(
label: const TextWrapper('Selected'),
icon: _icon(context),
),
),
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),
DecoratedBox(
decoration: BoxDecoration(

View File

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

View File

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

View File

@ -23,8 +23,19 @@ import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'button_state.dart';
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 {
if (state.isDisabled || state.isFreezed) {
return;
@ -32,6 +43,10 @@ class ButtonCubit extends Cubit<ButtonState> {
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 {
if (state.isDisabled || state.isFreezed) {
return;
@ -40,6 +55,10 @@ class ButtonCubit extends Cubit<ButtonState> {
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 {
if (state.isDisabled || state.isFreezed) {
return;
@ -47,6 +66,10 @@ class ButtonCubit extends Cubit<ButtonState> {
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 {
if (state.isDisabled || state.isFreezed) {
return;
@ -54,6 +77,10 @@ class ButtonCubit extends Cubit<ButtonState> {
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 {
if (state.isDisabled || state.isFreezed) {
return;
@ -61,39 +88,127 @@ class ButtonCubit extends Cubit<ButtonState> {
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 {
if (state.isDisabled) {
if (state.isDisabled || state.isFreezed) {
return;
}
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 {
if (state.isDisabled) {
if (state.isDisabled || state.isFreezed) {
return;
}
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 {
if (state.isFreezed) {
return;
}
emit(state.copyWith(state: ControlState.disabled));
/// Save the previous state.
/// 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 (state.isFreezed) {
if (_previousState == null) {
return;
}
emit(state.copyWith(state: ControlState.normal));
emit(_previousState!);
_previousState = null;
}
/// Set the button to hovered state and freeze it.
///
/// Use this method to programmatically set the button to hovered state.
FutureOr<void> hover() async {
emit(
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 {
emit(state.copyWith(freezed: true));
emit(
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 {
emit(state.copyWith(freezed: false));
emit(
state.copyWith(
extraStates: state.extraStates
.where((element) => element != ExtraState.freezed)
.toList(),
),
);
}
}

View File

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

View File

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

View File

@ -20,14 +20,32 @@ import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
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
FutureOr<void> onClickUpIn() async {
if (state.isDisabled || state.isFreezed) {
return;
}
emit(
state.copyWith(state: ControlState.hovered, selected: !state.selected),
);
emit(_toggle(state).copyWith(state: ControlState.hovered));
}
@override
@ -35,26 +53,31 @@ class SelectableButtonCubit extends ButtonCubit {
if (state.isDisabled || state.isFreezed) {
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 {
if (state.isDisabled || state.isFreezed) {
return;
}
emit(
state.copyWith(selected: true),
state.copyWith(extraStates: state.extraStates + [ExtraState.selected]),
);
}
/// 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 {
if (state.isDisabled || state.isFreezed) {
return;
}
emit(
state.copyWith(selected: false),
state.copyWith(
extraStates: state.extraStates
.where((element) => element != ExtraState.selected)
.toList(),
),
);
}
}

View File

@ -0,0 +1,35 @@
// 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

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

View File

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

View File

@ -21,6 +21,7 @@ import 'package:wyatt_bloc_helper/wyatt_bloc_helper.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/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/file_selection_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
@ -39,6 +40,7 @@ class FileSelectionButtonScreen
this.selectedStyle,
this.invalidStyle,
this.onPressed,
this.disabled,
this.mainAxisSize,
this.themeResolver,
super.key,
@ -58,11 +60,26 @@ class FileSelectionButtonScreen
final FileSelectionButtonStyle? invalidStyle;
final void Function(ControlState state)? onPressed;
final ValueNotifier<bool>? disabled;
final FileSelectionButtonThemeResolver? themeResolver;
@override
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.
FileSelectionButtonStyle _resolve(BuildContext context, ButtonState state) {
final FileSelectionButtonThemeResolver resolver = themeResolver ??

View File

@ -17,8 +17,6 @@
import 'package:flutter/material.dart' hide ButtonStyle;
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_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_theme_resolver.dart';
@ -26,7 +24,7 @@ part 'flat_button.g.dart';
@ComponentCopyWithExtension()
class FlatButton extends FlatButtonComponent with $FlatButtonCWMixin {
FlatButton({
const FlatButton({
super.prefix,
super.suffix,
super.label,
@ -36,15 +34,12 @@ class FlatButton extends FlatButtonComponent with $FlatButtonCWMixin {
super.focusedStyle,
super.tappedStyle,
super.onPressed,
super.disabled,
super.mainAxisSize,
super.themeResolver,
super.key,
});
final ButtonCubit _cubit = ButtonCubit();
ButtonCubit get bloc => _cubit;
@override
FlatButtonStyle? get disabledStyle => super.disabledStyle as FlatButtonStyle?;
@ -65,21 +60,19 @@ class FlatButton extends FlatButtonComponent with $FlatButtonCWMixin {
super.themeResolver as FlatButtonThemeResolver?;
@override
Widget build(BuildContext context) => ExportableBloc(
bloc: _cubit,
child: FlatButtonScreen(
prefix: prefix,
suffix: suffix,
label: label,
disabledStyle: disabledStyle,
normalStyle: normalStyle,
hoveredStyle: hoveredStyle,
focusedStyle: focusedStyle,
tappedStyle: tappedStyle,
onPressed: onPressed,
mainAxisSize: mainAxisSize,
themeResolver: themeResolver,
key: key,
),
Widget build(BuildContext context) => FlatButtonScreen(
prefix: prefix,
suffix: suffix,
label: label,
disabledStyle: disabledStyle,
normalStyle: normalStyle,
hoveredStyle: hoveredStyle,
focusedStyle: focusedStyle,
tappedStyle: tappedStyle,
onPressed: onPressed,
disabled: disabled,
mainAxisSize: mainAxisSize,
themeResolver: themeResolver,
key: key,
);
}

View File

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

View File

@ -20,6 +20,7 @@ import 'package:gap/gap.dart';
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.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/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/gradients/gradient_box_border.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
@ -35,6 +36,7 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
this.focusedStyle,
this.tappedStyle,
this.onPressed,
this.disabled,
this.mainAxisSize,
this.themeResolver,
super.key,
@ -52,11 +54,23 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
final FlatButtonStyle? tappedStyle;
final void Function(ControlState state)? onPressed;
final ValueNotifier<bool>? disabled;
final FlatButtonThemeResolver? themeResolver;
@override
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.
FlatButtonStyle _resolve(BuildContext context, ControlState state) {
final FlatButtonThemeResolver resolver = themeResolver ??

View File

@ -17,8 +17,6 @@
import 'package:flutter/material.dart' hide ButtonStyle;
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_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_screen.dart';
@ -27,7 +25,7 @@ part 'simple_icon_button.g.dart';
@ComponentCopyWithExtension()
class SimpleIconButton extends SimpleIconButtonComponent
with $SimpleIconButtonCWMixin {
SimpleIconButton({
const SimpleIconButton({
super.icon,
super.disabledStyle,
super.normalStyle,
@ -35,14 +33,11 @@ class SimpleIconButton extends SimpleIconButtonComponent
super.focusedStyle,
super.tappedStyle,
super.onPressed,
super.disabled,
super.themeResolver,
super.key,
});
final ButtonCubit _cubit = ButtonCubit();
ButtonCubit get bloc => _cubit;
@override
SimpleIconButtonStyle? get disabledStyle =>
super.disabledStyle as SimpleIconButtonStyle?;
@ -68,18 +63,16 @@ class SimpleIconButton extends SimpleIconButtonComponent
super.themeResolver as SimpleIconButtonThemeResolver?;
@override
Widget build(BuildContext context) => ExportableBloc(
bloc: _cubit,
child: SimpleIconButtonScreen(
icon: icon,
disabledStyle: disabledStyle,
normalStyle: normalStyle,
hoveredStyle: hoveredStyle,
focusedStyle: focusedStyle,
tappedStyle: tappedStyle,
onPressed: onPressed,
themeResolver: themeResolver,
key: key,
),
Widget build(BuildContext context) => SimpleIconButtonScreen(
icon: icon,
disabledStyle: disabledStyle,
normalStyle: normalStyle,
hoveredStyle: hoveredStyle,
focusedStyle: focusedStyle,
tappedStyle: tappedStyle,
onPressed: onPressed,
disabled: disabled,
themeResolver: themeResolver,
key: key,
);
}

View File

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

View File

@ -19,6 +19,7 @@ import 'package:flutter/services.dart';
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.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/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/gradients/gradient_box_border.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_icon.dart';
@ -33,6 +34,7 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
this.focusedStyle,
this.tappedStyle,
this.onPressed,
this.disabled,
this.themeResolver,
super.key,
});
@ -46,11 +48,24 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
final SimpleIconButtonStyle? tappedStyle;
final void Function(ControlState state)? onPressed;
final ValueNotifier<bool>? disabled;
final SimpleIconButtonThemeResolver? themeResolver;
@override
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.
SimpleIconButtonStyle _resolve(BuildContext context, ControlState state) {
final SimpleIconButtonThemeResolver resolver = themeResolver ??

View File

@ -17,17 +17,14 @@
import 'package:flutter/material.dart' hide ButtonStyle;
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_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_theme_resolver.dart';
part 'symbol_button.g.dart';
@ComponentCopyWithExtension()
class SymbolButton extends SymbolButtonComponent
with $SymbolButtonCWMixin{
SymbolButton({
class SymbolButton extends SymbolButtonComponent with $SymbolButtonCWMixin {
const SymbolButton({
super.icon,
super.label,
super.disabledStyle,
@ -39,13 +36,10 @@ class SymbolButton extends SymbolButtonComponent
super.mainAxisSize,
super.themeResolver,
super.onPressed,
super.disabled,
super.key,
});
final SelectableButtonCubit _cubit = SelectableButtonCubit();
SelectableButtonCubit get bloc => _cubit;
@override
SymbolButtonStyle? get disabledStyle =>
super.disabledStyle as SymbolButtonStyle?;
@ -73,21 +67,19 @@ class SymbolButton extends SymbolButtonComponent
super.themeResolver as SymbolButtonThemeResolver?;
@override
Widget build(BuildContext context) => ExportableBloc(
bloc: _cubit,
child: SymbolButtonScreen(
icon: icon,
label: label,
disabledStyle: disabledStyle,
normalStyle: normalStyle,
hoveredStyle: hoveredStyle,
focusedStyle: focusedStyle,
tappedStyle: tappedStyle,
selectedStyle: selectedStyle,
onPressed: onPressed,
mainAxisSize: mainAxisSize,
themeResolver: themeResolver,
key: key,
),
Widget build(BuildContext context) => SymbolButtonScreen(
icon: icon,
label: label,
disabledStyle: disabledStyle,
normalStyle: normalStyle,
hoveredStyle: hoveredStyle,
focusedStyle: focusedStyle,
tappedStyle: tappedStyle,
selectedStyle: selectedStyle,
onPressed: onPressed,
disabled: disabled,
mainAxisSize: mainAxisSize,
themeResolver: themeResolver,
key: key,
);
}

View File

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

View File

@ -21,6 +21,7 @@ import 'package:wyatt_bloc_helper/wyatt_bloc_helper.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/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/gradients/gradient_box_border.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
@ -37,6 +38,7 @@ class SymbolButtonScreen
this.tappedStyle,
this.selectedStyle,
this.onPressed,
this.disabled,
this.mainAxisSize,
this.themeResolver,
super.key,
@ -54,11 +56,26 @@ class SymbolButtonScreen
final SymbolButtonStyle? selectedStyle;
final void Function(ControlState state)? onPressed;
final ValueNotifier<bool>? disabled;
final SymbolButtonThemeResolver? themeResolver;
@override
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.
SymbolButtonStyle _resolve(BuildContext context, ButtonState state) {
final SymbolButtonThemeResolver resolver = themeResolver ??

View File

@ -20,7 +20,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.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_kit/src/components/loader/loader_theme_resolver.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
part 'loader.g.dart';
@ -33,30 +32,11 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
super.stroke,
super.duration,
super.flip,
super.themeResolver,
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
Widget build(BuildContext context) {
final style = _resolve(context);
final dimension =
(radius != null) ? radius! * 2 : context.buttonTheme.height;
return SizedBox.square(
@ -64,9 +44,34 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
child: RepaintBoundary(
child: CustomPaint(
painter: _LoaderPainter(
style.colors ?? const MultiColor([]),
ThemeHelper.getThemeElement<MultiColor, 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,
style.stroke ?? 4,
ThemeHelper.getThemeElement<double, double>(
[
stroke,
Theme.of(context).extension<LoaderThemeExtension>()?.stroke,
4,
],
valueValidator: (stroke) => stroke != null,
transform: (stroke) => stroke,
)!,
flip: flip ?? false,
),
)

View File

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

View File

@ -1,58 +0,0 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_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,7 +17,6 @@
import 'package:flutter/material.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_kit/src/components/rich_text_builder/rich_text_builder_theme_resolver.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
part 'rich_text_builder.g.dart';
@ -30,37 +29,39 @@ class RichTextBuilder extends RichTextBuilderComponent
super.parser,
super.defaultStyle,
super.styles,
super.themeResolver,
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
Widget build(BuildContext context) {
final style = _resolve(context);
final RegExp regex = RegExp(r'<(.*?)>(.*?)<\/\1>');
final root = RichTextNode.from(
text ?? '',
regex,
RichTextStyleParameter(
style.defaultStyle,
style.styles ?? {},
ThemeHelper.getThemeElement<TextStyle, TextStyle>(
[
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,
),
);

View File

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

View File

@ -1,53 +0,0 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_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';
@ComponentCopyWithExtension()
class CustomAppBar extends AppBarComponent with $CustomAppBarCWMixin {
class CustomAppBar extends TopAppBarComponent with $CustomAppBarCWMixin {
const CustomAppBar({
super.title,
super.key,
@ -13,6 +13,6 @@ class CustomAppBar extends AppBarComponent with $CustomAppBarCWMixin {
@override
Widget build(BuildContext context) => AppBar(
title: Text(title?.text ?? ''),
title: Text(title?.data ?? ''),
);
}

View File

@ -6,22 +6,85 @@ part of 'custom_app_bar.dart';
// ComponentCopyWithGenerator
// **************************************************************************
class $CustomAppBarCWProxyImpl implements $AppBarComponentCWProxy {
class $CustomAppBarCWProxyImpl implements $TopAppBarComponentCWProxy {
const $CustomAppBarCWProxyImpl(this._value);
final CustomAppBar _value;
@override
CustomAppBar title(String? title) => this(title: title);
CustomAppBar title(TextWrapper? 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
CustomAppBar leading(Widget? leading) => this(leading: leading);
@override
CustomAppBar actions(List<Widget>? actions) => this(actions: actions);
@override
CustomAppBar expandedWidget(List<Widget>? expandedWidget) =>
this(expandedWidget: expandedWidget);
@override
CustomAppBar key(Key? key) => this(key: key);
@override
CustomAppBar call({
String? 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,
List<Widget>? actions,
List<Widget>? expandedWidget,
Key? key,
}) =>
CustomAppBar(
@ -31,6 +94,6 @@ class $CustomAppBarCWProxyImpl implements $AppBarComponentCWProxy {
}
mixin $CustomAppBarCWMixin on Component {
$AppBarComponentCWProxy get copyWith =>
$TopAppBarComponentCWProxy get copyWith =>
$CustomAppBarCWProxyImpl(this as CustomAppBar);
}