Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
shiosyakeyakini-info committed Jul 5, 2023
2 parents fb83895 + 2ffc292 commit de704be
Show file tree
Hide file tree
Showing 15 changed files with 625 additions and 155 deletions.
3 changes: 2 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
<application
android:label="miria"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
android:icon="@mipmap/launcher_icon"
android:requestLegacyExternalStorage="true">
<activity
android:name=".MainActivity"
android:exported="true"
Expand Down
2 changes: 1 addition & 1 deletion assets_builder/misskey
Submodule misskey updated 154 files
6 changes: 6 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ PODS:
- FMDB/standard (2.7.5)
- image_editor_common (1.0.0):
- Flutter
- image_gallery_saver (2.0.2):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
Expand Down Expand Up @@ -68,6 +70,7 @@ DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- image_editor_common (from `.symlinks/plugins/image_editor_common/ios`)
- image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
Expand All @@ -93,6 +96,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
image_editor_common:
:path: ".symlinks/plugins/image_editor_common/ios"
image_gallery_saver:
:path: ".symlinks/plugins/image_gallery_saver/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
Expand All @@ -116,6 +121,7 @@ SPEC CHECKSUMS:
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
receive_sharing_intent: c0d87310754e74c0f9542947e7cbdf3a0335a3b1
Expand Down
4 changes: 3 additions & 1 deletion ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSPhotoLibraryUsageDescription</key>
<string>写真をアップロードするために、写真への権限を許可してください。</string>
<string>画像をアップロードするために、アルバムへの権限を許可してください。</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>画像を保存するために、アルバムへの権限を許可してください。</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
Expand Down
3 changes: 2 additions & 1 deletion lib/view/common/common_drawer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:miria/router/app_router.dart';
import 'package:miria/view/common/account_scope.dart';
import 'package:miria/view/common/avatar_icon.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:miria/view/common/misskey_notes/mfm_text.dart';

class CommonDrawer extends ConsumerWidget {
final Account initialOpenAccount;
Expand All @@ -27,7 +28,7 @@ class CommonDrawer extends ConsumerWidget {
initiallyExpanded:
account.userId == initialOpenAccount.userId &&
account.host == initialOpenAccount.host,
title: Text(account.i.name ?? account.i.username,
title: SimpleMfmText(account.i.name ?? account.i.username,
style: Theme.of(context).textTheme.titleMedium),
subtitle: Text(
"@${account.userId}@${account.host}",
Expand Down
47 changes: 43 additions & 4 deletions lib/view/common/misskey_notes/image_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import 'dart:math';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:miria/providers.dart';
import 'package:miria/view/common/misskey_notes/network_image.dart';

class ImageDialog extends StatefulWidget {
class ImageDialog extends ConsumerStatefulWidget {
final List<String> imageUrlList;
final int initialPage;

Expand All @@ -14,10 +19,10 @@ class ImageDialog extends StatefulWidget {
});

@override
State<StatefulWidget> createState() => ImageDialogState();
ConsumerState<ConsumerStatefulWidget> createState() => ImageDialogState();
}

class ImageDialogState extends State<ImageDialog> {
class ImageDialogState extends ConsumerState<ImageDialog> {
var scale = 1.0;
late final pageController = PageController(initialPage: widget.initialPage);
var verticalDragX = 0.0;
Expand Down Expand Up @@ -123,7 +128,7 @@ class ImageDialogState extends State<ImageDialog> {
),
)))),
Positioned(
right: 10,
left: 10,
top: 10,
child: RawMaterialButton(
onPressed: () {
Expand All @@ -146,6 +151,40 @@ class ImageDialogState extends State<ImageDialog> {
?.color
?.withAlpha(200)))),
),
if (defaultTargetPlatform == TargetPlatform.android ||
defaultTargetPlatform == TargetPlatform.iOS)
Positioned(
right: 10,
top: 10,
child: RawMaterialButton(
onPressed: () async {
final page = pageController.page?.toInt();
if (page == null) return;
final response = await ref.read(dioProvider).get(
widget.imageUrlList[page],
options:
Options(responseType: ResponseType.bytes));
await ImageGallerySaver.saveImage(response.data);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("画像保存したで")));
},
constraints:
const BoxConstraints(minWidth: 0, minHeight: 0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
padding: EdgeInsets.zero,
fillColor: Theme.of(context)
.scaffoldBackgroundColor
.withAlpha(200),
shape: const CircleBorder(),
child: Padding(
padding: const EdgeInsets.all(5),
child: Icon(Icons.save,
color: Theme.of(context)
.textTheme
.bodyMedium
?.color
?.withAlpha(200))))),
],
),
));
Expand Down
20 changes: 19 additions & 1 deletion lib/view/common/misskey_notes/mfm_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class MfmTextState extends ConsumerState<MfmText> {
final account = AccountScope.of(context);

// 他サーバーや外部サイトは別アプリで起動する
//TODO: nodeinfoから相手先サーバーがMisskeyの場合はそこで解決する
if (uri.host != AccountScope.of(context).host) {
if (await canLaunchUrl(uri)) {
if (!await launchUrl(uri,
Expand All @@ -69,6 +70,14 @@ class MfmTextState extends ConsumerState<MfmText> {
uri.pathSegments.first == "channels") {
context.pushRoute(
ChannelDetailRoute(account: account, channelId: uri.pathSegments[1]));
} else if (uri.pathSegments.length == 2 &&
uri.pathSegments.first == "notes") {
final note = await ref
.read(misskeyProvider(account))
.notes
.show(NotesShowRequest(noteId: uri.pathSegments[1]));
if (!mounted) return;
context.pushRoute(NoteDetailRoute(account: account, note: note));
} else if (uri.pathSegments.length == 1 &&
uri.pathSegments.first.startsWith("@")) {
await onMentionTap(uri.pathSegments.first);
Expand Down Expand Up @@ -286,6 +295,15 @@ class UserInformation extends ConsumerStatefulWidget {
}

class UserInformationState extends ConsumerState<UserInformation> {
String resolveIconUrl(Uri uri) {
final baseUrl = uri.toString();
if (baseUrl.startsWith("/")) {
return "https://${widget.user.host ?? AccountScope.of(context).host}$baseUrl";
} else {
return baseUrl;
}
}

@override
Widget build(BuildContext context) {
return SimpleMfmText(
Expand All @@ -304,7 +322,7 @@ class UserInformationState extends ConsumerState<UserInformation> {
message: badge.name,
child: NetworkImageView(
type: ImageType.role,
url: badge.iconUrl.toString(),
url: resolveIconUrl(badge.iconUrl!),
height: (DefaultTextStyle.of(context).style.fontSize ?? 22),
),
),
Expand Down
14 changes: 14 additions & 0 deletions lib/view/common/misskey_notes/note_modal_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import 'package:miria/providers.dart';
import 'package:miria/router/app_router.dart';
import 'package:miria/view/common/misskey_notes/abuse_dialog.dart';
import 'package:miria/view/common/misskey_notes/clip_modal_sheet.dart';
import 'package:miria/view/common/misskey_notes/open_another_account.dart';
import 'package:miria/view/common/not_implements_dialog.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:miria/view/dialogs/simple_confirm_dialog.dart';
import 'package:misskey_dart/misskey_dart.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:share_plus/share_plus.dart';

Expand Down Expand Up @@ -97,6 +99,18 @@ class NoteModalSheet extends ConsumerWidget {

Navigator.of(context).pop();
}),
if (targetNote.user.host != null)
ListTile(
title: const Text("ブラウザでリモート先を開く"),
onTap: () async {
final uri = targetNote.url ?? targetNote.uri;
if (uri == null) return;
launchUrl(uri, mode: LaunchMode.inAppWebView);

Navigator.of(context).pop();
}),
if (!targetNote.localOnly)
OpenAnotherAccount(note: targetNote, beforeOpenAccount: account),
ListTile(
title: const Text("ノートを共有"),
onTap: () {
Expand Down
124 changes: 124 additions & 0 deletions lib/view/common/misskey_notes/open_another_account.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import 'package:auto_route/auto_route.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:miria/model/account.dart';
import 'package:miria/providers.dart';
import 'package:miria/router/app_router.dart';
import 'package:miria/view/common/account_scope.dart';
import 'package:miria/view/common/avatar_icon.dart';
import 'package:miria/view/common/misskey_notes/mfm_text.dart';
import 'package:misskey_dart/misskey_dart.dart';

class OpenAnotherAccount extends ConsumerStatefulWidget {
final Note note;
final Account beforeOpenAccount;
const OpenAnotherAccount({
super.key,
required this.note,
required this.beforeOpenAccount,
});

@override
ConsumerState<ConsumerStatefulWidget> createState() =>
OpenAnotherAccountState();
}

class OpenAnotherAccountState extends ConsumerState<OpenAnotherAccount> {
@override
Widget build(BuildContext context) {
return ListTile(
title: const Text("別のアカウントで開く"),
onTap: () async {
final account = await showDialog<Account?>(
context: context,
builder: (context2) => const AccountSelectDialog());

if (account == null) return;

try {
// まず、自分のサーバーの直近のノートに該当のノートが含まれているか見る
final myHostUserData = await ref
.read(misskeyProvider(account))
.users
.showByName(UsersShowByUserNameRequest(
userName: widget.note.user.username,
host:
widget.note.user.host ?? widget.beforeOpenAccount.host));

final myHostUserNotes = await ref
.read(misskeyProvider(account))
.users
.notes(UsersNotesRequest(
userId: myHostUserData.id,
untilDate: widget.note.createdAt.millisecondsSinceEpoch + 1,
));

final foundMyHostNote = myHostUserNotes.firstWhereOrNull(
(e) => e.uri?.pathSegments.lastOrNull == widget.note.id);
if (foundMyHostNote != null) {
if (!mounted) return;
context.pushRoute(
NoteDetailRoute(note: foundMyHostNote, account: account));
return;
}
throw Exception();
} catch (e) {
// 最終手段として、連合で照会する
final result = await ref.read(misskeyProvider(account)).ap.show(
ApShowRequest(
uri: widget.note.uri ??
Uri(
scheme: "https",
host: widget.beforeOpenAccount.host,
pathSegments: ["notes", widget.note.id])));
// よくかんがえたら無駄
final resultNote = await ref
.read(misskeyProvider(account))
.notes
.show(NotesShowRequest(noteId: result.object["id"]));
if (!mounted) return;
context
.pushRoute(NoteDetailRoute(note: resultNote, account: account));
}
},
);
}
}

class AccountSelectDialog extends ConsumerWidget {
const AccountSelectDialog({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final accounts =
ref.watch(accountRepository.select((value) => value.account));
return AlertDialog(
title: const Text("開くアカウント選んでや"),
content: SizedBox(
width: MediaQuery.of(context).size.width * 0.8,
height: MediaQuery.of(context).size.height * 0.8,
child: ListView(
children: [
for (final account in accounts)
AccountScope(
account: account,
child: ListTile(
leading: AvatarIcon.fromIResponse(account.i),
title: SimpleMfmText(account.i.name ?? account.i.username,
style: Theme.of(context).textTheme.titleMedium),
subtitle: Text(
"@${account.userId}@${account.host}",
style: Theme.of(context).textTheme.bodySmall,
),
onTap: () {
Navigator.of(context).pop(account);
},
),
)
],
),
),
);
}
}
3 changes: 2 additions & 1 deletion lib/view/note_detail_page/note_detail_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:miria/extensions/date_time_extension.dart';
import 'package:miria/model/account.dart';
import 'package:miria/providers.dart';
import 'package:miria/view/common/account_scope.dart';
import 'package:miria/view/common/common_drawer.dart';
import 'package:miria/view/common/misskey_notes/misskey_note.dart';
import 'package:miria/view/common/pushable_listview.dart';
import 'package:misskey_dart/misskey_dart.dart';
Expand Down Expand Up @@ -93,7 +94,7 @@ class NoteDetailPageState extends ConsumerState<NoteDetailPage> {
Text(
"投稿時間: ${actualShow!.createdAt.formatUntilMilliSeconds}"),
const Padding(padding: EdgeInsets.only(top: 5)),
Divider(),
const Divider(),
const Padding(padding: EdgeInsets.only(top: 5)),
Padding(
padding: const EdgeInsets.only(left: 20),
Expand Down
Loading

0 comments on commit de704be

Please sign in to comment.