diff --git a/apps/wyatt_app_template/brick_config.yaml b/apps/wyatt_app_template/brick_config.yaml
index b90fd25..840bb2a 100644
--- a/apps/wyatt_app_template/brick_config.yaml
+++ b/apps/wyatt_app_template/brick_config.yaml
@@ -11,18 +11,21 @@ vars:
description: The display name
default: Wyatt App
prompt: "What is the display name?"
+
project_name:
name: wyatt_app_template
type: string
description: The project name
default: wyatt_app
prompt: "What is the project name?"
- org_name:
+
+ bundle_id:
name: io.wyattapp.new
type: string
- description: The organization name
+ description: The bundle id used in Android and iOS
default: io.wyattapp.new
- prompt: "What is the organization name?"
+ prompt: "What is the bundle id?"
+
description:
name: wyatt_description
type: string
diff --git a/apps/wyatt_app_template/wyatt_app_template/.metadata b/apps/wyatt_app_template/wyatt_app_template/.metadata
index ddd7794..32d8944 100644
--- a/apps/wyatt_app_template/wyatt_app_template/.metadata
+++ b/apps/wyatt_app_template/wyatt_app_template/.metadata
@@ -15,10 +15,7 @@ migration:
- platform: root
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- - platform: android
- create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- - platform: ios
+ - platform: web
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
diff --git a/apps/wyatt_app_template/wyatt_app_template/README.md b/apps/wyatt_app_template/wyatt_app_template/README.md
index 610f8d2..1545a0b 100644
--- a/apps/wyatt_app_template/wyatt_app_template/README.md
+++ b/apps/wyatt_app_template/wyatt_app_template/README.md
@@ -4,6 +4,56 @@ wyatt_description
## Requirements
-- Flutter
-- Taskfile
-- Trapeze (with `npm install` thanks to `package.json`)
\ No newline at end of file
+* Flutter
+* Taskfile
+* Trapeze (with `npm install` thanks to `package.json`)
+
+### Configuration
+
+Create `.env` file with
+
+```sh
+cp .env.example .env
+```
+
+### 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` |
+
+### Flavors
+
+| Flavor | Details |
+|-------|--------|
+| Development | Use `--dart-define="dev_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.
diff --git a/apps/wyatt_app_template/wyatt_app_template/analysis_options.yaml b/apps/wyatt_app_template/wyatt_app_template/analysis_options.yaml
index f165353..6b75b4c 100644
--- a/apps/wyatt_app_template/wyatt_app_template/analysis_options.yaml
+++ b/apps/wyatt_app_template/wyatt_app_template/analysis_options.yaml
@@ -1,5 +1,9 @@
include: package:wyatt_analysis/analysis_options.flutter.yaml
+analyzer:
+ plugins:
+ - dart_code_metrics
+
dart_code_metrics:
anti-patterns:
- long-method
diff --git a/apps/wyatt_app_template/wyatt_app_template/assets/fonts/.gitkeep b/apps/wyatt_app_template/wyatt_app_template/assets/fonts/.gitkeep
new file mode 100644
index 0000000..f94cb6f
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/assets/fonts/.gitkeep
@@ -0,0 +1 @@
+# just to keep empty folder in brick generation
\ No newline at end of file
diff --git a/apps/wyatt_app_template/wyatt_app_template/ios/Podfile.lock b/apps/wyatt_app_template/wyatt_app_template/ios/Podfile.lock
new file mode 100644
index 0000000..a5acb8c
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/ios/Podfile.lock
@@ -0,0 +1,28 @@
+PODS:
+ - Flutter (1.0.0)
+ - flutter_native_splash (0.0.1):
+ - Flutter
+ - url_launcher_ios (0.0.1):
+ - Flutter
+
+DEPENDENCIES:
+ - Flutter (from `Flutter`)
+ - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
+ - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
+
+EXTERNAL SOURCES:
+ Flutter:
+ :path: Flutter
+ flutter_native_splash:
+ :path: ".symlinks/plugins/flutter_native_splash/ios"
+ url_launcher_ios:
+ :path: ".symlinks/plugins/url_launcher_ios/ios"
+
+SPEC CHECKSUMS:
+ Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
+ flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
+ url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
+
+PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
+
+COCOAPODS: 1.11.3
diff --git a/apps/wyatt_app_template/wyatt_app_template/ios/Runner.xcodeproj/project.pbxproj b/apps/wyatt_app_template/wyatt_app_template/ios/Runner.xcodeproj/project.pbxproj
index f45320b..a1c40c5 100644
--- a/apps/wyatt_app_template/wyatt_app_template/ios/Runner.xcodeproj/project.pbxproj
+++ b/apps/wyatt_app_template/wyatt_app_template/ios/Runner.xcodeproj/project.pbxproj
@@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 50F1D9CF301DADBFF7F91098 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F58D6DFA5E148E9B1E5401F /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
@@ -29,8 +30,11 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 01240B090F6ECE02483CB484 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 18B4FB2B44E101F10AB8D41B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ 1F58D6DFA5E148E9B1E5401F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
@@ -42,6 +46,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ EA780011634A6BC46817CBE0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -49,12 +54,32 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 50F1D9CF301DADBFF7F91098 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 10872F84FB14C7DD915284C6 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 18B4FB2B44E101F10AB8D41B /* Pods-Runner.debug.xcconfig */,
+ 01240B090F6ECE02483CB484 /* Pods-Runner.release.xcconfig */,
+ EA780011634A6BC46817CBE0 /* Pods-Runner.profile.xcconfig */,
+ );
+ name = Pods;
+ path = Pods;
+ sourceTree = "";
+ };
+ 4204558B17A62367423769E8 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1F58D6DFA5E148E9B1E5401F /* Pods_Runner.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -72,6 +97,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
+ 10872F84FB14C7DD915284C6 /* Pods */,
+ 4204558B17A62367423769E8 /* Frameworks */,
);
sourceTree = "";
};
@@ -105,12 +132,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
+ B0C681F6443208846EBFB7D2 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ CF936C6216E6F00FB5F73F4C /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -197,6 +226,45 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
+ B0C681F6443208846EBFB7D2 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ CF936C6216E6F00FB5F73F4C /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
diff --git a/apps/wyatt_app_template/wyatt_app_template/ios/Runner.xcworkspace/contents.xcworkspacedata b/apps/wyatt_app_template/wyatt_app_template/ios/Runner.xcworkspace/contents.xcworkspacedata
index 1d526a1..21a3cc1 100644
--- a/apps/wyatt_app_template/wyatt_app_template/ios/Runner.xcworkspace/contents.xcworkspacedata
+++ b/apps/wyatt_app_template/wyatt_app_template/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,4 +4,7 @@
+
+
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/bootstrap.dart b/apps/wyatt_app_template/wyatt_app_template/lib/bootstrap.dart
index cf39bb3..fa13271 100644
--- a/apps/wyatt_app_template/wyatt_app_template/lib/bootstrap.dart
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/bootstrap.dart
@@ -2,14 +2,13 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:wyatt_app_template/core/dependency_injection/get_it.dart';
import 'package:wyatt_app_template/core/flavors/flavor.dart';
import 'package:wyatt_app_template/core/utils/app_bloc_observer.dart';
Future bootstrap(FutureOr Function() builder) async {
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
- FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
+ // FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
Bloc.observer = AppBlocObserver();
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/core/dependency_injection/get_it.dart b/apps/wyatt_app_template/wyatt_app_template/lib/core/dependency_injection/get_it.dart
index 5a5b94d..fa93316 100644
--- a/apps/wyatt_app_template/wyatt_app_template/lib/core/dependency_injection/get_it.dart
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/core/dependency_injection/get_it.dart
@@ -3,6 +3,8 @@ import 'dart:async';
import 'package:get_it/get_it.dart';
import 'package:wyatt_app_template/core/enums/dev_mode.dart';
import 'package:wyatt_app_template/core/flavors/flavor.dart';
+import 'package:wyatt_app_template/data/data_sources/local/counter_data_source_impl.dart';
+import 'package:wyatt_app_template/domain/data_sources/local/counter_data_source.dart';
final getIt = GetIt.I;
@@ -10,10 +12,13 @@ final getIt = GetIt.I;
abstract class GetItInitializer {
static FutureOr _initCommon() async {
// Initialize common sources/services
+ getIt.registerLazySingleton(
+ CounterDataSourceImpl.new,
+ );
}
static FutureOr _initMocks() async {
- // Initialize mocked sources/services
+ // Initialize mocked sources/services.
}
static FutureOr _initReal() async {
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/core/enums/dev_mode.dart b/apps/wyatt_app_template/wyatt_app_template/lib/core/enums/dev_mode.dart
index ab67a28..bd4ad84 100644
--- a/apps/wyatt_app_template/wyatt_app_template/lib/core/enums/dev_mode.dart
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/core/enums/dev_mode.dart
@@ -14,6 +14,7 @@ enum DevMode {
return m;
}
}
+
return fallback;
}
}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/core/flavors/flavor.dart b/apps/wyatt_app_template/wyatt_app_template/lib/core/flavors/flavor.dart
index 8c8657f..a4fd89e 100644
--- a/apps/wyatt_app_template/wyatt_app_template/lib/core/flavors/flavor.dart
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/core/flavors/flavor.dart
@@ -1,8 +1,10 @@
+import 'package:flutter/material.dart';
import 'package:wyatt_app_template/core/enums/dev_mode.dart';
abstract class Flavor {
Flavor._({
this.banner,
+ this.bannerColor = Colors.red,
this.devMode,
}) {
_instance = this;
@@ -11,6 +13,7 @@ abstract class Flavor {
static Flavor? _instance;
final String? banner;
+ final Color bannerColor;
final DevMode? devMode;
/// Returns [Flavor] instance.
@@ -18,6 +21,7 @@ abstract class Flavor {
if (_instance == null) {
throw Exception('Flavor not initialized!');
}
+
return _instance!;
}
@@ -35,7 +39,7 @@ class DevelopmentFlavor extends Flavor {
DevelopmentFlavor._({
required DevMode devMode,
}) : super._(
- banner: 'Mock',
+ banner: 'Dev',
devMode: devMode,
);
}
@@ -44,6 +48,7 @@ class StagingFlavor extends Flavor {
StagingFlavor()
: super._(
banner: 'Staging',
+ bannerColor: Colors.green,
);
}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/core/routes/router.dart b/apps/wyatt_app_template/wyatt_app_template/lib/core/routes/router.dart
index 79d65b2..c0a5220 100644
--- a/apps/wyatt_app_template/wyatt_app_template/lib/core/routes/router.dart
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/core/routes/router.dart
@@ -1,5 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:go_router/go_router.dart';
+import 'package:wyatt_app_template/presentation/features/counter/counter.dart';
+import 'package:wyatt_app_template/presentation/features/home/home.dart';
abstract class AppRouter {
/// Default transition for all pages
@@ -26,7 +28,7 @@ abstract class AppRouter {
);
/// Defines public routes (no authentication needed).
- ///
+ ///
/// Example:
/// ```dart
/// static final publicRoutes = [
@@ -38,5 +40,26 @@ abstract class AppRouter {
static final List publicRoutes = [];
/// Defines GoRoute routes.
- static final List routes = [];
+ static final List routes = [
+ GoRoute(
+ path: '/',
+ 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()),
+ ),
+ ];
+
+ /// Router
+ static GoRouter router = GoRouter(
+ initialLocation: '/',
+ routes: AppRouter.routes,
+ debugLogDiagnostics: true,
+ redirect: (context, state) => null,
+ );
}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/core/utils/app_bloc_observer.dart b/apps/wyatt_app_template/wyatt_app_template/lib/core/utils/app_bloc_observer.dart
index cb417f8..92be592 100644
--- a/apps/wyatt_app_template/wyatt_app_template/lib/core/utils/app_bloc_observer.dart
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/core/utils/app_bloc_observer.dart
@@ -1,7 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-const _messageLength = 120;
+const _messageLength = 100;
class AppBlocObserver extends BlocObserver {
AppBlocObserver({
@@ -20,6 +20,7 @@ class AppBlocObserver extends BlocObserver {
String sanitize(Object? object) {
final message = object.toString();
+
return fullPrint
? message
: message.substring(
@@ -32,16 +33,17 @@ class AppBlocObserver extends BlocObserver {
void onEvent(Bloc bloc, Object? event) {
super.onEvent(bloc, event);
if (printEvent) {
- debugPrint('onEvent(${bloc.runtimeType}, ${sanitize(event)})');
+ debugPrint('onEvent: ${bloc.runtimeType}\n'
+ '> event: ${sanitize(event)}');
}
}
@override
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
if (printError) {
- debugPrint(
- 'onError(${bloc.runtimeType}, ${sanitize(error)})\n$stackTrace',
- );
+ debugPrint('onError: ${bloc.runtimeType}\n'
+ '> error: ${sanitize(error)}\n'
+ '$stackTrace');
}
super.onError(bloc, error, stackTrace);
}
@@ -50,7 +52,9 @@ class AppBlocObserver extends BlocObserver {
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
if (printChange) {
- debugPrint('onChange(${bloc.runtimeType}, ${sanitize(change)})');
+ debugPrint('onChange: ${bloc.runtimeType}\n'
+ '> currentState: ${sanitize(change.currentState)}\n'
+ '> nextState: ${sanitize(change.nextState)}');
}
}
@@ -61,7 +65,10 @@ class AppBlocObserver extends BlocObserver {
) {
super.onTransition(bloc, transition);
if (printTransition) {
- debugPrint('onTransition(${bloc.runtimeType}, ${sanitize(transition)})');
+ debugPrint('onTransition: ${bloc.runtimeType}\n'
+ '> currentState: ${sanitize(transition.currentState)}\n'
+ '> event: ${sanitize(transition.event)}\n'
+ '> nextState: ${sanitize(transition.nextState)}');
}
}
}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/data/data_sources/local/counter_data_source_impl.dart b/apps/wyatt_app_template/wyatt_app_template/lib/data/data_sources/local/counter_data_source_impl.dart
new file mode 100644
index 0000000..2e48978
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/data/data_sources/local/counter_data_source_impl.dart
@@ -0,0 +1,59 @@
+import 'dart:convert';
+
+import 'package:wyatt_app_template/data/models/integer_model.dart';
+import 'package:wyatt_app_template/domain/data_sources/local/counter_data_source.dart';
+import 'package:wyatt_app_template/domain/entities/integer.dart';
+import 'package:wyatt_architecture/wyatt_architecture.dart';
+
+class CounterDataSourceImpl extends CounterDataSource {
+ // Simulate external data processing
+ String actual = '{"value": 0}';
+
+ @override
+ Future decrement(Integer value) async {
+ final current =
+ IntegerModel.fromJson(json.decode(actual) as Map);
+
+ final newValue = current.value - value.value;
+ if (newValue < 0) {
+ throw ClientException("Counter can't be negative!");
+ }
+
+ final newInteger = IntegerModel(value: newValue);
+ actual = jsonEncode(newInteger.toJson());
+
+ return newInteger;
+ }
+
+ @override
+ Future increment(Integer value) async {
+ final current =
+ IntegerModel.fromJson(json.decode(actual) as Map);
+
+ final newValue = current.value + value.value;
+ if (newValue < 0) {
+ throw ClientException("Counter can't be negative!");
+ }
+
+ final newInteger = IntegerModel(value: newValue);
+ actual = jsonEncode(newInteger.toJson());
+
+ return newInteger;
+ }
+
+ @override
+ Future getCurrent() async {
+ final current =
+ IntegerModel.fromJson(json.decode(actual) as Map);
+
+ return current;
+ }
+
+ @override
+ Future reset() async {
+ const newInteger = IntegerModel(value: 0);
+ actual = jsonEncode(newInteger.toJson());
+
+ return newInteger;
+ }
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/data/data_sources/remote/.gitkeep b/apps/wyatt_app_template/wyatt_app_template/lib/data/data_sources/remote/.gitkeep
new file mode 100644
index 0000000..f94cb6f
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/data/data_sources/remote/.gitkeep
@@ -0,0 +1 @@
+# just to keep empty folder in brick generation
\ No newline at end of file
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/data/models/integer_model.dart b/apps/wyatt_app_template/wyatt_app_template/lib/data/models/integer_model.dart
new file mode 100644
index 0000000..53b7c98
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/data/models/integer_model.dart
@@ -0,0 +1,15 @@
+import 'package:freezed_annotation/freezed_annotation.dart';
+import 'package:wyatt_app_template/domain/entities/integer.dart';
+
+part 'integer_model.freezed.dart';
+part 'integer_model.g.dart';
+
+@freezed
+class IntegerModel extends Integer with _$IntegerModel {
+ const factory IntegerModel({
+ required int value,
+ }) = _IntegerModel;
+
+ factory IntegerModel.fromJson(Map json) =>
+ _$IntegerModelFromJson(json);
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/data/models/integer_model.freezed.dart b/apps/wyatt_app_template/wyatt_app_template/lib/data/models/integer_model.freezed.dart
new file mode 100644
index 0000000..bed9972
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/data/models/integer_model.freezed.dart
@@ -0,0 +1,151 @@
+// coverage:ignore-file
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
+
+part of 'integer_model.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+T _$identity(T value) => value;
+
+final _privateConstructorUsedError = UnsupportedError(
+ 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
+
+IntegerModel _$IntegerModelFromJson(Map json) {
+ return _IntegerModel.fromJson(json);
+}
+
+/// @nodoc
+mixin _$IntegerModel {
+ int get value => throw _privateConstructorUsedError;
+
+ Map toJson() => throw _privateConstructorUsedError;
+ @JsonKey(ignore: true)
+ $IntegerModelCopyWith get copyWith =>
+ throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $IntegerModelCopyWith<$Res> {
+ factory $IntegerModelCopyWith(
+ IntegerModel value, $Res Function(IntegerModel) then) =
+ _$IntegerModelCopyWithImpl<$Res, IntegerModel>;
+ @useResult
+ $Res call({int value});
+}
+
+/// @nodoc
+class _$IntegerModelCopyWithImpl<$Res, $Val extends IntegerModel>
+ implements $IntegerModelCopyWith<$Res> {
+ _$IntegerModelCopyWithImpl(this._value, this._then);
+
+ // ignore: unused_field
+ final $Val _value;
+ // ignore: unused_field
+ final $Res Function($Val) _then;
+
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? value = null,
+ }) {
+ return _then(_value.copyWith(
+ value: null == value
+ ? _value.value
+ : value // ignore: cast_nullable_to_non_nullable
+ as int,
+ ) as $Val);
+ }
+}
+
+/// @nodoc
+abstract class _$$_IntegerModelCopyWith<$Res>
+ implements $IntegerModelCopyWith<$Res> {
+ factory _$$_IntegerModelCopyWith(
+ _$_IntegerModel value, $Res Function(_$_IntegerModel) then) =
+ __$$_IntegerModelCopyWithImpl<$Res>;
+ @override
+ @useResult
+ $Res call({int value});
+}
+
+/// @nodoc
+class __$$_IntegerModelCopyWithImpl<$Res>
+ extends _$IntegerModelCopyWithImpl<$Res, _$_IntegerModel>
+ implements _$$_IntegerModelCopyWith<$Res> {
+ __$$_IntegerModelCopyWithImpl(
+ _$_IntegerModel _value, $Res Function(_$_IntegerModel) _then)
+ : super(_value, _then);
+
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? value = null,
+ }) {
+ return _then(_$_IntegerModel(
+ value: null == value
+ ? _value.value
+ : value // ignore: cast_nullable_to_non_nullable
+ as int,
+ ));
+ }
+}
+
+/// @nodoc
+@JsonSerializable()
+class _$_IntegerModel implements _IntegerModel {
+ const _$_IntegerModel({required this.value});
+
+ factory _$_IntegerModel.fromJson(Map json) =>
+ _$$_IntegerModelFromJson(json);
+
+ @override
+ final int value;
+
+ @override
+ String toString() {
+ return 'IntegerModel(value: $value)';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType &&
+ other is _$_IntegerModel &&
+ (identical(other.value, value) || other.value == value));
+ }
+
+ @JsonKey(ignore: true)
+ @override
+ int get hashCode => Object.hash(runtimeType, value);
+
+ @JsonKey(ignore: true)
+ @override
+ @pragma('vm:prefer-inline')
+ _$$_IntegerModelCopyWith<_$_IntegerModel> get copyWith =>
+ __$$_IntegerModelCopyWithImpl<_$_IntegerModel>(this, _$identity);
+
+ @override
+ Map toJson() {
+ return _$$_IntegerModelToJson(
+ this,
+ );
+ }
+}
+
+abstract class _IntegerModel implements IntegerModel {
+ const factory _IntegerModel({required final int value}) = _$_IntegerModel;
+
+ factory _IntegerModel.fromJson(Map json) =
+ _$_IntegerModel.fromJson;
+
+ @override
+ int get value;
+ @override
+ @JsonKey(ignore: true)
+ _$$_IntegerModelCopyWith<_$_IntegerModel> get copyWith =>
+ throw _privateConstructorUsedError;
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/data/models/integer_model.g.dart b/apps/wyatt_app_template/wyatt_app_template/lib/data/models/integer_model.g.dart
new file mode 100644
index 0000000..291e5cf
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/data/models/integer_model.g.dart
@@ -0,0 +1,17 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'integer_model.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+_$_IntegerModel _$$_IntegerModelFromJson(Map json) =>
+ _$_IntegerModel(
+ value: json['value'] as int,
+ );
+
+Map _$$_IntegerModelToJson(_$_IntegerModel instance) =>
+ {
+ 'value': instance.value,
+ };
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/data/repositories/counter_repository_impl.dart b/apps/wyatt_app_template/wyatt_app_template/lib/data/repositories/counter_repository_impl.dart
new file mode 100644
index 0000000..934d42a
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/data/repositories/counter_repository_impl.dart
@@ -0,0 +1,41 @@
+import 'package:wyatt_app_template/domain/data_sources/local/counter_data_source.dart';
+import 'package:wyatt_app_template/domain/entities/integer.dart';
+import 'package:wyatt_app_template/domain/repositories/counter_repository.dart';
+import 'package:wyatt_architecture/wyatt_architecture.dart';
+import 'package:wyatt_type_utils/wyatt_type_utils.dart';
+
+class CounterRepositoryImpl extends CounterRepository {
+ CounterRepositoryImpl({
+ required CounterDataSource counterDataSource,
+ }) : _counterDataSource = counterDataSource;
+
+ final CounterDataSource _counterDataSource;
+
+ @override
+ FutureOrResult decrement({Integer by = const Integer(1)}) =>
+ Result.tryCatchAsync(
+ () async => _counterDataSource.decrement(by),
+ (error) => error,
+ );
+
+ @override
+ FutureOrResult increment({Integer by = const Integer(1)}) =>
+ Result.tryCatchAsync(
+ () async => _counterDataSource.increment(by),
+ (error) => error,
+ );
+
+ @override
+ FutureOrResult getCurrent() =>
+ Result.tryCatchAsync(
+ () async => _counterDataSource.getCurrent(),
+ (error) => error,
+ );
+
+ @override
+ FutureOrResult reset() =>
+ Result.tryCatchAsync(
+ () async => _counterDataSource.reset(),
+ (error) => error,
+ );
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/domain/data_sources/local/counter_data_source.dart b/apps/wyatt_app_template/wyatt_app_template/lib/domain/data_sources/local/counter_data_source.dart
new file mode 100644
index 0000000..fabb91a
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/domain/data_sources/local/counter_data_source.dart
@@ -0,0 +1,9 @@
+import 'package:wyatt_app_template/domain/entities/integer.dart';
+import 'package:wyatt_architecture/wyatt_architecture.dart';
+
+abstract class CounterDataSource extends BaseDataSource {
+ Future decrement(Integer value);
+ Future increment(Integer value);
+ Future getCurrent();
+ Future reset();
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/domain/data_sources/remote/.gitkeep b/apps/wyatt_app_template/wyatt_app_template/lib/domain/data_sources/remote/.gitkeep
new file mode 100644
index 0000000..f94cb6f
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/domain/data_sources/remote/.gitkeep
@@ -0,0 +1 @@
+# just to keep empty folder in brick generation
\ No newline at end of file
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/domain/entities/integer.dart b/apps/wyatt_app_template/wyatt_app_template/lib/domain/entities/integer.dart
new file mode 100644
index 0000000..aea24f1
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/domain/entities/integer.dart
@@ -0,0 +1,11 @@
+// ignore_for_file: public_member_api_docs, sort_constructors_first
+import 'package:wyatt_architecture/wyatt_architecture.dart';
+
+class Integer extends Entity {
+ const Integer(this.value);
+
+ final int value;
+
+ @override
+ String toString() => 'Integer(value: $value)';
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/domain/repositories/counter_repository.dart b/apps/wyatt_app_template/wyatt_app_template/lib/domain/repositories/counter_repository.dart
new file mode 100644
index 0000000..e3b7dd2
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/domain/repositories/counter_repository.dart
@@ -0,0 +1,9 @@
+import 'package:wyatt_app_template/domain/entities/integer.dart';
+import 'package:wyatt_architecture/wyatt_architecture.dart';
+
+abstract class CounterRepository extends BaseRepository {
+ FutureOrResult decrement({Integer by = const Integer(1)});
+ FutureOrResult increment({Integer by = const Integer(1)});
+ FutureOrResult getCurrent();
+ FutureOrResult reset();
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/decrement.dart b/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/decrement.dart
new file mode 100644
index 0000000..3825f48
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/decrement.dart
@@ -0,0 +1,18 @@
+import 'package:wyatt_app_template/domain/entities/integer.dart';
+import 'package:wyatt_app_template/domain/repositories/counter_repository.dart';
+import 'package:wyatt_architecture/wyatt_architecture.dart';
+
+class Decrement extends AsyncUseCase {
+ Decrement({
+ required CounterRepository counterRepository,
+ }) : _counterRepository = counterRepository;
+
+ final CounterRepository _counterRepository;
+
+ @override
+ FutureOrResult execute(int? params) async {
+ final step = Integer(params ?? 1);
+
+ return _counterRepository.decrement(by: step);
+ }
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/get_current.dart b/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/get_current.dart
new file mode 100644
index 0000000..4f1f5cd
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/get_current.dart
@@ -0,0 +1,31 @@
+// 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 .
+
+import 'package:wyatt_app_template/domain/entities/integer.dart';
+import 'package:wyatt_app_template/domain/repositories/counter_repository.dart';
+import 'package:wyatt_architecture/wyatt_architecture.dart';
+
+class GetCurrent extends AsyncUseCase {
+ GetCurrent({
+ required CounterRepository counterRepository,
+ }) : _counterRepository = counterRepository;
+
+ final CounterRepository _counterRepository;
+
+ @override
+ FutureOrResult execute(void params) async =>
+ _counterRepository.getCurrent();
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/increment.dart b/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/increment.dart
new file mode 100644
index 0000000..3eed0a2
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/increment.dart
@@ -0,0 +1,18 @@
+import 'package:wyatt_app_template/domain/entities/integer.dart';
+import 'package:wyatt_app_template/domain/repositories/counter_repository.dart';
+import 'package:wyatt_architecture/wyatt_architecture.dart';
+
+class Increment extends AsyncUseCase {
+ Increment({
+ required CounterRepository counterRepository,
+ }) : _counterRepository = counterRepository;
+
+ final CounterRepository _counterRepository;
+
+ @override
+ FutureOrResult execute(int? params) async {
+ final step = Integer(params ?? 1);
+
+ return _counterRepository.increment(by: step);
+ }
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/reset.dart b/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/reset.dart
new file mode 100644
index 0000000..ea1eb65
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/domain/usecases/counter/reset.dart
@@ -0,0 +1,31 @@
+// 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 .
+
+import 'package:wyatt_app_template/domain/entities/integer.dart';
+import 'package:wyatt_app_template/domain/repositories/counter_repository.dart';
+import 'package:wyatt_architecture/wyatt_architecture.dart';
+
+class Reset extends AsyncUseCase {
+ Reset({
+ required CounterRepository counterRepository,
+ }) : _counterRepository = counterRepository;
+
+ final CounterRepository _counterRepository;
+
+ @override
+ FutureOrResult execute(void params) async =>
+ _counterRepository.reset();
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/gen/assets.gen.dart b/apps/wyatt_app_template/wyatt_app_template/lib/gen/assets.gen.dart
new file mode 100644
index 0000000..3deea52
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/gen/assets.gen.dart
@@ -0,0 +1,92 @@
+/// GENERATED CODE - DO NOT MODIFY BY HAND
+/// *****************************************************
+/// FlutterGen
+/// *****************************************************
+
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal
+
+import 'package:flutter/widgets.dart';
+
+class $AssetsImagesGen {
+ const $AssetsImagesGen();
+
+ /// File path: assets/images/wyatt_logo.jpeg
+ AssetGenImage get wyattLogo =>
+ const AssetGenImage('assets/images/wyatt_logo.jpeg');
+
+ /// List of all assets
+ List get values => [wyattLogo];
+}
+
+class Assets {
+ Assets._();
+
+ static const $AssetsImagesGen images = $AssetsImagesGen();
+}
+
+class AssetGenImage {
+ const AssetGenImage(this._assetName);
+
+ final String _assetName;
+
+ Image image({
+ Key? key,
+ AssetBundle? bundle,
+ ImageFrameBuilder? frameBuilder,
+ ImageErrorWidgetBuilder? errorBuilder,
+ String? semanticLabel,
+ bool excludeFromSemantics = false,
+ double? scale,
+ double? width,
+ double? height,
+ Color? color,
+ Animation? opacity,
+ BlendMode? colorBlendMode,
+ BoxFit? fit,
+ AlignmentGeometry alignment = Alignment.center,
+ ImageRepeat repeat = ImageRepeat.noRepeat,
+ Rect? centerSlice,
+ bool matchTextDirection = false,
+ bool gaplessPlayback = false,
+ bool isAntiAlias = false,
+ String? package,
+ FilterQuality filterQuality = FilterQuality.low,
+ int? cacheWidth,
+ int? cacheHeight,
+ }) {
+ return Image.asset(
+ _assetName,
+ key: key,
+ bundle: bundle,
+ frameBuilder: frameBuilder,
+ errorBuilder: errorBuilder,
+ semanticLabel: semanticLabel,
+ excludeFromSemantics: excludeFromSemantics,
+ scale: scale,
+ width: width,
+ height: height,
+ color: color,
+ opacity: opacity,
+ colorBlendMode: colorBlendMode,
+ fit: fit,
+ alignment: alignment,
+ repeat: repeat,
+ centerSlice: centerSlice,
+ matchTextDirection: matchTextDirection,
+ gaplessPlayback: gaplessPlayback,
+ isAntiAlias: isAntiAlias,
+ package: package,
+ filterQuality: filterQuality,
+ cacheWidth: cacheWidth,
+ cacheHeight: cacheHeight,
+ );
+ }
+
+ ImageProvider provider() => AssetImage(_assetName);
+
+ String get path => _assetName;
+
+ String get keyName => _assetName;
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/gen/colors.gen.dart b/apps/wyatt_app_template/wyatt_app_template/lib/gen/colors.gen.dart
new file mode 100644
index 0000000..7140be2
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/gen/colors.gen.dart
@@ -0,0 +1,21 @@
+/// GENERATED CODE - DO NOT MODIFY BY HAND
+/// *****************************************************
+/// FlutterGen
+/// *****************************************************
+
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal
+
+import 'package:flutter/painting.dart';
+import 'package:flutter/material.dart';
+
+class ColorName {
+ ColorName._();
+
+ /// Color: #000000
+ static const Color black = Color(0xFF000000);
+
+ /// Color: #FFFFFF
+ static const Color white = Color(0xFFFFFFFF);
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/main_development.dart b/apps/wyatt_app_template/wyatt_app_template/lib/main_development.dart
index 158d435..137498e 100644
--- a/apps/wyatt_app_template/wyatt_app_template/lib/main_development.dart
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/main_development.dart
@@ -1,11 +1,11 @@
-import 'package:flutter/material.dart';
import 'package:wyatt_app_template/bootstrap.dart';
import 'package:wyatt_app_template/core/flavors/flavor.dart';
+import 'package:wyatt_app_template/presentation/features/app/app.dart';
void main(List args) {
// Define environment
DevelopmentFlavor();
// Initialize environment and variables
- bootstrap(() async => Container());
+ bootstrap(App.new);
}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/main_production.dart b/apps/wyatt_app_template/wyatt_app_template/lib/main_production.dart
index 69fdf89..525233f 100644
--- a/apps/wyatt_app_template/wyatt_app_template/lib/main_production.dart
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/main_production.dart
@@ -1,11 +1,11 @@
-import 'package:flutter/material.dart';
import 'package:wyatt_app_template/bootstrap.dart';
import 'package:wyatt_app_template/core/flavors/flavor.dart';
+import 'package:wyatt_app_template/presentation/features/app/app.dart';
void main(List args) {
// Define environment
ProductionFlavor();
// Initialize environment and variables
- bootstrap(() async => Container());
+ bootstrap(App.new);
}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/main_staging.dart b/apps/wyatt_app_template/wyatt_app_template/lib/main_staging.dart
index 5d63b09..b489323 100644
--- a/apps/wyatt_app_template/wyatt_app_template/lib/main_staging.dart
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/main_staging.dart
@@ -1,11 +1,11 @@
-import 'package:flutter/material.dart';
import 'package:wyatt_app_template/bootstrap.dart';
import 'package:wyatt_app_template/core/flavors/flavor.dart';
+import 'package:wyatt_app_template/presentation/features/app/app.dart';
void main(List args) {
// Define environment
StagingFlavor();
// Initialize environment and variables
- bootstrap(() async => Container());
+ bootstrap(App.new);
}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/presentation/features/app/app.dart b/apps/wyatt_app_template/wyatt_app_template/lib/presentation/features/app/app.dart
new file mode 100644
index 0000000..7825f54
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/presentation/features/app/app.dart
@@ -0,0 +1,63 @@
+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:wyatt_app_template/core/dependency_injection/get_it.dart';
+import 'package:wyatt_app_template/core/flavors/flavor.dart';
+import 'package:wyatt_app_template/core/routes/router.dart';
+import 'package:wyatt_app_template/data/repositories/counter_repository_impl.dart';
+import 'package:wyatt_app_template/domain/repositories/counter_repository.dart';
+import 'package:wyatt_app_template/gen/app_localizations.dart';
+import 'package:wyatt_app_template/presentation/features/counter/blocs/counter_bloc/counter_bloc.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(
+ create: (_) => CounterRepositoryImpl(counterDataSource: getIt()),
+ ),
+ ],
+ blocProviders: [
+ BlocProvider(
+ create: (_) => CounterBloc(),
+ ),
+ ],
+ child: _flavorBanner(
+ MaterialApp.router(
+ title: 'Wyatt App',
+ 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,
+ ),
+ ),
+ );
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/presentation/features/counter/blocs/counter_bloc/counter_bloc.dart b/apps/wyatt_app_template/wyatt_app_template/lib/presentation/features/counter/blocs/counter_bloc/counter_bloc.dart
new file mode 100644
index 0000000..cd0683d
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/presentation/features/counter/blocs/counter_bloc/counter_bloc.dart
@@ -0,0 +1,27 @@
+import 'dart:async';
+
+import 'package:equatable/equatable.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+part 'counter_event.dart';
+part 'counter_state.dart';
+
+/// {@template counter_bloc}
+/// CounterBloc description
+/// {@endtemplate}
+class CounterBloc extends Bloc {
+ /// {@macro counter_bloc}
+ CounterBloc() : super(const CounterInitial()) {
+ on(_onCustomCounterEvent);
+ }
+
+ FutureOr _onCustomCounterEvent(
+ CustomCounterEvent event,
+ Emitter emit,
+ ) async {
+ // TODO(wyatt): Add custom UI logic
+ const _ = 1 + 1;
+
+ return;
+ }
+}
diff --git a/apps/wyatt_app_template/wyatt_app_template/lib/presentation/features/counter/blocs/counter_bloc/counter_event.dart b/apps/wyatt_app_template/wyatt_app_template/lib/presentation/features/counter/blocs/counter_bloc/counter_event.dart
new file mode 100644
index 0000000..49c34d2
--- /dev/null
+++ b/apps/wyatt_app_template/wyatt_app_template/lib/presentation/features/counter/blocs/counter_bloc/counter_event.dart
@@ -0,0 +1,20 @@
+part of 'counter_bloc.dart';
+
+/// {@template counter_event}
+/// CounterEvent description
+/// {@endtemplate}
+abstract class CounterEvent extends Equatable {
+ /// {@macro counter_event}
+ const CounterEvent();
+}
+
+/// {@template custom_counter_event}
+/// Event added when some custom logic happens
+/// {@endtemplate}
+class CustomCounterEvent extends CounterEvent {
+ /// {@macro custom_counter_event}
+ const CustomCounterEvent();
+
+ @override
+ List