From 81a79f947622d18ddaf139651eae4fa59010ad75 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 23 Feb 2025 14:23:06 +0800 Subject: [PATCH] :sparkles: Stickers --- assets/translations/en-US.json | 3 +- assets/translations/zh-CN.json | 3 +- assets/translations/zh-HK.json | 18 +++- assets/translations/zh-TW.json | 18 +++- lib/screens/stickers.dart | 118 ++++++++++++++++++++++++++ lib/screens/stickers/pack_detail.dart | 8 ++ 6 files changed, 164 insertions(+), 4 deletions(-) diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index f57a568..97b6b97 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -716,5 +716,6 @@ "fieldStickerPackPrefix": "Prefix", "fieldStickerAttachment": "Attachment", "stickersNew": "New Sticker", - "stickersNewDescription": "Create a new sticker belongs to this pack." + "stickersNewDescription": "Create a new sticker belongs to this pack.", + "stickersPackNew": "New Sticker Pack" } diff --git a/assets/translations/zh-CN.json b/assets/translations/zh-CN.json index 24cbc75..e779b51 100644 --- a/assets/translations/zh-CN.json +++ b/assets/translations/zh-CN.json @@ -714,5 +714,6 @@ "fieldStickerPackPrefix": "贴图包前缀", "fieldStickerAttachment": "附件", "stickersNew": "新建贴图", - "stickersNewDescription": "创建一个新的贴图。" + "stickersNewDescription": "创建一个新的贴图。", + "stickersPackNew": "新建贴图包" } diff --git a/assets/translations/zh-HK.json b/assets/translations/zh-HK.json index 3715cd4..460d392 100644 --- a/assets/translations/zh-HK.json +++ b/assets/translations/zh-HK.json @@ -699,5 +699,21 @@ "stickersRemoved": "貼圖包已被移除,你可以隨時再次添加回來。", "stickersReload": "重載貼圖包", "stickersReloadDescription": "從服務器重新加載添加過的貼圖,更新貼圖選擇器。", - "stickersReloaded": "貼圖包已重載。" + "stickersReloaded": "貼圖包已重載。", + "stickersPackDelete": "刪除貼圖包 {}", + "stickersPackDeleteDescription": "你確定要刪除這個貼圖包嗎?這個操作不可撤銷。", + "stickersPackDeleted": "貼圖包已被刪除。", + "stickersDelete": "刪除貼圖 {}", + "stickersDeleteDescription": "你確定要刪除這個貼圖嗎?這個操作不可撤銷。", + "stickersDeleted": "貼圖已被刪除。", + "fieldStickerName": "貼圖名稱", + "fieldStickerAlias": "貼圖別名", + "fieldStickerAliasHint": "和貼圖包前綴組合成為本貼圖的唯一佔位符。", + "fieldStickerPackName": "名稱", + "fieldStickerPackDescription": "描述", + "fieldStickerPackPrefix": "貼圖包前綴", + "fieldStickerAttachment": "附件", + "stickersNew": "新建貼圖", + "stickersNewDescription": "創建一個新的貼圖。", + "stickersPackNew": "新建貼圖包" } diff --git a/assets/translations/zh-TW.json b/assets/translations/zh-TW.json index 07df298..aef54cd 100644 --- a/assets/translations/zh-TW.json +++ b/assets/translations/zh-TW.json @@ -699,5 +699,21 @@ "stickersRemoved": "貼圖包已被移除,你可以隨時再次添加回來。", "stickersReload": "重載貼圖包", "stickersReloadDescription": "從服務器重新加載添加過的貼圖,更新貼圖選擇器。", - "stickersReloaded": "貼圖包已重載。" + "stickersReloaded": "貼圖包已重載。", + "stickersPackDelete": "刪除貼圖包 {}", + "stickersPackDeleteDescription": "你確定要刪除這個貼圖包嗎?這個操作不可撤銷。", + "stickersPackDeleted": "貼圖包已被刪除。", + "stickersDelete": "刪除貼圖 {}", + "stickersDeleteDescription": "你確定要刪除這個貼圖嗎?這個操作不可撤銷。", + "stickersDeleted": "貼圖已被刪除。", + "fieldStickerName": "貼圖名稱", + "fieldStickerAlias": "貼圖別名", + "fieldStickerAliasHint": "和貼圖包前綴組合成為本貼圖的唯一佔位符。", + "fieldStickerPackName": "名稱", + "fieldStickerPackDescription": "描述", + "fieldStickerPackPrefix": "貼圖包前綴", + "fieldStickerAttachment": "附件", + "stickersNew": "新建貼圖", + "stickersNewDescription": "創建一個新的貼圖。", + "stickersPackNew": "新建貼圖包" } diff --git a/lib/screens/stickers.dart b/lib/screens/stickers.dart index 1308ba4..d96488e 100644 --- a/lib/screens/stickers.dart +++ b/lib/screens/stickers.dart @@ -136,6 +136,20 @@ class _StickerScreenState extends State appBar: AppBar( leading: AutoAppBarLeading(), title: Text('screenStickers').tr(), + actions: [ + IconButton( + icon: const Icon(Symbols.add_circle), + onPressed: () { + showDialog( + context: context, + builder: (context) => _StickerPackCreateDialog(), + ).then((value) { + if (value == true) _refreshPacks(); + }); + }, + ), + const Gap(8), + ], bottom: TabBar( controller: _tabController, tabs: [ @@ -344,3 +358,107 @@ class _StickerPackAddPopupState extends State<_StickerPackAddPopup> { ); } } + +class _StickerPackCreateDialog extends StatefulWidget { + const _StickerPackCreateDialog(); + + @override + State<_StickerPackCreateDialog> createState() => + _StickerPackCreateDialogState(); +} + +class _StickerPackCreateDialogState extends State<_StickerPackCreateDialog> { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _prefixController = TextEditingController(); + final TextEditingController _descriptionController = TextEditingController(); + + bool _isBusy = false; + + Future _createPack() async { + if (_nameController.text.isEmpty || + _prefixController.text.isEmpty || + _descriptionController.text.isEmpty) { + return; + } + + setState(() => _isBusy = true); + + try { + final sn = context.read(); + await sn.client.post( + '/cgi/uc/stickers/packs', + data: { + 'name': _nameController.text, + 'prefix': _prefixController.text, + 'description': _descriptionController.text, + }, + ); + if (!mounted) return; + Navigator.pop(context, true); + } catch (err) { + if (!mounted) return; + context.showErrorDialog(err); + } + } + + @override + void dispose() { + _nameController.dispose(); + _prefixController.dispose(); + _descriptionController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text('stickersPackNew').tr(), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextField( + controller: _nameController, + decoration: InputDecoration( + border: const UnderlineInputBorder(), + labelText: 'fieldStickerPackName'.tr(), + ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + ), + const Gap(4), + TextField( + controller: _prefixController, + decoration: InputDecoration( + border: const UnderlineInputBorder(), + labelText: 'fieldStickerPackPrefix'.tr(), + ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + ), + const Gap(4), + TextField( + controller: _descriptionController, + decoration: InputDecoration( + border: const UnderlineInputBorder(), + labelText: 'fieldStickerPackDescription'.tr(), + ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + ), + ], + ), + actions: [ + TextButton( + onPressed: _isBusy + ? null + : () { + Navigator.pop(context); + }, + child: Text('dialogDismiss').tr(), + ), + TextButton( + onPressed: _isBusy ? null : () => _createPack(), + child: Text('dialogConfirm').tr(), + ), + ], + ); + } +} diff --git a/lib/screens/stickers/pack_detail.dart b/lib/screens/stickers/pack_detail.dart index e3296f3..ddb2e7a 100644 --- a/lib/screens/stickers/pack_detail.dart +++ b/lib/screens/stickers/pack_detail.dart @@ -158,6 +158,14 @@ class _StickerCreateDialogState extends State<_StickerCreateDialog> { bool _isBusy = false; + @override + void dispose() { + _nameController.dispose(); + _aliasController.dispose(); + _attachmentController.dispose(); + super.dispose(); + } + Future _createSticker() async { if (_nameController.text.isEmpty || _aliasController.text.isEmpty ||