⬆️ Support new attachments system
This commit is contained in:
		| @@ -31,9 +31,9 @@ class PostEditorController extends GetxController { | |||||||
|   Rx<Realm?> realmZone = Rx(null); |   Rx<Realm?> realmZone = Rx(null); | ||||||
|   Rx<DateTime?> publishedAt = Rx(null); |   Rx<DateTime?> publishedAt = Rx(null); | ||||||
|   Rx<DateTime?> publishedUntil = Rx(null); |   Rx<DateTime?> publishedUntil = Rx(null); | ||||||
|   RxList<int> attachments = RxList<int>.empty(growable: true); |   RxList<String> attachments = RxList<String>.empty(growable: true); | ||||||
|   RxList<String> tags = RxList<String>.empty(growable: true); |   RxList<String> tags = RxList<String>.empty(growable: true); | ||||||
|   Rx<int?> thumbnail = Rx(null); |   Rx<String?> thumbnail = Rx(null); | ||||||
|  |  | ||||||
|   RxList<int> visibleUsers = RxList.empty(growable: true); |   RxList<int> visibleUsers = RxList.empty(growable: true); | ||||||
|   RxList<int> invisibleUsers = RxList.empty(growable: true); |   RxList<int> invisibleUsers = RxList.empty(growable: true); | ||||||
| @@ -116,12 +116,12 @@ class PostEditorController extends GetxController { | |||||||
|     return showModalBottomSheet( |     return showModalBottomSheet( | ||||||
|       context: context, |       context: context, | ||||||
|       builder: (context) => AttachmentEditorPopup( |       builder: (context) => AttachmentEditorPopup( | ||||||
|         usage: 'i.attachment', |         pool: 'interactive', | ||||||
|         initialAttachments: attachments, |         initialAttachments: attachments, | ||||||
|         onAdd: (int value) { |         onAdd: (String value) { | ||||||
|           attachments.add(value); |           attachments.add(value); | ||||||
|         }, |         }, | ||||||
|         onRemove: (int value) { |         onRemove: (String value) { | ||||||
|           attachments.remove(value); |           attachments.remove(value); | ||||||
|         }, |         }, | ||||||
|       ), |       ), | ||||||
| @@ -169,6 +169,7 @@ class PostEditorController extends GetxController { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   void currentClear() { |   void currentClear() { | ||||||
|  |     aliasController.clear(); | ||||||
|     titleController.clear(); |     titleController.clear(); | ||||||
|     descriptionController.clear(); |     descriptionController.clear(); | ||||||
|     contentController.clear(); |     contentController.clear(); | ||||||
|   | |||||||
| @@ -5,11 +5,11 @@ class Attachment { | |||||||
|   DateTime createdAt; |   DateTime createdAt; | ||||||
|   DateTime updatedAt; |   DateTime updatedAt; | ||||||
|   DateTime? deletedAt; |   DateTime? deletedAt; | ||||||
|  |   String rid; | ||||||
|   String uuid; |   String uuid; | ||||||
|   int size; |   int size; | ||||||
|   String name; |   String name; | ||||||
|   String alt; |   String alt; | ||||||
|   String usage; |  | ||||||
|   String mimetype; |   String mimetype; | ||||||
|   String hash; |   String hash; | ||||||
|   int destination; |   int destination; | ||||||
| @@ -24,11 +24,11 @@ class Attachment { | |||||||
|     required this.createdAt, |     required this.createdAt, | ||||||
|     required this.updatedAt, |     required this.updatedAt, | ||||||
|     required this.deletedAt, |     required this.deletedAt, | ||||||
|  |     required this.rid, | ||||||
|     required this.uuid, |     required this.uuid, | ||||||
|     required this.size, |     required this.size, | ||||||
|     required this.name, |     required this.name, | ||||||
|     required this.alt, |     required this.alt, | ||||||
|     required this.usage, |  | ||||||
|     required this.mimetype, |     required this.mimetype, | ||||||
|     required this.hash, |     required this.hash, | ||||||
|     required this.destination, |     required this.destination, | ||||||
| @@ -40,42 +40,45 @@ class Attachment { | |||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   factory Attachment.fromJson(Map<String, dynamic> json) => Attachment( |   factory Attachment.fromJson(Map<String, dynamic> json) => Attachment( | ||||||
|     id: json['id'], |         id: json['id'], | ||||||
|     createdAt: DateTime.parse(json['created_at']), |         createdAt: DateTime.parse(json['created_at']), | ||||||
|     updatedAt: DateTime.parse(json['updated_at']), |         updatedAt: DateTime.parse(json['updated_at']), | ||||||
|     deletedAt: json['deleted_at'] != null ? DateTime.parse(json['deleted_at']) : null, |         deletedAt: json['deleted_at'] != null | ||||||
|     uuid: json['uuid'], |             ? DateTime.parse(json['deleted_at']) | ||||||
|     size: json['size'], |             : null, | ||||||
|     name: json['name'], |         rid: json['rid'], | ||||||
|     alt: json['alt'], |         uuid: json['uuid'], | ||||||
|     usage: json['usage'], |         size: json['size'], | ||||||
|     mimetype: json['mimetype'], |         name: json['name'], | ||||||
|     hash: json['hash'], |         alt: json['alt'], | ||||||
|     destination: json['destination'], |         mimetype: json['mimetype'], | ||||||
|     isAnalyzed: json['is_analyzed'], |         hash: json['hash'], | ||||||
|     metadata: json['metadata'], |         destination: json['destination'], | ||||||
|     isMature: json['is_mature'], |         isAnalyzed: json['is_analyzed'], | ||||||
|     account: json['account'] != null ? Account.fromJson(json['account']) : null, |         metadata: json['metadata'], | ||||||
|     accountId: json['account_id'], |         isMature: json['is_mature'], | ||||||
|   ); |         account: | ||||||
|  |             json['account'] != null ? Account.fromJson(json['account']) : null, | ||||||
|  |         accountId: json['account_id'], | ||||||
|  |       ); | ||||||
|  |  | ||||||
|   Map<String, dynamic> toJson() => { |   Map<String, dynamic> toJson() => { | ||||||
|     'id': id, |         'id': id, | ||||||
|     'created_at': createdAt.toIso8601String(), |         'created_at': createdAt.toIso8601String(), | ||||||
|     'updated_at': updatedAt.toIso8601String(), |         'updated_at': updatedAt.toIso8601String(), | ||||||
|     'deleted_at': deletedAt?.toIso8601String(), |         'deleted_at': deletedAt?.toIso8601String(), | ||||||
|     'uuid': uuid, |         'rid': rid, | ||||||
|     'size': size, |         'uuid': uuid, | ||||||
|     'name': name, |         'size': size, | ||||||
|     'alt': alt, |         'name': name, | ||||||
|     'usage': usage, |         'alt': alt, | ||||||
|     'mimetype': mimetype, |         'mimetype': mimetype, | ||||||
|     'hash': hash, |         'hash': hash, | ||||||
|     'destination': destination, |         'destination': destination, | ||||||
|     'is_analyzed': isAnalyzed, |         'is_analyzed': isAnalyzed, | ||||||
|     'metadata': metadata, |         'metadata': metadata, | ||||||
|     'is_mature': isMature, |         'is_mature': isMature, | ||||||
|     'account': account?.toJson(), |         'account': account?.toJson(), | ||||||
|     'account_id': accountId, |         'account_id': accountId, | ||||||
|   }; |       }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -148,7 +148,7 @@ class AttachmentUploaderController extends GetxController { | |||||||
|   Future<void> uploadAttachmentWithCallback( |   Future<void> uploadAttachmentWithCallback( | ||||||
|     Uint8List data, |     Uint8List data, | ||||||
|     String path, |     String path, | ||||||
|     String usage, |     String pool, | ||||||
|     Map<String, dynamic>? metadata, |     Map<String, dynamic>? metadata, | ||||||
|     Function(Attachment?) callback, |     Function(Attachment?) callback, | ||||||
|   ) async { |   ) async { | ||||||
| @@ -158,7 +158,7 @@ class AttachmentUploaderController extends GetxController { | |||||||
|     final result = await _rawUploadAttachment( |     final result = await _rawUploadAttachment( | ||||||
|       data, |       data, | ||||||
|       path, |       path, | ||||||
|       usage, |       pool, | ||||||
|       metadata, |       metadata, | ||||||
|       onProgress: (progress) { |       onProgress: (progress) { | ||||||
|         progressOfUpload.value = progress; |         progressOfUpload.value = progress; | ||||||
| @@ -171,7 +171,7 @@ class AttachmentUploaderController extends GetxController { | |||||||
|   Future<Attachment?> uploadAttachment( |   Future<Attachment?> uploadAttachment( | ||||||
|     Uint8List data, |     Uint8List data, | ||||||
|     String path, |     String path, | ||||||
|     String usage, |     String pool, | ||||||
|     Map<String, dynamic>? metadata, |     Map<String, dynamic>? metadata, | ||||||
|   ) async { |   ) async { | ||||||
|     if (isUploading.value) throw Exception('uploading blocked'); |     if (isUploading.value) throw Exception('uploading blocked'); | ||||||
| @@ -180,7 +180,7 @@ class AttachmentUploaderController extends GetxController { | |||||||
|     final result = await _rawUploadAttachment( |     final result = await _rawUploadAttachment( | ||||||
|       data, |       data, | ||||||
|       path, |       path, | ||||||
|       usage, |       pool, | ||||||
|       metadata, |       metadata, | ||||||
|       onProgress: (progress) { |       onProgress: (progress) { | ||||||
|         progressOfUpload.value = progress; |         progressOfUpload.value = progress; | ||||||
| @@ -191,14 +191,14 @@ class AttachmentUploaderController extends GetxController { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<Attachment?> _rawUploadAttachment( |   Future<Attachment?> _rawUploadAttachment( | ||||||
|       Uint8List data, String path, String usage, Map<String, dynamic>? metadata, |       Uint8List data, String path, String pool, Map<String, dynamic>? metadata, | ||||||
|       {Function(double)? onProgress, Function(dynamic err)? onError}) async { |       {Function(double)? onProgress, Function(dynamic err)? onError}) async { | ||||||
|     final AttachmentProvider provider = Get.find(); |     final AttachmentProvider provider = Get.find(); | ||||||
|     try { |     try { | ||||||
|       final result = await provider.createAttachment( |       final result = await provider.createAttachment( | ||||||
|         data, |         data, | ||||||
|         path, |         path, | ||||||
|         usage, |         pool, | ||||||
|         metadata, |         metadata, | ||||||
|         onProgress: onProgress, |         onProgress: onProgress, | ||||||
|       ); |       ); | ||||||
|   | |||||||
| @@ -88,7 +88,30 @@ class ChatCallProvider extends GetxController { | |||||||
|  |  | ||||||
|   void initRoom() { |   void initRoom() { | ||||||
|     initHardware(); |     initHardware(); | ||||||
|     room = Room(); |     room = Room( | ||||||
|  |       roomOptions: const RoomOptions( | ||||||
|  |         dynacast: true, | ||||||
|  |         adaptiveStream: true, | ||||||
|  |         defaultAudioPublishOptions: AudioPublishOptions( | ||||||
|  |           name: 'call_voice', | ||||||
|  |           stream: 'call_stream', | ||||||
|  |         ), | ||||||
|  |         defaultVideoPublishOptions: VideoPublishOptions( | ||||||
|  |           name: 'call_video', | ||||||
|  |           stream: 'call_stream', | ||||||
|  |           simulcast: true, | ||||||
|  |           backupVideoCodec: BackupVideoCodec(enabled: true), | ||||||
|  |         ), | ||||||
|  |         defaultScreenShareCaptureOptions: ScreenShareCaptureOptions( | ||||||
|  |           useiOSBroadcastExtension: true, | ||||||
|  |           params: VideoParametersPresets.screenShareH1080FPS30, | ||||||
|  |         ), | ||||||
|  |         defaultCameraCaptureOptions: CameraCaptureOptions( | ||||||
|  |           maxFrameRate: 30, | ||||||
|  |           params: VideoParametersPresets.h1080_169, | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|     listener = room.createListener(); |     listener = room.createListener(); | ||||||
|     WakelockPlus.enable(); |     WakelockPlus.enable(); | ||||||
|   } |   } | ||||||
| @@ -104,28 +127,6 @@ class ChatCallProvider extends GetxController { | |||||||
|       await room.connect( |       await room.connect( | ||||||
|         url, |         url, | ||||||
|         token, |         token, | ||||||
|         roomOptions: const RoomOptions( |  | ||||||
|           dynacast: true, |  | ||||||
|           adaptiveStream: true, |  | ||||||
|           defaultAudioPublishOptions: AudioPublishOptions( |  | ||||||
|             name: 'call_voice', |  | ||||||
|             stream: 'call_stream', |  | ||||||
|           ), |  | ||||||
|           defaultVideoPublishOptions: VideoPublishOptions( |  | ||||||
|             name: 'call_video', |  | ||||||
|             stream: 'call_stream', |  | ||||||
|             simulcast: true, |  | ||||||
|             backupVideoCodec: BackupVideoCodec(enabled: true), |  | ||||||
|           ), |  | ||||||
|           defaultScreenShareCaptureOptions: ScreenShareCaptureOptions( |  | ||||||
|             useiOSBroadcastExtension: true, |  | ||||||
|             params: VideoParametersPresets.screenShareH1080FPS30, |  | ||||||
|           ), |  | ||||||
|           defaultCameraCaptureOptions: CameraCaptureOptions( |  | ||||||
|             maxFrameRate: 30, |  | ||||||
|             params: VideoParametersPresets.h1080_169, |  | ||||||
|           ), |  | ||||||
|         ), |  | ||||||
|         fastConnectOptions: FastConnectOptions( |         fastConnectOptions: FastConnectOptions( | ||||||
|           microphone: TrackOption(track: audioTrack.value), |           microphone: TrackOption(track: audioTrack.value), | ||||||
|           camera: TrackOption(track: videoTrack.value), |           camera: TrackOption(track: videoTrack.value), | ||||||
| @@ -152,7 +153,7 @@ class ChatCallProvider extends GetxController { | |||||||
|   void onRoomDidUpdate() => sortParticipants(); |   void onRoomDidUpdate() => sortParticipants(); | ||||||
|  |  | ||||||
|   void setupRoom() { |   void setupRoom() { | ||||||
|     if(isInitialized.value) return; |     if (isInitialized.value) return; | ||||||
|  |  | ||||||
|     sortParticipants(); |     sortParticipants(); | ||||||
|     room.addListener(onRoomDidUpdate); |     room.addListener(onRoomDidUpdate); | ||||||
|   | |||||||
| @@ -20,22 +20,22 @@ class AttachmentProvider extends GetConnect { | |||||||
|     httpClient.baseUrl = ServiceFinder.buildUrl('files', null); |     httpClient.baseUrl = ServiceFinder.buildUrl('files', null); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   final Map<int, Attachment> _cachedResponses = {}; |   final Map<String, Attachment> _cachedResponses = {}; | ||||||
|  |  | ||||||
|   Future<List<Attachment?>> listMetadata( |   Future<List<Attachment?>> listMetadata( | ||||||
|     List<int> id, { |     List<String> rid, { | ||||||
|     noCache = false, |     noCache = false, | ||||||
|   }) async { |   }) async { | ||||||
|     if (id.isEmpty) return List.empty(); |     if (rid.isEmpty) return List.empty(); | ||||||
|  |  | ||||||
|     List<Attachment?> result = List.filled(id.length, null); |     List<Attachment?> result = List.filled(rid.length, null); | ||||||
|     List<int> pendingQuery = List.empty(growable: true); |     List<String> pendingQuery = List.empty(growable: true); | ||||||
|     if (!noCache) { |     if (!noCache) { | ||||||
|       for (var idx = 0; idx < id.length; idx++) { |       for (var idx = 0; idx < rid.length; idx++) { | ||||||
|         if (_cachedResponses.containsKey(id[idx])) { |         if (_cachedResponses.containsKey(rid[idx])) { | ||||||
|           result[idx] = _cachedResponses[id[idx]]; |           result[idx] = _cachedResponses[rid[idx]]; | ||||||
|         } else { |         } else { | ||||||
|           pendingQuery.add(id[idx]); |           pendingQuery.add(rid[idx]); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -52,12 +52,12 @@ class AttachmentProvider extends GetConnect { | |||||||
|         rawOut.data!.map((x) => Attachment.fromJson(x)).toList(); |         rawOut.data!.map((x) => Attachment.fromJson(x)).toList(); | ||||||
|     for (final item in out) { |     for (final item in out) { | ||||||
|       if (item.destination != 0 && item.isAnalyzed) { |       if (item.destination != 0 && item.isAnalyzed) { | ||||||
|         _cachedResponses[item.id] = item; |         _cachedResponses[item.rid] = item; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     for (var i = 0; i < out.length; i++) { |     for (var i = 0; i < out.length; i++) { | ||||||
|       for (var j = 0; j < id.length; j++) { |       for (var j = 0; j < rid.length; j++) { | ||||||
|         if (out[i].id == id[j]) { |         if (out[i].rid == rid[j]) { | ||||||
|           result[j] = out[i]; |           result[j] = out[i]; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -66,16 +66,16 @@ class AttachmentProvider extends GetConnect { | |||||||
|     return result; |     return result; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<Attachment?> getMetadata(int id, {noCache = false}) async { |   Future<Attachment?> getMetadata(String rid, {noCache = false}) async { | ||||||
|     if (!noCache && _cachedResponses.containsKey(id)) { |     if (!noCache && _cachedResponses.containsKey(rid)) { | ||||||
|       return _cachedResponses[id]!; |       return _cachedResponses[rid]!; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final resp = await get('/attachments/$id/meta'); |     final resp = await get('/attachments/$rid/meta'); | ||||||
|     if (resp.statusCode == 200) { |     if (resp.statusCode == 200) { | ||||||
|       final result = Attachment.fromJson(resp.body); |       final result = Attachment.fromJson(resp.body); | ||||||
|       if (result.destination != 0 && result.isAnalyzed) { |       if (result.destination != 0 && result.isAnalyzed) { | ||||||
|         _cachedResponses[id] = result; |         _cachedResponses[rid] = result; | ||||||
|       } |       } | ||||||
|       return result; |       return result; | ||||||
|     } |     } | ||||||
| @@ -84,7 +84,7 @@ class AttachmentProvider extends GetConnect { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<Attachment> createAttachment( |   Future<Attachment> createAttachment( | ||||||
|       Uint8List data, String path, String usage, Map<String, dynamic>? metadata, |       Uint8List data, String path, String pool, Map<String, dynamic>? metadata, | ||||||
|       {Function(double)? onProgress}) async { |       {Function(double)? onProgress}) async { | ||||||
|     final AuthProvider auth = Get.find(); |     final AuthProvider auth = Get.find(); | ||||||
|     if (auth.isAuthorized.isFalse) throw Exception('unauthorized'); |     if (auth.isAuthorized.isFalse) throw Exception('unauthorized'); | ||||||
| @@ -108,7 +108,7 @@ class AttachmentProvider extends GetConnect { | |||||||
|     final payload = dio.FormData.fromMap({ |     final payload = dio.FormData.fromMap({ | ||||||
|       'alt': fileAlt, |       'alt': fileAlt, | ||||||
|       'file': filePayload, |       'file': filePayload, | ||||||
|       'usage': usage, |       'pool': pool, | ||||||
|       if (mimetypeOverride != null) 'mimetype': mimetypeOverride, |       if (mimetypeOverride != null) 'mimetype': mimetypeOverride, | ||||||
|       'metadata': jsonEncode(metadata), |       'metadata': jsonEncode(metadata), | ||||||
|     }); |     }); | ||||||
| @@ -133,8 +133,7 @@ class AttachmentProvider extends GetConnect { | |||||||
|  |  | ||||||
|   Future<Response> updateAttachment( |   Future<Response> updateAttachment( | ||||||
|     int id, |     int id, | ||||||
|     String alt, |     String alt, { | ||||||
|     String usage, { |  | ||||||
|     bool isMature = false, |     bool isMature = false, | ||||||
|   }) async { |   }) async { | ||||||
|     final AuthProvider auth = Get.find(); |     final AuthProvider auth = Get.find(); | ||||||
| @@ -144,7 +143,6 @@ class AttachmentProvider extends GetConnect { | |||||||
|  |  | ||||||
|     var resp = await client.put('/attachments/$id', { |     var resp = await client.put('/attachments/$id', { | ||||||
|       'alt': alt, |       'alt': alt, | ||||||
|       'usage': usage, |  | ||||||
|       'is_mature': isMature, |       'is_mature': isMature, | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -116,7 +116,7 @@ class _PersonalizeScreenState extends State<PersonalizeScreen> { | |||||||
|       attachResult = await provider.createAttachment( |       attachResult = await provider.createAttachment( | ||||||
|         await file.readAsBytes(), |         await file.readAsBytes(), | ||||||
|         file.path, |         file.path, | ||||||
|         'p.$position', |         'avatar', | ||||||
|         null, |         null, | ||||||
|       ); |       ); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|   | |||||||
| @@ -65,7 +65,7 @@ class _PostPublishScreenState extends State<PostPublishScreen> { | |||||||
|  |  | ||||||
|     final AttachmentUploaderController uploader = Get.find(); |     final AttachmentUploaderController uploader = Get.find(); | ||||||
|     if (uploader.queueOfUpload.any( |     if (uploader.queueOfUpload.any( | ||||||
|       ((x) => x.usage == 'i.attachment' && x.isUploading), |       ((x) => x.isUploading), | ||||||
|     )) { |     )) { | ||||||
|       context.showErrorDialog('attachmentUploadInProgress'.tr); |       context.showErrorDialog('attachmentUploadInProgress'.tr); | ||||||
|       return; |       return; | ||||||
| @@ -90,8 +90,8 @@ class _PostPublishScreenState extends State<PostPublishScreen> { | |||||||
|     if (resp.statusCode != 200) { |     if (resp.statusCode != 200) { | ||||||
|       context.showErrorDialog(resp.bodyString); |       context.showErrorDialog(resp.bodyString); | ||||||
|     } else { |     } else { | ||||||
|       _editorController.localClear(); |  | ||||||
|       _editorController.currentClear(); |       _editorController.currentClear(); | ||||||
|  |       _editorController.localClear(); | ||||||
|       AppRouter.instance.pop(resp.body); |       AppRouter.instance.pop(resp.body); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,7 +24,6 @@ class AccountAvatar extends StatelessWidget { | |||||||
|     if (content is String) { |     if (content is String) { | ||||||
|       direct = content.startsWith('http'); |       direct = content.startsWith('http'); | ||||||
|       if (!isEmpty) isEmpty = content.isEmpty; |       if (!isEmpty) isEmpty = content.isEmpty; | ||||||
|       if (!isEmpty) isEmpty = content.endsWith('/attachments/0'); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final url = direct |     final url = direct | ||||||
|   | |||||||
| @@ -16,10 +16,12 @@ class AttachmentAttrEditorDialog extends StatefulWidget { | |||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   State<AttachmentAttrEditorDialog> createState() => _AttachmentAttrEditorDialogState(); |   State<AttachmentAttrEditorDialog> createState() => | ||||||
|  |       _AttachmentAttrEditorDialogState(); | ||||||
| } | } | ||||||
|  |  | ||||||
| class _AttachmentAttrEditorDialogState extends State<AttachmentAttrEditorDialog> { | class _AttachmentAttrEditorDialogState | ||||||
|  |     extends State<AttachmentAttrEditorDialog> { | ||||||
|   final _altController = TextEditingController(); |   final _altController = TextEditingController(); | ||||||
|  |  | ||||||
|   bool _isBusy = false; |   bool _isBusy = false; | ||||||
| @@ -33,7 +35,6 @@ class _AttachmentAttrEditorDialogState extends State<AttachmentAttrEditorDialog> | |||||||
|       final resp = await provider.updateAttachment( |       final resp = await provider.updateAttachment( | ||||||
|         widget.item.id, |         widget.item.id, | ||||||
|         _altController.value.text, |         _altController.value.text, | ||||||
|         widget.item.usage, |  | ||||||
|         isMature: _isMature, |         isMature: _isMature, | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
| @@ -109,7 +110,7 @@ class _AttachmentAttrEditorDialogState extends State<AttachmentAttrEditorDialog> | |||||||
|             TextButton( |             TextButton( | ||||||
|               style: TextButton.styleFrom( |               style: TextButton.styleFrom( | ||||||
|                   foregroundColor: |                   foregroundColor: | ||||||
|                   Theme.of(context).colorScheme.onSurfaceVariant), |                       Theme.of(context).colorScheme.onSurfaceVariant), | ||||||
|               onPressed: () => Navigator.pop(context), |               onPressed: () => Navigator.pop(context), | ||||||
|               child: Text('cancel'.tr), |               child: Text('cancel'.tr), | ||||||
|             ), |             ), | ||||||
|   | |||||||
| @@ -22,19 +22,19 @@ import 'package:solian/widgets/attachments/attachment_attr_editor.dart'; | |||||||
| import 'package:solian/widgets/attachments/attachment_fullscreen.dart'; | import 'package:solian/widgets/attachments/attachment_fullscreen.dart'; | ||||||
|  |  | ||||||
| class AttachmentEditorPopup extends StatefulWidget { | class AttachmentEditorPopup extends StatefulWidget { | ||||||
|   final String usage; |   final String pool; | ||||||
|   final bool singleMode; |   final bool singleMode; | ||||||
|   final bool imageOnly; |   final bool imageOnly; | ||||||
|   final bool autoUpload; |   final bool autoUpload; | ||||||
|   final double? imageMaxWidth; |   final double? imageMaxWidth; | ||||||
|   final double? imageMaxHeight; |   final double? imageMaxHeight; | ||||||
|   final List<int>? initialAttachments; |   final List<String>? initialAttachments; | ||||||
|   final void Function(int) onAdd; |   final void Function(String) onAdd; | ||||||
|   final void Function(int) onRemove; |   final void Function(String) onRemove; | ||||||
|  |  | ||||||
|   const AttachmentEditorPopup({ |   const AttachmentEditorPopup({ | ||||||
|     super.key, |     super.key, | ||||||
|     required this.usage, |     required this.pool, | ||||||
|     required this.onAdd, |     required this.onAdd, | ||||||
|     required this.onRemove, |     required this.onRemove, | ||||||
|     this.singleMode = false, |     this.singleMode = false, | ||||||
| @@ -73,7 +73,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|  |  | ||||||
|       _enqueueTaskBatch(medias.map((x) { |       _enqueueTaskBatch(medias.map((x) { | ||||||
|         final file = File(x.path); |         final file = File(x.path); | ||||||
|         return AttachmentUploadTask(file: file, usage: widget.usage); |         return AttachmentUploadTask(file: file, usage: widget.pool); | ||||||
|       })); |       })); | ||||||
|     } else { |     } else { | ||||||
|       final media = await _imagePicker.pickMedia( |       final media = await _imagePicker.pickMedia( | ||||||
| @@ -83,7 +83,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|       if (media == null) return; |       if (media == null) return; | ||||||
|  |  | ||||||
|       _enqueueTask( |       _enqueueTask( | ||||||
|         AttachmentUploadTask(file: File(media.path), usage: widget.usage), |         AttachmentUploadTask(file: File(media.path), usage: widget.pool), | ||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -97,7 +97,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|  |  | ||||||
|     final file = File(media.path); |     final file = File(media.path); | ||||||
|     _enqueueTask( |     _enqueueTask( | ||||||
|       AttachmentUploadTask(file: file, usage: widget.usage), |       AttachmentUploadTask(file: file, usage: widget.pool), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -113,7 +113,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|     List<File> files = result.paths.map((path) => File(path!)).toList(); |     List<File> files = result.paths.map((path) => File(path!)).toList(); | ||||||
|  |  | ||||||
|     _enqueueTaskBatch(files.map((x) { |     _enqueueTaskBatch(files.map((x) { | ||||||
|       return AttachmentUploadTask(file: x, usage: widget.usage); |       return AttachmentUploadTask(file: x, usage: widget.pool); | ||||||
|     })); |     })); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -131,7 +131,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|  |  | ||||||
|     final file = File(media.path); |     final file = File(media.path); | ||||||
|     _enqueueTask( |     _enqueueTask( | ||||||
|       AttachmentUploadTask(file: file, usage: widget.usage), |       AttachmentUploadTask(file: file, usage: widget.pool), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -181,13 +181,11 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|     WidgetsBinding.instance.addPostFrameCallback((_) => controller.dispose()); |     WidgetsBinding.instance.addPostFrameCallback((_) => controller.dispose()); | ||||||
|  |  | ||||||
|     if (input == null || input.isEmpty) return; |     if (input == null || input.isEmpty) return; | ||||||
|     final value = int.tryParse(input); |  | ||||||
|     if (value == null) return; |  | ||||||
|  |  | ||||||
|     final AttachmentProvider attach = Get.find(); |     final AttachmentProvider attach = Get.find(); | ||||||
|     final result = await attach.getMetadata(value); |     final result = await attach.getMetadata(input); | ||||||
|     if (result != null) { |     if (result != null) { | ||||||
|       widget.onAdd(result.id); |       widget.onAdd(result.rid); | ||||||
|       setState(() => _attachments.add(result)); |       setState(() => _attachments.add(result)); | ||||||
|       if (widget.singleMode) Navigator.pop(context); |       if (widget.singleMode) Navigator.pop(context); | ||||||
|     } |     } | ||||||
| @@ -202,11 +200,11 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|     _uploadController.uploadAttachmentWithCallback( |     _uploadController.uploadAttachmentWithCallback( | ||||||
|       data, |       data, | ||||||
|       'Pasted Image', |       'Pasted Image', | ||||||
|       widget.usage, |       widget.pool, | ||||||
|       null, |       null, | ||||||
|       (item) { |       (item) { | ||||||
|         if (item == null) return; |         if (item == null) return; | ||||||
|         widget.onAdd(item.id); |         widget.onAdd(item.rid); | ||||||
|         if (mounted) { |         if (mounted) { | ||||||
|           setState(() => _attachments.add(item)); |           setState(() => _attachments.add(item)); | ||||||
|           if (widget.singleMode) Navigator.pop(context); |           if (widget.singleMode) Navigator.pop(context); | ||||||
| @@ -413,11 +411,11 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|                             : () { |                             : () { | ||||||
|                                 _uploadController |                                 _uploadController | ||||||
|                                     .performSingleTask(index) |                                     .performSingleTask(index) | ||||||
|                                     .then((r) { |                                     .then((out) { | ||||||
|                                   if (r == null) return; |                                   if (out == null) return; | ||||||
|                                   widget.onAdd(r.id); |                                   widget.onAdd(out.rid); | ||||||
|                                   if (mounted) { |                                   if (mounted) { | ||||||
|                                     setState(() => _attachments.add(r)); |                                     setState(() => _attachments.add(out)); | ||||||
|                                     if (widget.singleMode) { |                                     if (widget.singleMode) { | ||||||
|                                       Navigator.pop(context); |                                       Navigator.pop(context); | ||||||
|                                     } |                                     } | ||||||
| @@ -515,7 +513,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|                         ), |                         ), | ||||||
|                         onTap: () { |                         onTap: () { | ||||||
|                           _deleteAttachment(element).then((_) { |                           _deleteAttachment(element).then((_) { | ||||||
|                             widget.onRemove(element.id); |                             widget.onRemove(element.rid); | ||||||
|                             setState(() => _attachments.removeAt(index)); |                             setState(() => _attachments.removeAt(index)); | ||||||
|                           }); |                           }); | ||||||
|                         }, |                         }, | ||||||
| @@ -529,7 +527,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|                           ), |                           ), | ||||||
|                         ), |                         ), | ||||||
|                         onTap: () { |                         onTap: () { | ||||||
|                           widget.onRemove(element.id); |                           widget.onRemove(element.rid); | ||||||
|                           setState(() => _attachments.removeAt(index)); |                           setState(() => _attachments.removeAt(index)); | ||||||
|                         }, |                         }, | ||||||
|                       ), |                       ), | ||||||
| @@ -560,7 +558,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|  |  | ||||||
|   void _startUploading() { |   void _startUploading() { | ||||||
|     _uploadController.performUploadQueue(onData: (r) { |     _uploadController.performUploadQueue(onData: (r) { | ||||||
|       widget.onAdd(r.id); |       widget.onAdd(r.rid); | ||||||
|       if (mounted) { |       if (mounted) { | ||||||
|         setState(() => _attachments.add(r)); |         setState(() => _attachments.add(r)); | ||||||
|         if (widget.singleMode) Navigator.pop(context); |         if (widget.singleMode) Navigator.pop(context); | ||||||
| @@ -584,7 +582,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> { | |||||||
|           if (_uploadController.isUploading.value) return; |           if (_uploadController.isUploading.value) return; | ||||||
|           _enqueueTaskBatch(detail.files.map((x) { |           _enqueueTaskBatch(detail.files.map((x) { | ||||||
|             final file = File(x.path); |             final file = File(x.path); | ||||||
|             return AttachmentUploadTask(file: file, usage: widget.usage); |             return AttachmentUploadTask(file: file, usage: widget.pool); | ||||||
|           })); |           })); | ||||||
|         }, |         }, | ||||||
|         child: Column( |         child: Column( | ||||||
|   | |||||||
| @@ -67,9 +67,10 @@ class _AttachmentFullScreenState extends State<AttachmentFullScreen> { | |||||||
|   Future<void> _saveToAlbum() async { |   Future<void> _saveToAlbum() async { | ||||||
|     final url = ServiceFinder.buildUrl( |     final url = ServiceFinder.buildUrl( | ||||||
|       'files', |       'files', | ||||||
|       '/attachments/${widget.item.id}', |       '/attachments/${widget.item.rid}', | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|  |     print(url); | ||||||
|     if (PlatformInfo.isWeb || PlatformInfo.isDesktop) { |     if (PlatformInfo.isWeb || PlatformInfo.isDesktop) { | ||||||
|       await launchUrlString(url); |       await launchUrlString(url); | ||||||
|       return; |       return; | ||||||
| @@ -258,7 +259,7 @@ class _AttachmentFullScreenState extends State<AttachmentFullScreen> { | |||||||
|                         spacing: 6, |                         spacing: 6, | ||||||
|                         children: [ |                         children: [ | ||||||
|                           Text( |                           Text( | ||||||
|                             '#${widget.item.id}', |                             '#${widget.item.rid}', | ||||||
|                             style: metaTextStyle, |                             style: metaTextStyle, | ||||||
|                           ), |                           ), | ||||||
|                           if (widget.item.metadata?['width'] != null && |                           if (widget.item.metadata?['width'] != null && | ||||||
|   | |||||||
| @@ -91,7 +91,7 @@ class _AttachmentItemState extends State<AttachmentItem> { | |||||||
|                     launchUrlString( |                     launchUrlString( | ||||||
|                       ServiceFinder.buildUrl( |                       ServiceFinder.buildUrl( | ||||||
|                         'files', |                         'files', | ||||||
|                         '/attachments/${widget.item.id}', |                         '/attachments/${widget.item.rid}', | ||||||
|                       ), |                       ), | ||||||
|                     ); |                     ); | ||||||
|                   }, |                   }, | ||||||
| @@ -135,7 +135,7 @@ class _AttachmentItemImage extends StatelessWidget { | |||||||
|               fit: fit, |               fit: fit, | ||||||
|               imageUrl: ServiceFinder.buildUrl( |               imageUrl: ServiceFinder.buildUrl( | ||||||
|                 'files', |                 'files', | ||||||
|                 '/attachments/${item.id}', |                 '/attachments/${item.rid}', | ||||||
|               ), |               ), | ||||||
|               progressIndicatorBuilder: (context, url, downloadProgress) { |               progressIndicatorBuilder: (context, url, downloadProgress) { | ||||||
|                 return Center( |                 return Center( | ||||||
| @@ -240,7 +240,7 @@ class _AttachmentItemVideoState extends State<_AttachmentItemVideo> { | |||||||
|     final ratio = widget.item.metadata?['ratio'] ?? 16 / 9; |     final ratio = widget.item.metadata?['ratio'] ?? 16 / 9; | ||||||
|     _playerController = VideoPlayerController.networkUrl( |     _playerController = VideoPlayerController.networkUrl( | ||||||
|       Uri.parse( |       Uri.parse( | ||||||
|         ServiceFinder.buildUrl('files', '/attachments/${widget.item.id}'), |         ServiceFinder.buildUrl('files', '/attachments/${widget.item.rid}'), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|     _playerController!.initialize(); |     _playerController!.initialize(); | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ import 'package:solian/widgets/sized_container.dart'; | |||||||
|  |  | ||||||
| class AttachmentList extends StatefulWidget { | class AttachmentList extends StatefulWidget { | ||||||
|   final String parentId; |   final String parentId; | ||||||
|   final List<int> attachmentsId; |   final List<String> attachmentsId; | ||||||
|   final bool isGrid; |   final bool isGrid; | ||||||
|   final bool isForceGrid; |   final bool isForceGrid; | ||||||
|   final bool autoload; |   final bool autoload; | ||||||
| @@ -334,13 +334,13 @@ class AttachmentListEntry extends StatelessWidget { | |||||||
| } | } | ||||||
|  |  | ||||||
| class AttachmentSelfContainedEntry extends StatefulWidget { | class AttachmentSelfContainedEntry extends StatefulWidget { | ||||||
|   final int id; |   final String rid; | ||||||
|   final String parentId; |   final String parentId; | ||||||
|   final bool isDense; |   final bool isDense; | ||||||
|  |  | ||||||
|   const AttachmentSelfContainedEntry({ |   const AttachmentSelfContainedEntry({ | ||||||
|     super.key, |     super.key, | ||||||
|     required this.id, |     required this.rid, | ||||||
|     required this.parentId, |     required this.parentId, | ||||||
|     this.isDense = false, |     this.isDense = false, | ||||||
|   }); |   }); | ||||||
| @@ -359,10 +359,12 @@ class _AttachmentSelfContainedEntryState | |||||||
|     final AttachmentProvider attachments = Get.find(); |     final AttachmentProvider attachments = Get.find(); | ||||||
|  |  | ||||||
|     return FutureBuilder( |     return FutureBuilder( | ||||||
|       future: attachments.getMetadata(widget.id), |       future: attachments.getMetadata(widget.rid), | ||||||
|       builder: (context, snapshot) { |       builder: (context, snapshot) { | ||||||
|         if (!snapshot.hasData) { |         if (!snapshot.hasData) { | ||||||
|           return const Text('Loading...'); |           return const Center( | ||||||
|  |             child: CircularProgressIndicator(), | ||||||
|  |           ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return AttachmentListEntry( |         return AttachmentListEntry( | ||||||
|   | |||||||
| @@ -39,8 +39,8 @@ class ChatEvent extends StatelessWidget { | |||||||
|  |  | ||||||
|   Widget _buildAttachment(BuildContext context, {bool isMinimal = false}) { |   Widget _buildAttachment(BuildContext context, {bool isMinimal = false}) { | ||||||
|     final attachments = item.body['attachments'] != null |     final attachments = item.body['attachments'] != null | ||||||
|         ? List<int>.from(item.body['attachments'].map((x) => x)) |         ? List<String>.from(item.body['attachments'].map((x) => x)) | ||||||
|         : List<int>.empty(); |         : List<String>.empty(); | ||||||
|  |  | ||||||
|     if (attachments.isEmpty) return const SizedBox(); |     if (attachments.isEmpty) return const SizedBox(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -59,7 +59,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> { | |||||||
|   final TextEditingController _textController = TextEditingController(); |   final TextEditingController _textController = TextEditingController(); | ||||||
|   final FocusNode _focusNode = FocusNode(); |   final FocusNode _focusNode = FocusNode(); | ||||||
|  |  | ||||||
|   final List<int> _attachments = List.empty(growable: true); |   final List<String> _attachments = List.empty(growable: true); | ||||||
|  |  | ||||||
|   Event? _editTo; |   Event? _editTo; | ||||||
|   Event? _replyTo; |   Event? _replyTo; | ||||||
| @@ -68,7 +68,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> { | |||||||
|     showModalBottomSheet( |     showModalBottomSheet( | ||||||
|       context: context, |       context: context, | ||||||
|       builder: (context) => AttachmentEditorPopup( |       builder: (context) => AttachmentEditorPopup( | ||||||
|         usage: 'm.attachment', |         pool: 'messaging', | ||||||
|         initialAttachments: _attachments, |         initialAttachments: _attachments, | ||||||
|         onAdd: (value) { |         onAdd: (value) { | ||||||
|           setState(() { |           setState(() { | ||||||
| @@ -103,7 +103,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> { | |||||||
|  |  | ||||||
|     final AttachmentUploaderController uploader = Get.find(); |     final AttachmentUploaderController uploader = Get.find(); | ||||||
|     if (uploader.queueOfUpload.any( |     if (uploader.queueOfUpload.any( | ||||||
|       ((x) => x.usage == 'm.attachment' && x.isUploading), |       ((x) => x.isUploading), | ||||||
|     )) { |     )) { | ||||||
|       context.showErrorDialog('attachmentUploadInProgress'.tr); |       context.showErrorDialog('attachmentUploadInProgress'.tr); | ||||||
|       return; |       return; | ||||||
|   | |||||||
| @@ -131,7 +131,7 @@ class MarkdownTextContent extends StatelessWidget { | |||||||
|                   child: AttachmentSelfContainedEntry( |                   child: AttachmentSelfContainedEntry( | ||||||
|                     isDense: true, |                     isDense: true, | ||||||
|                     parentId: parentId, |                     parentId: parentId, | ||||||
|                     id: int.parse(segments[1]), |                     rid: segments[1], | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 ), | ||||||
|               ).paddingSymmetric(vertical: 4); |               ).paddingSymmetric(vertical: 4); | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ class _PostEditorThumbnailDialogState extends State<PostEditorThumbnailDialog> { | |||||||
|     showModalBottomSheet( |     showModalBottomSheet( | ||||||
|       context: context, |       context: context, | ||||||
|       builder: (context) => AttachmentEditorPopup( |       builder: (context) => AttachmentEditorPopup( | ||||||
|         usage: 'i.attachment', |         pool: 'interactive', | ||||||
|         singleMode: true, |         singleMode: true, | ||||||
|         imageOnly: true, |         imageOnly: true, | ||||||
|         autoUpload: true, |         autoUpload: true, | ||||||
| @@ -84,8 +84,7 @@ class _PostEditorThumbnailDialogState extends State<PostEditorThumbnailDialog> { | |||||||
|       actions: [ |       actions: [ | ||||||
|         TextButton( |         TextButton( | ||||||
|           onPressed: () { |           onPressed: () { | ||||||
|             widget.controller.thumbnail.value = |             widget.controller.thumbnail.value = _attachmentController.text; | ||||||
|                 int.tryParse(_attachmentController.text); |  | ||||||
|             Navigator.pop(context); |             Navigator.pop(context); | ||||||
|           }, |           }, | ||||||
|           child: Text('confirm'.tr), |           child: Text('confirm'.tr), | ||||||
|   | |||||||
| @@ -87,7 +87,7 @@ class _PostItemState extends State<PostItem> { | |||||||
|       child: AspectRatio( |       child: AspectRatio( | ||||||
|         aspectRatio: 16 / 9, |         aspectRatio: 16 / 9, | ||||||
|         child: AttachmentSelfContainedEntry( |         child: AttachmentSelfContainedEntry( | ||||||
|           id: widget.item.body['thumbnail'], |           rid: widget.item.body['thumbnail'], | ||||||
|           parentId: 'p${item.id}-thumbnail', |           parentId: 'p${item.id}-thumbnail', | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
| @@ -292,8 +292,8 @@ class _PostItemState extends State<PostItem> { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     final List<int> attachments = item.body['attachments'] is List |     final List<String> attachments = item.body['attachments'] is List | ||||||
|         ? item.body['attachments']?.cast<int>() |         ? item.body['attachments']?.cast<String>() | ||||||
|         : List.empty(); |         : List.empty(); | ||||||
|     final hasAttachment = attachments.isNotEmpty; |     final hasAttachment = attachments.isNotEmpty; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ class _StickerUploadDialogState extends State<StickerUploadDialog> { | |||||||
|     showModalBottomSheet( |     showModalBottomSheet( | ||||||
|       context: context, |       context: context, | ||||||
|       builder: (context) => AttachmentEditorPopup( |       builder: (context) => AttachmentEditorPopup( | ||||||
|         usage: 'sticker', |         pool: 'sticker', | ||||||
|         singleMode: true, |         singleMode: true, | ||||||
|         imageOnly: true, |         imageOnly: true, | ||||||
|         autoUpload: true, |         autoUpload: true, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user