feat(app): upgrade app template
This commit is contained in:
parent
ebd8618043
commit
a100a81acd
@ -6,54 +6,55 @@ A short project description
|
||||
|
||||
* Flutter <https://flutter.dev/>
|
||||
* Taskfile <https://taskfile.dev/>
|
||||
* Trapeze <https://trapeze.dev/> (with `npm install` thanks to `package.json`)
|
||||
|
||||
### Configuration
|
||||
|
||||
Create `.env` file with
|
||||
At the build time, the app will read the environment variables from `config.json` file.
|
||||
|
||||
```sh
|
||||
cp .env.example .env
|
||||
The important variable is `DEV_MODE` which can be `mock` , `local` or `real` .
|
||||
|
||||
```json
|
||||
{
|
||||
"DEV_MODE": "local"
|
||||
}
|
||||
```
|
||||
|
||||
> **Note** `local` can refer to a local server or a local emulator.
|
||||
|
||||
### Taskfile
|
||||
|
||||
Available tasks:
|
||||
|
||||
| Command | Description | Aliases |
|
||||
|----|-----|-----|
|
||||
| `clean` | Cleans the environment.| `cl` |
|
||||
| `format` |Formats the code.| `fmt` |
|
||||
| `help` |Help dialog.| `h, default` |
|
||||
| `lint` |Lints the code.| `l` |
|
||||
| `start-emulators` | Start needed emulators.| `emu` |
|
||||
| `build:android` | Building Android APK| `build:a` |
|
||||
| `build:ios` | Building iOS IPA| `build:i` |
|
||||
| `gen:build` | Running build runner| `gen:b` |
|
||||
| `gen:build-delete` |Running build runner with deletion of conflicting outputs| `gen:d` |
|
||||
| `gen:clean` | Cleaning build runner| `gen:c` |
|
||||
| `gen:intl` |Generating internationalization file| `gen:i` |
|
||||
| `gen:trapeze` | Running Trapeze config| `gen:t` |
|
||||
| `gen:watch` | Running build runner in watch mode| `gen:w` |
|
||||
| `pub:get` | Getting latest dependencies| `pub:g` |
|
||||
| `pub:outdated` |Checking for outdated dependencies| `pub:o` |
|
||||
| `pub:upgrade` | Upgrading dependencies| `pub:u` |
|
||||
| `pub:upgrade-major` | Upgrading dependencies| `pub:um` |
|
||||
| `pub:validate` |Running dependency validator| `pub:v` |
|
||||
| `run:dev` | Run app in development environment| `run:d` |
|
||||
| `run:emu` | Run app in development with emulated environment| `run:e` |
|
||||
| `run:logs` |Show log output for running Flutter apps| `run:l` |
|
||||
| `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` |
|
||||
| Commande | Description | Alias |
|
||||
| --- | --- | --- |
|
||||
| clean | Nettoie l'environnement de travail | cl |
|
||||
| format | Formate le code | fmt |
|
||||
| help | Affiche la boîte de dialogue d'aide | h, default |
|
||||
| lint | Vérifie la qualité du code | l |
|
||||
| start-emulators | Démarre les émulateurs nécessaires | emu |
|
||||
| build:android | Construit le fichier APK pour Android | build:a |
|
||||
| build:ios | Construit le fichier IPA pour iOS | build:i |
|
||||
| gen:build | Exécute le générateur de build | gen:b |
|
||||
| gen:build-delete | Exécute le générateur de build et supprime les sorties en conflit | gen:d |
|
||||
| gen:clean | Nettoie le générateur de build | gen:c |
|
||||
| gen:intl | Génère un fichier d'internationalisation | gen:i |
|
||||
| gen:watch | Exécute le générateur de build en mode surveillance | gen:w |
|
||||
| pub:get | Obtient les dernières dépendances | pub:g |
|
||||
| pub:outdated | Vérifie les dépendances obsolètes | pub:o |
|
||||
| pub:upgrade | Met à jour les dépendances | pub:u |
|
||||
| pub:upgrade-major | Met à jour les dépendances majeures | pub:um |
|
||||
| pub:validate | Exécute le validateur de dépendances | pub:v |
|
||||
| run:dev | Lance l'application en environnement de développement | run:d |
|
||||
| run:logs | Affiche la sortie de journalisation pour les applications Flutter en cours d'exécution | run:l |
|
||||
| run:prod | Lance l'application en environnement de production | run:p |
|
||||
| run:staging | Lance l'application en environnement de pré-production | run:s |
|
||||
|
||||
### Flavors
|
||||
### Parameters
|
||||
|
||||
| Flavor | Details |
|
||||
|-------|--------|
|
||||
| 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) |
|
||||
You can pass flutter options to the build and run commands.
|
||||
|
||||
> 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:
|
||||
cyclomatic-complexity: 20
|
||||
maximum-nesting-level: 5
|
||||
number-of-parameters: 4
|
||||
source-lines-of-code: 50
|
||||
number-of-parameters: 5
|
||||
source-lines-of-code: 250
|
||||
metrics-exclude:
|
||||
- test/**
|
||||
rules:
|
||||
|
@ -27,7 +27,7 @@ tasks:
|
||||
aliases: [a]
|
||||
cmds:
|
||||
- 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:
|
||||
desc: Building iOS IPA
|
||||
@ -35,4 +35,4 @@ tasks:
|
||||
aliases: [i]
|
||||
cmds:
|
||||
- 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:
|
||||
- echo -e "{{.GREEN}}{{.PREFIX}} Running build runner in watch mode...{{.COLOROFF}}"
|
||||
- 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}}"
|
||||
- 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:
|
||||
desc: Run app in development environment
|
||||
aliases: [d]
|
||||
cmds:
|
||||
- echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development/debug:real)...{{.COLOROFF}}"
|
||||
- flutter run --target lib/main_development.dart --dart-define="dev_mode=real"
|
||||
- echo -e "{{.GREEN}}{{.PREFIX}} Running the app (development)...{{.COLOROFF}}"
|
||||
- flutter run --target lib/main_development.dart --dart-define-from-file=config.json {{.CLI_ARGS}}
|
||||
|
||||
staging:
|
||||
desc: Run app in staging environment
|
||||
aliases: [s]
|
||||
cmds:
|
||||
- echo -e "{{.GREEN}}{{.PREFIX}} Running the app (staging/debug)...{{.COLOROFF}}"
|
||||
- flutter run --target lib/main_staging.dart
|
||||
- echo -e "{{.GREEN}}{{.PREFIX}} Running the app (staging)...{{.COLOROFF}}"
|
||||
- flutter run --target lib/main_staging.dart --dart-define-from-file=config.json {{.CLI_ARGS}}
|
||||
|
||||
prod:
|
||||
desc: Run app in production environment
|
||||
aliases: [p]
|
||||
cmds:
|
||||
- echo -e "{{.GREEN}}{{.PREFIX}} Running the app (production/debug)...{{.COLOROFF}}"
|
||||
- flutter run --target lib/main_production.dart
|
||||
|
||||
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
|
||||
- echo -e "{{.GREEN}}{{.PREFIX}} Running the app (production)...{{.COLOROFF}}"
|
||||
- flutter run --target lib/main_production.dart --dart-define-from-file=config.json {{.CLI_ARGS}}
|
||||
|
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';
|
||||
|
||||
Future<void> bootstrap(FutureOr<Widget> Function() builder) async {
|
||||
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
||||
// FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
Bloc.observer = AppBlocObserver();
|
||||
|
||||
debugPrint('Flavor: ${Flavor.get()}');
|
||||
debugPrint('${Flavor.instance}');
|
||||
|
||||
await GetItInitializer.init();
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
/// Firebase Emulator constants.
|
||||
///
|
||||
///
|
||||
/// If you don't use Firebase, it can be safely deleted.
|
||||
abstract class Emulator {
|
||||
static const String firebaseCloudFunctionEnvKey =
|
||||
'EMULATOR_FIREBASE_CLOUD_FUNCTION_PORT';
|
||||
'FIREBASE_EMULATOR_CLOUD_FUNCTION_PORT';
|
||||
static const String firebaseFirestoreEnvKey =
|
||||
'EMULATOR_FIREBASE_FIRESTORE_PORT';
|
||||
static const String firebaseAuthEnvKey = 'EMULATOR_FIREBASE_AUTH_PORT';
|
||||
static const String firebaseStorageEnvKey = 'EMULATOR_FIREBASE_STORAGE_PORT';
|
||||
static const String hostEnvKey = 'EMULATOR_HOST';
|
||||
'FIREBASE_EMULATOR_FIRESTORE_PORT';
|
||||
static const String firebaseAuthEnvKey = 'FIREBASE_EMULATOR_AUTH_PORT';
|
||||
static const String firebaseStorageEnvKey = 'FIREBASE_EMULATOR_STORAGE_PORT';
|
||||
static const String hostEnvKey = 'FIREBASE_EMULATOR_HOST';
|
||||
|
||||
static const int defaultFirebaseCloudFunctionPort = 5001;
|
||||
static const int defaultFirebaseFirestorePort = 8080;
|
||||
|
@ -1,38 +1,50 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:starting_template/core/enums/dev_mode.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/domain/data_sources/local/counter_data_source.dart';
|
||||
import 'package:starting_template/core/utils/firebase_emulator.dart';
|
||||
|
||||
final getIt = GetIt.I;
|
||||
|
||||
/// Service and Data Source locator
|
||||
abstract class GetItInitializer {
|
||||
static FutureOr<void> _initCommon() async {
|
||||
// Initialize common sources/services
|
||||
getIt.registerLazySingleton<CounterDataSource>(
|
||||
CounterDataSourceImpl.new,
|
||||
);
|
||||
// TODO(wyatt): Initialize common sources/services
|
||||
}
|
||||
|
||||
static FutureOr<void> _initMocks() async {
|
||||
// Initialize mocked sources/services.
|
||||
static FutureOr<void> _initMock() async {
|
||||
// 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 {
|
||||
// Initialize real sources/services
|
||||
// TODO(wyatt): Initialize real sources/services
|
||||
}
|
||||
|
||||
static FutureOr<void> init() async {
|
||||
// Initialize common sources/services
|
||||
await _initCommon();
|
||||
final flavor = Flavor.get();
|
||||
|
||||
if (flavor.devMode == DevMode.mock) {
|
||||
await _initMocks();
|
||||
} else {
|
||||
await _initReal();
|
||||
// Initialize sources/services based on flavor
|
||||
switch (Flavor.instance.devMode) {
|
||||
case DevMode.mock:
|
||||
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();
|
||||
|
@ -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,12 +1,17 @@
|
||||
enum DevMode {
|
||||
/// Mocked data sources and services
|
||||
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;
|
||||
|
||||
@override
|
||||
String toString() => name;
|
||||
|
||||
/// Tries to parse String and returns mode. Fallback is returned if there
|
||||
/// Tries to parse String and returns mode. Fallback is returned if there
|
||||
/// is an error during parsing.
|
||||
static DevMode fromString(String? mode, {DevMode fallback = DevMode.mock}) {
|
||||
for (final m in values) {
|
||||
|
@ -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:starting_template/core/enums/build_mode.dart';
|
||||
import 'package:starting_template/core/enums/dev_mode.dart';
|
||||
|
||||
abstract class Flavor {
|
||||
class Flavor {
|
||||
Flavor._({
|
||||
this.banner,
|
||||
this.bannerColor = Colors.red,
|
||||
this.devMode,
|
||||
this.flavorName,
|
||||
this.bannerColor,
|
||||
}) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
static Flavor? _instance;
|
||||
|
||||
final String? banner;
|
||||
final Color bannerColor;
|
||||
final DevMode? devMode;
|
||||
final String? flavorName;
|
||||
final Color? bannerColor;
|
||||
|
||||
late final DevMode? devMode;
|
||||
late final BuildMode? buildMode;
|
||||
|
||||
/// Returns [Flavor] instance.
|
||||
static Flavor get() {
|
||||
static Flavor get instance {
|
||||
if (_instance == null) {
|
||||
throw Exception('Flavor not initialized!');
|
||||
}
|
||||
@ -25,33 +40,26 @@ abstract class Flavor {
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
String get name => flavorName ?? 'Unknown';
|
||||
Color get color => bannerColor ?? Colors.grey;
|
||||
|
||||
static bool shouldShowBanner() => instance.buildMode != BuildMode.release;
|
||||
|
||||
@override
|
||||
String toString() => runtimeType.toString().replaceAll('Flavor', '');
|
||||
String toString() =>
|
||||
'Flavor: $flavorName, DevMode: $devMode, BuildMode: $buildMode';
|
||||
}
|
||||
|
||||
class DevelopmentFlavor extends Flavor {
|
||||
factory DevelopmentFlavor() {
|
||||
const modeString = String.fromEnvironment('dev_mode', defaultValue: 'mock');
|
||||
final mode = DevMode.fromString(modeString);
|
||||
|
||||
return DevelopmentFlavor._(devMode: mode);
|
||||
}
|
||||
DevelopmentFlavor._({
|
||||
required DevMode devMode,
|
||||
}) : super._(
|
||||
banner: 'Dev',
|
||||
devMode: devMode,
|
||||
);
|
||||
DevelopmentFlavor()
|
||||
: super._(flavorName: 'Development', bannerColor: Colors.red);
|
||||
}
|
||||
|
||||
class StagingFlavor extends Flavor {
|
||||
StagingFlavor()
|
||||
: super._(
|
||||
banner: 'Staging',
|
||||
bannerColor: Colors.green,
|
||||
);
|
||||
StagingFlavor() : super._(flavorName: 'Staging', bannerColor: Colors.orange);
|
||||
}
|
||||
|
||||
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: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';
|
||||
|
||||
abstract class AppRouter {
|
||||
@ -10,10 +12,7 @@ abstract class AppRouter {
|
||||
GoRouterState state,
|
||||
Widget child,
|
||||
) =>
|
||||
CupertinoPage<void>(
|
||||
key: state.pageKey,
|
||||
child: child,
|
||||
);
|
||||
CupertinoPage<void>(key: state.pageKey, child: child);
|
||||
|
||||
/// Disable transition animation
|
||||
static Page<void> noTransition(
|
||||
@ -21,23 +20,7 @@ abstract class AppRouter {
|
||||
GoRouterState state,
|
||||
Widget child,
|
||||
) =>
|
||||
CustomTransitionPage<void>(
|
||||
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 = [];
|
||||
NoTransitionPage(key: state.pageKey, child: child);
|
||||
|
||||
/// Defines GoRoute routes.
|
||||
static final List<GoRoute> routes = [
|
||||
@ -46,20 +29,32 @@ abstract class AppRouter {
|
||||
name: Home.pageName,
|
||||
pageBuilder: (context, state) =>
|
||||
defaultTransition(context, state, const Home()),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/counter',
|
||||
name: Counter.pageName,
|
||||
pageBuilder: (context, state) =>
|
||||
defaultTransition(context, state, const Counter()),
|
||||
),
|
||||
)..setPublic(),
|
||||
];
|
||||
|
||||
/// Router
|
||||
static GoRouter router = GoRouter(
|
||||
initialLocation: '/',
|
||||
routes: AppRouter.routes,
|
||||
debugLogDiagnostics: true,
|
||||
redirect: (context, state) => null,
|
||||
);
|
||||
static GoRouter routerOf(BuildContext context) => GoRouter(
|
||||
initialLocation: '/',
|
||||
routes: AppRouter.routes,
|
||||
debugLogDiagnostics: true,
|
||||
// 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
|
||||
final int value;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'IntegerModel(value: $value)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
// coverage:ignore-file
|
||||
// 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';
|
||||
|
||||
@ -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;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
// coverage:ignore-file
|
||||
// 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/material.dart';
|
||||
|
@ -3,7 +3,7 @@ import 'package:starting_template/core/flavors/flavor.dart';
|
||||
import 'package:starting_template/presentation/features/app/app.dart';
|
||||
|
||||
void main(List<String> args) {
|
||||
// Define environment
|
||||
// Define flavor
|
||||
DevelopmentFlavor();
|
||||
|
||||
// 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';
|
||||
|
||||
void main(List<String> args) {
|
||||
// Define environment
|
||||
// Define flavor
|
||||
ProductionFlavor();
|
||||
|
||||
// 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';
|
||||
|
||||
void main(List<String> args) {
|
||||
// Define environment
|
||||
// Define flavor
|
||||
StagingFlavor();
|
||||
|
||||
// Initialize environment and variables
|
||||
|
@ -1,63 +1,47 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.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/data/repositories/counter_repository_impl.dart';
|
||||
import 'package:starting_template/domain/repositories/counter_repository.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/shared/widgets/flavor_banner.dart';
|
||||
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
|
||||
|
||||
class App extends StatelessWidget {
|
||||
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
|
||||
Widget build(BuildContext context) => MultiProvider(
|
||||
repositoryProviders: [
|
||||
RepositoryProvider<CounterRepository>(
|
||||
create: (_) => CounterRepositoryImpl(counterDataSource: getIt()),
|
||||
repositoryProviders: [
|
||||
RepositoryProvider<CounterRepository>(
|
||||
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,90 +1,82 @@
|
||||
name: starting_template
|
||||
description: A short project description
|
||||
|
||||
publish_to: "none"
|
||||
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.18.0 <3.0.0"
|
||||
flutter: ">=3.0.0"
|
||||
|
||||
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
|
||||
publish_to: none
|
||||
description: A short project description
|
||||
environment:
|
||||
sdk: '>=2.18.0 <3.0.0'
|
||||
flutter: '>=3.0.0'
|
||||
dependencies:
|
||||
cupertino_icons: ^1.0.5
|
||||
get_it: ^7.2.0
|
||||
flutter_dotenv: ^5.0.2
|
||||
gap: ^2.0.1
|
||||
equatable: ^2.0.5
|
||||
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
|
||||
uuid: ^3.0.7
|
||||
flutter_native_splash: ^2.2.15
|
||||
wyatt_architecture:
|
||||
hosted:
|
||||
url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
wyatt_architecture:
|
||||
version: ^0.2.0
|
||||
hosted:
|
||||
name: wyatt_architecture
|
||||
version: 0.1.0+1
|
||||
wyatt_bloc_helper:
|
||||
hosted:
|
||||
url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
|
||||
wyatt_bloc_helper:
|
||||
version: ^2.0.1
|
||||
hosted:
|
||||
name: wyatt_bloc_helper
|
||||
version: 2.0.0
|
||||
wyatt_type_utils:
|
||||
hosted:
|
||||
url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
|
||||
wyatt_type_utils:
|
||||
version: ^0.0.5
|
||||
hosted:
|
||||
name: wyatt_type_utils
|
||||
version: 0.0.4
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test: { sdk: flutter }
|
||||
dependency_validator: ^3.2.2
|
||||
url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
|
||||
dev_dependencies:
|
||||
build_runner: ^2.3.3
|
||||
dart_code_metrics: ^5.4.0
|
||||
dependency_validator: ^3.2.2
|
||||
flutter_gen_runner: ^5.1.0+1
|
||||
flutter_launcher_icons: ^0.11.0
|
||||
freezed: ^2.3.2
|
||||
json_serializable: ^6.6.0
|
||||
flutter_launcher_icons: ^0.11.0
|
||||
dart_code_metrics: ^5.4.0
|
||||
pubspec_dependency_sorter: ^1.0.3
|
||||
rename: ^2.1.1
|
||||
wyatt_analysis:
|
||||
hosted:
|
||||
url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
wyatt_analysis:
|
||||
version: ^2.5.0
|
||||
hosted:
|
||||
name: wyatt_analysis
|
||||
version: 2.4.1
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
generate: true
|
||||
assets:
|
||||
- .env
|
||||
url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
|
||||
flutter:
|
||||
assets:
|
||||
- assets/images/
|
||||
|
||||
flutter_gen:
|
||||
uses-material-design: true
|
||||
flutter_gen:
|
||||
output: lib/gen/
|
||||
integrations:
|
||||
integrations:
|
||||
flutter_svg: true
|
||||
flare_flutter: true
|
||||
rive: true
|
||||
lottie: true
|
||||
colors:
|
||||
inputs:
|
||||
colors:
|
||||
inputs:
|
||||
- assets/colors.xml
|
||||
|
||||
flutter_icons:
|
||||
android: "launcher_icon"
|
||||
ios: true
|
||||
image_path: "assets/images/wyatt_logo.jpeg"
|
||||
adaptive_icon_background: "#FFFFFF"
|
||||
|
||||
flutter_native_splash:
|
||||
image: "assets/images/wyatt_logo.jpeg"
|
||||
color: "#FFFFFF"
|
||||
android: true
|
||||
flutter_icons:
|
||||
android: launcher_icon
|
||||
image_path: assets/images/wyatt_logo.jpeg
|
||||
adaptive_icon_background: '#FFFFFF'
|
||||
ios: true
|
||||
flutter_native_splash:
|
||||
image: assets/images/wyatt_logo.jpeg
|
||||
color: '#FFFFFF'
|
||||
android_gravity: fill
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user