mirror of
https://github.com/Iconica-Development/flutter_single_character_input.git
synced 2025-05-18 19:53:45 +02:00
Compare commits
13 commits
Author | SHA1 | Date | |
---|---|---|---|
|
f32ad75235 | ||
|
c7dd72a245 | ||
|
c26d9de2ca | ||
|
8e458231f7 | ||
|
00450d9e06 | ||
|
15aacb0809 | ||
|
ef4a966e33 | ||
|
362be1e683 | ||
|
2f9b55b3a3 | ||
|
8e58a78e20 | ||
88b91c7337 | |||
213559d958 | |||
|
44c838092f |
15 changed files with 342 additions and 424 deletions
14
.github/workflows/component-ci.yml
vendored
Normal file
14
.github/workflows/component-ci.yml
vendored
Normal file
|
@ -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
|
14
.github/workflows/component-documentation.yml
vendored
Normal file
14
.github/workflows/component-documentation.yml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
name: Iconica Standard Component Documentation Workflow
|
||||
# Workflow Caller version: 1.0.0
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
call-iconica-component-documentation-workflow:
|
||||
uses: Iconica-Development/.github/.github/workflows/component-documentation.yml@master
|
||||
secrets: inherit
|
||||
permissions: write-all
|
|
@ -1,3 +1,11 @@
|
|||
## [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
|
||||
|
||||
## [0.0.1] - 12 October 2022
|
||||
|
||||
- Initial release.
|
||||
|
|
10
LICENSE
10
LICENSE
|
@ -1 +1,9 @@
|
|||
TODO: Add your license here.
|
||||
Copyright (c) 2022 Iconica, All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
|
@ -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:
|
|
@ -1,214 +1,9 @@
|
|||
include: package:flutter_lints/flutter.yaml
|
||||
analyzer:
|
||||
errors:
|
||||
todo: ignore
|
||||
exclude: [lib/generated_plugin_registrant.dart]
|
||||
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
|
||||
lowercase_with_underscores: true
|
||||
secure_pubspec_urls: false
|
||||
sort_pub_dependencies: false
|
||||
include: package:flutter_iconica_analysis/analysis_options.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
# Possible to overwrite the rules from the package
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
|
||||
linter:
|
||||
rules:
|
|
@ -1,3 +1,7 @@
|
|||
// SPDX-FileCopyrightText: 2022 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_single_character_input/single_character_input.dart';
|
||||
|
||||
|
@ -6,7 +10,7 @@ void main() {
|
|||
}
|
||||
|
||||
class FlutterSingleCharacterInputDemo extends StatefulWidget {
|
||||
const FlutterSingleCharacterInputDemo({Key? key}) : super(key: key);
|
||||
const FlutterSingleCharacterInputDemo({super.key});
|
||||
|
||||
@override
|
||||
State<FlutterSingleCharacterInputDemo> createState() =>
|
||||
|
@ -30,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(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,49 +5,56 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
version: "2.11.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.3.0"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.16.0"
|
||||
version: "1.17.1"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cupertino_icons
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
flutter:
|
||||
|
@ -59,7 +66,8 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
flutter_single_character_input:
|
||||
|
@ -74,41 +82,54 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.12"
|
||||
version: "0.12.15"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
version: "0.2.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
version: "1.9.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
version: "1.8.3"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -118,51 +139,58 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
version: "1.9.1"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
version: "1.11.0"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.2.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.12"
|
||||
version: "0.5.1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.4"
|
||||
sdks:
|
||||
dart: ">=2.18.2 <3.0.0"
|
||||
dart: ">=3.0.0-0 <4.0.0"
|
||||
flutter: ">=1.17.0"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
|
||||
// SPDX-FileCopyrightText: 2022 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// SPDX-FileCopyrightText: 2022 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
///
|
||||
library single_character_input;
|
||||
|
||||
export 'src/input_character.dart';
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
// SPDX-FileCopyrightText: 2022 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Defines a character input configuration.
|
||||
class InputCharacter {
|
||||
/// Creates an [InputCharacter] configuration.
|
||||
///
|
||||
/// The [keyboardType] parameter is required.
|
||||
/// The [readOnly], [hint], and [formatter] parameters are optional.
|
||||
const InputCharacter({
|
||||
required this.keyboardType,
|
||||
this.readOnly = false,
|
||||
|
@ -8,14 +17,23 @@ class InputCharacter {
|
|||
this.formatter,
|
||||
});
|
||||
|
||||
/// The type of keyboard to display for the input.
|
||||
final TextInputType keyboardType;
|
||||
final CharacterFormatter? formatter;
|
||||
|
||||
/// A flag indicating whether the input is read-only.
|
||||
final bool readOnly;
|
||||
|
||||
/// The optional hint text displayed inside the input field.
|
||||
final String hint;
|
||||
|
||||
String format(String value) {
|
||||
return formatter?.call(value) ?? value;
|
||||
}
|
||||
/// The optional formatter function to format the input value.
|
||||
final CharacterFormatter? formatter;
|
||||
|
||||
/// Formats the input value using the provided formatter function.
|
||||
///
|
||||
/// If no formatter is provided, the input value remains unchanged.
|
||||
String format(String value) => formatter?.call(value) ?? value;
|
||||
}
|
||||
|
||||
/// Defines a function signature for formatting input characters.
|
||||
typedef CharacterFormatter = String Function(String);
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
// SPDX-FileCopyrightText: 2022 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_single_character_input/src/input_character.dart';
|
||||
|
||||
/// A StatefulWidget that represents a single character input.
|
||||
class SingleCharacterInput extends StatefulWidget {
|
||||
/// Creates a SingleCharacterInput widget.
|
||||
const SingleCharacterInput({
|
||||
required this.characters,
|
||||
required this.onChanged,
|
||||
|
@ -15,9 +21,11 @@ class SingleCharacterInput extends StatefulWidget {
|
|||
this.inputDecoration,
|
||||
this.spacing = 0,
|
||||
this.textStyle,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
super.key,
|
||||
});
|
||||
|
||||
/// A function that builds a custom input widget using
|
||||
/// the provided context and input widgets.
|
||||
final Widget Function(BuildContext context, List<Widget> inputs)?
|
||||
buildCustomInput;
|
||||
|
||||
|
@ -26,16 +34,25 @@ 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;
|
||||
|
||||
/// The decoration to be applied to the input widget.
|
||||
final InputDecoration? inputDecoration;
|
||||
|
||||
/// List of all character fields which are used to create inputs.
|
||||
final List<InputCharacter> characters;
|
||||
|
||||
/// The alignment of the input text.
|
||||
final TextAlign textAlign;
|
||||
|
||||
/// The alignment of the cursor.
|
||||
final TextAlign cursorTextAlign;
|
||||
|
||||
/// The spacing between input fields.
|
||||
final double spacing;
|
||||
|
||||
/// The style of the input text.
|
||||
final TextStyle? textStyle;
|
||||
|
||||
@override
|
||||
|
@ -101,92 +118,91 @@ class _SingleCharacterInputState extends State<SingleCharacterInput>
|
|||
}
|
||||
|
||||
@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(
|
||||
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);
|
||||
|
@ -205,6 +221,8 @@ class _SingleCharacterInputState extends State<SingleCharacterInput>
|
|||
if (_currentKeyboard != nextKeyboard) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_mainNodes[nextKeyboard]?.requestFocus();
|
||||
_mainController.selection =
|
||||
TextSelection.collapsed(offset: _currentIndex);
|
||||
});
|
||||
setState(() {
|
||||
_currentKeyboard = nextKeyboard;
|
||||
|
@ -253,9 +271,7 @@ class _SingleCharacterInputState extends State<SingleCharacterInput>
|
|||
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) {
|
||||
|
@ -264,19 +280,17 @@ class _SingleCharacterInputState extends State<SingleCharacterInput>
|
|||
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(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: flutter_single_character_input
|
||||
description: A new Flutter package project.
|
||||
version: 0.0.1
|
||||
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
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// SPDX-FileCopyrightText: 2022 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
|
|
Loading…
Reference in a new issue