2024-08-03 17:03:09 +00:00
|
|
|
import 'package:cached_network_image/cached_network_image.dart';
|
2024-08-03 13:29:48 +00:00
|
|
|
import 'package:flutter/material.dart';
|
2024-09-07 09:45:44 +00:00
|
|
|
import 'package:gap/gap.dart';
|
2024-08-03 13:29:48 +00:00
|
|
|
import 'package:get/get.dart';
|
|
|
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
|
|
|
import 'package:solian/models/pagination.dart';
|
2024-08-03 17:03:09 +00:00
|
|
|
import 'package:solian/models/stickers.dart';
|
|
|
|
import 'package:solian/platform.dart';
|
2024-08-03 13:29:48 +00:00
|
|
|
import 'package:solian/providers/auth.dart';
|
2024-08-03 17:37:54 +00:00
|
|
|
import 'package:solian/providers/stickers.dart';
|
2024-08-03 13:29:48 +00:00
|
|
|
import 'package:solian/services.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> {
|
2024-08-03 17:03:09 +00:00
|
|
|
final PagingController<int, StickerPack> _pagingController =
|
2024-08-03 13:29:48 +00:00
|
|
|
PagingController(firstPageKey: 0);
|
|
|
|
|
2024-08-03 17:03:09 +00:00
|
|
|
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}) {
|
2024-08-03 13:29:48 +00:00
|
|
|
return showDialog(
|
|
|
|
context: context,
|
2024-08-03 17:03:09 +00:00
|
|
|
builder: (context) => StickerUploadDialog(
|
|
|
|
edit: edit,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildEmoteEntry(Sticker item, String prefix) {
|
|
|
|
final imageUrl = ServiceFinder.buildUrl(
|
|
|
|
'files',
|
2024-08-18 17:35:38 +00:00
|
|
|
'/attachments/${item.attachment.rid}',
|
2024-08-03 17:03:09 +00:00
|
|
|
);
|
|
|
|
return ListTile(
|
|
|
|
title: Text(item.name),
|
2024-08-06 17:47:53 +00:00
|
|
|
subtitle: Text(item.textWarpedPlaceholder),
|
2024-08-03 17:03:09 +00:00
|
|
|
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,
|
|
|
|
),
|
2024-08-03 13:29:48 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
final AuthProvider auth = Get.find();
|
|
|
|
final name = auth.userProfile.value!['name'];
|
|
|
|
_pagingController.addPageRequestListener((pageKey) async {
|
|
|
|
final client = ServiceFinder.configureClient('files');
|
2024-08-03 17:03:09 +00:00
|
|
|
final resp = await client.get(
|
|
|
|
'/stickers/manifest?take=10&offset=$pageKey&author=$name',
|
|
|
|
);
|
2024-08-03 13:29:48 +00:00
|
|
|
if (resp.statusCode == 200) {
|
|
|
|
final result = PaginationResult.fromJson(resp.body);
|
2024-08-03 17:03:09 +00:00
|
|
|
final out = result.data?.map((e) => StickerPack.fromJson(e)).toList();
|
2024-08-03 13:29:48 +00:00
|
|
|
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() {
|
2024-08-03 17:37:54 +00:00
|
|
|
final StickerProvider sticker = Get.find();
|
|
|
|
sticker.refreshAvailableStickers();
|
2024-08-03 13:29:48 +00:00
|
|
|
_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: [
|
2024-08-03 17:03:09 +00:00
|
|
|
PagedSliverList<int, StickerPack>(
|
2024-08-03 13:29:48 +00:00
|
|
|
pagingController: _pagingController,
|
|
|
|
builderDelegate: PagedChildBuilderDelegate(
|
|
|
|
itemBuilder: (BuildContext context, item, int index) {
|
2024-08-03 17:03:09 +00:00
|
|
|
return ExpansionTile(
|
2024-08-06 16:56:06 +00:00
|
|
|
title: Row(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
Text(item.name),
|
2024-09-07 09:45:44 +00:00
|
|
|
const Gap(6),
|
2024-08-06 16:56:06 +00:00
|
|
|
Badge(
|
|
|
|
label: Text('#${item.id}'),
|
|
|
|
)
|
|
|
|
],
|
|
|
|
),
|
2024-08-03 17:03:09 +00:00
|
|
|
subtitle: Text(
|
|
|
|
item.description,
|
|
|
|
maxLines: 1,
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
),
|
2024-08-06 17:47:53 +00:00
|
|
|
children: item.stickers?.map((x) {
|
|
|
|
x.pack = item;
|
|
|
|
return _buildEmoteEntry(x, item.prefix);
|
|
|
|
}).toList() ??
|
2024-08-03 17:03:09 +00:00
|
|
|
List.empty(),
|
|
|
|
);
|
2024-08-03 13:29:48 +00:00
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|