Skip to content

Commit

Permalink
允許管理圖片 (evan361425#185)
Browse files Browse the repository at this point in the history
* chore: bump flutter to 3.7.8

* fix(trans): add normal import status

* test: fulfill

* feat: add image gallery

* fix(design): change splash background color

* test: fulfill test
  • Loading branch information
evan361425 authored Mar 26, 2023
1 parent 5cf2585 commit ed4ac7b
Show file tree
Hide file tree
Showing 30 changed files with 761 additions and 214 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy-to-playstore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.7.6"
flutter-version: "3.7.8"
cache: true
channel: "stable"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-candidate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ jobs:
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.7.6"
flutter-version: "3.7.8"
cache: true
channel: "stable"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
# Setup the flutter environment.
- uses: subosito/flutter-action@v2
with:
flutter-version: "3.7.6"
flutter-version: "3.7.8"
cache: true
channel: "stable"

Expand Down
Binary file modified android/app/src/main/res/drawable-v21/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/drawable/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion lib/components/dialog/delete_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ class DeleteDialog extends StatelessWidget {
BuildContext context, {
required Future<void> Function() deleteCallback,
bool popAfterDeleted = false,
bool finishMessage = true,
Widget? warningContent,
}) async {
startDelete() async {
await deleteCallback();
if (context.mounted) {
if (context.mounted && finishMessage) {
showSnackBar(context, S.actSuccess);
}

Expand Down
13 changes: 6 additions & 7 deletions lib/components/slivers/sliver_image_app_bar.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import 'package:flutter/material.dart';
import 'package:possystem/components/style/image_holder.dart';
import 'package:possystem/components/style/pop_button.dart';
import 'package:possystem/models/model.dart';

class SliverImageAppBar extends StatelessWidget {
final String title;

final ImageProvider<Object> image;
final ModelImage model;

const SliverImageAppBar({
Key? key,
required this.title,
required this.image,
required this.model,
}) : super(key: key);

@override
Expand All @@ -21,16 +19,17 @@ class SliverImageAppBar extends StatelessWidget {
leading: const PopButton(),
flexibleSpace: FlexibleSpaceBar(
title: Text(
title,
model.name,
style: TextStyle(
color: Theme.of(context).textTheme.bodyMedium!.color,
),
),
titlePadding: const EdgeInsets.fromLTRB(48, 0, 48, 6),
background: ImageHolder(
image: image,
image: model.image,
padding: const EdgeInsets.fromLTRB(0, 36, 0, 0),
title: '',
onImageError: () => model.saveImage(null),
),
),
actions: const <Widget>[PopButton(toHome: true)],
Expand Down
40 changes: 14 additions & 26 deletions lib/components/style/image_holder.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import 'package:flutter/material.dart';
import 'package:possystem/helpers/logger.dart';
import 'package:possystem/models/xfile.dart';
import 'package:possystem/services/image_dumper.dart';
import 'package:possystem/routes.dart';

class ImageHolder extends StatefulWidget {
class ImageHolder extends StatelessWidget {
final ImageProvider image;

final String title;

final void Function()? onPressed;

final void Function()? onImageError;

final FocusNode? focusNode;

final EdgeInsets padding;
Expand All @@ -19,17 +21,11 @@ class ImageHolder extends StatefulWidget {
required this.image,
required this.title,
this.onPressed,
this.onImageError,
this.focusNode,
this.padding = const EdgeInsets.fromLTRB(4.0, 8.0, 4.0, 8.0),
}) : super(key: key);

@override
State<ImageHolder> createState() => _ImageHolderState();
}

class _ImageHolderState extends State<ImageHolder> {
late ImageProvider image;

@override
Widget build(BuildContext context) {
final color = Theme.of(context).colorScheme.background;
Expand All @@ -44,7 +40,7 @@ class _ImageHolderState extends State<ImageHolder> {
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
padding: widget.padding,
padding: padding,
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: colors[0])),
gradient: LinearGradient(
Expand All @@ -53,15 +49,15 @@ class _ImageHolderState extends State<ImageHolder> {
end: Alignment.topCenter,
),
),
child: Text(widget.title, textAlign: TextAlign.center),
child: Text(title, textAlign: TextAlign.center),
),
),
);

if (widget.onPressed != null) {
if (onPressed != null) {
body = InkWell(
onTap: widget.onPressed,
focusNode: widget.focusNode,
onTap: onPressed,
focusNode: focusNode,
child: body,
);
}
Expand All @@ -70,13 +66,11 @@ class _ImageHolderState extends State<ImageHolder> {
aspectRatio: 1,
child: Ink.image(
padding: EdgeInsets.zero,
image: widget.image,
image: image,
fit: BoxFit.cover,
onImageError: (error, stack) {
Log.err(error, 'image_holder_error', stack);
setState(() {
image = const AssetImage("assets/food_placeholder.png");
});
onImageError?.call();
},
child: Material(
type: MaterialType.transparency,
Expand All @@ -86,12 +80,6 @@ class _ImageHolderState extends State<ImageHolder> {
),
);
}

@override
void initState() {
super.initState();
image = widget.image;
}
}

class EditImageHolder extends StatelessWidget {
Expand All @@ -116,8 +104,8 @@ class EditImageHolder extends StatelessWidget {
image: image,
title: path == null ? '點選以新增圖片' : '點擊以更新圖片',
onPressed: () async {
final image = await ImageDumper.instance.pick();
if (image != null) onSelected(image.path);
final file = await Navigator.of(context).pushNamed(Routes.imageGallery);
if (file != null && file is String) onSelected(file);
},
);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/l10n/app_zh.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@
}
}
},
"importerColumnStatus": "{status, select, staged{(新增)} stagedIng{(新的成分)} stagedQua{(新的份量)} updated{(異動)} other{UNKNOWN}}",
"importerColumnStatus": "{status, select, normal{(一般)} staged{(新增)} stagedIng{(新的成分)} stagedQua{(新的份量)} updated{(異動)} other{UNKNOWN}}",
"@importerColumnStatus": {
"description": "顯示該資料的額外狀態",
"placeholders": {
Expand Down
7 changes: 1 addition & 6 deletions lib/models/menu/catalog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,13 @@ class Catalog extends Model<CatalogObject>
Menu.instance.notifyItems();
}

@override
Future<void> removeRemotely() async {
await super.removeRemotely();
await Future.wait(items.map((e) => e.deleteImage()));
}

@override
CatalogObject toObject() => CatalogObject(
id: id,
index: index,
name: name,
createdAt: createdAt,
imagePath: imagePath,
products: items.map((e) => e.toObject()).toList(),
);
}
1 change: 1 addition & 0 deletions lib/models/menu/product.dart
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class Product extends Model<ProductObject>
price: price,
cost: cost,
createdAt: createdAt,
imagePath: imagePath,
ingredients: items.map((e) => e.toObject()).toList(),
);
}
50 changes: 9 additions & 41 deletions lib/models/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import 'package:possystem/helpers/util.dart';
import 'package:possystem/models/model_object.dart';
import 'package:possystem/models/repository.dart';
import 'package:possystem/models/xfile.dart';
import 'package:possystem/routes.dart';
import 'package:possystem/services/database.dart';
import 'package:possystem/services/image_dumper.dart';
import 'package:possystem/services/storage.dart';

enum ModelStatus {
Expand Down Expand Up @@ -121,50 +121,18 @@ mixin ModelImage<T extends ModelObject> on Model<T> {

String get _avatorPath => '$imagePath-avator';

Future<void> deleteImage() async {
if (imagePath != null) {
await Future.wait([
XFile(imagePath!).file.delete(),
XFile(_avatorPath).file.delete(),
]).onError((error, stackTrace) => []);
Future<void> pickImage(BuildContext context) async {
final image = await Navigator.of(context).pushNamed(Routes.imageGallery);
if (image != null && image is String && image != imagePath) {
saveImage(image);
}
}

Future<void> pickImage() async {
final image = await ImageDumper.instance.pick();
if (image == null) return;
Future<void> saveImage(String? image) async {
Log.ger('save_image', logName, toString());
await save({'$prefix.imagePath': image});

await saveImage(image);
}

@override
Future<void> removeRemotely() async {
await super.removeRemotely();
await deleteImage();
}

Future<void> replaceImage(String? path) async {
if (path != null && path != imagePath) {
await saveImage(XFile(path));
}
}

Future<void> saveImage(XFile image) async {
final dir = await XFile.createDir('menu_image');
final dstPath = '${dir.path}/$id';

// avator first, try sync with image
await ImageDumper.instance.resize(image, '$dstPath-avator', width: 120);

// save image from pick
await image.copy(dstPath);

Log.ger('save_image start', logName, toString());
await save({'$prefix.imagePath': dstPath});

await deleteImage();

imagePath = dstPath;
imagePath = image;

notifyItem();
}
Expand Down
8 changes: 8 additions & 0 deletions lib/models/objects/menu_object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ class CatalogObject extends ModelObject<Catalog> {
model.name = name;
result['$prefix.name'] = name;
}
if (imagePath != null && imagePath != model.imagePath) {
model.imagePath = imagePath;
result['$prefix.imagePath'] = imagePath!;
}
return result;
}

Expand Down Expand Up @@ -210,6 +214,10 @@ class ProductObject extends ModelObject<Product> {
model.searchedAt = searchedAt;
result['$prefix.searchedAt'] = Util.toUTC(now: searchedAt);
}
if (imagePath != null && imagePath != model.imagePath) {
model.imagePath = imagePath;
result['$prefix.imagePath'] = imagePath!;
}
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/models/xfile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class XFile {
static Future<Directory> createDir(String folder) async {
final directory = await getRootPath();

final path = '$directory/$folder';
final path = fs.path.join(directory, folder);

return XFile(path).dir.create();
}
Expand Down
25 changes: 14 additions & 11 deletions lib/routes.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
import 'package:flutter/material.dart';
import 'package:possystem/models/order/order_attribute.dart';
import 'package:possystem/models/order/order_attribute_option.dart';
import 'package:possystem/ui/cashier/widgets/cashier_surplus.dart';
import 'package:possystem/ui/exporter/exporter_screen.dart';
import 'package:possystem/ui/home/home_setup_feature_request.dart';
import 'package:possystem/ui/order/cashier/order_details_screen.dart';
import 'package:provider/provider.dart';

import 'models/menu/catalog.dart';
import 'models/menu/product.dart';
import 'models/menu/product_ingredient.dart';
import 'models/menu/product_quantity.dart';
import 'models/order/order_attribute.dart';
import 'models/order/order_attribute_option.dart';
import 'models/stock/ingredient.dart';
import 'models/stock/quantity.dart';
import 'models/stock/replenishment.dart';
import 'ui/cashier/changer/changer_modal.dart';
import 'ui/order_attr/order_attribute_screen.dart';
import 'ui/order_attr/widgets/order_attribute_reorder.dart';
import 'ui/order_attr/widgets/order_attribute_modal.dart';
import 'ui/order_attr/widgets/order_attribute_option_modal.dart';
import 'ui/order_attr/widgets/order_attribute_option_reorder.dart';
import 'ui/cashier/widgets/cashier_surplus.dart';
import 'ui/exporter/exporter_screen.dart';
import 'ui/home/home_setup_feature_request.dart';
import 'ui/image_gallery_screen.dart';
import 'ui/menu/catalog/catalog_screen.dart';
import 'ui/menu/catalog/widgets/product_modal.dart';
import 'ui/menu/catalog/widgets/product_orderable_list.dart';
Expand All @@ -30,7 +25,13 @@ import 'ui/menu/product/widgets/product_ingredient_modal.dart';
import 'ui/menu/product/widgets/product_quantity_modal.dart';
import 'ui/menu/widgets/catalog_modal.dart';
import 'ui/menu/widgets/catalog_orderable_list.dart';
import 'ui/order/cashier/order_details_screen.dart';
import 'ui/order/order_screen.dart';
import 'ui/order_attr/order_attribute_screen.dart';
import 'ui/order_attr/widgets/order_attribute_modal.dart';
import 'ui/order_attr/widgets/order_attribute_option_modal.dart';
import 'ui/order_attr/widgets/order_attribute_option_reorder.dart';
import 'ui/order_attr/widgets/order_attribute_reorder.dart';
import 'ui/quantities/quantity_screen.dart';
import 'ui/quantities/widgets/quantity_modal.dart';
import 'ui/setting/setting_screen.dart';
Expand All @@ -46,6 +47,7 @@ class Routes {
static const String order = 'order';
static const String quantities = 'quantities';
static const String setting = 'setting';
static const String imageGallery = 'image_gallery';

// sub-route
static const String cashierChanger = 'cashier/changer';
Expand Down Expand Up @@ -75,6 +77,7 @@ class Routes {
menu: (_) => const MenuScreen(),
order: (_) => const OrderScreen(),
setting: (_) => const SettingScreen(),
imageGallery: (_) => const ImageGalleryScreen(),
// sub-route
// cashier
cashierChanger: (_) => const ChangerModal(),
Expand Down
Loading

0 comments on commit ed4ac7b

Please sign in to comment.