Skip to content

Commit 042845c

Browse files
committed
chore: Use feature first approach
1 parent ab458a9 commit 042845c

File tree

10 files changed

+553
-327
lines changed

10 files changed

+553
-327
lines changed

.metadata

+15-15
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# This file should be version controlled.
55

66
version:
7-
revision: eb6d86ee27deecba4a83536aa20f366a6044895c
7+
revision: 135454af32477f815a7525073027a3ff9eff1bfd
88
channel: stable
99

1010
project_type: app
@@ -13,26 +13,26 @@ project_type: app
1313
migration:
1414
platforms:
1515
- platform: root
16-
create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
17-
base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
16+
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
17+
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
1818
- platform: android
19-
create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
20-
base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
19+
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
20+
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
2121
- platform: ios
22-
create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
23-
base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
22+
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
23+
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
2424
- platform: linux
25-
create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
26-
base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
25+
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
26+
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
2727
- platform: macos
28-
create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
29-
base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
28+
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
29+
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
3030
- platform: web
31-
create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
32-
base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
31+
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
32+
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
3333
- platform: windows
34-
create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
35-
base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
34+
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
35+
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
3636

3737
# User provided section
3838

ios/Podfile.lock

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
PODS:
2+
- Flutter (1.0.0)
3+
- path_provider_ios (0.0.1):
4+
- Flutter
5+
- url_launcher_ios (0.0.1):
6+
- Flutter
7+
8+
DEPENDENCIES:
9+
- Flutter (from `Flutter`)
10+
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
11+
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
12+
13+
EXTERNAL SOURCES:
14+
Flutter:
15+
:path: Flutter
16+
path_provider_ios:
17+
:path: ".symlinks/plugins/path_provider_ios/ios"
18+
url_launcher_ios:
19+
:path: ".symlinks/plugins/url_launcher_ios/ios"
20+
21+
SPEC CHECKSUMS:
22+
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
23+
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
24+
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
25+
26+
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
27+
28+
COCOAPODS: 1.11.3

ios/Runner.xcodeproj/project.pbxproj

+68
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
1414
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
1515
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16+
E2B689D6B551551A86F87587 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07200894BFAD0918D4D1AC4D /* Pods_Runner.framework */; };
1617
/* End PBXBuildFile section */
1718

1819
/* Begin PBXCopyFilesBuildPhase section */
@@ -29,32 +30,45 @@
2930
/* End PBXCopyFilesBuildPhase section */
3031

3132
/* Begin PBXFileReference section */
33+
07200894BFAD0918D4D1AC4D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3234
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
3335
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3436
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3537
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
3638
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
39+
777DAE19AC34B1C1B975C2BC /* 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>"; };
3740
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
41+
7CB4782BFA30D7B464F549CE /* 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>"; };
3842
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
3943
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
4044
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
4145
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
4246
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
4347
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
4448
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
49+
C1CAFBE0D4722324947E0846 /* 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>"; };
4550
/* End PBXFileReference section */
4651

4752
/* Begin PBXFrameworksBuildPhase section */
4853
97C146EB1CF9000F007C117D /* Frameworks */ = {
4954
isa = PBXFrameworksBuildPhase;
5055
buildActionMask = 2147483647;
5156
files = (
57+
E2B689D6B551551A86F87587 /* Pods_Runner.framework in Frameworks */,
5258
);
5359
runOnlyForDeploymentPostprocessing = 0;
5460
};
5561
/* End PBXFrameworksBuildPhase section */
5662

5763
/* Begin PBXGroup section */
64+
6FC45265568B6EFD58CED065 /* Frameworks */ = {
65+
isa = PBXGroup;
66+
children = (
67+
07200894BFAD0918D4D1AC4D /* Pods_Runner.framework */,
68+
);
69+
name = Frameworks;
70+
sourceTree = "<group>";
71+
};
5872
9740EEB11CF90186004384FC /* Flutter */ = {
5973
isa = PBXGroup;
6074
children = (
@@ -72,6 +86,8 @@
7286
9740EEB11CF90186004384FC /* Flutter */,
7387
97C146F01CF9000F007C117D /* Runner */,
7488
97C146EF1CF9000F007C117D /* Products */,
89+
9DF176E2B78DF40AD4A989E9 /* Pods */,
90+
6FC45265568B6EFD58CED065 /* Frameworks */,
7591
);
7692
sourceTree = "<group>";
7793
};
@@ -98,19 +114,32 @@
98114
path = Runner;
99115
sourceTree = "<group>";
100116
};
117+
9DF176E2B78DF40AD4A989E9 /* Pods */ = {
118+
isa = PBXGroup;
119+
children = (
120+
7CB4782BFA30D7B464F549CE /* Pods-Runner.debug.xcconfig */,
121+
C1CAFBE0D4722324947E0846 /* Pods-Runner.release.xcconfig */,
122+
777DAE19AC34B1C1B975C2BC /* Pods-Runner.profile.xcconfig */,
123+
);
124+
name = Pods;
125+
path = Pods;
126+
sourceTree = "<group>";
127+
};
101128
/* End PBXGroup section */
102129

103130
/* Begin PBXNativeTarget section */
104131
97C146ED1CF9000F007C117D /* Runner */ = {
105132
isa = PBXNativeTarget;
106133
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
107134
buildPhases = (
135+
178B113972AC155F7BCE6831 /* [CP] Check Pods Manifest.lock */,
108136
9740EEB61CF901F6004384FC /* Run Script */,
109137
97C146EA1CF9000F007C117D /* Sources */,
110138
97C146EB1CF9000F007C117D /* Frameworks */,
111139
97C146EC1CF9000F007C117D /* Resources */,
112140
9705A1C41CF9048500538489 /* Embed Frameworks */,
113141
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
142+
702EF9A13F3E63855C040E29 /* [CP] Embed Pods Frameworks */,
114143
);
115144
buildRules = (
116145
);
@@ -169,6 +198,28 @@
169198
/* End PBXResourcesBuildPhase section */
170199

171200
/* Begin PBXShellScriptBuildPhase section */
201+
178B113972AC155F7BCE6831 /* [CP] Check Pods Manifest.lock */ = {
202+
isa = PBXShellScriptBuildPhase;
203+
buildActionMask = 2147483647;
204+
files = (
205+
);
206+
inputFileListPaths = (
207+
);
208+
inputPaths = (
209+
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
210+
"${PODS_ROOT}/Manifest.lock",
211+
);
212+
name = "[CP] Check Pods Manifest.lock";
213+
outputFileListPaths = (
214+
);
215+
outputPaths = (
216+
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
217+
);
218+
runOnlyForDeploymentPostprocessing = 0;
219+
shellPath = /bin/sh;
220+
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";
221+
showEnvVarsInLog = 0;
222+
};
172223
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
173224
isa = PBXShellScriptBuildPhase;
174225
buildActionMask = 2147483647;
@@ -183,6 +234,23 @@
183234
shellPath = /bin/sh;
184235
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
185236
};
237+
702EF9A13F3E63855C040E29 /* [CP] Embed Pods Frameworks */ = {
238+
isa = PBXShellScriptBuildPhase;
239+
buildActionMask = 2147483647;
240+
files = (
241+
);
242+
inputFileListPaths = (
243+
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
244+
);
245+
name = "[CP] Embed Pods Frameworks";
246+
outputFileListPaths = (
247+
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
248+
);
249+
runOnlyForDeploymentPostprocessing = 0;
250+
shellPath = /bin/sh;
251+
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
252+
showEnvVarsInLog = 0;
253+
};
186254
9740EEB61CF901F6004384FC /* Run Script */ = {
187255
isa = PBXShellScriptBuildPhase;
188256
buildActionMask = 2147483647;

ios/Runner.xcworkspace/contents.xcworkspacedata

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/app.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ class QuoteRequestApp extends ConsumerWidget {
2424
),
2525
);
2626
}
27-
}
27+
}

lib/src/core/constants.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
const String kBaseUrl = 'YOUR_BASE_URL';
2-
const String kApiKey = 'YOUR_API_KEY';
1+
const String kBaseUrl = '';
2+
const String kApiKey = '';
+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_riverpod/flutter_riverpod.dart';
3+
import 'package:quote_request_app/src/features/estimates/models/quote_model.dart';
4+
5+
import '../form_validator.dart';
6+
import '../providers.dart';
7+
import '../styles.dart';
8+
import 'loading_widget.dart';
9+
10+
class EstimateForm extends ConsumerStatefulWidget {
11+
const EstimateForm({this.initalQuote, required this.onSubmitted, super.key});
12+
13+
final Quote? initalQuote;
14+
final void Function(Quote quote) onSubmitted;
15+
16+
@override
17+
ConsumerState<EstimateForm> createState() => _EstimateFormState();
18+
}
19+
20+
class _EstimateFormState extends ConsumerState<EstimateForm> {
21+
final _formKey = GlobalKey<FormState>();
22+
23+
final TextEditingController _productLinkController = TextEditingController();
24+
final TextEditingController _productNameController = TextEditingController();
25+
final TextEditingController _descriptionController = TextEditingController();
26+
final TextEditingController _quantityController = TextEditingController();
27+
28+
void _handleFormSubmission() {
29+
if (_formKey.currentState!.validate()) {
30+
_formKey.currentState!.save();
31+
32+
Map<String, dynamic> data = {
33+
'product_name': _productNameController.text,
34+
'product_link': _productLinkController.text,
35+
'description': _descriptionController.text,
36+
'quantity': _quantityController.text,
37+
};
38+
39+
widget.onSubmitted(Quote.fromJson(data));
40+
}
41+
}
42+
43+
@override
44+
Widget build(BuildContext context) {
45+
final quoteState = ref.watch(estimateNotifierProvider);
46+
return Form(
47+
key: _formKey,
48+
child: ListView(
49+
padding: const EdgeInsets.all(16),
50+
children: [
51+
const Text(
52+
"Link to the product",
53+
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
54+
),
55+
const SizedBox(height: 8),
56+
TextFormField(
57+
controller: _productLinkController,
58+
keyboardType: TextInputType.url,
59+
decoration: const InputDecoration(
60+
hintText: 'https://www.amazon.fr/dp/289225955X',
61+
labelStyle: TextStyle(color: Colors.grey),
62+
enabledBorder: AppInputBorder.enabledBorder,
63+
focusedBorder: AppInputBorder.focusedBorder,
64+
errorBorder: AppInputBorder.errorBorder,
65+
focusedErrorBorder: AppInputBorder.focusedErrorBorder,
66+
contentPadding: EdgeInsets.all(10),
67+
),
68+
validator: FormValidator.validateProductLink,
69+
),
70+
const SizedBox(height: 16),
71+
const Text(
72+
"Product name",
73+
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
74+
),
75+
const SizedBox(height: 8),
76+
TextFormField(
77+
controller: _productNameController,
78+
decoration: const InputDecoration(
79+
hintText: 'Enter product name',
80+
labelStyle: TextStyle(color: Colors.grey),
81+
enabledBorder: AppInputBorder.enabledBorder,
82+
focusedBorder: AppInputBorder.focusedBorder,
83+
errorBorder: AppInputBorder.errorBorder,
84+
contentPadding: EdgeInsets.all(10),
85+
),
86+
validator: FormValidator.validateProductName,
87+
),
88+
const SizedBox(height: 16),
89+
const Text(
90+
"Description",
91+
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
92+
),
93+
const SizedBox(height: 8),
94+
TextFormField(
95+
controller: _descriptionController,
96+
decoration: const InputDecoration(
97+
hintText: 'Product details',
98+
labelStyle: TextStyle(color: Colors.grey),
99+
enabledBorder: AppInputBorder.enabledBorder,
100+
focusedBorder: AppInputBorder.focusedBorder,
101+
errorBorder: AppInputBorder.errorBorder,
102+
contentPadding: EdgeInsets.all(10),
103+
),
104+
maxLines: 6,
105+
validator: FormValidator.validateProductDescription,
106+
),
107+
const SizedBox(height: 16),
108+
const Text(
109+
"Quantity",
110+
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
111+
),
112+
const SizedBox(height: 8),
113+
TextFormField(
114+
controller: _quantityController,
115+
keyboardType: TextInputType.number,
116+
decoration: const InputDecoration(
117+
hintText: 'Product quantity',
118+
labelStyle: TextStyle(color: Colors.grey),
119+
enabledBorder: AppInputBorder.enabledBorder,
120+
focusedBorder: AppInputBorder.focusedBorder,
121+
errorBorder: AppInputBorder.errorBorder,
122+
contentPadding: EdgeInsets.all(10),
123+
),
124+
validator: FormValidator.validateProductQuantity,
125+
),
126+
const SizedBox(height: 24),
127+
ElevatedButton(
128+
onPressed: quoteState.maybeWhen(
129+
loading: () => null,
130+
orElse: () => _handleFormSubmission,
131+
),
132+
style: ElevatedButton.styleFrom(
133+
elevation: 0,
134+
shape: RoundedRectangleBorder(
135+
borderRadius: BorderRadius.circular(10),
136+
),
137+
padding: const EdgeInsets.symmetric(vertical: 16),
138+
),
139+
child: quoteState.maybeWhen(
140+
loading: () => const LoadingWidget(),
141+
orElse: () => const Text('SUBMIT REQUEST'),
142+
),
143+
),
144+
],
145+
),
146+
);
147+
}
148+
}

0 commit comments

Comments
 (0)