Support for pinned messages #49
6 changed files with 94 additions and 13 deletions
Added a context menu entry for pinning/unpinning
; We can now also send the state event via the setState call.
commit
135be17555
|
|
@ -94,9 +94,9 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
|
|||
- [x] Editing
|
||||
- [x] Deleting
|
||||
- [x] Reactions
|
||||
- [ ] Pins
|
||||
- [ ] Displaying
|
||||
- [ ] Creating
|
||||
- [x] Pins
|
||||
- [x] Displaying
|
||||
- [x] Creating
|
||||
- [ ] Threads
|
||||
- [x] Profile popouts
|
||||
- [x] Working actions
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import "package:nexus/models/requests/report_request.dart";
|
|||
import "package:nexus/models/requests/send_event_request.dart";
|
||||
import "package:nexus/models/requests/send_message_request.dart";
|
||||
import "package:nexus/models/requests/set_membership_request.dart";
|
||||
import "package:nexus/models/requests/set_state_request.dart";
|
||||
import "package:nexus/models/room.dart";
|
||||
import "package:nexus/models/sync_data.dart";
|
||||
import "package:nexus/src/third_party/gomuks.g.dart";
|
||||
|
|
@ -172,6 +173,9 @@ class ClientController extends AsyncNotifier<int> {
|
|||
Future<Event> sendEvent(SendEventRequest request) async =>
|
||||
Event.fromJson(await _sendCommand("send_event", request.toJson()));
|
||||
|
||||
Future<Event> setState(SetStateRequest request) async =>
|
||||
Event.fromJson(await _sendCommand("set_state", request.toJson()));
|
||||
|
||||
Future<String?> verify(String recoveryKey) async {
|
||||
try {
|
||||
await _sendCommand("verify", {"recovery_key": recoveryKey});
|
||||
|
|
|
|||
|
|
@ -41,22 +41,49 @@ class PinnedEventsController extends AsyncNotifier<IList<Event>> {
|
|||
return .new();
|
||||
}
|
||||
|
||||
Future<void> togglePin(Event event) async {
|
||||
Future<void> addPin(Event event) async {
|
||||
final client = ref.read(ClientController.provider.notifier);
|
||||
final current = await future;
|
||||
|
||||
final updatedPinnedIds = current.any((e) => e.eventId == event.eventId)
|
||||
? current
|
||||
.where((e) => e.eventId != event.eventId)
|
||||
.map((e) => e.eventId)
|
||||
.toList()
|
||||
: [...current.map((e) => e.eventId), event.eventId];
|
||||
if (current.any((ev) => ev.eventId == event.eventId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await client.sendEvent(
|
||||
final updatedPinnedIds = [
|
||||
...current.map((ev) => ev.eventId),
|
||||
event.eventId,
|
||||
];
|
||||
|
||||
await client.setState(
|
||||
.new(
|
||||
roomId: roomId,
|
||||
type: EventType.pinnedEvents.type,
|
||||
stateKey: "",
|
||||
stateKey:
|
||||
"", //The empty string stands for m.room.pinned_events according to matrix spec.
|
||||
content: {"pinned": updatedPinnedIds},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> removePin(Event event) async {
|
||||
final client = ref.read(ClientController.provider.notifier);
|
||||
final current = await future;
|
||||
|
||||
if (!current.any((ev) => ev.eventId == event.eventId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final updatedPinnedIds = [
|
||||
...current
|
||||
.where((ev) => ev.eventId != event.eventId)
|
||||
.map((ev) => ev.eventId),
|
||||
];
|
||||
|
||||
await client.setState(
|
||||
.new(
|
||||
roomId: roomId,
|
||||
type: EventType.pinnedEvents.type,
|
||||
stateKey: "", //The empty string stands for m.room.pinned_events according to matrix spec.
|
||||
content: {"pinned": updatedPinnedIds},
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ abstract class SendEventRequest with _$SendEventRequest {
|
|||
required String roomId,
|
||||
required String type,
|
||||
required Map<String, dynamic> content,
|
||||
@Default(null) String? stateKey,
|
||||
@Default(false) bool synchronous,
|
||||
@Default(false) bool disableEncryption,
|
||||
}) = _SendEventRequest;
|
||||
|
|
|
|||
17
lib/models/requests/set_state_request.dart
Normal file
17
lib/models/requests/set_state_request.dart
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import "package:freezed_annotation/freezed_annotation.dart";
|
||||
part "set_state_request.freezed.dart";
|
||||
part "set_state_request.g.dart";
|
||||
|
||||
@freezed
|
||||
abstract class SetStateRequest with _$SetStateRequest {
|
||||
const factory SetStateRequest({
|
||||
required String roomId,
|
||||
required String type,
|
||||
required String stateKey,
|
||||
required Map<String, dynamic> content,
|
||||
@Default(0) int delayMs,
|
||||
}) = _SetStateRequest;
|
||||
|
||||
factory SetStateRequest.fromJson(Map<String, Object?> json) =>
|
||||
_$SetStateRequestFromJson(json);
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import "package:measure_size/measure_size.dart";
|
|||
import "package:nexus/controllers/account_data_controller.dart";
|
||||
import "package:nexus/controllers/client_controller.dart";
|
||||
import "package:nexus/controllers/client_state_controller.dart";
|
||||
import "package:nexus/controllers/pinned_events_controller.dart";
|
||||
import "package:nexus/controllers/power_level_controller.dart";
|
||||
import "package:nexus/controllers/rooms_controller.dart";
|
||||
import "package:nexus/controllers/room_chat_controller.dart";
|
||||
|
|
@ -249,6 +250,39 @@ class RoomChat extends HookConsumerWidget {
|
|||
},
|
||||
child: ListTile(leading: Icon(Icons.edit), title: Text("Edit")),
|
||||
),
|
||||
if (ref.watch(
|
||||
PowerLevelController.provider(
|
||||
PowerLevelConfig(eventType: .pinnedEvents, roomId: roomId),
|
||||
),
|
||||
))
|
||||
() {
|
||||
final isPinned = ref
|
||||
.watch(PinnedEventsController.provider(roomId))
|
||||
.maybeWhen(
|
||||
data: (pinnedEvents) =>
|
||||
pinnedEvents.any((ev) => ev.eventId == event.eventId),
|
||||
orElse: () => false,
|
||||
);
|
||||
|
||||
return PopupMenuItem(
|
||||
onTap: () async {
|
||||
final notifier = ref.read(
|
||||
PinnedEventsController.provider(roomId).notifier,
|
||||
);
|
||||
if (isPinned) {
|
||||
await notifier.removePin(event);
|
||||
} else {
|
||||
await notifier.addPin(event);
|
||||
}
|
||||
},
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
isPinned ? Icons.push_pin_outlined : Icons.push_pin,
|
||||
),
|
||||
title: Text(isPinned ? "Unpin Event" : "Pin Event"),
|
||||
),
|
||||
);
|
||||
}(),
|
||||
PopupMenuItem(
|
||||
onTap: () async {
|
||||
final room = ref.watch(
|
||||
|
|
|
|||
Loading…
Reference in a new issue