From 1f3f620d06e5dcc2b87d198745892b4f4d01d4b6 Mon Sep 17 00:00:00 2001 From: poppingmoon <63451158+poppingmoon@users.noreply.github.com> Date: Sat, 23 Dec 2023 18:16:23 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=8E=E3=83=BC=E3=83=88=E3=81=AE=E7=BF=BB?= =?UTF-8?q?=E8=A8=B3=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/l10n/app_ja.arb | 9 + lib/router/app_router.dart | 2 + lib/router/app_router.gr.dart | 61 ++++- .../common/download_file_notifier.g.dart | 2 +- .../note_create_state_notifier.g.dart | 2 +- .../translate_note_modal_sheet.dart | 111 +++++++++ .../translate_note_modal_sheet.g.dart | 235 ++++++++++++++++++ .../note_modal_sheet/note_modal_sheet.dart | 12 + .../note_modal_sheet/note_modal_sheet.g.dart | 2 +- lib/view/user_page/user_info_notifier.g.dart | 2 +- 10 files changed, 432 insertions(+), 6 deletions(-) create mode 100644 lib/view/common/misskey_notes/translate_note_modal_sheet.dart create mode 100644 lib/view/common/misskey_notes/translate_note_modal_sheet.g.dart diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 506952a72..6b6e2b8e0 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -209,6 +209,15 @@ "openNoteInBrowsers": "ブラウザでノートを開く", "changeFullScreen": "フルスクリーンに切り替え", "shareNotes": "ノートを共有", + "translateNote": "ノートを翻訳", + "translatedFrom": "{lang}から翻訳", + "@translatedFrom": { + "placeholders": { + "lang": { + "type": "String" + } + } + }, "deleteFavorite": "お気に入り解除", "notesAfterRenote": "リノート直後のノート", "deletedRecreate": "削除してなおす", diff --git a/lib/router/app_router.dart b/lib/router/app_router.dart index 194b63d0e..8a64ff60b 100644 --- a/lib/router/app_router.dart +++ b/lib/router/app_router.dart @@ -28,6 +28,7 @@ import "package:miria/view/common/color_picker_dialog.dart"; import "package:miria/view/common/misskey_notes/reaction_user_dialog.dart"; import "package:miria/view/common/misskey_notes/renote_modal_sheet.dart"; import "package:miria/view/common/misskey_notes/renote_user_dialog.dart"; +import "package:miria/view/common/misskey_notes/translate_note_modal_sheet.dart"; import "package:miria/view/explore_page/explore_page.dart"; import "package:miria/view/explore_page/explore_role_users_page.dart"; import "package:miria/view/favorited_note_page/favorited_note_page.dart"; @@ -170,6 +171,7 @@ class AppRouter extends _$AppRouter { AutoModalRouteSheet(page: AntennaModalRoute.page), AutoModalRouteSheet(page: ClipModalRoute.page), AutoModalRouteSheet(page: UsersListModalRoute.page), + AutoModalRouteSheet(page: TranslateNoteModalRoute.page), AutoModalRouteSheet(page: DriveModalRoute.page), ]; } diff --git a/lib/router/app_router.gr.dart b/lib/router/app_router.gr.dart index 2477e2e3a..625b8d028 100644 --- a/lib/router/app_router.gr.dart +++ b/lib/router/app_router.gr.dart @@ -107,12 +107,13 @@ abstract class _$AppRouter extends RootStackRouter { final args = routeData.argsAs(); return AutoRoutePage( routeData: routeData, - child: AntennaSettingsDialog( + child: WrappedRoute( + child: AntennaSettingsDialog( account: args.account, key: args.key, title: args.title, initialSettings: args.initialSettings, - ), + )), ); }, AppInfoRoute.name: (routeData) { @@ -644,6 +645,18 @@ abstract class _$AppRouter extends RootStackRouter { ), ); }, + TranslateNoteModalRoute.name: (routeData) { + final args = routeData.argsAs(); + return AutoRoutePage( + routeData: routeData, + child: WrappedRoute( + child: TranslateNoteModalSheet( + accountContext: args.accountContext, + note: args.note, + key: args.key, + )), + ); + }, UpdateMemoRoute.name: (routeData) { final args = routeData.argsAs(); return AutoRoutePage( @@ -2982,6 +2995,50 @@ class TimeLineRouteArgs { } } +/// generated route for +/// [TranslateNoteModalSheet] +class TranslateNoteModalRoute + extends PageRouteInfo { + TranslateNoteModalRoute({ + required AccountContext accountContext, + required Note note, + Key? key, + List? children, + }) : super( + TranslateNoteModalRoute.name, + args: TranslateNoteModalRouteArgs( + accountContext: accountContext, + note: note, + key: key, + ), + initialChildren: children, + ); + + static const String name = 'TranslateNoteModalRoute'; + + static const PageInfo page = + PageInfo(name); +} + +class TranslateNoteModalRouteArgs { + const TranslateNoteModalRouteArgs({ + required this.accountContext, + required this.note, + this.key, + }); + + final AccountContext accountContext; + + final Note note; + + final Key? key; + + @override + String toString() { + return 'TranslateNoteModalRouteArgs{accountContext: $accountContext, note: $note, key: $key}'; + } +} + /// generated route for /// [UpdateMemoDialog] class UpdateMemoRoute extends PageRouteInfo { diff --git a/lib/state_notifier/common/download_file_notifier.g.dart b/lib/state_notifier/common/download_file_notifier.g.dart index 09b95ecfb..d7688f927 100644 --- a/lib/state_notifier/common/download_file_notifier.g.dart +++ b/lib/state_notifier/common/download_file_notifier.g.dart @@ -7,7 +7,7 @@ part of 'download_file_notifier.dart'; // ************************************************************************** String _$downloadFileNotifierHash() => - r'1e16b1a213ec582509b1843d15b1987e27020a26'; + r'99b394364feb8276a67c277ad703172e94fffc1b'; /// See also [DownloadFileNotifier]. @ProviderFor(DownloadFileNotifier) diff --git a/lib/state_notifier/note_create_page/note_create_state_notifier.g.dart b/lib/state_notifier/note_create_page/note_create_state_notifier.g.dart index a4167f385..2d028345f 100644 --- a/lib/state_notifier/note_create_page/note_create_state_notifier.g.dart +++ b/lib/state_notifier/note_create_page/note_create_state_notifier.g.dart @@ -7,7 +7,7 @@ part of 'note_create_state_notifier.dart'; // ************************************************************************** String _$noteCreateNotifierHash() => - r'a6c19cac73b572cf30473220f793e1826dbeb286'; + r'b0b33bfab1c43af4ce3c0368c2e7f23aefd744dc'; /// See also [NoteCreateNotifier]. @ProviderFor(NoteCreateNotifier) diff --git a/lib/view/common/misskey_notes/translate_note_modal_sheet.dart b/lib/view/common/misskey_notes/translate_note_modal_sheet.dart new file mode 100644 index 000000000..75a4b94a9 --- /dev/null +++ b/lib/view/common/misskey_notes/translate_note_modal_sheet.dart @@ -0,0 +1,111 @@ +import "package:auto_route/auto_route.dart"; +import "package:flutter/material.dart"; +import "package:flutter/services.dart"; +import "package:flutter_gen/gen_l10n/app_localizations.dart"; +import "package:hooks_riverpod/hooks_riverpod.dart"; +import "package:miria/providers.dart"; +import "package:miria/view/common/account_scope.dart"; +import "package:miria/view/common/error_detail.dart"; +import "package:miria/view/common/misskey_notes/mfm_text.dart"; +import "package:misskey_dart/misskey_dart.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; + +part "translate_note_modal_sheet.g.dart"; + +@Riverpod(dependencies: [misskeyPostContext]) +FutureOr _notesTranslate( + _NotesTranslateRef ref, { + required String noteId, + required String targetLang, +}) { + return ref.read(misskeyPostContextProvider).notes.translate( + NotesTranslateRequest( + noteId: noteId, + targetLang: targetLang, + ), + ); +} + +@RoutePage() +class TranslateNoteModalSheet extends ConsumerWidget + implements AutoRouteWrapper { + const TranslateNoteModalSheet({ + required this.accountContext, + required this.note, + super.key, + }); + + final AccountContext accountContext; + final Note note; + + @override + Widget wrappedRoute(BuildContext context) => + AccountContextScope(context: accountContext, child: this); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final translatedNote = ref.watch( + _notesTranslateProvider( + noteId: note.id, + targetLang: Localizations.localeOf(context).toLanguageTag(), + ), + ); + + return Scaffold( + body: ListView( + children: [ + ...switch (translatedNote) { + AsyncValue(valueOrNull: final translatedNote?) => [ + ListTile( + title: Text( + S.of(context).translatedFrom(translatedNote.sourceLang), + ), + trailing: IconButton( + tooltip: S.of(context).copyContents, + onPressed: () async { + await Clipboard.setData( + ClipboardData(text: translatedNote.text), + ); + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(S.of(context).doneCopy), + duration: const Duration(seconds: 1), + ), + ); + }, + icon: const Icon(Icons.copy), + ), + ), + const Divider(height: 0.0), + SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: MfmText( + mfmText: translatedNote.text, + host: note.user.host, + emoji: note.emojis, + isEnableAnimatedMFM: ref + .watch(generalSettingsRepositoryProvider) + .settings + .enableAnimatedMFM, + ), + ), + ), + ], + AsyncValue(:final error?, :final stackTrace) => [ + ErrorDetail(error: error, stackTrace: stackTrace), + ], + _ => [ + const Padding( + padding: EdgeInsets.all(8.0), + child: Center(child: CircularProgressIndicator.adaptive()), + ), + ], + }, + ], + ), + ); + } +} diff --git a/lib/view/common/misskey_notes/translate_note_modal_sheet.g.dart b/lib/view/common/misskey_notes/translate_note_modal_sheet.g.dart new file mode 100644 index 000000000..8a2634fa8 --- /dev/null +++ b/lib/view/common/misskey_notes/translate_note_modal_sheet.g.dart @@ -0,0 +1,235 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'translate_note_modal_sheet.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$notesTranslateHash() => r'e1ed9adf98f2c71aebeee8531c25fa9675dee658'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +/// See also [_notesTranslate]. +@ProviderFor(_notesTranslate) +const _notesTranslateProvider = _NotesTranslateFamily(); + +/// See also [_notesTranslate]. +class _NotesTranslateFamily extends Family { + /// See also [_notesTranslate]. + const _NotesTranslateFamily(); + + static final Iterable _dependencies = [ + misskeyPostContextProvider + ]; + + static final Iterable _allTransitiveDependencies = + { + misskeyPostContextProvider, + ...?misskeyPostContextProvider.allTransitiveDependencies + }; + + @override + Iterable? get dependencies => _dependencies; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'_notesTranslateProvider'; + + /// See also [_notesTranslate]. + _NotesTranslateProvider call({ + required String noteId, + required String targetLang, + }) { + return _NotesTranslateProvider( + noteId: noteId, + targetLang: targetLang, + ); + } + + @visibleForOverriding + @override + _NotesTranslateProvider getProviderOverride( + covariant _NotesTranslateProvider provider, + ) { + return call( + noteId: provider.noteId, + targetLang: provider.targetLang, + ); + } + + /// Enables overriding the behavior of this provider, no matter the parameters. + Override overrideWith( + FutureOr Function(_NotesTranslateRef ref) + create) { + return _$NotesTranslateFamilyOverride(this, create); + } +} + +class _$NotesTranslateFamilyOverride implements FamilyOverride { + _$NotesTranslateFamilyOverride(this.overriddenFamily, this.create); + + final FutureOr Function(_NotesTranslateRef ref) + create; + + @override + final _NotesTranslateFamily overriddenFamily; + + @override + _NotesTranslateProvider getProviderOverride( + covariant _NotesTranslateProvider provider, + ) { + return provider._copyWith(create); + } +} + +/// See also [_notesTranslate]. +class _NotesTranslateProvider + extends AutoDisposeFutureProvider { + /// See also [_notesTranslate]. + _NotesTranslateProvider({ + required String noteId, + required String targetLang, + }) : this._internal( + (ref) => _notesTranslate( + ref as _NotesTranslateRef, + noteId: noteId, + targetLang: targetLang, + ), + from: _notesTranslateProvider, + name: r'_notesTranslateProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$notesTranslateHash, + dependencies: _NotesTranslateFamily._dependencies, + allTransitiveDependencies: + _NotesTranslateFamily._allTransitiveDependencies, + noteId: noteId, + targetLang: targetLang, + ); + + _NotesTranslateProvider._internal( + super.create, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.noteId, + required this.targetLang, + }) : super.internal(); + + final String noteId; + final String targetLang; + + @override + Override overrideWith( + FutureOr Function(_NotesTranslateRef ref) create, + ) { + return ProviderOverride( + origin: this, + override: _NotesTranslateProvider._internal( + (ref) => create(ref as _NotesTranslateRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + noteId: noteId, + targetLang: targetLang, + ), + ); + } + + @override + ({ + String noteId, + String targetLang, + }) get argument { + return ( + noteId: noteId, + targetLang: targetLang, + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _NotesTranslateProviderElement(this); + } + + _NotesTranslateProvider _copyWith( + FutureOr Function(_NotesTranslateRef ref) create, + ) { + return _NotesTranslateProvider._internal( + (ref) => create(ref as _NotesTranslateRef), + name: name, + dependencies: dependencies, + allTransitiveDependencies: allTransitiveDependencies, + debugGetCreateSourceHash: debugGetCreateSourceHash, + from: from, + noteId: noteId, + targetLang: targetLang, + ); + } + + @override + bool operator ==(Object other) { + return other is _NotesTranslateProvider && + other.noteId == noteId && + other.targetLang == targetLang; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, noteId.hashCode); + hash = _SystemHash.combine(hash, targetLang.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin _NotesTranslateRef + on AutoDisposeFutureProviderRef { + /// The parameter `noteId` of this provider. + String get noteId; + + /// The parameter `targetLang` of this provider. + String get targetLang; +} + +class _NotesTranslateProviderElement + extends AutoDisposeFutureProviderElement + with _NotesTranslateRef { + _NotesTranslateProviderElement(super.provider); + + @override + String get noteId => (origin as _NotesTranslateProvider).noteId; + @override + String get targetLang => (origin as _NotesTranslateProvider).targetLang; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, inference_failure_on_uninitialized_variable, inference_failure_on_function_return_type, inference_failure_on_untyped_parameter, deprecated_member_use_from_same_package diff --git a/lib/view/note_modal_sheet/note_modal_sheet.dart b/lib/view/note_modal_sheet/note_modal_sheet.dart index 09bdffa5f..774fea309 100644 --- a/lib/view/note_modal_sheet/note_modal_sheet.dart +++ b/lib/view/note_modal_sheet/note_modal_sheet.dart @@ -386,6 +386,18 @@ class NoteModalSheet extends ConsumerWidget implements AutoRouteWrapper { }); }, ), + if (accountContext.postAccount.i.policies.canUseTranslator && + (accountContext.postAccount.meta?.translatorAvailable ?? false)) + ListTile( + leading: const Icon(Icons.translate), + title: Text(S.of(context).translateNote), + onTap: () async => await context.pushRoute( + TranslateNoteModalRoute( + accountContext: accountContext, + note: targetNote, + ), + ), + ), if (accountContext.isSame) switch (noteStatus) { null => const SizedBox.shrink(), diff --git a/lib/view/note_modal_sheet/note_modal_sheet.g.dart b/lib/view/note_modal_sheet/note_modal_sheet.g.dart index 39a63ab2b..653d1e5fc 100644 --- a/lib/view/note_modal_sheet/note_modal_sheet.g.dart +++ b/lib/view/note_modal_sheet/note_modal_sheet.g.dart @@ -7,7 +7,7 @@ part of 'note_modal_sheet.dart'; // ************************************************************************** String _$noteModalSheetNotifierHash() => - r'6e16e66d1e8ce6671ac6ba8bd9bb208c9b7b6652'; + r'7d2d5ee4f994089c0ae3b3b1fcbbec8ad53c8db9'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/view/user_page/user_info_notifier.g.dart b/lib/view/user_page/user_info_notifier.g.dart index 796682d30..1832bd342 100644 --- a/lib/view/user_page/user_info_notifier.g.dart +++ b/lib/view/user_page/user_info_notifier.g.dart @@ -384,7 +384,7 @@ class _UserInfoProxyProviderElement String get userId => (origin as UserInfoProxyProvider).userId; } -String _$userInfoNotifierHash() => r'cd97bc5433d147b8881446c0431fa623f0d2319e'; +String _$userInfoNotifierHash() => r'b4b78145b2cb531abe6da2fb840c4b01bb12f4dd'; abstract class _$UserInfoNotifier extends BuildlessAutoDisposeAsyncNotifier {