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 unmarshalAndCall(req.Data, func(params *getProfileParams) (*mautrix.RespUserProfile, error) {
|
||||||
return h.Client.GetProfile(ctx, params.UserID)
|
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":
|
case "get_mutual_rooms":
|
||||||
return unmarshalAndCall(req.Data, func(params *getProfileParams) ([]id.RoomID, error) {
|
return unmarshalAndCall(req.Data, func(params *getProfileParams) ([]id.RoomID, error) {
|
||||||
return h.GetMutualRooms(ctx, params.UserID)
|
return h.GetMutualRooms(ctx, params.UserID)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import type {
|
||||||
Mentions,
|
Mentions,
|
||||||
MessageEventContent,
|
MessageEventContent,
|
||||||
PaginationResponse,
|
PaginationResponse,
|
||||||
|
Presence,
|
||||||
ProfileEncryptionInfo,
|
ProfileEncryptionInfo,
|
||||||
RPCCommand,
|
RPCCommand,
|
||||||
RPCEvent,
|
RPCEvent,
|
||||||
|
@ -180,6 +181,10 @@ export default abstract class RPCClient {
|
||||||
return this.request("get_profile", { user_id })
|
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[]> {
|
getMutualRooms(user_id: UserID): Promise<RoomID[]> {
|
||||||
return this.request("get_mutual_rooms", { user_id })
|
return this.request("get_mutual_rooms", { user_id })
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,15 @@ export interface UserProfile {
|
||||||
[custom: string]: unknown
|
[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 type Membership = "join" | "leave" | "ban" | "invite" | "knock"
|
||||||
|
|
||||||
export interface MemberEventContent extends UserProfile {
|
export interface MemberEventContent extends UserProfile {
|
||||||
|
|
|
@ -83,6 +83,20 @@ div.right-panel-content.user {
|
||||||
font-family: var(--monospace-font-stack);
|
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 {
|
div.userid, div.displayname {
|
||||||
/* Ensure names aren't too long */
|
/* Ensure names aren't too long */
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { use, useEffect, useState } from "react"
|
||||||
import { PuffLoader } from "react-spinners"
|
import { PuffLoader } from "react-spinners"
|
||||||
import { getAvatarURL } from "@/api/media.ts"
|
import { getAvatarURL } from "@/api/media.ts"
|
||||||
import { useRoomMember } from "@/api/statestore"
|
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 { getLocalpart } from "@/util/validation.ts"
|
||||||
import ClientContext from "../ClientContext.ts"
|
import ClientContext from "../ClientContext.ts"
|
||||||
import { LightboxContext } from "../modal/Lightbox.tsx"
|
import { LightboxContext } from "../modal/Lightbox.tsx"
|
||||||
|
@ -30,6 +30,12 @@ interface UserInfoProps {
|
||||||
userID: UserID
|
userID: UserID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PresenceEmojis = {
|
||||||
|
online: "🟢",
|
||||||
|
offline: "⚫",
|
||||||
|
unavailable: "🔴",
|
||||||
|
}
|
||||||
|
|
||||||
const UserInfo = ({ userID }: UserInfoProps) => {
|
const UserInfo = ({ userID }: UserInfoProps) => {
|
||||||
const client = use(ClientContext)!
|
const client = use(ClientContext)!
|
||||||
const roomCtx = use(RoomContext)
|
const roomCtx = use(RoomContext)
|
||||||
|
@ -37,6 +43,7 @@ const UserInfo = ({ userID }: UserInfoProps) => {
|
||||||
const memberEvt = useRoomMember(client, roomCtx?.store, userID)
|
const memberEvt = useRoomMember(client, roomCtx?.store, userID)
|
||||||
const member = (memberEvt?.content ?? null) as MemberEventContent | null
|
const member = (memberEvt?.content ?? null) as MemberEventContent | null
|
||||||
const [globalProfile, setGlobalProfile] = useState<UserProfile | null>(null)
|
const [globalProfile, setGlobalProfile] = useState<UserProfile | null>(null)
|
||||||
|
const [presence, setPresence] = useState<Presence>({ presence: "offline"})
|
||||||
const [errors, setErrors] = useState<string[] | null>(null)
|
const [errors, setErrors] = useState<string[] | null>(null)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setErrors(null)
|
setErrors(null)
|
||||||
|
@ -45,6 +52,10 @@ const UserInfo = ({ userID }: UserInfoProps) => {
|
||||||
setGlobalProfile,
|
setGlobalProfile,
|
||||||
err => setErrors([`${err}`]),
|
err => setErrors([`${err}`]),
|
||||||
)
|
)
|
||||||
|
client.rpc.getPresence(userID).then(
|
||||||
|
setPresence,
|
||||||
|
err => setErrors([`${err}`]),
|
||||||
|
)
|
||||||
}, [roomCtx, userID, client])
|
}, [roomCtx, userID, client])
|
||||||
|
|
||||||
const displayname = member?.displayname || globalProfile?.displayname || getLocalpart(userID)
|
const displayname = member?.displayname || globalProfile?.displayname || getLocalpart(userID)
|
||||||
|
@ -63,6 +74,17 @@ const UserInfo = ({ userID }: UserInfoProps) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="displayname" title={displayname}>{displayname}</div>
|
<div className="displayname" title={displayname}>{displayname}</div>
|
||||||
<div className="userid" title={userID}>{userID}</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/>
|
<hr/>
|
||||||
{userID !== client.userID && <>
|
{userID !== client.userID && <>
|
||||||
<MutualRooms client={client} userID={userID}/>
|
<MutualRooms client={client} userID={userID}/>
|
||||||
|
|
Loading…
Add table
Reference in a new issue