✨ Basic sticker management
This commit is contained in:
		
							
								
								
									
										122
									
								
								lib/models/stickers.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								lib/models/stickers.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					import 'package:solian/models/account.dart';
 | 
				
			||||||
 | 
					import 'package:solian/models/attachment.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Sticker {
 | 
				
			||||||
 | 
					  int id;
 | 
				
			||||||
 | 
					  DateTime createdAt;
 | 
				
			||||||
 | 
					  DateTime updatedAt;
 | 
				
			||||||
 | 
					  DateTime? deletedAt;
 | 
				
			||||||
 | 
					  String alias;
 | 
				
			||||||
 | 
					  String name;
 | 
				
			||||||
 | 
					  int attachmentId;
 | 
				
			||||||
 | 
					  Attachment attachment;
 | 
				
			||||||
 | 
					  int packId;
 | 
				
			||||||
 | 
					  StickerPack? pack;
 | 
				
			||||||
 | 
					  int accountId;
 | 
				
			||||||
 | 
					  Account account;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Sticker({
 | 
				
			||||||
 | 
					    required this.id,
 | 
				
			||||||
 | 
					    required this.createdAt,
 | 
				
			||||||
 | 
					    required this.updatedAt,
 | 
				
			||||||
 | 
					    required this.deletedAt,
 | 
				
			||||||
 | 
					    required this.alias,
 | 
				
			||||||
 | 
					    required this.name,
 | 
				
			||||||
 | 
					    required this.attachmentId,
 | 
				
			||||||
 | 
					    required this.attachment,
 | 
				
			||||||
 | 
					    required this.packId,
 | 
				
			||||||
 | 
					    required this.pack,
 | 
				
			||||||
 | 
					    required this.accountId,
 | 
				
			||||||
 | 
					    required this.account,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  factory Sticker.fromJson(Map<String, dynamic> json) => Sticker(
 | 
				
			||||||
 | 
					        id: json['id'],
 | 
				
			||||||
 | 
					        createdAt: DateTime.parse(json['created_at']),
 | 
				
			||||||
 | 
					        updatedAt: DateTime.parse(json['updated_at']),
 | 
				
			||||||
 | 
					        deletedAt: json['deleted_at'] != null
 | 
				
			||||||
 | 
					            ? DateTime.parse(json['deleted_at'])
 | 
				
			||||||
 | 
					            : json['deleted_at'],
 | 
				
			||||||
 | 
					        alias: json['alias'],
 | 
				
			||||||
 | 
					        name: json['name'],
 | 
				
			||||||
 | 
					        attachmentId: json['attachment_id'],
 | 
				
			||||||
 | 
					        attachment: Attachment.fromJson(json['attachment']),
 | 
				
			||||||
 | 
					        packId: json['pack_id'],
 | 
				
			||||||
 | 
					        pack: json['pack'] != null ? StickerPack.fromJson(json['pack']) : null,
 | 
				
			||||||
 | 
					        accountId: json['account_id'],
 | 
				
			||||||
 | 
					        account: Account.fromJson(json['account']),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Map<String, dynamic> toJson() => {
 | 
				
			||||||
 | 
					        'id': id,
 | 
				
			||||||
 | 
					        'created_at': createdAt.toIso8601String(),
 | 
				
			||||||
 | 
					        'updated_at': updatedAt.toIso8601String(),
 | 
				
			||||||
 | 
					        'deleted_at': deletedAt?.toIso8601String(),
 | 
				
			||||||
 | 
					        'alias': alias,
 | 
				
			||||||
 | 
					        'name': name,
 | 
				
			||||||
 | 
					        'attachment_id': attachmentId,
 | 
				
			||||||
 | 
					        'attachment': attachment.toJson(),
 | 
				
			||||||
 | 
					        'pack_id': packId,
 | 
				
			||||||
 | 
					        'account_id': accountId,
 | 
				
			||||||
 | 
					        'account': account.toJson(),
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StickerPack {
 | 
				
			||||||
 | 
					  int id;
 | 
				
			||||||
 | 
					  DateTime createdAt;
 | 
				
			||||||
 | 
					  DateTime updatedAt;
 | 
				
			||||||
 | 
					  DateTime? deletedAt;
 | 
				
			||||||
 | 
					  String prefix;
 | 
				
			||||||
 | 
					  String name;
 | 
				
			||||||
 | 
					  String description;
 | 
				
			||||||
 | 
					  List<Sticker>? stickers;
 | 
				
			||||||
 | 
					  int accountId;
 | 
				
			||||||
 | 
					  Account account;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  StickerPack({
 | 
				
			||||||
 | 
					    required this.id,
 | 
				
			||||||
 | 
					    required this.createdAt,
 | 
				
			||||||
 | 
					    required this.updatedAt,
 | 
				
			||||||
 | 
					    required this.deletedAt,
 | 
				
			||||||
 | 
					    required this.prefix,
 | 
				
			||||||
 | 
					    required this.name,
 | 
				
			||||||
 | 
					    required this.description,
 | 
				
			||||||
 | 
					    required this.stickers,
 | 
				
			||||||
 | 
					    required this.accountId,
 | 
				
			||||||
 | 
					    required this.account,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  factory StickerPack.fromJson(Map<String, dynamic> json) => StickerPack(
 | 
				
			||||||
 | 
					        id: json['id'],
 | 
				
			||||||
 | 
					        createdAt: DateTime.parse(json['created_at']),
 | 
				
			||||||
 | 
					        updatedAt: DateTime.parse(json['updated_at']),
 | 
				
			||||||
 | 
					        deletedAt: json['deleted_at'] != null
 | 
				
			||||||
 | 
					            ? DateTime.parse(json['deleted_at'])
 | 
				
			||||||
 | 
					            : json['deleted_at'],
 | 
				
			||||||
 | 
					        prefix: json['prefix'],
 | 
				
			||||||
 | 
					        name: json['name'],
 | 
				
			||||||
 | 
					        description: json['description'],
 | 
				
			||||||
 | 
					        stickers: json['stickers'] == null
 | 
				
			||||||
 | 
					            ? []
 | 
				
			||||||
 | 
					            : List<Sticker>.from(
 | 
				
			||||||
 | 
					                json['stickers']!.map((x) => Sticker.fromJson(x))),
 | 
				
			||||||
 | 
					        accountId: json['account_id'],
 | 
				
			||||||
 | 
					        account: Account.fromJson(json['account']),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Map<String, dynamic> toJson() => {
 | 
				
			||||||
 | 
					        'id': id,
 | 
				
			||||||
 | 
					        'created_at': createdAt.toIso8601String(),
 | 
				
			||||||
 | 
					        'updated_at': updatedAt.toIso8601String(),
 | 
				
			||||||
 | 
					        'deleted_at': deletedAt?.toIso8601String(),
 | 
				
			||||||
 | 
					        'prefix': prefix,
 | 
				
			||||||
 | 
					        'name': name,
 | 
				
			||||||
 | 
					        'description': description,
 | 
				
			||||||
 | 
					        'stickers': stickers == null
 | 
				
			||||||
 | 
					            ? []
 | 
				
			||||||
 | 
					            : List<dynamic>.from(stickers!.map((x) => x.toJson())),
 | 
				
			||||||
 | 
					        'account_id': accountId,
 | 
				
			||||||
 | 
					        'account': account.toJson(),
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,10 @@
 | 
				
			|||||||
 | 
					import 'package:cached_network_image/cached_network_image.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:get/get.dart';
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
 | 
					import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
 | 
				
			||||||
import 'package:solian/models/pagination.dart';
 | 
					import 'package:solian/models/pagination.dart';
 | 
				
			||||||
 | 
					import 'package:solian/models/stickers.dart';
 | 
				
			||||||
 | 
					import 'package:solian/platform.dart';
 | 
				
			||||||
import 'package:solian/providers/auth.dart';
 | 
					import 'package:solian/providers/auth.dart';
 | 
				
			||||||
import 'package:solian/services.dart';
 | 
					import 'package:solian/services.dart';
 | 
				
			||||||
import 'package:solian/widgets/stickers/sticker_uploader.dart';
 | 
					import 'package:solian/widgets/stickers/sticker_uploader.dart';
 | 
				
			||||||
@@ -14,13 +17,92 @@ class StickerScreen extends StatefulWidget {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _StickerScreenState extends State<StickerScreen> {
 | 
					class _StickerScreenState extends State<StickerScreen> {
 | 
				
			||||||
  final PagingController<int, dynamic> _pagingController =
 | 
					  final PagingController<int, StickerPack> _pagingController =
 | 
				
			||||||
      PagingController(firstPageKey: 0);
 | 
					      PagingController(firstPageKey: 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<bool?> _promptUploadSticker() {
 | 
					  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 = auth.configureClient('files');
 | 
				
			||||||
 | 
					    final resp = await client.delete('/stickers/${item.id}');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return resp.statusCode == 200;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<bool?> _promptUploadSticker({Sticker? edit}) {
 | 
				
			||||||
    return showDialog(
 | 
					    return showDialog(
 | 
				
			||||||
      context: context,
 | 
					      context: context,
 | 
				
			||||||
      builder: (context) => const StickerUploadDialog(),
 | 
					      builder: (context) => StickerUploadDialog(
 | 
				
			||||||
 | 
					        edit: edit,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Widget _buildEmoteEntry(Sticker item, String prefix) {
 | 
				
			||||||
 | 
					    final imageUrl = ServiceFinder.buildUrl(
 | 
				
			||||||
 | 
					      'files',
 | 
				
			||||||
 | 
					      '/attachments/${item.attachmentId}',
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    return ListTile(
 | 
				
			||||||
 | 
					      title: Text(item.name),
 | 
				
			||||||
 | 
					      subtitle: Text(':${'$prefix${item.alias}'.camelCase}:'),
 | 
				
			||||||
 | 
					      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: PlatformInfo.canCacheImage
 | 
				
			||||||
 | 
					          ? CachedNetworkImage(
 | 
				
			||||||
 | 
					              imageUrl: imageUrl,
 | 
				
			||||||
 | 
					              width: 28,
 | 
				
			||||||
 | 
					              height: 28,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          : Image.network(
 | 
				
			||||||
 | 
					              imageUrl,
 | 
				
			||||||
 | 
					              width: 28,
 | 
				
			||||||
 | 
					              height: 28,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,13 +112,12 @@ class _StickerScreenState extends State<StickerScreen> {
 | 
				
			|||||||
    final name = auth.userProfile.value!['name'];
 | 
					    final name = auth.userProfile.value!['name'];
 | 
				
			||||||
    _pagingController.addPageRequestListener((pageKey) async {
 | 
					    _pagingController.addPageRequestListener((pageKey) async {
 | 
				
			||||||
      final client = ServiceFinder.configureClient('files');
 | 
					      final client = ServiceFinder.configureClient('files');
 | 
				
			||||||
      final resp =
 | 
					      final resp = await client.get(
 | 
				
			||||||
          await client.get('/stickers?take=10&offset=$pageKey&author=$name');
 | 
					        '/stickers/manifest?take=10&offset=$pageKey&author=$name',
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
      if (resp.statusCode == 200) {
 | 
					      if (resp.statusCode == 200) {
 | 
				
			||||||
        final result = PaginationResult.fromJson(resp.body);
 | 
					        final result = PaginationResult.fromJson(resp.body);
 | 
				
			||||||
        final out = result.data
 | 
					        final out = result.data?.map((e) => StickerPack.fromJson(e)).toList();
 | 
				
			||||||
            ?.map((e) => e) // TODO transform object
 | 
					 | 
				
			||||||
            .toList();
 | 
					 | 
				
			||||||
        if (out != null && result.data!.length >= 10) {
 | 
					        if (out != null && result.data!.length >= 10) {
 | 
				
			||||||
          _pagingController.appendPage(out, pageKey + out.length);
 | 
					          _pagingController.appendPage(out, pageKey + out.length);
 | 
				
			||||||
        } else if (out != null) {
 | 
					        } else if (out != null) {
 | 
				
			||||||
@@ -70,11 +151,22 @@ class _StickerScreenState extends State<StickerScreen> {
 | 
				
			|||||||
        onRefresh: () => Future.sync(() => _pagingController.refresh()),
 | 
					        onRefresh: () => Future.sync(() => _pagingController.refresh()),
 | 
				
			||||||
        child: CustomScrollView(
 | 
					        child: CustomScrollView(
 | 
				
			||||||
          slivers: [
 | 
					          slivers: [
 | 
				
			||||||
            PagedSliverList(
 | 
					            PagedSliverList<int, StickerPack>(
 | 
				
			||||||
              pagingController: _pagingController,
 | 
					              pagingController: _pagingController,
 | 
				
			||||||
              builderDelegate: PagedChildBuilderDelegate(
 | 
					              builderDelegate: PagedChildBuilderDelegate(
 | 
				
			||||||
                itemBuilder: (BuildContext context, item, int index) {
 | 
					                itemBuilder: (BuildContext context, item, int index) {
 | 
				
			||||||
                  return const SizedBox();
 | 
					                  return ExpansionTile(
 | 
				
			||||||
 | 
					                    title: Text(item.name),
 | 
				
			||||||
 | 
					                    subtitle: Text(
 | 
				
			||||||
 | 
					                      item.description,
 | 
				
			||||||
 | 
					                      maxLines: 1,
 | 
				
			||||||
 | 
					                      overflow: TextOverflow.ellipsis,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                    children: item.stickers
 | 
				
			||||||
 | 
					                            ?.map((x) => _buildEmoteEntry(x, item.prefix))
 | 
				
			||||||
 | 
					                            .toList() ??
 | 
				
			||||||
 | 
					                        List.empty(),
 | 
				
			||||||
 | 
					                  );
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -163,9 +163,11 @@ const i18nEnglish = {
 | 
				
			|||||||
  'attachmentAutoUpload': 'Auto Upload',
 | 
					  'attachmentAutoUpload': 'Auto Upload',
 | 
				
			||||||
  'attachmentUploadQueue': 'Upload Queue',
 | 
					  'attachmentUploadQueue': 'Upload Queue',
 | 
				
			||||||
  'attachmentUploadQueueStart': 'Start All',
 | 
					  'attachmentUploadQueueStart': 'Start All',
 | 
				
			||||||
  'attachmentUploadInProgress': 'There are attachments being uploaded. Please wait until all attachments have been uploaded before proceeding...',
 | 
					  'attachmentUploadInProgress':
 | 
				
			||||||
 | 
					      'There are attachments being uploaded. Please wait until all attachments have been uploaded before proceeding...',
 | 
				
			||||||
  'attachmentAttached': 'Exists Files',
 | 
					  'attachmentAttached': 'Exists Files',
 | 
				
			||||||
  'attachmentUploadBlocked': 'Upload blocked, there is currently a task in progress...',
 | 
					  'attachmentUploadBlocked':
 | 
				
			||||||
 | 
					      'Upload blocked, there is currently a task in progress...',
 | 
				
			||||||
  'attachmentAdd': 'Attach attachments',
 | 
					  'attachmentAdd': 'Attach attachments',
 | 
				
			||||||
  'attachmentAddGalleryPhoto': 'Gallery photo',
 | 
					  'attachmentAddGalleryPhoto': 'Gallery photo',
 | 
				
			||||||
  'attachmentAddGalleryVideo': 'Gallery video',
 | 
					  'attachmentAddGalleryVideo': 'Gallery video',
 | 
				
			||||||
@@ -174,7 +176,8 @@ const i18nEnglish = {
 | 
				
			|||||||
  'attachmentAddClipboard': 'Paste file',
 | 
					  'attachmentAddClipboard': 'Paste file',
 | 
				
			||||||
  'attachmentAddFile': 'Attach file',
 | 
					  'attachmentAddFile': 'Attach file',
 | 
				
			||||||
  'attachmentAddLink': 'Link attachments',
 | 
					  'attachmentAddLink': 'Link attachments',
 | 
				
			||||||
  'attachmentAddLinkHint': 'Enter attachment serial number to link that attachment',
 | 
					  'attachmentAddLinkHint':
 | 
				
			||||||
 | 
					      'Enter attachment serial number to link that attachment',
 | 
				
			||||||
  'attachmentAddLinkInput': 'Serial number',
 | 
					  'attachmentAddLinkInput': 'Serial number',
 | 
				
			||||||
  'attachmentSetting': 'Adjust attachment',
 | 
					  'attachmentSetting': 'Adjust attachment',
 | 
				
			||||||
  'attachmentAlt': 'Alternative text',
 | 
					  'attachmentAlt': 'Alternative text',
 | 
				
			||||||
@@ -318,8 +321,10 @@ const i18nEnglish = {
 | 
				
			|||||||
  'bsCheckForUpdate': 'Checking For Updates',
 | 
					  'bsCheckForUpdate': 'Checking For Updates',
 | 
				
			||||||
  'bsCheckForUpdateFailed': 'Unable to Check Updates',
 | 
					  'bsCheckForUpdateFailed': 'Unable to Check Updates',
 | 
				
			||||||
  'bsCheckForUpdateNew': 'Found New Version',
 | 
					  'bsCheckForUpdateNew': 'Found New Version',
 | 
				
			||||||
  'bsCheckForUpdateDescApple': 'Please head to TestFlight and update your app to latest version to prevent error happens and get latest functions.',
 | 
					  'bsCheckForUpdateDescApple':
 | 
				
			||||||
  'bsCheckForUpdateDescCommon': 'Please head to our website download and install latest version of application to prevent error happens and get latest functions.',
 | 
					      'Please head to TestFlight and update your app to latest version to prevent error happens and get latest functions.',
 | 
				
			||||||
 | 
					  'bsCheckForUpdateDescCommon':
 | 
				
			||||||
 | 
					      'Please head to our website download and install latest version of application to prevent error happens and get latest functions.',
 | 
				
			||||||
  'bsCheckingServer': 'Checking Server Status',
 | 
					  'bsCheckingServer': 'Checking Server Status',
 | 
				
			||||||
  'bsCheckingServerFail':
 | 
					  'bsCheckingServerFail':
 | 
				
			||||||
      'Unable connect to server, check your network connection',
 | 
					      'Unable connect to server, check your network connection',
 | 
				
			||||||
@@ -337,6 +342,9 @@ const i18nEnglish = {
 | 
				
			|||||||
  'themeColorMiku': 'Miku Blue',
 | 
					  'themeColorMiku': 'Miku Blue',
 | 
				
			||||||
  'themeColorKagamine': 'Kagamine Yellow',
 | 
					  'themeColorKagamine': 'Kagamine Yellow',
 | 
				
			||||||
  'themeColorLuka': 'Luka Pink',
 | 
					  'themeColorLuka': 'Luka Pink',
 | 
				
			||||||
 | 
					  'stickerDeletionConfirm': 'Confirm sticker delete',
 | 
				
			||||||
 | 
					  'stickerDeletionConfirmCaption':
 | 
				
			||||||
 | 
					      'Are you sure to delete sticker @name? This action cannot be undo.',
 | 
				
			||||||
  'themeColorApplied': 'Global theme color has been applied.',
 | 
					  'themeColorApplied': 'Global theme color has been applied.',
 | 
				
			||||||
  'attachmentSaved': 'Attachment saved to your system album.',
 | 
					  'attachmentSaved': 'Attachment saved to your system album.',
 | 
				
			||||||
  'cropImage': 'Crop Image',
 | 
					  'cropImage': 'Crop Image',
 | 
				
			||||||
@@ -344,9 +352,12 @@ const i18nEnglish = {
 | 
				
			|||||||
  'stickerUploaderAttachmentNew': 'Upload new attachment',
 | 
					  'stickerUploaderAttachmentNew': 'Upload new attachment',
 | 
				
			||||||
  'stickerUploaderAttachment': 'Attachment serial number',
 | 
					  'stickerUploaderAttachment': 'Attachment serial number',
 | 
				
			||||||
  'stickerUploaderPack': 'Sticker pack serial number',
 | 
					  'stickerUploaderPack': 'Sticker pack serial number',
 | 
				
			||||||
  'stickerUploaderPackHint': 'Don\'t have pack id? Head to creator platform and create one!',
 | 
					  'stickerUploaderPackHint':
 | 
				
			||||||
 | 
					      'Don\'t have pack id? Head to creator platform and create one!',
 | 
				
			||||||
  'stickerUploaderAlias': 'Alias',
 | 
					  'stickerUploaderAlias': 'Alias',
 | 
				
			||||||
  'stickerUploaderAliasHint': 'Will be used as a placeholder with the sticker pack prefix when entered.',
 | 
					  'stickerUploaderAliasHint':
 | 
				
			||||||
 | 
					      'Will be used as a placeholder with the sticker pack prefix when entered.',
 | 
				
			||||||
  'stickerUploaderName': 'Name',
 | 
					  'stickerUploaderName': 'Name',
 | 
				
			||||||
  'stickerUploaderNameHint': 'A human-friendly name given to the user in the sticker selection interface.',
 | 
					  'stickerUploaderNameHint':
 | 
				
			||||||
 | 
					      'A human-friendly name given to the user in the sticker selection interface.',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -315,6 +315,8 @@ const i18nSimplifiedChinese = {
 | 
				
			|||||||
  'themeColorKagamine': '镜音黄',
 | 
					  'themeColorKagamine': '镜音黄',
 | 
				
			||||||
  'themeColorLuka': '流音粉',
 | 
					  'themeColorLuka': '流音粉',
 | 
				
			||||||
  'themeColorApplied': '全局主题颜色已应用',
 | 
					  'themeColorApplied': '全局主题颜色已应用',
 | 
				
			||||||
 | 
					  'stickerDeletionConfirm': '确认删除贴图',
 | 
				
			||||||
 | 
					  'stickerDeletionConfirmCaption': '你确认要删除贴图 @name 吗?该操作不可撤销。',
 | 
				
			||||||
  'attachmentSaved': '附件已保存到系统相册',
 | 
					  'attachmentSaved': '附件已保存到系统相册',
 | 
				
			||||||
  'cropImage': '裁剪图片',
 | 
					  'cropImage': '裁剪图片',
 | 
				
			||||||
  'stickerUploader': '上传贴图',
 | 
					  'stickerUploader': '上传贴图',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,14 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:get/get.dart';
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
import 'package:solian/exts.dart';
 | 
					import 'package:solian/exts.dart';
 | 
				
			||||||
 | 
					import 'package:solian/models/stickers.dart';
 | 
				
			||||||
import 'package:solian/providers/auth.dart';
 | 
					import 'package:solian/providers/auth.dart';
 | 
				
			||||||
import 'package:solian/widgets/attachments/attachment_editor.dart';
 | 
					import 'package:solian/widgets/attachments/attachment_editor.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StickerUploadDialog extends StatefulWidget {
 | 
					class StickerUploadDialog extends StatefulWidget {
 | 
				
			||||||
  const StickerUploadDialog({super.key});
 | 
					  final Sticker? edit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const StickerUploadDialog({super.key, this.edit});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State<StickerUploadDialog> createState() => _StickerUploadDialogState();
 | 
					  State<StickerUploadDialog> createState() => _StickerUploadDialogState();
 | 
				
			||||||
@@ -56,13 +59,27 @@ class _StickerUploadDialogState extends State<StickerUploadDialog> {
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setState(() => _isBusy = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Response resp;
 | 
				
			||||||
    final client = auth.configureClient('files');
 | 
					    final client = auth.configureClient('files');
 | 
				
			||||||
    final resp = await client.post('/stickers', {
 | 
					    if (widget.edit == null) {
 | 
				
			||||||
      'name': _nameController.text,
 | 
					      resp = await client.post('/stickers', {
 | 
				
			||||||
      'alias': _aliasController.text,
 | 
					        'name': _nameController.text,
 | 
				
			||||||
      'pack_id': int.tryParse(_packController.text),
 | 
					        'alias': _aliasController.text,
 | 
				
			||||||
      'attachment_id': int.tryParse(_attachmentController.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) {
 | 
					    if (resp.statusCode != 200) {
 | 
				
			||||||
      context.showErrorDialog(resp.bodyString);
 | 
					      context.showErrorDialog(resp.bodyString);
 | 
				
			||||||
@@ -71,6 +88,17 @@ class _StickerUploadDialogState extends State<StickerUploadDialog> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @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
 | 
					  @override
 | 
				
			||||||
  void dispose() {
 | 
					  void dispose() {
 | 
				
			||||||
    _attachmentController.dispose();
 | 
					    _attachmentController.dispose();
 | 
				
			||||||
@@ -164,7 +192,7 @@ class _StickerUploadDialogState extends State<StickerUploadDialog> {
 | 
				
			|||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      actions: <Widget>[
 | 
					      actions: [
 | 
				
			||||||
        TextButton(
 | 
					        TextButton(
 | 
				
			||||||
          style: TextButton.styleFrom(
 | 
					          style: TextButton.styleFrom(
 | 
				
			||||||
            foregroundColor:
 | 
					            foregroundColor:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user