Browse Source

Merge pull request #4 from h1376h/main

feature: add dependabot & CI (+ lint improvements)
pull/5/head
Khoren Markosyan 2 years ago committed by GitHub
parent
commit
57d9b1e7eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      .github/dependabot.yml
  2. 37
      .github/workflows/main.yml
  3. 1
      analysis_options.yaml
  4. 2
      android/build.gradle
  5. 242
      zxscanner/analysis_options.yaml
  6. 12
      zxscanner/lib/configs/app_store.dart
  7. 20
      zxscanner/lib/configs/app_store.g.dart
  8. 2
      zxscanner/lib/configs/app_theme.dart
  9. 18
      zxscanner/lib/configs/constants.dart
  10. 22
      zxscanner/lib/generated/intl/messages_all.dart
  11. 4
      zxscanner/lib/generated/intl/messages_en_US.dart
  12. 13
      zxscanner/lib/generated/l10n.dart
  13. 14
      zxscanner/lib/main.dart
  14. 16
      zxscanner/lib/models/code.dart
  15. 4
      zxscanner/lib/models/code.g.dart
  16. 20
      zxscanner/lib/models/encode.dart
  17. 4
      zxscanner/lib/models/encode.g.dart
  18. 25
      zxscanner/lib/pages/barcodes_page.dart
  19. 40
      zxscanner/lib/pages/creator_page.dart
  20. 62
      zxscanner/lib/pages/help_page.dart
  21. 23
      zxscanner/lib/pages/history_page.dart
  22. 42
      zxscanner/lib/pages/home_page.dart
  23. 22
      zxscanner/lib/pages/scanner_page.dart
  24. 14
      zxscanner/lib/pages/settings_page.dart
  25. 29
      zxscanner/lib/utils/db_service.dart
  26. 4
      zxscanner/lib/utils/extensions.dart
  27. 34
      zxscanner/lib/utils/router.dart
  28. 2
      zxscanner/lib/utils/scroll_behavior.dart
  29. 34
      zxscanner/lib/utils/shared_pref.dart
  30. 4
      zxscanner/lib/widgets/common_widgets.dart
  31. 18
      zxscanner/lib/widgets/language_widget.dart
  32. 4
      zxscanner/lib/widgets/setting_tile.dart
  33. 4
      zxscanner/lib/widgets/theme_mode_switch.dart
  34. 7
      zxscanner/lib/widgets/theme_selector.dart
  35. 14
      zxscanner/pubspec.lock

27
.github/dependabot.yml

@ -0,0 +1,27 @@
version: 2
enable-beta-ecosystems: true
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
reviewers:
- "khoren93"
- package-ecosystem: "pub"
directory: "/"
schedule:
interval: "weekly"
reviewers:
- "khoren93"
- package-ecosystem: "pub"
directory: "/example"
schedule:
interval: "weekly"
reviewers:
- "khoren93"
- package-ecosystem: "pub"
directory: "/zxscanner"
schedule:
interval: "weekly"
reviewers:
- "khoren93"

37
.github/workflows/main.yml

@ -0,0 +1,37 @@
name: Flutter CI
# This workflow is triggered on pushes to the repository.
on:
push:
branches:
- main
jobs:
build:
# This job will run on ubuntu virtual machine
runs-on: ubuntu-latest
steps:
# Setup Java environment in order to build the Android app.
- uses: actions/checkout@v3.0.2
- uses: actions/setup-java@v3.4.0
with:
java-version: 11
distribution: temurin
# Setup the flutter environment.
- uses: subosito/flutter-action@v2.4.0
with:
channel: 'stable' # 'dev', 'alpha', default to: 'stable'
cache: true
# flutter-version: '1.22.x' # you can also specify exact version of flutter
# Get flutter dependencies.
- run: flutter pub get
# Check for any formatting issues in the code.
- run: flutter format .
# Statically analyze the Dart code for any errors.
- run: flutter analyze .

1
analysis_options.yaml

@ -26,6 +26,7 @@ analyzer:
# Turned off until null-safe rollout is complete. # Turned off until null-safe rollout is complete.
unnecessary_null_comparison: warning unnecessary_null_comparison: warning
exclude: exclude:
- "zxscanner/**"
- "bin/cache/**" - "bin/cache/**"
# Ignore protoc generated files # Ignore protoc generated files
- "dev/conductor/lib/proto/*" - "dev/conductor/lib/proto/*"

2
android/build.gradle

@ -9,7 +9,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.1.0' classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

242
zxscanner/analysis_options.yaml

@ -9,21 +9,231 @@
# packages, and plugins designed to encourage good coding practices. # packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml include: package:flutter_lints/flutter.yaml
analyzer:
language:
strict-casts: false
strict-raw-types: true
errors:
# treat missing required parameters as a warning (not a hint)
missing_required_param: warning
# treat missing returns as a warning (not a hint)
missing_return: warning
# not allowing having TODO comments in the code
# todo: warning
# allow self-reference to deprecated members (we do this because otherwise we have
# to annotate every member in every test, assert, etc, when we deprecate something)
deprecated_member_use_from_same_package: ignore
# Turned off until null-safe rollout is complete.
unnecessary_null_comparison: warning
exclude:
- "bin/cache/**"
# Ignore protoc generated files
- "dev/conductor/lib/proto/*"
- "lib/generated_bindings.dart"
linter: linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules: rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule # This list is derived from the list of all available lints located at
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule # https://github.com/dart-lang/linter/blob/master/example/all.yaml
- always_declare_return_types
# Additional information about this file can be found at - always_put_control_body_on_new_line
# https://dart.dev/guides/language/analysis-options # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219
- always_require_non_null_named_parameters
- always_specify_types
# - always_use_package_imports # we do this commonly
- annotate_overrides
# - avoid_annotating_with_dynamic # conflicts with always_specify_types
- avoid_bool_literals_in_conditional_expressions
# - avoid_catches_without_on_clauses # blocked on https://github.com/dart-lang/linter/issues/3023
# - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023
- avoid_classes_with_only_static_members
- 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 # incompatible with prefer_final_parameters
- avoid_function_literals_in_foreach_calls
- avoid_implementing_value_types
- avoid_init_to_null
- avoid_js_rounded_ints
# - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to
- avoid_null_checks_in_equality_operators
# - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it
- avoid_print
# - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356)
- avoid_redundant_argument_values
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
# - avoid_returning_null # still violated by some pre-nnbd code that we haven't yet migrated
- avoid_returning_null_for_future
- avoid_returning_null_for_void
# - avoid_returning_this # there are enough valid reasons to return `this` that this lint ends up with too many false positives
- 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 # conflicts with always_specify_types
- avoid_unnecessary_containers
- avoid_unused_constructor_parameters
- avoid_void_async
# - avoid_web_libraries_in_flutter # we use web libraries in web-specific code, and our tests prevent us from using them elsewhere
- await_only_futures
- camel_case_extensions
- camel_case_types
- cancel_subscriptions
# - cascade_invocations # doesn't match the typical style of this repo
- cast_nullable_to_non_nullable
# - close_sinks # not reliable enough
# - comment_references # blocked on https://github.com/dart-lang/linter/issues/1142
# - conditional_uri_does_not_exist # not yet tested
# - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204
- control_flow_in_finally
# - curly_braces_in_flow_control_structures # not required by flutter style
- depend_on_referenced_packages
- deprecated_consistency
# - diagnostic_describe_all_properties # enabled only at the framework level (packages/flutter/lib)
- directives_ordering
# - do_not_use_environment # there are appropriate times to use the environment, especially in our tests and build logic
- empty_catches
- empty_constructor_bodies
- empty_statements
- eol_at_end_of_file
- exhaustive_cases
- file_names
- hash_and_equals
- implementation_imports
# - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811
- iterable_contains_unrelated_type
# - join_return_with_assignment # not required by flutter style
- leading_newlines_in_multiline_strings
- library_names
- library_prefixes
- library_private_types_in_public_api
# - lines_longer_than_80_chars # not required by flutter style
- list_remove_unrelated_type
# - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/linter/issues/453
- 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_logic_in_create_state
# - no_runtimeType_toString # ok in tests; we enable this only in packages/
- non_constant_identifier_names
- noop_primitive_operations
- null_check_on_nullable_type_parameter
- null_closures
# - omit_local_variable_types # opposite of always_specify_types
# - one_member_abstracts # too many false positives
- only_throw_errors # this does get disabled in a few places where we have legacy code that uses strings et al
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
# - parameter_assignments # we do this commonly
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
# - prefer_asserts_with_message # not required by flutter style
- 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 # far too many false positives
- prefer_contains
# - prefer_double_quotes # opposite of prefer_single_quotes
- prefer_equal_for_default_values
# - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
# - prefer_final_parameters # we should enable this one day when it can be auto-fixed (https://github.com/dart-lang/linter/issues/3104), see also parameter_assignments
- prefer_for_elements_to_map_fromIterable
- prefer_foreach
- 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 # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use-double-literals-for-double-constants
- prefer_interpolation_to_compose_strings
- prefer_is_empty
- prefer_is_not_empty
- prefer_is_not_operator
- prefer_iterable_whereType
# - prefer_mixin # Has false positives, see https://github.com/dart-lang/linter/issues/3018
# - prefer_null_aware_method_calls # "call()" is confusing to people new to the language since it's not documented anywhere
- prefer_null_aware_operators
- prefer_relative_imports
- prefer_single_quotes
- prefer_spread_collections
- prefer_typing_uninitialized_variables
- prefer_void_to_null
- provide_deprecation_message
# - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml
- recursive_getters
# - require_trailing_commas # blocked on https://github.com/dart-lang/sdk/issues/47441
- secure_pubspec_urls
- sized_box_for_whitespace
# - sized_box_shrink_expand # not yet tested
- slash_for_doc_comments
- sort_child_properties_last
- sort_constructors_first
# - sort_pub_dependencies # prevents separating pinned transitive dependencies
- sort_unnamed_constructors_first
- test_types_in_equals
- throw_in_finally
- tighten_type_of_initializing_formals
# - type_annotate_public_apis # subset of always_specify_types
- type_init_formals
# - unawaited_futures # too many false positives, especially with the way AnimationController works
- unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- unnecessary_const
- unnecessary_constructor_name
# - unnecessary_final # conflicts with prefer_final_locals
- unnecessary_getters_setters
# - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498
- 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 # what's "necessary" is a matter of opinion; consistency across strings can help readability more than this lint
- unnecessary_statements
- unnecessary_string_escapes
- unnecessary_string_interpolations
- unnecessary_this
- unrelated_type_equality_checks
- unsafe_html
- use_build_context_synchronously
# - use_colored_box # not yet tested
# - use_decorated_box # not yet tested
# - use_enums # not yet tested
- use_full_hex_values_for_flutter_colors
- use_function_type_syntax_for_parameters
- use_if_null_to_convert_nulls_to_bools
- use_is_even_rather_than_modulo
- use_key_in_widget_constructors
- 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 # has false positives: https://github.com/dart-lang/sdk/issues/34182
- use_super_parameters
- use_test_throws_matchers
# - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review
- valid_regexps
- void_checks

12
zxscanner/lib/configs/app_store.dart

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:zxscanner/utils/shared_pref.dart'; import '../utils/shared_pref.dart';
part 'app_store.g.dart'; part 'app_store.g.dart';
@ -8,11 +8,11 @@ AppStore appStore = AppStore();
class AppStore = AppStoreBase with _$AppStore; class AppStore = AppStoreBase with _$AppStore;
const themeModePref = 'themeModePref'; const String themeModePref = 'themeModePref';
const colorSchemeIndexPref = 'colorSchemeIndexPref'; const String colorSchemeIndexPref = 'colorSchemeIndexPref';
const isSoundOnPref = 'isSoundOnPref'; const String isSoundOnPref = 'isSoundOnPref';
const isVibrationOnPref = 'isVibrationOnPref'; const String isVibrationOnPref = 'isVibrationOnPref';
const languagePref = 'languagePref'; const String languagePref = 'languagePref';
abstract class AppStoreBase with Store { abstract class AppStoreBase with Store {
@observable @observable

20
zxscanner/lib/configs/app_store.g.dart

@ -9,7 +9,7 @@ part of 'app_store.dart';
// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
mixin _$AppStore on AppStoreBase, Store { mixin _$AppStore on AppStoreBase, Store {
final _$themeModeAtom = Atom(name: 'AppStoreBase.themeMode'); final Atom _$themeModeAtom = Atom(name: 'AppStoreBase.themeMode');
@override @override
ThemeMode get themeMode { ThemeMode get themeMode {
@ -24,7 +24,7 @@ mixin _$AppStore on AppStoreBase, Store {
}); });
} }
final _$colorSchemeIndexAtom = Atom(name: 'AppStoreBase.colorSchemeIndex'); final Atom _$colorSchemeIndexAtom = Atom(name: 'AppStoreBase.colorSchemeIndex');
@override @override
int get colorSchemeIndex { int get colorSchemeIndex {
@ -39,7 +39,7 @@ mixin _$AppStore on AppStoreBase, Store {
}); });
} }
final _$isSoundOnAtom = Atom(name: 'AppStoreBase.isSoundOn'); final Atom _$isSoundOnAtom = Atom(name: 'AppStoreBase.isSoundOn');
@override @override
bool get isSoundOn { bool get isSoundOn {
@ -54,7 +54,7 @@ mixin _$AppStore on AppStoreBase, Store {
}); });
} }
final _$isVibrationOnAtom = Atom(name: 'AppStoreBase.isVibrationOn'); final Atom _$isVibrationOnAtom = Atom(name: 'AppStoreBase.isVibrationOn');
@override @override
bool get isVibrationOn { bool get isVibrationOn {
@ -69,7 +69,7 @@ mixin _$AppStore on AppStoreBase, Store {
}); });
} }
final _$selectedLanguageAtom = Atom(name: 'AppStoreBase.selectedLanguage'); final Atom _$selectedLanguageAtom = Atom(name: 'AppStoreBase.selectedLanguage');
@override @override
String get selectedLanguage { String get selectedLanguage {
@ -84,14 +84,14 @@ mixin _$AppStore on AppStoreBase, Store {
}); });
} }
final _$setThemeModeAsyncAction = AsyncAction('AppStoreBase.setThemeMode'); final AsyncAction _$setThemeModeAsyncAction = AsyncAction('AppStoreBase.setThemeMode');
@override @override
Future<void> setThemeMode(ThemeMode value) { Future<void> setThemeMode(ThemeMode value) {
return _$setThemeModeAsyncAction.run(() => super.setThemeMode(value)); return _$setThemeModeAsyncAction.run(() => super.setThemeMode(value));
} }
final _$setColorSchemeIndexAsyncAction = final AsyncAction _$setColorSchemeIndexAsyncAction =
AsyncAction('AppStoreBase.setColorSchemeIndex'); AsyncAction('AppStoreBase.setColorSchemeIndex');
@override @override
@ -100,7 +100,7 @@ mixin _$AppStore on AppStoreBase, Store {
.run(() => super.setColorSchemeIndex(value)); .run(() => super.setColorSchemeIndex(value));
} }
final _$toggleSoundModeAsyncAction = final AsyncAction _$toggleSoundModeAsyncAction =
AsyncAction('AppStoreBase.toggleSoundMode'); AsyncAction('AppStoreBase.toggleSoundMode');
@override @override
@ -109,7 +109,7 @@ mixin _$AppStore on AppStoreBase, Store {
.run(() => super.toggleSoundMode(value: value)); .run(() => super.toggleSoundMode(value: value));
} }
final _$toggleVibrationModeAsyncAction = final AsyncAction _$toggleVibrationModeAsyncAction =
AsyncAction('AppStoreBase.toggleVibrationMode'); AsyncAction('AppStoreBase.toggleVibrationMode');
@override @override
@ -118,7 +118,7 @@ mixin _$AppStore on AppStoreBase, Store {
.run(() => super.toggleVibrationMode(value: value)); .run(() => super.toggleVibrationMode(value: value));
} }
final _$setLanguageAsyncAction = AsyncAction('AppStoreBase.setLanguage'); final AsyncAction _$setLanguageAsyncAction = AsyncAction('AppStoreBase.setLanguage');
@override @override
Future<void> setLanguage(String aLanguage) { Future<void> setLanguage(String aLanguage) {

2
zxscanner/lib/configs/app_theme.dart

@ -8,14 +8,12 @@ class AppTheme {
static ThemeData flexLightTheme() => FlexThemeData.light( static ThemeData flexLightTheme() => FlexThemeData.light(
colors: FlexColor.schemesList[appStore.colorSchemeIndex].light, colors: FlexColor.schemesList[appStore.colorSchemeIndex].light,
tabBarStyle: FlexTabBarStyle.forAppBar,
surfaceMode: FlexSurfaceMode.highScaffoldLevelSurface, surfaceMode: FlexSurfaceMode.highScaffoldLevelSurface,
blendLevel: 12, blendLevel: 12,
); );
static ThemeData flexDarkTheme() => FlexThemeData.dark( static ThemeData flexDarkTheme() => FlexThemeData.dark(
colors: FlexColor.schemesList[appStore.colorSchemeIndex].dark, colors: FlexColor.schemesList[appStore.colorSchemeIndex].dark,
tabBarStyle: FlexTabBarStyle.forAppBar,
surfaceMode: FlexSurfaceMode.highScaffoldLevelSurface, surfaceMode: FlexSurfaceMode.highScaffoldLevelSurface,
blendLevel: 6, blendLevel: 6,
); );

18
zxscanner/lib/configs/constants.dart

@ -1,13 +1,13 @@
const String appName = 'ZXScanner'; const String appName = 'ZXScanner';
/// space between widgets /// space between widgets
const spaceSmall = 2.0; const double spaceSmall = 2.0;
const spaceSmall2 = 4.0; const double spaceSmall2 = 4.0;
const spaceMedium = 8.0; const double spaceMedium = 8.0;
const spaceDefault = 16.0; const double spaceDefault = 16.0;
const spaceLarge = 24.0; const double spaceLarge = 24.0;
const spaceLarge2 = 32.0; const double spaceLarge2 = 32.0;
const spaceLarge3 = 40.0; const double spaceLarge3 = 40.0;
const spaceLarge4 = 96.0; const double spaceLarge4 = 96.0;
const spaceMaxWidth = 736.0; const double spaceMaxWidth = 736.0;

22
zxscanner/lib/generated/intl/messages_all.dart

@ -18,8 +18,10 @@ import 'package:intl/src/intl_helpers.dart';
import 'messages_en_US.dart' as messages_en_us; import 'messages_en_US.dart' as messages_en_us;
typedef Future<dynamic> LibraryLoader(); typedef Future<dynamic> LibraryLoader();
// ignore: always_specify_types
Map<String, LibraryLoader> _deferredLibraries = { Map<String, LibraryLoader> _deferredLibraries = {
'en_US': () => new Future.value(null), // ignore: always_specify_types
'en_US': () => new Future.value(),
}; };
MessageLookupByLibrary? _findExact(String localeName) { MessageLookupByLibrary? _findExact(String localeName) {
@ -33,17 +35,17 @@ MessageLookupByLibrary? _findExact(String localeName) {
/// User programs should call this before using [localeName] for messages. /// User programs should call this before using [localeName] for messages.
Future<bool> initializeMessages(String localeName) async { Future<bool> initializeMessages(String localeName) async {
var availableLocale = Intl.verifiedLocale( final String? availableLocale = Intl.verifiedLocale(
localeName, (locale) => _deferredLibraries[locale] != null, localeName, (String locale) => _deferredLibraries[locale] != null,
onFailure: (_) => null); onFailure: (_) => null);
if (availableLocale == null) { if (availableLocale == null) {
return new Future.value(false); return new Future<bool>.value(false);
} }
var lib = _deferredLibraries[availableLocale]; final LibraryLoader? lib = _deferredLibraries[availableLocale];
await (lib == null ? new Future.value(false) : lib()); await (lib == null ? new Future<bool>.value(false) : lib());
initializeInternalMessageLookup(() => new CompositeMessageLookup()); initializeInternalMessageLookup(() => new CompositeMessageLookup());
messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
return new Future.value(true); return new Future<bool>.value(true);
} }
bool _messagesExistFor(String locale) { bool _messagesExistFor(String locale) {
@ -55,8 +57,10 @@ bool _messagesExistFor(String locale) {
} }
MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) {
var actualLocale = final String? actualLocale =
Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null);
if (actualLocale == null) return null; if (actualLocale == null) {
return null;
}
return _findExact(actualLocale); return _findExact(actualLocale);
} }

4
zxscanner/lib/generated/intl/messages_en_US.dart

@ -13,14 +13,14 @@
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/message_lookup_by_library.dart';
final messages = new MessageLookup(); final MessageLookup messages = new MessageLookup();
typedef String MessageIfAbsent(String messageStr, List<dynamic> args); typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
class MessageLookup extends MessageLookupByLibrary { class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'en_US'; String get localeName => 'en_US';
final messages = _notInlinedMessages(_notInlinedMessages); final Map<String, Function> messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{ static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"settingsAppBarTitle": MessageLookupByLibrary.simpleMessage("Settings"), "settingsAppBarTitle": MessageLookupByLibrary.simpleMessage("Settings"),
"settingsLanguageTitle": "settingsLanguageTitle":

13
zxscanner/lib/generated/l10n.dart

@ -26,13 +26,13 @@ class S {
static const AppLocalizationDelegate delegate = AppLocalizationDelegate(); static const AppLocalizationDelegate delegate = AppLocalizationDelegate();
static Future<S> load(Locale locale) { static Future<S> load(Locale locale) {
final name = (locale.countryCode?.isEmpty ?? false) final String name = (locale.countryCode?.isEmpty ?? false)
? locale.languageCode ? locale.languageCode
: locale.toString(); : locale.toString();
final localeName = Intl.canonicalizedLocale(name); final String localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) { return initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName; Intl.defaultLocale = localeName;
final instance = S(); final S instance = S();
S._current = instance; S._current = instance;
return instance; return instance;
@ -40,7 +40,7 @@ class S {
} }
static S of(BuildContext context) { static S of(BuildContext context) {
final instance = S.maybeOf(context); final S? instance = S.maybeOf(context);
assert(instance != null, assert(instance != null,
'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?'); 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?');
return instance!; return instance!;
@ -56,7 +56,6 @@ class S {
'Settings', 'Settings',
name: 'settingsAppBarTitle', name: 'settingsAppBarTitle',
desc: '', desc: '',
args: [],
); );
} }
@ -66,7 +65,6 @@ class S {
'Theme', 'Theme',
name: 'settingsThemeModeTitle', name: 'settingsThemeModeTitle',
desc: '', desc: '',
args: [],
); );
} }
@ -76,7 +74,6 @@ class S {
'Language', 'Language',
name: 'settingsLanguageTitle', name: 'settingsLanguageTitle',
desc: '', desc: '',
args: [],
); );
} }
} }
@ -98,7 +95,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate<S> {
bool shouldReload(AppLocalizationDelegate old) => false; bool shouldReload(AppLocalizationDelegate old) => false;
bool _isSupported(Locale locale) { bool _isSupported(Locale locale) {
for (var supportedLocale in supportedLocales) { for (Locale supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode) { if (supportedLocale.languageCode == locale.languageCode) {
return true; return true;
} }

14
zxscanner/lib/main.dart

@ -3,16 +3,16 @@ import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_zxing/flutter_zxing.dart'; import 'package:flutter_zxing/flutter_zxing.dart';
import 'package:zxscanner/configs/constants.dart';
import 'package:zxscanner/utils/db_service.dart';
import 'package:zxscanner/utils/extensions.dart';
import 'package:zxscanner/utils/shared_pref.dart';
import 'configs/app_store.dart'; import 'configs/app_store.dart';
import 'configs/app_theme.dart'; import 'configs/app_theme.dart';
import 'configs/constants.dart';
import 'generated/l10n.dart' as loc; import 'generated/l10n.dart' as loc;
import 'utils/db_service.dart';
import 'utils/extensions.dart';
import 'utils/router.dart'; import 'utils/router.dart';
import 'utils/scroll_behavior.dart'; import 'utils/scroll_behavior.dart';
import 'utils/shared_pref.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@ -23,14 +23,14 @@ void main() async {
} }
class MyApp extends StatefulWidget { class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key); const MyApp({super.key});
@override @override
State<MyApp> createState() => _MyAppState(); State<MyApp> createState() => _MyAppState();
} }
class _MyAppState extends State<MyApp> { class _MyAppState extends State<MyApp> {
final _appRouter = AppRouter(); final AppRouter _appRouter = AppRouter();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -40,7 +40,7 @@ class _MyAppState extends State<MyApp> {
theme: AppTheme.flexLightTheme(), theme: AppTheme.flexLightTheme(),
darkTheme: AppTheme.flexDarkTheme(), darkTheme: AppTheme.flexDarkTheme(),
themeMode: appStore.themeMode, themeMode: appStore.themeMode,
localizationsDelegates: const [ localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
loc.S.delegate, loc.S.delegate,
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,

16
zxscanner/lib/models/code.dart

@ -5,14 +5,6 @@ part 'code.g.dart';
@HiveType(typeId: 0) @HiveType(typeId: 0)
class Code extends HiveObject { class Code extends HiveObject {
@HiveField(0)
bool? isValid;
@HiveField(1)
int? format;
@HiveField(2)
String? text;
Code(); Code();
@ -21,6 +13,14 @@ class Code extends HiveObject {
format = result.format; format = result.format;
text = result.textString; text = result.textString;
} }
@HiveField(0)
bool? isValid;
@HiveField(1)
int? format;
@HiveField(2)
String? text;
String get formatName => barcodeFormatName(format ?? 0); String get formatName => barcodeFormatName(format ?? 0);
} }

4
zxscanner/lib/models/code.g.dart

@ -12,8 +12,8 @@ class CodeAdapter extends TypeAdapter<Code> {
@override @override
Code read(BinaryReader reader) { Code read(BinaryReader reader) {
final numOfFields = reader.readByte(); final int numOfFields = reader.readByte();
final fields = <int, dynamic>{ final Map<int, dynamic> fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
}; };
return Code() return Code()

20
zxscanner/lib/models/encode.dart

@ -7,6 +7,16 @@ part 'encode.g.dart';
@HiveType(typeId: 1) @HiveType(typeId: 1)
class Encode extends HiveObject { class Encode extends HiveObject {
Encode();
Encode.fromEncodeResult(EncodeResult result, Uint8List? bytes) {
isValid = result.isValidBool;
format = result.format;
text = result.textString;
data = bytes;
length = result.length;
}
@HiveField(0) @HiveField(0)
bool? isValid; bool? isValid;
@ -22,15 +32,5 @@ class Encode extends HiveObject {
@HiveField(4) @HiveField(4)
int? length; int? length;
Encode();
Encode.fromEncodeResult(EncodeResult result, Uint8List? bytes) {
isValid = result.isValidBool;
format = result.format;
text = result.textString;
data = bytes;
length = result.length;
}
String get formatName => barcodeFormatName(format ?? 0); String get formatName => barcodeFormatName(format ?? 0);
} }

4
zxscanner/lib/models/encode.g.dart

@ -12,8 +12,8 @@ class EncodeAdapter extends TypeAdapter<Encode> {
@override @override
Encode read(BinaryReader reader) { Encode read(BinaryReader reader) {
final numOfFields = reader.readByte(); final int numOfFields = reader.readByte();
final fields = <int, dynamic>{ final Map<int, dynamic> fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
}; };
return Encode() return Encode()

25
zxscanner/lib/pages/barcodes_page.dart

@ -2,17 +2,18 @@ import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:zxscanner/models/models.dart';
import 'package:zxscanner/utils/db_service.dart';
import 'package:zxscanner/utils/router.dart';
import 'package:zxscanner/widgets/common_widgets.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import '../models/models.dart';
import '../utils/db_service.dart';
import '../utils/router.dart';
import '../widgets/common_widgets.dart';
class BarcodesPage extends StatefulWidget { class BarcodesPage extends StatefulWidget {
const BarcodesPage({ const BarcodesPage({
Key? key, super.key,
}) : super(key: key); });
@override @override
State<BarcodesPage> createState() => _BarcodesPageState(); State<BarcodesPage> createState() => _BarcodesPageState();
@ -35,11 +36,11 @@ class _BarcodesPageState extends State<BarcodesPage> {
); );
} }
_buildResultList() { ValueListenableBuilder<Box<Encode>> _buildResultList() {
return ValueListenableBuilder<Box<Encode>>( return ValueListenableBuilder<Box<Encode>>(
valueListenable: DbService.instance.getEncodes().listenable(), valueListenable: DbService.instance.getEncodes().listenable(),
builder: (context, box, _) { builder: (BuildContext context, Box<Encode> box, _) {
final results = box.values.toList().cast<Encode>(); final List<Encode> results = box.values.toList().cast<Encode>();
return results.isEmpty return results.isEmpty
? const Center( ? const Center(
child: Text( child: Text(
@ -48,8 +49,8 @@ class _BarcodesPageState extends State<BarcodesPage> {
)) ))
: ListView.builder( : ListView.builder(
itemCount: results.length, itemCount: results.length,
itemBuilder: (context, index) { itemBuilder: (BuildContext context, int index) {
final result = results[index]; final Encode result = results[index];
return ContainerX( return ContainerX(
child: Card( child: Card(
child: ListTile( child: ListTile(
@ -61,7 +62,7 @@ class _BarcodesPageState extends State<BarcodesPage> {
subtitle: Text(result.formatName), subtitle: Text(result.formatName),
trailing: ButtonBar( trailing: ButtonBar(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: <Widget>[
// Copy button // Copy button
IconButton( IconButton(
icon: const Icon(FontAwesomeIcons.copy), icon: const Icon(FontAwesomeIcons.copy),

40
zxscanner/lib/pages/creator_page.dart

@ -3,21 +3,22 @@ import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_zxing/flutter_zxing.dart'; import 'package:flutter_zxing/flutter_zxing.dart';
import 'package:zxscanner/configs/constants.dart';
import 'package:zxscanner/models/encode.dart';
import 'package:zxscanner/utils/db_service.dart';
import 'package:zxscanner/utils/extensions.dart';
import 'package:zxscanner/widgets/common_widgets.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import '../configs/constants.dart';
import '../models/encode.dart';
import '../utils/db_service.dart';
import '../utils/extensions.dart';
import '../widgets/common_widgets.dart';
late Directory tempDir; late Directory tempDir;
String get tempPath => '${tempDir.path}/zxing.jpg'; String get tempPath => '${tempDir.path}/zxing.jpg';
class CreatorPage extends StatefulWidget { class CreatorPage extends StatefulWidget {
const CreatorPage({ const CreatorPage({
Key? key, super.key,
}) : super(key: key); });
@override @override
State<CreatorPage> createState() => _CreatorPageState(); State<CreatorPage> createState() => _CreatorPageState();
@ -36,8 +37,8 @@ class _CreatorPageState extends State<CreatorPage> {
initStateAsync(); initStateAsync();
} }
void initStateAsync() async { Future<void> initStateAsync() async {
getTemporaryDirectory().then((value) { getTemporaryDirectory().then((Directory value) {
tempDir = value; tempDir = value;
}); });
} }
@ -51,14 +52,14 @@ class _CreatorPageState extends State<CreatorPage> {
body: SingleChildScrollView( body: SingleChildScrollView(
child: ContainerX( child: ContainerX(
child: Column( child: Column(
children: [ children: <Widget>[
WriterWidget( WriterWidget(
onSuccess: (result, bytes) { onSuccess: (EncodeResult result, Uint8List? bytes) {
setState(() { setState(() {
encode = Encode.fromEncodeResult(result, bytes); encode = Encode.fromEncodeResult(result, bytes);
}); });
}, },
onError: (error) { onError: (String error) {
setState(() { setState(() {
encode = null; encode = null;
}); });
@ -75,23 +76,22 @@ class _CreatorPageState extends State<CreatorPage> {
Column buildWriteResult() { Column buildWriteResult() {
return Column( return Column(
children: [ children: <Widget>[
// Barcode image // Barcode image
if (encode?.data != null) Image.memory(encode?.data ?? Uint8List(0)), if (encode?.data != null) Image.memory(encode?.data ?? Uint8List(0)),
const SizedBox(height: spaceLarge), const SizedBox(height: spaceLarge),
// Share button // Share button
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[
children: [
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
// Save image to device // Save image to device
final file = File(tempPath); final File file = File(tempPath);
file.writeAsBytesSync(encode?.data ?? Uint8List(0)); file.writeAsBytesSync(encode?.data ?? Uint8List(0));
final path = file.path; final String path = file.path;
// Share image // Share image
Share.shareFiles([path]); Share.shareFiles(<String>[path]);
}, },
child: const Text('Share'), child: const Text('Share'),
), ),
@ -99,7 +99,9 @@ class _CreatorPageState extends State<CreatorPage> {
onPressed: () async { onPressed: () async {
if (encode != null) { if (encode != null) {
await DbService.instance.addEncode(encode!); await DbService.instance.addEncode(encode!);
if (!mounted) return; if (!mounted) {
return;
}
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
}, },

62
zxscanner/lib/pages/help_page.dart

@ -1,11 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
import 'package:zxscanner/configs/constants.dart'; import '../configs/constants.dart';
import 'package:zxscanner/widgets/common_widgets.dart'; import '../widgets/common_widgets.dart';
class HelpPage extends StatelessWidget { class HelpPage extends StatelessWidget {
const HelpPage({Key? key}) : super(key: key); const HelpPage({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -15,7 +15,7 @@ class HelpPage extends StatelessWidget {
), ),
body: ContainerX( body: ContainerX(
child: Column( child: Column(
children: [ children: <Widget>[
Padding( Padding(
padding: const EdgeInsets.all(spaceDefault), padding: const EdgeInsets.all(spaceDefault),
child: InkWell( child: InkWell(
@ -23,10 +23,12 @@ class HelpPage extends StatelessWidget {
launchUrlString('https://scanbot.io'); launchUrlString('https://scanbot.io');
}, },
child: Column( child: Column(
children: const [ children: const <Widget>[
Text('All information is taken from'), Text('All information is taken from'),
Text('scanbot.io', Text(
style: TextStyle(fontWeight: FontWeight.bold)), 'scanbot.io',
style: TextStyle(fontWeight: FontWeight.bold),
),
], ],
), ),
), ),
@ -58,7 +60,7 @@ class HelpPage extends StatelessWidget {
), ),
child: ExpansionTile( child: ExpansionTile(
title: Text(title ?? ''), title: Text(title ?? ''),
children: [ children: <Widget>[
Padding( Padding(
padding: const EdgeInsets.all(spaceDefault), padding: const EdgeInsets.all(spaceDefault),
child: MarkdownBody(data: body ?? ''), child: MarkdownBody(data: body ?? ''),
@ -70,23 +72,23 @@ class HelpPage extends StatelessWidget {
); );
} }
createSlides(BuildContext context) { List<Widget> createSlides(BuildContext context) {
return [ return <Widget>[
createSlide( createSlide(
context, context,
title: 'QR Code', title: 'QR Code',
body: """ body: '''
QR codes are highly versatile and cover a range of applications because they store a large amount of information in a relatively small area. They are particularly popular in advertising, such as on flyers or shop windows, in public transport and airline ticketing, and in parcel delivery. QR codes are highly versatile and cover a range of applications because they store a large amount of information in a relatively small area. They are particularly popular in advertising, such as on flyers or shop windows, in public transport and airline ticketing, and in parcel delivery.
* Defined in the ISO/IEC 18004:2006 and JIS X0510 standards. * Defined in the ISO/IEC 18004:2006 and JIS X0510 standards.
* 2D barcode that stores a maximum of 7089 digits or 4296 alphanumeric characters. * 2D barcode that stores a maximum of 7089 digits or 4296 alphanumeric characters.
* Can be used free of charge specifications are available from the Swiss-based International Organization for Standardization. * Can be used free of charge specifications are available from the Swiss-based International Organization for Standardization.
* Automatic error correction recovers damage to up to 30%, depending on the correction level chosen. * Automatic error correction recovers damage to up to 30%, depending on the correction level chosen.
""", ''',
), ),
createSlide( createSlide(
context, context,
title: 'DataMatrix', title: 'DataMatrix',
body: """ body: '''
Due to its small size and large storage capacity, the Data Matrix code is most frequently used in the aerospace, automotive, and electronics sectors. Applied through permanent marking, the code can identify spare parts over their whole lifespan. It also has applications in healthcare and postal services. Due to its small size and large storage capacity, the Data Matrix code is most frequently used in the aerospace, automotive, and electronics sectors. Applied through permanent marking, the code can identify spare parts over their whole lifespan. It also has applications in healthcare and postal services.
* 2D barcode with L-shaped border and pixel matrix. * 2D barcode with L-shaped border and pixel matrix.
* Defined in the ISO/IEC 16022 standard. * Defined in the ISO/IEC 16022 standard.
@ -94,12 +96,12 @@ Due to its small size and large storage capacity, the Data Matrix code is most f
* Smallest size: 2.5 mm x 2.5 mm, thus ideal for small units. * Smallest size: 2.5 mm x 2.5 mm, thus ideal for small units.
* Often engraved on items via Direct Part Marking (DPM). * Often engraved on items via Direct Part Marking (DPM).
* Readable even with low contrast. * Readable even with low contrast.
""", ''',
), ),
createSlide( createSlide(
context, context,
title: 'Aztec', title: 'Aztec',
body: """ body: '''
The transportation sector accounts for most Aztec Code use cases. Lufthansa airline tickets contain this code, as do Deutsche Bahn tickets. The International Union of Railways (UIC) has chosen the Aztec Code as its standard for ticketing. Additionally, Aztec Codes are used in the healthcare sector, notably on patient identification bracelets. The transportation sector accounts for most Aztec Code use cases. Lufthansa airline tickets contain this code, as do Deutsche Bahn tickets. The International Union of Railways (UIC) has chosen the Aztec Code as its standard for ticketing. Additionally, Aztec Codes are used in the healthcare sector, notably on patient identification bracelets.
* Two-dimensional barcode, standardized in ISO/IEC 24778. * Two-dimensional barcode, standardized in ISO/IEC 24778.
* Freely available under US patent number 5591956. * Freely available under US patent number 5591956.
@ -107,7 +109,7 @@ The transportation sector accounts for most Aztec Code use cases. Lufthansa airl
* Less widely used than QR and Data Matrix Codes. * Less widely used than QR and Data Matrix Codes.
* Enables both high data density and up to 95% error tolerance. * Enables both high data density and up to 95% error tolerance.
* Pattern resembles a top-down view of an Aztec pyramid * Pattern resembles a top-down view of an Aztec pyramid
""", ''',
), ),
createSlide( createSlide(
context, context,
@ -124,75 +126,75 @@ Ticketing, travel, and logistics are some of the most common areas of applicatio
createSlide( createSlide(
context, context,
title: 'UPCA, UPCE', title: 'UPCA, UPCE',
body: """ body: '''
The Universal Product Code (UPC) is perfect for retail, warehousing, and distribution. Stores or warehouses use it in combination with their databases to assign individual prices or quantities to the coded products. Since the price is explicitly not part of the barcode, retail stores can set prices independently using their checkout system. The Universal Product Code (UPC) is perfect for retail, warehousing, and distribution. Stores or warehouses use it in combination with their databases to assign individual prices or quantities to the coded products. Since the price is explicitly not part of the barcode, retail stores can set prices independently using their checkout system.
* Exclusively used within North America. * Exclusively used within North America.
* One-dimensional barcode that stores exactly 12 numeric characters, which form the Global Trade Item Number (GTIN). * One-dimensional barcode that stores exactly 12 numeric characters, which form the Global Trade Item Number (GTIN).
* The low data density makes it inadequate for encoding complex data. * The low data density makes it inadequate for encoding complex data.
""", ''',
), ),
createSlide( createSlide(
context, context,
title: 'EAN8, EAN13', title: 'EAN8, EAN13',
body: """ body: '''
The most important areas of application for EAN codes are retail, distribution, and warehousing. The EAN short for European Article Number is used to identify individual products, which can then be linked to quantities or prices in the stores database. Since they can only store a limited amount of data, EAN codes are not suitable for the kind of complex information seen in ticketing or parcel shipping. The most important areas of application for EAN codes are retail, distribution, and warehousing. The EAN short for European Article Number is used to identify individual products, which can then be linked to quantities or prices in the stores database. Since they can only store a limited amount of data, EAN codes are not suitable for the kind of complex information seen in ticketing or parcel shipping.
* Used worldwide despite the name, except for North America, which uses the UPC standard. * Used worldwide despite the name, except for North America, which uses the UPC standard.
* Stores either 13 or 8 digits (EAN-13 vs. EAN-8), which encode a GTIN (Global Trade Identification Number). * Stores either 13 or 8 digits (EAN-13 vs. EAN-8), which encode a GTIN (Global Trade Identification Number).
* The last digit is a mod10 checksum. * The last digit is a mod10 checksum.
* EAN codes are defined as GS1 standards. * EAN codes are defined as GS1 standards.
""", ''',
), ),
createSlide( createSlide(
context, context,
title: 'Code39', title: 'Code39',
body: """ body: '''
Unlike other common barcodes, Code 39 can also encode letters, which makes it indispensable in the industrial sector. A frequent use case is in factory automation in the automotive and electronics industries. In the US, it was standardized and adopted by the AIAG (Automotive Industry Action Group). Unlike other common barcodes, Code 39 can also encode letters, which makes it indispensable in the industrial sector. A frequent use case is in factory automation in the automotive and electronics industries. In the US, it was standardized and adopted by the AIAG (Automotive Industry Action Group).
* One-dimensional barcode that encodes 43 characters: uppercase letters, numeric digits, and a number of special characters. * One-dimensional barcode that encodes 43 characters: uppercase letters, numeric digits, and a number of special characters.
* Self-checking. However, a modulo 43 check digit is sometimes included. * Self-checking. However, a modulo 43 check digit is sometimes included.
* The low data density makes it unsuitable for tiny items. * The low data density makes it unsuitable for tiny items.
* Standardized as ANSI MH 10.8 M-1983 and ANSI/AIM BC1/1995. * Standardized as ANSI MH 10.8 M-1983 and ANSI/AIM BC1/1995.
""", ''',
), ),
createSlide( createSlide(
context, context,
title: 'Code93', title: 'Code93',
body: """ body: '''
This barcode symbology can store alphanumeric characters. Its main user, Canada Post, encodes supplementary delivery information with it. This barcode symbology can store alphanumeric characters. Its main user, Canada Post, encodes supplementary delivery information with it.
* One-dimensional barcode encoding 43 alphanumeric characters and 5 special characters. * One-dimensional barcode encoding 43 alphanumeric characters and 5 special characters.
* In Code 93 Extended, combinations of those characters can represent all 128 ASCII characters. * In Code 93 Extended, combinations of those characters can represent all 128 ASCII characters.
""", ''',
), ),
createSlide( createSlide(
context, context,
title: 'Code128', title: 'Code128',
body: """ body: '''
The Code 128 barcode is most frequently used in transporting goods, especially to mark containers for distribution, and warehousing. With it, various kinds of information about the respective goods can be flexibly encoded and read with a wide range of conventional scanners or smartphones. Its focus is clearly on non-POS areas. Check out our Barcode Scanner for logistics to learn more about possible application among the transportation area. The Code 128 barcode is most frequently used in transporting goods, especially to mark containers for distribution, and warehousing. With it, various kinds of information about the respective goods can be flexibly encoded and read with a wide range of conventional scanners or smartphones. Its focus is clearly on non-POS areas. Check out our Barcode Scanner for logistics to learn more about possible application among the transportation area.
* A one-dimensional barcode defined in the ISO/IEC 15417 standard. * A one-dimensional barcode defined in the ISO/IEC 15417 standard.
* Can encode all ASCII characters, including special characters. * Can encode all ASCII characters, including special characters.
* High data density compared to other 1D barcode formats. * High data density compared to other 1D barcode formats.
""", ''',
), ),
createSlide( createSlide(
context, context,
title: 'CodaBar', title: 'CodaBar',
body: """ body: '''
The Codabar barcode is only used in blood banks, libraries, and in laboratories. The Codabar barcode is only used in blood banks, libraries, and in laboratories.
* 1D (linear) barcode type. * 1D (linear) barcode type.
* Self-checking, with no need for a check digit. * Self-checking, with no need for a check digit.
* Encodes alphanumeric characters, as well as six special characters. * Encodes alphanumeric characters, as well as six special characters.
* Stores up to 16 characters. * Stores up to 16 characters.
* Newer barcode types can store more data in less space. * Newer barcode types can store more data in less space.
""", ''',
), ),
createSlide( createSlide(
context, context,
title: 'ITF', title: 'ITF',
body: """ body: '''
ITF barcodes are often described as Standard Distribution Codes. They are frequently found on cardboard boxes and other kinds of outer packaging. ITF barcodes are often described as Standard Distribution Codes. They are frequently found on cardboard boxes and other kinds of outer packaging.
* One-dimensional barcodes that encode two numerical characters for every five bars. * One-dimensional barcodes that encode two numerical characters for every five bars.
* High data density, as data is stored in both the bars and the gaps.  * High data density, as data is stored in both the bars and the gaps. 
* Compared to other linear barcodes, more data can be accommodated using the same label size. * Compared to other linear barcodes, more data can be accommodated using the same label size.
""", ''',
), ),
]; ];
} }

23
zxscanner/lib/pages/history_page.dart

@ -1,15 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:zxscanner/models/code.dart';
import 'package:zxscanner/utils/db_service.dart';
import 'package:zxscanner/widgets/common_widgets.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import '../models/code.dart';
import '../utils/db_service.dart';
import '../widgets/common_widgets.dart';
class HistoryPage extends StatefulWidget { class HistoryPage extends StatefulWidget {
const HistoryPage({ const HistoryPage({
Key? key, super.key,
}) : super(key: key); });
@override @override
State<HistoryPage> createState() => _HistoryPageState(); State<HistoryPage> createState() => _HistoryPageState();
@ -26,11 +27,11 @@ class _HistoryPageState extends State<HistoryPage> {
); );
} }
_buildResultList() { ValueListenableBuilder<Box<Code>> _buildResultList() {
return ValueListenableBuilder<Box<Code>>( return ValueListenableBuilder<Box<Code>>(
valueListenable: DbService.instance.getCodes().listenable(), valueListenable: DbService.instance.getCodes().listenable(),
builder: (context, box, _) { builder: (BuildContext context, Box<Code> box, _) {
final results = box.values.toList().cast<Code>(); final List<Code> results = box.values.toList().cast<Code>();
return results.isEmpty return results.isEmpty
? const Center( ? const Center(
child: Text( child: Text(
@ -39,8 +40,8 @@ class _HistoryPageState extends State<HistoryPage> {
)) ))
: ListView.builder( : ListView.builder(
itemCount: results.length, itemCount: results.length,
itemBuilder: (context, index) { itemBuilder: (BuildContext context, int index) {
final result = results[index]; final Code result = results[index];
return ContainerX( return ContainerX(
child: Card( child: Card(
child: ListTile( child: ListTile(
@ -48,7 +49,7 @@ class _HistoryPageState extends State<HistoryPage> {
subtitle: Text(result.formatName), subtitle: Text(result.formatName),
trailing: ButtonBar( trailing: ButtonBar(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: <Widget>[
// Copy button // Copy button
IconButton( IconButton(
icon: const Icon(FontAwesomeIcons.copy), icon: const Icon(FontAwesomeIcons.copy),

42
zxscanner/lib/pages/home_page.dart

@ -1,29 +1,30 @@
import 'package:convex_bottom_bar/convex_bottom_bar.dart'; import 'package:convex_bottom_bar/convex_bottom_bar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:zxscanner/pages/barcodes_page.dart';
import 'package:zxscanner/pages/help_page.dart';
import 'package:zxscanner/pages/history_page.dart';
import 'package:zxscanner/pages/scanner_page.dart';
import 'package:zxscanner/pages/settings_page.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'barcodes_page.dart';
import 'help_page.dart';
import 'history_page.dart';
import 'scanner_page.dart';
import 'settings_page.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key); const HomePage({super.key});
@override @override
State<HomePage> createState() => _HomePageState(); State<HomePage> createState() => _HomePageState();
} }
class _HomePageState extends State<HomePage> { class _HomePageState extends State<HomePage> {
var selectedIndex = 2; int selectedIndex = 2;
final barcodesPage = const BarcodesPage(); final BarcodesPage barcodesPage = const BarcodesPage();
final historyPage = const HistoryPage(); final HistoryPage historyPage = const HistoryPage();
final scannerPage = const ScannerPage(); final ScannerPage scannerPage = const ScannerPage();
final helpPage = const HelpPage(); final HelpPage helpPage = const HelpPage();
final settingsPage = const SettingsPage(); final SettingsPage settingsPage = const SettingsPage();
dynamic pages() => [ dynamic pages() => <dynamic>[
barcodesPage, barcodesPage,
historyPage, historyPage,
scannerPage, scannerPage,
@ -31,17 +32,18 @@ class _HomePageState extends State<HomePage> {
settingsPage, settingsPage,
]; ];
dynamic tabItems() => [ dynamic tabItems() => <TabItem<IconData>>[
const TabItem(icon: FontAwesomeIcons.barcode), const TabItem<IconData>(icon: FontAwesomeIcons.barcode),
const TabItem(icon: FontAwesomeIcons.clockRotateLeft), const TabItem<IconData>(icon: FontAwesomeIcons.clockRotateLeft),
const TabItem(icon: Icons.qr_code_scanner), const TabItem<IconData>(icon: Icons.qr_code_scanner),
const TabItem(icon: FontAwesomeIcons.circleQuestion), const TabItem<IconData>(icon: FontAwesomeIcons.circleQuestion),
const TabItem(icon: FontAwesomeIcons.gear), const TabItem<IconData>(icon: FontAwesomeIcons.gear),
]; ];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
// ignore: avoid_dynamic_calls
body: pages()[selectedIndex], body: pages()[selectedIndex],
bottomNavigationBar: ConvexAppBar( bottomNavigationBar: ConvexAppBar(
style: TabStyle.fixedCircle, style: TabStyle.fixedCircle,
@ -50,7 +52,7 @@ class _HomePageState extends State<HomePage> {
activeColor: Theme.of(context).colorScheme.primary, activeColor: Theme.of(context).colorScheme.primary,
items: tabItems(), items: tabItems(),
initialActiveIndex: selectedIndex, initialActiveIndex: selectedIndex,
onTap: (index) { onTap: (int index) {
setState(() { setState(() {
selectedIndex = index; selectedIndex = index;
}); });

22
zxscanner/lib/pages/scanner_page.dart

@ -1,15 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_zxing/flutter_zxing.dart'; import 'package:flutter_zxing/flutter_zxing.dart';
import 'package:zxscanner/models/models.dart';
import 'package:zxscanner/utils/db_service.dart';
import 'package:zxscanner/utils/extensions.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import '../models/models.dart';
import '../utils/db_service.dart';
import '../utils/extensions.dart';
class ScannerPage extends StatefulWidget { class ScannerPage extends StatefulWidget {
const ScannerPage({ const ScannerPage({
Key? key, super.key,
}) : super(key: key); });
@override @override
State<ScannerPage> createState() => _ScannerPageState(); State<ScannerPage> createState() => _ScannerPageState();
@ -25,7 +26,7 @@ class _ScannerPageState extends State<ScannerPage> {
title: const Text('Scanner'), title: const Text('Scanner'),
), ),
body: ReaderWidget( body: ReaderWidget(
onScan: (result) async { onScan: (CodeResult result) async {
addCode(result); addCode(result);
}, },
), ),
@ -36,6 +37,7 @@ class _ScannerPageState extends State<ScannerPage> {
); );
} }
// ignore: always_declare_return_types
pickImage() async { pickImage() async {
try { try {
final XFile? file = await _picker.pickImage(source: ImageSource.gallery); final XFile? file = await _picker.pickImage(source: ImageSource.gallery);
@ -48,18 +50,20 @@ class _ScannerPageState extends State<ScannerPage> {
} }
} }
readCodeFromImage(XFile file) async { Future<void> readCodeFromImage(XFile file) async {
final CodeResult? result = await readBarcodeImagePath(file); final CodeResult? result = await readBarcodeImagePath(file);
if (result != null && result.isValidBool) { if (result != null && result.isValidBool) {
addCode(result); addCode(result);
} else { } else {
if (!mounted) return; if (!mounted) {
return;
}
context.showToast('No code found'); context.showToast('No code found');
} }
} }
void addCode(CodeResult result) { void addCode(CodeResult result) {
Code code = Code.fromCodeResult(result); final Code code = Code.fromCodeResult(result);
DbService.instance.addCode(code); DbService.instance.addCode(code);
context.showToast('Code added:\n${code.text ?? ''}'); context.showToast('Code added:\n${code.text ?? ''}');
} }

14
zxscanner/lib/pages/settings_page.dart

@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:zxscanner/configs/app_store.dart'; import '../configs/app_store.dart';
import 'package:zxscanner/configs/constants.dart'; import '../configs/constants.dart';
import 'package:zxscanner/generated/l10n.dart'; import '../generated/l10n.dart';
import 'package:zxscanner/widgets/common_widgets.dart'; import '../widgets/common_widgets.dart';
// import 'package:font_awesome_flutter/font_awesome_flutter.dart'; // import 'package:font_awesome_flutter/font_awesome_flutter.dart';
@ -12,7 +12,7 @@ import '../widgets/theme_mode_switch.dart';
import '../widgets/theme_selector.dart'; import '../widgets/theme_selector.dart';
class SettingsPage extends StatefulWidget { class SettingsPage extends StatefulWidget {
const SettingsPage({Key? key}) : super(key: key); const SettingsPage({super.key});
@override @override
State<SettingsPage> createState() => _SettingsPageState(); State<SettingsPage> createState() => _SettingsPageState();
@ -28,7 +28,7 @@ class _SettingsPageState extends State<SettingsPage> {
body: SingleChildScrollView( body: SingleChildScrollView(
child: ContainerX( child: ContainerX(
child: Column( child: Column(
children: [ children: <Widget>[
const SizedBox(height: spaceDefault), const SizedBox(height: spaceDefault),
const Padding( const Padding(
padding: EdgeInsets.symmetric(horizontal: spaceDefault), padding: EdgeInsets.symmetric(horizontal: spaceDefault),
@ -40,7 +40,7 @@ class _SettingsPageState extends State<SettingsPage> {
title: S.current.settingsThemeModeTitle, title: S.current.settingsThemeModeTitle,
trailing: ThemeModeSwitch( trailing: ThemeModeSwitch(
themeMode: appStore.themeMode, themeMode: appStore.themeMode,
onChanged: (mode) { onChanged: (ThemeMode mode) {
appStore.setThemeMode(mode); appStore.setThemeMode(mode);
setState(() {}); setState(() {});
}, },

29
zxscanner/lib/utils/db_service.dart

@ -1,6 +1,7 @@
import 'package:zxscanner/models/models.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import '../models/models.dart';
class DbService { class DbService {
DbService._privateConstructor(); DbService._privateConstructor();
@ -17,44 +18,42 @@ class DbService {
Box<Code> getCodes() => Hive.box<Code>('codes'); Box<Code> getCodes() => Hive.box<Code>('codes');
Future deleteCodes() async { Future<void> deleteCodes() async {
var items = getCodes(); final Box<Code> items = getCodes();
await items.deleteAll(items.keys); await items.deleteAll(items.keys);
return;
} }
Future addCode(Code value) async { Future<int> addCode(Code value) async {
var items = getCodes(); final Box<Code> items = getCodes();
if (!items.values.contains(value)) { if (!items.values.contains(value)) {
return items.add(value); return items.add(value);
} }
return; return -1;
} }
Future<void> deleteCode(Code value) async { Future<void> deleteCode(Code value) async {
var items = getCodes(); final Box<Code> items = getCodes();
await items.delete(value.key); await items.delete(value.key);
return; return;
} }
Box<Encode> getEncodes() => Hive.box<Encode>('encodes'); Box<Encode> getEncodes() => Hive.box<Encode>('encodes');
Future deleteEncodes() async { Future<void> deleteEncodes() async {
var items = getEncodes(); final Box<Encode> items = getEncodes();
await items.deleteAll(items.keys); await items.deleteAll(items.keys);
return;
} }
Future addEncode(Encode value) async { Future<int> addEncode(Encode value) async {
var items = getEncodes(); final Box<Encode> items = getEncodes();
if (!items.values.contains(value)) { if (!items.values.contains(value)) {
return items.add(value); return items.add(value);
} }
return; return -1;
} }
Future<void> deleteEncode(Encode value) async { Future<void> deleteEncode(Encode value) async {
var items = getEncodes(); final Box<Encode> items = getEncodes();
await items.delete(value.key); await items.delete(value.key);
return; return;
} }

4
zxscanner/lib/utils/extensions.dart

@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
extension LocaleParsing on String { extension LocaleParsing on String {
Locale parseLocale() { Locale parseLocale() {
assert(contains('_') == true); assert(contains('_') == true);
var languageCode = split('_').first; final String languageCode = split('_').first;
var countryCode = split('_').last; final String countryCode = split('_').last;
return Locale.fromSubtags( return Locale.fromSubtags(
languageCode: languageCode, countryCode: countryCode); languageCode: languageCode, countryCode: countryCode);
} }

34
zxscanner/lib/utils/router.dart

@ -1,43 +1,43 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:zxscanner/pages/creator_page.dart'; import '../pages/creator_page.dart';
import 'package:zxscanner/pages/history_page.dart'; import '../pages/history_page.dart';
import 'package:zxscanner/pages/home_page.dart'; import '../pages/home_page.dart';
import 'package:zxscanner/pages/scanner_page.dart'; import '../pages/scanner_page.dart';
import 'package:zxscanner/pages/settings_page.dart'; import '../pages/settings_page.dart';
abstract class AppRoutes { abstract class AppRoutes {
static const creator = '/creator'; static const String creator = '/creator';
static const history = '/history'; static const String history = '/history';
static const home = '/'; static const String home = '/';
static const scanner = '/scanner'; static const String scanner = '/scanner';
static const settings = '/settings'; static const String settings = '/settings';
} }
class AppRouter { class AppRouter {
Route onGenerateRoute(RouteSettings settings) { Route<void> onGenerateRoute(RouteSettings settings) {
switch (settings.name) { switch (settings.name) {
case AppRoutes.creator: case AppRoutes.creator:
return MaterialPageRoute( return MaterialPageRoute<void>(
builder: (_) => const CreatorPage(), builder: (_) => const CreatorPage(),
); );
case AppRoutes.history: case AppRoutes.history:
return MaterialPageRoute( return MaterialPageRoute<void>(
builder: (_) => const HistoryPage(), builder: (_) => const HistoryPage(),
); );
case AppRoutes.home: case AppRoutes.home:
return MaterialPageRoute( return MaterialPageRoute<void>(
builder: (_) => const HomePage(), builder: (_) => const HomePage(),
); );
case AppRoutes.scanner: case AppRoutes.scanner:
return MaterialPageRoute( return MaterialPageRoute<void>(
builder: (_) => const ScannerPage(), builder: (_) => const ScannerPage(),
); );
case AppRoutes.settings: case AppRoutes.settings:
return MaterialPageRoute( return MaterialPageRoute<void>(
builder: (_) => const SettingsPage(), builder: (_) => const SettingsPage(),
); );
default: default:
return MaterialPageRoute( return MaterialPageRoute<void>(
builder: (_) => Container(), builder: (_) => Container(),
); );
} }

2
zxscanner/lib/utils/scroll_behavior.dart

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
class MyCustomScrollBehavior extends MaterialScrollBehavior { class MyCustomScrollBehavior extends MaterialScrollBehavior {
@override @override
Set<PointerDeviceKind> get dragDevices => { Set<PointerDeviceKind> get dragDevices => <PointerDeviceKind>{
PointerDeviceKind.touch, PointerDeviceKind.touch,
PointerDeviceKind.mouse, PointerDeviceKind.mouse,
}; };

34
zxscanner/lib/utils/shared_pref.dart

@ -2,19 +2,19 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:zxscanner/configs/app_store.dart'; import '../configs/app_store.dart';
late SharedPreferences sharedPreferences; late SharedPreferences sharedPreferences;
Future<void> initializePrefs() async { Future<void> initializePrefs() async {
sharedPreferences = await SharedPreferences.getInstance(); sharedPreferences = await SharedPreferences.getInstance();
final themeModeString = getPrefString( final String themeModeString = getPrefString(
themeModePref, themeModePref,
defaultValue: appStore.themeMode.toString(), defaultValue: appStore.themeMode.toString(),
); );
await appStore.setThemeMode( await appStore.setThemeMode(
ThemeMode.values ThemeMode.values.firstWhere(
.firstWhere((element) => element.toString() == themeModeString), (ThemeMode element) => element.toString() == themeModeString),
); );
await appStore.setColorSchemeIndex( await appStore.setColorSchemeIndex(
getPrefInt(colorSchemeIndexPref, defaultValue: appStore.colorSchemeIndex), getPrefInt(colorSchemeIndexPref, defaultValue: appStore.colorSchemeIndex),
@ -34,27 +34,28 @@ Future<void> initializePrefs() async {
Future<bool> setPrefValue(String key, dynamic value, Future<bool> setPrefValue(String key, dynamic value,
{bool print = true}) async { {bool print = true}) async {
if (value is String) { if (value is String) {
return await sharedPreferences.setString(key, value); return sharedPreferences.setString(key, value);
} else if (value is int) { } else if (value is int) {
return await sharedPreferences.setInt(key, value); return sharedPreferences.setInt(key, value);
} else if (value is bool) { } else if (value is bool) {
return await sharedPreferences.setBool(key, value); return sharedPreferences.setBool(key, value);
} else if (value is double) { } else if (value is double) {
return await sharedPreferences.setDouble(key, value); return sharedPreferences.setDouble(key, value);
} else if (value is Map<String, dynamic>) { } else if (value is Map<String, dynamic>) {
return await sharedPreferences.setString(key, jsonEncode(value)); return sharedPreferences.setString(key, jsonEncode(value));
} else if (value is List<String>) { } else if (value is List<String>) {
return await sharedPreferences.setStringList(key, value); return sharedPreferences.setStringList(key, value);
} else { } else {
throw ArgumentError( throw ArgumentError(
'Invalid value ${value.runtimeType} - Must be a String, int, bool, double, Map<String, dynamic> or StringList'); 'Invalid value ${value.runtimeType} - Must be a String, int, bool, double, Map<String, dynamic> or StringList',
);
} }
} }
/// Returns List of Keys that matches with given Key /// Returns List of Keys that matches with given Key
List<String> getMatchingSharedPrefKeys(String key) { List<String> getMatchingSharedPrefKeys(String key) {
List<String> keys = []; final List<String> keys = <String>[];
sharedPreferences.getKeys().forEach((element) { sharedPreferences.getKeys().forEach((String element) {
if (element.contains(key)) { if (element.contains(key)) {
keys.add(element); keys.add(element);
} }
@ -88,13 +89,12 @@ Map<String, dynamic> getPrefJSON(String key,
if (sharedPreferences.containsKey(key)) { if (sharedPreferences.containsKey(key)) {
return jsonDecode(sharedPreferences.getString(key) ?? ''); return jsonDecode(sharedPreferences.getString(key) ?? '');
} else { } else {
return defaultValue ?? {}; return defaultValue ?? <String, dynamic>{};
} }
} }
/// remove key from SharedPref /// remove key from SharedPref
Future<bool> removePrefKey(String key) async => Future<bool> removePrefKey(String key) async => sharedPreferences.remove(key);
await sharedPreferences.remove(key);
/// clear SharedPref /// clear SharedPref
Future<bool> clearSharedPref() async => await sharedPreferences.clear(); Future<bool> clearSharedPref() async => sharedPreferences.clear();

4
zxscanner/lib/widgets/common_widgets.dart

@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:zxscanner/configs/constants.dart'; import '../configs/constants.dart';
class ContainerX extends StatelessWidget { class ContainerX extends StatelessWidget {
const ContainerX({Key? key, this.child}) : super(key: key); const ContainerX({super.key, this.child});
final Widget? child; final Widget? child;

18
zxscanner/lib/widgets/language_widget.dart

@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:zxscanner/configs/app_store.dart'; import '../configs/app_store.dart';
import 'package:zxscanner/generated/l10n.dart'; import '../generated/l10n.dart';
import 'package:zxscanner/utils/extensions.dart'; import '../utils/extensions.dart';
class LanguageWidget extends StatelessWidget { class LanguageWidget extends StatelessWidget {
const LanguageWidget({Key? key, required this.onChanged}) : super(key: key); const LanguageWidget({super.key, required this.onChanged});
final Function(Locale) onChanged; final Function(Locale) onChanged;
@ -12,19 +12,17 @@ class LanguageWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DropdownButton<Locale>( return DropdownButton<Locale>(
value: appStore.selectedLanguage.parseLocale(), value: appStore.selectedLanguage.parseLocale(),
isExpanded: false,
isDense: false,
underline: const SizedBox(), underline: const SizedBox(),
onChanged: (value) async { onChanged: (Locale? value) async {
if (value != null) { if (value != null) {
await S.load(value); await S.load(value);
appStore.setLanguage(value.toString()); appStore.setLanguage(value.toString());
onChanged(value); onChanged(value);
} }
}, },
selectedItemBuilder: (context) { selectedItemBuilder: (BuildContext context) {
return S.delegate.supportedLocales return S.delegate.supportedLocales
.map((e) => DropdownMenuItem<Locale>( .map((Locale e) => DropdownMenuItem<Locale>(
value: e, value: e,
child: SizedBox( child: SizedBox(
width: 80, width: 80,
@ -38,7 +36,7 @@ class LanguageWidget extends StatelessWidget {
.toList(); .toList();
}, },
items: S.delegate.supportedLocales items: S.delegate.supportedLocales
.map((e) => DropdownMenuItem( .map((Locale e) => DropdownMenuItem<Locale>(
value: e, value: e,
child: Text(e.countryCode?.toLangName() ?? ''), child: Text(e.countryCode?.toLangName() ?? ''),
)) ))

4
zxscanner/lib/widgets/setting_tile.dart

@ -3,12 +3,12 @@ import 'package:flutter/material.dart';
class SettingTile extends StatelessWidget { class SettingTile extends StatelessWidget {
const SettingTile( const SettingTile(
this.context, { this.context, {
Key? key, super.key,
this.leading, this.leading,
this.title, this.title,
this.trailing, this.trailing,
this.onTap, this.onTap,
}) : super(key: key); });
final BuildContext context; final BuildContext context;
final IconData? leading; final IconData? leading;

4
zxscanner/lib/widgets/theme_mode_switch.dart

@ -7,10 +7,10 @@ import 'package:flutter/material.dart';
/// can be dropped into any application. /// can be dropped into any application.
class ThemeModeSwitch extends StatelessWidget { class ThemeModeSwitch extends StatelessWidget {
const ThemeModeSwitch({ const ThemeModeSwitch({
Key? key, super.key,
required this.themeMode, required this.themeMode,
required this.onChanged, required this.onChanged,
}) : super(key: key); });
final ThemeMode themeMode; final ThemeMode themeMode;
final ValueChanged<ThemeMode> onChanged; final ValueChanged<ThemeMode> onChanged;

7
zxscanner/lib/widgets/theme_selector.dart

@ -1,6 +1,6 @@
import 'package:flex_color_scheme/flex_color_scheme.dart'; import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:zxscanner/configs/app_store.dart'; import '../configs/app_store.dart';
// The width size of the scrolling button. // The width size of the scrolling button.
const double _kWidthOfScrollItem = 71.6; const double _kWidthOfScrollItem = 71.6;
@ -16,8 +16,8 @@ const double _kWidthOfScrollItem = 71.6;
// The theme is controlled via the passed in ThemeController. // The theme is controlled via the passed in ThemeController.
class ThemeSelector extends StatefulWidget { class ThemeSelector extends StatefulWidget {
const ThemeSelector({ const ThemeSelector({
Key? key, super.key,
}) : super(key: key); });
@override @override
State<ThemeSelector> createState() => _ThemeSelectorState(); State<ThemeSelector> createState() => _ThemeSelectorState();
@ -32,7 +32,6 @@ class _ThemeSelectorState extends State<ThemeSelector> {
super.initState(); super.initState();
schemeIndex = appStore.colorSchemeIndex; schemeIndex = appStore.colorSchemeIndex;
scrollController = ScrollController( scrollController = ScrollController(
keepScrollOffset: true,
initialScrollOffset: _kWidthOfScrollItem * schemeIndex, initialScrollOffset: _kWidthOfScrollItem * schemeIndex,
); );
} }

14
zxscanner/pubspec.lock

@ -35,7 +35,7 @@ packages:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.8.2" version: "2.9.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -140,7 +140,7 @@ packages:
name: characters name: characters
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.2.1"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
@ -510,14 +510,14 @@ packages:
name: material_color_utilities name: material_color_utilities
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.4" version: "0.1.5"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.7.0" version: "1.8.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@ -552,7 +552,7 @@ packages:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.1" version: "1.8.2"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
@ -795,7 +795,7 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.2" version: "1.9.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -823,7 +823,7 @@ packages:
name: string_scanner name: string_scanner
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:

Loading…
Cancel
Save