feat(app): upgrade app brick
This commit is contained in:
parent
fbf62ffe16
commit
21e304e776
@ -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 _initMock();
|
||||||
|
break;
|
||||||
|
case DevMode.local:
|
||||||
|
await _initLocal();
|
||||||
|
break;
|
||||||
|
case DevMode.real:
|
||||||
await _initReal();
|
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,36 +1,18 @@
|
|||||||
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: [
|
||||||
@ -43,13 +25,15 @@ class App extends StatelessWidget {
|
|||||||
create: (_) => CounterBloc(),
|
create: (_) => CounterBloc(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: _flavorBanner(
|
child: FlavorBanner(
|
||||||
MaterialApp.router(
|
child: MaterialApp.router(
|
||||||
title: '{{#titleCase}}{{display_name}}{{/titleCase}}',
|
title: '{{#titleCase}}{{display_name}}{{/titleCase}}',
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
routerDelegate: AppRouter.router.routerDelegate,
|
routerDelegate: AppRouter.routerOf(context).routerDelegate,
|
||||||
routeInformationParser: AppRouter.router.routeInformationParser,
|
routeInformationParser:
|
||||||
routeInformationProvider: AppRouter.router.routeInformationProvider,
|
AppRouter.routerOf(context).routeInformationParser,
|
||||||
|
routeInformationProvider:
|
||||||
|
AppRouter.routerOf(context).routeInformationProvider,
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
AppLocalizations.delegate,
|
AppLocalizations.delegate,
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
@ -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
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user