Browse Source

Merge pull request #4 from h1376h/main

feature: add dependabot & CI (+ lint improvements)
pull/5/head
Khoren Markosyan 3 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. 64
      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.
unnecessary_null_comparison: warning
exclude:
- "zxscanner/**"
- "bin/cache/**"
# Ignore protoc generated files
- "dev/conductor/lib/proto/*"

2
android/build.gradle

@ -9,7 +9,7 @@ buildscript {
}
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"
}
}

242
zxscanner/analysis_options.yaml

@ -9,21 +9,231 @@
# packages, and plugins designed to encourage good coding practices.
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:
# 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:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
# This list is derived from the list of all available lints located at
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
- always_declare_return_types
- always_put_control_body_on_new_line
# - 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:mobx/mobx.dart';
import 'package:zxscanner/utils/shared_pref.dart';
import '../utils/shared_pref.dart';
part 'app_store.g.dart';
@ -8,11 +8,11 @@ AppStore appStore = AppStore();
class AppStore = AppStoreBase with _$AppStore;
const themeModePref = 'themeModePref';
const colorSchemeIndexPref = 'colorSchemeIndexPref';
const isSoundOnPref = 'isSoundOnPref';
const isVibrationOnPref = 'isVibrationOnPref';
const languagePref = 'languagePref';
const String themeModePref = 'themeModePref';
const String colorSchemeIndexPref = 'colorSchemeIndexPref';
const String isSoundOnPref = 'isSoundOnPref';
const String isVibrationOnPref = 'isVibrationOnPref';
const String languagePref = 'languagePref';
abstract class AppStoreBase with Store {
@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
mixin _$AppStore on AppStoreBase, Store {
final _$themeModeAtom = Atom(name: 'AppStoreBase.themeMode');
final Atom _$themeModeAtom = Atom(name: 'AppStoreBase.themeMode');
@override
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
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
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
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
String get selectedLanguage {
@ -84,14 +84,14 @@ mixin _$AppStore on AppStoreBase, Store {
});
}
final _$setThemeModeAsyncAction = AsyncAction('AppStoreBase.setThemeMode');
final AsyncAction _$setThemeModeAsyncAction = AsyncAction('AppStoreBase.setThemeMode');
@override
Future<void> setThemeMode(ThemeMode value) {
return _$setThemeModeAsyncAction.run(() => super.setThemeMode(value));
}
final _$setColorSchemeIndexAsyncAction =
final AsyncAction _$setColorSchemeIndexAsyncAction =
AsyncAction('AppStoreBase.setColorSchemeIndex');
@override
@ -100,7 +100,7 @@ mixin _$AppStore on AppStoreBase, Store {
.run(() => super.setColorSchemeIndex(value));
}
final _$toggleSoundModeAsyncAction =
final AsyncAction _$toggleSoundModeAsyncAction =
AsyncAction('AppStoreBase.toggleSoundMode');
@override
@ -109,7 +109,7 @@ mixin _$AppStore on AppStoreBase, Store {
.run(() => super.toggleSoundMode(value: value));
}
final _$toggleVibrationModeAsyncAction =
final AsyncAction _$toggleVibrationModeAsyncAction =
AsyncAction('AppStoreBase.toggleVibrationMode');
@override
@ -118,7 +118,7 @@ mixin _$AppStore on AppStoreBase, Store {
.run(() => super.toggleVibrationMode(value: value));
}
final _$setLanguageAsyncAction = AsyncAction('AppStoreBase.setLanguage');
final AsyncAction _$setLanguageAsyncAction = AsyncAction('AppStoreBase.setLanguage');
@override
Future<void> setLanguage(String aLanguage) {

2
zxscanner/lib/configs/app_theme.dart

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

18
zxscanner/lib/configs/constants.dart

@ -1,13 +1,13 @@
const String appName = 'ZXScanner';
/// space between widgets
const spaceSmall = 2.0;
const spaceSmall2 = 4.0;
const spaceMedium = 8.0;
const spaceDefault = 16.0;
const spaceLarge = 24.0;
const spaceLarge2 = 32.0;
const spaceLarge3 = 40.0;
const spaceLarge4 = 96.0;
const double spaceSmall = 2.0;
const double spaceSmall2 = 4.0;
const double spaceMedium = 8.0;
const double spaceDefault = 16.0;
const double spaceLarge = 24.0;
const double spaceLarge2 = 32.0;
const double spaceLarge3 = 40.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;
typedef Future<dynamic> LibraryLoader();
// ignore: always_specify_types
Map<String, LibraryLoader> _deferredLibraries = {
'en_US': () => new Future.value(null),
// ignore: always_specify_types
'en_US': () => new Future.value(),
};
MessageLookupByLibrary? _findExact(String localeName) {
@ -33,17 +35,17 @@ MessageLookupByLibrary? _findExact(String localeName) {
/// User programs should call this before using [localeName] for messages.
Future<bool> initializeMessages(String localeName) async {
var availableLocale = Intl.verifiedLocale(
localeName, (locale) => _deferredLibraries[locale] != null,
final String? availableLocale = Intl.verifiedLocale(
localeName, (String locale) => _deferredLibraries[locale] != null,
onFailure: (_) => null);
if (availableLocale == null) {
return new Future.value(false);
return new Future<bool>.value(false);
}
var lib = _deferredLibraries[availableLocale];
await (lib == null ? new Future.value(false) : lib());
final LibraryLoader? lib = _deferredLibraries[availableLocale];
await (lib == null ? new Future<bool>.value(false) : lib());
initializeInternalMessageLookup(() => new CompositeMessageLookup());
messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
return new Future.value(true);
return new Future<bool>.value(true);
}
bool _messagesExistFor(String locale) {
@ -55,8 +57,10 @@ bool _messagesExistFor(String locale) {
}
MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) {
var actualLocale =
final String? actualLocale =
Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null);
if (actualLocale == null) return null;
if (actualLocale == null) {
return null;
}
return _findExact(actualLocale);
}

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

@ -13,14 +13,14 @@
import 'package:intl/intl.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);
class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'en_US';
final messages = _notInlinedMessages(_notInlinedMessages);
final Map<String, Function> messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"settingsAppBarTitle": MessageLookupByLibrary.simpleMessage("Settings"),
"settingsLanguageTitle":

13
zxscanner/lib/generated/l10n.dart

@ -26,13 +26,13 @@ class S {
static const AppLocalizationDelegate delegate = AppLocalizationDelegate();
static Future<S> load(Locale locale) {
final name = (locale.countryCode?.isEmpty ?? false)
final String name = (locale.countryCode?.isEmpty ?? false)
? locale.languageCode
: locale.toString();
final localeName = Intl.canonicalizedLocale(name);
final String localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName;
final instance = S();
final S instance = S();
S._current = instance;
return instance;
@ -40,7 +40,7 @@ class S {
}
static S of(BuildContext context) {
final instance = S.maybeOf(context);
final S? instance = S.maybeOf(context);
assert(instance != null,
'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?');
return instance!;
@ -56,7 +56,6 @@ class S {
'Settings',
name: 'settingsAppBarTitle',
desc: '',
args: [],
);
}
@ -66,7 +65,6 @@ class S {
'Theme',
name: 'settingsThemeModeTitle',
desc: '',
args: [],
);
}
@ -76,7 +74,6 @@ class S {
'Language',
name: 'settingsLanguageTitle',
desc: '',
args: [],
);
}
}
@ -98,7 +95,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate<S> {
bool shouldReload(AppLocalizationDelegate old) => false;
bool _isSupported(Locale locale) {
for (var supportedLocale in supportedLocales) {
for (Locale supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode) {
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_mobx/flutter_mobx.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_theme.dart';
import 'configs/constants.dart';
import 'generated/l10n.dart' as loc;
import 'utils/db_service.dart';
import 'utils/extensions.dart';
import 'utils/router.dart';
import 'utils/scroll_behavior.dart';
import 'utils/shared_pref.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -23,14 +23,14 @@ void main() async {
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _appRouter = AppRouter();
final AppRouter _appRouter = AppRouter();
@override
Widget build(BuildContext context) {
@ -40,7 +40,7 @@ class _MyAppState extends State<MyApp> {
theme: AppTheme.flexLightTheme(),
darkTheme: AppTheme.flexDarkTheme(),
themeMode: appStore.themeMode,
localizationsDelegates: const [
localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
loc.S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,

16
zxscanner/lib/models/code.dart

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

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

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

20
zxscanner/lib/models/encode.dart

@ -7,6 +7,16 @@ part 'encode.g.dart';
@HiveType(typeId: 1)
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)
bool? isValid;
@ -22,15 +32,5 @@ class Encode extends HiveObject {
@HiveField(4)
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);
}

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

@ -12,8 +12,8 @@ class EncodeAdapter extends TypeAdapter<Encode> {
@override
Encode read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
final int numOfFields = reader.readByte();
final Map<int, dynamic> fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
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/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: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 {
const BarcodesPage({
Key? key,
}) : super(key: key);
super.key,
});
@override
State<BarcodesPage> createState() => _BarcodesPageState();
@ -35,11 +36,11 @@ class _BarcodesPageState extends State<BarcodesPage> {
);
}
_buildResultList() {
ValueListenableBuilder<Box<Encode>> _buildResultList() {
return ValueListenableBuilder<Box<Encode>>(
valueListenable: DbService.instance.getEncodes().listenable(),
builder: (context, box, _) {
final results = box.values.toList().cast<Encode>();
builder: (BuildContext context, Box<Encode> box, _) {
final List<Encode> results = box.values.toList().cast<Encode>();
return results.isEmpty
? const Center(
child: Text(
@ -48,8 +49,8 @@ class _BarcodesPageState extends State<BarcodesPage> {
))
: ListView.builder(
itemCount: results.length,
itemBuilder: (context, index) {
final result = results[index];
itemBuilder: (BuildContext context, int index) {
final Encode result = results[index];
return ContainerX(
child: Card(
child: ListTile(
@ -61,7 +62,7 @@ class _BarcodesPageState extends State<BarcodesPage> {
subtitle: Text(result.formatName),
trailing: ButtonBar(
mainAxisSize: MainAxisSize.min,
children: [
children: <Widget>[
// Copy button
IconButton(
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_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: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;
String get tempPath => '${tempDir.path}/zxing.jpg';
class CreatorPage extends StatefulWidget {
const CreatorPage({
Key? key,
}) : super(key: key);
super.key,
});
@override
State<CreatorPage> createState() => _CreatorPageState();
@ -36,8 +37,8 @@ class _CreatorPageState extends State<CreatorPage> {
initStateAsync();
}
void initStateAsync() async {
getTemporaryDirectory().then((value) {
Future<void> initStateAsync() async {
getTemporaryDirectory().then((Directory value) {
tempDir = value;
});
}
@ -51,14 +52,14 @@ class _CreatorPageState extends State<CreatorPage> {
body: SingleChildScrollView(
child: ContainerX(
child: Column(
children: [
children: <Widget>[
WriterWidget(
onSuccess: (result, bytes) {
onSuccess: (EncodeResult result, Uint8List? bytes) {
setState(() {
encode = Encode.fromEncodeResult(result, bytes);
});
},
onError: (error) {
onError: (String error) {
setState(() {
encode = null;
});
@ -75,23 +76,22 @@ class _CreatorPageState extends State<CreatorPage> {
Column buildWriteResult() {
return Column(
children: [
children: <Widget>[
// Barcode image
if (encode?.data != null) Image.memory(encode?.data ?? Uint8List(0)),
const SizedBox(height: spaceLarge),
// Share button
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
children: <Widget>[
ElevatedButton(
onPressed: () {
// Save image to device
final file = File(tempPath);
final File file = File(tempPath);
file.writeAsBytesSync(encode?.data ?? Uint8List(0));
final path = file.path;
final String path = file.path;
// Share image
Share.shareFiles([path]);
Share.shareFiles(<String>[path]);
},
child: const Text('Share'),
),
@ -99,7 +99,9 @@ class _CreatorPageState extends State<CreatorPage> {
onPressed: () async {
if (encode != null) {
await DbService.instance.addEncode(encode!);
if (!mounted) return;
if (!mounted) {
return;
}
Navigator.of(context).pop();
}
},

64
zxscanner/lib/pages/help_page.dart

@ -1,11 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:zxscanner/configs/constants.dart';
import 'package:zxscanner/widgets/common_widgets.dart';
import '../configs/constants.dart';
import '../widgets/common_widgets.dart';
class HelpPage extends StatelessWidget {
const HelpPage({Key? key}) : super(key: key);
const HelpPage({super.key});
@override
Widget build(BuildContext context) {
@ -15,7 +15,7 @@ class HelpPage extends StatelessWidget {
),
body: ContainerX(
child: Column(
children: [
children: <Widget>[
Padding(
padding: const EdgeInsets.all(spaceDefault),
child: InkWell(
@ -23,10 +23,12 @@ class HelpPage extends StatelessWidget {
launchUrlString('https://scanbot.io');
},
child: Column(
children: const [
children: const <Widget>[
Text('All information is taken from'),
Text('scanbot.io',
style: TextStyle(fontWeight: FontWeight.bold)),
Text(
'scanbot.io',
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
),
@ -58,7 +60,7 @@ class HelpPage extends StatelessWidget {
),
child: ExpansionTile(
title: Text(title ?? ''),
children: [
children: <Widget>[
Padding(
padding: const EdgeInsets.all(spaceDefault),
child: MarkdownBody(data: body ?? ''),
@ -70,23 +72,23 @@ class HelpPage extends StatelessWidget {
);
}
createSlides(BuildContext context) {
return [
List<Widget> createSlides(BuildContext context) {
return <Widget>[
createSlide(
context,
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.
* Defined in the ISO/IEC 18004:2006 and JIS X0510 standards.
* 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.
* Automatic error correction recovers damage to up to 30%, depending on the correction level chosen.
""",
''',
),
createSlide(
context,
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.
* 2D barcode with L-shaped border and pixel matrix.
* 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.
* Often engraved on items via Direct Part Marking (DPM).
* Readable even with low contrast.
""",
''',
),
createSlide(
context,
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.
* Two-dimensional barcode, standardized in ISO/IEC 24778.
* 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.
* Enables both high data density and up to 95% error tolerance.
* Pattern resembles a top-down view of an Aztec pyramid
""",
''',
),
createSlide(
context,
@ -124,75 +126,75 @@ Ticketing, travel, and logistics are some of the most common areas of applicatio
createSlide(
context,
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.
* Exclusively used within North America.
* 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.
""",
''',
),
createSlide(
context,
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.
* 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).
* The last digit is a mod10 checksum.
* EAN codes are defined as GS1 standards.
""",
''',
),
createSlide(
context,
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).
* 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.
* The low data density makes it unsuitable for tiny items.
* Standardized as ANSI MH 10.8 M-1983 and ANSI/AIM BC1/1995.
""",
''',
),
createSlide(
context,
title: 'Code93',
body: """
body: '''
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.
* In Code 93 Extended, combinations of those characters can represent all 128 ASCII characters.
""",
''',
),
createSlide(
context,
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.
* A one-dimensional barcode defined in the ISO/IEC 15417 standard.
* Can encode all ASCII characters, including special characters.
* High data density compared to other 1D barcode formats.
""",
''',
),
createSlide(
context,
title: 'CodaBar',
body: """
body: '''
The Codabar barcode is only used in blood banks, libraries, and in laboratories.
* 1D (linear) barcode type.
* Self-checking, with no need for a check digit.
* Encodes alphanumeric characters, as well as six special characters.
* Stores up to 16 characters.
* Newer barcode types can store more data in less space.
""",
''',
),
createSlide(
context,
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.
* 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. 
* Compared to other linear barcodes, more data can be accommodated using the same label size.
""",
''',
),
];
}
@ -206,4 +208,4 @@ DataBarExpanded
MaxiCode
*/
*/

23
zxscanner/lib/pages/history_page.dart

@ -1,15 +1,16 @@
import 'package:flutter/material.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:hive_flutter/hive_flutter.dart';
import '../models/code.dart';
import '../utils/db_service.dart';
import '../widgets/common_widgets.dart';
class HistoryPage extends StatefulWidget {
const HistoryPage({
Key? key,
}) : super(key: key);
super.key,
});
@override
State<HistoryPage> createState() => _HistoryPageState();
@ -26,11 +27,11 @@ class _HistoryPageState extends State<HistoryPage> {
);
}
_buildResultList() {
ValueListenableBuilder<Box<Code>> _buildResultList() {
return ValueListenableBuilder<Box<Code>>(
valueListenable: DbService.instance.getCodes().listenable(),
builder: (context, box, _) {
final results = box.values.toList().cast<Code>();
builder: (BuildContext context, Box<Code> box, _) {
final List<Code> results = box.values.toList().cast<Code>();
return results.isEmpty
? const Center(
child: Text(
@ -39,8 +40,8 @@ class _HistoryPageState extends State<HistoryPage> {
))
: ListView.builder(
itemCount: results.length,
itemBuilder: (context, index) {
final result = results[index];
itemBuilder: (BuildContext context, int index) {
final Code result = results[index];
return ContainerX(
child: Card(
child: ListTile(
@ -48,7 +49,7 @@ class _HistoryPageState extends State<HistoryPage> {
subtitle: Text(result.formatName),
trailing: ButtonBar(
mainAxisSize: MainAxisSize.min,
children: [
children: <Widget>[
// Copy button
IconButton(
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: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 'barcodes_page.dart';
import 'help_page.dart';
import 'history_page.dart';
import 'scanner_page.dart';
import 'settings_page.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
var selectedIndex = 2;
int selectedIndex = 2;
final barcodesPage = const BarcodesPage();
final historyPage = const HistoryPage();
final scannerPage = const ScannerPage();
final helpPage = const HelpPage();
final settingsPage = const SettingsPage();
final BarcodesPage barcodesPage = const BarcodesPage();
final HistoryPage historyPage = const HistoryPage();
final ScannerPage scannerPage = const ScannerPage();
final HelpPage helpPage = const HelpPage();
final SettingsPage settingsPage = const SettingsPage();
dynamic pages() => [
dynamic pages() => <dynamic>[
barcodesPage,
historyPage,
scannerPage,
@ -31,17 +32,18 @@ class _HomePageState extends State<HomePage> {
settingsPage,
];
dynamic tabItems() => [
const TabItem(icon: FontAwesomeIcons.barcode),
const TabItem(icon: FontAwesomeIcons.clockRotateLeft),
const TabItem(icon: Icons.qr_code_scanner),
const TabItem(icon: FontAwesomeIcons.circleQuestion),
const TabItem(icon: FontAwesomeIcons.gear),
dynamic tabItems() => <TabItem<IconData>>[
const TabItem<IconData>(icon: FontAwesomeIcons.barcode),
const TabItem<IconData>(icon: FontAwesomeIcons.clockRotateLeft),
const TabItem<IconData>(icon: Icons.qr_code_scanner),
const TabItem<IconData>(icon: FontAwesomeIcons.circleQuestion),
const TabItem<IconData>(icon: FontAwesomeIcons.gear),
];
@override
Widget build(BuildContext context) {
return Scaffold(
// ignore: avoid_dynamic_calls
body: pages()[selectedIndex],
bottomNavigationBar: ConvexAppBar(
style: TabStyle.fixedCircle,
@ -50,7 +52,7 @@ class _HomePageState extends State<HomePage> {
activeColor: Theme.of(context).colorScheme.primary,
items: tabItems(),
initialActiveIndex: selectedIndex,
onTap: (index) {
onTap: (int index) {
setState(() {
selectedIndex = index;
});

22
zxscanner/lib/pages/scanner_page.dart

@ -1,15 +1,16 @@
import 'package:flutter/material.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:image_picker/image_picker.dart';
import '../models/models.dart';
import '../utils/db_service.dart';
import '../utils/extensions.dart';
class ScannerPage extends StatefulWidget {
const ScannerPage({
Key? key,
}) : super(key: key);
super.key,
});
@override
State<ScannerPage> createState() => _ScannerPageState();
@ -25,7 +26,7 @@ class _ScannerPageState extends State<ScannerPage> {
title: const Text('Scanner'),
),
body: ReaderWidget(
onScan: (result) async {
onScan: (CodeResult result) async {
addCode(result);
},
),
@ -36,6 +37,7 @@ class _ScannerPageState extends State<ScannerPage> {
);
}
// ignore: always_declare_return_types
pickImage() async {
try {
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);
if (result != null && result.isValidBool) {
addCode(result);
} else {
if (!mounted) return;
if (!mounted) {
return;
}
context.showToast('No code found');
}
}
void addCode(CodeResult result) {
Code code = Code.fromCodeResult(result);
final Code code = Code.fromCodeResult(result);
DbService.instance.addCode(code);
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:zxscanner/configs/app_store.dart';
import 'package:zxscanner/configs/constants.dart';
import 'package:zxscanner/generated/l10n.dart';
import 'package:zxscanner/widgets/common_widgets.dart';
import '../configs/app_store.dart';
import '../configs/constants.dart';
import '../generated/l10n.dart';
import '../widgets/common_widgets.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';
class SettingsPage extends StatefulWidget {
const SettingsPage({Key? key}) : super(key: key);
const SettingsPage({super.key});
@override
State<SettingsPage> createState() => _SettingsPageState();
@ -28,7 +28,7 @@ class _SettingsPageState extends State<SettingsPage> {
body: SingleChildScrollView(
child: ContainerX(
child: Column(
children: [
children: <Widget>[
const SizedBox(height: spaceDefault),
const Padding(
padding: EdgeInsets.symmetric(horizontal: spaceDefault),
@ -40,7 +40,7 @@ class _SettingsPageState extends State<SettingsPage> {
title: S.current.settingsThemeModeTitle,
trailing: ThemeModeSwitch(
themeMode: appStore.themeMode,
onChanged: (mode) {
onChanged: (ThemeMode mode) {
appStore.setThemeMode(mode);
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 '../models/models.dart';
class DbService {
DbService._privateConstructor();
@ -17,44 +18,42 @@ class DbService {
Box<Code> getCodes() => Hive.box<Code>('codes');
Future deleteCodes() async {
var items = getCodes();
Future<void> deleteCodes() async {
final Box<Code> items = getCodes();
await items.deleteAll(items.keys);
return;
}
Future addCode(Code value) async {
var items = getCodes();
Future<int> addCode(Code value) async {
final Box<Code> items = getCodes();
if (!items.values.contains(value)) {
return items.add(value);
}
return;
return -1;
}
Future<void> deleteCode(Code value) async {
var items = getCodes();
final Box<Code> items = getCodes();
await items.delete(value.key);
return;
}
Box<Encode> getEncodes() => Hive.box<Encode>('encodes');
Future deleteEncodes() async {
var items = getEncodes();
Future<void> deleteEncodes() async {
final Box<Encode> items = getEncodes();
await items.deleteAll(items.keys);
return;
}
Future addEncode(Encode value) async {
var items = getEncodes();
Future<int> addEncode(Encode value) async {
final Box<Encode> items = getEncodes();
if (!items.values.contains(value)) {
return items.add(value);
}
return;
return -1;
}
Future<void> deleteEncode(Encode value) async {
var items = getEncodes();
final Box<Encode> items = getEncodes();
await items.delete(value.key);
return;
}

4
zxscanner/lib/utils/extensions.dart

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

34
zxscanner/lib/utils/router.dart

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

2
zxscanner/lib/utils/scroll_behavior.dart

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

34
zxscanner/lib/utils/shared_pref.dart

@ -2,19 +2,19 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:zxscanner/configs/app_store.dart';
import '../configs/app_store.dart';
late SharedPreferences sharedPreferences;
Future<void> initializePrefs() async {
sharedPreferences = await SharedPreferences.getInstance();
final themeModeString = getPrefString(
final String themeModeString = getPrefString(
themeModePref,
defaultValue: appStore.themeMode.toString(),
);
await appStore.setThemeMode(
ThemeMode.values
.firstWhere((element) => element.toString() == themeModeString),
ThemeMode.values.firstWhere(
(ThemeMode element) => element.toString() == themeModeString),
);
await appStore.setColorSchemeIndex(
getPrefInt(colorSchemeIndexPref, defaultValue: appStore.colorSchemeIndex),
@ -34,27 +34,28 @@ Future<void> initializePrefs() async {
Future<bool> setPrefValue(String key, dynamic value,
{bool print = true}) async {
if (value is String) {
return await sharedPreferences.setString(key, value);
return sharedPreferences.setString(key, value);
} else if (value is int) {
return await sharedPreferences.setInt(key, value);
return sharedPreferences.setInt(key, value);
} else if (value is bool) {
return await sharedPreferences.setBool(key, value);
return sharedPreferences.setBool(key, value);
} else if (value is double) {
return await sharedPreferences.setDouble(key, value);
return sharedPreferences.setDouble(key, value);
} 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>) {
return await sharedPreferences.setStringList(key, value);
return sharedPreferences.setStringList(key, value);
} else {
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
List<String> getMatchingSharedPrefKeys(String key) {
List<String> keys = [];
sharedPreferences.getKeys().forEach((element) {
final List<String> keys = <String>[];
sharedPreferences.getKeys().forEach((String element) {
if (element.contains(key)) {
keys.add(element);
}
@ -88,13 +89,12 @@ Map<String, dynamic> getPrefJSON(String key,
if (sharedPreferences.containsKey(key)) {
return jsonDecode(sharedPreferences.getString(key) ?? '');
} else {
return defaultValue ?? {};
return defaultValue ?? <String, dynamic>{};
}
}
/// remove key from SharedPref
Future<bool> removePrefKey(String key) async =>
await sharedPreferences.remove(key);
Future<bool> removePrefKey(String key) async => sharedPreferences.remove(key);
/// 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:zxscanner/configs/constants.dart';
import '../configs/constants.dart';
class ContainerX extends StatelessWidget {
const ContainerX({Key? key, this.child}) : super(key: key);
const ContainerX({super.key, this.child});
final Widget? child;

18
zxscanner/lib/widgets/language_widget.dart

@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:zxscanner/configs/app_store.dart';
import 'package:zxscanner/generated/l10n.dart';
import 'package:zxscanner/utils/extensions.dart';
import '../configs/app_store.dart';
import '../generated/l10n.dart';
import '../utils/extensions.dart';
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;
@ -12,19 +12,17 @@ class LanguageWidget extends StatelessWidget {
Widget build(BuildContext context) {
return DropdownButton<Locale>(
value: appStore.selectedLanguage.parseLocale(),
isExpanded: false,
isDense: false,
underline: const SizedBox(),
onChanged: (value) async {
onChanged: (Locale? value) async {
if (value != null) {
await S.load(value);
appStore.setLanguage(value.toString());
onChanged(value);
}
},
selectedItemBuilder: (context) {
selectedItemBuilder: (BuildContext context) {
return S.delegate.supportedLocales
.map((e) => DropdownMenuItem<Locale>(
.map((Locale e) => DropdownMenuItem<Locale>(
value: e,
child: SizedBox(
width: 80,
@ -38,7 +36,7 @@ class LanguageWidget extends StatelessWidget {
.toList();
},
items: S.delegate.supportedLocales
.map((e) => DropdownMenuItem(
.map((Locale e) => DropdownMenuItem<Locale>(
value: e,
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 {
const SettingTile(
this.context, {
Key? key,
super.key,
this.leading,
this.title,
this.trailing,
this.onTap,
}) : super(key: key);
});
final BuildContext context;
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.
class ThemeModeSwitch extends StatelessWidget {
const ThemeModeSwitch({
Key? key,
super.key,
required this.themeMode,
required this.onChanged,
}) : super(key: key);
});
final ThemeMode themeMode;
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:flutter/material.dart';
import 'package:zxscanner/configs/app_store.dart';
import '../configs/app_store.dart';
// The width size of the scrolling button.
const double _kWidthOfScrollItem = 71.6;
@ -16,8 +16,8 @@ const double _kWidthOfScrollItem = 71.6;
// The theme is controlled via the passed in ThemeController.
class ThemeSelector extends StatefulWidget {
const ThemeSelector({
Key? key,
}) : super(key: key);
super.key,
});
@override
State<ThemeSelector> createState() => _ThemeSelectorState();
@ -32,7 +32,6 @@ class _ThemeSelectorState extends State<ThemeSelector> {
super.initState();
schemeIndex = appStore.colorSchemeIndex;
scrollController = ScrollController(
keepScrollOffset: true,
initialScrollOffset: _kWidthOfScrollItem * schemeIndex,
);
}

14
zxscanner/pubspec.lock

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

Loading…
Cancel
Save