💄 Unified design of single attachment uploader
This commit is contained in:
parent
ad1dc064e6
commit
152efd97a0
@ -157,6 +157,9 @@
|
|||||||
"postListNews": "News",
|
"postListNews": "News",
|
||||||
"postListFriends": "Friends",
|
"postListFriends": "Friends",
|
||||||
"postListShuffle": "Random",
|
"postListShuffle": "Random",
|
||||||
|
"attachmentThumbnail": "Thumbnail",
|
||||||
|
"attachmentThumbnailAttachmentNew": "Upload thumbnail",
|
||||||
|
"attachmentThumbnailAttachment": "Attachment serial number",
|
||||||
"postEditorModeStory": "Post a post",
|
"postEditorModeStory": "Post a post",
|
||||||
"postEditorModeArticle": "Post an article",
|
"postEditorModeArticle": "Post an article",
|
||||||
"postEditor": "Post editor",
|
"postEditor": "Post editor",
|
||||||
|
@ -168,6 +168,9 @@
|
|||||||
"postListNews": "新鲜事",
|
"postListNews": "新鲜事",
|
||||||
"postListFriends": "好友圈",
|
"postListFriends": "好友圈",
|
||||||
"postListShuffle": "打乱看",
|
"postListShuffle": "打乱看",
|
||||||
|
"attachmentThumbnail": "附件缩略图",
|
||||||
|
"attachmentThumbnailAttachmentNew": "上传附件作为缩略图",
|
||||||
|
"attachmentThumbnailAttachment": "附件序列号",
|
||||||
"postNew": "创建新帖子",
|
"postNew": "创建新帖子",
|
||||||
"postNewInRealmHint": "在领域 @realm 里发表新帖子",
|
"postNewInRealmHint": "在领域 @realm 里发表新帖子",
|
||||||
"postAction": "发表",
|
"postAction": "发表",
|
||||||
|
@ -9,7 +9,6 @@ import 'package:solian/providers/auth.dart';
|
|||||||
import 'package:solian/providers/content/channel.dart';
|
import 'package:solian/providers/content/channel.dart';
|
||||||
import 'package:solian/providers/content/realm.dart';
|
import 'package:solian/providers/content/realm.dart';
|
||||||
import 'package:solian/providers/relation.dart';
|
import 'package:solian/providers/relation.dart';
|
||||||
import 'package:solian/providers/stickers.dart';
|
|
||||||
import 'package:solian/providers/theme_switcher.dart';
|
import 'package:solian/providers/theme_switcher.dart';
|
||||||
import 'package:solian/providers/websocket.dart';
|
import 'package:solian/providers/websocket.dart';
|
||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
@ -115,7 +114,6 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
|||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
try {
|
try {
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
Get.find<StickerProvider>().refreshAvailableStickers(),
|
|
||||||
if (auth.isAuthorized.isTrue)
|
if (auth.isAuthorized.isTrue)
|
||||||
Get.find<ChannelProvider>().refreshAvailableChannel(),
|
Get.find<ChannelProvider>().refreshAvailableChannel(),
|
||||||
if (auth.isAuthorized.isTrue)
|
if (auth.isAuthorized.isTrue)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:solian/exceptions/request.dart';
|
||||||
import 'package:solian/models/pagination.dart';
|
import 'package:solian/models/pagination.dart';
|
||||||
import 'package:solian/models/stickers.dart';
|
import 'package:solian/models/stickers.dart';
|
||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
@ -31,4 +32,16 @@ class StickerProvider extends GetxController {
|
|||||||
}
|
}
|
||||||
availableStickers.refresh();
|
availableStickers.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Sticker?> getStickerByAlias(String alias) async {
|
||||||
|
final client = await ServiceFinder.configureClient('files');
|
||||||
|
final resp = await client.get(
|
||||||
|
'/stickers/lookup/$alias',
|
||||||
|
);
|
||||||
|
if (resp.statusCode != 200) {
|
||||||
|
throw RequestException(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sticker.fromJson(resp.body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import 'package:solian/screens/account.dart';
|
|||||||
import 'package:solian/screens/account/friend.dart';
|
import 'package:solian/screens/account/friend.dart';
|
||||||
import 'package:solian/screens/account/personalize.dart';
|
import 'package:solian/screens/account/personalize.dart';
|
||||||
import 'package:solian/screens/account/profile_page.dart';
|
import 'package:solian/screens/account/profile_page.dart';
|
||||||
import 'package:solian/screens/account/stickers.dart';
|
|
||||||
import 'package:solian/screens/auth/signin.dart';
|
import 'package:solian/screens/auth/signin.dart';
|
||||||
import 'package:solian/screens/auth/signup.dart';
|
import 'package:solian/screens/auth/signup.dart';
|
||||||
import 'package:solian/screens/channel/channel_chat.dart';
|
import 'package:solian/screens/channel/channel_chat.dart';
|
||||||
@ -238,14 +237,6 @@ abstract class AppRouter {
|
|||||||
name: 'accountFriend',
|
name: 'accountFriend',
|
||||||
builder: (context, state) => const FriendScreen(),
|
builder: (context, state) => const FriendScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
|
||||||
path: '/account/stickers',
|
|
||||||
name: 'accountStickers',
|
|
||||||
builder: (context, state) => TitleShell(
|
|
||||||
state: state,
|
|
||||||
child: const StickerScreen(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/account/personalize',
|
path: '/account/personalize',
|
||||||
name: 'accountProfile',
|
name: 'accountProfile',
|
||||||
|
@ -45,11 +45,6 @@ class _AccountScreenState extends State<AccountScreen> {
|
|||||||
'accountFriend'.tr,
|
'accountFriend'.tr,
|
||||||
'accountFriend',
|
'accountFriend',
|
||||||
),
|
),
|
||||||
(
|
|
||||||
const Icon(Icons.emoji_symbols),
|
|
||||||
'accountStickers'.tr,
|
|
||||||
'accountStickers',
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
|
@ -1,186 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
|
||||||
import 'package:solian/models/pagination.dart';
|
|
||||||
import 'package:solian/models/stickers.dart';
|
|
||||||
import 'package:solian/providers/auth.dart';
|
|
||||||
import 'package:solian/providers/stickers.dart';
|
|
||||||
import 'package:solian/services.dart';
|
|
||||||
import 'package:solian/widgets/auto_cache_image.dart';
|
|
||||||
import 'package:solian/widgets/stickers/sticker_uploader.dart';
|
|
||||||
|
|
||||||
class StickerScreen extends StatefulWidget {
|
|
||||||
const StickerScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StickerScreen> createState() => _StickerScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _StickerScreenState extends State<StickerScreen> {
|
|
||||||
final PagingController<int, StickerPack> _pagingController =
|
|
||||||
PagingController(firstPageKey: 0);
|
|
||||||
|
|
||||||
Future<bool> _promptDelete(Sticker item, String prefix) async {
|
|
||||||
final AuthProvider auth = Get.find();
|
|
||||||
if (auth.isAuthorized.isFalse) return false;
|
|
||||||
|
|
||||||
final confirm = await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: Text('stickerDeletionConfirm'.tr),
|
|
||||||
content: Text(
|
|
||||||
'stickerDeletionConfirmCaption'.trParams({
|
|
||||||
'name': ':${'$prefix${item.alias}'.camelCase}:',
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: Text('cancel'.tr),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context, true),
|
|
||||||
child: Text('confirm'.tr),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (confirm != true) return false;
|
|
||||||
|
|
||||||
final client = await auth.configureClient('files');
|
|
||||||
final resp = await client.delete('/stickers/${item.id}');
|
|
||||||
|
|
||||||
return resp.statusCode == 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool?> _promptUploadSticker({Sticker? edit}) {
|
|
||||||
return showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => StickerUploadDialog(
|
|
||||||
edit: edit,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildEmoteEntry(Sticker item, String prefix) {
|
|
||||||
final imageUrl = ServiceFinder.buildUrl(
|
|
||||||
'files',
|
|
||||||
'/attachments/${item.attachment.rid}',
|
|
||||||
);
|
|
||||||
return ListTile(
|
|
||||||
title: Text(item.name),
|
|
||||||
subtitle: Text(item.textWarpedPlaceholder),
|
|
||||||
contentPadding: const EdgeInsets.only(left: 16, right: 14),
|
|
||||||
trailing: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.edit_square),
|
|
||||||
onPressed: () {
|
|
||||||
_promptUploadSticker(edit: item).then((value) {
|
|
||||||
if (value == true) _pagingController.refresh();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.delete),
|
|
||||||
onPressed: () {
|
|
||||||
_promptDelete(item, prefix).then((value) {
|
|
||||||
if (value == true) _pagingController.refresh();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
leading: AutoCacheImage(
|
|
||||||
imageUrl,
|
|
||||||
width: 28,
|
|
||||||
height: 28,
|
|
||||||
noErrorWidget: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
final AuthProvider auth = Get.find();
|
|
||||||
final name = auth.userProfile.value!['name'];
|
|
||||||
_pagingController.addPageRequestListener((pageKey) async {
|
|
||||||
final client = await ServiceFinder.configureClient('files');
|
|
||||||
final resp = await client.get(
|
|
||||||
'/stickers/manifest?take=10&offset=$pageKey&author=$name',
|
|
||||||
);
|
|
||||||
if (resp.statusCode == 200) {
|
|
||||||
final result = PaginationResult.fromJson(resp.body);
|
|
||||||
final out = result.data?.map((e) => StickerPack.fromJson(e)).toList();
|
|
||||||
if (out != null && result.data!.length >= 10) {
|
|
||||||
_pagingController.appendPage(out, pageKey + out.length);
|
|
||||||
} else if (out != null) {
|
|
||||||
_pagingController.appendLastPage(out);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_pagingController.error = resp.bodyString;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
final StickerProvider sticker = Get.find();
|
|
||||||
sticker.refreshAvailableStickers();
|
|
||||||
_pagingController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
child: const Icon(Icons.add),
|
|
||||||
onPressed: () {
|
|
||||||
_promptUploadSticker().then((value) {
|
|
||||||
if (value == true) _pagingController.refresh();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
body: RefreshIndicator(
|
|
||||||
onRefresh: () => Future.sync(() => _pagingController.refresh()),
|
|
||||||
child: CustomScrollView(
|
|
||||||
slivers: [
|
|
||||||
PagedSliverList<int, StickerPack>(
|
|
||||||
pagingController: _pagingController,
|
|
||||||
builderDelegate: PagedChildBuilderDelegate(
|
|
||||||
itemBuilder: (BuildContext context, item, int index) {
|
|
||||||
return ExpansionTile(
|
|
||||||
title: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(item.name),
|
|
||||||
const Gap(6),
|
|
||||||
Badge(
|
|
||||||
label: Text('#${item.id}'),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
item.description,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
children: item.stickers?.map((x) {
|
|
||||||
x.pack = item;
|
|
||||||
return _buildEmoteEntry(x, item.prefix);
|
|
||||||
}).toList() ??
|
|
||||||
List.empty(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -93,14 +93,14 @@ class _AttachmentEditorThumbnailDialogState
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text('postThumbnail'.tr),
|
title: Text('attachmentThumbnail'.tr),
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Card(
|
Card(
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text('postThumbnailAttachmentNew'.tr),
|
title: Text('attachmentThumbnailAttachmentNew'.tr),
|
||||||
contentPadding: const EdgeInsets.only(left: 12, right: 9),
|
contentPadding: const EdgeInsets.only(left: 12, right: 9),
|
||||||
trailing: const Icon(Icons.chevron_right),
|
trailing: const Icon(Icons.chevron_right),
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
@ -122,7 +122,7 @@ class _AttachmentEditorThumbnailDialogState
|
|||||||
isDense: true,
|
isDense: true,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
prefixText: '#',
|
prefixText: '#',
|
||||||
labelText: 'postThumbnailAttachment'.tr,
|
labelText: 'attachmentThumbnailAttachment'.tr,
|
||||||
),
|
),
|
||||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:solian/controllers/post_editor_controller.dart';
|
import 'package:solian/controllers/post_editor_controller.dart';
|
||||||
import 'package:solian/widgets/attachments/attachment_editor.dart';
|
import 'package:solian/widgets/attachments/attachment_editor.dart';
|
||||||
@ -58,18 +57,25 @@ class _PostEditorThumbnailDialogState extends State<PostEditorThumbnailDialog> {
|
|||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
Card(
|
||||||
title: Text('postThumbnailAttachmentNew'.tr),
|
margin: EdgeInsets.zero,
|
||||||
contentPadding: const EdgeInsets.only(left: 16, right: 13),
|
child: ListTile(
|
||||||
trailing: const Icon(Icons.chevron_right),
|
title: Text('postThumbnailAttachmentNew'.tr),
|
||||||
shape: const RoundedRectangleBorder(
|
contentPadding: const EdgeInsets.only(left: 12, right: 9),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
trailing: const Icon(Icons.chevron_right),
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
_promptUploadNewAttachment();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
onTap: () {
|
|
||||||
_promptUploadNewAttachment();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Row(children: <Widget>[
|
||||||
|
Expanded(child: Divider()),
|
||||||
|
Text('OR'),
|
||||||
|
Expanded(child: Divider()),
|
||||||
|
]).paddingOnly(top: 12, bottom: 16, left: 16, right: 16),
|
||||||
TextField(
|
TextField(
|
||||||
controller: _attachmentController,
|
controller: _attachmentController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
@ -1,212 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:solian/exts.dart';
|
|
||||||
import 'package:solian/models/stickers.dart';
|
|
||||||
import 'package:solian/providers/auth.dart';
|
|
||||||
import 'package:solian/widgets/attachments/attachment_editor.dart';
|
|
||||||
|
|
||||||
class StickerUploadDialog extends StatefulWidget {
|
|
||||||
final Sticker? edit;
|
|
||||||
|
|
||||||
const StickerUploadDialog({super.key, this.edit});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StickerUploadDialog> createState() => _StickerUploadDialogState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _StickerUploadDialogState extends State<StickerUploadDialog> {
|
|
||||||
final TextEditingController _attachmentController = TextEditingController();
|
|
||||||
final TextEditingController _packController = TextEditingController();
|
|
||||||
final TextEditingController _aliasController = TextEditingController();
|
|
||||||
final TextEditingController _nameController = TextEditingController();
|
|
||||||
|
|
||||||
Color get _unFocusColor =>
|
|
||||||
Theme.of(context).colorScheme.onSurface.withOpacity(0.75);
|
|
||||||
|
|
||||||
bool _isBusy = false;
|
|
||||||
|
|
||||||
void _promptUploadNewAttachment() {
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AttachmentEditorPopup(
|
|
||||||
pool: 'sticker',
|
|
||||||
singleMode: true,
|
|
||||||
imageOnly: true,
|
|
||||||
autoUpload: true,
|
|
||||||
imageMaxHeight: 28,
|
|
||||||
imageMaxWidth: 28,
|
|
||||||
onAdd: (value) {
|
|
||||||
setState(() {
|
|
||||||
_attachmentController.text = value.toString();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
initialAttachments: const [],
|
|
||||||
onRemove: (_) {},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _applySticker() async {
|
|
||||||
final AuthProvider auth = Get.find();
|
|
||||||
if (auth.isAuthorized.isFalse) return;
|
|
||||||
|
|
||||||
if ([
|
|
||||||
_nameController.text.isEmpty,
|
|
||||||
_aliasController.text.isEmpty,
|
|
||||||
_packController.text.isEmpty,
|
|
||||||
_attachmentController.text.isEmpty,
|
|
||||||
].any((x) => x)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() => _isBusy = true);
|
|
||||||
|
|
||||||
Response resp;
|
|
||||||
final client = await auth.configureClient('files');
|
|
||||||
if (widget.edit == null) {
|
|
||||||
resp = await client.post('/stickers', {
|
|
||||||
'name': _nameController.text,
|
|
||||||
'alias': _aliasController.text,
|
|
||||||
'pack_id': int.tryParse(_packController.text),
|
|
||||||
'attachment_id': int.tryParse(_attachmentController.text),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resp = await client.put('/stickers/${widget.edit!.id}', {
|
|
||||||
'name': _nameController.text,
|
|
||||||
'alias': _aliasController.text,
|
|
||||||
'pack_id': int.tryParse(_packController.text),
|
|
||||||
'attachment_id': int.tryParse(_attachmentController.text),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() => _isBusy = false);
|
|
||||||
|
|
||||||
if (resp.statusCode != 200) {
|
|
||||||
context.showErrorDialog(resp.bodyString);
|
|
||||||
} else {
|
|
||||||
Navigator.pop(context, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
if (widget.edit != null) {
|
|
||||||
_attachmentController.text = widget.edit!.attachmentId.toString();
|
|
||||||
_packController.text = widget.edit!.packId.toString();
|
|
||||||
_aliasController.text = widget.edit!.alias;
|
|
||||||
_nameController.text = widget.edit!.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_attachmentController.dispose();
|
|
||||||
_packController.dispose();
|
|
||||||
_aliasController.dispose();
|
|
||||||
_nameController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: Text('stickerUploader'.tr),
|
|
||||||
content: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
ListTile(
|
|
||||||
title: Text('stickerUploaderAttachmentNew'.tr),
|
|
||||||
contentPadding: const EdgeInsets.only(left: 16, right: 13),
|
|
||||||
trailing: const Icon(Icons.chevron_right),
|
|
||||||
shape: const RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
_promptUploadNewAttachment();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Gap(8),
|
|
||||||
TextField(
|
|
||||||
controller: _attachmentController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
isDense: true,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
prefixText: '#',
|
|
||||||
labelText: 'stickerUploaderAttachment'.tr,
|
|
||||||
),
|
|
||||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
|
||||||
const Gap(8),
|
|
||||||
TextField(
|
|
||||||
controller: _packController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
isDense: true,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
prefixText: '#',
|
|
||||||
labelText: 'stickerUploaderPack'.tr,
|
|
||||||
),
|
|
||||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 6),
|
|
||||||
child: Text(
|
|
||||||
'stickerUploaderPackHint'.tr,
|
|
||||||
style: TextStyle(color: _unFocusColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextField(
|
|
||||||
controller: _aliasController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
isDense: true,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
labelText: 'stickerUploaderAlias'.tr,
|
|
||||||
),
|
|
||||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 6),
|
|
||||||
child: Text(
|
|
||||||
'stickerUploaderAliasHint'.tr,
|
|
||||||
style: TextStyle(color: _unFocusColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextField(
|
|
||||||
controller: _nameController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
isDense: true,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
labelText: 'stickerUploaderName'.tr,
|
|
||||||
),
|
|
||||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.only(left: 8, right: 8, top: 4),
|
|
||||||
child: Text(
|
|
||||||
'stickerUploaderNameHint'.tr,
|
|
||||||
style: TextStyle(color: _unFocusColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
foregroundColor:
|
|
||||||
Theme.of(context).colorScheme.onSurface.withOpacity(0.8),
|
|
||||||
),
|
|
||||||
onPressed: _isBusy ? null : () => Navigator.pop(context),
|
|
||||||
child: Text('cancel'.tr),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: _isBusy ? null : () => _applySticker(),
|
|
||||||
child: Text('apply'.tr),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user