diff --git a/web/src/icons/door-open.svg b/web/src/icons/door-open.svg
new file mode 100644
index 0000000..d4a5719
--- /dev/null
+++ b/web/src/icons/door-open.svg
@@ -0,0 +1 @@
+
diff --git a/web/src/icons/mark-read.svg b/web/src/icons/mark-read.svg
new file mode 100644
index 0000000..3819d33
--- /dev/null
+++ b/web/src/icons/mark-read.svg
@@ -0,0 +1 @@
+
diff --git a/web/src/icons/mark-unread.svg b/web/src/icons/mark-unread.svg
new file mode 100644
index 0000000..2228f31
--- /dev/null
+++ b/web/src/icons/mark-unread.svg
@@ -0,0 +1 @@
+
diff --git a/web/src/ui/menu/RoomMenu.tsx b/web/src/ui/menu/RoomMenu.tsx
index 6adb172..a0ccd20 100644
--- a/web/src/ui/menu/RoomMenu.tsx
+++ b/web/src/ui/menu/RoomMenu.tsx
@@ -16,9 +16,13 @@
import { CSSProperties, use } from "react"
import { RoomListEntry, RoomStateStore, useAccountData } from "@/api/statestore"
import { RoomID } from "@/api/types"
+import { useEventAsState } from "@/util/eventdispatcher.ts"
import ClientContext from "../ClientContext.ts"
-import { ModalContext } from "../modal"
+import { ModalCloseContext, ModalContext } from "../modal"
import SettingsView from "../settings/SettingsView.tsx"
+import DoorOpenIcon from "@/icons/door-open.svg?react"
+import MarkReadIcon from "@/icons/mark-read.svg?react"
+import MarkUnreadIcon from "@/icons/mark-unread.svg?react"
import NotificationsOffIcon from "@/icons/notifications-off.svg?react"
import NotificationsIcon from "@/icons/notifications.svg?react"
import SettingsIcon from "@/icons/settings.svg?react"
@@ -36,6 +40,7 @@ const hasNotifyingActions = (actions: unknown) => {
const MuteButton = ({ roomID }: { roomID: RoomID }) => {
const client = use(ClientContext)!
+ const closeModal = use(ModalCloseContext)
const roomRules = useAccountData(client.store, "m.push_rules")?.global?.room
const pushRule = Array.isArray(roomRules) ? roomRules.find(rule => rule?.rule_id === roomID) : null
const muted = pushRule?.enabled === true && !hasNotifyingActions(pushRule.actions)
@@ -44,6 +49,7 @@ const MuteButton = ({ roomID }: { roomID: RoomID }) => {
console.error("Failed to mute room", err)
window.alert(`Failed to ${muted ? "unmute" : "mute"} room: ${err}`)
})
+ closeModal()
}
return
}
+const MarkReadButton = ({ room }: { room: RoomStateStore }) => {
+ const meta = useEventAsState(room.meta)
+ const client = use(ClientContext)!
+ const closeModal = use(ModalCloseContext)
+ const read = !meta.marked_unread && meta.unread_messages === 0
+ const markRead = () => {
+ const evt = room.eventsByRowID.get(
+ room.timeline[room.timeline.length-1]?.event_rowid ?? meta.preview_event_rowid,
+ )
+ if (!evt) {
+ window.alert("Can't mark room as read: last event not found in cache")
+ return
+ }
+ const rrType = room.preferences.send_read_receipts ? "m.read" : "m.read.private"
+ client.rpc.markRead(room.roomID, evt.event_id, rrType).catch(err => {
+ console.error("Failed to mark room as read", err)
+ window.alert(`Failed to mark room as read: ${err}`)
+ })
+ closeModal()
+ }
+ const markUnread = () => {
+ client.rpc.setAccountData("m.marked_unread", { unread: true }, room.roomID).catch(err => {
+ console.error("Failed to mark room as unread", err)
+ window.alert(`Failed to mark room as unread: ${err}`)
+ })
+ closeModal()
+ }
+ return
+}
+
export const RoomMenu = ({ room, style }: RoomMenuProps) => {
const openModal = use(ModalContext)
+ const closeModal = use(ModalCloseContext)
+ const client = use(ClientContext)!
const openSettings = () => {
openModal({
dimmed: true,
@@ -61,8 +102,17 @@ export const RoomMenu = ({ room, style }: RoomMenuProps) => {
content: