feat: add web in new template
This commit is contained in:
parent
0c10a900a6
commit
07f16dc512
@ -11,18 +11,21 @@ vars:
|
|||||||
description: The display name
|
description: The display name
|
||||||
default: Wyatt App
|
default: Wyatt App
|
||||||
prompt: "What is the display name?"
|
prompt: "What is the display name?"
|
||||||
|
|
||||||
project_name:
|
project_name:
|
||||||
name: wyatt_app_template
|
name: wyatt_app_template
|
||||||
type: string
|
type: string
|
||||||
description: The project name
|
description: The project name
|
||||||
default: wyatt_app
|
default: wyatt_app
|
||||||
prompt: "What is the project name?"
|
prompt: "What is the project name?"
|
||||||
org_name:
|
|
||||||
|
bundle_id:
|
||||||
name: io.wyattapp.new
|
name: io.wyattapp.new
|
||||||
type: string
|
type: string
|
||||||
description: The organization name
|
description: The bundle id used in Android and iOS
|
||||||
default: io.wyattapp.new
|
default: io.wyattapp.new
|
||||||
prompt: "What is the organization name?"
|
prompt: "What is the bundle id?"
|
||||||
|
|
||||||
description:
|
description:
|
||||||
name: wyatt_description
|
name: wyatt_description
|
||||||
type: string
|
type: string
|
||||||
|
@ -15,10 +15,7 @@ migration:
|
|||||||
- platform: root
|
- platform: root
|
||||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||||
- platform: android
|
- platform: web
|
||||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
|
||||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
|
||||||
- platform: ios
|
|
||||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||||
|
|
||||||
|
@ -4,6 +4,56 @@ wyatt_description
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- 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`)
|
* Trapeze <https://trapeze.dev/> (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=<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.
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
include: package:wyatt_analysis/analysis_options.flutter.yaml
|
include: package:wyatt_analysis/analysis_options.flutter.yaml
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
plugins:
|
||||||
|
- dart_code_metrics
|
||||||
|
|
||||||
dart_code_metrics:
|
dart_code_metrics:
|
||||||
anti-patterns:
|
anti-patterns:
|
||||||
- long-method
|
- long-method
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
# just to keep empty folder in brick generation
|
28
apps/wyatt_app_template/wyatt_app_template/ios/Podfile.lock
Normal file
28
apps/wyatt_app_template/wyatt_app_template/ios/Podfile.lock
Normal file
@ -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
|
@ -9,6 +9,7 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
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 */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
@ -29,8 +30,11 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference 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 = "<group>"; };
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
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 = "<group>"; };
|
||||||
|
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 = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
@ -42,6 +46,7 @@
|
|||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
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 = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -49,12 +54,32 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
50F1D9CF301DADBFF7F91098 /* Pods_Runner.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup 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 = "<group>";
|
||||||
|
};
|
||||||
|
4204558B17A62367423769E8 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
1F58D6DFA5E148E9B1E5401F /* Pods_Runner.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -72,6 +97,8 @@
|
|||||||
9740EEB11CF90186004384FC /* Flutter */,
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
|
10872F84FB14C7DD915284C6 /* Pods */,
|
||||||
|
4204558B17A62367423769E8 /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -105,12 +132,14 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
B0C681F6443208846EBFB7D2 /* [CP] Check Pods Manifest.lock */,
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
|
CF936C6216E6F00FB5F73F4C /* [CP] Embed Pods Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -197,6 +226,45 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
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 */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
@ -4,4 +4,7 @@
|
|||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
@ -2,14 +2,13 @@ import 'dart:async';
|
|||||||
|
|
||||||
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_native_splash/flutter_native_splash.dart';
|
|
||||||
import 'package:wyatt_app_template/core/dependency_injection/get_it.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/flavors/flavor.dart';
|
||||||
import 'package:wyatt_app_template/core/utils/app_bloc_observer.dart';
|
import 'package:wyatt_app_template/core/utils/app_bloc_observer.dart';
|
||||||
|
|
||||||
Future<void> bootstrap(FutureOr<Widget> Function() builder) async {
|
Future<void> bootstrap(FutureOr<Widget> Function() builder) async {
|
||||||
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
||||||
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
// FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||||
|
|
||||||
Bloc.observer = AppBlocObserver();
|
Bloc.observer = AppBlocObserver();
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ import 'dart:async';
|
|||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:wyatt_app_template/core/enums/dev_mode.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/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;
|
final getIt = GetIt.I;
|
||||||
|
|
||||||
@ -10,10 +12,13 @@ final getIt = GetIt.I;
|
|||||||
abstract class GetItInitializer {
|
abstract class GetItInitializer {
|
||||||
static FutureOr<void> _initCommon() async {
|
static FutureOr<void> _initCommon() async {
|
||||||
// Initialize common sources/services
|
// Initialize common sources/services
|
||||||
|
getIt.registerLazySingleton<CounterDataSource>(
|
||||||
|
CounterDataSourceImpl.new,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FutureOr<void> _initMocks() async {
|
static FutureOr<void> _initMocks() async {
|
||||||
// Initialize mocked sources/services
|
// Initialize mocked sources/services.
|
||||||
}
|
}
|
||||||
|
|
||||||
static FutureOr<void> _initReal() async {
|
static FutureOr<void> _initReal() async {
|
||||||
|
@ -14,6 +14,7 @@ enum DevMode {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:wyatt_app_template/core/enums/dev_mode.dart';
|
import 'package:wyatt_app_template/core/enums/dev_mode.dart';
|
||||||
|
|
||||||
abstract class Flavor {
|
abstract class Flavor {
|
||||||
Flavor._({
|
Flavor._({
|
||||||
this.banner,
|
this.banner,
|
||||||
|
this.bannerColor = Colors.red,
|
||||||
this.devMode,
|
this.devMode,
|
||||||
}) {
|
}) {
|
||||||
_instance = this;
|
_instance = this;
|
||||||
@ -11,6 +13,7 @@ abstract class Flavor {
|
|||||||
static Flavor? _instance;
|
static Flavor? _instance;
|
||||||
|
|
||||||
final String? banner;
|
final String? banner;
|
||||||
|
final Color bannerColor;
|
||||||
final DevMode? devMode;
|
final DevMode? devMode;
|
||||||
|
|
||||||
/// Returns [Flavor] instance.
|
/// Returns [Flavor] instance.
|
||||||
@ -18,6 +21,7 @@ abstract class Flavor {
|
|||||||
if (_instance == null) {
|
if (_instance == null) {
|
||||||
throw Exception('Flavor not initialized!');
|
throw Exception('Flavor not initialized!');
|
||||||
}
|
}
|
||||||
|
|
||||||
return _instance!;
|
return _instance!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +39,7 @@ class DevelopmentFlavor extends Flavor {
|
|||||||
DevelopmentFlavor._({
|
DevelopmentFlavor._({
|
||||||
required DevMode devMode,
|
required DevMode devMode,
|
||||||
}) : super._(
|
}) : super._(
|
||||||
banner: 'Mock',
|
banner: 'Dev',
|
||||||
devMode: devMode,
|
devMode: devMode,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -44,6 +48,7 @@ class StagingFlavor extends Flavor {
|
|||||||
StagingFlavor()
|
StagingFlavor()
|
||||||
: super._(
|
: super._(
|
||||||
banner: 'Staging',
|
banner: 'Staging',
|
||||||
|
bannerColor: Colors.green,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
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:wyatt_app_template/presentation/features/counter/counter.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/features/home/home.dart';
|
||||||
|
|
||||||
abstract class AppRouter {
|
abstract class AppRouter {
|
||||||
/// Default transition for all pages
|
/// Default transition for all pages
|
||||||
@ -38,5 +40,26 @@ abstract class AppRouter {
|
|||||||
static final List<String> publicRoutes = [];
|
static final List<String> publicRoutes = [];
|
||||||
|
|
||||||
/// Defines GoRoute routes.
|
/// Defines GoRoute routes.
|
||||||
static final List<GoRoute> routes = [];
|
static final List<GoRoute> 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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
const _messageLength = 120;
|
const _messageLength = 100;
|
||||||
|
|
||||||
class AppBlocObserver extends BlocObserver {
|
class AppBlocObserver extends BlocObserver {
|
||||||
AppBlocObserver({
|
AppBlocObserver({
|
||||||
@ -20,6 +20,7 @@ class AppBlocObserver extends BlocObserver {
|
|||||||
|
|
||||||
String sanitize(Object? object) {
|
String sanitize(Object? object) {
|
||||||
final message = object.toString();
|
final message = object.toString();
|
||||||
|
|
||||||
return fullPrint
|
return fullPrint
|
||||||
? message
|
? message
|
||||||
: message.substring(
|
: message.substring(
|
||||||
@ -32,16 +33,17 @@ class AppBlocObserver extends BlocObserver {
|
|||||||
void onEvent(Bloc<dynamic, dynamic> bloc, Object? event) {
|
void onEvent(Bloc<dynamic, dynamic> bloc, Object? event) {
|
||||||
super.onEvent(bloc, event);
|
super.onEvent(bloc, event);
|
||||||
if (printEvent) {
|
if (printEvent) {
|
||||||
debugPrint('onEvent(${bloc.runtimeType}, ${sanitize(event)})');
|
debugPrint('onEvent: ${bloc.runtimeType}\n'
|
||||||
|
'> event: ${sanitize(event)}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onError(BlocBase<dynamic> bloc, Object error, StackTrace stackTrace) {
|
void onError(BlocBase<dynamic> bloc, Object error, StackTrace stackTrace) {
|
||||||
if (printError) {
|
if (printError) {
|
||||||
debugPrint(
|
debugPrint('onError: ${bloc.runtimeType}\n'
|
||||||
'onError(${bloc.runtimeType}, ${sanitize(error)})\n$stackTrace',
|
'> error: ${sanitize(error)}\n'
|
||||||
);
|
'$stackTrace');
|
||||||
}
|
}
|
||||||
super.onError(bloc, error, stackTrace);
|
super.onError(bloc, error, stackTrace);
|
||||||
}
|
}
|
||||||
@ -50,7 +52,9 @@ class AppBlocObserver extends BlocObserver {
|
|||||||
void onChange(BlocBase<dynamic> bloc, Change<dynamic> change) {
|
void onChange(BlocBase<dynamic> bloc, Change<dynamic> change) {
|
||||||
super.onChange(bloc, change);
|
super.onChange(bloc, change);
|
||||||
if (printChange) {
|
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);
|
super.onTransition(bloc, transition);
|
||||||
if (printTransition) {
|
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)}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<Integer> decrement(Integer value) async {
|
||||||
|
final current =
|
||||||
|
IntegerModel.fromJson(json.decode(actual) as Map<String, Object?>);
|
||||||
|
|
||||||
|
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<Integer> increment(Integer value) async {
|
||||||
|
final current =
|
||||||
|
IntegerModel.fromJson(json.decode(actual) as Map<String, Object?>);
|
||||||
|
|
||||||
|
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<Integer> getCurrent() async {
|
||||||
|
final current =
|
||||||
|
IntegerModel.fromJson(json.decode(actual) as Map<String, Object?>);
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Integer> reset() async {
|
||||||
|
const newInteger = IntegerModel(value: 0);
|
||||||
|
actual = jsonEncode(newInteger.toJson());
|
||||||
|
|
||||||
|
return newInteger;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
# just to keep empty folder in brick generation
|
@ -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<String, Object?> json) =>
|
||||||
|
_$IntegerModelFromJson(json);
|
||||||
|
}
|
@ -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>(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<String, dynamic> json) {
|
||||||
|
return _IntegerModel.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$IntegerModel {
|
||||||
|
int get value => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$IntegerModelCopyWith<IntegerModel> 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<String, dynamic> 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<String, dynamic> toJson() {
|
||||||
|
return _$$_IntegerModelToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _IntegerModel implements IntegerModel {
|
||||||
|
const factory _IntegerModel({required final int value}) = _$_IntegerModel;
|
||||||
|
|
||||||
|
factory _IntegerModel.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$_IntegerModel.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get value;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$_IntegerModelCopyWith<_$_IntegerModel> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'integer_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$_IntegerModel _$$_IntegerModelFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_IntegerModel(
|
||||||
|
value: json['value'] as int,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_IntegerModelToJson(_$_IntegerModel instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'value': instance.value,
|
||||||
|
};
|
@ -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<Integer> decrement({Integer by = const Integer(1)}) =>
|
||||||
|
Result.tryCatchAsync<Integer, AppException, AppException>(
|
||||||
|
() async => _counterDataSource.decrement(by),
|
||||||
|
(error) => error,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<Integer> increment({Integer by = const Integer(1)}) =>
|
||||||
|
Result.tryCatchAsync<Integer, AppException, AppException>(
|
||||||
|
() async => _counterDataSource.increment(by),
|
||||||
|
(error) => error,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<Integer> getCurrent() =>
|
||||||
|
Result.tryCatchAsync<Integer, AppException, AppException>(
|
||||||
|
() async => _counterDataSource.getCurrent(),
|
||||||
|
(error) => error,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<Integer> reset() =>
|
||||||
|
Result.tryCatchAsync<Integer, AppException, AppException>(
|
||||||
|
() async => _counterDataSource.reset(),
|
||||||
|
(error) => error,
|
||||||
|
);
|
||||||
|
}
|
@ -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<Integer> decrement(Integer value);
|
||||||
|
Future<Integer> increment(Integer value);
|
||||||
|
Future<Integer> getCurrent();
|
||||||
|
Future<Integer> reset();
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
# just to keep empty folder in brick generation
|
@ -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)';
|
||||||
|
}
|
@ -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<Integer> decrement({Integer by = const Integer(1)});
|
||||||
|
FutureOrResult<Integer> increment({Integer by = const Integer(1)});
|
||||||
|
FutureOrResult<Integer> getCurrent();
|
||||||
|
FutureOrResult<Integer> reset();
|
||||||
|
}
|
@ -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<int, Integer> {
|
||||||
|
Decrement({
|
||||||
|
required CounterRepository counterRepository,
|
||||||
|
}) : _counterRepository = counterRepository;
|
||||||
|
|
||||||
|
final CounterRepository _counterRepository;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<Integer> execute(int? params) async {
|
||||||
|
final step = Integer(params ?? 1);
|
||||||
|
|
||||||
|
return _counterRepository.decrement(by: step);
|
||||||
|
}
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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<void, Integer> {
|
||||||
|
GetCurrent({
|
||||||
|
required CounterRepository counterRepository,
|
||||||
|
}) : _counterRepository = counterRepository;
|
||||||
|
|
||||||
|
final CounterRepository _counterRepository;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<Integer> execute(void params) async =>
|
||||||
|
_counterRepository.getCurrent();
|
||||||
|
}
|
@ -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<int, Integer> {
|
||||||
|
Increment({
|
||||||
|
required CounterRepository counterRepository,
|
||||||
|
}) : _counterRepository = counterRepository;
|
||||||
|
|
||||||
|
final CounterRepository _counterRepository;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<Integer> execute(int? params) async {
|
||||||
|
final step = Integer(params ?? 1);
|
||||||
|
|
||||||
|
return _counterRepository.increment(by: step);
|
||||||
|
}
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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<void, Integer> {
|
||||||
|
Reset({
|
||||||
|
required CounterRepository counterRepository,
|
||||||
|
}) : _counterRepository = counterRepository;
|
||||||
|
|
||||||
|
final CounterRepository _counterRepository;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<Integer> execute(void params) async =>
|
||||||
|
_counterRepository.reset();
|
||||||
|
}
|
@ -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<AssetGenImage> 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<double>? 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;
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:wyatt_app_template/bootstrap.dart';
|
import 'package:wyatt_app_template/bootstrap.dart';
|
||||||
import 'package:wyatt_app_template/core/flavors/flavor.dart';
|
import 'package:wyatt_app_template/core/flavors/flavor.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/features/app/app.dart';
|
||||||
|
|
||||||
void main(List<String> args) {
|
void main(List<String> args) {
|
||||||
// Define environment
|
// Define environment
|
||||||
DevelopmentFlavor();
|
DevelopmentFlavor();
|
||||||
|
|
||||||
// Initialize environment and variables
|
// Initialize environment and variables
|
||||||
bootstrap(() async => Container());
|
bootstrap(App.new);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:wyatt_app_template/bootstrap.dart';
|
import 'package:wyatt_app_template/bootstrap.dart';
|
||||||
import 'package:wyatt_app_template/core/flavors/flavor.dart';
|
import 'package:wyatt_app_template/core/flavors/flavor.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/features/app/app.dart';
|
||||||
|
|
||||||
void main(List<String> args) {
|
void main(List<String> args) {
|
||||||
// Define environment
|
// Define environment
|
||||||
ProductionFlavor();
|
ProductionFlavor();
|
||||||
|
|
||||||
// Initialize environment and variables
|
// Initialize environment and variables
|
||||||
bootstrap(() async => Container());
|
bootstrap(App.new);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:wyatt_app_template/bootstrap.dart';
|
import 'package:wyatt_app_template/bootstrap.dart';
|
||||||
import 'package:wyatt_app_template/core/flavors/flavor.dart';
|
import 'package:wyatt_app_template/core/flavors/flavor.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/features/app/app.dart';
|
||||||
|
|
||||||
void main(List<String> args) {
|
void main(List<String> args) {
|
||||||
// Define environment
|
// Define environment
|
||||||
StagingFlavor();
|
StagingFlavor();
|
||||||
|
|
||||||
// Initialize environment and variables
|
// Initialize environment and variables
|
||||||
bootstrap(() async => Container());
|
bootstrap(App.new);
|
||||||
}
|
}
|
||||||
|
@ -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<CounterRepository>(
|
||||||
|
create: (_) => CounterRepositoryImpl(counterDataSource: getIt()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
blocProviders: [
|
||||||
|
BlocProvider<CounterBloc>(
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
@ -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<CounterEvent, CounterState> {
|
||||||
|
/// {@macro counter_bloc}
|
||||||
|
CounterBloc() : super(const CounterInitial()) {
|
||||||
|
on<CustomCounterEvent>(_onCustomCounterEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureOr<void> _onCustomCounterEvent(
|
||||||
|
CustomCounterEvent event,
|
||||||
|
Emitter<CounterState> emit,
|
||||||
|
) async {
|
||||||
|
// TODO(wyatt): Add custom UI logic
|
||||||
|
const _ = 1 + 1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
@ -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<Object?> get props => [];
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
part of 'counter_bloc.dart';
|
||||||
|
|
||||||
|
/// {@template counter_state}
|
||||||
|
/// CounterState description
|
||||||
|
/// {@endtemplate}
|
||||||
|
abstract class CounterState extends Equatable {
|
||||||
|
/// {@macro counter_state}
|
||||||
|
const CounterState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@template counter_initial}
|
||||||
|
/// The initial state of CounterState
|
||||||
|
/// {@endtemplate}
|
||||||
|
class CounterInitial extends CounterState {
|
||||||
|
/// {@macro counter_initial}
|
||||||
|
const CounterInitial();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:wyatt_app_template/domain/usecases/counter/decrement.dart';
|
||||||
|
import 'package:wyatt_app_template/domain/usecases/counter/get_current.dart';
|
||||||
|
import 'package:wyatt_app_template/domain/usecases/counter/increment.dart';
|
||||||
|
import 'package:wyatt_app_template/domain/usecases/counter/reset.dart';
|
||||||
|
|
||||||
|
part 'counter_state.dart';
|
||||||
|
|
||||||
|
/// {@template counter_cubit}
|
||||||
|
/// CounterCubit manages UI depending on counter state.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class CounterCubit extends Cubit<CounterState> {
|
||||||
|
/// {@macro counter_cubit}
|
||||||
|
CounterCubit({
|
||||||
|
required Decrement decrement,
|
||||||
|
required Increment increment,
|
||||||
|
required GetCurrent getCurrent,
|
||||||
|
required Reset reset,
|
||||||
|
}) : _decrement = decrement,
|
||||||
|
_increment = increment,
|
||||||
|
_getCurrent = getCurrent,
|
||||||
|
_reset = reset,
|
||||||
|
super(const CounterState(0));
|
||||||
|
|
||||||
|
final Decrement _decrement;
|
||||||
|
final Increment _increment;
|
||||||
|
final GetCurrent _getCurrent;
|
||||||
|
final Reset _reset;
|
||||||
|
|
||||||
|
/// Decrement counter.
|
||||||
|
FutureOr<void> decrement([int by = 1]) async {
|
||||||
|
final result = await _decrement.call(by);
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(integer) => emit(CounterState(integer.value)),
|
||||||
|
addError,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increment counter.
|
||||||
|
FutureOr<void> increment([int by = 1]) async {
|
||||||
|
final result = await _increment.call(by);
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(integer) => emit(CounterState(integer.value)),
|
||||||
|
addError,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get current counter state.
|
||||||
|
FutureOr<void> getCurrent() async {
|
||||||
|
final result = await _getCurrent.call(null);
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(integer) => emit(CounterState(integer.value)),
|
||||||
|
addError,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset counter state.
|
||||||
|
FutureOr<void> reset() async {
|
||||||
|
final result = await _reset.call(null);
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(integer) => emit(CounterState(integer.value)),
|
||||||
|
addError,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onError(Object error, StackTrace stackTrace) {
|
||||||
|
emit(state);
|
||||||
|
super.onError(error, stackTrace);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
part of 'counter_cubit.dart';
|
||||||
|
|
||||||
|
/// {@template counter_state}
|
||||||
|
/// CounterState containing counter value
|
||||||
|
/// {@endtemplate}
|
||||||
|
class CounterState extends Equatable {
|
||||||
|
/// {@macro counter_state}
|
||||||
|
const CounterState(this.value);
|
||||||
|
|
||||||
|
final int value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [value];
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/features/counter/screens/counter_provider.dart';
|
||||||
|
|
||||||
|
class Counter extends StatelessWidget {
|
||||||
|
const Counter({super.key});
|
||||||
|
|
||||||
|
static const String pageName = 'counterPage';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => const CounterProvider();
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:wyatt_app_template/core/extensions/build_context_extension.dart';
|
||||||
|
import 'package:wyatt_app_template/domain/repositories/counter_repository.dart';
|
||||||
|
import 'package:wyatt_app_template/domain/usecases/counter/decrement.dart';
|
||||||
|
import 'package:wyatt_app_template/domain/usecases/counter/get_current.dart';
|
||||||
|
import 'package:wyatt_app_template/domain/usecases/counter/increment.dart';
|
||||||
|
import 'package:wyatt_app_template/domain/usecases/counter/reset.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/features/counter/blocs/counter_cubit/counter_cubit.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/features/counter/screens/widgets/counter_consumer_widget.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/shared/layouts/wyatt_app_template_scaffold.dart';
|
||||||
|
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
|
||||||
|
|
||||||
|
/// {@template counter_provider}
|
||||||
|
/// CounterProvider provides bloc to his children.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class CounterProvider extends CubitProviderScreen<CounterCubit, CounterState> {
|
||||||
|
/// {@macro counter_provider}
|
||||||
|
const CounterProvider({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
CounterCubit create(BuildContext context) => CounterCubit(
|
||||||
|
decrement: Decrement(
|
||||||
|
counterRepository: repo<CounterRepository>(context),
|
||||||
|
),
|
||||||
|
increment: Increment(
|
||||||
|
counterRepository: repo<CounterRepository>(context),
|
||||||
|
),
|
||||||
|
getCurrent: GetCurrent(
|
||||||
|
counterRepository: repo<CounterRepository>(context),
|
||||||
|
),
|
||||||
|
reset: Reset(
|
||||||
|
counterRepository: repo<CounterRepository>(context),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
CounterCubit init(BuildContext context, CounterCubit bloc) =>
|
||||||
|
bloc..getCurrent();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget builder(BuildContext context) => WyattAppTemplateScaffold(
|
||||||
|
title: Text(context.l10n.counterAppBarTitle),
|
||||||
|
body: const CounterConsumerWidget(),
|
||||||
|
fabChildren: [
|
||||||
|
FloatingActionButton(
|
||||||
|
heroTag: 'increment_tag',
|
||||||
|
onPressed: () => bloc(context).increment(),
|
||||||
|
child: const Icon(Icons.add),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
FloatingActionButton(
|
||||||
|
heroTag: 'increment_10_tag',
|
||||||
|
onPressed: () => bloc(context).increment(10),
|
||||||
|
child: const Text('+10'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
FloatingActionButton(
|
||||||
|
heroTag: 'decrement_tag',
|
||||||
|
onPressed: () => bloc(context).decrement(),
|
||||||
|
child: const Icon(Icons.remove),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
FloatingActionButton(
|
||||||
|
heroTag: 'decrement_10_tag',
|
||||||
|
onPressed: () => bloc(context).decrement(10),
|
||||||
|
child: const Text('-10'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
FloatingActionButton(
|
||||||
|
heroTag: 'reset_tag',
|
||||||
|
onPressed: () => bloc(context).reset(),
|
||||||
|
child: const Icon(Icons.refresh),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:wyatt_app_template/core/extensions/build_context_extension.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/features/counter/blocs/counter_cubit/counter_cubit.dart';
|
||||||
|
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
|
||||||
|
|
||||||
|
/// {@template counter_consumer_widget}
|
||||||
|
/// CounterConsumerWidget is a stateful widget. Aware of state changes.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class CounterConsumerWidget
|
||||||
|
extends CubitConsumerScreen<CounterCubit, CounterState> {
|
||||||
|
/// {@macro counter_consumer_widget}
|
||||||
|
const CounterConsumerWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget onBuild(BuildContext context, CounterState state) => Text(
|
||||||
|
context.l10n.youHavePushed(state.value),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: Theme.of(context).textTheme.headline3,
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// {@template counter_widget}
|
||||||
|
/// CounterWidget is a stateless widget. (Not aware of cubit or bloc states)
|
||||||
|
/// {@endtemplate}
|
||||||
|
class CounterWidget extends StatelessWidget {
|
||||||
|
/// {@macro counter_widget}
|
||||||
|
const CounterWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Container();
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:wyatt_app_template/core/extensions/build_context_extension.dart';
|
||||||
|
import 'package:wyatt_app_template/gen/assets.gen.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/features/counter/counter.dart';
|
||||||
|
import 'package:wyatt_app_template/presentation/shared/layouts/wyatt_app_template_scaffold.dart';
|
||||||
|
|
||||||
|
class Home extends StatelessWidget {
|
||||||
|
const Home({super.key});
|
||||||
|
|
||||||
|
static const String pageName = 'homePage';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => WyattAppTemplateScaffold(
|
||||||
|
body: Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Assets.images.wyattLogo.image(width: 150),
|
||||||
|
const Gap(30),
|
||||||
|
ElevatedButton(
|
||||||
|
child: Text(context.l10n.goToCounter),
|
||||||
|
onPressed: () => context.pushNamed(Counter.pageName),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class WyattAppTemplateScaffold extends StatelessWidget {
|
||||||
|
const WyattAppTemplateScaffold({
|
||||||
|
required this.body,
|
||||||
|
super.key,
|
||||||
|
this.title,
|
||||||
|
this.fabChildren,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Widget? title;
|
||||||
|
final Widget body;
|
||||||
|
final List<Widget>? fabChildren;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Scaffold(
|
||||||
|
appBar: AppBar(title: title),
|
||||||
|
body: body,
|
||||||
|
floatingActionButton: (fabChildren?.isNotEmpty ?? false)
|
||||||
|
? Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: fabChildren!,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
# just to keep empty folder in brick generation
|
@ -1,30 +1 @@
|
|||||||
// This is a basic Flutter widget test.
|
// TODO(wyatt): add some tests
|
||||||
//
|
|
||||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
|
||||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
|
||||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
|
||||||
// tree, read text, and verify that the values of widget properties are correct.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
|
|
||||||
import 'package:wyatt_app_template/main.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('Counter increments smoke test', (tester) async {
|
|
||||||
// Build our app and trigger a frame.
|
|
||||||
await tester.pumpWidget(const MyApp());
|
|
||||||
|
|
||||||
// Verify that our counter starts at 0.
|
|
||||||
expect(find.text('0'), findsOneWidget);
|
|
||||||
expect(find.text('1'), findsNothing);
|
|
||||||
|
|
||||||
// Tap the '+' icon and trigger a frame.
|
|
||||||
await tester.tap(find.byIcon(Icons.add));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Verify that our counter has incremented.
|
|
||||||
expect(find.text('0'), findsNothing);
|
|
||||||
expect(find.text('1'), findsOneWidget);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
BIN
apps/wyatt_app_template/wyatt_app_template/web/favicon.png
Normal file
BIN
apps/wyatt_app_template/wyatt_app_template/web/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 917 B |
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
58
apps/wyatt_app_template/wyatt_app_template/web/index.html
Normal file
58
apps/wyatt_app_template/wyatt_app_template/web/index.html
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
If you are serving your web app in a path other than the root, change the
|
||||||
|
href value below to reflect the base path you are serving from.
|
||||||
|
|
||||||
|
The path provided below has to start and end with a slash "/" in order for
|
||||||
|
it to work correctly.
|
||||||
|
|
||||||
|
For more details:
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||||
|
|
||||||
|
This is a placeholder for base href that will be replaced by the value of
|
||||||
|
the `--base-href` argument provided to `flutter build`.
|
||||||
|
-->
|
||||||
|
<base href="$FLUTTER_BASE_HREF">
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||||
|
<meta name="description" content="wyatt_description">
|
||||||
|
|
||||||
|
<!-- iOS meta tags & icons -->
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
<meta name="apple-mobile-web-app-title" content="Wyatt App">
|
||||||
|
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||||
|
|
||||||
|
<title>Wyatt App</title>
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// The value below is injected by flutter build, do not touch.
|
||||||
|
var serviceWorkerVersion = null;
|
||||||
|
</script>
|
||||||
|
<!-- This script adds the flutter initialization JS code -->
|
||||||
|
<script src="flutter.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
window.addEventListener('load', function(ev) {
|
||||||
|
// Download main.dart.js
|
||||||
|
_flutter.loader.loadEntrypoint({
|
||||||
|
serviceWorker: {
|
||||||
|
serviceWorkerVersion: serviceWorkerVersion,
|
||||||
|
}
|
||||||
|
}).then(function(engineInitializer) {
|
||||||
|
return engineInitializer.initializeEngine();
|
||||||
|
}).then(function(appRunner) {
|
||||||
|
return appRunner.runApp();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
35
apps/wyatt_app_template/wyatt_app_template/web/manifest.json
Normal file
35
apps/wyatt_app_template/wyatt_app_template/web/manifest.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "Wyatt App",
|
||||||
|
"short_name": "Wyatt App",
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#0175C2",
|
||||||
|
"theme_color": "#0175C2",
|
||||||
|
"description": "wyatt_description",
|
||||||
|
"orientation": "portrait-primary",
|
||||||
|
"prefer_related_applications": false,
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user