Setting of attachment thumbnail

This commit is contained in:
LittleSheep 2024-09-10 21:36:10 +08:00
parent 1210cda998
commit c5a975b5ed
7 changed files with 218 additions and 34 deletions

View File

@ -1,6 +1,4 @@
PODS:
- audio_session (0.0.1):
- Flutter
- connectivity_plus (0.0.1):
- Flutter
- FlutterMacOS
@ -223,11 +221,15 @@ PODS:
- TOCropViewController (~> 2.7.4)
- image_picker_ios (0.0.1):
- Flutter
- just_audio (0.0.1):
- Flutter
- livekit_client (2.2.4):
- Flutter
- WebRTC-SDK (= 125.6422.04)
- media_kit_libs_ios_video (1.0.4):
- Flutter
- media_kit_native_event_loop (1.0.0):
- Flutter
- media_kit_video (0.0.1):
- Flutter
- nanopb (3.30910.0):
- nanopb/decode (= 3.30910.0)
- nanopb/encode (= 3.30910.0)
@ -249,6 +251,8 @@ PODS:
- PromisesObjC (= 2.4.0)
- protocol_handler_ios (0.0.1):
- Flutter
- screen_brightness_ios (0.1.0):
- Flutter
- SDWebImage (5.19.7):
- SDWebImage/Core (= 5.19.7)
- SDWebImage/Core (5.19.7)
@ -264,15 +268,13 @@ PODS:
- TOCropViewController (2.7.4)
- url_launcher_ios (0.0.1):
- Flutter
- video_player_avfoundation (0.0.1):
- volume_controller (0.0.1):
- Flutter
- FlutterMacOS
- wakelock_plus (0.0.1):
- Flutter
- WebRTC-SDK (125.6422.04)
DEPENDENCIES:
- audio_session (from `.symlinks/plugins/audio_session/ios`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
@ -289,19 +291,22 @@ DEPENDENCIES:
- gal (from `.symlinks/plugins/gal/darwin`)
- image_cropper (from `.symlinks/plugins/image_cropper/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- just_audio (from `.symlinks/plugins/just_audio/ios`)
- livekit_client (from `.symlinks/plugins/livekit_client/ios`)
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
- protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`)
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
- volume_controller (from `.symlinks/plugins/volume_controller/ios`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
SPEC REPOS:
@ -334,8 +339,6 @@ SPEC REPOS:
- WebRTC-SDK
EXTERNAL SOURCES:
audio_session:
:path: ".symlinks/plugins/audio_session/ios"
connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/darwin"
device_info_plus:
@ -368,10 +371,14 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/image_cropper/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
just_audio:
:path: ".symlinks/plugins/just_audio/ios"
livekit_client:
:path: ".symlinks/plugins/livekit_client/ios"
media_kit_libs_ios_video:
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
media_kit_native_event_loop:
:path: ".symlinks/plugins/media_kit_native_event_loop/ios"
media_kit_video:
:path: ".symlinks/plugins/media_kit_video/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
pasteboard:
@ -384,6 +391,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/pointer_interceptor_ios/ios"
protocol_handler_ios:
:path: ".symlinks/plugins/protocol_handler_ios/ios"
screen_brightness_ios:
:path: ".symlinks/plugins/screen_brightness_ios/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
@ -392,13 +401,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sqflite/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
video_player_avfoundation:
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
volume_controller:
:path: ".symlinks/plugins/volume_controller/ios"
wakelock_plus:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207
connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
@ -434,8 +442,10 @@ SPEC CHECKSUMS:
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
livekit_client: d079c5f040d4bf2b80440ff0ae997725a183e4bc
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0
@ -445,6 +455,7 @@ SPEC CHECKSUMS:
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
protocol_handler_ios: a5db8abc38526ee326988b808be621e5fd568990
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
@ -452,7 +463,7 @@ SPEC CHECKSUMS:
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
WebRTC-SDK: c3d69a87e7185fad3568f6f3cff7c9ac5890acf3

View File

@ -192,6 +192,7 @@ class AttachmentProvider extends GetConnect {
Future<Response> updateAttachment(
int id,
String alt, {
required Map<String, dynamic> metadata,
bool isMature = false,
}) async {
final AuthProvider auth = Get.find();
@ -201,6 +202,7 @@ class AttachmentProvider extends GetConnect {
var resp = await client.put('/attachments/$id', {
'alt': alt,
'metadata': metadata,
'is_mature': isMature,
});

View File

@ -37,6 +37,7 @@ class _AttachmentAttrEditorDialogState
widget.item.id,
_altController.value.text,
isMature: _isMature,
metadata: widget.item.metadata ?? {},
);
Get.find<AttachmentProvider>().clearCache(id: widget.item.rid);

View File

@ -20,6 +20,7 @@ import 'package:solian/providers/attachment_uploader.dart';
import 'package:solian/providers/auth.dart';
import 'package:solian/providers/content/attachment.dart';
import 'package:solian/widgets/attachments/attachment_attr_editor.dart';
import 'package:solian/widgets/attachments/attachment_editor_thumbnail.dart';
import 'package:solian/widgets/attachments/attachment_fullscreen.dart';
class AttachmentEditorPopup extends StatefulWidget {
@ -264,6 +265,21 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
);
}
void _showAttachmentThumbnailEditor(Attachment element, int idx) {
showDialog(
context: context,
builder: (context) => AttachmentEditorThumbnailDialog(
item: element,
pool: widget.pool,
initialItem: element.metadata?['thumbnail'],
onUpdate: (value) {
_attachments[idx]!.metadata ??= {};
_attachments[idx]!.metadata!['thumbnail'] = value;
},
),
);
}
void _showEdit(Attachment element, int index) {
showDialog(
context: context,
@ -455,11 +471,12 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
);
}
Widget _buildListEntry(Attachment element, int index) {
Widget _buildListEntry(Attachment element, int idx) {
var fileType = element.mimetype.split('/').firstOrNull;
fileType ??= 'unknown';
final canBePreview = fileType.toLowerCase() == 'image';
final canHasThumbnail = fileType.toLowerCase() != 'image';
return Container(
padding: const EdgeInsets.only(left: 16, right: 8, bottom: 16),
@ -491,14 +508,23 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
],
),
),
IconButton(
color: Colors.teal,
icon: const Icon(Icons.preview),
visualDensity: const VisualDensity(horizontal: -4),
onPressed: canBePreview
? () => _showAttachmentPreview(element)
: null,
),
if (canBePreview)
IconButton(
color: Colors.teal,
icon: const Icon(Icons.preview),
visualDensity: const VisualDensity(horizontal: -4),
onPressed: () => _showAttachmentPreview(element),
),
if (canHasThumbnail)
IconButton(
color: Colors.teal,
icon: const Icon(Icons.add_photo_alternate),
visualDensity: const VisualDensity(horizontal: -4),
onPressed: () => _showAttachmentThumbnailEditor(
element,
idx,
),
),
PopupMenuButton(
icon: const Icon(Icons.more_horiz),
iconColor: Theme.of(context).colorScheme.primary,
@ -514,7 +540,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
horizontal: 8,
),
),
onTap: () => _showEdit(element, index),
onTap: () => _showEdit(element, idx),
),
PopupMenuItem(
child: ListTile(
@ -527,7 +553,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
onTap: () {
_deleteAttachment(element).then((_) {
widget.onRemove(element.rid);
setState(() => _attachments.removeAt(index));
setState(() => _attachments.removeAt(idx));
});
},
),
@ -541,7 +567,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
),
onTap: () {
widget.onRemove(element.rid);
setState(() => _attachments.removeAt(index));
setState(() => _attachments.removeAt(idx));
},
),
],

View File

@ -0,0 +1,144 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:solian/exts.dart';
import 'package:solian/models/attachment.dart';
import 'package:solian/providers/content/attachment.dart';
import 'package:solian/widgets/attachments/attachment_editor.dart';
class AttachmentEditorThumbnailDialog extends StatefulWidget {
final Attachment item;
final String pool;
final String? initialItem;
final Function(String? id) onUpdate;
const AttachmentEditorThumbnailDialog({
super.key,
required this.item,
required this.pool,
required this.initialItem,
required this.onUpdate,
});
@override
State<AttachmentEditorThumbnailDialog> createState() =>
_AttachmentEditorThumbnailDialogState();
}
class _AttachmentEditorThumbnailDialogState
extends State<AttachmentEditorThumbnailDialog> {
bool _isLoading = false;
final TextEditingController _attachmentController = TextEditingController();
void _promptUploadNewAttachment() {
showModalBottomSheet(
context: context,
builder: (context) => AttachmentEditorPopup(
pool: widget.pool,
singleMode: true,
imageOnly: true,
autoUpload: true,
onAdd: (value) {
widget.onUpdate(value);
_attachmentController.text = value;
},
initialAttachments: const [],
onRemove: (_) {},
),
);
}
Future<void> _updateAttachment() async {
setState(() => _isLoading = true);
final AttachmentProvider attach = Get.find();
widget.item.metadata ??= {};
widget.item.metadata!['thumbnail'] = _attachmentController.text;
try {
await attach.updateAttachment(
widget.item.id,
widget.item.alt,
isMature: widget.item.isMature,
metadata: widget.item.metadata!,
);
Get.find<AttachmentProvider>().clearCache(id: widget.item.rid);
} catch (e) {
context.showErrorDialog(e);
} finally {
setState(() => _isLoading = false);
}
}
@override
void initState() {
if (widget.initialItem != null) {
_attachmentController.text = widget.initialItem!;
}
super.initState();
}
@override
void dispose() {
_attachmentController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('postThumbnail'.tr),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
margin: EdgeInsets.zero,
child: ListTile(
title: Text('postThumbnailAttachmentNew'.tr),
contentPadding: const EdgeInsets.only(left: 12, right: 9),
trailing: const Icon(Icons.chevron_right),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
onTap: () {
_promptUploadNewAttachment();
},
),
),
const Row(children: <Widget>[
Expanded(child: Divider()),
Text('OR'),
Expanded(child: Divider()),
]).paddingOnly(top: 12, bottom: 16, left: 16, right: 16),
TextField(
controller: _attachmentController,
decoration: InputDecoration(
isDense: true,
border: const OutlineInputBorder(),
prefixText: '#',
labelText: 'postThumbnailAttachment'.tr,
),
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
),
],
),
actions: [
TextButton(
onPressed: _isLoading
? null
: () {
_updateAttachment().then((_) {
widget.onUpdate(_attachmentController.text);
if (mounted) {
Navigator.pop(context);
}
});
},
child: Text('confirm'.tr),
),
],
);
}
}

View File

@ -299,14 +299,14 @@ class _PostItemState extends State<PostItem> {
return AttachmentList(
parentId: widget.item.id.toString(),
attachmentsId: attachments,
autoload: true,
autoload: false,
isGrid: true,
).paddingOnly(left: 36, top: 4, bottom: 4);
} else if (attachments.length > 1) {
return AttachmentList(
parentId: widget.item.id.toString(),
attachmentsId: attachments,
autoload: true,
autoload: false,
isColumn: true,
).paddingOnly(left: 60, right: 24);
} else {
@ -314,7 +314,7 @@ class _PostItemState extends State<PostItem> {
flatMaxHeight: MediaQuery.of(context).size.width,
parentId: widget.item.id.toString(),
attachmentsId: attachments,
autoload: true,
autoload: false,
);
}
}

View File

@ -2,7 +2,7 @@ name: solian
description: "The Solar Network App"
publish_to: "none"
version: 1.2.1+30
version: 1.2.1+32
environment:
sdk: ">=3.3.4 <4.0.0"