Skip to content

Commit

Permalink
Add option to view modlog entry for removed comments (#1628)
Browse files Browse the repository at this point in the history
* Allow navigating to modlog for removed comment

* Remove comment modlog custom filtering

* Only show comment modlog for 0.19.4+
  • Loading branch information
micahmo authored Dec 12, 2024
1 parent aef85b8 commit fd2b972
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 31 deletions.
1 change: 1 addition & 0 deletions lib/core/singletons/lemmy_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ enum LemmyFeature {
multiRead(0, 19, 0, preRelease: ["rc", "1"]),
hidePosts(0, 19, 4),
customThumbnail(0, 19, 4),
commentModLog(0, 19, 4),
imageDimension(0, 19, 6),
;

Expand Down
4 changes: 4 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2813,6 +2813,10 @@
"@viewCommentSource": {
"description": "Menu item for viewing a comment's source"
},
"viewModlog": "View Modlog",
"@viewModlog": {
"description": "Action which allows the user to navigate to the modlog for a particular entity"
},
"viewOriginal": "View original",
"@viewOriginal": {
"description": "Action for viewing original text (as opposed to raw markdown)"
Expand Down
3 changes: 3 additions & 0 deletions lib/modlog/bloc/modlog_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class ModlogBloc extends Bloc<ModlogEvent, ModlogState> {
communityId: state.communityId,
userId: state.userId,
moderatorId: state.moderatorId,
commentId: state.commentId,
reset: true,
));
}
Expand All @@ -91,6 +92,7 @@ class ModlogBloc extends Bloc<ModlogEvent, ModlogState> {
communityId: event.communityId,
userId: event.userId,
moderatorId: event.moderatorId,
commentId: event.commentId,
lemmyClient: lemmyClient,
);

Expand Down Expand Up @@ -130,6 +132,7 @@ class ModlogBloc extends Bloc<ModlogEvent, ModlogState> {
communityId: state.communityId,
userId: state.userId,
moderatorId: state.moderatorId,
commentId: event.commentId,
lemmyClient: lemmyClient,
);

Expand Down
4 changes: 4 additions & 0 deletions lib/modlog/bloc/modlog_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ final class ModlogFeedFetchedEvent extends ModlogEvent {
/// The id of the moderator to display posts for.
final int? moderatorId;

/// The id of a specific comment to show in the modlog (optional)
final int? commentId;

/// Boolean which indicates whether or not to reset the feed
final bool reset;

Expand All @@ -32,6 +35,7 @@ final class ModlogFeedFetchedEvent extends ModlogEvent {
this.communityId,
this.userId,
this.moderatorId,
this.commentId,
this.reset = false,
});
}
Expand Down
10 changes: 8 additions & 2 deletions lib/modlog/bloc/modlog_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ final class ModlogState extends Equatable {
this.communityId,
this.userId,
this.moderatorId,
this.commentId,
this.modlogEventItems = const <ModlogEventItem>[],
this.hasReachedEnd = false,
this.currentPage = 1,
Expand All @@ -30,6 +31,9 @@ final class ModlogState extends Equatable {
/// The id of the moderator to display modlog events for.
final int? moderatorId;

/// The id of a specific comment to show in the modlog (optional)
final int? commentId;

/// The list of modlog events
final List<ModlogEventItem> modlogEventItems;

Expand All @@ -48,6 +52,7 @@ final class ModlogState extends Equatable {
int? communityId,
int? userId,
int? moderatorId,
int? commentId,
List<ModlogEventItem>? modlogEventItems,
bool? hasReachedEnd,
int? currentPage,
Expand All @@ -59,6 +64,7 @@ final class ModlogState extends Equatable {
communityId: communityId ?? this.communityId,
userId: userId ?? this.userId,
moderatorId: moderatorId ?? this.moderatorId,
commentId: commentId ?? this.commentId,
modlogEventItems: modlogEventItems ?? this.modlogEventItems,
hasReachedEnd: hasReachedEnd ?? this.hasReachedEnd,
currentPage: currentPage ?? this.currentPage,
Expand All @@ -68,9 +74,9 @@ final class ModlogState extends Equatable {

@override
String toString() {
return '''ModlogState { status: $status, modlogActionType: $modlogActionType, communityId: $communityId, userId: $userId, moderatorId: $moderatorId, modlogEventItems: ${modlogEventItems.length}, hasReachedEnd: $hasReachedEnd }''';
return '''ModlogState { status: $status, modlogActionType: $modlogActionType, communityId: $communityId, userId: $userId, moderatorId: $moderatorId, commentId: $commentId, modlogEventItems: ${modlogEventItems.length}, hasReachedEnd: $hasReachedEnd }''';
}

@override
List<dynamic> get props => [status, modlogActionType, communityId, userId, moderatorId, modlogEventItems, hasReachedEnd, currentPage, message];
List<dynamic> get props => [status, modlogActionType, communityId, userId, moderatorId, commentId, modlogEventItems, hasReachedEnd, currentPage, message];
}
2 changes: 2 additions & 0 deletions lib/modlog/utils/modlog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Future<Map<String, dynamic>> fetchModlogEvents({
int? communityId,
int? userId,
int? moderatorId,
int? commentId,
required LemmyClient lemmyClient,
}) async {
Account? account = await fetchActiveProfileAccount();
Expand All @@ -34,6 +35,7 @@ Future<Map<String, dynamic>> fetchModlogEvents({
communityId: communityId,
otherPersonId: userId,
modPersonId: moderatorId,
commentId: commentId,
));

List<ModlogEventItem> items = [];
Expand Down
8 changes: 6 additions & 2 deletions lib/modlog/utils/navigate_modlog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import 'package:thunder/utils/swipe.dart';

Future<void> navigateToModlogPage(
BuildContext context, {
required FeedBloc feedBloc,
FeedBloc? feedBloc,
ModlogActionType? modlogActionType,
int? communityId,
int? userId,
int? moderatorId,
int? commentId,
LemmyClient? lemmyClient,
Widget? subtitle,
}) async {
final ThunderBloc thunderBloc = context.read<ThunderBloc>();
final bool reduceAnimations = thunderBloc.state.reduceAnimations;
Expand All @@ -42,15 +44,17 @@ Future<void> navigateToModlogPage(
canOnlySwipeFromEdge: canOnlySwipeFromEdge,
builder: (context) => MultiBlocProvider(
providers: [
BlocProvider.value(value: feedBloc),
if (feedBloc != null) BlocProvider.value(value: feedBloc),
BlocProvider.value(value: thunderBloc),
],
child: ModlogFeedPage(
modlogActionType: modlogActionType,
communityId: communityId,
userId: userId,
moderatorId: moderatorId,
commentId: commentId,
lemmyClient: lemmyClient,
subtitle: subtitle,
),
),
),
Expand Down
51 changes: 45 additions & 6 deletions lib/modlog/view/modlog_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import 'package:thunder/core/enums/font_scale.dart';
import 'package:thunder/core/singletons/lemmy_client.dart';
import 'package:thunder/feed/feed.dart';
import 'package:thunder/modlog/modlog.dart';
import 'package:thunder/shared/full_name_widgets.dart';
import 'package:thunder/shared/snackbar.dart';
import 'package:thunder/shared/text/scalable_text.dart';
import 'package:thunder/thunder/bloc/thunder_bloc.dart';
import 'package:thunder/utils/instance.dart';

/// Creates a [ModlogPage] which holds a list of modlog events.
class ModlogFeedPage extends StatefulWidget {
Expand All @@ -23,6 +25,8 @@ class ModlogFeedPage extends StatefulWidget {
this.userId,
this.moderatorId,
this.lemmyClient,
this.subtitle,
this.commentId,
});

/// The filtering to be applied to the feed.
Expand All @@ -37,9 +41,16 @@ class ModlogFeedPage extends StatefulWidget {
/// The id of the moderator to display modlog events for.
final int? moderatorId;

/// The id of a specific comment to show in the modlog (optional)
final int? commentId;

/// An optional lemmy client to use a different instance and override the singleton
final LemmyClient? lemmyClient;

/// An optional widget to display as the subtitle on the app bar.
/// If not specified, this will be the instance or community name.
final Widget? subtitle;

@override
State<ModlogFeedPage> createState() => _ModlogFeedPageState();
}
Expand All @@ -54,9 +65,10 @@ class _ModlogFeedPageState extends State<ModlogFeedPage> {
communityId: widget.communityId,
userId: widget.userId,
moderatorId: widget.moderatorId,
commentId: widget.commentId,
reset: true,
)),
child: ModlogFeedView(lemmyClient: widget.lemmyClient ?? LemmyClient.instance),
child: ModlogFeedView(lemmyClient: widget.lemmyClient ?? LemmyClient.instance, subtitle: widget.subtitle),
);
}
}
Expand All @@ -65,7 +77,10 @@ class ModlogFeedView extends StatefulWidget {
/// The current Lemmy client
final LemmyClient lemmyClient;

const ModlogFeedView({super.key, required this.lemmyClient});
/// Subtitle to display on app bar
final Widget? subtitle;

const ModlogFeedView({super.key, required this.lemmyClient, required this.subtitle});

@override
State<ModlogFeedView> createState() => _ModlogFeedViewState();
Expand Down Expand Up @@ -130,6 +145,25 @@ class _ModlogFeedViewState extends State<ModlogFeedView> {
final thunderState = context.watch<ThunderBloc>().state;
final l10n = AppLocalizations.of(context)!;

Widget? subtitle = widget.subtitle;

if (subtitle == null) {
try {
FeedState feedState = context.read<FeedBloc>().state;

subtitle = feedState.fullCommunityView != null
? CommunityFullNameWidget(
context,
feedState.fullCommunityView!.communityView.community.name,
feedState.fullCommunityView!.communityView.community.title,
fetchInstanceNameFromUrl(feedState.fullCommunityView!.communityView.community.actorId),
)
: Text(widget.lemmyClient.lemmyApiV3.host);
} catch (e) {
// Ignore if we can't get the FeedBloc from this context
}
}

return Scaffold(
body: SafeArea(
top: thunderState.hideTopBarOnScroll, // Don't apply to top of screen to allow for the status bar colour to extend
Expand Down Expand Up @@ -163,9 +197,14 @@ class _ModlogFeedViewState extends State<ModlogFeedView> {
return RefreshIndicator(
onRefresh: () async {
HapticFeedback.mediumImpact();
context
.read<ModlogBloc>()
.add(ModlogFeedFetchedEvent(modlogActionType: state.modlogActionType, communityId: state.communityId, userId: state.userId, moderatorId: state.moderatorId, reset: true));
context.read<ModlogBloc>().add(ModlogFeedFetchedEvent(
modlogActionType: state.modlogActionType,
communityId: state.communityId,
userId: state.userId,
moderatorId: state.moderatorId,
commentId: state.commentId,
reset: true,
));
},
edgeOffset: 95.0, // This offset is placed to allow the correct positioning of the refresh indicator
child: Stack(
Expand All @@ -175,7 +214,7 @@ class _ModlogFeedViewState extends State<ModlogFeedView> {
slivers: <Widget>[
ModlogFeedPageAppBar(
showAppBarTitle: state.status != ModlogStatus.initial ? true : showAppBarTitle,
lemmyClient: widget.lemmyClient,
subtitle: subtitle,
),
// Display loading indicator until the feed is fetched
if (state.status == ModlogStatus.initial)
Expand Down
33 changes: 12 additions & 21 deletions lib/modlog/widgets/modlog_feed_page_app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,19 @@ import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import 'package:thunder/core/singletons/lemmy_client.dart';
import 'package:thunder/feed/bloc/feed_bloc.dart';
import 'package:thunder/modlog/bloc/modlog_bloc.dart';
import 'package:thunder/modlog/widgets/modlog_filter_picker.dart';
import 'package:thunder/shared/full_name_widgets.dart';
import 'package:thunder/thunder/bloc/thunder_bloc.dart';
import 'package:thunder/utils/instance.dart';

/// The app bar for the modlog feed page
class ModlogFeedPageAppBar extends StatelessWidget {
const ModlogFeedPageAppBar({super.key, required this.showAppBarTitle, required this.lemmyClient});
const ModlogFeedPageAppBar({super.key, required this.showAppBarTitle, required this.subtitle});

/// Boolean which indicates whether the title on the app bar should be shown
final bool showAppBarTitle;

/// The current Lemmy client
final LemmyClient lemmyClient;
/// The subtitle to display below "Modlog" on the app bar
final Widget? subtitle;

@override
Widget build(BuildContext context) {
Expand All @@ -35,7 +31,7 @@ class ModlogFeedPageAppBar extends StatelessWidget {
centerTitle: false,
toolbarHeight: 70.0,
surfaceTintColor: state.hideTopBarOnScroll ? Colors.transparent : null,
title: ModlogFeedAppBarTitle(visible: showAppBarTitle, lemmyClient: lemmyClient),
title: ModlogFeedAppBarTitle(visible: showAppBarTitle, subtitle: subtitle),
leading: IconButton(
icon: (!kIsWeb && Platform.isIOS
? Icon(
Expand Down Expand Up @@ -75,21 +71,23 @@ class ModlogFeedPageAppBar extends StatelessWidget {
}

class ModlogFeedAppBarTitle extends StatelessWidget {
const ModlogFeedAppBarTitle({super.key, this.visible = true, required this.lemmyClient});
const ModlogFeedAppBarTitle({
super.key,
this.visible = true,
required this.subtitle,
});

/// Boolean which indicates whether the title on the app bar should be shown
final bool visible;

/// The current Lemmy client
final LemmyClient lemmyClient;
/// The subtitle to display below "Modlog" on the app bar
final Widget? subtitle;

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final l10n = AppLocalizations.of(context)!;

final feedState = context.read<FeedBloc>().state;

return AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: visible ? 1.0 : 0.0,
Expand All @@ -100,14 +98,7 @@ class ModlogFeedAppBarTitle extends StatelessWidget {
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: feedState.fullCommunityView != null
? CommunityFullNameWidget(
context,
feedState.fullCommunityView!.communityView.community.name,
feedState.fullCommunityView!.communityView.community.title,
fetchInstanceNameFromUrl(feedState.fullCommunityView!.communityView.community.actorId),
)
: Text(lemmyClient.lemmyApiV3.host),
subtitle: subtitle,
contentPadding: const EdgeInsets.symmetric(horizontal: 0),
),
);
Expand Down
Loading

0 comments on commit fd2b972

Please sign in to comment.