@@ -32,6 +32,7 @@ class _EditProductScreenState extends State<EditProductScreen> {
3232 'imageUrl' : '' ,
3333 };
3434 bool _isInit = true ;
35+ bool _isLoading = false ;
3536
3637 @override
3738 void dispose () {
@@ -50,11 +51,25 @@ class _EditProductScreenState extends State<EditProductScreen> {
5051 }
5152 // save 메쇠드 사용시 각 TextFormFiled 의 onSave가 동작
5253 _formKey.currentState.save ();
54+ setState (() {
55+ _isLoading = true ;
56+ });
5357 if (_editedProduct.id != null ) {
5458 Provider .of <Products >(context, listen: false )
5559 .updateProduct (_editedProduct.id, _editedProduct);
60+ Navigator .of (context).pop ();
61+ setState (() {
62+ _isLoading = false ;
63+ });
5664 }
57- Provider .of <Products >(context, listen: false ).addProduct (_editedProduct);
65+ Provider .of <Products >(context, listen: false )
66+ .addProduct (_editedProduct)
67+ .then (((_) {
68+ Navigator .of (context).pop ();
69+ setState (() {
70+ _isLoading = false ;
71+ });
72+ }));
5873 }
5974
6075 @override
@@ -87,170 +102,174 @@ class _EditProductScreenState extends State<EditProductScreen> {
87102 icon: Icon (Icons .save),
88103 onPressed: () {
89104 _saveForm ();
90- Navigator .of (context).pop ();
91105 }),
92106 ],
93107 ),
94- body: Padding (
95- padding: const EdgeInsets .all (16.0 ),
96- child: Form (
97- key: _formKey,
98- child: ListView (
99- children: < Widget > [
100- TextFormField (
101- initialValue: _initValue['title' ],
102- decoration: InputDecoration (labelText: 'Title' ),
103- textInputAction: TextInputAction .next,
104- onFieldSubmitted: (_) {
105- FocusScope .of (context).requestFocus (_priceFocusNode);
106- },
107- validator: (value) {
108- if (value.isEmpty) {
109- return 'Please provide a value' ;
110- }
111- return null ;
112- },
113- onSaved: (value) {
114- _editedProduct = Product (
115- title: value,
116- price: _editedProduct.price,
117- description: _editedProduct.description,
118- imageUrl: _editedProduct.imageUrl,
119- id: _editedProduct.id,
120- isFavorite: _editedProduct.isFavorite,
121- );
122- },
123- ),
124- TextFormField (
125- initialValue: _initValue['price' ],
126- decoration: InputDecoration (labelText: 'Price' ),
127- textInputAction: TextInputAction .next,
128- keyboardType: TextInputType .number,
129- focusNode: _priceFocusNode,
130- onFieldSubmitted: (_) {
131- FocusScope .of (context).requestFocus (_descriptionFocusNode);
132- },
133- validator: (value) {
134- if (value.isEmpty) {
135- return 'Please provide a price' ;
136- }
137- if (double .tryParse (value) == null ) {
138- return 'Please enter a valid number' ;
139- }
140- if (double .parse (value) <= 0 ) {
141- return 'Please enater a number greater than zero' ;
142- }
143- return null ;
144- },
145- onSaved: (value) {
146- _editedProduct = Product (
147- title: _editedProduct.title,
148- price: double .parse (value),
149- description: _editedProduct.description,
150- imageUrl: _editedProduct.imageUrl,
151- id: _editedProduct.id,
152- isFavorite: _editedProduct.isFavorite,
153- );
154- },
155- ),
156- TextFormField (
157- initialValue: _initValue['description' ],
158- decoration: InputDecoration (labelText: 'Description' ),
159- maxLines: 3 ,
160- textInputAction: TextInputAction .next,
161- keyboardType: TextInputType .multiline,
162- focusNode: _descriptionFocusNode,
163- onFieldSubmitted: (_) {
164- FocusScope .of (context).requestFocus (_imageUrlFocusNode);
165- },
166- validator: (value) {
167- if (value.isEmpty) {
168- return 'Please provide a description' ;
169- }
170- if (value.length < 10 ) {
171- return 'Should be at least 10 characters long' ;
172- }
173- return null ;
174- },
175- onSaved: (value) {
176- _editedProduct = Product (
177- title: _editedProduct.title,
178- price: _editedProduct.price,
179- description: value,
180- imageUrl: _editedProduct.imageUrl,
181- id: _editedProduct.id,
182- isFavorite: _editedProduct.isFavorite,
183- );
184- },
185- ),
186- Row (
187- crossAxisAlignment: CrossAxisAlignment .end,
188- children: < Widget > [
189- Container (
190- width: 100 ,
191- height: 100 ,
192- margin: EdgeInsets .only (top: 8 , right: 10 ),
193- decoration: BoxDecoration (
194- border: Border .all (
195- width: 1 ,
196- color: Colors .grey,
197- ),
108+ body: _isLoading
109+ ? Center (
110+ child: CircularProgressIndicator (),
111+ )
112+ : Padding (
113+ padding: const EdgeInsets .all (16.0 ),
114+ child: Form (
115+ key: _formKey,
116+ child: ListView (
117+ children: < Widget > [
118+ TextFormField (
119+ initialValue: _initValue['title' ],
120+ decoration: InputDecoration (labelText: 'Title' ),
121+ textInputAction: TextInputAction .next,
122+ onFieldSubmitted: (_) {
123+ FocusScope .of (context).requestFocus (_priceFocusNode);
124+ },
125+ validator: (value) {
126+ if (value.isEmpty) {
127+ return 'Please provide a value' ;
128+ }
129+ return null ;
130+ },
131+ onSaved: (value) {
132+ _editedProduct = Product (
133+ title: value,
134+ price: _editedProduct.price,
135+ description: _editedProduct.description,
136+ imageUrl: _editedProduct.imageUrl,
137+ id: _editedProduct.id,
138+ isFavorite: _editedProduct.isFavorite,
139+ );
140+ },
198141 ),
199- child: _imageUrlController.text.isEmpty
200- ? Text (
201- 'Enter a URL' ,
202- textAlign: TextAlign .center,
203- )
204- : FittedBox (
205- child: Image .network (
206- _imageUrlController.text,
207- fit: BoxFit .cover,
208- ),
209- ),
210- ),
211- Expanded (
212- child: TextFormField (
213- decoration: InputDecoration (labelText: 'Image URL' ),
214- keyboardType: TextInputType .url,
215- textInputAction: TextInputAction .done,
216- controller: _imageUrlController,
217- focusNode: _imageUrlFocusNode,
218- onEditingComplete: () {
219- setState (() {});
142+ TextFormField (
143+ initialValue: _initValue['price' ],
144+ decoration: InputDecoration (labelText: 'Price' ),
145+ textInputAction: TextInputAction .next,
146+ keyboardType: TextInputType .number,
147+ focusNode: _priceFocusNode,
148+ onFieldSubmitted: (_) {
149+ FocusScope .of (context)
150+ .requestFocus (_descriptionFocusNode);
220151 },
221152 validator: (value) {
222153 if (value.isEmpty) {
223- return 'Please enter an image URL ' ;
154+ return 'Please provide a price ' ;
224155 }
225- if (! value.startsWith ('http' ) &&
226- ! value.startsWith ('https' )) {
227- return 'Please enter a valid URL' ;
156+ if (double .tryParse (value) == null ) {
157+ return 'Please enter a valid number' ;
228158 }
229- if (! value.endsWith ('.png' ) &&
230- ! value.endsWith ('.jpg' ) &&
231- ! value.endsWith ('.jpeg' )) {
232- return 'Please enter a valid image URL' ;
159+ if (double .parse (value) <= 0 ) {
160+ return 'Please enater a number greater than zero' ;
233161 }
234162 return null ;
235163 },
236164 onSaved: (value) {
237165 _editedProduct = Product (
238166 title: _editedProduct.title,
239- price: _editedProduct.price ,
167+ price: double . parse (value) ,
240168 description: _editedProduct.description,
241- imageUrl: value ,
169+ imageUrl: _editedProduct.imageUrl ,
242170 id: _editedProduct.id,
243171 isFavorite: _editedProduct.isFavorite,
244172 );
245173 },
246174 ),
247- )
248- ],
249- )
250- ],
251- ),
252- ),
253- ),
175+ TextFormField (
176+ initialValue: _initValue['description' ],
177+ decoration: InputDecoration (labelText: 'Description' ),
178+ maxLines: 3 ,
179+ textInputAction: TextInputAction .next,
180+ keyboardType: TextInputType .multiline,
181+ focusNode: _descriptionFocusNode,
182+ onFieldSubmitted: (_) {
183+ FocusScope .of (context).requestFocus (_imageUrlFocusNode);
184+ },
185+ validator: (value) {
186+ if (value.isEmpty) {
187+ return 'Please provide a description' ;
188+ }
189+ if (value.length < 10 ) {
190+ return 'Should be at least 10 characters long' ;
191+ }
192+ return null ;
193+ },
194+ onSaved: (value) {
195+ _editedProduct = Product (
196+ title: _editedProduct.title,
197+ price: _editedProduct.price,
198+ description: value,
199+ imageUrl: _editedProduct.imageUrl,
200+ id: _editedProduct.id,
201+ isFavorite: _editedProduct.isFavorite,
202+ );
203+ },
204+ ),
205+ Row (
206+ crossAxisAlignment: CrossAxisAlignment .end,
207+ children: < Widget > [
208+ Container (
209+ width: 100 ,
210+ height: 100 ,
211+ margin: EdgeInsets .only (top: 8 , right: 10 ),
212+ decoration: BoxDecoration (
213+ border: Border .all (
214+ width: 1 ,
215+ color: Colors .grey,
216+ ),
217+ ),
218+ child: _imageUrlController.text.isEmpty
219+ ? Text (
220+ 'Enter a URL' ,
221+ textAlign: TextAlign .center,
222+ )
223+ : FittedBox (
224+ child: Image .network (
225+ _imageUrlController.text,
226+ fit: BoxFit .cover,
227+ ),
228+ ),
229+ ),
230+ Expanded (
231+ child: TextFormField (
232+ decoration: InputDecoration (labelText: 'Image URL' ),
233+ keyboardType: TextInputType .url,
234+ textInputAction: TextInputAction .done,
235+ controller: _imageUrlController,
236+ focusNode: _imageUrlFocusNode,
237+ onEditingComplete: () {
238+ setState (() {});
239+ },
240+ validator: (value) {
241+ if (value.isEmpty) {
242+ return 'Please enter an image URL' ;
243+ }
244+ if (! value.startsWith ('http' ) &&
245+ ! value.startsWith ('https' )) {
246+ return 'Please enter a valid URL' ;
247+ }
248+ if (! value.endsWith ('.png' ) &&
249+ ! value.endsWith ('.jpg' ) &&
250+ ! value.endsWith ('.jpeg' )) {
251+ return 'Please enter a valid image URL' ;
252+ }
253+ return null ;
254+ },
255+ onSaved: (value) {
256+ _editedProduct = Product (
257+ title: _editedProduct.title,
258+ price: _editedProduct.price,
259+ description: _editedProduct.description,
260+ imageUrl: value,
261+ id: _editedProduct.id,
262+ isFavorite: _editedProduct.isFavorite,
263+ );
264+ },
265+ ),
266+ )
267+ ],
268+ )
269+ ],
270+ ),
271+ ),
272+ ),
254273 );
255274 }
256275}
0 commit comments