1
+ import 'dart:typed_data' ;
2
+
1
3
import 'package:flutter/material.dart' ;
2
4
3
5
import '../constants.dart' ;
4
6
import '../isar_collection/isar_collections.dart' show Store;
5
7
import '../isar_service.dart' ;
6
8
import '../shared/bottom_sheet_scroll_header.dart' ;
9
+ import '../shared/dashed_border_container.dart' ;
10
+ import '../shared/padded_text.dart' ;
7
11
import 'edit_currency_state.dart' ;
12
+ import 'edit_store_state.dart' ;
13
+ import 'preview_state.dart' show getTextLogo;
8
14
9
15
class EditStorePage extends StatefulWidget {
10
16
static const routeName = '/edit-store' ;
@@ -23,41 +29,94 @@ class _EditStorePageState extends State<EditStorePage> {
23
29
final _formKey = GlobalKey <FormState >();
24
30
final _email = TextEditingController ();
25
31
final _name = TextEditingController ();
32
+ final _note = TextEditingController ();
26
33
late Currency _curr;
34
+ var _action = LogoAction .update;
35
+
36
+ Uint8List ? _imageBytes;
27
37
28
38
@override
29
39
void initState () {
30
40
super .initState ();
41
+ WidgetsBinding .instance.addPostFrameCallback ((_) {
42
+ loadImage ((v) => setState (() => _imageBytes = v));
43
+ });
31
44
_editedStore = widget.store;
32
45
_email.text = widget.store.email! ;
33
46
_name.text = widget.store.name! ;
47
+ _note.text = widget.store.thankNote! ;
34
48
_curr = getCurrency (widget.store.locale! );
35
49
}
36
50
37
51
@override
38
52
void dispose () {
39
53
_email.dispose ();
40
54
_name.dispose ();
55
+ _note.dispose ();
41
56
super .dispose ();
42
57
}
43
58
44
59
@override
45
60
Widget build (BuildContext context) {
46
61
final colors = Theme .of (context).colorScheme;
47
62
final disabledColor = Theme .of (context).disabledColor;
48
-
63
+ final textTheme = Theme .of (context).textTheme;
64
+ final alertStyle =
65
+ textTheme.bodySmall! .copyWith (color: colors.onTertiaryContainer);
66
+ final textBold = TextStyle (fontWeight: FontWeight .bold);
49
67
return Scaffold (
50
68
appBar: AppBar (
51
69
title: Text ('Edit store info' ),
52
70
),
53
71
body: Form (
54
72
key: _formKey,
55
- child: Column (
56
- spacing: 16.0 ,
57
- crossAxisAlignment: CrossAxisAlignment .stretch,
58
- mainAxisSize: MainAxisSize .min,
73
+ child: ListView (
59
74
children: [
60
- SizedBox (),
75
+ _DividerText (text: 'Logo' ),
76
+ Padding (
77
+ padding: kPx,
78
+ child: _CompanyLogoButton (
79
+ bytes: _imageBytes,
80
+ name: widget.store.name! ,
81
+ action: _imageBytes != null
82
+ ? PopupMenuButton <LogoAction >(
83
+ initialValue: _action,
84
+ onSelected: (v) => _onSelected (v),
85
+ iconColor: colors.primary,
86
+ itemBuilder: (context) => < PopupMenuEntry <LogoAction >> [
87
+ const PopupMenuItem <LogoAction >(
88
+ value: LogoAction .update,
89
+ child: Text ('Update' ),
90
+ ),
91
+ const PopupMenuItem <LogoAction >(
92
+ value: LogoAction .delete,
93
+ child: Text ('Remove' ),
94
+ ),
95
+ ],
96
+ )
97
+ : IconButton (
98
+ onPressed: () => _onPickImage (),
99
+ icon: Icon (Icons .edit, color: colors.primary),
100
+ ),
101
+ ),
102
+ ),
103
+ _AlertTextBox (
104
+ margin: EdgeInsets .fromLTRB (16.0 , 12.0 , 16.0 , 0.0 ),
105
+ backgroundColor: colors.tertiaryContainer,
106
+ iconColor: colors.onTertiaryContainer,
107
+ icon: Icons .info_outline,
108
+ child: Text .rich (
109
+ style: alertStyle,
110
+ TextSpan (
111
+ text: kLogoHelp1,
112
+ children: [
113
+ TextSpan (text: kLogoHelp2, style: textBold),
114
+ TextSpan (text: kLogoHelp3),
115
+ ],
116
+ ),
117
+ ),
118
+ ),
119
+ _DividerText (text: 'Main' ),
61
120
Padding (
62
121
padding: kPx,
63
122
child: TextFormField (
@@ -70,6 +129,7 @@ class _EditStorePageState extends State<EditStorePage> {
70
129
onChanged: (v) => setState (() {}),
71
130
),
72
131
),
132
+ const SizedBox (height: 16.0 ),
73
133
Padding (
74
134
padding: kPx,
75
135
child: TextFormField (
@@ -82,10 +142,27 @@ class _EditStorePageState extends State<EditStorePage> {
82
142
onChanged: (v) => setState (() {}),
83
143
),
84
144
),
145
+ const SizedBox (height: 16.0 ),
85
146
_CurrencyButton (
86
147
title: getName (_curr),
87
148
onPressed: () => _onEditCurrency (),
88
149
),
150
+ _DividerText (text: 'Tank note' ),
151
+ Padding (
152
+ padding: kPx,
153
+ child: TextFormField (
154
+ controller: _note,
155
+ decoration: InputDecoration (
156
+ hintText: 'Thank you for your business!' ,
157
+ label: Text ('Thank note' ),
158
+ ),
159
+ keyboardType: TextInputType .text,
160
+ maxLines: 8 ,
161
+ minLines: 2 ,
162
+ onChanged: (v) => setState (() {}),
163
+ ),
164
+ ),
165
+ SizedBox (height: kToolbarHeight * 2 ),
89
166
],
90
167
),
91
168
),
@@ -110,6 +187,7 @@ class _EditStorePageState extends State<EditStorePage> {
110
187
_editedStore.email = _email.text.trim ();
111
188
_editedStore.locale = getLocale (_curr);
112
189
_editedStore.symbol = getSymbol (_curr);
190
+ _editedStore.thankNote = _note.text.isEmpty ? kNote : _note.text.trim ();
113
191
await _db.updateStore (_editedStore);
114
192
nav.pushNamedAndRemoveUntil ('/' , (_) => false );
115
193
}
@@ -144,6 +222,25 @@ class _EditStorePageState extends State<EditStorePage> {
144
222
setState (() => _curr = currency);
145
223
nav.pop ();
146
224
}
225
+
226
+ Future <void > _onPickImage () async {
227
+ await pickImage ((v) => setState (() => _imageBytes = v));
228
+ }
229
+
230
+ Future <void > _onDelete () async {
231
+ await removeImage ();
232
+ setState (() => _imageBytes = null );
233
+ }
234
+
235
+ Future <void > _onSelected (LogoAction action) async {
236
+ switch (action) {
237
+ case LogoAction .update:
238
+ await _onPickImage ().then ((_) => setState (() => _action = action));
239
+ break ;
240
+ default :
241
+ await _onDelete ().then ((_) => setState (() => _action = action));
242
+ }
243
+ }
147
244
}
148
245
149
246
class EditStoreArgs {
@@ -180,11 +277,129 @@ class _CurrencyButton extends StatelessWidget {
180
277
),
181
278
Padding (
182
279
padding: const EdgeInsets .all (12.0 ),
183
- child: Icon (Icons .arrow_drop_down_outlined),
280
+ child: Icon (
281
+ Icons .arrow_drop_down_outlined,
282
+ color: colors.primary,
283
+ ),
184
284
),
185
285
],
186
286
),
187
287
),
188
288
);
189
289
}
190
290
}
291
+
292
+ class _CompanyLogoButton extends StatelessWidget {
293
+ const _CompanyLogoButton ({
294
+ required this .action,
295
+ this .bytes,
296
+ required this .name,
297
+ });
298
+
299
+ final String name;
300
+ final Uint8List ? bytes;
301
+ final Widget action;
302
+
303
+ @override
304
+ Widget build (BuildContext context) {
305
+ final textTheme = Theme .of (context).textTheme;
306
+ final colors = Theme .of (context).colorScheme;
307
+
308
+ return Card (
309
+ child: Row (
310
+ crossAxisAlignment: CrossAxisAlignment .start,
311
+ mainAxisAlignment: MainAxisAlignment .spaceBetween,
312
+ children: [
313
+ Padding (
314
+ padding: const EdgeInsets .all (16.0 ),
315
+ child: DashedBorderContainer (
316
+ color: colors.outline,
317
+ strokeWidth: 1 ,
318
+ dashSpace: bytes != null ? 0.0 : 3.0 ,
319
+ dashWidth: 5.0 ,
320
+ borderRadius: 6.0 ,
321
+ child: Container (
322
+ alignment: Alignment .center,
323
+ width: 128.0 ,
324
+ height: 128.0 ,
325
+ clipBehavior: Clip .antiAlias,
326
+ decoration: BoxDecoration (
327
+ borderRadius: BorderRadius .all (Radius .circular (6.0 )),
328
+ image: bytes != null
329
+ ? DecorationImage (image: MemoryImage (bytes! ))
330
+ : null ,
331
+ ),
332
+ child: bytes != null
333
+ ? null
334
+ : Text (
335
+ getTextLogo (name),
336
+ style: textTheme.displaySmall,
337
+ ),
338
+ ),
339
+ ),
340
+ ),
341
+ Padding (
342
+ padding: const EdgeInsets .all (8.0 ),
343
+ child: action,
344
+ ),
345
+ ],
346
+ ),
347
+ );
348
+ }
349
+ }
350
+
351
+ class _DividerText extends StatelessWidget {
352
+ const _DividerText ({required this .text});
353
+
354
+ final String text;
355
+
356
+ @override
357
+ Widget build (BuildContext context) {
358
+ final textTheme = Theme .of (context).textTheme;
359
+
360
+ return PaddedText (
361
+ text: text,
362
+ style: textTheme.titleMedium,
363
+ left: 16 ,
364
+ top: 20 ,
365
+ right: 16 ,
366
+ bottom: 12 ,
367
+ );
368
+ }
369
+ }
370
+
371
+ class _AlertTextBox extends StatelessWidget {
372
+ const _AlertTextBox ({
373
+ required this .backgroundColor,
374
+ required this .icon,
375
+ required this .child,
376
+ required this .iconColor,
377
+ this .margin,
378
+ });
379
+
380
+ final Color backgroundColor;
381
+ final Widget child;
382
+ final IconData icon;
383
+ final Color iconColor;
384
+ final EdgeInsets ? margin;
385
+
386
+ @override
387
+ Widget build (BuildContext context) {
388
+ return Container (
389
+ margin: margin,
390
+ padding: EdgeInsets .all (12.0 ),
391
+ decoration: BoxDecoration (
392
+ color: backgroundColor,
393
+ borderRadius: BorderRadius .all (Radius .circular (12.0 )),
394
+ ),
395
+ child: Row (
396
+ spacing: 12.0 ,
397
+ crossAxisAlignment: CrossAxisAlignment .start,
398
+ children: [
399
+ Icon (icon, color: iconColor),
400
+ Expanded (child: child),
401
+ ],
402
+ ),
403
+ );
404
+ }
405
+ }
0 commit comments