diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 683dfeee2..0736f713e 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -726,6 +726,7 @@ "pleaseAddVoteChoice": "投票の選択肢を2つ以上入れてや", "pleaseSpecifyExpirationDate": "投票がいつまでか入れてや", "pleaseSpecifyExpirationDuration": "投票期間を入れてや", + "tooManyFiles": "ファイルは16個以下にしてください", "cannotMentionToRemoteInLocalOnlyNote": "連合オフやのによそのサーバーの人がメンションに含まれてるで", "cannotPublicReplyToPrivateNote": "リプライが{visibility}やから、パブリックにでけへん", "@cannotPublicReplyToPrivateNote": { diff --git a/lib/state_notifier/note_create_page/note_create_state_notifier.dart b/lib/state_notifier/note_create_page/note_create_state_notifier.dart index 44260a84d..c5096c8a3 100644 --- a/lib/state_notifier/note_create_page/note_create_state_notifier.dart +++ b/lib/state_notifier/note_create_page/note_create_state_notifier.dart @@ -1,5 +1,6 @@ import 'dart:typed_data'; +import 'package:collection/collection.dart'; import 'package:dio/dio.dart'; import 'package:file/file.dart'; import 'package:file_picker/file_picker.dart'; @@ -67,6 +68,8 @@ class EmptyVoteExpireDateException implements NoteCreateException {} class EmptyVoteExpireDurationException implements NoteCreateException {} +class TooManyFilesException implements NoteCreateException {} + class MentionToRemoteInLocalOnlyNoteException implements NoteCreateException {} @freezed @@ -281,70 +284,13 @@ class NoteCreateNotifier extends StateNotifier { throw EmptyVoteExpireDurationException(); } + if (state.files.length > 16) { + throw TooManyFilesException(); + } + try { state = state.copyWith(isNoteSending: NoteSendStatus.sending); - final fileIds = []; - - for (final file in state.files) { - switch (file) { - case PostFile(): - Uint8List contents = await file.file.readAsBytes(); - if (["image/jpeg", "image/tiff"].contains(file.type)) { - try { - contents = - await FlutterImageCompress.compressWithList(contents); - } catch (e) { - debugPrint("failed to compress file"); - } - } - final response = await misskey.drive.files.createAsBinary( - DriveFilesCreateRequest( - force: true, - name: file.fileName, - isSensitive: file.isNsfw, - comment: file.caption, - ), - contents, - ); - if (response.isSensitive == true && - !file.isNsfw && - !state.account.i.alwaysMarkNsfw) { - if (context.mounted) { - final confirmResult = await SimpleConfirmDialog.show( - context: context, - message: S.of(context).unexpectedSensitive, - primary: S.of(context).staySensitive, - secondary: S.of(context).unsetSensitive, - ); - if (confirmResult == false) { - await misskey.drive.files.update( - DriveFilesUpdateRequest( - fileId: response.id, - isSensitive: false, - ), - ); - } - } - } - fileIds.add(response.id); - case AlreadyPostedFile(): - if (file.isEdited) { - await misskey.drive.files.update( - DriveFilesUpdateRequest( - fileId: file.file.id, - name: file.fileName, - isSensitive: file.isNsfw, - comment: file.caption, - ), - ); - } - fileIds.add(file.file.id); - } - } - - if (!mounted) return; - final nodes = const MfmParser().parse(state.text); final userList = []; @@ -367,6 +313,73 @@ class NoteCreateNotifier extends StateNotifier { throw MentionToRemoteInLocalOnlyNoteException(); } + final files = await Future.wait( + state.files.map( + (file) async { + switch (file) { + case PostFile(): + Uint8List contents = await file.file.readAsBytes(); + if (["image/jpeg", "image/tiff"].contains(file.type)) { + try { + contents = + await FlutterImageCompress.compressWithList(contents); + } catch (e) { + debugPrint("failed to compress file"); + } + } + final response = await misskey.drive.files.createAsBinary( + DriveFilesCreateRequest( + force: true, + name: file.fileName, + isSensitive: file.isNsfw, + comment: file.caption, + ), + contents, + ); + return response; + case AlreadyPostedFile(): + if (file.isEdited) { + return await misskey.drive.files.update( + DriveFilesUpdateRequest( + fileId: file.file.id, + name: file.fileName, + isSensitive: file.isNsfw, + comment: file.caption, + ), + ); + } else { + return file.file; + } + } + }, + ), + ); + final autoSensitiveFiles = files.whereIndexed( + (index, file) => file.isSensitive && !state.files[index].isNsfw, + ); + if (autoSensitiveFiles.isNotEmpty && !state.account.i.alwaysMarkNsfw) { + if (context.mounted) { + final confirmResult = await SimpleConfirmDialog.show( + context: context, + message: S.of(context).unexpectedSensitive, + primary: S.of(context).staySensitive, + secondary: S.of(context).unsetSensitive, + ); + if (confirmResult == false) { + await Future.wait( + autoSensitiveFiles.map( + (file) => misskey.drive.files.update( + DriveFilesUpdateRequest( + fileId: file.id, + isSensitive: false, + ), + ), + ), + ); + } + } + } + final mentionTargetUsers = [ for (final user in userList) await misskey.users.showByName(UsersShowByUserNameRequest( @@ -423,7 +436,7 @@ class NoteCreateNotifier extends StateNotifier { replyId: state.reply?.id, renoteId: state.renote?.id, channelId: state.channel?.id, - fileIds: fileIds.isEmpty ? null : fileIds, + fileIds: files.isEmpty ? null : files.map((file) => file.id).toList(), visibleUserIds: visibleUserIds.toSet().toList(), //distinct list reactionAcceptance: state.reactionAcceptance, poll: state.isVote ? poll : null, diff --git a/lib/view/common/error_dialog_listener.dart b/lib/view/common/error_dialog_listener.dart index 76204e8fe..bfaf0fcbe 100644 --- a/lib/view/common/error_dialog_listener.dart +++ b/lib/view/common/error_dialog_listener.dart @@ -52,6 +52,7 @@ class ErrorDialogListener extends ConsumerWidget { S.of(context).pleaseSpecifyExpirationDate, EmptyVoteExpireDurationException() => S.of(context).pleaseSpecifyExpirationDuration, + TooManyFilesException() => S.of(context).tooManyFiles, MentionToRemoteInLocalOnlyNoteException() => S.of(context).cannotMentionToRemoteInLocalOnlyNote, };