allow hiding client stickies

Fixes #105
This commit is contained in:
Henry Hiles 2026-10-02 17:00:40 -04:00
commit c409ddcb54
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
6 changed files with 76 additions and 17 deletions

View file

@ -97,6 +97,25 @@ class RoomChatController(final ChatParams info)
),
);
void hideClientSticky(int eventRowId) => ref
.read(RoomsController.provider.notifier)
.update(
.new({
info.roomId: Room(
resetClientSticky: true,
clientSticky:
ref
.read(
RoomsController.provider.select(
(rooms) => rooms[info.roomId]?.clientSticky,
),
)
?.remove(eventRowId) ??
.new(),
),
}),
);
Future<void> paginate(Direction direction) async {
if (state.isLoading) return;

View file

@ -46,13 +46,16 @@ class RoomsController extends Notifier<IMap<String, Room>> {
roomId,
existing?.copyWith(
hasMore: incoming.hasMore,
clientSticky:
(incoming.clientSticky.isEmpty == true
? existing.clientSticky
: existing.clientSticky.addAll(incoming.clientSticky))
.removeWhere(
(rowId) => incoming.timeline.values.contains(rowId),
),
clientSticky: incoming.resetClientSticky
? incoming.clientSticky
: (incoming.clientSticky.isEmpty == true
? existing.clientSticky
: existing.clientSticky.addAll(
incoming.clientSticky,
))
.removeWhere(
(rowId) => incoming.timeline.values.contains(rowId),
),
metadata: incoming.metadata ?? existing.metadata,
events: incoming.events.isEmpty
? existing.events
@ -64,6 +67,7 @@ class RoomsController extends Notifier<IMap<String, Room>> {
(previousValue[event.key] ?? .new()).addAll(event.value),
),
),
resetClientSticky: false,
reset: false,
hasFetchedMembers:
incoming.hasFetchedMembers || existing.hasFetchedMembers,

View file

@ -225,10 +225,11 @@ extension BuildEventOptions on Event {
),
if (ref.watch(
PowerLevelController.provider(
.redaction(targetUser: sender, roomId: roomId),
),
))
PowerLevelController.provider(
.redaction(targetUser: sender, roomId: roomId),
),
) &&
!eventId.startsWith("~"))
PopupMenuItem(
onTap: () => showReasonDialog(
title: "Delete Message",
@ -245,6 +246,15 @@ extension BuildEventOptions on Event {
),
),
if (eventId.startsWith("~"))
PopupMenuItem(
onTap: () => ref.watch(notifier).hideClientSticky(rowId),
child: ListTile(
leading: Icon(Icons.delete, color: danger),
title: Text("Hide", style: .new(color: danger)),
),
),
PopupMenuItem(
onTap: () => showReasonDialog(
title: "Report",

View file

@ -25,6 +25,8 @@ class const Room({
final IMap<int, Event> events = const IMap.empty(),
final bool reset = false,
@JsonKey(includeFromJson: false, includeToJson: false)
final bool resetClientSticky = false,
@JsonKey(includeFromJson: false, includeToJson: false)
final bool hasFetchedState = false,

View file

@ -134,7 +134,7 @@ class const Composer(
child: Row(
mainAxisAlignment: .center,
children:
ref.watch(
!ref.watch(
PowerLevelController.provider(
.new(eventType: .message, roomId: roomId),
),

View file

@ -4,6 +4,7 @@ import "package:material_ui/material_ui.dart";
import "package:flutter_hooks/flutter_hooks.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:nexus/controllers/event.dart";
import "package:nexus/controllers/room_chat.dart";
import "package:nexus/controllers/rooms.dart";
import "package:nexus/helpers/extensions/show_context_menu.dart";
import "package:nexus/helpers/hooks/chat_scroll.dart";
@ -270,11 +271,34 @@ class const EventRenderer(
if (event.sendError != null && event.sendError != "not sent")
Padding(
padding: .only(bottom: 4),
child: Text(
event.sendError!,
style: theme.textTheme.labelSmall?.copyWith(
color: theme.colorScheme.error,
),
child: Row(
spacing: 4,
children: [
Text(
event.sendError!,
style: theme.textTheme.labelSmall?.copyWith(
color: theme.colorScheme.error,
),
),
InkWell(
child: Text(
"Hide",
style: theme.textTheme.labelSmall?.copyWith(
color: theme.colorScheme.primary,
decoration: .underline,
decorationColor: theme.colorScheme.primary,
),
),
onTap: () => ref
.read(
RoomChatController.provider((
roomId: roomId,
contextualEvent: null,
)).notifier,
)
.hideClientSticky(event.rowId),
),
],
),
),
].map((child) => Padding(padding: .only(left: 4), child: child)),