Add presence & status message rendering

This commit is contained in:
nexy7574 2024-12-21 22:39:00 +00:00
parent 1ff9ba241a
commit 16ccd3dcfc
No known key found for this signature in database
5 changed files with 55 additions and 1 deletions

View file

@ -86,6 +86,10 @@ func (h *HiClient) handleJSONCommand(ctx context.Context, req *JSONCommand) (any
return unmarshalAndCall(req.Data, func(params *getProfileParams) (*mautrix.RespUserProfile, error) {
return h.Client.GetProfile(ctx, params.UserID)
})
case "get_presence":
return unmarshalAndCall(req.Data, func(params *getProfileParams) (*mautrix.RespPresence, error) {
return h.Client.GetPresence(ctx, params.UserID)
})
case "get_mutual_rooms":
return unmarshalAndCall(req.Data, func(params *getProfileParams) ([]id.RoomID, error) {
return h.GetMutualRooms(ctx, params.UserID)

View file

@ -25,6 +25,7 @@ import type {
Mentions,
MessageEventContent,
PaginationResponse,
Presence,
ProfileEncryptionInfo,
RPCCommand,
RPCEvent,
@ -180,6 +181,10 @@ export default abstract class RPCClient {
return this.request("get_profile", { user_id })
}
getPresence(user_id: UserID): Promise<Presence> {
return this.request("get_presence", { user_id })
}
getMutualRooms(user_id: UserID): Promise<RoomID[]> {
return this.request("get_mutual_rooms", { user_id })
}

View file

@ -68,6 +68,15 @@ export interface UserProfile {
[custom: string]: unknown
}
export type PresenceState = "online" | "offline" | "unavailable"
export interface Presence {
currently_active?: boolean
last_active_ago?: number
presence: PresenceState
status_msg?: string | null
}
export type Membership = "join" | "leave" | "ban" | "invite" | "knock"
export interface MemberEventContent extends UserProfile {

View file

@ -83,6 +83,20 @@ div.right-panel-content.user {
font-family: var(--monospace-font-stack);
}
div.presence {
text-align: center;
font-size: 1.125rem;
}
div.statusmessage {
text-align: center;
font-size: 1rem;
font-style: italic;
/* Wrap words that are so long that they spill out of bounds */
word-wrap: break-word;
}
div.userid, div.displayname {
/* Ensure names aren't too long */
display: -webkit-box;

View file

@ -17,7 +17,7 @@ import { use, useEffect, useState } from "react"
import { PuffLoader } from "react-spinners"
import { getAvatarURL } from "@/api/media.ts"
import { useRoomMember } from "@/api/statestore"
import { MemberEventContent, UserID, UserProfile } from "@/api/types"
import { MemberEventContent, UserID, UserProfile, Presence } from "@/api/types"
import { getLocalpart } from "@/util/validation.ts"
import ClientContext from "../ClientContext.ts"
import { LightboxContext } from "../modal/Lightbox.tsx"
@ -30,6 +30,12 @@ interface UserInfoProps {
userID: UserID
}
const PresenceEmojis = {
online: "🟢",
offline: "⚫",
unavailable: "🔴",
}
const UserInfo = ({ userID }: UserInfoProps) => {
const client = use(ClientContext)!
const roomCtx = use(RoomContext)
@ -37,6 +43,7 @@ const UserInfo = ({ userID }: UserInfoProps) => {
const memberEvt = useRoomMember(client, roomCtx?.store, userID)
const member = (memberEvt?.content ?? null) as MemberEventContent | null
const [globalProfile, setGlobalProfile] = useState<UserProfile | null>(null)
const [presence, setPresence] = useState<Presence>({ presence: "offline"})
const [errors, setErrors] = useState<string[] | null>(null)
useEffect(() => {
setErrors(null)
@ -45,6 +52,10 @@ const UserInfo = ({ userID }: UserInfoProps) => {
setGlobalProfile,
err => setErrors([`${err}`]),
)
client.rpc.getPresence(userID).then(
setPresence,
err => setErrors([`${err}`]),
)
}, [roomCtx, userID, client])
const displayname = member?.displayname || globalProfile?.displayname || getLocalpart(userID)
@ -63,6 +74,17 @@ const UserInfo = ({ userID }: UserInfoProps) => {
</div>
<div className="displayname" title={displayname}>{displayname}</div>
<div className="userid" title={userID}>{userID}</div>
{presence && (
<>
<div className="presence" title={presence.presence}>{PresenceEmojis[presence.presence]} {presence.presence}</div>
{
presence.status_msg?.length && (
<div className="statusmessage" title={"Status message"}><blockquote>{presence.status_msg}</blockquote></div>
)
}
</>
)
}
<hr/>
{userID !== client.userID && <>
<MutualRooms client={client} userID={userID}/>