commit b269c4b832311664a2e9361989741341ff15a269 Author: Laha Luhem Date: Fri Oct 27 22:48:44 2023 +0200 added files from repo more gitignore diff --git a/gamestore/.gitattributes b/gamestore/.gitattributes new file mode 100644 index 0000000..252a94f --- /dev/null +++ b/gamestore/.gitattributes @@ -0,0 +1,36 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Always perform LF normalization +*.dart text +*.gradle text +*.html text +*.java text +*.json text +*.md text +*.py text +*.sh text +*.txt text +*.xml text +*.yaml text + +# Make sure that these Windows files always have CRLF line endings at checkout +*.bat text eol=crlf +*.ps1 text eol=crlf +*.rc text eol=crlf +*.sln text eol=crlf +*.props text eol=crlf +*.vcxproj text eol=crlf +*.vcxproj.filters text eol=crlf +# Including templates +*.sln.tmpl text eol=crlf +*.props.tmpl text eol=crlf +*.vcxproj.tmpl text eol=crlf + +# Never perform LF normalization +*.ico binary +*.jar binary +*.png binary +*.zip binary +*.ttf binary +*.otf binary diff --git a/gamestore/.gitignore b/gamestore/.gitignore new file mode 100644 index 0000000..8eeb02a --- /dev/null +++ b/gamestore/.gitignore @@ -0,0 +1,425 @@ +# Custom +.DS_Store + +# Created by https://www.toptal.com/developers/gitignore/api/androidstudio,visualstudiocode,flutter,dart,android,kotlin,xcode,swift,objective-c +# Edit at https://www.toptal.com/developers/gitignore?templates=androidstudio,visualstudiocode,flutter,dart,android,kotlin,xcode,swift,objective-c + +### Android ### +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Log/OS Files +*.log + +# Android Studio generated files and folders +captures/ +.externalNativeBuild/ +.cxx/ +*.apk +output.json + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Android Profiling +*.hprof + +### Android Patch ### +gen-external-apklibs + +# Replacement of .externalNativeBuild directories introduced +# with Android Studio 3.5. + +### Dart ### +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# Directory created by dartdoc +# If you don't generate documentation locally you can remove this line. +doc/api/ + +# dotenv environment variables file +.env* + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + +.flutter-plugins +.flutter-plugins-dependencies + +### Dart Patch ### +# dotenv environment variables file +.env + +### Flutter ### +# Flutter/Dart/Pub related +**/doc/api/ +.fvm/flutter_sdk +.pub-cache/ +.pub/ +coverage/ +lib/generated_plugin_registrant.dart +# For library packages, don’t commit the pubspec.lock file. +# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies. +# See https://dart.dev/guides/libraries/private-files#pubspeclock +#pubspec.lock + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/key.properties +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/.last_build_id +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages + +### Kotlin ### +# Compiled class file +*.class + +# Log file + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### Objective-C ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + +### Objective-C Patch ### + +### Swift ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + + + + + + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### Xcode ### + +## Xcode 8 and earlier + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcodeproj/project.xcworkspace/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno +**/xcshareddata/WorkspaceSettings.xcsettings + +### AndroidStudio ### +# Covers files to be ignored for android development using Android Studio. + +# Built application files +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle + +# Signing files +.signing/ + +# Local configuration file (sdk path, etc) + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files + +# Android Studio +/*/build/ +/*/local.properties +/*/out +/*/*/build +/*/*/production +.navigation/ +*.ipr +*~ +*.swp + +# Keystore files + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Android Patch + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# NDK +obj/ + +# IntelliJ IDEA +*.iws +/out/ + +# User-specific configurations +.idea/caches/ +.idea/libraries/ +.idea/shelf/ +.idea/workspace.xml +.idea/tasks.xml +.idea/.name +.idea/compiler.xml +.idea/copyright/profiles_settings.xml +.idea/encodings.xml +.idea/misc.xml +.idea/modules.xml +.idea/scopes/scope_settings.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml +.idea/datasources.xml +.idea/dataSources.ids +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml +.idea/assetWizardSettings.xml +.idea/gradle.xml +.idea/jarRepositories.xml +.idea/navEditor.xml + +# Legacy Eclipse project files +.classpath +.project +.cproject +.settings/ + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) + +## Plugin-specific files: + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Mongo Explorer plugin +.idea/mongoSettings.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### AndroidStudio Patch ### + +!/gradle/wrapper/gradle-wrapper.jar + +# End of https://www.toptal.com/developers/gitignore/api/androidstudio,visualstudiocode,flutter,dart,android,kotlin,xcode,swift,objective-c \ No newline at end of file diff --git a/gamestore/.idea/.gitignore b/gamestore/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/gamestore/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/gamestore/.idea/gamestore.iml b/gamestore/.idea/gamestore.iml new file mode 100644 index 0000000..c898a44 --- /dev/null +++ b/gamestore/.idea/gamestore.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gamestore/.idea/git_toolbox_prj.xml b/gamestore/.idea/git_toolbox_prj.xml new file mode 100644 index 0000000..02b915b --- /dev/null +++ b/gamestore/.idea/git_toolbox_prj.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/gamestore/.idea/runConfigurations/Build APK.run.xml b/gamestore/.idea/runConfigurations/Build APK.run.xml new file mode 100644 index 0000000..9ca18e0 --- /dev/null +++ b/gamestore/.idea/runConfigurations/Build APK.run.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/gamestore/.idea/runConfigurations/Build IPA.run.xml b/gamestore/.idea/runConfigurations/Build IPA.run.xml new file mode 100644 index 0000000..8b84e6f --- /dev/null +++ b/gamestore/.idea/runConfigurations/Build IPA.run.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/gamestore/.idea/runConfigurations/Dart_cleanup.xml b/gamestore/.idea/runConfigurations/Dart_cleanup.xml new file mode 100644 index 0000000..889d64a --- /dev/null +++ b/gamestore/.idea/runConfigurations/Dart_cleanup.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/gamestore/.idea/runConfigurations/Debug launch Develop.run.xml b/gamestore/.idea/runConfigurations/Debug launch Develop.run.xml new file mode 100644 index 0000000..7d06409 --- /dev/null +++ b/gamestore/.idea/runConfigurations/Debug launch Develop.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/gamestore/.idea/runConfigurations/Debug launch Prod.run.xml b/gamestore/.idea/runConfigurations/Debug launch Prod.run.xml new file mode 100644 index 0000000..7ae1878 --- /dev/null +++ b/gamestore/.idea/runConfigurations/Debug launch Prod.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/gamestore/.idea/runConfigurations/Profile launch Develop.run.xml b/gamestore/.idea/runConfigurations/Profile launch Develop.run.xml new file mode 100644 index 0000000..d00b0a0 --- /dev/null +++ b/gamestore/.idea/runConfigurations/Profile launch Develop.run.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/gamestore/.idea/runConfigurations/Release launch Develop.run.xml b/gamestore/.idea/runConfigurations/Release launch Develop.run.xml new file mode 100644 index 0000000..d156875 --- /dev/null +++ b/gamestore/.idea/runConfigurations/Release launch Develop.run.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/gamestore/.idea/runConfigurations/Release launch Prod.run.xml b/gamestore/.idea/runConfigurations/Release launch Prod.run.xml new file mode 100644 index 0000000..6d8476f --- /dev/null +++ b/gamestore/.idea/runConfigurations/Release launch Prod.run.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/gamestore/.metadata b/gamestore/.metadata new file mode 100644 index 0000000..6c07a80 --- /dev/null +++ b/gamestore/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "efbf63d9c66b9f6ec30e9ad4611189aa80003d31" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31 + base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31 + - platform: ios + create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31 + base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/gamestore/README.md b/gamestore/README.md new file mode 100644 index 0000000..c04a143 --- /dev/null +++ b/gamestore/README.md @@ -0,0 +1,16 @@ +# gamestore + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/gamestore/analysis_options.yaml b/gamestore/analysis_options.yaml new file mode 100644 index 0000000..6783e42 --- /dev/null +++ b/gamestore/analysis_options.yaml @@ -0,0 +1,219 @@ +# include: package:flutter_lints/flutter.yaml +include: package:very_good_analysis/analysis_options.yaml + +analyzer: + + errors: + avoid_dynamic_calls: error + missing_required_param: error + missing_return: error + # allow having TODOs in the code + todo: info + missing_enum_constant_in_switch: error + implicit_dynamic_type: info + implicit_dynamic_map_literal: info + implicit_dynamic_list_literal: info + implicit_dynamic_method: warning + implicit_dynamic_function: warning + invalid_use_of_protected_member: error + unused_local_variable: warning + deprecated_member_use: warning + unused_element: warning + unused_field: warning + dead_code: error + must_call_super: error + + # linter errors + unnecessary_statements: error + recursive_getters: error + unnecessary_new: error + unnecessary_getters_setters: error + use_function_type_syntax_for_parameters: error + no_duplicate_case_values: error + no_adjacent_strings_in_list: error + non_constant_identifier_names: error + constant_identifier_names: error + avoid_returning_this: error + prefer_const_constructors_in_immutables: error + prefer_const_literals_to_create_immutables: error + avoid_equals_and_hash_code_on_mutable_classes: error + camel_case_types: error + camel_case_extensions: error + library_names: error + file_names: error + library_prefixes: error + + # linter warnings + avoid_print: warning + unnecessary_lambdas: warning + use_key_in_widget_constructors: warning + prefer_final_fields: warning + prefer_final_locals: warning + prefer_final_in_for_each: warning + prefer_const_constructors: warning + unnecessary_const: warning + unnecessary_brace_in_string_interps: warning + + # Ignore analyzer hints for updating pubspecs when using Future or + # Stream and not importing dart:async + # Please see https://github.com/flutter/flutter/pull/24528 for details. + sdk_version_async_exported_from_core: ignore + exclude: + - "bin/cache/**" + - "**/*.chopper.dart" + - "**/generated/**" + - "**/*.g.dart" + language: + strict-casts: true + strict-raw-types: true + +linter: + rules: + # these rules are documented on and in the same order as + # the Dart Lint rules page to make maintenance easier + # 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 + - always_require_non_null_named_parameters + - avoid_dynamic_calls + # - always_specify_types + - annotate_overrides + - avoid_print + # - avoid_annotating_with_dynamic # conflicts with always_specify_types + - avoid_returning_this + - avoid_init_to_null + - avoid_bool_literals_in_conditional_expressions + # - avoid_catches_without_on_clauses # we do this commonly + # - avoid_catching_errors # we do this commonly + # - avoid_classes_with_only_static_members + # - avoid_double_and_int_checks # only useful when targeting JS runtime + - avoid_empty_else + - avoid_field_initializers_in_const_classes + - avoid_function_literals_in_foreach_calls + # - avoid_js_rounded_ints # only useful when targeting JS runtime + - avoid_null_checks_in_equality_operators + # - avoid_positional_boolean_parameters + # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) + - avoid_relative_lib_imports + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + # - avoid_returning_null # there are plenty of valid reasons to return null + # - avoid_returning_null_for_future # not yet tested + - avoid_returning_null_for_void + # - avoid_returning_this # there are plenty of valid reasons to return this + # - avoid_setters_without_getters # not yet tested + # - avoid_shadowing_type_parameters # not yet tested + # - avoid_single_cascade_in_expression_statements # not yet tested + - avoid_slow_async_io + - avoid_types_as_parameter_names + # - avoid_types_on_closure_parameters # conflicts with always_specify_types + - avoid_unused_constructor_parameters + - avoid_void_async + - await_only_futures + - camel_case_types + - cancel_subscriptions + # - cascade_invocations # not yet tested + # - close_sinks # not reliable enough + # - comment_references # blocked on https://github.com/flutter/flutter/issues/20765 + # - 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 yet tested + # - diagnostic_describe_all_properties # not yet tested + - directives_ordering + - empty_catches + - empty_constructor_bodies + - empty_statements + # - file_names # not yet tested + - hash_and_equals + - implementation_imports + # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 + - collection_methods_unrelated_type + # - join_return_with_assignment # not yet tested + - library_names + - library_prefixes + # - lines_longer_than_80_chars # not yet tested + # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181 + - no_adjacent_strings_in_list + - no_duplicate_case_values + - non_constant_identifier_names + # - null_closures # not yet tested + # - omit_local_variable_types # opposite of always_specify_types + # - one_member_abstracts # too many false positives + # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 + - 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 yet tested + - 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 # not yet tested + - prefer_contains + # - prefer_double_quotes # opposite of prefer_single_quotes + # - 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 # not yet tested + - prefer_final_locals + # - prefer_for_elements_to_map_fromIterable # not yet tested + - prefer_foreach + # - prefer_function_declarations_over_variables # not yet tested + - prefer_generic_function_type_aliases + # - prefer_if_elements_to_conditional_expressions # not yet tested + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + # - prefer_int_literals # not yet tested + # - prefer_interpolation_to_compose_strings # not yet tested + - prefer_is_empty + - prefer_is_not_empty + - prefer_iterable_whereType + # - prefer_mixin # https://github.com/dart-lang/language/issues/32 + # - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932 + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - prefer_void_to_null + # - provide_deprecation_message # not yet tested + # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml + - recursive_getters + - slash_for_doc_comments + # - sort_child_properties_last # not yet tested + # - sort_constructors_first + # - sort_pub_dependencies + - sort_unnamed_constructors_first + - test_types_in_equals + - throw_in_finally + # - type_annotate_public_apis # subset of always_specify_types + - type_init_formals + - unawaited_futures + # - unnecessary_await_in_return # not yet tested + - unnecessary_brace_in_string_interps + - unnecessary_const + - unnecessary_getters_setters + # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_in_if_null_operators + - unnecessary_overrides + - unnecessary_parenthesis + - unnecessary_statements + - unnecessary_this + - unrelated_type_equality_checks + # - unsafe_html # not yet tested + - use_full_hex_values_for_flutter_colors + # - use_function_type_syntax_for_parameters # not yet tested + - use_rethrow_when_possible + - use_key_in_widget_constructors + # - use_setters_to_change_properties # not yet tested + # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 + # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review + - valid_regexps + # - void_checks # not yet tested diff --git a/gamestore/android/.gitignore b/gamestore/android/.gitignore new file mode 100644 index 0000000..66bda08 --- /dev/null +++ b/gamestore/android/.gitignore @@ -0,0 +1,39 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks + +# User-specific configurations +.idea/caches/ +.idea/libraries/ +.idea/shelf/ +.idea/workspace.xml +.idea/tasks.xml +.idea/.name +.idea/compiler.xml +.idea/copyright/profiles_settings.xml +.idea/encodings.xml +.idea/misc.xml +.idea/modules.xml +.idea/scopes/scope_settings.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml +.idea/datasources.xml +.idea/dataSources.ids +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml +.idea/assetWizardSettings.xml +.idea/gradle.xml +.idea/jarRepositories.xml +.idea/navEditor.xml \ No newline at end of file diff --git a/gamestore/android/.idea/kotlinc.xml b/gamestore/android/.idea/kotlinc.xml new file mode 100644 index 0000000..b1077fb --- /dev/null +++ b/gamestore/android/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/gamestore/android/app/build.gradle b/gamestore/android/app/build.gradle new file mode 100644 index 0000000..e0d5309 --- /dev/null +++ b/gamestore/android/app/build.gradle @@ -0,0 +1,91 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + + // ----- BEGIN flavorDimensions (autogenerated by flutter_flavorizr) ----- + flavorDimensions "flavor-type" + + productFlavors { + develop { + dimension "flavor-type" + applicationIdSuffix ".dev" + resValue "string", "app_name", "Gamestore dev" + versionNameSuffix ".dev" + } + prod { + dimension "flavor-type" + resValue "string", "app_name", "Gamestore" + } + } + + // ----- END flavorDimensions (autogenerated by flutter_flavorizr) ----- + namespace "com.aequoplay.gamestore" + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.aequoplay.gamestore" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + multiDexEnabled true + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/gamestore/android/app/src/develop/AndroidManifest.xml b/gamestore/android/app/src/develop/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/gamestore/android/app/src/develop/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/gamestore/android/app/src/develop/res/mipmap-hdpi/launcher_icon.png b/gamestore/android/app/src/develop/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000..beecbd2 Binary files /dev/null and b/gamestore/android/app/src/develop/res/mipmap-hdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/develop/res/mipmap-mdpi/launcher_icon.png b/gamestore/android/app/src/develop/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000..a0121fb Binary files /dev/null and b/gamestore/android/app/src/develop/res/mipmap-mdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/develop/res/mipmap-xhdpi/launcher_icon.png b/gamestore/android/app/src/develop/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000..e8aea96 Binary files /dev/null and b/gamestore/android/app/src/develop/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/develop/res/mipmap-xxhdpi/launcher_icon.png b/gamestore/android/app/src/develop/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000..719b257 Binary files /dev/null and b/gamestore/android/app/src/develop/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/develop/res/mipmap-xxxhdpi/launcher_icon.png b/gamestore/android/app/src/develop/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000..465b37f Binary files /dev/null and b/gamestore/android/app/src/develop/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/main/AndroidManifest.xml b/gamestore/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..75dc595 --- /dev/null +++ b/gamestore/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/gamestore/android/app/src/main/kotlin/com/aequoplay/gamestore/gamestore/MainActivity.kt b/gamestore/android/app/src/main/kotlin/com/aequoplay/gamestore/gamestore/MainActivity.kt new file mode 100644 index 0000000..d918832 --- /dev/null +++ b/gamestore/android/app/src/main/kotlin/com/aequoplay/gamestore/gamestore/MainActivity.kt @@ -0,0 +1,6 @@ +package com.aequoplay.gamestore + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/gamestore/android/app/src/main/res/drawable-v21/launch_background.xml b/gamestore/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/gamestore/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gamestore/android/app/src/main/res/drawable/launch_background.xml b/gamestore/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/gamestore/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gamestore/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/gamestore/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/gamestore/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/gamestore/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/gamestore/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/gamestore/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/gamestore/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/gamestore/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/gamestore/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/gamestore/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/gamestore/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/gamestore/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/gamestore/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/gamestore/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/gamestore/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/gamestore/android/app/src/main/res/values-night/styles.xml b/gamestore/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/gamestore/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/gamestore/android/app/src/main/res/values/styles.xml b/gamestore/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/gamestore/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/gamestore/android/app/src/prod/AndroidManifest.xml b/gamestore/android/app/src/prod/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/gamestore/android/app/src/prod/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/gamestore/android/app/src/prod/res/mipmap-hdpi/launcher_icon.png b/gamestore/android/app/src/prod/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000..057fdb9 Binary files /dev/null and b/gamestore/android/app/src/prod/res/mipmap-hdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/prod/res/mipmap-mdpi/launcher_icon.png b/gamestore/android/app/src/prod/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000..52d11d0 Binary files /dev/null and b/gamestore/android/app/src/prod/res/mipmap-mdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/prod/res/mipmap-xhdpi/launcher_icon.png b/gamestore/android/app/src/prod/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000..2f886ee Binary files /dev/null and b/gamestore/android/app/src/prod/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/prod/res/mipmap-xxhdpi/launcher_icon.png b/gamestore/android/app/src/prod/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000..7fabff5 Binary files /dev/null and b/gamestore/android/app/src/prod/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/prod/res/mipmap-xxxhdpi/launcher_icon.png b/gamestore/android/app/src/prod/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000..0881e45 Binary files /dev/null and b/gamestore/android/app/src/prod/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/gamestore/android/app/src/profile/AndroidManifest.xml b/gamestore/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/gamestore/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/gamestore/android/build.gradle b/gamestore/android/build.gradle new file mode 100644 index 0000000..bf1ce3f --- /dev/null +++ b/gamestore/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/gamestore/android/gradle.properties b/gamestore/android/gradle.properties new file mode 100644 index 0000000..b9a9a24 --- /dev/null +++ b/gamestore/android/gradle.properties @@ -0,0 +1,6 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false diff --git a/gamestore/android/gradle/wrapper/gradle-wrapper.properties b/gamestore/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..8bc9958 --- /dev/null +++ b/gamestore/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip diff --git a/gamestore/android/settings.gradle b/gamestore/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/gamestore/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/gamestore/assets/icons/.gitkeep b/gamestore/assets/icons/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/gamestore/assets/logos/.gitkeep b/gamestore/assets/logos/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/gamestore/assets/res/app_icon-dev.png b/gamestore/assets/res/app_icon-dev.png new file mode 100644 index 0000000..6d811a0 Binary files /dev/null and b/gamestore/assets/res/app_icon-dev.png differ diff --git a/gamestore/assets/res/app_icon.png b/gamestore/assets/res/app_icon.png new file mode 100644 index 0000000..5ef17d3 Binary files /dev/null and b/gamestore/assets/res/app_icon.png differ diff --git a/gamestore/flavorizr.yaml b/gamestore/flavorizr.yaml new file mode 100644 index 0000000..2d31ce6 --- /dev/null +++ b/gamestore/flavorizr.yaml @@ -0,0 +1,39 @@ +flavors: + develop: + app: + name: "AequoPlay Gamestore dev" + icon: "assets/res/app_icon-dev.png" + + android: + applicationId: "com.aequoplay.gamestore.dev" + ios: + bundleId: "com.aequoplay.gamestore.dev" + macos: + bundleId: "com.aequoplay.gamestore.dev" + + + prod: + app: + name: "AequoPlay Gamestore" + icon: "assets/res/app_icon.png" + + android: + applicationId: "com.aequoplay.gamestore" + ios: + bundleId: "com.aequoplay.gamestore" + macos: + bundleId: "ccom.aequoplay.gamestore" + + + +instructions: + - android:buildGradle, +# - android:icons +# - ios:xcconfig +# - ios:buildTargets +# - ios:schema +# - ios:icons + - ios:plist +# - assets:clean + +ide: "idea" diff --git a/gamestore/flutter_launcher_icons-develop.yaml b/gamestore/flutter_launcher_icons-develop.yaml new file mode 100644 index 0000000..a167aeb --- /dev/null +++ b/gamestore/flutter_launcher_icons-develop.yaml @@ -0,0 +1,18 @@ +flutter_icons: + android: "launcher_icon" + ios: true + remove_alpha_ios: true + image_path: "assets/res/app_icon-dev.png" + min_sdk_android: 23 + web: + generate: false + image_path: "path/to/image.png" + background_color: "#hexcode" + theme_color: "#hexcode" + windows: + generate: false + image_path: "path/to/image.png" + icon_size: 48 # min:48, max:256, default: 48 + macos: + generate: false + image_path: "path/to/image.png" \ No newline at end of file diff --git a/gamestore/flutter_launcher_icons-prod.yaml b/gamestore/flutter_launcher_icons-prod.yaml new file mode 100644 index 0000000..3794d1f --- /dev/null +++ b/gamestore/flutter_launcher_icons-prod.yaml @@ -0,0 +1,18 @@ +flutter_icons: + android: "launcher_icon" + ios: true + remove_alpha_ios: true + image_path: "assets/res/app_icon.png" + min_sdk_android: 23 + web: + generate: false + image_path: "path/to/image.png" + background_color: "#hexcode" + theme_color: "#hexcode" + windows: + generate: false + image_path: "path/to/image.png" + icon_size: 48 # min:48, max:256, default: 48 + macos: + generate: false + image_path: "path/to/image.png" \ No newline at end of file diff --git a/gamestore/flutter_native_splash.yaml b/gamestore/flutter_native_splash.yaml new file mode 100644 index 0000000..356ce63 --- /dev/null +++ b/gamestore/flutter_native_splash.yaml @@ -0,0 +1,134 @@ +flutter_native_splash: + # To restore Flutter's default white splash screen, run the following command in the terminal: + # dart run flutter_native_splash:remove + + # color or background_image is the only required parameter. Use color to set the background + # of your splash screen to a solid color. Use background_image to set the background of your + # splash screen to a png image. This is useful for gradients. The image will be stretch to the + # size of the app. Only one parameter can be used, color and background_image cannot both be set. + color: "#42a5f5" + #background_image: "assets/background.png" + + # Optional parameters are listed below. To enable a parameter, uncomment the line by removing + # the leading # character. + + # The image parameter allows you to specify an image used in the splash screen. It must be a + # png file and should be sized for 4x pixel density. + #image: assets/splash.png + + # The branding property allows you to specify an image used as branding in the splash screen. + # It must be a png file. It is supported for Android, iOS and the Web. For Android 12, + # see the Android 12 section below. + #branding: assets/dart.png + + # To position the branding image at the bottom of the screen you can use bottom, bottomRight, + # and bottomLeft. The default values is bottom if not specified or specified something else. + #branding_mode: bottom + + # The color_dark, background_image_dark, image_dark, branding_dark are parameters that set the background + # and image when the device is in dark mode. If they are not specified, the app will use the + # parameters from above. If the image_dark parameter is specified, color_dark or + # background_image_dark must be specified. color_dark and background_image_dark cannot both be + # set. + #color_dark: "#042a49" + #background_image_dark: "assets/dark-background.png" + #image_dark: assets/splash-invert.png + #branding_dark: assets/dart_dark.png + + # Android 12 handles the splash screen differently than previous versions. Please visit + # https://developer.android.com/guide/topics/ui/splash-screen + # Following are Android 12 specific parameter. + android_12: + # The image parameter sets the splash screen icon image. If this parameter is not specified, + # the app's launcher icon will be used instead. + # Please note that the splash screen will be clipped to a circle on the center of the screen. + # App icon with an icon background: This should be 960Γ—960 pixels, and fit within a circle + # 640 pixels in diameter. + # App icon without an icon background: This should be 1152Γ—1152 pixels, and fit within a circle + # 768 pixels in diameter. + #image: assets/android12splash.png + + # Splash screen background color. + #color: "#42a5f5" + + # App icon background color. + #icon_background_color: "#111111" + + # The branding property allows you to specify an image used as branding in the splash screen. + #branding: assets/dart.png + + # The image_dark, color_dark, icon_background_color_dark, and branding_dark set values that + # apply when the device is in dark mode. If they are not specified, the app will use the + # parameters from above. + #image_dark: assets/android12splash-invert.png + #color_dark: "#042a49" + #icon_background_color_dark: "#eeeeee" + + # The android, ios and web parameters can be used to disable generating a splash screen on a given + # platform. + #android: false + #ios: false + #web: false + + # Platform specific images can be specified with the following parameters, which will override + # the respective parameter. You may specify all, selected, or none of these parameters: + #color_android: "#42a5f5" + #color_dark_android: "#042a49" + #color_ios: "#42a5f5" + #color_dark_ios: "#042a49" + #color_web: "#42a5f5" + #color_dark_web: "#042a49" + #image_android: assets/splash-android.png + #image_dark_android: assets/splash-invert-android.png + #image_ios: assets/splash-ios.png + #image_dark_ios: assets/splash-invert-ios.png + #image_web: assets/splash-web.gif + #image_dark_web: assets/splash-invert-web.gif + #background_image_android: "assets/background-android.png" + #background_image_dark_android: "assets/dark-background-android.png" + #background_image_ios: "assets/background-ios.png" + #background_image_dark_ios: "assets/dark-background-ios.png" + #background_image_web: "assets/background-web.png" + #background_image_dark_web: "assets/dark-background-web.png" + #branding_android: assets/brand-android.png + #branding_dark_android: assets/dart_dark-android.png + #branding_ios: assets/brand-ios.gif + #branding_dark_ios: assets/dart_dark-ios.gif + + # The position of the splash image can be set with android_gravity, ios_content_mode, and + # web_image_mode parameters. All default to center. + # + # android_gravity can be one of the following Android Gravity (see + # https://developer.android.com/reference/android/view/Gravity): bottom, center, + # center_horizontal, center_vertical, clip_horizontal, clip_vertical, end, fill, fill_horizontal, + # fill_vertical, left, right, start, or top. + #android_gravity: center + # + # ios_content_mode can be one of the following iOS UIView.ContentMode (see + # https://developer.apple.com/documentation/uikit/uiview/contentmode): scaleToFill, + # scaleAspectFit, scaleAspectFill, center, top, bottom, left, right, topLeft, topRight, + # bottomLeft, or bottomRight. + #ios_content_mode: center + # + # web_image_mode can be one of the following modes: center, contain, stretch, and cover. + #web_image_mode: center + + # The screen orientation can be set in Android with the android_screen_orientation parameter. + # Valid parameters can be found here: + # https://developer.android.com/guide/topics/manifest/activity-element#screen + #android_screen_orientation: sensorLandscape + + # To hide the notification bar, use the fullscreen parameter. Has no effect in web since web + # has no notification bar. Defaults to false. + # NOTE: Unlike Android, iOS will not automatically show the notification bar when the app loads. + # To show the notification bar, add the following code to your Flutter app: + # WidgetsFlutterBinding.ensureInitialized(); + # SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top], ); + #fullscreen: true + + # If you have changed the name(s) of your info.plist file(s), you can specify the filename(s) + # with the info_plist_files parameter. Remove only the # characters in the three lines below, + # do not remove any spaces: + #info_plist_files: + # - 'ios/Runner/Info-Debug.plist' + # - 'ios/Runner/Info-Release.plist' \ No newline at end of file diff --git a/gamestore/ios/.gitignore b/gamestore/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/gamestore/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/gamestore/ios/Flutter/AppFrameworkInfo.plist b/gamestore/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..9625e10 --- /dev/null +++ b/gamestore/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/gamestore/ios/Flutter/Debug.xcconfig b/gamestore/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/gamestore/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/gamestore/ios/Flutter/Release.xcconfig b/gamestore/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/gamestore/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/gamestore/ios/Podfile b/gamestore/ios/Podfile new file mode 100644 index 0000000..24c9161 --- /dev/null +++ b/gamestore/ios/Podfile @@ -0,0 +1,49 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + # Use pre-compiled SDK for FirebaseFirestore, to speed-up build times + # from https://github.com/invertase/firestore-ios-sdk-frameworks + # Use https://github.com/firebase/flutterfire/blob/master/packages/firebase_core/firebase_core/ios/firebase_sdk_version.rb to check for the latest version number + pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '10.12.0' + + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +# target 'RunnerTests' do +# inherit! :search_paths +# end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/gamestore/ios/Podfile.lock b/gamestore/ios/Podfile.lock new file mode 100644 index 0000000..d88382f --- /dev/null +++ b/gamestore/ios/Podfile.lock @@ -0,0 +1,154 @@ +PODS: + - cloud_firestore (4.8.5): + - Firebase/Firestore (= 10.12.0) + - firebase_core + - Flutter + - nanopb (< 2.30910.0, >= 2.30908.0) + - Firebase/CoreOnly (10.12.0): + - FirebaseCore (= 10.12.0) + - Firebase/Crashlytics (10.12.0): + - Firebase/CoreOnly + - FirebaseCrashlytics (~> 10.12.0) + - Firebase/Firestore (10.12.0): + - Firebase/CoreOnly + - FirebaseFirestore (~> 10.12.0) + - firebase_core (2.15.1): + - Firebase/CoreOnly (= 10.12.0) + - Flutter + - firebase_crashlytics (3.3.5): + - Firebase/Crashlytics (= 10.12.0) + - firebase_core + - Flutter + - FirebaseCore (10.12.0): + - FirebaseCoreInternal (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/Logger (~> 7.8) + - FirebaseCoreExtension (10.14.0): + - FirebaseCore (~> 10.0) + - FirebaseCoreInternal (10.14.0): + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseCrashlytics (10.12.0): + - FirebaseCore (~> 10.5) + - FirebaseInstallations (~> 10.0) + - FirebaseSessions (~> 10.5) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.8) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesObjC (~> 2.1) + - FirebaseFirestore (10.12.0): + - FirebaseFirestore/AutodetectLeveldb (= 10.12.0) + - FirebaseFirestore/AutodetectLeveldb (10.12.0): + - FirebaseFirestore/Base + - FirebaseFirestore/WithLeveldb + - FirebaseFirestore/Base (10.12.0) + - FirebaseFirestore/WithLeveldb (10.12.0): + - FirebaseFirestore/Base + - FirebaseInstallations (10.14.0): + - FirebaseCore (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) + - PromisesObjC (~> 2.1) + - FirebaseSessions (10.14.0): + - FirebaseCore (~> 10.5) + - FirebaseCoreExtension (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.10) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesSwift (~> 2.1) + - Flutter (1.0.0) + - flutter_native_splash (0.0.1): + - Flutter + - GoogleDataTransport (9.2.5): + - GoogleUtilities/Environment (~> 7.7) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Environment (7.11.5): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.11.5): + - GoogleUtilities/Environment + - "GoogleUtilities/NSData+zlib (7.11.5)" + - GoogleUtilities/UserDefaults (7.11.5): + - GoogleUtilities/Logger + - nanopb (2.30909.0): + - nanopb/decode (= 2.30909.0) + - nanopb/encode (= 2.30909.0) + - nanopb/decode (2.30909.0) + - nanopb/encode (2.30909.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - PromisesObjC (2.3.1) + - PromisesSwift (2.3.1): + - PromisesObjC (= 2.3.1) + +DEPENDENCIES: + - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) + - FirebaseFirestore (from `https://github.com/invertase/firestore-ios-sdk-frameworks.git`, tag `10.12.0`) + - Flutter (from `Flutter`) + - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + +SPEC REPOS: + trunk: + - Firebase + - FirebaseCore + - FirebaseCoreExtension + - FirebaseCoreInternal + - FirebaseCrashlytics + - FirebaseInstallations + - FirebaseSessions + - GoogleDataTransport + - GoogleUtilities + - nanopb + - PromisesObjC + - PromisesSwift + +EXTERNAL SOURCES: + cloud_firestore: + :path: ".symlinks/plugins/cloud_firestore/ios" + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_crashlytics: + :path: ".symlinks/plugins/firebase_crashlytics/ios" + FirebaseFirestore: + :git: https://github.com/invertase/firestore-ios-sdk-frameworks.git + :tag: 10.12.0 + Flutter: + :path: Flutter + flutter_native_splash: + :path: ".symlinks/plugins/flutter_native_splash/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + +CHECKOUT OPTIONS: + FirebaseFirestore: + :git: https://github.com/invertase/firestore-ios-sdk-frameworks.git + :tag: 10.12.0 + +SPEC CHECKSUMS: + cloud_firestore: c556fefce96568e422e453bf9aeda683dd435367 + Firebase: 07150e75d142fb9399f6777fa56a187b17f833a0 + firebase_core: 4a3246a02f828a01c74a2c26427037786d90f17f + firebase_crashlytics: df144edf7d04ace42beb3a3e29d825bfa49dd04b + FirebaseCore: f86a1394906b97ac445ae49c92552a9425831bed + FirebaseCoreExtension: 976638051b1a46b503afce7ec80277f9161f2040 + FirebaseCoreInternal: d558159ee6cc4b823c2296ecc193de9f6d9a5bb3 + FirebaseCrashlytics: c4d111b7430c49744c74bcc6346ea00868661ac8 + FirebaseFirestore: 8d9dd05bb50e0891ebe4fdd9bd0f9b9d22ea5556 + FirebaseInstallations: f672b1eda64e6381c21d424a2f680a943fd83f3b + FirebaseSessions: f145e7365d36bec0d724c4574a8750e6f82fa6c8 + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef + GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2 + GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084 + nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 + PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265 + +PODFILE CHECKSUM: 7f097e782cb82b6dd602b7ffce0ccb34f1aa2f14 + +COCOAPODS: 1.12.1 diff --git a/gamestore/ios/Runner.xcodeproj/project.pbxproj b/gamestore/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..c77ced5 --- /dev/null +++ b/gamestore/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,1002 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 025E17C09ABA3002D0EAE0CF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F0F9E85E53EAE7C45008ADE /* Pods_Runner.framework */; }; + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0A7DA883DD4FD1EA77564827 /* Pods-Runner.release-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-prod.xcconfig"; sourceTree = ""; }; + 0AAB445AFDACE0FDEEDC867B /* Pods-Runner.release-develop.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-develop.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-develop.xcconfig"; sourceTree = ""; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 1D480218F83E89DAFDFBA6AD /* Pods-Runner.debug-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-prod.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 45E81EF0475B285611C3D4FA /* Pods-Runner.debug-develop.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-develop.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-develop.xcconfig"; sourceTree = ""; }; + 4F0F9E85E53EAE7C45008ADE /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 60CF85B7BE9BC035402A2852 /* Pods-Runner.profile-develop.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-develop.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-develop.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A1E6546006C3326A6634EAF0 /* Pods-Runner.profile-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-prod.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 025E17C09ABA3002D0EAE0CF /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 7EC7A991E8F1B65107B9EED8 /* Pods */ = { + isa = PBXGroup; + children = ( + 1D480218F83E89DAFDFBA6AD /* Pods-Runner.debug-prod.xcconfig */, + 45E81EF0475B285611C3D4FA /* Pods-Runner.debug-develop.xcconfig */, + 0A7DA883DD4FD1EA77564827 /* Pods-Runner.release-prod.xcconfig */, + 0AAB445AFDACE0FDEEDC867B /* Pods-Runner.release-develop.xcconfig */, + A1E6546006C3326A6634EAF0 /* Pods-Runner.profile-prod.xcconfig */, + 60CF85B7BE9BC035402A2852 /* Pods-Runner.profile-develop.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + 7EC7A991E8F1B65107B9EED8 /* Pods */, + DD0167235D037E4A0C2D0883 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + DD0167235D037E4A0C2D0883 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4F0F9E85E53EAE7C45008ADE /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + C9AB6FC4BF39B56152D51A45 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 7BF18DC9F6E41146D587F360 /* [CP] Embed Pods Frameworks */, + F3724DF3309EA42A1E185243 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 7BF18DC9F6E41146D587F360 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + C9AB6FC4BF39B56152D51A45 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + F3724DF3309EA42A1E185243 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile-prod */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Profile-prod"; + }; + 249021D4217E4FDB00AE95B9 /* Profile-prod */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + APP_DISPLAY_NAME = Gamestore; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = YY8TRZ9JW3; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "AequoPlay Gamestore"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-prod"; + }; + 24ED26922A955A6300DA3478 /* Debug-develop */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-develop"; + }; + 24ED26932A955A6300DA3478 /* Debug-develop */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + APP_DISPLAY_NAME = "Gamestore dev"; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-develop"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = YY8TRZ9JW3; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "AequoPlay Gamestore dev"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-develop"; + }; + 24ED26942A955A6300DA3478 /* Debug-develop */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = "Debug-develop"; + }; + 24ED26952A955A6500DA3478 /* Release-develop */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-develop"; + }; + 24ED26962A955A6500DA3478 /* Release-develop */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + APP_DISPLAY_NAME = "Gamestore dev"; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-develop"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = YY8TRZ9JW3; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "AequoPlay Gamestore dev"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-develop"; + }; + 24ED26972A955A6500DA3478 /* Release-develop */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = "Release-develop"; + }; + 24ED26982A955A6700DA3478 /* Profile-develop */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Profile-develop"; + }; + 24ED26992A955A6700DA3478 /* Profile-develop */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + APP_DISPLAY_NAME = "Gamestore dev"; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-develop"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = YY8TRZ9JW3; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "AequoPlay Gamestore dev"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-develop"; + }; + 24ED269A2A955A6700DA3478 /* Profile-develop */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = "Profile-develop"; + }; + 331C8088294A63A400263BE5 /* Debug-prod */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = "Debug-prod"; + }; + 331C8089294A63A400263BE5 /* Release-prod */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = "Release-prod"; + }; + 331C808A294A63A400263BE5 /* Profile-prod */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = "Profile-prod"; + }; + 97C147031CF9000F007C117D /* Debug-prod */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-prod"; + }; + 97C147041CF9000F007C117D /* Release-prod */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-prod"; + }; + 97C147061CF9000F007C117D /* Debug-prod */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + APP_DISPLAY_NAME = Gamestore; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = YY8TRZ9JW3; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "AequoPlay Gamestore"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-prod"; + }; + 97C147071CF9000F007C117D /* Release-prod */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + APP_DISPLAY_NAME = Gamestore; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = YY8TRZ9JW3; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "AequoPlay Gamestore"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.aequoplay.gamestore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-prod"; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug-prod */, + 24ED26942A955A6300DA3478 /* Debug-develop */, + 331C8089294A63A400263BE5 /* Release-prod */, + 24ED26972A955A6500DA3478 /* Release-develop */, + 331C808A294A63A400263BE5 /* Profile-prod */, + 24ED269A2A955A6700DA3478 /* Profile-develop */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Release-prod"; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug-prod */, + 24ED26922A955A6300DA3478 /* Debug-develop */, + 97C147041CF9000F007C117D /* Release-prod */, + 24ED26952A955A6500DA3478 /* Release-develop */, + 249021D3217E4FDB00AE95B9 /* Profile-prod */, + 24ED26982A955A6700DA3478 /* Profile-develop */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Release-prod"; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug-prod */, + 24ED26932A955A6300DA3478 /* Debug-develop */, + 97C147071CF9000F007C117D /* Release-prod */, + 24ED26962A955A6500DA3478 /* Release-develop */, + 249021D4217E4FDB00AE95B9 /* Profile-prod */, + 24ED26992A955A6700DA3478 /* Profile-develop */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Release-prod"; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/gamestore/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/gamestore/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/gamestore/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/gamestore/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/gamestore/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/gamestore/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/gamestore/ios/Runner.xcodeproj/xcshareddata/xcschemes/develop.xcscheme b/gamestore/ios/Runner.xcodeproj/xcshareddata/xcschemes/develop.xcscheme new file mode 100644 index 0000000..9e7c733 --- /dev/null +++ b/gamestore/ios/Runner.xcodeproj/xcshareddata/xcschemes/develop.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gamestore/ios/Runner.xcodeproj/xcshareddata/xcschemes/prod.xcscheme b/gamestore/ios/Runner.xcodeproj/xcshareddata/xcschemes/prod.xcscheme new file mode 100644 index 0000000..a434fbd --- /dev/null +++ b/gamestore/ios/Runner.xcodeproj/xcshareddata/xcschemes/prod.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gamestore/ios/Runner.xcworkspace/contents.xcworkspacedata b/gamestore/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/gamestore/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/gamestore/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/gamestore/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/gamestore/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/gamestore/ios/Runner/AppDelegate.swift b/gamestore/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/gamestore/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-1024x1024@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-1024x1024@1x.png new file mode 100644 index 0000000..bee68e7 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-1024x1024@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-20x20@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-20x20@1x.png new file mode 100644 index 0000000..564001e Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-20x20@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-20x20@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-20x20@2x.png new file mode 100644 index 0000000..b7ce0b7 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-20x20@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-20x20@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-20x20@3x.png new file mode 100644 index 0000000..511fbe0 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-20x20@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-29x29@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-29x29@1x.png new file mode 100644 index 0000000..c2d82a8 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-29x29@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-29x29@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-29x29@2x.png new file mode 100644 index 0000000..9839763 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-29x29@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-29x29@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-29x29@3x.png new file mode 100644 index 0000000..63d2ad8 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-29x29@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-40x40@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-40x40@1x.png new file mode 100644 index 0000000..b7ce0b7 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-40x40@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-40x40@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-40x40@2x.png new file mode 100644 index 0000000..c59ca45 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-40x40@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-40x40@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-40x40@3x.png new file mode 100644 index 0000000..aa70418 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-40x40@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-50x50@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-50x50@1x.png new file mode 100644 index 0000000..f924c08 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-50x50@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-50x50@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-50x50@2x.png new file mode 100644 index 0000000..ca05446 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-50x50@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-57x57@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-57x57@1x.png new file mode 100644 index 0000000..7134d0e Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-57x57@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-57x57@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-57x57@2x.png new file mode 100644 index 0000000..d1c919b Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-57x57@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-60x60@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-60x60@2x.png new file mode 100644 index 0000000..aa70418 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-60x60@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-60x60@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-60x60@3x.png new file mode 100644 index 0000000..c981fa4 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-60x60@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-72x72@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-72x72@1x.png new file mode 100644 index 0000000..37b8e7c Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-72x72@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-72x72@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-72x72@2x.png new file mode 100644 index 0000000..28406a5 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-72x72@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-76x76@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-76x76@1x.png new file mode 100644 index 0000000..c99f54c Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-76x76@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-76x76@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-76x76@2x.png new file mode 100644 index 0000000..3a148fc Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-76x76@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-83.5x83.5@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-83.5x83.5@2x.png new file mode 100644 index 0000000..1bdd2d5 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/AppIcon-develop-83.5x83.5@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/Contents.json b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/Contents.json new file mode 100644 index 0000000..20122a1 --- /dev/null +++ b/gamestore/ios/Runner/Assets.xcassets/AppIcon-develop.appiconset/Contents.json @@ -0,0 +1 @@ +{"images":[{"size":"20x20","idiom":"iphone","filename":"AppIcon-develop-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"AppIcon-develop-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-develop-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-develop-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-develop-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-develop-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-develop-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-develop-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-develop-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-develop-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-develop-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-develop-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-develop-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-develop-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-develop-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-develop-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-develop-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-develop-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-develop-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-develop-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-develop-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-develop-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-develop-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"AppIcon-develop-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"AppIcon-develop-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} \ No newline at end of file diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-1024x1024@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-1024x1024@1x.png new file mode 100644 index 0000000..4dfcbf2 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-1024x1024@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-20x20@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-20x20@1x.png new file mode 100644 index 0000000..f358ed6 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-20x20@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-20x20@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-20x20@2x.png new file mode 100644 index 0000000..6e323ee Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-20x20@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-20x20@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-20x20@3x.png new file mode 100644 index 0000000..adcee5f Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-20x20@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-29x29@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-29x29@1x.png new file mode 100644 index 0000000..ac53713 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-29x29@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-29x29@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-29x29@2x.png new file mode 100644 index 0000000..51965dd Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-29x29@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-29x29@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-29x29@3x.png new file mode 100644 index 0000000..ba71205 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-29x29@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-40x40@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-40x40@1x.png new file mode 100644 index 0000000..6e323ee Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-40x40@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-40x40@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-40x40@2x.png new file mode 100644 index 0000000..f16084f Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-40x40@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-40x40@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-40x40@3x.png new file mode 100644 index 0000000..5080d81 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-40x40@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-50x50@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-50x50@1x.png new file mode 100644 index 0000000..848a5c6 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-50x50@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-50x50@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-50x50@2x.png new file mode 100644 index 0000000..be5f621 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-50x50@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-57x57@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-57x57@1x.png new file mode 100644 index 0000000..d6017d7 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-57x57@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-57x57@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-57x57@2x.png new file mode 100644 index 0000000..dd570ba Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-57x57@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-60x60@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-60x60@2x.png new file mode 100644 index 0000000..5080d81 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-60x60@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-60x60@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-60x60@3x.png new file mode 100644 index 0000000..f9cb84d Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-60x60@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-72x72@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-72x72@1x.png new file mode 100644 index 0000000..33443b0 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-72x72@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-72x72@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-72x72@2x.png new file mode 100644 index 0000000..bbbb465 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-72x72@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-76x76@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-76x76@1x.png new file mode 100644 index 0000000..34ac1b8 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-76x76@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-76x76@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-76x76@2x.png new file mode 100644 index 0000000..4829441 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-76x76@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-83.5x83.5@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-83.5x83.5@2x.png new file mode 100644 index 0000000..2479465 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/AppIcon-prod-83.5x83.5@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Contents.json b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Contents.json new file mode 100644 index 0000000..c1baccf --- /dev/null +++ b/gamestore/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Contents.json @@ -0,0 +1 @@ +{"images":[{"size":"20x20","idiom":"iphone","filename":"AppIcon-prod-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"AppIcon-prod-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-prod-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-prod-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-prod-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-prod-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-prod-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-prod-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-prod-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-prod-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-prod-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-prod-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-prod-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-prod-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-prod-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-prod-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-prod-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-prod-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-prod-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-prod-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-prod-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-prod-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-prod-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"AppIcon-prod-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"AppIcon-prod-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} \ No newline at end of file diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..7353c41 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..6ed2d93 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cd7b00 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..fe73094 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..321773c Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..502f463 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..e9f5fea Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..84ac32a Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..8953cba Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..0467bf1 Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/gamestore/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/gamestore/ios/Runner/Base.lproj/LaunchScreen.storyboard b/gamestore/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/gamestore/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gamestore/ios/Runner/Base.lproj/Main.storyboard b/gamestore/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/gamestore/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gamestore/ios/Runner/Info.plist b/gamestore/ios/Runner/Info.plist new file mode 100644 index 0000000..28e671f --- /dev/null +++ b/gamestore/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + $(APP_DISPLAY_NAME) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(BUNDLE_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/gamestore/ios/Runner/Runner-Bridging-Header.h b/gamestore/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/gamestore/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/gamestore/ios/RunnerTests/RunnerTests.swift b/gamestore/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/gamestore/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/gamestore/lib/app.dart b/gamestore/lib/app.dart new file mode 100644 index 0000000..3774e5e --- /dev/null +++ b/gamestore/lib/app.dart @@ -0,0 +1,54 @@ +import 'dart:async'; + +import 'package:flutter/material.dart' show Theme; +import 'package:flutter/widgets.dart'; +import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +import 'features/core/abstracts/app_setup.dart'; +import 'features/core/abstracts/router/app_router.dart'; +import 'features/core/data/constants/const_colours.dart' as custom_app_themes; +import 'features/core/data/constants/const_values.dart'; +import 'features/core/data/extensions/context_extensions.dart'; + +/// Root entry-point for Dart +Future mainRoot() async { + await runZonedGuarded( + () async { + await AppSetup.initialise(); + runApp(const GamestoreApp()); + }, + AppSetup.onUncaughtException, + ); +} + +/// Base app widget +class GamestoreApp extends StatelessWidget { + ///Constructor + const GamestoreApp({super.key}); + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return ScreenUtilInit( + builder: (context, __) => Theme( + data: platformThemeData( + context, + material: (_) => context.isDarkMode + ? custom_app_themes.materialDarkTheme + : custom_app_themes.materialLightTheme, + cupertino: (_) => context.isDarkMode + ? custom_app_themes.cupertinoThemeDarkHack + : custom_app_themes.cupertinoThemeLightHack, + ), + child: PlatformApp.router( + title: ConstValues.appTitle, + debugShowCheckedModeBanner: false, + routerConfig: AppRouter.router, + localizationsDelegates: AppSetup.localizationDelegates, + supportedLocales: AppSetup.supportedLocales, + ), + ), + ); + } +} diff --git a/gamestore/lib/env/.gitignore b/gamestore/lib/env/.gitignore new file mode 100644 index 0000000..45be6a3 --- /dev/null +++ b/gamestore/lib/env/.gitignore @@ -0,0 +1,2 @@ +keystore/** +env.g.dart \ No newline at end of file diff --git a/gamestore/lib/env/env.dart b/gamestore/lib/env/env.dart new file mode 100644 index 0000000..2543b74 --- /dev/null +++ b/gamestore/lib/env/env.dart @@ -0,0 +1,26 @@ +import 'package:envied/envied.dart'; + +import '/features/core/data/enums/environment_type.dart'; + +// part 'env.g.dart'; + +/// Wrapper for providing the correct Environment-specific keys +class EnvConfig { + /// Constructor + EnvConfig({required EnvironmentType environmentType}) { + switch (environmentType) { + case EnvironmentType.dev: + break; + case EnvironmentType.live: + break; + } + } +} + +/// Envied path for the dev environment +@Envied(path: 'lib/env/keystore/.env.dev') +class _EnvDev implements EnvConfig {} + +/// Envied path for the production environment +@Envied(path: 'lib/env/keystore/.env.prod') +class _EnvProd implements EnvConfig {} diff --git a/gamestore/lib/features/auth/services/auth_service.dart b/gamestore/lib/features/auth/services/auth_service.dart new file mode 100644 index 0000000..23e46d7 --- /dev/null +++ b/gamestore/lib/features/auth/services/auth_service.dart @@ -0,0 +1,37 @@ +import 'dart:io'; + +import '/features/core/data/typedefs/http_status_code.dart'; +import '/features/core/services/logging_service.dart'; +import '/locator.dart'; + +/// Responsible for authentication +class AuthService { + /// Constructor + AuthService(); + + final _loggingService = LoggingService.locate; + + /// (On success): Sets the received [AuthDTO] and returns a [HttpStatus.ok] + /// + /// (on Failures): Auth failed -> [HttpStatus.forbidden]
+ /// No data for account -> [HttpStatus.noContent]
+ /// Any other exceptions encountered -> [HttpStatus.serviceUnavailable] + Future login({ + required String username, + required String password, + }) async { + _loggingService.info('Sending logging credentials'); + + _loggingService.info('Received auth response from the mavis client'); + + throw UnimplementedError('Implement me!'); + } + + /// Handles logout + Future logout() async { + throw UnimplementedError('Implement me!'); + } + + /// Locator DI + static AuthService get locate => Locator.locate(); +} diff --git a/gamestore/lib/features/core/abstracts/app_setup.dart b/gamestore/lib/features/core/abstracts/app_setup.dart new file mode 100644 index 0000000..b3c987b --- /dev/null +++ b/gamestore/lib/features/core/abstracts/app_setup.dart @@ -0,0 +1,89 @@ +import 'dart:async'; + +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import '/l10n/generated/l10n.dart'; +import '/locator.dart'; +import '../data/enums/supported_language.dart'; + +/// Handles setting up of the app. +abstract class AppSetup { + // TODO(mehul): When locator is properly refactored we should not have to use these stub methods for testing + /// Initializes everything before the app is run. + static Future initialise({ + List? locatorSetupStubs, + List? locatorInitStubs, + }) async { + WidgetsFlutterBinding.ensureInitialized(); + + await SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + ]); + + // await Firebase.initializeApp(); + + await Locator.setup(); + + await initialiseAppSetupServices(); + + await setupStrings(); + } + + /// Setup any other services that other services need access to. + @visibleForTesting + static Future initialiseAppSetupServices() async {} + + /// Resolves the supported locales + static List get supportedLocales => kReleaseMode + ? [ + for (final languageCode in SupportedLanguage.values) + Locale.fromSubtags(languageCode: languageCode.name), + ] + : Strings.delegate.supportedLocales; + + /// Resolves localization delegates + static Iterable> get localizationDelegates => const [ + ...AppLocalizations.localizationsDelegates, + Strings.delegate, + ]; + + /// Sets up strings for the correct locale. + static Future setupStrings() { + return Strings.load( + _resolveLocale( + preferredLocales: PlatformDispatcher.instance.locales, + supportedLocales: supportedLocales, + ), + ); + } + + static Locale _resolveLocale({ + required Iterable supportedLocales, + List? preferredLocales, + }) { + for (final locale in preferredLocales ?? const []) { + // Check if the current device locale is supported + for (final supportedLocale in supportedLocales) { + if (supportedLocale.languageCode == locale.languageCode) { + return supportedLocale; + } + } + } + return supportedLocales.first; + } + + /// Callback for any missed exception + static void Function(Object error, StackTrace stackTrace) get onUncaughtException => ( + error, + stackTrace, + ) => + FirebaseCrashlytics.instance.recordError( + 'Location: Zoned | Unhandled exception caught: $error', + stackTrace, + ); +} diff --git a/gamestore/lib/features/core/abstracts/base_view_model.dart b/gamestore/lib/features/core/abstracts/base_view_model.dart new file mode 100644 index 0000000..c79e1e9 --- /dev/null +++ b/gamestore/lib/features/core/abstracts/base_view_model.dart @@ -0,0 +1,120 @@ +// ignore_for_file: avoid_positional_boolean_parameters + +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +import '/l10n/generated/l10n.dart'; +import '../data/enums/view_model_state.dart'; +import '../services/logging_service.dart'; + +/// Base class for a View Model +abstract class BaseViewModel extends ChangeNotifier { + final ValueNotifier _isInitialised = ValueNotifier(false); + + /// initialized + ValueListenable get isInitialised => _isInitialised; + + final ValueNotifier _isBusy = ValueNotifier(false); + + /// busy + ValueListenable get isBusy => _isBusy; + + final ValueNotifier _hasError = ValueNotifier(false); + + /// has error + ValueListenable get hasError => _hasError; + + final ValueNotifier _state = ValueNotifier(ViewModelState.isInitialising); + + /// VM state + ValueListenable get state => _state; + + /// All possible [Listenable]s. + List> get stateListenables => [ + _isInitialised, + _isBusy, + _hasError, + ]; + + @protected + // ignore: public_member_api_docs + final loggingService = LoggingService.locate; + + String? _errorMessage; + + /// Error message + String get errorMessage => _errorMessage ?? Strings.current.somethingWentWrong; + + /// Setup before ViewModel is ready + /// [disposableBuildContext] provides a temporary [BuildContext] that should not be used further. + /// [mounted] is a callback for indicating a successful frame mount. + /// [arguments] That need to be passed to the VM. + @mustCallSuper + void initialise(BuildContext disposableBuildContext, bool Function() mounted, [E? arguments]) { + isMounted = mounted; + _isInitialised.value = true; + _state.value = ViewModelState.isInitialised; + + loggingService.successfulInit(location: runtimeType.toString()); + } + + /// Set _isInitialised. + // ignore: use_setters_to_change_properties + void setInitialised(bool isInitialised) => _isInitialised.value = isInitialised; + + /// Set state as busy + void setBusy(bool isBusy) { + _isBusy.value = isBusy; + if (isBusy) { + _state.value = ViewModelState.isBusy; + } else { + _state.value = ViewModelState.isInitialised; + } + } + + /// Set state as error + void setError(bool hasError, {String? message}) { + _errorMessage = hasError ? message : null; + _hasError.value = hasError; + if (hasError) { + _state.value = ViewModelState.hasError; + } else { + _state.value = ViewModelState.isInitialised; + } + } + + @override + void dispose() { + super.dispose(); + + loggingService.successfulDispose(location: runtimeType.toString()); + } + + /// isMounted + late final bool Function() isMounted; + + /// Callback for after successful mount. + void ifMounted(VoidCallback voidCallback) { + if (isMounted()) { + voidCallback(); + } + } + + /// Awaits the [future], while setting [isBusy] and releasing it after completion. + Future runBusyFuture(Future future) async { + try { + setBusy(true); + return await future; + } catch (e) { + rethrow; + } finally { + setBusy(false); + } + } + + /// Callback to be executed after the widget tree is fully built and mounted + void addPostFrameCallback(FrameCallback frameCallback) => + WidgetsBinding.instance.addPostFrameCallback(frameCallback); +} diff --git a/gamestore/lib/features/core/abstracts/mwa_navigation.dart b/gamestore/lib/features/core/abstracts/mwa_navigation.dart new file mode 100644 index 0000000..81107e9 --- /dev/null +++ b/gamestore/lib/features/core/abstracts/mwa_navigation.dart @@ -0,0 +1,3 @@ +/// For any common methods for all the navigation such as custom-pop, and for easy +/// analytics injections +abstract class GsNavigation {} diff --git a/gamestore/lib/features/core/abstracts/router/app_router.dart b/gamestore/lib/features/core/abstracts/router/app_router.dart new file mode 100644 index 0000000..d8bb48f --- /dev/null +++ b/gamestore/lib/features/core/abstracts/router/app_router.dart @@ -0,0 +1,29 @@ +import 'package:flutter/cupertino.dart'; +import 'package:go_router/go_router.dart'; + +import '../../views/home/home_view.dart'; +import 'routes.dart'; + +// TODO(mehul): Use Shell navigation later +// final _rootNavigatorKey = GlobalKey(); +// final _shellNavigatorKey = GlobalKey(); + +/// App's router +class AppRouter { + /// Main router object to persist. + static final router = GoRouter( + initialLocation: AppRoute.home.routeAddress, + routes: [ + GoRoute( + path: AppRoute.onboarding.routeAddress, + name: AppRoute.onboarding.name, + builder: (_, __) => const SizedBox.shrink(), + ), + GoRoute( + path: AppRoute.home.routeAddress, + name: AppRoute.home.name, + builder: (_, __) => const HomeView(), + ), + ], + ); +} diff --git a/gamestore/lib/features/core/abstracts/router/routes.dart b/gamestore/lib/features/core/abstracts/router/routes.dart new file mode 100644 index 0000000..acdfe79 --- /dev/null +++ b/gamestore/lib/features/core/abstracts/router/routes.dart @@ -0,0 +1,31 @@ +// ignore_for_file: library_private_types_in_public_api + +/// Page-routes in the app +enum AppRoute { + /// First + home( + _RoutesInfo( + routeAddress: '/', + ), + ), + + /// Signup/Sign-in + onboarding( + _RoutesInfo( + routeAddress: '/onboarding', + ), + ); + + final _RoutesInfo _routeInfo; + + /// Address of the route + String get routeAddress => _routeInfo.routeAddress; + + const AppRoute(this._routeInfo); +} + +class _RoutesInfo { + final String routeAddress; + + const _RoutesInfo({required this.routeAddress}); +} diff --git a/gamestore/lib/features/core/data/constants/const_app.dart b/gamestore/lib/features/core/data/constants/const_app.dart new file mode 100644 index 0000000..27c8044 --- /dev/null +++ b/gamestore/lib/features/core/data/constants/const_app.dart @@ -0,0 +1,2 @@ +/// App constants for native-channel communication +abstract class ConstApp {} diff --git a/gamestore/lib/features/core/data/constants/const_colours.dart b/gamestore/lib/features/core/data/constants/const_colours.dart new file mode 100644 index 0000000..69fb954 --- /dev/null +++ b/gamestore/lib/features/core/data/constants/const_colours.dart @@ -0,0 +1,66 @@ +// ignore_for_file: public_member_api_docs + +import 'dart:ui'; + +import 'package:flutter/cupertino.dart' show CupertinoColors, CupertinoThemeData; +import 'package:flutter/material.dart' show CardTheme, Color, ThemeData; +import 'package:flutter/painting.dart'; + +import 'ui/const_sizes.dart'; + +/// Colours and themes +abstract class ConstColours { + static const vampireBlack = Color(0xFF050505); + static const indigoDye = Color(0xFF171C8F); + static const orangeRed = Color(0xFFFF671F); + + static const transparent = Color(0x00000000); + static const white = Color(0xFFFFFFFF); + static const darkSilver = Color(0xFF707070); + + static const cupertinoBackground = CupertinoColors.systemBackground; + static const cupertinoBackgroundGrouped = CupertinoColors.systemGroupedBackground; + static const cupertinoBackgroundGroupedSecondary = + CupertinoColors.secondarySystemGroupedBackground; + + static const cupertinoActiveGreen = CupertinoColors.activeGreen; + static const cupertinoActiveOrange = CupertinoColors.activeOrange; + static const cupertinoDestructiveRed = CupertinoColors.destructiveRed; +} + +ThemeData get materialLightTheme => ThemeData( + useMaterial3: true, + brightness: Brightness.light, + colorSchemeSeed: ConstColours.indigoDye, + cardTheme: const CardTheme( + shape: RoundedRectangleBorder( + borderRadius: ConstSizes.genericCurvatureBorderRadius, + ), + elevation: ConstSizes.defaultElevation, + ), + ); + +ThemeData get materialDarkTheme => ThemeData( + useMaterial3: true, + brightness: Brightness.dark, + colorSchemeSeed: ConstColours.indigoDye, + ); + +CupertinoThemeData get cupertinoLightTheme => const CupertinoThemeData( + brightness: Brightness.light, + scaffoldBackgroundColor: CupertinoColors.systemGroupedBackground, + // primaryColor: ConstColours.indigoDye, + // primaryContrastingColor: ConstColours.orangeRed, + ); + +CupertinoThemeData get cupertinoDarkTheme => const CupertinoThemeData( + brightness: Brightness.dark, + // primaryColor: ConstColours.indigoDye, + // primaryContrastingColor: ConstColours.orangeRed, + ); + +ThemeData get cupertinoThemeLightHack => + materialLightTheme.copyWith(cupertinoOverrideTheme: cupertinoLightTheme); + +ThemeData get cupertinoThemeDarkHack => + materialDarkTheme.copyWith(cupertinoOverrideTheme: cupertinoDarkTheme); diff --git a/gamestore/lib/features/core/data/constants/const_durations.dart b/gamestore/lib/features/core/data/constants/const_durations.dart new file mode 100644 index 0000000..0c2147a --- /dev/null +++ b/gamestore/lib/features/core/data/constants/const_durations.dart @@ -0,0 +1,12 @@ +// ignore_for_file: public_member_api_docs + +/// Standard durations +abstract class ConstDurations { + static const Duration tripleDefaultAnimationDuration = Duration(milliseconds: 1200); + static const Duration doubleDefaultAnimationDuration = Duration(milliseconds: 800); + static const Duration oneAndHalfDefaultAnimationDuration = Duration(milliseconds: 600); + static const Duration defaultAnimationDuration = Duration(milliseconds: 400); + static const Duration halfDefaultAnimationDuration = Duration(milliseconds: 200); + static const Duration quarterDefaultAnimationDuration = Duration(milliseconds: 100); + static const Duration zero = Duration.zero; +} diff --git a/gamestore/lib/features/core/data/constants/const_media.dart b/gamestore/lib/features/core/data/constants/const_media.dart new file mode 100644 index 0000000..c65de47 --- /dev/null +++ b/gamestore/lib/features/core/data/constants/const_media.dart @@ -0,0 +1,86 @@ +// ignore_for_file: public_member_api_docs + +import 'dart:typed_data'; + +import 'package:dartz/dartz.dart'; +import 'package:flutter/painting.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import 'const_values.dart'; + +/// Wrapper for all Icons, [Svg]s, local Json files and other assets. +abstract class ConstMedia { + // PNGs + + // SVGs + + // JSONs + + static SvgPicture buildIcon( + String iconReference, { + BoxFit fit = BoxFit.contain, + Clip clipBehavior = Clip.hardEdge, + Alignment alignment = Alignment.center, + }) => + SvgPicture.asset( + iconReference, + fit: fit, + clipBehavior: clipBehavior, + alignment: alignment, + ); + + static SvgPicture buildIconWithSize( + String iconReference, { + double? width, + double? height, + Clip clipBehavior = Clip.hardEdge, + }) => + SvgPicture.asset( + iconReference, + width: width, + height: height, + fit: BoxFit.fitWidth, + clipBehavior: clipBehavior, + ); + + /// Fetches an SVG image from a [Uri] or a [Uint8List] directly. + /// + /// Can be a URL(https scheme) or a local asset path. + /// Does NOT check for XML validity though. + /// So would fail silently if XML is unacceptable. + static SvgPicture buildIconWithLocalUriOrByteData({ + required Either uriOrUint8List, + double? height, + double? width, + BoxFit fit = BoxFit.fitHeight, + }) { + return uriOrUint8List.fold( + (Uri iconReference) => (iconReference.isScheme(ConstValues.httpsScheme)) + ? SvgPicture.network( + iconReference.toString(), + height: height, + width: width, + fit: fit, + ) + : SvgPicture.asset( + iconReference.toString(), + height: height, + width: width, + fit: fit, + ), + (Uint8List dataBytes) => SvgPicture.memory( + dataBytes, + height: height, + width: width, + fit: fit, + ), + ); + } + + ///Builds an [ImageProvider] of respective type, given the [urlPath]. + static ImageProvider imageFromProviderPath({required String urlPath}) { + final uri = Uri.parse(urlPath); + if (uri.isScheme(ConstValues.httpsScheme)) return NetworkImage(urlPath); + return AssetImage(uri.toString()); + } +} diff --git a/gamestore/lib/features/core/data/constants/const_text.dart b/gamestore/lib/features/core/data/constants/const_text.dart new file mode 100644 index 0000000..814750e --- /dev/null +++ b/gamestore/lib/features/core/data/constants/const_text.dart @@ -0,0 +1,58 @@ +import 'package:flutter/painting.dart'; + +import 'const_colours.dart'; + +/// Wrapper for standard [TextStyle]s. +abstract class ConstText { + static const _roboto = 'Roboto'; + + /// Level-1 header + static const header1 = TextStyle( + color: ConstColours.white, + fontSize: 20, + fontFamily: _roboto, + fontWeight: FontWeight.bold, + height: 16 / 20, + letterSpacing: 0, + ); + + /// Level-2 header + static const header2 = TextStyle( + color: ConstColours.white, + fontSize: 14, + fontFamily: _roboto, + fontWeight: FontWeight.normal, + height: 17 / 14, + letterSpacing: 0, + ); + + /// Tab-label + static const tab = TextStyle( + fontSize: 16, + fontFamily: _roboto, + height: 19 / 16, + letterSpacing: 0, + ); + + /// Level-1 body + static const body1 = TextStyle( + color: ConstColours.vampireBlack, + fontSize: 14, + fontFamily: _roboto, + fontWeight: FontWeight.w400, + height: 17 / 14, + letterSpacing: 0, + ); + + /// Level-1 body with a link + static TextStyle get bodyLink1 => body1.copyWith( + fontWeight: FontWeight.w600, + color: ConstColours.darkSilver, + decoration: TextDecoration.underline, + ); + + /// Destructive action (red) for iOS + static const cupertinoDestructiveAction = TextStyle( + color: ConstColours.cupertinoDestructiveRed, + ); +} diff --git a/gamestore/lib/features/core/data/constants/const_validators.dart b/gamestore/lib/features/core/data/constants/const_validators.dart new file mode 100644 index 0000000..95fe11d --- /dev/null +++ b/gamestore/lib/features/core/data/constants/const_validators.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; +import 'package:form_builder_validators/form_builder_validators.dart'; + +import '/l10n/generated/l10n.dart'; + +/// Validation functions +abstract class ConstValidators { + /// Defines multiple [FormFieldValidator]s to be checked + static FormFieldValidator multiple(List> validators) => + FormBuilderValidators.compose(validators); + + /// Prevents a field from sending null ot empty values + static FormFieldValidator required() { + return (T? valueCandidate) { + if (valueCandidate == null || valueCandidate is String && valueCandidate.trim().isEmpty) { + return Strings.current.formFieldRequired.toUpperCase(); + } + return null; + }; + } +} diff --git a/gamestore/lib/features/core/data/constants/const_values.dart b/gamestore/lib/features/core/data/constants/const_values.dart new file mode 100644 index 0000000..9c1ad7d --- /dev/null +++ b/gamestore/lib/features/core/data/constants/const_values.dart @@ -0,0 +1,59 @@ +// ignore_for_file: public_member_api_docs + +/// Stores the literals/constants used throughout the app +abstract class ConstValues { + // A + static const appTitle = 'AequoPlay Gamestore'; + + // B + + // C + + // D + + // E + static const euroSign = '€'; + + // F + + // G + + // H + static const httpsScheme = 'https'; + + // I + + // J + + // K + + // L + + // M + + // N + + // O + + // P + + // Q + + // R + + // S + + // T + + // U + + // V + + // W + + // X + + // Y + + // Z +} diff --git a/gamestore/lib/features/core/data/constants/ui/const_box_shadows.dart b/gamestore/lib/features/core/data/constants/ui/const_box_shadows.dart new file mode 100644 index 0000000..2e2cf26 --- /dev/null +++ b/gamestore/lib/features/core/data/constants/ui/const_box_shadows.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart' show Colors; +import 'package:flutter/painting.dart'; + +/// Defines the shadow for layering +abstract class ConstBoxShadows { + /// Default + static BoxShadow get defaultShadow => BoxShadow( + color: Colors.black.withOpacity(0.1), + offset: const Offset(0, 4), + blurRadius: 5, + ); + + /// Lowest elevation + static List get elevation3 => [ + BoxShadow( + color: Colors.black.withOpacity(0.12), + blurRadius: 4, + offset: const Offset(0, 3), + ), + BoxShadow( + color: Colors.black.withOpacity(0.04), + blurRadius: 3, + offset: const Offset(3, 3), + ), + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 8, + offset: const Offset(0, 1), + ), + ]; + + /// Medium elevation + static List get elevation4 => [ + BoxShadow( + color: Colors.black.withOpacity(0.10), + blurRadius: 5, + offset: const Offset(0, 4), + ), + BoxShadow( + color: Colors.black.withOpacity(0.04), + blurRadius: 10, + offset: const Offset(0, 1), + ), + BoxShadow( + color: Colors.black.withOpacity(0.12), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ]; +} diff --git a/gamestore/lib/features/core/data/constants/ui/const_opacities.dart b/gamestore/lib/features/core/data/constants/ui/const_opacities.dart new file mode 100644 index 0000000..0ade02b --- /dev/null +++ b/gamestore/lib/features/core/data/constants/ui/const_opacities.dart @@ -0,0 +1,5 @@ +/// Opacity values +abstract class ConstOpacities { + /// Disabled look + static const defaultDisabled = 0.2; +} diff --git a/gamestore/lib/features/core/data/constants/ui/const_sizes.dart b/gamestore/lib/features/core/data/constants/ui/const_sizes.dart new file mode 100644 index 0000000..9216f0e --- /dev/null +++ b/gamestore/lib/features/core/data/constants/ui/const_sizes.dart @@ -0,0 +1,10 @@ +import 'package:flutter/painting.dart'; + +/// App sizes +abstract class ConstSizes { + /// Borders + static const genericCurvatureBorderRadius = BorderRadius.all(Radius.circular(24)); + + /// Elevation + static const defaultElevation = 6.0; +} diff --git a/gamestore/lib/features/core/data/converters/timestamp_converters.dart b/gamestore/lib/features/core/data/converters/timestamp_converters.dart new file mode 100644 index 0000000..f5bbb6a --- /dev/null +++ b/gamestore/lib/features/core/data/converters/timestamp_converters.dart @@ -0,0 +1,32 @@ +// ignore_for_file: sort_constructors_first + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:json_annotation/json_annotation.dart'; + +export 'package:cloud_firestore/cloud_firestore.dart'; + +/// Conversion between [DateTime] and Firestore's [Timestamp]. +class TimestampConverter implements JsonConverter { + @override + DateTime fromJson(Timestamp timestamp) { + return timestamp.toDate(); + } + + @override + Timestamp toJson(DateTime date) => Timestamp.fromDate(date); + + /// const Constructor + const TimestampConverter(); +} + +/// Nullable variant of [TimestampConverter]. +class TimestampConverterNullable implements JsonConverter { + @override + DateTime? fromJson(Timestamp? json) => json?.toDate(); + + @override + Timestamp? toJson(DateTime? object) => object != null ? Timestamp.fromDate(object) : null; + + /// const Constructor + const TimestampConverterNullable(); +} diff --git a/gamestore/lib/features/core/data/enums/date_formats.dart b/gamestore/lib/features/core/data/enums/date_formats.dart new file mode 100644 index 0000000..960d464 --- /dev/null +++ b/gamestore/lib/features/core/data/enums/date_formats.dart @@ -0,0 +1,18 @@ +import 'package:intl/intl.dart'; + +/// All the [DateFormat]s formats to be used in the app. +enum DateTimeFormats { + /// (04-20-2009) + shortDayMonthLongYearHyphens('dd-MM-yyyy'), + + /// (5:30) + timeOnlyColons('H:m'); + + /// Format string + final String format; + + /// Wrapper for format string + DateFormat get dateFormat => DateFormat(format); + + const DateTimeFormats(this.format); +} diff --git a/gamestore/lib/features/core/data/enums/environment_type.dart b/gamestore/lib/features/core/data/enums/environment_type.dart new file mode 100644 index 0000000..96fe540 --- /dev/null +++ b/gamestore/lib/features/core/data/enums/environment_type.dart @@ -0,0 +1,20 @@ +import 'package:flutter/widgets.dart'; + +import '/env/env.dart'; +import 'supported_language.dart'; + +/// Defines the app flavours/environments in use +enum EnvironmentType { + /// Development + dev, + + /// Live + live; + + /// Override and sets up the environment-specific configuration + void override() => EnvConfig(environmentType: this); + + /// Resolves the current app language + static SupportedLanguage currentLanguage(BuildContext context) => + Localizations.localeOf(context).languageCode.toSupportedLanguage; +} diff --git a/gamestore/lib/features/core/data/enums/form_field_type.dart b/gamestore/lib/features/core/data/enums/form_field_type.dart new file mode 100644 index 0000000..91bcf6c --- /dev/null +++ b/gamestore/lib/features/core/data/enums/form_field_type.dart @@ -0,0 +1,11 @@ +/// Functional types of form fields +enum FormFieldType { + /// General text + text, + + /// Email + email, + + /// Masked password value + password; +} diff --git a/gamestore/lib/features/core/data/enums/supported_language.dart b/gamestore/lib/features/core/data/enums/supported_language.dart new file mode 100644 index 0000000..5412cac --- /dev/null +++ b/gamestore/lib/features/core/data/enums/supported_language.dart @@ -0,0 +1,17 @@ +/// languages supported by the app +enum SupportedLanguage { + /// English + en, + + /// Dutch + nl; +} + +///extension +extension SupportedLanguagesExtension on String? { + /// Resolves the default supported language + SupportedLanguage get toSupportedLanguage => SupportedLanguage.values.firstWhere( + (element) => element.name == this?.trim().toLowerCase(), + orElse: () => SupportedLanguage.en, + ); +} diff --git a/gamestore/lib/features/core/data/enums/supported_phone_number.dart b/gamestore/lib/features/core/data/enums/supported_phone_number.dart new file mode 100644 index 0000000..f690874 --- /dev/null +++ b/gamestore/lib/features/core/data/enums/supported_phone_number.dart @@ -0,0 +1,28 @@ +/// Phone numbers supported by the app +enum SupportedPhoneNumber { + /// Dutch + nl, + + /// Belgium + be; + + /// phone-number number code + String get countryPhoneCode { + switch (this) { + case SupportedPhoneNumber.nl: + return '+31'; + case SupportedPhoneNumber.be: + return '+32'; + } + } + + /// phone-number country-name code + String get countryCode { + switch (this) { + case SupportedPhoneNumber.nl: + return 'NL'; + case SupportedPhoneNumber.be: + return 'BE'; + } + } +} diff --git a/gamestore/lib/features/core/data/enums/view_model_state.dart b/gamestore/lib/features/core/data/enums/view_model_state.dart new file mode 100644 index 0000000..600a458 --- /dev/null +++ b/gamestore/lib/features/core/data/enums/view_model_state.dart @@ -0,0 +1,14 @@ +/// Initialing states of a ViewModel. +enum ViewModelState { + /// Initializing + isInitialising, + + /// Initializing done + isInitialised, + + /// Busy with some other task + isBusy, + + /// Error + hasError; +} diff --git a/gamestore/lib/features/core/data/extensions/context_extensions.dart b/gamestore/lib/features/core/data/extensions/context_extensions.dart new file mode 100644 index 0000000..6f0d9ca --- /dev/null +++ b/gamestore/lib/features/core/data/extensions/context_extensions.dart @@ -0,0 +1,16 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +import '/l10n/generated/l10n.dart'; + +/// extension +extension DarkMode on BuildContext { + /// is dark mode currently enabled? + /// + /// Using the context version in release throws exception. + bool get isDarkMode => + WidgetsBinding.instance.platformDispatcher.platformBrightness == Brightness.dark; + + /// Returns the instance of [Strings.current] + Strings get strings => Strings.current; +} diff --git a/gamestore/lib/features/core/data/extensions/date_time_extensions.dart b/gamestore/lib/features/core/data/extensions/date_time_extensions.dart new file mode 100644 index 0000000..e4a788b --- /dev/null +++ b/gamestore/lib/features/core/data/extensions/date_time_extensions.dart @@ -0,0 +1,17 @@ +import 'package:intl/intl.dart'; + +import '../enums/date_formats.dart'; + +/// Extensions on [DateTime]. +extension DateTimeExtensions on DateTime { + /// Formats given [DateTime] into a [String], according to [dateTimeFormat] format. + String inFormat({required DateTimeFormats dateTimeFormat}) => + DateFormat(dateTimeFormat.format).format(this); + + /// Start of actual new day + DateTime get dayStart => DateTime(year, month, day); + + /// Returns whether 2 [DateTime]s are on the same day of the year, ignoring time. + bool isSameDateAs(DateTime other) => + year == other.year && month == other.month && day == other.day; +} diff --git a/gamestore/lib/features/core/data/extensions/future_extensions.dart b/gamestore/lib/features/core/data/extensions/future_extensions.dart new file mode 100644 index 0000000..beae94e --- /dev/null +++ b/gamestore/lib/features/core/data/extensions/future_extensions.dart @@ -0,0 +1,7 @@ +import 'dart:async' as async; + +///extension +extension FutureExtension on Future { + /// Decorator instead of wrapper + void get unawaited => async.unawaited(this); +} diff --git a/gamestore/lib/features/core/data/extensions/list_extensions.dart b/gamestore/lib/features/core/data/extensions/list_extensions.dart new file mode 100644 index 0000000..a557aae --- /dev/null +++ b/gamestore/lib/features/core/data/extensions/list_extensions.dart @@ -0,0 +1,13 @@ +///extension +extension ListExtensions on List { + /// Creates an unaliased deep copy + List get deepCopy => [...this]; + + /// Create an [List.unmodifiable] from given list + List get unmodifiable => List.unmodifiable(this); + + /// Removes the last object in this list iff the list is not empty + void removeLastSafely() { + if (isNotEmpty) removeLast(); + } +} diff --git a/gamestore/lib/features/core/data/extensions/map_extensions.dart b/gamestore/lib/features/core/data/extensions/map_extensions.dart new file mode 100644 index 0000000..8cc1538 --- /dev/null +++ b/gamestore/lib/features/core/data/extensions/map_extensions.dart @@ -0,0 +1,5 @@ +///extension +extension MapExtensions on Map { + /// Creates an unaliased deep copy + Map get deepCopy => {...this}; +} diff --git a/gamestore/lib/features/core/data/extensions/object_extensions.dart b/gamestore/lib/features/core/data/extensions/object_extensions.dart new file mode 100644 index 0000000..a39f26e --- /dev/null +++ b/gamestore/lib/features/core/data/extensions/object_extensions.dart @@ -0,0 +1,11 @@ +///extension +extension ObjectExtensions on Object? { + /// Syntactic sugar for explicit type-casting + E asType() => this as E; +} + +///extension +extension AsCallback on T { + /// Syntactic sugar for creating a lazy-evaluation + T Function() get asCallback => () => this; +} diff --git a/gamestore/lib/features/core/data/extensions/response_extensions.dart b/gamestore/lib/features/core/data/extensions/response_extensions.dart new file mode 100644 index 0000000..37c4ed7 --- /dev/null +++ b/gamestore/lib/features/core/data/extensions/response_extensions.dart @@ -0,0 +1,10 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; + +///extension +extension ResponseExtension on Response { + /// Returns whether the received response was successful. + /// If the response did not have status-code key, then it will return false. + bool get wasSuccessful => statusCode == HttpStatus.ok; +} diff --git a/gamestore/lib/features/core/data/extensions/stream_extensions.dart b/gamestore/lib/features/core/data/extensions/stream_extensions.dart new file mode 100644 index 0000000..5bab54a --- /dev/null +++ b/gamestore/lib/features/core/data/extensions/stream_extensions.dart @@ -0,0 +1,41 @@ +import 'package:flutter/foundation.dart'; + +///extension +extension StreamExtensions on Stream { + /// Convert to a [ValueListenable]. + ValueListenable toValueNotifier( + T initialValue, { + bool Function(T previous, T current)? notifyWhen, + }) { + final notifier = ValueNotifier(initialValue); + listen((value) { + if (notifyWhen == null || notifyWhen(notifier.value, value)) { + notifier.value = value; + } + }); + return notifier; + } + + /// Convert to a [ValueListenable]?. + ValueListenable toNullableValueNotifier({ + bool Function(T? previous, T? current)? notifyWhen, + }) { + final notifier = ValueNotifier(null); + listen((value) { + if (notifyWhen == null || notifyWhen(notifier.value, value)) { + notifier.value = value; + } + }); + return notifier; + } + + /// Convert to a [Listenable]. + Listenable toListenable() { + final notifier = ChangeNotifier(); + listen((_) { + // ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member + notifier.notifyListeners(); + }); + return notifier; + } +} diff --git a/gamestore/lib/features/core/data/extensions/string_extensions.dart b/gamestore/lib/features/core/data/extensions/string_extensions.dart new file mode 100644 index 0000000..f0967ed --- /dev/null +++ b/gamestore/lib/features/core/data/extensions/string_extensions.dart @@ -0,0 +1,41 @@ +///extension +extension StringExtensions on String { + /// Capitalizes the first letter of every word, except some exceptions such as + /// articles, numeral-names, place-words etc. + String get capitalizeWithBlockedValues { + final blockedValues = ['op', 'de', 'het', 'een', "'s-", 'β€˜s-']; + + String capitaliseFirst(String value, List blockedValues) => + value.isNotEmpty && !value._isBlocked(blockedValues) + ? value[0].toUpperCase() + (value.length > 1 ? value.substring(1).toLowerCase() : '') + : value.toLowerCase(); + + return split(' ') + .map( + (nonCapitalised) => nonCapitalised + .split('-') + .map((nonCapitalised) => capitaliseFirst(nonCapitalised, blockedValues)) + .join('-'), + ) + .join(' '); + } + + /// Returns the character-wise difference. + String difference(String? other) { + if (other != null) { + if (length == other.length) { + return ''; + } else if (length > other.length) { + return replaceAll(other, ''); + } else { + return other.replaceAll(this, ''); + } + } else if (other == null) { + return this; + } else { + return ''; + } + } + + bool _isBlocked(List blockedValues) => blockedValues.contains(toLowerCase()); +} diff --git a/gamestore/lib/features/core/data/formatters/decimal_length_limiting.dart b/gamestore/lib/features/core/data/formatters/decimal_length_limiting.dart new file mode 100644 index 0000000..93ebabf --- /dev/null +++ b/gamestore/lib/features/core/data/formatters/decimal_length_limiting.dart @@ -0,0 +1,67 @@ +import 'package:flutter/services.dart'; + +/// Formatting decimals +class DecimalLengthLimitingTextInputFormatter extends TextInputFormatter { + /// maximum length of a whole number + final int maxWholeNumberLength; + + /// maximum length of a floating-point number + final int maxDecimalNumberLength; + + /// Constructor + DecimalLengthLimitingTextInputFormatter( + this.maxWholeNumberLength, [ + this.maxDecimalNumberLength = 2, + ]) : assert( + maxWholeNumberLength >= 0 && maxDecimalNumberLength >= 0, + "Arguments can't be negative", + ); + + @override + TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { + final text = newValue.text.replaceAll(',', '.').trim(); + if (text == '.' || text.isEmpty) { + return newValue.copyWith(text: newValue.text.replaceAll('.', ',').trim()); + } + + if (!_canParseToDouble(text) || text.contains('-')) return oldValue; + + final splitNumber = text.split('.'); + final wholeNumbers = splitNumber[0]; + String? decimalNumbers; + + if (splitNumber.length > 1) { + decimalNumbers = splitNumber[1]; + } + + final parsedWholeNumbers = int.tryParse(wholeNumbers)?.toString() ?? ''; + + if (parsedWholeNumbers.length > maxWholeNumberLength) return oldValue; + if (decimalNumbers != null && decimalNumbers.length > maxDecimalNumberLength) { + return oldValue; + } + + final newText = parsedWholeNumbers + (decimalNumbers == null ? '' : ',$decimalNumbers'); + final selection = newValue.selection; + final composing = newValue.composing; + + if (newText == oldValue.text) return oldValue; + + return newValue.copyWith( + text: newText, + selection: selection.copyWith( + baseOffset: selection.baseOffset.clamp(0, newText.length), + extentOffset: selection.extentOffset.clamp(0, newText.length), + ), + composing: TextRange( + start: composing.start.clamp(0, newText.length), + end: composing.start.clamp(0, newText.length), + ), + ); + } + + bool _canParseToDouble(String value) { + final formattedValue = value.replaceAll(',', '.'); + return double.tryParse(formattedValue) != null; + } +} diff --git a/gamestore/lib/features/core/data/formatters/text_input_formatters.dart b/gamestore/lib/features/core/data/formatters/text_input_formatters.dart new file mode 100644 index 0000000..532de0d --- /dev/null +++ b/gamestore/lib/features/core/data/formatters/text_input_formatters.dart @@ -0,0 +1,95 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; + +import '../../data/enums/supported_phone_number.dart'; +import '../../data/extensions/string_extensions.dart'; + +/// Text input formatters +abstract class TextInputFormatters { + /// Formats input to capitalize each first letter. + static TextInputFormatter capitalize() => TextInputFormatter.withFunction( + (oldValue, newValue) { + final newText = newValue.text; + if (oldValue.text.difference(newText) == ' ') return newValue; + return newValue.copyWith(text: newText.capitalizeWithBlockedValues); + }, + ); + + /// Formats input to only allow for numbers. + static TextInputFormatter numbers([int? maxLength]) => TextInputFormatter.withFunction( + (oldValue, newValue) { + if ((maxLength != null && maxLength >= newValue.text.length) || maxLength == null) { + final newText = newValue.text; + final isNumeric = RegExp(r'^-?[0-9]+$'); + + /// check if the string contains only numbers + return newText.isEmpty || isNumeric.hasMatch(newText) ? newValue : oldValue; + } else { + return oldValue; + } + }, + ); + + /// Formats input to only allow for letters. + static TextInputFormatter letters([int? maxLength]) => TextInputFormatter.withFunction( + (oldValue, newValue) { + if ((maxLength != null && maxLength >= newValue.text.length) || maxLength == null) { + final newText = newValue.text; + final isNumeric = RegExp(r'^-?[0-9]+$'); + + return newText.isEmpty || !isNumeric.hasMatch(newText.difference(oldValue.text)) + ? newValue + : oldValue; + } else { + return oldValue; + } + }, + ); + + /// Formats into lowercase + static TextInputFormatter lowerCase() => TextInputFormatter.withFunction( + (oldValue, newValue) => newValue.copyWith(text: newValue.text.toLowerCase()), + ); + + /// Formats into uppercase + static TextInputFormatter upperCase() => TextInputFormatter.withFunction( + (oldValue, newValue) => newValue.copyWith(text: newValue.text.toUpperCase()), + ); + + /// Strips country codes from the beginning of text. + /// + /// Stripping happens only WHEN the country-code has been typed. + static TextInputFormatter phoneNumber({ + required ValueListenable supportedPhoneNumber, + }) => + TextInputFormatter.withFunction( + (_, newValue) { + final sanitizedText = newValue.text + // Remove ANY occurring spaces + .replaceAll(r'\s', '') + // Remove custom characters + .replaceAll( + RegExp(r'[()\[\]]'), + '', + ) + // Remove country-code and any other abbreviations + .replaceFirst( + RegExp('^(\\${supportedPhoneNumber.value.countryPhoneCode}|0)'), + '', + ); + + final replaceLength = newValue.text.length - sanitizedText.length; + if (replaceLength != 0) { + return newValue.copyWith( + text: sanitizedText, + selection: newValue.selection.copyWith( + baseOffset: sanitizedText.length, + extentOffset: sanitizedText.length, + ), + ); + } else { + return newValue; + } + }, + ); +} diff --git a/gamestore/lib/features/core/data/formatters/whole_number_length_limiting.dart b/gamestore/lib/features/core/data/formatters/whole_number_length_limiting.dart new file mode 100644 index 0000000..094037c --- /dev/null +++ b/gamestore/lib/features/core/data/formatters/whole_number_length_limiting.dart @@ -0,0 +1,34 @@ +import 'package:flutter/services.dart'; + +/// Formatting for whole numbers +class WholeNumberLengthLimitingTextInputFormatter extends TextInputFormatter { + /// maximum length of number + final int maxNumbers; + + /// Constructor + WholeNumberLengthLimitingTextInputFormatter( + this.maxNumbers, + ) : assert(maxNumbers >= 0, "Argument can't be negative"); + + @override + TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { + final text = newValue.text.trim(); + if (text.isEmpty) return newValue.copyWith(text: text); + + if (text.length > maxNumbers || text.contains(RegExp(r'[\D]'))) return oldValue; + + final parsed = int.tryParse(text); + + if (parsed == null) return oldValue; + + final selection = newValue.selection; + final parsedString = parsed.toString(); + return newValue.copyWith( + text: parsedString, + selection: selection.copyWith( + baseOffset: selection.baseOffset.clamp(0, parsedString.length), + extentOffset: selection.extentOffset.clamp(0, parsedString.length), + ), + ); + } +} diff --git a/gamestore/lib/features/core/data/typedefs/http_status_code.dart b/gamestore/lib/features/core/data/typedefs/http_status_code.dart new file mode 100644 index 0000000..fabc076 --- /dev/null +++ b/gamestore/lib/features/core/data/typedefs/http_status_code.dart @@ -0,0 +1,10 @@ +import 'dart:io'; + +/// Special int as an HttpStatusCode +typedef HttpStatusCode = int; + +/// extension +extension HttpStatusCodeExtension on HttpStatusCode { + /// Whether the received status was [HttpStatus.ok] + bool get wasSuccessful => this == HttpStatus.ok; +} diff --git a/gamestore/lib/features/core/data/typedefs/json.dart b/gamestore/lib/features/core/data/typedefs/json.dart new file mode 100644 index 0000000..acf909a --- /dev/null +++ b/gamestore/lib/features/core/data/typedefs/json.dart @@ -0,0 +1,2 @@ +/// Wrapper for Json data received as [Map] +typedef Json = Map; diff --git a/gamestore/lib/features/core/forms/form_field_config.dart b/gamestore/lib/features/core/forms/form_field_config.dart new file mode 100644 index 0000000..0b4d315 --- /dev/null +++ b/gamestore/lib/features/core/forms/form_field_config.dart @@ -0,0 +1,25 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +/// Complete store of all definitions for all kinds of fields for forms +class FormFieldConfig { + /// Constructor + FormFieldConfig({ + this.hintText, + this.textEditingController, + this.focusNode, + ValueListenable? isEnabledListenable, + }) : isEnabledListenable = isEnabledListenable ?? ValueNotifier(true); + + /// Hint for a field + final String? hintText; + + /// Field controller + final TextEditingController? textEditingController; + + /// Focus definition + final FocusNode? focusNode; + + /// Field enabled + final ValueListenable isEnabledListenable; +} diff --git a/gamestore/lib/features/core/services/logging_service.dart b/gamestore/lib/features/core/services/logging_service.dart new file mode 100644 index 0000000..73f9eaf --- /dev/null +++ b/gamestore/lib/features/core/services/logging_service.dart @@ -0,0 +1,98 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:talker/talker.dart'; +import 'package:talker_dio_logger/talker_dio_logger_interceptor.dart'; +import 'package:talker_dio_logger/talker_dio_logger_settings.dart'; + +import '/locator.dart'; + +/// Logs important events +class LoggingService { + final Talker _talker = Talker( + // observer: _CrashlyticsObserver(), + settings: TalkerSettings( + useHistory: false, + ), + logger: TalkerLogger( + formatter: !Platform.isIOS ? const ColoredLoggerFormatter() : const ExtendedLoggerFormatter(), + settings: TalkerLoggerSettings( + enableColors: !Platform.isIOS, + ), + ), + ); + + /// Successful critical event + void Function(dynamic msg, [Object? exception, StackTrace? stackTrace]) get good => _talker.good; + + /// Common/general event + void Function(dynamic msg, [Object? exception, StackTrace? stackTrace]) get info => + _talker.verbose; + + /// Non-fatal but important/recovered event + void Function(dynamic msg, [Object exception, StackTrace stackTrace]) get warning => + _talker.warning; + + /// Fatal and important recorded event + void Function(dynamic msg, [Object? exception, StackTrace? stackTrace]) get error => + _talker.error; + + /// Initialised successfully + /// Generally reserved for ViewModels + void successfulInit({required String location}) => + _talker.good('[$location] πŸ“š I am initialized'); + + /// Disposed successfully + /// Generally reserved for ViewModels + void successfulDispose({required String location}) => + _talker.good('[$location] πŸ—‘ I am disposed'); + + /// Adds logging to dio calls + void addLoggingInterceptor({ + required Dio dio, + required TalkerDioLoggerSettings? talkerDioLoggerSettings, + }) { + dio.interceptors.add( + TalkerDioLogger( + talker: Talker( + logger: TalkerLogger(formatter: const ColoredLoggerFormatter()), + settings: TalkerSettings( + useHistory: false, + ), + ), + settings: talkerDioLoggerSettings ?? + const TalkerDioLoggerSettings( + printRequestHeaders: true, + printResponseHeaders: true, + ), + ), + ); + } + + /// Locates for DI + static LoggingService get locate => Locator.locate(); +} + +// class _CrashlyticsObserver implements TalkerObserver { +// final crashlyticsInstance = FirebaseCrashlytics.instance; +// +// @override +// void onLog(TalkerDataInterface talkerLog) => +// crashlyticsInstance.log('[${talkerLog.title}] | ${talkerLog.displayMessage}'); +// +// @override +// void onError(TalkerError talkerError) => crashlyticsInstance.recordError( +// talkerError.error, +// talkerError.stackTrace, +// reason: '[${talkerError.title}]\n${talkerError.displayMessage}', +// fatal: true, +// ); +// +// @override +// void onException(TalkerException talkerException) => crashlyticsInstance.recordError( +// talkerException.exception, +// talkerException.stackTrace, +// reason: '[${talkerException.title}]\n${talkerException.displayMessage}', +// fatal: true, +// ); +// } diff --git a/gamestore/lib/features/core/services/navigation/core_router.dart b/gamestore/lib/features/core/services/navigation/core_router.dart new file mode 100644 index 0000000..92276f3 --- /dev/null +++ b/gamestore/lib/features/core/services/navigation/core_router.dart @@ -0,0 +1,5 @@ +part of 'navigation_service.dart'; + +/// Use for controlling popups, bottomsheet-pull-ups, inter-tab nav (such as +/// notificare alert appearing -> notificare inbox) +class _CoreRouter extends GsNavigation {} diff --git a/gamestore/lib/features/core/services/navigation/home_router.dart b/gamestore/lib/features/core/services/navigation/home_router.dart new file mode 100644 index 0000000..a060a9f --- /dev/null +++ b/gamestore/lib/features/core/services/navigation/home_router.dart @@ -0,0 +1,10 @@ +part of 'navigation_service.dart'; + +/// Use for programmatically changing navigation tabs. +class _HomeRouter extends GsNavigation { + static const _tabs = []; + + void popUntilLogin(BuildContext context) => context.goNamed(AppRoute.onboarding.name); + + static AppRoute get lastActiveRoute => _tabs[0]; +} diff --git a/gamestore/lib/features/core/services/navigation/navigation_service.dart b/gamestore/lib/features/core/services/navigation/navigation_service.dart new file mode 100644 index 0000000..fbd400f --- /dev/null +++ b/gamestore/lib/features/core/services/navigation/navigation_service.dart @@ -0,0 +1,34 @@ +// ignore_for_file: library_private_types_in_public_api + +import 'package:flutter/widgets.dart'; +import 'package:go_router/go_router.dart'; + +import '/locator.dart'; +import '../../abstracts/mwa_navigation.dart'; +import '../../abstracts/router/routes.dart'; + +part 'core_router.dart'; +part 'home_router.dart'; + +/// Provides convenient navigation functions +class NavigationService { + /// Constructor + NavigationService() + : core = _CoreRouter(), + home = _HomeRouter(); + + /// Core + final _CoreRouter core; + + /// Home + final _HomeRouter home; + + /// Dismisses any pop-up dialogs + void dismissPopup(BuildContext context) => context.pop(); + + /// Close any pop-up dialogs + void closeModalSheet(BuildContext context) => context.pop(); + + /// Locator + static NavigationService get locate => Locator.locate(); +} diff --git a/gamestore/lib/features/core/utils/iterable_utils.dart b/gamestore/lib/features/core/utils/iterable_utils.dart new file mode 100644 index 0000000..c43c488 --- /dev/null +++ b/gamestore/lib/features/core/utils/iterable_utils.dart @@ -0,0 +1,23 @@ +/// Allows for parallel iteration +/// Synonymous to the `zip` function in Python +class Pair { + /// Constructor + const Pair(this.a, this.b); + + /// Iterable 1 + final A a; + + /// Iterable 2 + final B b; +} + +/// Zips up the given Iterables for parallel iteration, and yielding +Iterable> zip(List listA, List listB) sync* { + assert( + listA.length == listB.length, + 'For zipping, lengths of the lists must match', + ); + for (var i = 0; i < listA.length; i++) { + yield Pair(listA[i], listB[i]); + } +} diff --git a/gamestore/lib/features/core/views/home/home_view.dart b/gamestore/lib/features/core/views/home/home_view.dart new file mode 100644 index 0000000..07e0a8f --- /dev/null +++ b/gamestore/lib/features/core/views/home/home_view.dart @@ -0,0 +1,33 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:gamestore/features/core/widgets/gs_app_bar.dart'; + +import '../../widgets/state/view_model_builder.dart'; +import 'home_view_model.dart'; + +/// Home view with the tabs +class HomeView extends StatelessWidget { + /// Constructor + const HomeView({super.key}); + + @override + Widget build(BuildContext context) { + return ViewModelBuilder( + disposableBuildContext: context, + viewModelBuilder: () => HomeViewModel.locate, + builder: (context, model) => PlatformScaffold( + appBar: GsAppBar(), + body: const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Center( + child: Text( + 'You have pushed the button this many times:', + ), + ), + ], + ), + ), + ); + } +} diff --git a/gamestore/lib/features/core/views/home/home_view_model.dart b/gamestore/lib/features/core/views/home/home_view_model.dart new file mode 100644 index 0000000..d2df61b --- /dev/null +++ b/gamestore/lib/features/core/views/home/home_view_model.dart @@ -0,0 +1,37 @@ +import 'package:flutter/widgets.dart'; + +import '/features/auth/services/auth_service.dart'; +import '/features/core/abstracts/base_view_model.dart'; +import '/locator.dart'; +import '../../services/navigation/navigation_service.dart'; + +/// Home VM +class HomeViewModel extends BaseViewModel { + /// Constructor + HomeViewModel({ + required AuthService authService, + required NavigationService navigationService, + }) : _authService = authService, + _navigationService = navigationService; + + @override + Future initialise( + BuildContext disposableBuildContext, + bool Function() mounted, [ + Object? arguments, + ]) async { + super.initialise(disposableBuildContext, mounted, arguments); + } + + final AuthService _authService; + final NavigationService _navigationService; + + /// On press of the logout button + Future onLogoutPressed(BuildContext context) async { + await _authService.logout(); + _navigationService.home.popUntilLogin(context); + } + + /// Locator DI + static HomeViewModel get locate => Locator.locate(); +} diff --git a/gamestore/lib/features/core/widgets/animations/animated_column.dart b/gamestore/lib/features/core/widgets/animations/animated_column.dart new file mode 100644 index 0000000..6c2a27f --- /dev/null +++ b/gamestore/lib/features/core/widgets/animations/animated_column.dart @@ -0,0 +1,74 @@ +import 'package:flutter/widgets.dart'; + +import '../../data/constants/const_durations.dart'; + +/// [AnimatedColumn] Animates its children when they get added or removed, +/// at its end. +class AnimatedColumn extends StatelessWidget { + /// Constructor + const AnimatedColumn({ + required this.children, + this.duration = ConstDurations.defaultAnimationDuration, + this.mainAxisAlignment = MainAxisAlignment.start, + this.mainAxisSize = MainAxisSize.max, + this.crossAxisAlignment = CrossAxisAlignment.center, + this.textDirection, + this.verticalDirection = VerticalDirection.down, + this.textBaseline, + this.maxAnimatingChildren = 2, + super.key, + }); + + /// [duration] specifies the duration of the add/remove animation + final Duration duration; + + /// [maxAnimatingChildren] determines the maximum number of chidren that can + /// be animating at once, if more are removed or added at within an animation + /// duration they will pop in instead + final int maxAnimatingChildren; + + /// [Column] property + final MainAxisAlignment mainAxisAlignment; + + /// [Column] property + final MainAxisSize mainAxisSize; + + /// [Column] property + final CrossAxisAlignment crossAxisAlignment; + + /// [Column] property + final TextDirection? textDirection; + + /// [Column] property + final VerticalDirection verticalDirection; + + /// [Column] property + final TextBaseline? textBaseline; + + /// [Column] property + final List children; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: crossAxisAlignment, + children: [ + for (int i = 0; i < children.length + maxAnimatingChildren; i++) + AnimatedSwitcher( + duration: duration, + switchInCurve: Curves.easeInOut, + switchOutCurve: Curves.easeInOut, + transitionBuilder: (child, animation) => FadeTransition( + opacity: animation, + child: SizeTransition( + sizeFactor: animation, + axisAlignment: -1, + child: child, + ), + ), + child: i < children.length ? children[i] : const SizedBox.shrink(), + ), + ], + ); + } +} diff --git a/gamestore/lib/features/core/widgets/animations/animated_enabled.dart b/gamestore/lib/features/core/widgets/animations/animated_enabled.dart new file mode 100644 index 0000000..7146e24 --- /dev/null +++ b/gamestore/lib/features/core/widgets/animations/animated_enabled.dart @@ -0,0 +1,35 @@ +import 'package:flutter/widgets.dart'; + +import '../../data/constants/const_durations.dart'; +import '../../data/constants/ui/const_opacities.dart'; + +/// Switches the enabled/disabled state of child with animation. +class AnimatedEnabled extends StatelessWidget { + /// Constructor + const AnimatedEnabled({ + required this.isEnabled, + required this.child, + this.animationDuration = ConstDurations.defaultAnimationDuration, + super.key, + }); + + /// Current state of [child]. + final bool isEnabled; + + /// Child + final Widget child; + + /// Animation duration + final Duration animationDuration; + + @override + Widget build(BuildContext context) => AnimatedOpacity( + opacity: isEnabled ? 1 : ConstOpacities.defaultDisabled, + duration: animationDuration, + curve: Curves.easeInOut, + child: IgnorePointer( + ignoring: !isEnabled, + child: child, + ), + ); +} diff --git a/gamestore/lib/features/core/widgets/animations/custom_ticker_provider.dart b/gamestore/lib/features/core/widgets/animations/custom_ticker_provider.dart new file mode 100644 index 0000000..c2254e9 --- /dev/null +++ b/gamestore/lib/features/core/widgets/animations/custom_ticker_provider.dart @@ -0,0 +1,89 @@ +// ignore_for_file: library_private_types_in_public_api + +import 'package:flutter/widgets.dart'; + +/// Provider for Animation controller +class AnimationControllerProvider extends StatefulWidget { + /// Constructor + const AnimationControllerProvider({ + required this.builder, + double? value, + Duration? duration, + Duration? reverseDuration, + String? debugLabel, + double lowerBound = 0.0, + double upperBound = 1.0, + AnimationBehavior animationBehavior = AnimationBehavior.normal, + bool repeatAnimation = true, + super.key, + }) : _value = value, + _duration = duration, + _reverseDuration = reverseDuration, + _debugLabel = debugLabel, + _lowerBound = lowerBound, + _upperBound = upperBound, + _animationBehavior = animationBehavior, + _repeatAnimation = repeatAnimation; + + ///Builder + final Widget Function( + BuildContext context, + AnimationController animationController, + ) builder; + + final double? _value; + final Duration? _duration; + final Duration? _reverseDuration; + final String? _debugLabel; + final double _lowerBound; + final double _upperBound; + final AnimationBehavior _animationBehavior; + final bool _repeatAnimation; + + @override + _AnimationControllerProviderState createState() => _AnimationControllerProviderState(); +} + +class _AnimationControllerProviderState extends State + with TickerProviderStateMixin { + late final AnimationController _animationController = AnimationController( + vsync: this, + value: widget._value, + duration: widget._duration, + reverseDuration: widget._reverseDuration, + debugLabel: widget._debugLabel, + lowerBound: widget._lowerBound, + upperBound: widget._upperBound, + animationBehavior: widget._animationBehavior, + ); + + @override + void initState() { + if (widget._repeatAnimation) { + _animationController.addStatusListener(_repeatListener); + } + super.initState(); + } + + void _repeatListener(AnimationStatus status) { + if (status == AnimationStatus.completed) { + _animationController.forward(from: 0); + } + } + + @override + void dispose() { + _animationController.stop(); + if (widget._repeatAnimation) { + _animationController.removeStatusListener(_repeatListener); + } + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) => widget.builder( + context, + _animationController, + ); +} diff --git a/gamestore/lib/features/core/widgets/animations/dropdown_shrink.dart b/gamestore/lib/features/core/widgets/animations/dropdown_shrink.dart new file mode 100644 index 0000000..c5885ac --- /dev/null +++ b/gamestore/lib/features/core/widgets/animations/dropdown_shrink.dart @@ -0,0 +1,151 @@ +import 'package:flutter/material.dart'; + +import '/features/core/data/constants/const_durations.dart'; + +/// Creates a shrink animation for a dropdown. +class DropdownShrink extends StatelessWidget { + /// Main constructor + const DropdownShrink.showHide({ + required this.show, + required this.child, + required this.clipFieldRadius, + required this.clipPadding, + super.key, + this.fadeDuration = ConstDurations.defaultAnimationDuration, + this.sizeDuration = ConstDurations.defaultAnimationDuration, + this.fadeInCurve = Curves.easeInOut, + this.fadeOutCurve = Curves.easeInOut, + this.sizeCurve = Curves.easeInOut, + this.alignment = Alignment.center, + this.hide, + this.width, + }); + + static final _key = UniqueKey(); + + /// Child + final Widget child; + + /// Fade [Duration] + final Duration fadeDuration; + + /// Size change animation [Duration] + final Duration sizeDuration; + + /// Curve definition for fade-in + final Curve fadeInCurve; + + /// Curve definition for fade-out + final Curve fadeOutCurve; + + /// Curve definition for resizing + final Curve sizeCurve; + + /// Alignment property. + final AlignmentGeometry alignment; + + /// Whether to show the content + final bool show; + + /// Widget to hide with + final Widget? hide; + + /// Width of the dropdown + final double? width; + + /// Radial distance from the clip + final double clipFieldRadius; + + /// Clip padding + final EdgeInsets clipPadding; + + @override + Widget build(BuildContext context) { + return ClipPath( + clipper: _DropdownClipper( + fieldRadius: clipFieldRadius, + padding: clipPadding, + ), + child: AnimatedSize( + duration: sizeDuration, + curve: sizeCurve, + alignment: alignment, + child: AnimatedSwitcher( + duration: fadeDuration, + switchInCurve: fadeInCurve, + switchOutCurve: fadeOutCurve, + transitionBuilder: hide != null + ? (child, animation) => FadeTransition( + opacity: Tween(begin: 0, end: 1).animate( + CurvedAnimation( + parent: animation, + curve: const Interval(0.15, 1, curve: Curves.easeInOut), + ), + ), + child: child, + ) + : AnimatedSwitcher.defaultTransitionBuilder, + layoutBuilder: (currentChild, previousChildren) { + var children = previousChildren; + if (currentChild != null) { + if (previousChildren.isEmpty) { + children = [currentChild]; + } else { + children = [ + Positioned( + left: 0, + right: 0, + child: previousChildren[0], + ), + currentChild, + ]; + } + } + return Stack( + clipBehavior: Clip.none, + alignment: alignment, + children: children, + ); + }, + child: show + ? child + : (hide ?? + SizedBox( + key: _key, + width: width ?? double.infinity, + height: 0, + )), + ), + ), + ); + } +} + +class _DropdownClipper extends CustomClipper { + const _DropdownClipper({ + required this.padding, + required this.fieldRadius, + }); + + final EdgeInsets padding; + final double fieldRadius; + + @override + Path getClip(Size size) { + final path = Path() + ..moveTo(fieldRadius, 0) + ..relativeQuadraticBezierTo(-fieldRadius, 0, -fieldRadius, -fieldRadius) + ..lineTo(0, 0) + ..lineTo(-padding.left, 0) + ..lineTo(-padding.left, size.height + padding.bottom) + ..lineTo(size.width + padding.right, size.height + padding.bottom) + ..lineTo(size.width + padding.right, -fieldRadius) + ..lineTo(size.width, -fieldRadius) + ..relativeQuadraticBezierTo(0, fieldRadius, -fieldRadius, fieldRadius) + ..close(); + return path; + } + + @override + bool shouldReclip(CustomClipper oldClipper) => false; +} diff --git a/gamestore/lib/features/core/widgets/animations/fade_in_fade_out_switcher.dart b/gamestore/lib/features/core/widgets/animations/fade_in_fade_out_switcher.dart new file mode 100644 index 0000000..8536ca2 --- /dev/null +++ b/gamestore/lib/features/core/widgets/animations/fade_in_fade_out_switcher.dart @@ -0,0 +1,50 @@ +import 'package:animated_list_plus/transitions.dart'; +import 'package:flutter/widgets.dart'; + +import '/features/core/data/constants/const_durations.dart'; + +/// Switches in a [Widget] when it is changed, with a Fade Effect. +class FadeInFadeOutSwitcher extends StatelessWidget { + /// Constructor + const FadeInFadeOutSwitcher({ + required Widget child, + bool transformSize = false, + this.animationDuration = ConstDurations.defaultAnimationDuration, + super.key, + }) : _child = child, + _transformSize = transformSize; + + final Widget _child; + final bool _transformSize; + + /// Animation timing + final Duration animationDuration; + + @override + Widget build(BuildContext context) { + return AnimatedSize( + duration: animationDuration, + child: AnimatedSwitcher( + duration: animationDuration, + transitionBuilder: (child, animation) { + final animationTween = Tween(begin: 0, end: 1).animate( + CurvedAnimation( + parent: animation, + curve: const Interval(0.15, 1, curve: Curves.easeInOut), + ), + ); + return _transformSize + ? SizeFadeTransition( + animation: animationTween, + child: child, + ) + : FadeTransition( + opacity: animationTween, + child: child, + ); + }, + child: _child, + ), + ); + } +} diff --git a/gamestore/lib/features/core/widgets/animations/shrink.dart b/gamestore/lib/features/core/widgets/animations/shrink.dart new file mode 100644 index 0000000..30c58d1 --- /dev/null +++ b/gamestore/lib/features/core/widgets/animations/shrink.dart @@ -0,0 +1,220 @@ +import 'package:flutter/material.dart'; + +import '../../data/constants/const_durations.dart'; + +/// Animates the vertical shrinking and fading of its child widgets. +class VerticalShrink extends StatelessWidget { + /// Main constructor + const VerticalShrink.showHide({ + required this.show, + required this.showChild, + this.fadeDuration = ConstDurations.defaultAnimationDuration, + this.sizeDuration = ConstDurations.defaultAnimationDuration, + this.fadeInCurve = Curves.easeInOut, + this.fadeOutCurve = Curves.easeInOut, + this.sizeCurve = Curves.easeInOut, + this.alignment = Alignment.center, + this.curveIntervalStart = 0.15, + this.hideChild, + this.width, + super.key, + }); + + static final _key = UniqueKey(); + + /// The widget to be shown when show is true + final Widget showChild; + + /// Duration of the fade animation + final Duration fadeDuration; + + /// Duration of the size (vertical shrink) animation + final Duration sizeDuration; + + /// Curve for the fade-in animation + final Curve fadeInCurve; + + /// Curve for the fade-out animation + final Curve fadeOutCurve; + + /// Curve for the size animation + final Curve sizeCurve; + + /// Alignment of the child widgets + final AlignmentGeometry alignment; + + /// Should be shown + final bool show; + + /// An optional widget to be shown when show is false. + /// If not provided, a SizedBox with no dimensions is used + final Widget? hideChild; + + /// The start point of the curve interval for the fade-in animation + final double curveIntervalStart; + + /// An optional width to be applied to the SizedBox when hideChild is used + final double? width; + + @override + Widget build(BuildContext context) { + return ClipRect( + child: AnimatedSize( + duration: sizeDuration, + curve: sizeCurve, + alignment: alignment, + child: AnimatedSwitcher( + duration: fadeDuration, + switchInCurve: fadeInCurve, + switchOutCurve: fadeOutCurve, + transitionBuilder: hideChild != null + ? (child, animation) => FadeTransition( + opacity: Tween(begin: 0, end: 1).animate( + CurvedAnimation( + parent: animation, + curve: Interval( + curveIntervalStart, + 1, + curve: Curves.easeInOut, + ), + ), + ), + child: child, + ) + : AnimatedSwitcher.defaultTransitionBuilder, + layoutBuilder: (currentChild, previousChildren) { + final children = List.empty(growable: true); + if (currentChild != null) { + if (previousChildren.isEmpty) { + children.add(currentChild); + } else { + children.addAll( + [ + Positioned( + left: 0, + right: 0, + child: previousChildren[0], + ), + currentChild, + ], + ); + } + } + return Stack( + clipBehavior: Clip.none, + alignment: alignment, + children: children.isNotEmpty ? children : previousChildren, + ); + }, + child: show + ? showChild + : (hideChild ?? + SizedBox( + key: _key, + width: width ?? double.infinity, + height: 0, + )), + ), + ), + ); + } +} + +/// Animates the horizontal shrinking and fading of its child widgets. +class HorizontalShrink extends StatelessWidget { + /// Main constructor + const HorizontalShrink.showHide({ + required this.show, + required this.showChild, + this.fadeDuration = ConstDurations.defaultAnimationDuration, + this.sizeDuration = ConstDurations.defaultAnimationDuration, + this.fadeInCurve = Curves.easeInOut, + this.fadeOutCurve = Curves.easeInOut, + this.sizeCurve = Curves.easeInOut, + this.alignment = Alignment.center, + this.hideChild, + this.height, + super.key, + }); + + static final _key = UniqueKey(); + + /// The widget to be shown when show is true + final Widget showChild; + + /// Duration of the fade animation + final Duration fadeDuration; + + /// Duration of the size (vertical shrink) animation + final Duration sizeDuration; + + /// Curve for the fade-in animation + final Curve fadeInCurve; + + /// Curve for the fade-out animation + final Curve fadeOutCurve; + + /// Curve for the size animation + final Curve sizeCurve; + + /// Alignment of the child widgets + final AlignmentGeometry alignment; + + /// Should be shown + final bool show; + + /// An optional widget to be shown when show is false. + /// If not provided, a SizedBox with no dimensions is used + final Widget? hideChild; + + /// An optional width to be applied to the SizedBox when hideChild is used + final double? height; + + @override + Widget build(BuildContext context) { + return ClipRect( + child: AnimatedSize( + duration: sizeDuration, + curve: sizeCurve, + alignment: alignment, + child: AnimatedSwitcher( + duration: fadeDuration, + switchInCurve: fadeInCurve, + layoutBuilder: (currentChild, previousChildren) { + final children = List.empty(growable: true); + if (currentChild != null) { + if (previousChildren.isEmpty) { + children.add(currentChild); + } else { + children.addAll( + [ + Positioned( + top: 0, + bottom: 0, + child: previousChildren[0], + ), + currentChild, + ], + ); + } + } + return Stack( + clipBehavior: Clip.none, + alignment: alignment, + children: children.isNotEmpty ? children : previousChildren, + ); + }, + switchOutCurve: fadeOutCurve, + child: show + ? showChild + : (hideChild ?? + SizedBox( + key: _key, + width: 0, + height: height ?? double.infinity, + )), + ), + ), + ); + } +} diff --git a/gamestore/lib/features/core/widgets/gap.dart b/gamestore/lib/features/core/widgets/gap.dart new file mode 100644 index 0000000..39cbf6f --- /dev/null +++ b/gamestore/lib/features/core/widgets/gap.dart @@ -0,0 +1,268 @@ +// ignore_for_file: library_private_types_in_public_api + +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; + +/// Create constant size based on parent layout. +class Gap extends LeafRenderObjectWidget { + /// Constructor + const Gap(this.size, {super.key}); + + /// Pixel-size + final double size; + + @override + _RenderGap createRenderObject(BuildContext context) => _RenderGap(size); + + @override + void updateRenderObject( + BuildContext context, + covariant _RenderGap renderObject, + ) { + renderObject.gap = size; + super.updateRenderObject(context, renderObject); + } + + /// 4 pixels + static const size4 = Gap(4); + + /// 8 pixels + static const size8 = Gap(8); + + /// 16 pixels + static const size16 = Gap(16); + + /// 24 pixels + static const size24 = Gap(24); + + /// 32 pixels + static const size32 = Gap(32); + + /// 48 pixels + static const size48 = Gap(48); + + /// 64 pixels + static const size64 = Gap(64); +} + +class _RenderGap extends RenderBox { + _RenderGap(this._gap) : super() { + markNeedsLayout(); + } + + double _gap; + double get gap => _gap; + + set gap(double value) { + if (_gap != value) { + _gap = value; + markNeedsLayout(); + } + } + + @override + void performLayout() { + final parent = this.parent; + Size newSize; + if (parent is RenderFlex) { + switch (parent.direction) { + case Axis.vertical: + newSize = Size(0, gap); + case Axis.horizontal: + newSize = Size(gap, 0); + } + } else { + newSize = Size.square(gap); + } + size = constraints.constrain(newSize); + } +} + +/// Animated version of the [Gap] widget. +class AnimatedGap extends StatefulWidget { + /// Constructor + const AnimatedGap( + this.gap, { + super.key, + this.duration = const Duration(milliseconds: 200), + this.curve = Curves.easeInOut, + }); + + /// Time of animation + final Duration duration; + + /// Pixel size + final double gap; + + /// Rate of change of animation + final Curve curve; + + @override + State createState() => _AnimatedGapState(); +} + +class _AnimatedGapState extends State with SingleTickerProviderStateMixin { + late final _controller = AnimationController( + vsync: this, + value: widget.gap, + ); + + @override + void didUpdateWidget(covariant AnimatedGap oldWidget) { + if (oldWidget.gap != widget.gap) { + _controller.animateTo( + widget.gap, + curve: widget.curve, + duration: widget.duration, + ); + } + super.didUpdateWidget(oldWidget); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _controller, + builder: (context, _) { + return Gap(_controller.value); + }, + ); + } +} + +/// An [SliverGap] that can be used inside of a [RenderSliver]. +class SliverGap extends LeafRenderObjectWidget { + /// Constructor + const SliverGap(this.gap, {super.key}); + + /// Pixel size + final double gap; + + /// 4 pixels + static const size4 = SliverGap(4); + + /// 8 pixels + static const size8 = SliverGap(8); + + /// 16 pixels + static const size16 = SliverGap(16); + + /// 24 pixels + static const size24 = SliverGap(24); + + /// 32 pixels + static const size32 = SliverGap(32); + + /// 48 pixels + static const size48 = SliverGap(48); + + /// 64 pixels + static const size64 = SliverGap(64); + + @override + _RenderSliverGap createRenderObject(BuildContext context) => _RenderSliverGap(gap); + + @override + void updateRenderObject( + BuildContext context, + covariant _RenderSliverGap renderObject, + ) { + renderObject.gap = gap; + super.updateRenderObject(context, renderObject); + } +} + +class _RenderSliverGap extends RenderSliver { + _RenderSliverGap(this._gap) : super() { + markNeedsLayout(); + } + + double _gap; + + double get gap => _gap; + + set gap(double value) { + if (_gap != value) { + _gap = value; + markNeedsLayout(); + } + } + + @override + void performLayout() { + final cacheExtent = calculateCacheOffset(constraints, from: 0, to: gap); + final paintExtent = calculatePaintOffset(constraints, from: 0, to: gap); + geometry = SliverGeometry( + paintExtent: paintExtent, + scrollExtent: gap, + visible: false, + cacheExtent: cacheExtent, + maxPaintExtent: gap, + ); + } +} + +/// An [AnimatedGap] that can be used inside of a [RenderSliver]. +class AnimatedSliverGap extends StatefulWidget { + /// Constructor + const AnimatedSliverGap( + this.gap, { + super.key, + this.duration = const Duration(milliseconds: 200), + this.curve = Curves.easeInOut, + }); + + /// Time of animation + final Duration duration; + + /// Pixel size + final double gap; + + /// Rate of change of animation + final Curve curve; + + @override + State createState() => _AnimatedSliverGapState(); +} + +class _AnimatedSliverGapState extends State with SingleTickerProviderStateMixin { + late final _controller = AnimationController( + vsync: this, + duration: widget.duration, + ); + + late final _gapTween = Tween( + begin: 0, + end: widget.gap, + ); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + void didUpdateWidget(covariant AnimatedSliverGap oldWidget) { + if (oldWidget.gap != widget.gap) { + _gapTween + ..begin = oldWidget.gap + ..end = widget.gap; + _controller + ..reset() + ..forward(); + } + super.didUpdateWidget(oldWidget); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + final gap = _gapTween.evaluate(_controller); + return SliverGap(gap); + }, + ); + } +} diff --git a/gamestore/lib/features/core/widgets/gs_app_bar.dart b/gamestore/lib/features/core/widgets/gs_app_bar.dart new file mode 100644 index 0000000..93a9a35 --- /dev/null +++ b/gamestore/lib/features/core/widgets/gs_app_bar.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart' show kToolbarHeight; +import 'package:flutter/widgets.dart'; +import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; + +import '../data/constants/const_colours.dart'; + +/// Standard [PlatformAppBar] for the app +class GsAppBar extends PlatformAppBar implements PreferredSizeWidget { + /// Customized app bar for the app + GsAppBar({ + Widget? title, + bool centerTitle = true, + Widget? leading, + Widget? trailing, + super.automaticallyImplyLeading = true, + super.key, + }) : super( + title: centerTitle + ? Center( + child: title, + ) + : title, + backgroundColor: ConstColours.indigoDye, + leading: leading ?? + IgnorePointer( + child: Opacity( + opacity: 0, + child: trailing, + ), + ), + trailingActions: trailing != null + ? [trailing] + : (centerTitle + ? [ + IgnorePointer( + child: Opacity(opacity: 0, child: leading), + ), + ] + : []), + cupertino: (_, __) => CupertinoNavigationBarData( + noMaterialParent: true, + transitionBetweenRoutes: true, + ), + ); + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); +} diff --git a/gamestore/lib/features/core/widgets/platform_custom_form.dart b/gamestore/lib/features/core/widgets/platform_custom_form.dart new file mode 100644 index 0000000..e21cb62 --- /dev/null +++ b/gamestore/lib/features/core/widgets/platform_custom_form.dart @@ -0,0 +1,83 @@ +import 'package:flutter/cupertino.dart' show CupertinoFormSection, CupertinoTextFormFieldRow; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart' show InputDecoration, TextFormField; +import 'package:flutter/widgets.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; + +import '../data/enums/form_field_type.dart'; +import '../forms/form_field_config.dart'; + +/// Standard form +class PlatformCustomForm extends StatelessWidget { + /// Constructor + const PlatformCustomForm({ + required this.fields, + super.key, + }); + + /// Fields to be included inside the form. + final Map fields; + + @override + Widget build(BuildContext context) { + return FormBuilder( + child: PlatformWidget( + material: (context, _) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Column( + children: [ + for (final field in fields.entries) + ValueListenableBuilder( + valueListenable: field.value.isEnabledListenable, + builder: (context, isEnabled, _) => TextFormField( + decoration: InputDecoration(labelText: field.value.hintText), + obscureText: field.key == FormFieldType.password, + controller: field.value.textEditingController, + enabled: isEnabled, + ), + ), + ], + ), + ), + cupertino: (context, _) => fields.length == 1 + ? _ListenableCupertinoTextFormField( + field: fields.entries.first, + isEnabledListenable: fields.entries.first.value.isEnabledListenable, + ) + : CupertinoFormSection.insetGrouped( + children: [ + for (final field in fields.entries) + _ListenableCupertinoTextFormField( + field: field, + isEnabledListenable: field.value.isEnabledListenable, + ), + ], + ), + ), + ); + } +} + +class _ListenableCupertinoTextFormField extends StatelessWidget { + const _ListenableCupertinoTextFormField({ + required this.field, + required this.isEnabledListenable, + }); + + final MapEntry field; + final ValueListenable isEnabledListenable; + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: field.value.isEnabledListenable, + builder: (context, isEnabled, _) => CupertinoTextFormFieldRow( + prefix: Text(field.value.hintText ?? ''), + obscureText: field.key == FormFieldType.password, + controller: field.value.textEditingController, + enabled: isEnabled, + ), + ); + } +} diff --git a/gamestore/lib/features/core/widgets/state/multi_value_listenable_builder.dart b/gamestore/lib/features/core/widgets/state/multi_value_listenable_builder.dart new file mode 100644 index 0000000..be35c3e --- /dev/null +++ b/gamestore/lib/features/core/widgets/state/multi_value_listenable_builder.dart @@ -0,0 +1,43 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +/// This widget listens to multiple [ValueListenable]s and calls given builder function +/// if any one of them changes. +class MultiValueListenableBuilder extends StatelessWidget { + /// Constructor + const MultiValueListenableBuilder({ + required this.valueListenables, + required this.builder, + this.child, + super.key, + }) : assert( + valueListenables.length != 0, + 'Attached valueListenables must not be empty', + ); + + /// List of [ValueListenable]s to be listened to. + final List> valueListenables; + + /// The builder function to be called when value of any of the [ValueListenable] changes. + /// The order of values list will be same as [valueListenables] list. + final Widget Function(BuildContext context, List values, Widget? child) builder; + + /// An optional child widget which will be available as child parameter in [builder]. + final Widget? child; + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: Listenable.merge(valueListenables), + builder: (context, child) { + final providedValues = valueListenables.map((listenable) => listenable.value); + return builder( + context, + List.unmodifiable(providedValues), + child, + ); + }, + child: child, + ); + } +} diff --git a/gamestore/lib/features/core/widgets/state/view_model_builder.dart b/gamestore/lib/features/core/widgets/state/view_model_builder.dart new file mode 100644 index 0000000..c2a3d7d --- /dev/null +++ b/gamestore/lib/features/core/widgets/state/view_model_builder.dart @@ -0,0 +1,74 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:provider/provider.dart'; + +import '/features/core/abstracts/base_view_model.dart'; +import '../../data/constants/const_durations.dart'; +import '../animations/fade_in_fade_out_switcher.dart'; + +/// Builds the bridge between a View and the View Model +class ViewModelBuilder extends StatefulWidget { + /// Builds the bridge between a View and the View Model + const ViewModelBuilder({ + required Widget Function(BuildContext context, T model) builder, + required T Function() viewModelBuilder, + required BuildContext disposableBuildContext, + dynamic Function()? argumentBuilder, + Widget? loadingIndicator, + super.key, + }) : _builder = builder, + _viewModelBuilder = viewModelBuilder, + _argumentBuilder = argumentBuilder, + _loadingIndicator = loadingIndicator, + _disposableBuildContext = disposableBuildContext; + + final Widget Function(BuildContext context, T model) _builder; + final T Function() _viewModelBuilder; + final dynamic Function()? _argumentBuilder; + + final Widget? _loadingIndicator; + final BuildContext _disposableBuildContext; + + @override + // ignore: library_private_types_in_public_api + _ViewModelBuilderState createState() => _ViewModelBuilderState(); +} + +class _ViewModelBuilderState extends State> { + late final T _viewModel; + + @override + void initState() { + _viewModel = widget._viewModelBuilder(); + _viewModel.initialise( + widget._disposableBuildContext, + () => mounted, + widget._argumentBuilder?.call(), + ); + super.initState(); + } + + @override + void dispose() { + _viewModel.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext _) => ChangeNotifierProvider.value( + value: _viewModel, + child: Consumer( + builder: (context, model, _) => ValueListenableBuilder( + valueListenable: _viewModel.isInitialised, + builder: (context, isInitialised, _) => FadeInFadeOutSwitcher( + animationDuration: ConstDurations.oneAndHalfDefaultAnimationDuration, + child: isInitialised + ? widget._builder(context, model) + : Center( + child: widget._loadingIndicator ?? PlatformCircularProgressIndicator(), + ), + ), + ), + ), + ); +} diff --git a/gamestore/lib/features/core/widgets/state/view_model_widget.dart b/gamestore/lib/features/core/widgets/state/view_model_widget.dart new file mode 100644 index 0000000..5eab2a9 --- /dev/null +++ b/gamestore/lib/features/core/widgets/state/view_model_widget.dart @@ -0,0 +1,38 @@ +// ignore_for_file: library_private_types_in_public_api + +import 'package:flutter/widgets.dart'; +import 'package:provider/provider.dart'; + +/// Provides a model to a widget and rebuilds when notifyListeners is called. +/// +/// Do keep in mind that you need to have the model in the context, +/// so only use these widgets inside the views of the view models +/// where the view model is present. +abstract class ViewModelWidget extends Widget { + /// Constructor + const ViewModelWidget({super.key}); + + /// Build abstract method + @protected + Widget build(BuildContext context, T model); + + @override + _DataProviderElement createElement() => _DataProviderElement(this); +} + +class _DataProviderElement extends ComponentElement { + _DataProviderElement(ViewModelWidget super.widget); + + @override + ViewModelWidget get widget => super.widget as ViewModelWidget; + + @override + Widget build() => widget.build(this, Provider.of(this)); + + @override + void update(ViewModelWidget newWidget) { + super.update(newWidget); + assert(widget == newWidget, 'widget is the same as newWidget'); + rebuild(); + } +} diff --git a/gamestore/lib/l10n/generated/intl/messages_all.dart b/gamestore/lib/l10n/generated/intl/messages_all.dart new file mode 100644 index 0000000..203415c --- /dev/null +++ b/gamestore/lib/l10n/generated/intl/messages_all.dart @@ -0,0 +1,63 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that looks up messages for specific locales by +// delegating to the appropriate library. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:implementation_imports, file_names, unnecessary_new +// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering +// ignore_for_file:argument_type_not_assignable, invalid_assignment +// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases +// ignore_for_file:comment_references + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; +import 'package:intl/src/intl_helpers.dart'; + +import 'messages_en.dart' as messages_en; + +typedef Future LibraryLoader(); +Map _deferredLibraries = { + 'en': () => new SynchronousFuture(null), +}; + +MessageLookupByLibrary? _findExact(String localeName) { + switch (localeName) { + case 'en': + return messages_en.messages; + default: + return null; + } +} + +/// User programs should call this before using [localeName] for messages. +Future initializeMessages(String localeName) { + var availableLocale = Intl.verifiedLocale( + localeName, (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); + if (availableLocale == null) { + return new SynchronousFuture(false); + } + var lib = _deferredLibraries[availableLocale]; + lib == null ? new SynchronousFuture(false) : lib(); + initializeInternalMessageLookup(() => new CompositeMessageLookup()); + messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); + return new SynchronousFuture(true); +} + +bool _messagesExistFor(String locale) { + try { + return _findExact(locale) != null; + } catch (e) { + return false; + } +} + +MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { + var actualLocale = + Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); + if (actualLocale == null) return null; + return _findExact(actualLocale); +} diff --git a/gamestore/lib/l10n/generated/intl/messages_en.dart b/gamestore/lib/l10n/generated/intl/messages_en.dart new file mode 100644 index 0000000..2952cbb --- /dev/null +++ b/gamestore/lib/l10n/generated/intl/messages_en.dart @@ -0,0 +1,30 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a en locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'en'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "formFieldRequired": + MessageLookupByLibrary.simpleMessage("This is required"), + "somethingWentWrong": + MessageLookupByLibrary.simpleMessage("Something went wrong") + }; +} diff --git a/gamestore/lib/l10n/generated/l10n.dart b/gamestore/lib/l10n/generated/l10n.dart new file mode 100644 index 0000000..4c14d0e --- /dev/null +++ b/gamestore/lib/l10n/generated/l10n.dart @@ -0,0 +1,98 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'intl/messages_all.dart'; + +// ************************************************************************** +// Generator: Flutter Intl IDE plugin +// Made by Localizely +// ************************************************************************** + +// ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars +// ignore_for_file: join_return_with_assignment, prefer_final_in_for_each +// ignore_for_file: avoid_redundant_argument_values, avoid_escaping_inner_quotes + +class Strings { + Strings(); + + static Strings? _current; + + static Strings get current { + assert(_current != null, + 'No instance of Strings was loaded. Try to initialize the Strings delegate before accessing Strings.current.'); + return _current!; + } + + static const AppLocalizationDelegate delegate = AppLocalizationDelegate(); + + static Future load(Locale locale) { + final name = (locale.countryCode?.isEmpty ?? false) + ? locale.languageCode + : locale.toString(); + final localeName = Intl.canonicalizedLocale(name); + return initializeMessages(localeName).then((_) { + Intl.defaultLocale = localeName; + final instance = Strings(); + Strings._current = instance; + + return instance; + }); + } + + static Strings of(BuildContext context) { + final instance = Strings.maybeOf(context); + assert(instance != null, + 'No instance of Strings present in the widget tree. Did you add Strings.delegate in localizationsDelegates?'); + return instance!; + } + + static Strings? maybeOf(BuildContext context) { + return Localizations.of(context, Strings); + } + + /// `Something went wrong` + String get somethingWentWrong { + return Intl.message( + 'Something went wrong', + name: 'somethingWentWrong', + desc: '', + args: [], + ); + } + + /// `This is required` + String get formFieldRequired { + return Intl.message( + 'This is required', + name: 'formFieldRequired', + desc: '', + args: [], + ); + } +} + +class AppLocalizationDelegate extends LocalizationsDelegate { + const AppLocalizationDelegate(); + + List get supportedLocales { + return const [ + Locale.fromSubtags(languageCode: 'en'), + ]; + } + + @override + bool isSupported(Locale locale) => _isSupported(locale); + @override + Future load(Locale locale) => Strings.load(locale); + @override + bool shouldReload(AppLocalizationDelegate old) => false; + + bool _isSupported(Locale locale) { + for (var supportedLocale in supportedLocales) { + if (supportedLocale.languageCode == locale.languageCode) { + return true; + } + } + return false; + } +} diff --git a/gamestore/lib/l10n/intl_en.arb b/gamestore/lib/l10n/intl_en.arb new file mode 100644 index 0000000..b8a2ca0 --- /dev/null +++ b/gamestore/lib/l10n/intl_en.arb @@ -0,0 +1,6 @@ +{ + "@@locale": "en", + + "somethingWentWrong": "Something went wrong", + "formFieldRequired": "This is required" +} \ No newline at end of file diff --git a/gamestore/lib/locator.dart b/gamestore/lib/locator.dart new file mode 100644 index 0000000..ae3d1b8 --- /dev/null +++ b/gamestore/lib/locator.dart @@ -0,0 +1,70 @@ +import 'dart:async'; + +import 'package:gamestore/features/auth/services/auth_service.dart'; +import 'package:gamestore/features/core/services/navigation/navigation_service.dart'; +import 'package:gamestore/features/core/views/home/home_view_model.dart'; +import 'package:get_it/get_it.dart'; + +import 'features/core/services/logging_service.dart'; + +/// Locates dependency for DI +GetIt get locate => Locator.instance(); + +/// Dependency Injection +class Locator { + /// Instance of [GetIt] + static GetIt instance() => GetIt.instance; + + /// Callback for performing a DI lookup + static T locate() => instance().get(); + + /// Set up of all DI registrations + static Future setup() async { + final locator = instance()..registerFactory(LoggingService.new); + + _registerStores(locator); + _registerAPIs(locator); + _registerViewModels(locator); + _registerLazySingletons(); + _registerFactories(); + + await _registerDaos(locator); + await _registerServices(locator); + + await _registerRepos(locator); + await _registerBlocs(locator); + + _registerSingletons(); + } + + static void _registerAPIs(GetIt it) {} + + static void _registerLazySingletons() {} + + static void _registerSingletons() {} + + static void _registerFactories() {} + + static void _registerStores(GetIt it) {} + + static Future _registerBlocs(GetIt it) async {} + + static Future _registerDaos(GetIt it) async {} + + static Future _registerRepos(GetIt it) async {} + + static Future _registerServices(GetIt it) async { + it + ..registerLazySingleton(AuthService.new) + ..registerLazySingleton(NavigationService.new); + } + + static void _registerViewModels(GetIt it) { + it.registerFactory( + () => HomeViewModel( + authService: AuthService.locate, + navigationService: NavigationService.locate, + ), + ); + } +} diff --git a/gamestore/lib/main_dev.dart b/gamestore/lib/main_dev.dart new file mode 100644 index 0000000..e82d712 --- /dev/null +++ b/gamestore/lib/main_dev.dart @@ -0,0 +1,7 @@ +import 'app.dart'; +import 'features/core/data/enums/environment_type.dart'; + +Future main() async { + EnvironmentType.dev.override(); + await mainRoot(); +} diff --git a/gamestore/lib/main_prod.dart b/gamestore/lib/main_prod.dart new file mode 100644 index 0000000..e82d712 --- /dev/null +++ b/gamestore/lib/main_prod.dart @@ -0,0 +1,7 @@ +import 'app.dart'; +import 'features/core/data/enums/environment_type.dart'; + +Future main() async { + EnvironmentType.dev.override(); + await mainRoot(); +} diff --git a/gamestore/pubspec.yaml b/gamestore/pubspec.yaml new file mode 100644 index 0000000..197eb89 --- /dev/null +++ b/gamestore/pubspec.yaml @@ -0,0 +1,107 @@ +name: gamestore +description: A new Flutter project. +publish_to: 'none' +version: 1.0.0+1 +environment: + flutter: '>=3.13.0 <4.0.0' + sdk: '>=3.0.0 <4.0.0' + + + + + + +dependencies: + flutter: + sdk: flutter + + # Firebase + cloud_firestore: ^4.12.1 + firebase_core: ^2.20.0 + firebase_crashlytics: ^3.4.2 + + # Backend + get_it: ^7.6.4 + + # UI + animated_list_plus: ^0.5.2 + cupertino_icons: ^1.0.6 + flutter_form_builder: ^9.1.1 + enough_platform_widgets: ^0.7.4 + + # Utils + flutter_screenutil: ^5.9.0 + flutter_svg: ^2.0.8 + form_builder_validators: ^9.1.0 + go_router: ^12.0.0 + intl: 0.18.1 + intl_utils: ^2.8.5 + + # Data + dartz: ^0.10.1 + envied: ^0.3.0+3 + hive: ^2.2.3 + hive_flutter: ^1.1.0 + json_annotation: ^4.8.1 + json_serializable: ^6.7.1 + + # Networking + dio: ^5.3.3 + + # Logging + talker: ^3.1.4 + talker_dio_logger: ^2.3.1 + + # State management + equatable: ^2.0.5 + informers: ^0.0.3+1 + provider: ^6.0.5 + + + + + + +dev_dependencies: + # Generators + build_runner: ^2.4.6 + envied_generator: ^0.3.0+3 + + # Analysis + analyzer: ^5.13.0 + flutter_lints: ^3.0.0 + very_good_analysis: ^5.1.0 + + # Testing + flutter_test: + sdk: flutter + + # Bundling + flutter_flavorizr: ^2.2.1 + flutter_native_splash: ^2.3.4 + flutter_launcher_icons: ^0.13.1 + + + + + + +flutter: + generate: true + uses-material-design: true + + assets: + - assets/icons/ + - assets/logos/ + + + + + + +flutter_intl: + enabled: true + class_name: Strings + main_locale: "en" + output_dir: lib/l10n/generated + # use_deferred_loading: true diff --git a/gamestore/test/widget_test.dart b/gamestore/test/widget_test.dart new file mode 100644 index 0000000..62e6a58 --- /dev/null +++ b/gamestore/test/widget_test.dart @@ -0,0 +1,29 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:gamestore/app.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const GamestoreApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +}