diff --git a/lib/feed/widgets/feed_page_app_bar.dart b/lib/feed/widgets/feed_page_app_bar.dart index 23437661c..5e4063cb5 100644 --- a/lib/feed/widgets/feed_page_app_bar.dart +++ b/lib/feed/widgets/feed_page_app_bar.dart @@ -19,14 +19,13 @@ import 'package:thunder/feed/utils/community_share.dart'; import 'package:thunder/feed/utils/user_share.dart'; import 'package:thunder/feed/utils/utils.dart'; import 'package:thunder/feed/view/feed_page.dart'; -import 'package:thunder/modlog/view/modlog_page.dart'; +import 'package:thunder/modlog/utils/navigate_modlog.dart'; import 'package:thunder/search/bloc/search_bloc.dart'; import 'package:thunder/search/pages/search_page.dart'; import 'package:thunder/shared/snackbar.dart'; import 'package:thunder/shared/sort_picker.dart'; import 'package:thunder/shared/thunder_popup_menu_item.dart'; import 'package:thunder/thunder/bloc/thunder_bloc.dart'; -import 'package:thunder/utils/swipe.dart'; /// Holds the app bar for the feed page. The app bar actions changes depending on the type of feed (general, community, user) class FeedPageAppBar extends StatelessWidget { @@ -223,22 +222,10 @@ class FeedAppBarCommunityActions extends StatelessWidget { ), ThunderPopupMenuItem( onTap: () async { - final state = context.read().state; - final reduceAnimations = state.reduceAnimations; - - await Navigator.of(context).push( - SwipeablePageRoute( - transitionDuration: reduceAnimations ? const Duration(milliseconds: 100) : null, - backGestureDetectionWidth: 45, - canOnlySwipeFromEdge: true, - builder: (context) => MultiBlocProvider( - providers: [ - BlocProvider.value(value: feedBloc), - BlocProvider.value(value: thunderBloc), - ], - child: ModlogFeedPage(communityId: feedBloc.state.fullCommunityView!.communityView.community.id), - ), - ), + await navigateToModlogPage( + context, + feedBloc: feedBloc, + communityId: feedBloc.state.fullCommunityView!.communityView.community.id, ); }, icon: Icons.shield_rounded, @@ -339,28 +326,7 @@ class FeedAppBarGeneralActions extends StatelessWidget { ThunderPopupMenuItem( onTap: () async { HapticFeedback.mediumImpact(); - - AuthBloc authBloc = context.read(); - ThunderBloc thunderBloc = context.read(); - - await Navigator.of(context).push( - SwipeablePageRoute( - transitionDuration: thunderBloc.state.reduceAnimations ? const Duration(milliseconds: 100) : null, - backGestureDetectionStartOffset: !kIsWeb && Platform.isAndroid ? 45 : 0, - backGestureDetectionWidth: 45, - canOnlySwipeFromEdge: - disableFullPageSwipe(isUserLoggedIn: authBloc.state.isLoggedIn, state: thunderBloc.state, isPostPage: false) || !thunderBloc.state.enableFullScreenSwipeNavigationGesture, - builder: (otherContext) { - return MultiBlocProvider( - providers: [ - BlocProvider.value(value: feedBloc), - BlocProvider.value(value: thunderBloc), - ], - child: const ModlogFeedPage(), - ); - }, - ), - ); + await navigateToModlogPage(context, feedBloc: feedBloc); }, icon: Icons.shield_rounded, title: l10n.modlog, diff --git a/lib/instance/pages/instance_page.dart b/lib/instance/pages/instance_page.dart index e03f5861f..d631a918c 100644 --- a/lib/instance/pages/instance_page.dart +++ b/lib/instance/pages/instance_page.dart @@ -1,11 +1,7 @@ -import 'dart:io'; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lemmy_api_client/v3.dart'; -import 'package:swipeable_page_route/swipeable_page_route.dart'; import 'package:thunder/comment/widgets/comment_list_entry.dart'; import 'package:thunder/community/widgets/community_list_entry.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; @@ -16,7 +12,7 @@ import 'package:thunder/instance/bloc/instance_bloc.dart'; import 'package:thunder/instance/cubit/instance_page_cubit.dart'; import 'package:thunder/instance/enums/instance_action.dart'; import 'package:thunder/instance/widgets/instance_view.dart'; -import 'package:thunder/modlog/view/modlog_page.dart'; +import 'package:thunder/modlog/utils/navigate_modlog.dart'; import 'package:thunder/search/widgets/search_action_chip.dart'; import 'package:thunder/shared/error_message.dart'; import 'package:thunder/shared/persistent_header.dart'; @@ -28,7 +24,6 @@ import 'package:thunder/utils/instance.dart'; import 'package:thunder/utils/links.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:thunder/utils/numbers.dart'; -import 'package:thunder/utils/swipe.dart'; class InstancePage extends StatefulWidget { final GetSiteResponse getSiteResponse; @@ -166,28 +161,11 @@ class _InstancePageState extends State { ThunderPopupMenuItem( onTap: () async { HapticFeedback.mediumImpact(); - - AuthBloc authBloc = context.read(); - ThunderBloc thunderBloc = context.read(); FeedBloc feedBloc = context.read(); - - await Navigator.of(context).push( - SwipeablePageRoute( - transitionDuration: thunderBloc.state.reduceAnimations ? const Duration(milliseconds: 100) : null, - backGestureDetectionStartOffset: !kIsWeb && Platform.isAndroid ? 45 : 0, - backGestureDetectionWidth: 45, - canOnlySwipeFromEdge: disableFullPageSwipe(isUserLoggedIn: authBloc.state.isLoggedIn, state: thunderBloc.state, isPostPage: false) || - !thunderBloc.state.enableFullScreenSwipeNavigationGesture, - builder: (otherContext) { - return MultiBlocProvider( - providers: [ - BlocProvider.value(value: feedBloc), - BlocProvider.value(value: thunderBloc), - ], - child: ModlogFeedPage(lemmyClient: feedBloc.lemmyClient), - ); - }, - ), + navigateToModlogPage( + context, + feedBloc: feedBloc, + lemmyClient: feedBloc.lemmyClient, ); }, icon: Icons.shield_rounded, diff --git a/lib/modlog/utils/navigate_modlog.dart b/lib/modlog/utils/navigate_modlog.dart new file mode 100644 index 000000000..0f44e913d --- /dev/null +++ b/lib/modlog/utils/navigate_modlog.dart @@ -0,0 +1,53 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:lemmy_api_client/v3.dart'; +import 'package:swipeable_page_route/swipeable_page_route.dart'; +import 'package:thunder/core/auth/bloc/auth_bloc.dart'; +import 'package:thunder/core/singletons/lemmy_client.dart'; +import 'package:thunder/feed/bloc/feed_bloc.dart'; +import 'package:thunder/modlog/view/modlog_page.dart'; +import 'package:thunder/thunder/bloc/thunder_bloc.dart'; +import 'package:thunder/utils/swipe.dart'; + +Future navigateToModlogPage( + BuildContext context, { + required FeedBloc feedBloc, + ModlogActionType? modlogActionType, + int? communityId, + int? userId, + int? moderatorId, + LemmyClient? lemmyClient, +}) async { + final ThunderBloc thunderBloc = context.read(); + final bool reduceAnimations = thunderBloc.state.reduceAnimations; + + bool canOnlySwipeFromEdge = true; + try { + AuthBloc authBloc = context.read(); + canOnlySwipeFromEdge = disableFullPageSwipe(isUserLoggedIn: authBloc.state.isLoggedIn, state: thunderBloc.state, isPostPage: false) || !thunderBloc.state.enableFullScreenSwipeNavigationGesture; + } catch (e) {} + + await Navigator.of(context).push( + SwipeablePageRoute( + transitionDuration: reduceAnimations ? const Duration(milliseconds: 100) : null, + backGestureDetectionStartOffset: !kIsWeb && Platform.isAndroid ? 45 : 0, + canOnlySwipeFromEdge: canOnlySwipeFromEdge, + builder: (context) => MultiBlocProvider( + providers: [ + BlocProvider.value(value: feedBloc), + BlocProvider.value(value: thunderBloc), + ], + child: ModlogFeedPage( + modlogActionType: modlogActionType, + communityId: communityId, + userId: userId, + moderatorId: moderatorId, + lemmyClient: lemmyClient, + ), + ), + ), + ); +} diff --git a/lib/thunder/cubits/deep_links_cubit/deep_links_cubit.dart b/lib/thunder/cubits/deep_links_cubit/deep_links_cubit.dart index cca15f89f..0f8f0fe71 100644 --- a/lib/thunder/cubits/deep_links_cubit/deep_links_cubit.dart +++ b/lib/thunder/cubits/deep_links_cubit/deep_links_cubit.dart @@ -43,6 +43,12 @@ class DeepLinksCubit extends Cubit { link: link, linkType: LinkType.community, )); + } else if (link.contains("/modlog")) { + emit(state.copyWith( + deepLinkStatus: DeepLinkStatus.success, + link: link, + linkType: LinkType.modlog, + )); } else if (Uri.tryParse(link)?.pathSegments.isEmpty == true) { emit(state.copyWith( deepLinkStatus: DeepLinkStatus.success, diff --git a/lib/thunder/enums/deep_link_enums.dart b/lib/thunder/enums/deep_link_enums.dart index 5c542d366..c07b733b0 100644 --- a/lib/thunder/enums/deep_link_enums.dart +++ b/lib/thunder/enums/deep_link_enums.dart @@ -1 +1,9 @@ -enum LinkType { user, post, comment, instance, unknown, community } +enum LinkType { + user, + post, + comment, + instance, + unknown, + community, + modlog, +} diff --git a/lib/thunder/pages/thunder_page.dart b/lib/thunder/pages/thunder_page.dart index c83e57c9c..f4abe7b8d 100644 --- a/lib/thunder/pages/thunder_page.dart +++ b/lib/thunder/pages/thunder_page.dart @@ -32,6 +32,7 @@ import 'package:thunder/feed/bloc/feed_bloc.dart'; import 'package:thunder/feed/feed.dart'; import 'package:thunder/feed/view/feed_page.dart'; import 'package:thunder/feed/widgets/feed_fab.dart'; +import 'package:thunder/modlog/utils/navigate_modlog.dart'; import 'package:thunder/post/utils/post.dart'; import 'package:thunder/shared/common_markdown_body.dart'; import 'package:thunder/shared/snackbar.dart'; @@ -263,6 +264,8 @@ class _ThunderState extends State { if (context.mounted) await _navigateToPost(_link); case LinkType.community: if (context.mounted) await _navigateToCommunity(_link); + case LinkType.modlog: + if (context.mounted) await _navigateToModlog(_link); case LinkType.instance: if (context.mounted) await _navigateToInstance(_link); case LinkType.unknown: @@ -333,6 +336,31 @@ class _ThunderState extends State { } } + Future _navigateToModlog(String link) async { + try { + Uri? uri = Uri.tryParse(link); + if (uri != null) { + final LemmyClient lemmyClient = LemmyClient()..changeBaseUrl(uri.host); + FeedBloc feedBloc = FeedBloc(lemmyClient: lemmyClient); + await navigateToModlogPage( + context, + feedBloc: feedBloc, + modlogActionType: ModlogActionType.fromJson(uri.queryParameters['actionType'] ?? ModlogActionType.all.value), + communityId: int.tryParse(uri.queryParameters['communityId'] ?? ''), + userId: int.tryParse(uri.queryParameters['userId'] ?? ''), + moderatorId: int.tryParse(uri.queryParameters['modId'] ?? ''), + lemmyClient: lemmyClient, + ); + return; + } + } catch (e) {} + + // Show an error for any issues processing the link + if (context.mounted) { + _showLinkProcessingError(context, AppLocalizations.of(context)!.exceptionProcessingUri, link); + } + } + Future _navigateToComment(String link) async { final commentId = await getLemmyCommentId(link); if (context.mounted && commentId != null) { diff --git a/lib/utils/links.dart b/lib/utils/links.dart index cc3d99555..3b6423544 100644 --- a/lib/utils/links.dart +++ b/lib/utils/links.dart @@ -11,7 +11,9 @@ import 'package:link_preview_generator/link_preview_generator.dart'; import 'package:share_plus/share_plus.dart'; import 'package:swipeable_page_route/swipeable_page_route.dart'; import 'package:thunder/core/enums/browser_mode.dart'; +import 'package:thunder/feed/bloc/feed_bloc.dart'; import 'package:thunder/instances.dart'; +import 'package:thunder/modlog/utils/navigate_modlog.dart'; import 'package:thunder/shared/pages/loading_page.dart'; import 'package:thunder/shared/webview.dart'; import 'package:thunder/utils/bottom_sheet_list_picker.dart'; @@ -197,6 +199,25 @@ void handleLink(BuildContext context, {required String url}) async { } } + // Try navigate to modlog + Uri? uri = Uri.tryParse(url); + if (context.mounted && uri != null && instances.contains(uri.host) && url.contains('/modlog')) { + try { + final LemmyClient lemmyClient = LemmyClient()..changeBaseUrl(uri.host); + FeedBloc feedBloc = FeedBloc(lemmyClient: lemmyClient); + await navigateToModlogPage( + context, + feedBloc: feedBloc, + modlogActionType: ModlogActionType.fromJson(uri.queryParameters['actionType'] ?? ModlogActionType.all.value), + communityId: int.tryParse(uri.queryParameters['communityId'] ?? ''), + userId: int.tryParse(uri.queryParameters['userId'] ?? ''), + moderatorId: int.tryParse(uri.queryParameters['modId'] ?? ''), + lemmyClient: lemmyClient, + ); + return; + } catch (e) {} + } + // Try opening it as an image try { if (isImageUrl(url) && context.mounted) {