From 2f9b55b3a3bb8a86e42d602e08f44df2cab23bf7 Mon Sep 17 00:00:00 2001 From: mike doornenbal Date: Tue, 6 Feb 2024 16:36:01 +0100 Subject: [PATCH] fix: added ci and linter --- .github/workflows/component-ci.yml | 14 ++ CHANGELOG.md | 4 + analysis_options.yaml | 12 +- example/analysis_options.yaml | 217 +--------------------------- example/lib/main.dart | 124 ++++++++-------- example/pubspec.yaml | 6 +- lib/single_character_input.dart | 2 +- lib/src/input_character.dart | 4 +- lib/src/single_character_input.dart | 193 ++++++++++++------------- pubspec.yaml | 7 +- 10 files changed, 198 insertions(+), 385 deletions(-) create mode 100644 .github/workflows/component-ci.yml diff --git a/.github/workflows/component-ci.yml b/.github/workflows/component-ci.yml new file mode 100644 index 0000000..e2f6ffe --- /dev/null +++ b/.github/workflows/component-ci.yml @@ -0,0 +1,14 @@ +name: Iconica Standard Component CI Workflow +# Workflow Caller version: 2.0.0 + +on: + pull_request: + workflow_dispatch: + +jobs: + call-global-iconica-workflow: + uses: Iconica-Development/.github/.github/workflows/component-ci.yml@master + secrets: inherit + permissions: write-all + with: + subfolder: "." # add optional subfolder to run workflow in \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e34ee..5304450 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [0.0.3] - 7 february 2024 + +- Add CI and linter + ## [0.0.2] - 15 may 2023 - Fix text input for web on flutter 3.10 diff --git a/analysis_options.yaml b/analysis_options.yaml index eaf2f3e..e2b30bf 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,5 +1,9 @@ -include: package:flutter_lints/flutter.yaml +include: package:flutter_iconica_analysis/analysis_options.yaml + +# Possible to overwrite the rules from the package + analyzer: - errors: - todo: ignore - exclude: [lib/generated_plugin_registrant.dart] + exclude: + +linter: + rules: \ No newline at end of file diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index 25f5c77..e2b30bf 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -1,212 +1,9 @@ -include: package:flutter_lints/flutter.yaml +include: package:flutter_iconica_analysis/analysis_options.yaml + +# Possible to overwrite the rules from the package + analyzer: - errors: - todo: ignore - exclude: [lib/generated_plugin_registrant.dart] + exclude: + linter: - # https://dart.dev/tools/linter-rules#lints - rules: - # error rules - always_use_package_imports: false - avoid_dynamic_calls: true - avoid_empty_else: true - avoid_print: true - avoid_relative_lib_imports: true - avoid_returning_null_for_future: true - avoid_slow_async_io: true - avoid_type_to_string: true - avoid_types_as_parameter_names: true - avoid_web_libraries_in_flutter: true - cancel_subscriptions: true - close_sinks: true - comment_references: false - control_flow_in_finally: true - diagnostic_describe_all_properties: false - empty_statements: true - hash_and_equals: true - invariant_booleans: true - iterable_contains_unrelated_type: true - list_remove_unrelated_type: true - literal_only_boolean_expressions: true - no_adjacent_strings_in_list: true - no_duplicate_case_values: true - no_logic_in_create_state: true - prefer_relative_imports: false - prefer_void_to_null: true - test_types_in_equals: true - throw_in_finally: true - unnecessary_statements: true - unrelated_type_equality_checks: true - unsafe_html: true - use_build_context_synchronously: true - use_key_in_widget_constructors: true - valid_regexps: true - # style rules - always_declare_return_types: true - always_put_control_body_on_new_line: true - always_put_required_named_parameters_first: true - always_require_non_null_named_parameters: true - always_specify_types: false - annotate_overrides: true - avoid_annotating_with_dynamic: false - avoid_bool_literals_in_conditional_expressions: true - avoid_catches_without_on_clauses: false - avoid_catching_errors: false - avoid_classes_with_only_static_members: true - avoid_double_and_int_checks: true - avoid_equals_and_hash_code_on_mutable_classes: false - avoid_escaping_inner_quotes: false - avoid_field_initializers_in_const_classes: true - avoid_final_parameters: true - avoid_function_literals_in_foreach_calls: true - avoid_implementing_value_types: true - avoid_init_to_null: true - avoid_js_rounded_ints: true - avoid_multiple_declarations_per_line: true - avoid_null_checks_in_equality_operators: true - avoid_positional_boolean_parameters: true - avoid_private_typedef_functions: true - avoid_redundant_argument_values: false - avoid_renaming_method_parameters: true - avoid_return_types_on_setters: true - avoid_returning_null: true - avoid_returning_null_for_void: true - avoid_returning_this: true - avoid_setters_without_getters: true - avoid_shadowing_type_parameters: true - avoid_single_cascade_in_expression_statements: true - avoid_types_on_closure_parameters: false - avoid_unnecessary_containers: false - avoid_unused_constructor_parameters: true - avoid_void_async: true - await_only_futures: true - camel_case_extensions: true - camel_case_types: true - cascade_invocations: true - cast_nullable_to_non_nullable: true - conditional_uri_does_not_exist: true - constant_identifier_names: true - curly_braces_in_flow_control_structures: true - deprecated_consistency: true - directives_ordering: true - do_not_use_environment: true - empty_catches: true - empty_constructor_bodies: true - eol_at_end_of_file: true - exhaustive_cases: true - file_names: true - flutter_style_todos: true - implementation_imports: true - join_return_with_assignment: true - leading_newlines_in_multiline_strings: true - library_names: true - library_prefixes: true - library_private_types_in_public_api: true - lines_longer_than_80_chars: true - missing_whitespace_between_adjacent_strings: true - no_default_cases: true - no_leading_underscores_for_library_prefixes: true - no_leading_underscores_for_local_identifiers: true - no_runtimeType_toString: true - non_constant_identifier_names: true - noop_primitive_operations: true - null_check_on_nullable_type_parameter: true - null_closures: true - omit_local_variable_types: true - one_member_abstracts: true - only_throw_errors: true - overridden_fields: true - package_api_docs: true - package_prefixed_library_names: true - parameter_assignments: true - prefer_adjacent_string_concatenation: true - prefer_asserts_in_initializer_lists: true - prefer_asserts_with_message: true - prefer_collection_literals: true - prefer_conditional_assignment: true - prefer_const_constructors: true - prefer_const_constructors_in_immutables: true - prefer_const_declarations: false - prefer_const_literals_to_create_immutables: false - prefer_constructors_over_static_methods: true - prefer_contains: true - prefer_double_quotes: false - prefer_equal_for_default_values: true - prefer_expression_function_bodies: false - prefer_final_fields: true - prefer_final_in_for_each: false - prefer_final_locals: false - prefer_final_parameters: false - prefer_for_elements_to_map_fromIterable: true - prefer_foreach: true - prefer_function_declarations_over_variables: true - prefer_generic_function_type_aliases: true - prefer_if_elements_to_conditional_expressions: true - prefer_if_null_operators: true - prefer_initializing_formals: true - prefer_inlined_adds: true - prefer_int_literals: false - prefer_interpolation_to_compose_strings: true - prefer_is_empty: true - prefer_is_not_empty: true - prefer_is_not_operator: true - prefer_iterable_whereType: true - prefer_mixin: true - prefer_null_aware_method_calls: true - prefer_null_aware_operators: true - prefer_single_quotes: true - prefer_spread_collections: true - prefer_typing_uninitialized_variables: true - provide_deprecation_message: true - public_member_api_docs: false - recursive_getters: true - require_trailing_commas: true - sized_box_for_whitespace: true - sized_box_shrink_expand: true - slash_for_doc_comments: true - sort_child_properties_last: true - sort_constructors_first: true - sort_unnamed_constructors_first: true - tighten_type_of_initializing_formals: true - type_annotate_public_apis: true - type_init_formals: true - unawaited_futures: true - unnecessary_await_in_return: true - unnecessary_brace_in_string_interps: true - unnecessary_const: false - unnecessary_constructor_name: true - unnecessary_final: true - unnecessary_getters_setters: true - unnecessary_lambdas: true - unnecessary_late: true - unnecessary_new: true - unnecessary_null_aware_assignments: true - unnecessary_null_checks: true - unnecessary_null_in_if_null_operators: true - unnecessary_nullable_for_final_variable_declarations: true - unnecessary_overrides: true - unnecessary_parenthesis: true - unnecessary_raw_strings: true - unnecessary_string_escapes: true - unnecessary_string_interpolations: true - unnecessary_this: true - use_decorated_box: true - use_full_hex_values_for_flutter_colors: true - use_function_type_syntax_for_parameters: true - use_if_null_to_convert_nulls_to_bools: true - use_is_even_rather_than_modulo: true - use_late_for_private_fields_and_variables: true - use_named_constants: true - use_raw_strings: false - use_rethrow_when_possible: true - use_setters_to_change_properties: true - use_string_buffers: true - use_test_throws_matchers: true - use_to_and_as_if_applicable: true - void_checks: true - # pub rules - depend_on_referenced_packages: true - secure_pubspec_urls: false - sort_pub_dependencies: false -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options + rules: \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index cdabf08..cec8e4d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -10,7 +10,7 @@ void main() { } class FlutterSingleCharacterInputDemo extends StatefulWidget { - const FlutterSingleCharacterInputDemo({Key? key}) : super(key: key); + const FlutterSingleCharacterInputDemo({super.key}); @override State createState() => @@ -34,82 +34,78 @@ class _FlutterSingleCharacterInputDemoState }; @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: SingleCharacterInput( - characters: [ - InputCharacter( - hint: '1', - keyboardType: const TextInputType.numberWithOptions( - signed: true, - decimal: true, + Widget build(BuildContext context) => Scaffold( + body: Center( + child: SingleCharacterInput( + characters: [ + InputCharacter( + hint: '1', + keyboardType: const TextInputType.numberWithOptions( + signed: true, + decimal: true, + ), + formatter: _numberFormatter, ), - formatter: _numberFormatter, - ), - InputCharacter( - hint: '2', - keyboardType: const TextInputType.numberWithOptions( - signed: true, - decimal: true, + InputCharacter( + hint: '2', + keyboardType: const TextInputType.numberWithOptions( + signed: true, + decimal: true, + ), + formatter: _numberFormatter, ), - formatter: _numberFormatter, - ), - InputCharacter( - hint: '3', - keyboardType: const TextInputType.numberWithOptions( - signed: true, - decimal: true, + InputCharacter( + hint: '3', + keyboardType: const TextInputType.numberWithOptions( + signed: true, + decimal: true, + ), + formatter: _numberFormatter, ), - formatter: _numberFormatter, - ), - InputCharacter( - hint: '4', - keyboardType: const TextInputType.numberWithOptions( - signed: true, - decimal: true, + InputCharacter( + hint: '4', + keyboardType: const TextInputType.numberWithOptions( + signed: true, + decimal: true, + ), + formatter: _numberFormatter, ), - formatter: _numberFormatter, - ), - InputCharacter( - hint: 'A', - keyboardType: TextInputType.name, - formatter: _textFormatter, - ), - InputCharacter( - hint: 'B', - keyboardType: TextInputType.name, - formatter: _textFormatter, - ), - ], - textStyle: Theme.of(context).textTheme.headline1?.copyWith( - fontWeight: FontWeight.w400, - fontSize: 28, + InputCharacter( + hint: 'A', + keyboardType: TextInputType.name, + formatter: _textFormatter, ), - inputDecoration: InputDecoration( - hintStyle: Theme.of(context).textTheme.bodyText1?.copyWith( + InputCharacter( + hint: 'B', + keyboardType: TextInputType.name, + formatter: _textFormatter, + ), + ], + textStyle: Theme.of(context).textTheme.displayLarge?.copyWith( fontWeight: FontWeight.w400, - color: const Color(0xFFBBBBBB), fontSize: 28, ), - isDense: true, - isCollapsed: true, - ), - buildDecoration: (context, input) { - return Container( + inputDecoration: InputDecoration( + hintStyle: Theme.of(context).textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w400, + color: const Color(0xFFBBBBBB), + fontSize: 28, + ), + isDense: true, + isCollapsed: true, + ), + buildDecoration: (context, input) => Container( margin: const EdgeInsets.all(5), child: Container( padding: const EdgeInsets.symmetric(vertical: 15), width: 32, child: input, ), - ); - }, - onChanged: (value, finished) { - // setState(() {}); - }, + ), + onChanged: (value, finished) { + // setState(() {}); + }, + ), ), - ), - ); - } + ); } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fe5c957..0e0e169 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -19,8 +19,10 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - - flutter_lints: ^2.0.0 + flutter_iconica_analysis: + git: + url: https://github.com/Iconica-Development/flutter_iconica_analysis + ref: 6.0.0 flutter: uses-material-design: true diff --git a/lib/single_character_input.dart b/lib/single_character_input.dart index bebdfef..bc116e8 100644 --- a/lib/single_character_input.dart +++ b/lib/single_character_input.dart @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2022 Iconica // // SPDX-License-Identifier: BSD-3-Clause - +/// library single_character_input; export 'src/input_character.dart'; diff --git a/lib/src/input_character.dart b/lib/src/input_character.dart index c669b63..db2c168 100644 --- a/lib/src/input_character.dart +++ b/lib/src/input_character.dart @@ -17,9 +17,7 @@ class InputCharacter { final bool readOnly; final String hint; - String format(String value) { - return formatter?.call(value) ?? value; - } + String format(String value) => formatter?.call(value) ?? value; } typedef CharacterFormatter = String Function(String); diff --git a/lib/src/single_character_input.dart b/lib/src/single_character_input.dart index f71bfbb..bf068bd 100644 --- a/lib/src/single_character_input.dart +++ b/lib/src/single_character_input.dart @@ -19,8 +19,8 @@ class SingleCharacterInput extends StatefulWidget { this.inputDecoration, this.spacing = 0, this.textStyle, - Key? key, - }) : super(key: key); + super.key, + }); final Widget Function(BuildContext context, List inputs)? buildCustomInput; @@ -30,6 +30,7 @@ class SingleCharacterInput extends StatefulWidget { /// Gets called when the value is changed. /// Passes the changed value and if all inputs are filled in. + // ignore: avoid_positional_boolean_parameters final void Function(String value, bool isComplete) onChanged; final InputDecoration? inputDecoration; @@ -105,93 +106,91 @@ class _SingleCharacterInputState extends State } @override - Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - WidgetsBinding.instance.addPostFrameCallback((_) { - _mainNodes[_currentKeyboard]?.unfocus(); - _mainNodes[_currentKeyboard]?.requestFocus(); - }); - setState(() {}); - }, - child: Wrap( - direction: Axis.horizontal, - children: [ - Offstage( - child: Column( - children: _mainNodes - .map((key, value) { - return MapEntry( - key, - TextField( - enableInteractiveSelection: false, - focusNode: value, - controller: _mainController, - textCapitalization: TextCapitalization.characters, - keyboardType: key, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp('[a-zA-Z0-9]'), - ), - LengthLimitingTextInputFormatter( - widget.characters.length, - ), - ], - onChanged: (String value) { - if (value.length > _currentIndex) { - var result = widget.characters[_currentIndex] - .format(value[_currentIndex]); - if (value[_currentIndex] != result) { - value = value.replaceRange( - _currentIndex, - _currentIndex + 1, - result, - ); - _mainController.value = - _mainController.value.copyWith( - text: value, - selection: TextSelection.collapsed( - offset: value.length, - ), - ); + Widget build(BuildContext context) => GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + WidgetsBinding.instance.addPostFrameCallback((_) { + _mainNodes[_currentKeyboard]?.unfocus(); + _mainNodes[_currentKeyboard]?.requestFocus(); + }); + setState(() {}); + }, + child: Wrap( + direction: Axis.horizontal, + children: [ + Offstage( + child: Column( + children: _mainNodes + .map( + (key, value) => MapEntry( + key, + TextField( + enableInteractiveSelection: false, + focusNode: value, + controller: _mainController, + textCapitalization: TextCapitalization.characters, + keyboardType: key, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp('[a-zA-Z0-9]'), + ), + LengthLimitingTextInputFormatter( + widget.characters.length, + ), + ], + onChanged: (String value) { + if (value.length > _currentIndex) { + var result = widget.characters[_currentIndex] + .format(value[_currentIndex]); + if (value[_currentIndex] != result) { + value = value.replaceRange( + _currentIndex, + _currentIndex + 1, + result, + ); + _mainController.value = + _mainController.value.copyWith( + text: value, + selection: TextSelection.collapsed( + offset: value.length, + ), + ); + } } - } - _onChanged(value); - }, + _onChanged(value); + }, + ), ), - ); - }) - .values - .toList(), + ) + .values + .toList(), + ), ), - ), - if (widget.buildCustomInput != null) ...[ - widget.buildCustomInput!.call( - context, - widget.characters - .asMap() - .map( - (key, value) => MapEntry(key, _createCharacter(key)), - ) - .values - .toList(), - ), - ] else ...[ - for (var i = 0; i < widget.characters.length; i++) ...[ - _createCharacter(i), - if (i < widget.characters.length - 1 && widget.spacing > 0) ...[ - SizedBox( - height: widget.spacing, - width: widget.spacing, - ), - ] + if (widget.buildCustomInput != null) ...[ + widget.buildCustomInput!.call( + context, + widget.characters + .asMap() + .map( + (key, value) => MapEntry(key, _createCharacter(key)), + ) + .values + .toList(), + ), + ] else ...[ + for (var i = 0; i < widget.characters.length; i++) ...[ + _createCharacter(i), + if (i < widget.characters.length - 1 && widget.spacing > 0) ...[ + SizedBox( + height: widget.spacing, + width: widget.spacing, + ), + ], + ], ], ], - ], - ), - ); - } + ), + ); void _onChanged(String value) { widget.onChanged.call(value, value.length == widget.characters.length); @@ -260,9 +259,7 @@ class _SingleCharacterInputState extends State return ''; } - bool _hasFocus() { - return _mainNodes.values.any((element) => element.hasFocus); - } + bool _hasFocus() => _mainNodes.values.any((element) => element.hasFocus); Widget _createLabel(int index) { if (index < _currentValue.length) { @@ -271,19 +268,17 @@ class _SingleCharacterInputState extends State if (index == _currentValue.length && _hasFocus()) { return AnimatedBuilder( animation: _cursorAnimation, - builder: (context, _) { - return Opacity( - opacity: _cursorAnimation.value, - child: Container( - alignment: _getAlignment(widget.cursorTextAlign), - child: Text( - '|', - style: widget.textStyle, - textAlign: widget.cursorTextAlign, - ), + builder: (context, _) => Opacity( + opacity: _cursorAnimation.value, + child: Container( + alignment: _getAlignment(widget.cursorTextAlign), + child: Text( + '|', + style: widget.textStyle, + textAlign: widget.cursorTextAlign, ), - ); - }, + ), + ), ); } else { return Container( diff --git a/pubspec.yaml b/pubspec.yaml index 8c19c82..4448c93 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_single_character_input description: A new Flutter package project. -version: 0.0.2 +version: 0.0.3 environment: sdk: ">=2.18.0 <3.0.0" @@ -13,4 +13,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.0 + flutter_iconica_analysis: + git: + url: https://github.com/Iconica-Development/flutter_iconica_analysis + ref: 6.0.0