mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-19 18:13:41 -05:00
Add presence & status message rendering
This commit is contained in:
parent
1ff9ba241a
commit
16ccd3dcfc
5 changed files with 55 additions and 1 deletions
|
@ -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)
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}/>
|
||||
|
|
Loading…
Add table
Reference in a new issue