feat/upgrade-app-template #7
| @ -6,54 +6,55 @@ A short project description | |||||||
| 
 | 
 | ||||||
| * Flutter <https://flutter.dev/> | * Flutter <https://flutter.dev/> | ||||||
| * Taskfile <https://taskfile.dev/> | * Taskfile <https://taskfile.dev/> | ||||||
| * Trapeze <https://trapeze.dev/> (with `npm install` thanks to `package.json`) |  | ||||||
| 
 | 
 | ||||||
| ### Configuration | ### Configuration | ||||||
| 
 | 
 | ||||||
| Create `.env` file with | At the build time, the app will read the environment variables from `config.json` file. | ||||||
| 
 | 
 | ||||||
| ```sh | The important variable is `DEV_MODE` which can be `mock` , `local` or `real` . | ||||||
| cp .env.example .env | 
 | ||||||
|  | ```json | ||||||
|  | { | ||||||
|  |   "DEV_MODE": "local" | ||||||
|  | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | > **Note** `local` can refer to a local server or a local emulator. | ||||||
|  | 
 | ||||||
| ### Taskfile | ### Taskfile | ||||||
| 
 | 
 | ||||||
| Available tasks: | Available tasks: | ||||||
| 
 | 
 | ||||||
| | Command | Description | Aliases | | | Commande | Description | Alias | | ||||||
| |----|-----|-----| | | --- | --- | --- | | ||||||
| | `clean` | Cleans the environment.| `cl` | | | clean | Nettoie l'environnement de travail | cl | | ||||||
| | `format` |Formats the code.| `fmt` | | | format | Formate le code | fmt | | ||||||
| | `help` |Help dialog.| `h, default` | | | help | Affiche la boîte de dialogue d'aide | h, default | | ||||||
| | `lint` |Lints the code.| `l` | | | lint | Vérifie la qualité du code | l | | ||||||
| | `start-emulators` | Start needed emulators.| `emu` | | | start-emulators | Démarre les émulateurs nécessaires | emu | | ||||||
| | `build:android` | Building Android APK| `build:a` | | | build:android | Construit le fichier APK pour Android | build:a | | ||||||
| | `build:ios` | Building iOS IPA| `build:i` | | | build:ios | Construit le fichier IPA pour iOS | build:i | | ||||||
| | `gen:build` | Running build runner| `gen:b` | | | gen:build | Exécute le générateur de build | gen:b | | ||||||
| | `gen:build-delete` |Running build runner with deletion of conflicting outputs| `gen:d` | | | gen:build-delete | Exécute le générateur de build et supprime les sorties en conflit | gen:d | | ||||||
| | `gen:clean` | Cleaning build runner| `gen:c` | | | gen:clean | Nettoie le générateur de build | gen:c | | ||||||
| | `gen:intl` |Generating internationalization file| `gen:i` | | | gen:intl | Génère un fichier d'internationalisation | gen:i | | ||||||
| | `gen:trapeze` | Running Trapeze config| `gen:t` | | | gen:watch | Exécute le générateur de build en mode surveillance | gen:w | | ||||||
| | `gen:watch` | Running build runner in watch mode| `gen:w` | | | pub:get | Obtient les dernières dépendances | pub:g | | ||||||
| | `pub:get` | Getting latest dependencies| `pub:g` | | | pub:outdated | Vérifie les dépendances obsolètes | pub:o | | ||||||
| | `pub:outdated` |Checking for outdated dependencies| `pub:o` | | | pub:upgrade | Met à jour les dépendances | pub:u | | ||||||
| | `pub:upgrade` | Upgrading dependencies| `pub:u` | | | pub:upgrade-major | Met à jour les dépendances majeures | pub:um | | ||||||
| | `pub:upgrade-major` | Upgrading dependencies| `pub:um` | | | pub:validate | Exécute le validateur de dépendances | pub:v | | ||||||
| | `pub:validate` |Running dependency validator| `pub:v` | | | run:dev | Lance l'application en environnement de développement | run:d | | ||||||
| | `run:dev` | Run app in development environment| `run:d` | | | run:logs | Affiche la sortie de journalisation pour les applications Flutter en cours d'exécution | run:l | | ||||||
| | `run:emu` | Run app in development with emulated environment| `run:e` | | | run:prod | Lance l'application en environnement de production | run:p | | ||||||
| | `run:logs` |Show log output for running Flutter apps| `run:l` | | | run:staging | Lance l'application en environnement de pré-production | run:s | | ||||||
| | `run:mock` |Run app in development environment with mocks| `run:m` | |  | ||||||
| | `run:prod` |Run app in production environment| `run:p` | |  | ||||||
| | `run:release` | Run app in production environment and in release mode| `run:r` | |  | ||||||
| | `run:staging` | Run app in staging environment| `run:s` | |  | ||||||
| 
 | 
 | ||||||
| ### Flavors | ### Parameters | ||||||
| 
 | 
 | ||||||
| | Flavor | Details | | You can pass flutter options to the build and run commands. | ||||||
| |-------|--------| |  | ||||||
| | Development | Use `--dart-define="dev_mode=<MODE>"` to choose between `mock` , `emulator` and `real` | |  | ||||||
| | Staging | With a green banner. Only `real` mode available (remote data sources) | |  | ||||||
| | Production | Only `real` mode available (remote data sources) | |  | ||||||
| 
 | 
 | ||||||
| > In `lib/core/flavors/flavor.dart` you can customize flavors. | ```sh | ||||||
|  | task run:staging -- -d chrome | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | > **Note** The `--` is required to pass options to the command. | ||||||
|  | |||||||
| @ -11,8 +11,8 @@ dart_code_metrics: | |||||||
|   metrics: |   metrics: | ||||||
|     cyclomatic-complexity: 20 |     cyclomatic-complexity: 20 | ||||||
|     maximum-nesting-level: 5 |     maximum-nesting-level: 5 | ||||||
|     number-of-parameters: 4 |     number-of-parameters: 5 | ||||||
|     source-lines-of-code: 50 |     source-lines-of-code: 250 | ||||||
|   metrics-exclude: |   metrics-exclude: | ||||||
|     - test/** |     - test/** | ||||||
|   rules: |   rules: | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ tasks: | |||||||
|     aliases: [a] |     aliases: [a] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Building Android APK...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Building Android APK...{{.COLOROFF}}" | ||||||
|       - flutter build lib/main_production apk --no-pub --no-shrink |       - flutter build apk --target=lib/main_production --no-pub --no-shrink | ||||||
|    |    | ||||||
|   ios: |   ios: | ||||||
|     desc: Building iOS IPA |     desc: Building iOS IPA | ||||||
| @ -35,4 +35,4 @@ tasks: | |||||||
|     aliases: [i] |     aliases: [i] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Building iOS IPA...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Building iOS IPA...{{.COLOROFF}}" | ||||||
|       - flutter build lib/main_production ipa --no-pub |       - flutter build ipa --target=lib/main_production --no-pub | ||||||
|  | |||||||
| @ -54,10 +54,3 @@ tasks: | |||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running build runner in watch mode...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Running build runner in watch mode...{{.COLOROFF}}" | ||||||
|       - flutter pub run build_runner watch |       - flutter pub run build_runner watch | ||||||
|    |  | ||||||
|   trapeze: |  | ||||||
|     desc: Running Trapeze config |  | ||||||
|     aliases: [t] |  | ||||||
|     cmds: |  | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running Trapeze config...{{.COLOROFF}}" |  | ||||||
|       - npx trapeze run trapeze.yaml --android-project android --ios-project ios |  | ||||||
|  | |||||||
| @ -16,44 +16,23 @@ tasks: | |||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Showing log output for running Flutter apps...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Showing log output for running Flutter apps...{{.COLOROFF}}" | ||||||
|       - flutter logs |       - flutter logs | ||||||
| 
 | 
 | ||||||
|   mock: |  | ||||||
|     desc: Run app in development environment with mocks |  | ||||||
|     aliases: [m] |  | ||||||
|     cmds: |  | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development/debug:mocks)...{{.COLOROFF}}" |  | ||||||
|       - flutter run --target lib/main_development.dart --dart-define="dev_mode=mock" |  | ||||||
| 
 |  | ||||||
|   emu: |  | ||||||
|     desc: Run app in development with emulated environment |  | ||||||
|     aliases: [e] |  | ||||||
|     cmds: |  | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development/debug:emulator)...{{.COLOROFF}}" |  | ||||||
|       - flutter run --target lib/main_development.dart --dart-define="dev_mode=emulator" |  | ||||||
| 
 |  | ||||||
|   dev: |   dev: | ||||||
|     desc: Run app in development environment |     desc: Run app in development environment | ||||||
|     aliases: [d] |     aliases: [d] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development/debug:real)...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development)...{{.COLOROFF}}" | ||||||
|       - flutter run --target lib/main_development.dart --dart-define="dev_mode=real" |       - flutter run --target lib/main_development.dart --dart-define-from-file=config.json {{.CLI_ARGS}} | ||||||
| 
 | 
 | ||||||
|   staging: |   staging: | ||||||
|     desc: Run app in staging environment |     desc: Run app in staging environment | ||||||
|     aliases: [s] |     aliases: [s] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (staging/debug)...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (staging)...{{.COLOROFF}}" | ||||||
|       - flutter run --target lib/main_staging.dart |       - flutter run --target lib/main_staging.dart --dart-define-from-file=config.json {{.CLI_ARGS}} | ||||||
| 
 | 
 | ||||||
|   prod: |   prod: | ||||||
|     desc: Run app in production environment |     desc: Run app in production environment | ||||||
|     aliases: [p] |     aliases: [p] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (production/debug)...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (production)...{{.COLOROFF}}" | ||||||
|       - flutter run --target lib/main_production.dart |       - flutter run --target lib/main_production.dart --dart-define-from-file=config.json {{.CLI_ARGS}} | ||||||
| 
 |  | ||||||
|   release: |  | ||||||
|     desc: Run app in production environment and in release mode |  | ||||||
|     aliases: [r] |  | ||||||
|     cmds: |  | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (production/release)...{{.COLOROFF}}" |  | ||||||
|       - flutter run --target lib/main_production.dart --release |  | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								apps/wyatt_app_template/starting_template/config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								apps/wyatt_app_template/starting_template/config.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | { | ||||||
|  |   "FIREBASE_EMULATOR_CLOUD_FUNCTION_PORT": 5001, | ||||||
|  |   "FIREBASE_EMULATOR_FIRESTORE_PORT": 8080, | ||||||
|  |   "FIREBASE_EMULATOR_AUTH_PORT": 9099, | ||||||
|  |   "FIREBASE_EMULATOR_STORAGE_PORT": 919911, | ||||||
|  |   "FIREBASE_EMULATOR_HOST": "localhost", | ||||||
|  |   "DEV_MODE": "local" | ||||||
|  | } | ||||||
| @ -7,12 +7,11 @@ import 'package:starting_template/core/flavors/flavor.dart'; | |||||||
| import 'package:starting_template/core/utils/app_bloc_observer.dart'; | import 'package:starting_template/core/utils/app_bloc_observer.dart'; | ||||||
| 
 | 
 | ||||||
| Future<void> bootstrap(FutureOr<Widget> Function() builder) async { | Future<void> bootstrap(FutureOr<Widget> Function() builder) async { | ||||||
|   final widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); |   WidgetsFlutterBinding.ensureInitialized(); | ||||||
|   // FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); |  | ||||||
| 
 | 
 | ||||||
|   Bloc.observer = AppBlocObserver(); |   Bloc.observer = AppBlocObserver(); | ||||||
| 
 | 
 | ||||||
|   debugPrint('Flavor: ${Flavor.get()}'); |   debugPrint('${Flavor.instance}'); | ||||||
| 
 | 
 | ||||||
|   await GetItInitializer.init(); |   await GetItInitializer.init(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,12 +3,12 @@ | |||||||
| /// If you don't use Firebase, it can be safely deleted. | /// If you don't use Firebase, it can be safely deleted. | ||||||
| abstract class Emulator { | abstract class Emulator { | ||||||
|   static const String firebaseCloudFunctionEnvKey = |   static const String firebaseCloudFunctionEnvKey = | ||||||
|       'EMULATOR_FIREBASE_CLOUD_FUNCTION_PORT'; |       'FIREBASE_EMULATOR_CLOUD_FUNCTION_PORT'; | ||||||
|   static const String firebaseFirestoreEnvKey = |   static const String firebaseFirestoreEnvKey = | ||||||
|       'EMULATOR_FIREBASE_FIRESTORE_PORT'; |       'FIREBASE_EMULATOR_FIRESTORE_PORT'; | ||||||
|   static const String firebaseAuthEnvKey = 'EMULATOR_FIREBASE_AUTH_PORT'; |   static const String firebaseAuthEnvKey = 'FIREBASE_EMULATOR_AUTH_PORT'; | ||||||
|   static const String firebaseStorageEnvKey = 'EMULATOR_FIREBASE_STORAGE_PORT'; |   static const String firebaseStorageEnvKey = 'FIREBASE_EMULATOR_STORAGE_PORT'; | ||||||
|   static const String hostEnvKey = 'EMULATOR_HOST'; |   static const String hostEnvKey = 'FIREBASE_EMULATOR_HOST'; | ||||||
| 
 | 
 | ||||||
|   static const int defaultFirebaseCloudFunctionPort = 5001; |   static const int defaultFirebaseCloudFunctionPort = 5001; | ||||||
|   static const int defaultFirebaseFirestorePort = 8080; |   static const int defaultFirebaseFirestorePort = 8080; | ||||||
|  | |||||||
| @ -1,38 +1,50 @@ | |||||||
| import 'dart:async'; | import 'dart:async'; | ||||||
| 
 | 
 | ||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:get_it/get_it.dart'; | import 'package:get_it/get_it.dart'; | ||||||
| import 'package:starting_template/core/enums/dev_mode.dart'; | import 'package:starting_template/core/enums/dev_mode.dart'; | ||||||
| import 'package:starting_template/core/flavors/flavor.dart'; | import 'package:starting_template/core/flavors/flavor.dart'; | ||||||
| import 'package:starting_template/data/data_sources/local/counter_data_source_impl.dart'; | import 'package:starting_template/core/utils/firebase_emulator.dart'; | ||||||
| import 'package:starting_template/domain/data_sources/local/counter_data_source.dart'; |  | ||||||
| 
 | 
 | ||||||
| final getIt = GetIt.I; | final getIt = GetIt.I; | ||||||
| 
 | 
 | ||||||
| /// Service and Data Source locator | /// Service and Data Source locator | ||||||
| abstract class GetItInitializer { | abstract class GetItInitializer { | ||||||
|   static FutureOr<void> _initCommon() async { |   static FutureOr<void> _initCommon() async { | ||||||
|     // Initialize common sources/services |     // TODO(wyatt): Initialize common sources/services | ||||||
|     getIt.registerLazySingleton<CounterDataSource>( |  | ||||||
|       CounterDataSourceImpl.new, |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static FutureOr<void> _initMocks() async { |   static FutureOr<void> _initMock() async { | ||||||
|     // Initialize mocked sources/services. |     // TODO(wyatt): Initialize mocked sources/services. | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static FutureOr<void> _initLocal() async { | ||||||
|  |     // TODO(wyatt): Initialize local sources/services. | ||||||
|  |     final emulator = FirebaseEmulator.fromEnv(); | ||||||
|  |     debugPrint('Firebase Emulator: $emulator'); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static FutureOr<void> _initReal() async { |   static FutureOr<void> _initReal() async { | ||||||
|     // Initialize real sources/services |     // TODO(wyatt): Initialize real sources/services | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static FutureOr<void> init() async { |   static FutureOr<void> init() async { | ||||||
|  |     // Initialize common sources/services | ||||||
|     await _initCommon(); |     await _initCommon(); | ||||||
|     final flavor = Flavor.get(); |  | ||||||
| 
 | 
 | ||||||
|     if (flavor.devMode == DevMode.mock) { |     // Initialize sources/services based on flavor | ||||||
|       await _initMocks(); |     switch (Flavor.instance.devMode) { | ||||||
|     } else { |       case DevMode.mock: | ||||||
|       await _initReal(); |         await _initMock(); | ||||||
|  |         break; | ||||||
|  |       case DevMode.local: | ||||||
|  |         await _initLocal(); | ||||||
|  |         break; | ||||||
|  |       case DevMode.real: | ||||||
|  |         await _initReal(); | ||||||
|  |         break; | ||||||
|  |       case null: | ||||||
|  |         throw Exception('DevMode not initialized!'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await getIt.allReady(); |     await getIt.allReady(); | ||||||
|  | |||||||
| @ -0,0 +1,31 @@ | |||||||
|  | enum BuildMode { | ||||||
|  |   /// Debug build mode. Pass `--debug` to `flutter run` or `flutter build` to | ||||||
|  |   /// use this mode. | ||||||
|  |   debug, | ||||||
|  | 
 | ||||||
|  |   /// Release build mode. Pass `--profile` to `flutter run` or `flutter build` | ||||||
|  |   /// to use this mode. | ||||||
|  |   profile, | ||||||
|  | 
 | ||||||
|  |   /// Release build mode. Pass `--release` to `flutter run` or `flutter build` | ||||||
|  |   /// to use this mode. | ||||||
|  |   release; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => name; | ||||||
|  | 
 | ||||||
|  |   /// Tries to parse String and returns mode. Fallback is returned if there | ||||||
|  |   /// is an error during parsing. | ||||||
|  |   static BuildMode fromString( | ||||||
|  |     String? mode, { | ||||||
|  |     BuildMode fallback = BuildMode.debug, | ||||||
|  |   }) { | ||||||
|  |     for (final m in values) { | ||||||
|  |       if (m.name == mode) { | ||||||
|  |         return m; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return fallback; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,6 +1,11 @@ | |||||||
| enum DevMode { | enum DevMode { | ||||||
|  |   /// Mocked data sources and services | ||||||
|   mock, |   mock, | ||||||
|   emulator, | 
 | ||||||
|  |   /// Local data sources and services, like local database, or firebase emulator | ||||||
|  |   local, | ||||||
|  | 
 | ||||||
|  |   /// Real data sources and services, like firebase or other cloud services | ||||||
|   real; |   real; | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|  | |||||||
| @ -0,0 +1,26 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | enum PageProtection { | ||||||
|  |   /// The page can be accessed without authentication. | ||||||
|  |   public, | ||||||
|  | 
 | ||||||
|  |   /// The page can only be accessed with authentication. | ||||||
|  |   protected, | ||||||
|  | 
 | ||||||
|  |   /// The page protection is unknown, and the default one should be used. | ||||||
|  |   none, | ||||||
|  | } | ||||||
| @ -0,0 +1,53 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:go_router/go_router.dart'; | ||||||
|  | import 'package:starting_template/core/enums/page_protection.dart'; | ||||||
|  | 
 | ||||||
|  | /// Defines if a GoRoute is public or not. | ||||||
|  | /// | ||||||
|  | /// By default, all routes are in the [PageProtection.none] state. | ||||||
|  | extension GoRouteGuard on GoRoute { | ||||||
|  |   static final _guard = Expando<PageProtection>(); | ||||||
|  | 
 | ||||||
|  |   /// Returns `true` if the route is public. | ||||||
|  |   bool get isPublic => _guard[this] == PageProtection.public; | ||||||
|  | 
 | ||||||
|  |   /// Returns `true` if the route is protected. | ||||||
|  |   bool get isProtected => _guard[this] == PageProtection.protected; | ||||||
|  | 
 | ||||||
|  |   /// Returns `true` if the route is neither public nor protected. | ||||||
|  |   /// This is the default state. | ||||||
|  |   bool get isNone => _guard[this] == PageProtection.none; | ||||||
|  | 
 | ||||||
|  |   /// Sets the route to be public. | ||||||
|  |   /// This is useful for routes that should be accessible | ||||||
|  |   /// without authentication. | ||||||
|  |   /// ```dart | ||||||
|  |   /// GoRoute( | ||||||
|  |   ///  path: '/sign_in', | ||||||
|  |   ///  ... | ||||||
|  |   /// )..setPublic(), | ||||||
|  |   /// ``` | ||||||
|  |   void setPublic() => _guard[this] = PageProtection.public; | ||||||
|  | 
 | ||||||
|  |   /// Sets the route to be protected. | ||||||
|  |   /// This is useful for routes that should only be accessible | ||||||
|  |   /// with authentication. | ||||||
|  |   void setProtected() => _guard[this] = PageProtection.protected; | ||||||
|  | 
 | ||||||
|  |   PageProtection get guard => _guard[this] ?? PageProtection.none; | ||||||
|  | } | ||||||
| @ -1,23 +1,38 @@ | |||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:starting_template/core/enums/build_mode.dart'; | ||||||
| import 'package:starting_template/core/enums/dev_mode.dart'; | import 'package:starting_template/core/enums/dev_mode.dart'; | ||||||
| 
 | 
 | ||||||
| abstract class Flavor { | class Flavor { | ||||||
|   Flavor._({ |   Flavor._({ | ||||||
|     this.banner, |     this.flavorName, | ||||||
|     this.bannerColor = Colors.red, |     this.bannerColor, | ||||||
|     this.devMode, |  | ||||||
|   }) { |   }) { | ||||||
|  |     // Determine build mode | ||||||
|  |     buildMode = kReleaseMode | ||||||
|  |         ? BuildMode.release | ||||||
|  |         : kProfileMode | ||||||
|  |             ? BuildMode.profile | ||||||
|  |             : BuildMode.debug; | ||||||
|  | 
 | ||||||
|  |     // Retrieve dev mode, fallback to mock | ||||||
|  |     devMode = DevMode.fromString( | ||||||
|  |       const String.fromEnvironment('DEV_MODE', defaultValue: 'mock'), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|     _instance = this; |     _instance = this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static Flavor? _instance; |   static Flavor? _instance; | ||||||
| 
 | 
 | ||||||
|   final String? banner; |   final String? flavorName; | ||||||
|   final Color bannerColor; |   final Color? bannerColor; | ||||||
|   final DevMode? devMode; | 
 | ||||||
|  |   late final DevMode? devMode; | ||||||
|  |   late final BuildMode? buildMode; | ||||||
| 
 | 
 | ||||||
|   /// Returns [Flavor] instance. |   /// Returns [Flavor] instance. | ||||||
|   static Flavor get() { |   static Flavor get instance { | ||||||
|     if (_instance == null) { |     if (_instance == null) { | ||||||
|       throw Exception('Flavor not initialized!'); |       throw Exception('Flavor not initialized!'); | ||||||
|     } |     } | ||||||
| @ -25,33 +40,26 @@ abstract class Flavor { | |||||||
|     return _instance!; |     return _instance!; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   String get name => flavorName ?? 'Unknown'; | ||||||
|  |   Color get color => bannerColor ?? Colors.grey; | ||||||
|  | 
 | ||||||
|  |   static bool shouldShowBanner() => instance.buildMode != BuildMode.release; | ||||||
|  | 
 | ||||||
|   @override |   @override | ||||||
|   String toString() => runtimeType.toString().replaceAll('Flavor', ''); |   String toString() => | ||||||
|  |       'Flavor: $flavorName, DevMode: $devMode, BuildMode: $buildMode'; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class DevelopmentFlavor extends Flavor { | class DevelopmentFlavor extends Flavor { | ||||||
|   factory DevelopmentFlavor() { |   DevelopmentFlavor() | ||||||
|     const modeString = String.fromEnvironment('dev_mode', defaultValue: 'mock'); |       : super._(flavorName: 'Development', bannerColor: Colors.red); | ||||||
|     final mode = DevMode.fromString(modeString); |  | ||||||
| 
 |  | ||||||
|     return DevelopmentFlavor._(devMode: mode); |  | ||||||
|   } |  | ||||||
|   DevelopmentFlavor._({ |  | ||||||
|     required DevMode devMode, |  | ||||||
|   }) : super._( |  | ||||||
|           banner: 'Dev', |  | ||||||
|           devMode: devMode, |  | ||||||
|         ); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class StagingFlavor extends Flavor { | class StagingFlavor extends Flavor { | ||||||
|   StagingFlavor() |   StagingFlavor() : super._(flavorName: 'Staging', bannerColor: Colors.orange); | ||||||
|       : super._( |  | ||||||
|           banner: 'Staging', |  | ||||||
|           bannerColor: Colors.green, |  | ||||||
|         ); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class ProductionFlavor extends Flavor { | class ProductionFlavor extends Flavor { | ||||||
|   ProductionFlavor() : super._(); |   ProductionFlavor() | ||||||
|  |       : super._(flavorName: 'Production', bannerColor: Colors.green); | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,40 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'dart:async'; | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
|  | 
 | ||||||
|  | /// {@template go_router_refresh_stream} | ||||||
|  | /// A [ChangeNotifier] that notifies its listeners when a stream emits a value. | ||||||
|  | /// {@endtemplate} | ||||||
|  | class GoRouterRefreshStream extends ChangeNotifier { | ||||||
|  |   /// {@macro go_router_refresh_stream} | ||||||
|  |   GoRouterRefreshStream(Stream<dynamic> stream) { | ||||||
|  |     notifyListeners(); | ||||||
|  |     _subscription = stream.asBroadcastStream().listen( | ||||||
|  |           (dynamic _) => notifyListeners(), | ||||||
|  |         ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   late final StreamSubscription<dynamic> _subscription; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     _subscription.cancel(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,6 +1,8 @@ | |||||||
| import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||||
| import 'package:go_router/go_router.dart'; | import 'package:go_router/go_router.dart'; | ||||||
| import 'package:starting_template/presentation/features/counter/counter.dart'; | import 'package:starting_template/core/enums/page_protection.dart'; | ||||||
|  | import 'package:starting_template/core/extensions/go_route_extension.dart'; | ||||||
|  | import 'package:starting_template/core/routes/go_router_refresh_stream.dart'; | ||||||
| import 'package:starting_template/presentation/features/home/home.dart'; | import 'package:starting_template/presentation/features/home/home.dart'; | ||||||
| 
 | 
 | ||||||
| abstract class AppRouter { | abstract class AppRouter { | ||||||
| @ -10,10 +12,7 @@ abstract class AppRouter { | |||||||
|     GoRouterState state, |     GoRouterState state, | ||||||
|     Widget child, |     Widget child, | ||||||
|   ) => |   ) => | ||||||
|       CupertinoPage<void>( |       CupertinoPage<void>(key: state.pageKey, child: child); | ||||||
|         key: state.pageKey, |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 | 
 | ||||||
|   /// Disable transition animation |   /// Disable transition animation | ||||||
|   static Page<void> noTransition( |   static Page<void> noTransition( | ||||||
| @ -21,23 +20,7 @@ abstract class AppRouter { | |||||||
|     GoRouterState state, |     GoRouterState state, | ||||||
|     Widget child, |     Widget child, | ||||||
|   ) => |   ) => | ||||||
|       CustomTransitionPage<void>( |       NoTransitionPage(key: state.pageKey, child: child); | ||||||
|         key: state.pageKey, |  | ||||||
|         transitionsBuilder: (_, __, ___, child) => child, |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|   /// Defines public routes (no authentication needed). |  | ||||||
|   /// |  | ||||||
|   /// Example: |  | ||||||
|   /// ```dart |  | ||||||
|   /// static final publicRoutes = [ |  | ||||||
|   /// '/', |  | ||||||
|   /// '/sign_in', |  | ||||||
|   /// '/sign_up', |  | ||||||
|   /// ]; |  | ||||||
|   /// ``` |  | ||||||
|   static final List<String> publicRoutes = []; |  | ||||||
| 
 | 
 | ||||||
|   /// Defines GoRoute routes. |   /// Defines GoRoute routes. | ||||||
|   static final List<GoRoute> routes = [ |   static final List<GoRoute> routes = [ | ||||||
| @ -46,20 +29,32 @@ abstract class AppRouter { | |||||||
|       name: Home.pageName, |       name: Home.pageName, | ||||||
|       pageBuilder: (context, state) => |       pageBuilder: (context, state) => | ||||||
|           defaultTransition(context, state, const Home()), |           defaultTransition(context, state, const Home()), | ||||||
|     ), |     )..setPublic(), | ||||||
|     GoRoute( |  | ||||||
|       path: '/counter', |  | ||||||
|       name: Counter.pageName, |  | ||||||
|       pageBuilder: (context, state) => |  | ||||||
|           defaultTransition(context, state, const Counter()), |  | ||||||
|     ), |  | ||||||
|   ]; |   ]; | ||||||
| 
 | 
 | ||||||
|   /// Router |   /// Router | ||||||
|   static GoRouter router = GoRouter( |   static GoRouter routerOf(BuildContext context) => GoRouter( | ||||||
|     initialLocation: '/', |         initialLocation: '/', | ||||||
|     routes: AppRouter.routes, |         routes: AppRouter.routes, | ||||||
|     debugLogDiagnostics: true, |         debugLogDiagnostics: true, | ||||||
|     redirect: (context, state) => null, |         // TODO(wyatt): Add authentication logic | ||||||
|   ); |         redirect: (context, state) { | ||||||
|  |           /// Define the default guard | ||||||
|  |           /// This is the guard that will be used if the route | ||||||
|  |           /// does not have a guard set. (It is set to [PageProtection.none]) | ||||||
|  |           const defaultGuard = PageProtection.protected; | ||||||
|  | 
 | ||||||
|  |           // Compute current route | ||||||
|  |           // Compute current route | ||||||
|  |           final currentRoute = AppRouter.routes.firstWhere( | ||||||
|  |             (route) => route.path == state.location, | ||||||
|  |           ); | ||||||
|  | 
 | ||||||
|  |           // Get the guard of the current route | ||||||
|  |           final guard = currentRoute.guard; | ||||||
|  | 
 | ||||||
|  |           return null; | ||||||
|  |         }, | ||||||
|  |         refreshListenable: GoRouterRefreshStream(const Stream.empty()), | ||||||
|  |       ); | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,61 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:starting_template/core/constants/emulator.dart'; | ||||||
|  | 
 | ||||||
|  | class FirebaseEmulator { | ||||||
|  |   const FirebaseEmulator._({ | ||||||
|  |     required this.cloudFunctionPort, | ||||||
|  |     required this.firestorePort, | ||||||
|  |     required this.authPort, | ||||||
|  |     required this.storagePort, | ||||||
|  |     required this.host, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   factory FirebaseEmulator.fromEnv() => const FirebaseEmulator._( | ||||||
|  |         cloudFunctionPort: int.fromEnvironment( | ||||||
|  |           Emulator.firebaseCloudFunctionEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultFirebaseCloudFunctionPort, | ||||||
|  |         ), | ||||||
|  |         firestorePort: int.fromEnvironment( | ||||||
|  |           Emulator.firebaseFirestoreEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultFirebaseFirestorePort, | ||||||
|  |         ), | ||||||
|  |         authPort: int.fromEnvironment( | ||||||
|  |           Emulator.firebaseAuthEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultFirebaseAuthPort, | ||||||
|  |         ), | ||||||
|  |         storagePort: int.fromEnvironment( | ||||||
|  |           Emulator.firebaseStorageEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultFirebaseStoragePort, | ||||||
|  |         ), | ||||||
|  |         host: String.fromEnvironment( | ||||||
|  |           Emulator.hostEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultHost, | ||||||
|  |         ), | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |   final int cloudFunctionPort; | ||||||
|  |   final int firestorePort; | ||||||
|  |   final int authPort; | ||||||
|  |   final int storagePort; | ||||||
|  |   final String host; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => 'FirebaseEmulator(cloudFunctionPort: ' | ||||||
|  |       '$cloudFunctionPort, firestorePort: $firestorePort, authPort: $authPort, ' | ||||||
|  |       'storagePort: $storagePort, host: $host)'; | ||||||
|  | } | ||||||
| @ -105,11 +105,6 @@ class _$_IntegerModel implements _IntegerModel { | |||||||
|   @override |   @override | ||||||
|   final int value; |   final int value; | ||||||
| 
 | 
 | ||||||
|   @override |  | ||||||
|   String toString() { |  | ||||||
|     return 'IntegerModel(value: $value)'; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |   @override | ||||||
|   bool operator ==(dynamic other) { |   bool operator ==(dynamic other) { | ||||||
|     return identical(this, other) || |     return identical(this, other) || | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
| 
 | 
 | ||||||
| // coverage:ignore-file | // coverage:ignore-file | ||||||
| // ignore_for_file: type=lint | // ignore_for_file: type=lint | ||||||
| // ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal | // ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use | ||||||
| 
 | 
 | ||||||
| import 'package:flutter/widgets.dart'; | import 'package:flutter/widgets.dart'; | ||||||
| 
 | 
 | ||||||
| @ -84,7 +84,16 @@ class AssetGenImage { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ImageProvider provider() => AssetImage(_assetName); |   ImageProvider provider({ | ||||||
|  |     AssetBundle? bundle, | ||||||
|  |     String? package, | ||||||
|  |   }) { | ||||||
|  |     return AssetImage( | ||||||
|  |       _assetName, | ||||||
|  |       bundle: bundle, | ||||||
|  |       package: package, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   String get path => _assetName; |   String get path => _assetName; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
| 
 | 
 | ||||||
| // coverage:ignore-file | // coverage:ignore-file | ||||||
| // ignore_for_file: type=lint | // ignore_for_file: type=lint | ||||||
| // ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal | // ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use | ||||||
| 
 | 
 | ||||||
| import 'package:flutter/painting.dart'; | import 'package:flutter/painting.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import 'package:starting_template/core/flavors/flavor.dart'; | |||||||
| import 'package:starting_template/presentation/features/app/app.dart'; | import 'package:starting_template/presentation/features/app/app.dart'; | ||||||
| 
 | 
 | ||||||
| void main(List<String> args) { | void main(List<String> args) { | ||||||
|   // Define environment |   // Define flavor | ||||||
|   DevelopmentFlavor(); |   DevelopmentFlavor(); | ||||||
| 
 | 
 | ||||||
|   // Initialize environment and variables |   // Initialize environment and variables | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import 'package:starting_template/core/flavors/flavor.dart'; | |||||||
| import 'package:starting_template/presentation/features/app/app.dart'; | import 'package:starting_template/presentation/features/app/app.dart'; | ||||||
| 
 | 
 | ||||||
| void main(List<String> args) { | void main(List<String> args) { | ||||||
|   // Define environment |   // Define flavor | ||||||
|   ProductionFlavor(); |   ProductionFlavor(); | ||||||
| 
 | 
 | ||||||
|   // Initialize environment and variables |   // Initialize environment and variables | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import 'package:starting_template/core/flavors/flavor.dart'; | |||||||
| import 'package:starting_template/presentation/features/app/app.dart'; | import 'package:starting_template/presentation/features/app/app.dart'; | ||||||
| 
 | 
 | ||||||
| void main(List<String> args) { | void main(List<String> args) { | ||||||
|   // Define environment |   // Define flavor | ||||||
|   StagingFlavor(); |   StagingFlavor(); | ||||||
| 
 | 
 | ||||||
|   // Initialize environment and variables |   // Initialize environment and variables | ||||||
|  | |||||||
| @ -1,63 +1,47 @@ | |||||||
| import 'package:flutter/foundation.dart'; |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| import 'package:flutter_localizations/flutter_localizations.dart'; | import 'package:flutter_localizations/flutter_localizations.dart'; | ||||||
| import 'package:starting_template/core/dependency_injection/get_it.dart'; | import 'package:starting_template/core/dependency_injection/get_it.dart'; | ||||||
| import 'package:starting_template/core/flavors/flavor.dart'; |  | ||||||
| import 'package:starting_template/core/routes/router.dart'; | import 'package:starting_template/core/routes/router.dart'; | ||||||
| import 'package:starting_template/data/repositories/counter_repository_impl.dart'; | import 'package:starting_template/data/repositories/counter_repository_impl.dart'; | ||||||
| import 'package:starting_template/domain/repositories/counter_repository.dart'; | import 'package:starting_template/domain/repositories/counter_repository.dart'; | ||||||
| import 'package:starting_template/gen/app_localizations.dart'; | import 'package:starting_template/gen/app_localizations.dart'; | ||||||
| import 'package:starting_template/presentation/features/counter/blocs/counter_bloc/counter_bloc.dart'; | import 'package:starting_template/presentation/features/counter/blocs/counter_bloc/counter_bloc.dart'; | ||||||
|  | import 'package:starting_template/presentation/shared/widgets/flavor_banner.dart'; | ||||||
| import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | ||||||
| 
 | 
 | ||||||
| class App extends StatelessWidget { | class App extends StatelessWidget { | ||||||
|   const App({super.key}); |   const App({super.key}); | ||||||
| 
 | 
 | ||||||
|   Widget _flavorBanner(Widget child) { |  | ||||||
|     final flavor = Flavor.get(); |  | ||||||
|     if (flavor.banner != null && !kReleaseMode) { |  | ||||||
|       return Directionality( |  | ||||||
|         textDirection: TextDirection.ltr, |  | ||||||
|         child: Banner( |  | ||||||
|           location: BannerLocation.topEnd, |  | ||||||
|           message: flavor.banner!, |  | ||||||
|           color: flavor.bannerColor, |  | ||||||
|           child: child, |  | ||||||
|         ), |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return child; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) => MultiProvider( |   Widget build(BuildContext context) => MultiProvider( | ||||||
|       repositoryProviders: [ |         repositoryProviders: [ | ||||||
|         RepositoryProvider<CounterRepository>( |           RepositoryProvider<CounterRepository>( | ||||||
|           create: (_) => CounterRepositoryImpl(counterDataSource: getIt()), |             create: (_) => CounterRepositoryImpl(counterDataSource: getIt()), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |         blocProviders: [ | ||||||
|  |           BlocProvider<CounterBloc>( | ||||||
|  |             create: (_) => CounterBloc(), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |         child: FlavorBanner( | ||||||
|  |           child: MaterialApp.router( | ||||||
|  |             title: 'Display Name', | ||||||
|  |             debugShowCheckedModeBanner: false, | ||||||
|  |             routerDelegate: AppRouter.routerOf(context).routerDelegate, | ||||||
|  |             routeInformationParser: | ||||||
|  |                 AppRouter.routerOf(context).routeInformationParser, | ||||||
|  |             routeInformationProvider: | ||||||
|  |                 AppRouter.routerOf(context).routeInformationProvider, | ||||||
|  |             localizationsDelegates: const [ | ||||||
|  |               AppLocalizations.delegate, | ||||||
|  |               GlobalMaterialLocalizations.delegate, | ||||||
|  |               GlobalWidgetsLocalizations.delegate, | ||||||
|  |               GlobalCupertinoLocalizations.delegate, | ||||||
|  |             ], | ||||||
|  |             supportedLocales: AppLocalizations.supportedLocales, | ||||||
|  |           ), | ||||||
|         ), |         ), | ||||||
|       ], |       ); | ||||||
|       blocProviders: [ |  | ||||||
|         BlocProvider<CounterBloc>( |  | ||||||
|           create: (_) => CounterBloc(), |  | ||||||
|         ), |  | ||||||
|       ], |  | ||||||
|       child: _flavorBanner( |  | ||||||
|         MaterialApp.router( |  | ||||||
|           title: 'Display Name', |  | ||||||
|           debugShowCheckedModeBanner: false, |  | ||||||
|           routerDelegate: AppRouter.router.routerDelegate, |  | ||||||
|           routeInformationParser: AppRouter.router.routeInformationParser, |  | ||||||
|           routeInformationProvider: AppRouter.router.routeInformationProvider, |  | ||||||
|           localizationsDelegates: const [ |  | ||||||
|             AppLocalizations.delegate, |  | ||||||
|             GlobalMaterialLocalizations.delegate, |  | ||||||
|             GlobalWidgetsLocalizations.delegate, |  | ||||||
|             GlobalCupertinoLocalizations.delegate, |  | ||||||
|           ], |  | ||||||
|           supportedLocales: AppLocalizations.supportedLocales, |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,73 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:starting_template/core/flavors/flavor.dart'; | ||||||
|  | 
 | ||||||
|  | /// {@template flavor_banner} | ||||||
|  | /// A banner that displays the current flavor. | ||||||
|  | /// This is useful for quickly identifying which flavor is currently running. | ||||||
|  | /// | ||||||
|  | /// When [Flavor.shouldShowBanner] is `false`, this widget will return [child]. | ||||||
|  | /// You can also override this behavior by setting [visible] to `true`. | ||||||
|  | /// | ||||||
|  | /// Wrap your [MaterialApp] with this widget to display the banner. | ||||||
|  | /// | ||||||
|  | /// Example: | ||||||
|  | /// | ||||||
|  | /// ```dart | ||||||
|  | /// FlavorBanner( | ||||||
|  | ///  visible: true, // or null to use Flavor.shouldShowBanner() | ||||||
|  | ///  child: const MaterialApp( | ||||||
|  | ///   title: 'Starting Template', | ||||||
|  | ///   ... | ||||||
|  | ///  ), | ||||||
|  | /// ); | ||||||
|  | /// ``` | ||||||
|  | /// {@endtemplate} | ||||||
|  | class FlavorBanner extends StatelessWidget { | ||||||
|  |   const FlavorBanner({ | ||||||
|  |     this.child, | ||||||
|  |     this.visible, | ||||||
|  |     super.key, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   final Widget? child; | ||||||
|  | 
 | ||||||
|  |   /// Defaults to [Flavor.shouldShowBanner]. | ||||||
|  |   final bool? visible; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     final visible = this.visible ?? Flavor.shouldShowBanner(); | ||||||
|  | 
 | ||||||
|  |     if (!visible) { | ||||||
|  |       return child ?? const SizedBox.shrink(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     final flavor = Flavor.instance; | ||||||
|  | 
 | ||||||
|  |     return Directionality( | ||||||
|  |       textDirection: TextDirection.ltr, | ||||||
|  |       child: Banner( | ||||||
|  |         location: BannerLocation.topEnd, | ||||||
|  |         message: flavor.name, | ||||||
|  |         color: flavor.color, | ||||||
|  |         child: child, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										6524
									
								
								apps/wyatt_app_template/starting_template/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6524
									
								
								apps/wyatt_app_template/starting_template/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,5 +0,0 @@ | |||||||
| { |  | ||||||
|   "dependencies": { |  | ||||||
|     "@trapezedev/configure": "^7.0.5" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,69 +1,63 @@ | |||||||
| name: starting_template | name: starting_template | ||||||
| description: A short project description |  | ||||||
| 
 |  | ||||||
| publish_to: "none" |  | ||||||
| 
 |  | ||||||
| version: 1.0.0+1 | version: 1.0.0+1 | ||||||
| 
 | publish_to: none | ||||||
|  | description: A short project description | ||||||
| environment:  | environment:  | ||||||
|   sdk: ">=2.18.0 <3.0.0" |   sdk: '>=2.18.0 <3.0.0' | ||||||
|   flutter: ">=3.0.0" |   flutter: '>=3.0.0' | ||||||
| 
 |  | ||||||
| dependencies:  | dependencies:  | ||||||
|   flutter: { sdk: flutter } |  | ||||||
|   flutter_localizations: { sdk: flutter } |  | ||||||
|   intl: ^0.17.0 |  | ||||||
|   go_router: ^6.0.1 |  | ||||||
|   equatable: ^2.0.5 |  | ||||||
|   freezed_annotation: ^2.2.0 |  | ||||||
|   json_annotation: ^4.8.0 |  | ||||||
|   cupertino_icons: ^1.0.5 |   cupertino_icons: ^1.0.5 | ||||||
|   get_it: ^7.2.0 |   equatable: ^2.0.5 | ||||||
|   flutter_dotenv: ^5.0.2 |  | ||||||
|   gap: ^2.0.1 |  | ||||||
|   flutter_bloc: ^8.1.1 |   flutter_bloc: ^8.1.1 | ||||||
|  |   flutter_native_splash: ^2.2.15 | ||||||
|  |   freezed_annotation: ^2.2.0 | ||||||
|  |   gap: ^2.0.1 | ||||||
|  |   get_it: ^7.2.0 | ||||||
|  |   go_router: ^6.0.1 | ||||||
|  |   intl: ^0.17.0 | ||||||
|  |   json_annotation: ^4.8.0 | ||||||
|   url_launcher: ^6.1.7 |   url_launcher: ^6.1.7 | ||||||
|   uuid: ^3.0.7 |   uuid: ^3.0.7 | ||||||
|   flutter_native_splash: ^2.2.15 |   flutter:  | ||||||
|  |     sdk: flutter | ||||||
|  |   flutter_localizations:  | ||||||
|  |     sdk: flutter | ||||||
|   wyatt_architecture:  |   wyatt_architecture:  | ||||||
|  |     version: ^0.2.0 | ||||||
|     hosted:  |     hosted:  | ||||||
|       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |  | ||||||
|       name: wyatt_architecture |       name: wyatt_architecture | ||||||
|     version: 0.1.0+1 |       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|   wyatt_bloc_helper:  |   wyatt_bloc_helper:  | ||||||
|  |     version: ^2.0.1 | ||||||
|     hosted:  |     hosted:  | ||||||
|       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |  | ||||||
|       name: wyatt_bloc_helper |       name: wyatt_bloc_helper | ||||||
|     version: 2.0.0 |  | ||||||
|   wyatt_type_utils: |  | ||||||
|     hosted: |  | ||||||
|       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|  |   wyatt_type_utils:  | ||||||
|  |     version: ^0.0.5 | ||||||
|  |     hosted:  | ||||||
|       name: wyatt_type_utils |       name: wyatt_type_utils | ||||||
|     version: 0.0.4 |       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
| 
 |  | ||||||
| dev_dependencies:  | dev_dependencies:  | ||||||
|   flutter_test: { sdk: flutter } |  | ||||||
|   dependency_validator: ^3.2.2 |  | ||||||
|   build_runner: ^2.3.3 |   build_runner: ^2.3.3 | ||||||
|  |   dart_code_metrics: ^5.4.0 | ||||||
|  |   dependency_validator: ^3.2.2 | ||||||
|   flutter_gen_runner: ^5.1.0+1 |   flutter_gen_runner: ^5.1.0+1 | ||||||
|  |   flutter_launcher_icons: ^0.11.0 | ||||||
|   freezed: ^2.3.2 |   freezed: ^2.3.2 | ||||||
|   json_serializable: ^6.6.0 |   json_serializable: ^6.6.0 | ||||||
|   flutter_launcher_icons: ^0.11.0 |   pubspec_dependency_sorter: ^1.0.3 | ||||||
|   dart_code_metrics: ^5.4.0 |  | ||||||
|   rename: ^2.1.1 |   rename: ^2.1.1 | ||||||
|  |   flutter_test:  | ||||||
|  |     sdk: flutter | ||||||
|   wyatt_analysis:  |   wyatt_analysis:  | ||||||
|  |     version: ^2.5.0 | ||||||
|     hosted:  |     hosted:  | ||||||
|       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |  | ||||||
|       name: wyatt_analysis |       name: wyatt_analysis | ||||||
|     version: 2.4.1 |       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
| 
 |  | ||||||
| flutter:  | flutter:  | ||||||
|   uses-material-design: true |  | ||||||
|   generate: true |  | ||||||
|   assets:  |   assets:  | ||||||
|     - .env |  | ||||||
|     - assets/images/ |     - assets/images/ | ||||||
| 
 |   uses-material-design: true | ||||||
| flutter_gen:  | flutter_gen:  | ||||||
|   output: lib/gen/ |   output: lib/gen/ | ||||||
|   integrations:  |   integrations:  | ||||||
| @ -74,17 +68,15 @@ flutter_gen: | |||||||
|   colors:  |   colors:  | ||||||
|     inputs:  |     inputs:  | ||||||
|       - assets/colors.xml |       - assets/colors.xml | ||||||
| 
 |  | ||||||
| flutter_icons:  | flutter_icons:  | ||||||
|   android: "launcher_icon" |   android: launcher_icon | ||||||
|  |   image_path: assets/images/wyatt_logo.jpeg | ||||||
|  |   adaptive_icon_background: '#FFFFFF' | ||||||
|   ios: true |   ios: true | ||||||
|   image_path: "assets/images/wyatt_logo.jpeg" |  | ||||||
|   adaptive_icon_background: "#FFFFFF" |  | ||||||
| 
 |  | ||||||
| flutter_native_splash:  | flutter_native_splash:  | ||||||
|   image: "assets/images/wyatt_logo.jpeg" |   image: assets/images/wyatt_logo.jpeg | ||||||
|   color: "#FFFFFF" |   color: '#FFFFFF' | ||||||
|   android: true |  | ||||||
|   ios: true |  | ||||||
|   android_gravity: fill |   android_gravity: fill | ||||||
|   ios_content_mode: scaleAspectFit |   ios_content_mode: scaleAspectFit | ||||||
|  |   android: true | ||||||
|  |   ios: true | ||||||
|  | |||||||
| @ -1,36 +0,0 @@ | |||||||
| vars: |  | ||||||
|   PACKAGE_NAME: |  | ||||||
|     default: starting_template |  | ||||||
|   BUNDLE_ID: |  | ||||||
|     default: io.wyattapp.start |  | ||||||
|   APP_NAME: |  | ||||||
|     default: Display Name |  | ||||||
| 
 |  | ||||||
| platforms: |  | ||||||
|   android: |  | ||||||
|     appName: $APP_NAME |  | ||||||
|     packageName: $BUNDLE_ID |  | ||||||
|     # Uncomment to add some permissions |  | ||||||
|     # manifest: |  | ||||||
|     #   - file: AndroidManifest.xml |  | ||||||
|     #     target: manifest/application |  | ||||||
|     #     inject: |  | ||||||
|     #       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |  | ||||||
|   ios: |  | ||||||
|     targets: |  | ||||||
|       Runner: |  | ||||||
|         bundleId: $BUNDLE_ID |  | ||||||
|         productName: $APP_NAME |  | ||||||
|         displayName: $APP_NAME |  | ||||||
|         entitlements: |  | ||||||
|           replace: true |  | ||||||
|           # Workaround for https://stackoverflow.com/questions/55167611/flutter-ios-app-submission-issue-warning-missing-push-notification-entitlement |  | ||||||
|           entries: |  | ||||||
|             - aps-environment: development |  | ||||||
|         # Uncomment to add some permissions |  | ||||||
|         # plist: |  | ||||||
|         #   - replace: true |  | ||||||
|         #     entries: |  | ||||||
|         #       - UISupportedInterfaceOrientations: |  | ||||||
|         #           - UIInterfaceOrientationPortrait |  | ||||||
| 
 |  | ||||||
| @ -6,54 +6,55 @@ | |||||||
| 
 | 
 | ||||||
| * Flutter <https://flutter.dev/> | * Flutter <https://flutter.dev/> | ||||||
| * Taskfile <https://taskfile.dev/> | * Taskfile <https://taskfile.dev/> | ||||||
| * Trapeze <https://trapeze.dev/> (with `npm install` thanks to `package.json`) |  | ||||||
| 
 | 
 | ||||||
| ### Configuration | ### Configuration | ||||||
| 
 | 
 | ||||||
| Create `.env` file with | At the build time, the app will read the environment variables from `config.json` file. | ||||||
| 
 | 
 | ||||||
| ```sh | The important variable is `DEV_MODE` which can be `mock` , `local` or `real` . | ||||||
| cp .env.example .env | 
 | ||||||
|  | ```json | ||||||
|  | { | ||||||
|  |   "DEV_MODE": "local" | ||||||
|  | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | > **Note** `local` can refer to a local server or a local emulator. | ||||||
|  | 
 | ||||||
| ### Taskfile | ### Taskfile | ||||||
| 
 | 
 | ||||||
| Available tasks: | Available tasks: | ||||||
| 
 | 
 | ||||||
| | Command | Description | Aliases | | | Commande | Description | Alias | | ||||||
| |----|-----|-----| | | --- | --- | --- | | ||||||
| | `clean` | Cleans the environment.| `cl` | | | clean | Nettoie l'environnement de travail | cl | | ||||||
| | `format` |Formats the code.| `fmt` | | | format | Formate le code | fmt | | ||||||
| | `help` |Help dialog.| `h, default` | | | help | Affiche la boîte de dialogue d'aide | h, default | | ||||||
| | `lint` |Lints the code.| `l` | | | lint | Vérifie la qualité du code | l | | ||||||
| | `start-emulators` | Start needed emulators.| `emu` | | | start-emulators | Démarre les émulateurs nécessaires | emu | | ||||||
| | `build:android` | Building Android APK| `build:a` | | | build:android | Construit le fichier APK pour Android | build:a | | ||||||
| | `build:ios` | Building iOS IPA| `build:i` | | | build:ios | Construit le fichier IPA pour iOS | build:i | | ||||||
| | `gen:build` | Running build runner| `gen:b` | | | gen:build | Exécute le générateur de build | gen:b | | ||||||
| | `gen:build-delete` |Running build runner with deletion of conflicting outputs| `gen:d` | | | gen:build-delete | Exécute le générateur de build et supprime les sorties en conflit | gen:d | | ||||||
| | `gen:clean` | Cleaning build runner| `gen:c` | | | gen:clean | Nettoie le générateur de build | gen:c | | ||||||
| | `gen:intl` |Generating internationalization file| `gen:i` | | | gen:intl | Génère un fichier d'internationalisation | gen:i | | ||||||
| | `gen:trapeze` | Running Trapeze config| `gen:t` | | | gen:watch | Exécute le générateur de build en mode surveillance | gen:w | | ||||||
| | `gen:watch` | Running build runner in watch mode| `gen:w` | | | pub:get | Obtient les dernières dépendances | pub:g | | ||||||
| | `pub:get` | Getting latest dependencies| `pub:g` | | | pub:outdated | Vérifie les dépendances obsolètes | pub:o | | ||||||
| | `pub:outdated` |Checking for outdated dependencies| `pub:o` | | | pub:upgrade | Met à jour les dépendances | pub:u | | ||||||
| | `pub:upgrade` | Upgrading dependencies| `pub:u` | | | pub:upgrade-major | Met à jour les dépendances majeures | pub:um | | ||||||
| | `pub:upgrade-major` | Upgrading dependencies| `pub:um` | | | pub:validate | Exécute le validateur de dépendances | pub:v | | ||||||
| | `pub:validate` |Running dependency validator| `pub:v` | | | run:dev | Lance l'application en environnement de développement | run:d | | ||||||
| | `run:dev` | Run app in development environment| `run:d` | | | run:logs | Affiche la sortie de journalisation pour les applications Flutter en cours d'exécution | run:l | | ||||||
| | `run:emu` | Run app in development with emulated environment| `run:e` | | | run:prod | Lance l'application en environnement de production | run:p | | ||||||
| | `run:logs` |Show log output for running Flutter apps| `run:l` | | | run:staging | Lance l'application en environnement de pré-production | run:s | | ||||||
| | `run:mock` |Run app in development environment with mocks| `run:m` | |  | ||||||
| | `run:prod` |Run app in production environment| `run:p` | |  | ||||||
| | `run:release` | Run app in production environment and in release mode| `run:r` | |  | ||||||
| | `run:staging` | Run app in staging environment| `run:s` | |  | ||||||
| 
 | 
 | ||||||
| ### Flavors | ### Parameters | ||||||
| 
 | 
 | ||||||
| | Flavor | Details | | You can pass flutter options to the build and run commands. | ||||||
| |-------|--------| |  | ||||||
| | Development | Use `--dart-define="dev_mode=<MODE>"` to choose between `mock` , `emulator` and `real` | |  | ||||||
| | Staging | With a green banner. Only `real` mode available (remote data sources) | |  | ||||||
| | Production | Only `real` mode available (remote data sources) | |  | ||||||
| 
 | 
 | ||||||
| > In `lib/core/flavors/flavor.dart` you can customize flavors. | ```sh | ||||||
|  | task run:staging -- -d chrome | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | > **Note** The `--` is required to pass options to the command. | ||||||
|  | |||||||
| @ -11,8 +11,8 @@ dart_code_metrics: | |||||||
|   metrics: |   metrics: | ||||||
|     cyclomatic-complexity: 20 |     cyclomatic-complexity: 20 | ||||||
|     maximum-nesting-level: 5 |     maximum-nesting-level: 5 | ||||||
|     number-of-parameters: 4 |     number-of-parameters: 5 | ||||||
|     source-lines-of-code: 50 |     source-lines-of-code: 250 | ||||||
|   metrics-exclude: |   metrics-exclude: | ||||||
|     - test/** |     - test/** | ||||||
|   rules: |   rules: | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ tasks: | |||||||
|     aliases: [a] |     aliases: [a] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Building Android APK...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Building Android APK...{{.COLOROFF}}" | ||||||
|       - flutter build lib/main_production apk --no-pub --no-shrink |       - flutter build apk --target=lib/main_production --no-pub --no-shrink | ||||||
|    |    | ||||||
|   ios: |   ios: | ||||||
|     desc: Building iOS IPA |     desc: Building iOS IPA | ||||||
| @ -35,4 +35,4 @@ tasks: | |||||||
|     aliases: [i] |     aliases: [i] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Building iOS IPA...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Building iOS IPA...{{.COLOROFF}}" | ||||||
|       - flutter build lib/main_production ipa --no-pub |       - flutter build ipa --target=lib/main_production --no-pub | ||||||
|  | |||||||
| @ -54,10 +54,3 @@ tasks: | |||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running build runner in watch mode...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Running build runner in watch mode...{{.COLOROFF}}" | ||||||
|       - flutter pub run build_runner watch |       - flutter pub run build_runner watch | ||||||
|    |  | ||||||
|   trapeze: |  | ||||||
|     desc: Running Trapeze config |  | ||||||
|     aliases: [t] |  | ||||||
|     cmds: |  | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running Trapeze config...{{.COLOROFF}}" |  | ||||||
|       - npx trapeze run trapeze.yaml --android-project android --ios-project ios |  | ||||||
|  | |||||||
| @ -16,44 +16,23 @@ tasks: | |||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Showing log output for running Flutter apps...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Showing log output for running Flutter apps...{{.COLOROFF}}" | ||||||
|       - flutter logs |       - flutter logs | ||||||
| 
 | 
 | ||||||
|   mock: |  | ||||||
|     desc: Run app in development environment with mocks |  | ||||||
|     aliases: [m] |  | ||||||
|     cmds: |  | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development/debug:mocks)...{{.COLOROFF}}" |  | ||||||
|       - flutter run --target lib/main_development.dart --dart-define="dev_mode=mock" |  | ||||||
| 
 |  | ||||||
|   emu: |  | ||||||
|     desc: Run app in development with emulated environment |  | ||||||
|     aliases: [e] |  | ||||||
|     cmds: |  | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development/debug:emulator)...{{.COLOROFF}}" |  | ||||||
|       - flutter run --target lib/main_development.dart --dart-define="dev_mode=emulator" |  | ||||||
| 
 |  | ||||||
|   dev: |   dev: | ||||||
|     desc: Run app in development environment |     desc: Run app in development environment | ||||||
|     aliases: [d] |     aliases: [d] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development/debug:real)...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development)...{{.COLOROFF}}" | ||||||
|       - flutter run --target lib/main_development.dart --dart-define="dev_mode=real" |       - flutter run --target lib/main_development.dart --dart-define-from-file=config.json {{.CLI_ARGS}} | ||||||
| 
 | 
 | ||||||
|   staging: |   staging: | ||||||
|     desc: Run app in staging environment |     desc: Run app in staging environment | ||||||
|     aliases: [s] |     aliases: [s] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (staging/debug)...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (staging)...{{.COLOROFF}}" | ||||||
|       - flutter run --target lib/main_staging.dart |       - flutter run --target lib/main_staging.dart --dart-define-from-file=config.json {{.CLI_ARGS}} | ||||||
| 
 | 
 | ||||||
|   prod: |   prod: | ||||||
|     desc: Run app in production environment |     desc: Run app in production environment | ||||||
|     aliases: [p] |     aliases: [p] | ||||||
|     cmds: |     cmds: | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (production/debug)...{{.COLOROFF}}" |       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (production)...{{.COLOROFF}}" | ||||||
|       - flutter run --target lib/main_production.dart |       - flutter run --target lib/main_production.dart --dart-define-from-file=config.json {{.CLI_ARGS}} | ||||||
| 
 |  | ||||||
|   release: |  | ||||||
|     desc: Run app in production environment and in release mode |  | ||||||
|     aliases: [r] |  | ||||||
|     cmds: |  | ||||||
|       - echo -e "{{.GREEN}}{{.PREFIX}} Running the app (production/release)...{{.COLOROFF}}" |  | ||||||
|       - flutter run --target lib/main_production.dart --release |  | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								bricks/wyatt_app_template/__brick__/config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								bricks/wyatt_app_template/__brick__/config.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | { | ||||||
|  |   "FIREBASE_EMULATOR_CLOUD_FUNCTION_PORT": 5001, | ||||||
|  |   "FIREBASE_EMULATOR_FIRESTORE_PORT": 8080, | ||||||
|  |   "FIREBASE_EMULATOR_AUTH_PORT": 9099, | ||||||
|  |   "FIREBASE_EMULATOR_STORAGE_PORT": 919911, | ||||||
|  |   "FIREBASE_EMULATOR_HOST": "localhost", | ||||||
|  |   "DEV_MODE": "local" | ||||||
|  | } | ||||||
| @ -7,12 +7,11 @@ import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/flavors/flavor | |||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/utils/app_bloc_observer.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/utils/app_bloc_observer.dart'; | ||||||
| 
 | 
 | ||||||
| Future<void> bootstrap(FutureOr<Widget> Function() builder) async { | Future<void> bootstrap(FutureOr<Widget> Function() builder) async { | ||||||
|   final widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); |   WidgetsFlutterBinding.ensureInitialized(); | ||||||
|   // FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); |  | ||||||
| 
 | 
 | ||||||
|   Bloc.observer = AppBlocObserver(); |   Bloc.observer = AppBlocObserver(); | ||||||
| 
 | 
 | ||||||
|   debugPrint('Flavor: ${Flavor.get()}'); |   debugPrint('${Flavor.instance}'); | ||||||
| 
 | 
 | ||||||
|   await GetItInitializer.init(); |   await GetItInitializer.init(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,12 +3,12 @@ | |||||||
| /// If you don't use Firebase, it can be safely deleted. | /// If you don't use Firebase, it can be safely deleted. | ||||||
| abstract class Emulator { | abstract class Emulator { | ||||||
|   static const String firebaseCloudFunctionEnvKey = |   static const String firebaseCloudFunctionEnvKey = | ||||||
|       'EMULATOR_FIREBASE_CLOUD_FUNCTION_PORT'; |       'FIREBASE_EMULATOR_CLOUD_FUNCTION_PORT'; | ||||||
|   static const String firebaseFirestoreEnvKey = |   static const String firebaseFirestoreEnvKey = | ||||||
|       'EMULATOR_FIREBASE_FIRESTORE_PORT'; |       'FIREBASE_EMULATOR_FIRESTORE_PORT'; | ||||||
|   static const String firebaseAuthEnvKey = 'EMULATOR_FIREBASE_AUTH_PORT'; |   static const String firebaseAuthEnvKey = 'FIREBASE_EMULATOR_AUTH_PORT'; | ||||||
|   static const String firebaseStorageEnvKey = 'EMULATOR_FIREBASE_STORAGE_PORT'; |   static const String firebaseStorageEnvKey = 'FIREBASE_EMULATOR_STORAGE_PORT'; | ||||||
|   static const String hostEnvKey = 'EMULATOR_HOST'; |   static const String hostEnvKey = 'FIREBASE_EMULATOR_HOST'; | ||||||
| 
 | 
 | ||||||
|   static const int defaultFirebaseCloudFunctionPort = 5001; |   static const int defaultFirebaseCloudFunctionPort = 5001; | ||||||
|   static const int defaultFirebaseFirestorePort = 8080; |   static const int defaultFirebaseFirestorePort = 8080; | ||||||
|  | |||||||
| @ -1,38 +1,50 @@ | |||||||
| import 'dart:async'; | import 'dart:async'; | ||||||
| 
 | 
 | ||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:get_it/get_it.dart'; | import 'package:get_it/get_it.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/enums/dev_mode.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/enums/dev_mode.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/flavors/flavor.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/flavors/flavor.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/data/data_sources/local/counter_data_source_impl.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/utils/firebase_emulator.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/domain/data_sources/local/counter_data_source.dart'; |  | ||||||
| 
 | 
 | ||||||
| final getIt = GetIt.I; | final getIt = GetIt.I; | ||||||
| 
 | 
 | ||||||
| /// Service and Data Source locator | /// Service and Data Source locator | ||||||
| abstract class GetItInitializer { | abstract class GetItInitializer { | ||||||
|   static FutureOr<void> _initCommon() async { |   static FutureOr<void> _initCommon() async { | ||||||
|     // Initialize common sources/services |     // TODO(wyatt): Initialize common sources/services | ||||||
|     getIt.registerLazySingleton<CounterDataSource>( |  | ||||||
|       CounterDataSourceImpl.new, |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static FutureOr<void> _initMocks() async { |   static FutureOr<void> _initMock() async { | ||||||
|     // Initialize mocked sources/services. |     // TODO(wyatt): Initialize mocked sources/services. | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static FutureOr<void> _initLocal() async { | ||||||
|  |     // TODO(wyatt): Initialize local sources/services. | ||||||
|  |     final emulator = FirebaseEmulator.fromEnv(); | ||||||
|  |     debugPrint('Firebase Emulator: $emulator'); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static FutureOr<void> _initReal() async { |   static FutureOr<void> _initReal() async { | ||||||
|     // Initialize real sources/services |     // TODO(wyatt): Initialize real sources/services | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static FutureOr<void> init() async { |   static FutureOr<void> init() async { | ||||||
|  |     // Initialize common sources/services | ||||||
|     await _initCommon(); |     await _initCommon(); | ||||||
|     final flavor = Flavor.get(); |  | ||||||
| 
 | 
 | ||||||
|     if (flavor.devMode == DevMode.mock) { |     // Initialize sources/services based on flavor | ||||||
|       await _initMocks(); |     switch (Flavor.instance.devMode) { | ||||||
|     } else { |       case DevMode.mock: | ||||||
|       await _initReal(); |         await _initMock(); | ||||||
|  |         break; | ||||||
|  |       case DevMode.local: | ||||||
|  |         await _initLocal(); | ||||||
|  |         break; | ||||||
|  |       case DevMode.real: | ||||||
|  |         await _initReal(); | ||||||
|  |         break; | ||||||
|  |       case null: | ||||||
|  |         throw Exception('DevMode not initialized!'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await getIt.allReady(); |     await getIt.allReady(); | ||||||
|  | |||||||
| @ -0,0 +1,31 @@ | |||||||
|  | enum BuildMode { | ||||||
|  |   /// Debug build mode. Pass `--debug` to `flutter run` or `flutter build` to | ||||||
|  |   /// use this mode. | ||||||
|  |   debug, | ||||||
|  | 
 | ||||||
|  |   /// Release build mode. Pass `--profile` to `flutter run` or `flutter build` | ||||||
|  |   /// to use this mode. | ||||||
|  |   profile, | ||||||
|  | 
 | ||||||
|  |   /// Release build mode. Pass `--release` to `flutter run` or `flutter build` | ||||||
|  |   /// to use this mode. | ||||||
|  |   release; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => name; | ||||||
|  | 
 | ||||||
|  |   /// Tries to parse String and returns mode. Fallback is returned if there | ||||||
|  |   /// is an error during parsing. | ||||||
|  |   static BuildMode fromString( | ||||||
|  |     String? mode, { | ||||||
|  |     BuildMode fallback = BuildMode.debug, | ||||||
|  |   }) { | ||||||
|  |     for (final m in values) { | ||||||
|  |       if (m.name == mode) { | ||||||
|  |         return m; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return fallback; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,6 +1,11 @@ | |||||||
| enum DevMode { | enum DevMode { | ||||||
|  |   /// Mocked data sources and services | ||||||
|   mock, |   mock, | ||||||
|   emulator, | 
 | ||||||
|  |   /// Local data sources and services, like local database, or firebase emulator | ||||||
|  |   local, | ||||||
|  | 
 | ||||||
|  |   /// Real data sources and services, like firebase or other cloud services | ||||||
|   real; |   real; | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|  | |||||||
| @ -0,0 +1,26 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | enum PageProtection { | ||||||
|  |   /// The page can be accessed without authentication. | ||||||
|  |   public, | ||||||
|  | 
 | ||||||
|  |   /// The page can only be accessed with authentication. | ||||||
|  |   protected, | ||||||
|  | 
 | ||||||
|  |   /// The page protection is unknown, and the default one should be used. | ||||||
|  |   none, | ||||||
|  | } | ||||||
| @ -0,0 +1,53 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:go_router/go_router.dart'; | ||||||
|  | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/enums/page_protection.dart'; | ||||||
|  | 
 | ||||||
|  | /// Defines if a GoRoute is public or not. | ||||||
|  | /// | ||||||
|  | /// By default, all routes are in the [PageProtection.none] state. | ||||||
|  | extension GoRouteGuard on GoRoute { | ||||||
|  |   static final _guard = Expando<PageProtection>(); | ||||||
|  | 
 | ||||||
|  |   /// Returns `true` if the route is public. | ||||||
|  |   bool get isPublic => _guard[this] == PageProtection.public; | ||||||
|  | 
 | ||||||
|  |   /// Returns `true` if the route is protected. | ||||||
|  |   bool get isProtected => _guard[this] == PageProtection.protected; | ||||||
|  | 
 | ||||||
|  |   /// Returns `true` if the route is neither public nor protected. | ||||||
|  |   /// This is the default state. | ||||||
|  |   bool get isNone => _guard[this] == PageProtection.none; | ||||||
|  | 
 | ||||||
|  |   /// Sets the route to be public. | ||||||
|  |   /// This is useful for routes that should be accessible | ||||||
|  |   /// without authentication. | ||||||
|  |   /// ```dart | ||||||
|  |   /// GoRoute( | ||||||
|  |   ///  path: '/sign_in', | ||||||
|  |   ///  ... | ||||||
|  |   /// )..setPublic(), | ||||||
|  |   /// ``` | ||||||
|  |   void setPublic() => _guard[this] = PageProtection.public; | ||||||
|  | 
 | ||||||
|  |   /// Sets the route to be protected. | ||||||
|  |   /// This is useful for routes that should only be accessible | ||||||
|  |   /// with authentication. | ||||||
|  |   void setProtected() => _guard[this] = PageProtection.protected; | ||||||
|  | 
 | ||||||
|  |   PageProtection get guard => _guard[this] ?? PageProtection.none; | ||||||
|  | } | ||||||
| @ -1,23 +1,38 @@ | |||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/enums/build_mode.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/enums/dev_mode.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/enums/dev_mode.dart'; | ||||||
| 
 | 
 | ||||||
| abstract class Flavor { | class Flavor { | ||||||
|   Flavor._({ |   Flavor._({ | ||||||
|     this.banner, |     this.flavorName, | ||||||
|     this.bannerColor = Colors.red, |     this.bannerColor, | ||||||
|     this.devMode, |  | ||||||
|   }) { |   }) { | ||||||
|  |     // Determine build mode | ||||||
|  |     buildMode = kReleaseMode | ||||||
|  |         ? BuildMode.release | ||||||
|  |         : kProfileMode | ||||||
|  |             ? BuildMode.profile | ||||||
|  |             : BuildMode.debug; | ||||||
|  | 
 | ||||||
|  |     // Retrieve dev mode, fallback to mock | ||||||
|  |     devMode = DevMode.fromString( | ||||||
|  |       const String.fromEnvironment('DEV_MODE', defaultValue: 'mock'), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|     _instance = this; |     _instance = this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static Flavor? _instance; |   static Flavor? _instance; | ||||||
| 
 | 
 | ||||||
|   final String? banner; |   final String? flavorName; | ||||||
|   final Color bannerColor; |   final Color? bannerColor; | ||||||
|   final DevMode? devMode; | 
 | ||||||
|  |   late final DevMode? devMode; | ||||||
|  |   late final BuildMode? buildMode; | ||||||
| 
 | 
 | ||||||
|   /// Returns [Flavor] instance. |   /// Returns [Flavor] instance. | ||||||
|   static Flavor get() { |   static Flavor get instance { | ||||||
|     if (_instance == null) { |     if (_instance == null) { | ||||||
|       throw Exception('Flavor not initialized!'); |       throw Exception('Flavor not initialized!'); | ||||||
|     } |     } | ||||||
| @ -25,33 +40,26 @@ abstract class Flavor { | |||||||
|     return _instance!; |     return _instance!; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   String get name => flavorName ?? 'Unknown'; | ||||||
|  |   Color get color => bannerColor ?? Colors.grey; | ||||||
|  | 
 | ||||||
|  |   static bool shouldShowBanner() => instance.buildMode != BuildMode.release; | ||||||
|  | 
 | ||||||
|   @override |   @override | ||||||
|   String toString() => runtimeType.toString().replaceAll('Flavor', ''); |   String toString() => | ||||||
|  |       'Flavor: $flavorName, DevMode: $devMode, BuildMode: $buildMode'; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class DevelopmentFlavor extends Flavor { | class DevelopmentFlavor extends Flavor { | ||||||
|   factory DevelopmentFlavor() { |   DevelopmentFlavor() | ||||||
|     const modeString = String.fromEnvironment('dev_mode', defaultValue: 'mock'); |       : super._(flavorName: 'Development', bannerColor: Colors.red); | ||||||
|     final mode = DevMode.fromString(modeString); |  | ||||||
| 
 |  | ||||||
|     return DevelopmentFlavor._(devMode: mode); |  | ||||||
|   } |  | ||||||
|   DevelopmentFlavor._({ |  | ||||||
|     required DevMode devMode, |  | ||||||
|   }) : super._( |  | ||||||
|           banner: 'Dev', |  | ||||||
|           devMode: devMode, |  | ||||||
|         ); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class StagingFlavor extends Flavor { | class StagingFlavor extends Flavor { | ||||||
|   StagingFlavor() |   StagingFlavor() : super._(flavorName: 'Staging', bannerColor: Colors.orange); | ||||||
|       : super._( |  | ||||||
|           banner: 'Staging', |  | ||||||
|           bannerColor: Colors.green, |  | ||||||
|         ); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class ProductionFlavor extends Flavor { | class ProductionFlavor extends Flavor { | ||||||
|   ProductionFlavor() : super._(); |   ProductionFlavor() | ||||||
|  |       : super._(flavorName: 'Production', bannerColor: Colors.green); | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,40 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'dart:async'; | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
|  | 
 | ||||||
|  | /// {@template go_router_refresh_stream} | ||||||
|  | /// A [ChangeNotifier] that notifies its listeners when a stream emits a value. | ||||||
|  | /// {@endtemplate} | ||||||
|  | class GoRouterRefreshStream extends ChangeNotifier { | ||||||
|  |   /// {@macro go_router_refresh_stream} | ||||||
|  |   GoRouterRefreshStream(Stream<dynamic> stream) { | ||||||
|  |     notifyListeners(); | ||||||
|  |     _subscription = stream.asBroadcastStream().listen( | ||||||
|  |           (dynamic _) => notifyListeners(), | ||||||
|  |         ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   late final StreamSubscription<dynamic> _subscription; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     _subscription.cancel(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,6 +1,8 @@ | |||||||
| import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||||
| import 'package:go_router/go_router.dart'; | import 'package:go_router/go_router.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/counter/counter.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/enums/page_protection.dart'; | ||||||
|  | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/extensions/go_route_extension.dart'; | ||||||
|  | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/routes/go_router_refresh_stream.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/home/home.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/home/home.dart'; | ||||||
| 
 | 
 | ||||||
| abstract class AppRouter { | abstract class AppRouter { | ||||||
| @ -10,10 +12,7 @@ abstract class AppRouter { | |||||||
|     GoRouterState state, |     GoRouterState state, | ||||||
|     Widget child, |     Widget child, | ||||||
|   ) => |   ) => | ||||||
|       CupertinoPage<void>( |       CupertinoPage<void>(key: state.pageKey, child: child); | ||||||
|         key: state.pageKey, |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 | 
 | ||||||
|   /// Disable transition animation |   /// Disable transition animation | ||||||
|   static Page<void> noTransition( |   static Page<void> noTransition( | ||||||
| @ -21,23 +20,7 @@ abstract class AppRouter { | |||||||
|     GoRouterState state, |     GoRouterState state, | ||||||
|     Widget child, |     Widget child, | ||||||
|   ) => |   ) => | ||||||
|       CustomTransitionPage<void>( |       NoTransitionPage(key: state.pageKey, child: child); | ||||||
|         key: state.pageKey, |  | ||||||
|         transitionsBuilder: (_, __, ___, child) => child, |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|   /// Defines public routes (no authentication needed). |  | ||||||
|   /// |  | ||||||
|   /// Example: |  | ||||||
|   /// ```dart |  | ||||||
|   /// static final publicRoutes = [ |  | ||||||
|   /// '/', |  | ||||||
|   /// '/sign_in', |  | ||||||
|   /// '/sign_up', |  | ||||||
|   /// ]; |  | ||||||
|   /// ``` |  | ||||||
|   static final List<String> publicRoutes = []; |  | ||||||
| 
 | 
 | ||||||
|   /// Defines GoRoute routes. |   /// Defines GoRoute routes. | ||||||
|   static final List<GoRoute> routes = [ |   static final List<GoRoute> routes = [ | ||||||
| @ -46,20 +29,32 @@ abstract class AppRouter { | |||||||
|       name: Home.pageName, |       name: Home.pageName, | ||||||
|       pageBuilder: (context, state) => |       pageBuilder: (context, state) => | ||||||
|           defaultTransition(context, state, const Home()), |           defaultTransition(context, state, const Home()), | ||||||
|     ), |     )..setPublic(), | ||||||
|     GoRoute( |  | ||||||
|       path: '/counter', |  | ||||||
|       name: Counter.pageName, |  | ||||||
|       pageBuilder: (context, state) => |  | ||||||
|           defaultTransition(context, state, const Counter()), |  | ||||||
|     ), |  | ||||||
|   ]; |   ]; | ||||||
| 
 | 
 | ||||||
|   /// Router |   /// Router | ||||||
|   static GoRouter router = GoRouter( |   static GoRouter routerOf(BuildContext context) => GoRouter( | ||||||
|     initialLocation: '/', |         initialLocation: '/', | ||||||
|     routes: AppRouter.routes, |         routes: AppRouter.routes, | ||||||
|     debugLogDiagnostics: true, |         debugLogDiagnostics: true, | ||||||
|     redirect: (context, state) => null, |         // TODO(wyatt): Add authentication logic | ||||||
|   ); |         redirect: (context, state) { | ||||||
|  |           /// Define the default guard | ||||||
|  |           /// This is the guard that will be used if the route | ||||||
|  |           /// does not have a guard set. (It is set to [PageProtection.none]) | ||||||
|  |           const defaultGuard = PageProtection.protected; | ||||||
|  | 
 | ||||||
|  |           // Compute current route | ||||||
|  |           // Compute current route | ||||||
|  |           final currentRoute = AppRouter.routes.firstWhere( | ||||||
|  |             (route) => route.path == state.location, | ||||||
|  |           ); | ||||||
|  | 
 | ||||||
|  |           // Get the guard of the current route | ||||||
|  |           final guard = currentRoute.guard; | ||||||
|  | 
 | ||||||
|  |           return null; | ||||||
|  |         }, | ||||||
|  |         refreshListenable: GoRouterRefreshStream(const Stream.empty()), | ||||||
|  |       ); | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,61 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/constants/emulator.dart'; | ||||||
|  | 
 | ||||||
|  | class FirebaseEmulator { | ||||||
|  |   const FirebaseEmulator._({ | ||||||
|  |     required this.cloudFunctionPort, | ||||||
|  |     required this.firestorePort, | ||||||
|  |     required this.authPort, | ||||||
|  |     required this.storagePort, | ||||||
|  |     required this.host, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   factory FirebaseEmulator.fromEnv() => const FirebaseEmulator._( | ||||||
|  |         cloudFunctionPort: int.fromEnvironment( | ||||||
|  |           Emulator.firebaseCloudFunctionEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultFirebaseCloudFunctionPort, | ||||||
|  |         ), | ||||||
|  |         firestorePort: int.fromEnvironment( | ||||||
|  |           Emulator.firebaseFirestoreEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultFirebaseFirestorePort, | ||||||
|  |         ), | ||||||
|  |         authPort: int.fromEnvironment( | ||||||
|  |           Emulator.firebaseAuthEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultFirebaseAuthPort, | ||||||
|  |         ), | ||||||
|  |         storagePort: int.fromEnvironment( | ||||||
|  |           Emulator.firebaseStorageEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultFirebaseStoragePort, | ||||||
|  |         ), | ||||||
|  |         host: String.fromEnvironment( | ||||||
|  |           Emulator.hostEnvKey, | ||||||
|  |           defaultValue: Emulator.defaultHost, | ||||||
|  |         ), | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |   final int cloudFunctionPort; | ||||||
|  |   final int firestorePort; | ||||||
|  |   final int authPort; | ||||||
|  |   final int storagePort; | ||||||
|  |   final String host; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => 'FirebaseEmulator(cloudFunctionPort: ' | ||||||
|  |       '$cloudFunctionPort, firestorePort: $firestorePort, authPort: $authPort, ' | ||||||
|  |       'storagePort: $storagePort, host: $host)'; | ||||||
|  | } | ||||||
| @ -105,11 +105,6 @@ class _$_IntegerModel implements _IntegerModel { | |||||||
|   @override |   @override | ||||||
|   final int value; |   final int value; | ||||||
| 
 | 
 | ||||||
|   @override |  | ||||||
|   String toString() { |  | ||||||
|     return 'IntegerModel(value: $value)'; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |   @override | ||||||
|   bool operator ==(dynamic other) { |   bool operator ==(dynamic other) { | ||||||
|     return identical(this, other) || |     return identical(this, other) || | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
| 
 | 
 | ||||||
| // coverage:ignore-file | // coverage:ignore-file | ||||||
| // ignore_for_file: type=lint | // ignore_for_file: type=lint | ||||||
| // ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal | // ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use | ||||||
| 
 | 
 | ||||||
| import 'package:flutter/widgets.dart'; | import 'package:flutter/widgets.dart'; | ||||||
| 
 | 
 | ||||||
| @ -84,7 +84,16 @@ class AssetGenImage { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ImageProvider provider() => AssetImage(_assetName); |   ImageProvider provider({ | ||||||
|  |     AssetBundle? bundle, | ||||||
|  |     String? package, | ||||||
|  |   }) { | ||||||
|  |     return AssetImage( | ||||||
|  |       _assetName, | ||||||
|  |       bundle: bundle, | ||||||
|  |       package: package, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   String get path => _assetName; |   String get path => _assetName; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
| 
 | 
 | ||||||
| // coverage:ignore-file | // coverage:ignore-file | ||||||
| // ignore_for_file: type=lint | // ignore_for_file: type=lint | ||||||
| // ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal | // ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use | ||||||
| 
 | 
 | ||||||
| import 'package:flutter/painting.dart'; | import 'package:flutter/painting.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/flavors/flavor | |||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/app/app.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/app/app.dart'; | ||||||
| 
 | 
 | ||||||
| void main(List<String> args) { | void main(List<String> args) { | ||||||
|   // Define environment |   // Define flavor | ||||||
|   DevelopmentFlavor(); |   DevelopmentFlavor(); | ||||||
| 
 | 
 | ||||||
|   // Initialize environment and variables |   // Initialize environment and variables | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/flavors/flavor | |||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/app/app.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/app/app.dart'; | ||||||
| 
 | 
 | ||||||
| void main(List<String> args) { | void main(List<String> args) { | ||||||
|   // Define environment |   // Define flavor | ||||||
|   ProductionFlavor(); |   ProductionFlavor(); | ||||||
| 
 | 
 | ||||||
|   // Initialize environment and variables |   // Initialize environment and variables | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/flavors/flavor | |||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/app/app.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/app/app.dart'; | ||||||
| 
 | 
 | ||||||
| void main(List<String> args) { | void main(List<String> args) { | ||||||
|   // Define environment |   // Define flavor | ||||||
|   StagingFlavor(); |   StagingFlavor(); | ||||||
| 
 | 
 | ||||||
|   // Initialize environment and variables |   // Initialize environment and variables | ||||||
|  | |||||||
| @ -1,63 +1,47 @@ | |||||||
| import 'package:flutter/foundation.dart'; |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| import 'package:flutter_localizations/flutter_localizations.dart'; | import 'package:flutter_localizations/flutter_localizations.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/dependency_injection/get_it.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/dependency_injection/get_it.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/flavors/flavor.dart'; |  | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/routes/router.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/routes/router.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/data/repositories/counter_repository_impl.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/data/repositories/counter_repository_impl.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/domain/repositories/counter_repository.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/domain/repositories/counter_repository.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/gen/app_localizations.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/gen/app_localizations.dart'; | ||||||
| import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/counter/blocs/counter_bloc/counter_bloc.dart'; | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/features/counter/blocs/counter_bloc/counter_bloc.dart'; | ||||||
|  | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/presentation/shared/widgets/flavor_banner.dart'; | ||||||
| import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | ||||||
| 
 | 
 | ||||||
| class App extends StatelessWidget { | class App extends StatelessWidget { | ||||||
|   const App({super.key}); |   const App({super.key}); | ||||||
| 
 | 
 | ||||||
|   Widget _flavorBanner(Widget child) { |  | ||||||
|     final flavor = Flavor.get(); |  | ||||||
|     if (flavor.banner != null && !kReleaseMode) { |  | ||||||
|       return Directionality( |  | ||||||
|         textDirection: TextDirection.ltr, |  | ||||||
|         child: Banner( |  | ||||||
|           location: BannerLocation.topEnd, |  | ||||||
|           message: flavor.banner!, |  | ||||||
|           color: flavor.bannerColor, |  | ||||||
|           child: child, |  | ||||||
|         ), |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return child; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) => MultiProvider( |   Widget build(BuildContext context) => MultiProvider( | ||||||
|       repositoryProviders: [ |         repositoryProviders: [ | ||||||
|         RepositoryProvider<CounterRepository>( |           RepositoryProvider<CounterRepository>( | ||||||
|           create: (_) => CounterRepositoryImpl(counterDataSource: getIt()), |             create: (_) => CounterRepositoryImpl(counterDataSource: getIt()), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |         blocProviders: [ | ||||||
|  |           BlocProvider<CounterBloc>( | ||||||
|  |             create: (_) => CounterBloc(), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |         child: FlavorBanner( | ||||||
|  |           child: MaterialApp.router( | ||||||
|  |             title: '{{#titleCase}}{{display_name}}{{/titleCase}}', | ||||||
|  |             debugShowCheckedModeBanner: false, | ||||||
|  |             routerDelegate: AppRouter.routerOf(context).routerDelegate, | ||||||
|  |             routeInformationParser: | ||||||
|  |                 AppRouter.routerOf(context).routeInformationParser, | ||||||
|  |             routeInformationProvider: | ||||||
|  |                 AppRouter.routerOf(context).routeInformationProvider, | ||||||
|  |             localizationsDelegates: const [ | ||||||
|  |               AppLocalizations.delegate, | ||||||
|  |               GlobalMaterialLocalizations.delegate, | ||||||
|  |               GlobalWidgetsLocalizations.delegate, | ||||||
|  |               GlobalCupertinoLocalizations.delegate, | ||||||
|  |             ], | ||||||
|  |             supportedLocales: AppLocalizations.supportedLocales, | ||||||
|  |           ), | ||||||
|         ), |         ), | ||||||
|       ], |       ); | ||||||
|       blocProviders: [ |  | ||||||
|         BlocProvider<CounterBloc>( |  | ||||||
|           create: (_) => CounterBloc(), |  | ||||||
|         ), |  | ||||||
|       ], |  | ||||||
|       child: _flavorBanner( |  | ||||||
|         MaterialApp.router( |  | ||||||
|           title: '{{#titleCase}}{{display_name}}{{/titleCase}}', |  | ||||||
|           debugShowCheckedModeBanner: false, |  | ||||||
|           routerDelegate: AppRouter.router.routerDelegate, |  | ||||||
|           routeInformationParser: AppRouter.router.routeInformationParser, |  | ||||||
|           routeInformationProvider: AppRouter.router.routeInformationProvider, |  | ||||||
|           localizationsDelegates: const [ |  | ||||||
|             AppLocalizations.delegate, |  | ||||||
|             GlobalMaterialLocalizations.delegate, |  | ||||||
|             GlobalWidgetsLocalizations.delegate, |  | ||||||
|             GlobalCupertinoLocalizations.delegate, |  | ||||||
|           ], |  | ||||||
|           supportedLocales: AppLocalizations.supportedLocales, |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,73 @@ | |||||||
|  | // Copyright (C) 2023 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:{{#snakeCase}}{{project_name}}{{/snakeCase}}/core/flavors/flavor.dart'; | ||||||
|  | 
 | ||||||
|  | /// {@template flavor_banner} | ||||||
|  | /// A banner that displays the current flavor. | ||||||
|  | /// This is useful for quickly identifying which flavor is currently running. | ||||||
|  | /// | ||||||
|  | /// When [Flavor.shouldShowBanner] is `false`, this widget will return [child]. | ||||||
|  | /// You can also override this behavior by setting [visible] to `true`. | ||||||
|  | /// | ||||||
|  | /// Wrap your [MaterialApp] with this widget to display the banner. | ||||||
|  | /// | ||||||
|  | /// Example: | ||||||
|  | /// | ||||||
|  | /// ```dart | ||||||
|  | /// FlavorBanner( | ||||||
|  | ///  visible: true, // or null to use Flavor.shouldShowBanner() | ||||||
|  | ///  child: const MaterialApp( | ||||||
|  | ///   title: 'Starting Template', | ||||||
|  | ///   ... | ||||||
|  | ///  ), | ||||||
|  | /// ); | ||||||
|  | /// ``` | ||||||
|  | /// {@endtemplate} | ||||||
|  | class FlavorBanner extends StatelessWidget { | ||||||
|  |   const FlavorBanner({ | ||||||
|  |     this.child, | ||||||
|  |     this.visible, | ||||||
|  |     super.key, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   final Widget? child; | ||||||
|  | 
 | ||||||
|  |   /// Defaults to [Flavor.shouldShowBanner]. | ||||||
|  |   final bool? visible; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     final visible = this.visible ?? Flavor.shouldShowBanner(); | ||||||
|  | 
 | ||||||
|  |     if (!visible) { | ||||||
|  |       return child ?? const SizedBox.shrink(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     final flavor = Flavor.instance; | ||||||
|  | 
 | ||||||
|  |     return Directionality( | ||||||
|  |       textDirection: TextDirection.ltr, | ||||||
|  |       child: Banner( | ||||||
|  |         location: BannerLocation.topEnd, | ||||||
|  |         message: flavor.name, | ||||||
|  |         color: flavor.color, | ||||||
|  |         child: child, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,5 +0,0 @@ | |||||||
| { |  | ||||||
|   "dependencies": { |  | ||||||
|     "@trapezedev/configure": "^7.0.5" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,69 +1,63 @@ | |||||||
| name: {{#snakeCase}}{{project_name}}{{/snakeCase}} | name: {{#snakeCase}}{{project_name}}{{/snakeCase}} | ||||||
| description: {{#sentenceCase}}{{description}}{{/sentenceCase}} |  | ||||||
| 
 |  | ||||||
| publish_to: "none" |  | ||||||
| 
 |  | ||||||
| version: 1.0.0+1 | version: 1.0.0+1 | ||||||
| 
 | publish_to: none | ||||||
|  | description: {{#sentenceCase}}{{description}}{{/sentenceCase}} | ||||||
| environment:  | environment:  | ||||||
|   sdk: ">=2.18.0 <3.0.0" |   sdk: '>=2.18.0 <3.0.0' | ||||||
|   flutter: ">=3.0.0" |   flutter: '>=3.0.0' | ||||||
| 
 |  | ||||||
| dependencies:  | dependencies:  | ||||||
|   flutter: { sdk: flutter } |  | ||||||
|   flutter_localizations: { sdk: flutter } |  | ||||||
|   intl: ^0.17.0 |  | ||||||
|   go_router: ^6.0.1 |  | ||||||
|   equatable: ^2.0.5 |  | ||||||
|   freezed_annotation: ^2.2.0 |  | ||||||
|   json_annotation: ^4.8.0 |  | ||||||
|   cupertino_icons: ^1.0.5 |   cupertino_icons: ^1.0.5 | ||||||
|   get_it: ^7.2.0 |   equatable: ^2.0.5 | ||||||
|   flutter_dotenv: ^5.0.2 |  | ||||||
|   gap: ^2.0.1 |  | ||||||
|   flutter_bloc: ^8.1.1 |   flutter_bloc: ^8.1.1 | ||||||
|  |   flutter_native_splash: ^2.2.15 | ||||||
|  |   freezed_annotation: ^2.2.0 | ||||||
|  |   gap: ^2.0.1 | ||||||
|  |   get_it: ^7.2.0 | ||||||
|  |   go_router: ^6.0.1 | ||||||
|  |   intl: ^0.17.0 | ||||||
|  |   json_annotation: ^4.8.0 | ||||||
|   url_launcher: ^6.1.7 |   url_launcher: ^6.1.7 | ||||||
|   uuid: ^3.0.7 |   uuid: ^3.0.7 | ||||||
|   flutter_native_splash: ^2.2.15 |   flutter:  | ||||||
|  |     sdk: flutter | ||||||
|  |   flutter_localizations:  | ||||||
|  |     sdk: flutter | ||||||
|   wyatt_architecture:  |   wyatt_architecture:  | ||||||
|  |     version: ^0.2.0 | ||||||
|     hosted:  |     hosted:  | ||||||
|       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |  | ||||||
|       name: wyatt_architecture |       name: wyatt_architecture | ||||||
|     version: 0.1.0+1 |       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|   wyatt_bloc_helper:  |   wyatt_bloc_helper:  | ||||||
|  |     version: ^2.0.1 | ||||||
|     hosted:  |     hosted:  | ||||||
|       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |  | ||||||
|       name: wyatt_bloc_helper |       name: wyatt_bloc_helper | ||||||
|     version: 2.0.0 |  | ||||||
|   wyatt_type_utils: |  | ||||||
|     hosted: |  | ||||||
|       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|  |   wyatt_type_utils:  | ||||||
|  |     version: ^0.0.5 | ||||||
|  |     hosted:  | ||||||
|       name: wyatt_type_utils |       name: wyatt_type_utils | ||||||
|     version: 0.0.4 |       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
| 
 |  | ||||||
| dev_dependencies:  | dev_dependencies:  | ||||||
|   flutter_test: { sdk: flutter } |  | ||||||
|   dependency_validator: ^3.2.2 |  | ||||||
|   build_runner: ^2.3.3 |   build_runner: ^2.3.3 | ||||||
|  |   dart_code_metrics: ^5.4.0 | ||||||
|  |   dependency_validator: ^3.2.2 | ||||||
|   flutter_gen_runner: ^5.1.0+1 |   flutter_gen_runner: ^5.1.0+1 | ||||||
|  |   flutter_launcher_icons: ^0.11.0 | ||||||
|   freezed: ^2.3.2 |   freezed: ^2.3.2 | ||||||
|   json_serializable: ^6.6.0 |   json_serializable: ^6.6.0 | ||||||
|   flutter_launcher_icons: ^0.11.0 |   pubspec_dependency_sorter: ^1.0.3 | ||||||
|   dart_code_metrics: ^5.4.0 |  | ||||||
|   rename: ^2.1.1 |   rename: ^2.1.1 | ||||||
|  |   flutter_test:  | ||||||
|  |     sdk: flutter | ||||||
|   wyatt_analysis:  |   wyatt_analysis:  | ||||||
|  |     version: ^2.5.0 | ||||||
|     hosted:  |     hosted:  | ||||||
|       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |  | ||||||
|       name: wyatt_analysis |       name: wyatt_analysis | ||||||
|     version: 2.4.1 |       url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
| 
 |  | ||||||
| flutter:  | flutter:  | ||||||
|   uses-material-design: true |  | ||||||
|   generate: true |  | ||||||
|   assets:  |   assets:  | ||||||
|     - .env |  | ||||||
|     - assets/images/ |     - assets/images/ | ||||||
| 
 |   uses-material-design: true | ||||||
| flutter_gen:  | flutter_gen:  | ||||||
|   output: lib/gen/ |   output: lib/gen/ | ||||||
|   integrations:  |   integrations:  | ||||||
| @ -74,17 +68,15 @@ flutter_gen: | |||||||
|   colors:  |   colors:  | ||||||
|     inputs:  |     inputs:  | ||||||
|       - assets/colors.xml |       - assets/colors.xml | ||||||
| 
 |  | ||||||
| flutter_icons:  | flutter_icons:  | ||||||
|   android: "launcher_icon" |   android: launcher_icon | ||||||
|  |   image_path: assets/images/wyatt_logo.jpeg | ||||||
|  |   adaptive_icon_background: '#FFFFFF' | ||||||
|   ios: true |   ios: true | ||||||
|   image_path: "assets/images/wyatt_logo.jpeg" |  | ||||||
|   adaptive_icon_background: "#FFFFFF" |  | ||||||
| 
 |  | ||||||
| flutter_native_splash:  | flutter_native_splash:  | ||||||
|   image: "assets/images/wyatt_logo.jpeg" |   image: assets/images/wyatt_logo.jpeg | ||||||
|   color: "#FFFFFF" |   color: '#FFFFFF' | ||||||
|   android: true |  | ||||||
|   ios: true |  | ||||||
|   android_gravity: fill |   android_gravity: fill | ||||||
|   ios_content_mode: scaleAspectFit |   ios_content_mode: scaleAspectFit | ||||||
|  |   android: true | ||||||
|  |   ios: true | ||||||
|  | |||||||
| @ -1,36 +0,0 @@ | |||||||
| vars: |  | ||||||
|   PACKAGE_NAME: |  | ||||||
|     default: {{#snakeCase}}{{project_name}}{{/snakeCase}} |  | ||||||
|   BUNDLE_ID: |  | ||||||
|     default: {{#dotCase}}{{bundle_id}}{{/dotCase}} |  | ||||||
|   APP_NAME: |  | ||||||
|     default: {{#titleCase}}{{display_name}}{{/titleCase}} |  | ||||||
| 
 |  | ||||||
| platforms: |  | ||||||
|   android: |  | ||||||
|     appName: $APP_NAME |  | ||||||
|     packageName: $BUNDLE_ID |  | ||||||
|     # Uncomment to add some permissions |  | ||||||
|     # manifest: |  | ||||||
|     #   - file: AndroidManifest.xml |  | ||||||
|     #     target: manifest/application |  | ||||||
|     #     inject: |  | ||||||
|     #       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |  | ||||||
|   ios: |  | ||||||
|     targets: |  | ||||||
|       Runner: |  | ||||||
|         bundleId: $BUNDLE_ID |  | ||||||
|         productName: $APP_NAME |  | ||||||
|         displayName: $APP_NAME |  | ||||||
|         entitlements: |  | ||||||
|           replace: true |  | ||||||
|           # Workaround for https://stackoverflow.com/questions/55167611/flutter-ios-app-submission-issue-warning-missing-push-notification-entitlement |  | ||||||
|           entries: |  | ||||||
|             - aps-environment: development |  | ||||||
|         # Uncomment to add some permissions |  | ||||||
|         # plist: |  | ||||||
|         #   - replace: true |  | ||||||
|         #     entries: |  | ||||||
|         #       - UISupportedInterfaceOrientations: |  | ||||||
|         #           - UIInterfaceOrientationPortrait |  | ||||||
| 
 |  | ||||||
| @ -1,7 +1,7 @@ | |||||||
| name: wyatt_app_template | name: wyatt_app_template | ||||||
| description: New app template for Wyatt Studio projects. | description: New app template for Wyatt Studio projects. | ||||||
| 
 | 
 | ||||||
| version: 0.1.2 | version: 0.2.0 | ||||||
| 
 | 
 | ||||||
| vars: | vars: | ||||||
|   display_name: |   display_name: | ||||||
|  | |||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 31 KiB | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user