Introduce online status broadcast (#99)
This commit is contained in:
parent
f957aa76cf
commit
7c3f256e61
|
@ -1,4 +1,4 @@
|
||||||
import { lightTheme, ReactChat } from "@dappconnect/react-chat";
|
import { darkTheme, lightTheme, ReactChat } from "@dappconnect/react-chat";
|
||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
@ -32,6 +32,8 @@ function DragDiv() {
|
||||||
const moved = useRef(false);
|
const moved = useRef(false);
|
||||||
const setting = useRef("");
|
const setting = useRef("");
|
||||||
|
|
||||||
|
const [theme, setTheme] = useState(true);
|
||||||
|
|
||||||
const onMouseMove = (e: MouseEvent) => {
|
const onMouseMove = (e: MouseEvent) => {
|
||||||
if (setting.current === "position") {
|
if (setting.current === "position") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -54,33 +56,42 @@ function DragDiv() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drag style={{ left: x, top: y, width: width, height: height }} ref={ref}>
|
<>
|
||||||
<Bubble
|
<button
|
||||||
onMouseDown={() => {
|
onClick={() => {
|
||||||
setting.current = "position";
|
setTheme(!theme);
|
||||||
document.addEventListener("mousemove", onMouseMove);
|
|
||||||
document.addEventListener("mouseup", onMouseUp);
|
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
<FloatingDiv className={showChat ? "" : "hide"}>
|
Change theme
|
||||||
<ReactChat
|
</button>
|
||||||
theme={lightTheme}
|
<Drag style={{ left: x, top: y, width: width, height: height }} ref={ref}>
|
||||||
communityKey={
|
<Bubble
|
||||||
"0x0262c65c881f5a9f79343a26faaa02aad3af7c533d9445fb1939ed11b8bf4d2abd"
|
|
||||||
}
|
|
||||||
fetchMetadata={fetchMetadata}
|
|
||||||
/>
|
|
||||||
</FloatingDiv>
|
|
||||||
{showChat && (
|
|
||||||
<SizeSet
|
|
||||||
onMouseDown={() => {
|
onMouseDown={() => {
|
||||||
setting.current = "size";
|
setting.current = "position";
|
||||||
document.addEventListener("mousemove", onMouseMove);
|
document.addEventListener("mousemove", onMouseMove);
|
||||||
document.addEventListener("mouseup", onMouseUp);
|
document.addEventListener("mouseup", onMouseUp);
|
||||||
}}
|
}}
|
||||||
></SizeSet>
|
/>
|
||||||
)}
|
<FloatingDiv className={showChat ? "" : "hide"}>
|
||||||
</Drag>
|
<ReactChat
|
||||||
|
theme={theme ? lightTheme : darkTheme}
|
||||||
|
communityKey={
|
||||||
|
"0x0262c65c881f5a9f79343a26faaa02aad3af7c533d9445fb1939ed11b8bf4d2abd"
|
||||||
|
}
|
||||||
|
fetchMetadata={fetchMetadata}
|
||||||
|
/>
|
||||||
|
</FloatingDiv>
|
||||||
|
{showChat && (
|
||||||
|
<SizeSet
|
||||||
|
onMouseDown={() => {
|
||||||
|
setting.current = "size";
|
||||||
|
document.addEventListener("mousemove", onMouseMove);
|
||||||
|
document.addEventListener("mouseup", onMouseUp);
|
||||||
|
}}
|
||||||
|
></SizeSet>
|
||||||
|
)}
|
||||||
|
</Drag>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ export function Chat({
|
||||||
loadPrevDay,
|
loadPrevDay,
|
||||||
loadingMessages,
|
loadingMessages,
|
||||||
community,
|
community,
|
||||||
|
contacts,
|
||||||
} = useMessenger(activeChannel?.id ?? "", communityKey, identity);
|
} = useMessenger(activeChannel?.id ?? "", communityKey, identity);
|
||||||
|
|
||||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||||
|
@ -68,14 +69,7 @@ export function Chat({
|
||||||
description: community.description.identity?.description ?? "",
|
description: community.description.identity?.description ?? "",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return undefined;
|
||||||
id: 1,
|
|
||||||
name: "",
|
|
||||||
icon: "",
|
|
||||||
members: 0,
|
|
||||||
membersList: [],
|
|
||||||
description: "",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}, [community]);
|
}, [community]);
|
||||||
|
|
||||||
|
@ -101,7 +95,7 @@ export function Chat({
|
||||||
<ChatWrapper>
|
<ChatWrapper>
|
||||||
{showChannels && !narrow && (
|
{showChannels && !narrow && (
|
||||||
<ChannelsWrapper>
|
<ChannelsWrapper>
|
||||||
{messenger ? (
|
{community && communityData ? (
|
||||||
<StyledCommunity onClick={showModal} community={communityData} />
|
<StyledCommunity onClick={showModal} community={communityData} />
|
||||||
) : (
|
) : (
|
||||||
<CommunitySkeleton />
|
<CommunitySkeleton />
|
||||||
|
@ -117,6 +111,8 @@ export function Chat({
|
||||||
</ChannelsWrapper>
|
</ChannelsWrapper>
|
||||||
)}
|
)}
|
||||||
<ChatBody
|
<ChatBody
|
||||||
|
identity={identity}
|
||||||
|
contacts={contacts}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
channel={activeChannel}
|
channel={activeChannel}
|
||||||
messenger={messenger}
|
messenger={messenger}
|
||||||
|
@ -140,20 +136,23 @@ export function Chat({
|
||||||
/>
|
/>
|
||||||
{showMembers && !narrow && (
|
{showMembers && !narrow && (
|
||||||
<Members
|
<Members
|
||||||
community={communityData}
|
identity={identity}
|
||||||
|
contacts={contacts}
|
||||||
setShowChannels={setShowChannels}
|
setShowChannels={setShowChannels}
|
||||||
setMembersList={setMembersList}
|
setMembersList={setMembersList}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<CommunityModal
|
{communityData && (
|
||||||
isVisible={isModalVisible}
|
<CommunityModal
|
||||||
onClose={() => setIsModalVisible(false)}
|
isVisible={isModalVisible}
|
||||||
icon={communityData.icon}
|
onClose={() => setIsModalVisible(false)}
|
||||||
name={communityData.name}
|
icon={communityData.icon}
|
||||||
subtitle="Public Community"
|
name={communityData.name}
|
||||||
description={communityData.description}
|
subtitle="Public Community"
|
||||||
publicKey={communityKey}
|
description={communityData.description}
|
||||||
/>
|
publicKey={communityKey}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</ChatWrapper>
|
</ChatWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
import { Identity } from "status-communities/dist/cjs";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { useNarrow } from "../../contexts/narrowProvider";
|
import { useNarrow } from "../../contexts/narrowProvider";
|
||||||
import { ChannelData } from "../../models/ChannelData";
|
import { ChannelData } from "../../models/ChannelData";
|
||||||
import { ChatMessage } from "../../models/ChatMessage";
|
import { ChatMessage } from "../../models/ChatMessage";
|
||||||
import { CommunityData } from "../../models/CommunityData";
|
import { CommunityData } from "../../models/CommunityData";
|
||||||
|
import { Contact } from "../../models/Contact";
|
||||||
import { Metadata } from "../../models/Metadata";
|
import { Metadata } from "../../models/Metadata";
|
||||||
import { Theme } from "../../styles/themes";
|
import { Theme } from "../../styles/themes";
|
||||||
import { Channel } from "../Channels/Channel";
|
import { Channel } from "../Channels/Channel";
|
||||||
|
@ -21,9 +23,11 @@ import { ChatInput } from "./ChatInput";
|
||||||
import { ChatMessages } from "./ChatMessages";
|
import { ChatMessages } from "./ChatMessages";
|
||||||
|
|
||||||
interface ChatBodyProps {
|
interface ChatBodyProps {
|
||||||
|
identity: Identity;
|
||||||
|
contacts: Contact[];
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
channel: ChannelData;
|
channel: ChannelData;
|
||||||
community: CommunityData;
|
community: CommunityData | undefined;
|
||||||
messenger: any;
|
messenger: any;
|
||||||
messages: ChatMessage[];
|
messages: ChatMessage[];
|
||||||
sendMessage: (text: string, image?: Uint8Array) => void;
|
sendMessage: (text: string, image?: Uint8Array) => void;
|
||||||
|
@ -44,6 +48,8 @@ interface ChatBodyProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChatBody({
|
export function ChatBody({
|
||||||
|
identity,
|
||||||
|
contacts,
|
||||||
theme,
|
theme,
|
||||||
channel,
|
channel,
|
||||||
community,
|
community,
|
||||||
|
@ -95,7 +101,7 @@ export function ChatBody({
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ChannelWrapper className={className}>
|
<ChannelWrapper className={className}>
|
||||||
{messenger ? (
|
{messenger && community ? (
|
||||||
<>
|
<>
|
||||||
{(showCommunity || narrow) && (
|
{(showCommunity || narrow) && (
|
||||||
<CommunityWrap className={className}>
|
<CommunityWrap className={className}>
|
||||||
|
@ -125,14 +131,14 @@ export function ChatBody({
|
||||||
>
|
>
|
||||||
<MembersIcon />
|
<MembersIcon />
|
||||||
</MemberBtn>
|
</MemberBtn>
|
||||||
{!messenger && <Loading />}
|
{!community && <Loading />}
|
||||||
</ChatTopbar>
|
</ChatTopbar>
|
||||||
{messenger ? (
|
{messenger && community ? (
|
||||||
<>
|
<>
|
||||||
{!showChannelsList && !showMembersList && (
|
{!showChannelsList && !showMembersList && (
|
||||||
<>
|
<>
|
||||||
{messages.length > 0 ? (
|
{messages.length > 0 ? (
|
||||||
messenger ? (
|
messenger && community ? (
|
||||||
<ChatMessages
|
<ChatMessages
|
||||||
messages={messages}
|
messages={messages}
|
||||||
loadPrevDay={loadPrevDay}
|
loadPrevDay={loadPrevDay}
|
||||||
|
@ -163,6 +169,8 @@ export function ChatBody({
|
||||||
)}
|
)}
|
||||||
{showMembersList && narrow && (
|
{showMembersList && narrow && (
|
||||||
<NarrowMembers
|
<NarrowMembers
|
||||||
|
identity={identity}
|
||||||
|
contacts={contacts}
|
||||||
community={community}
|
community={community}
|
||||||
setShowChannels={setShowChannelsList}
|
setShowChannels={setShowChannelsList}
|
||||||
setShowMembersList={setShowMembersList}
|
setShowMembersList={setShowMembersList}
|
||||||
|
|
|
@ -23,6 +23,7 @@ export function ChatInput({ theme, addMessage }: ChatInputProps) {
|
||||||
const [inputHeight, setInputHeight] = useState(40);
|
const [inputHeight, setInputHeight] = useState(40);
|
||||||
const [imageUint, setImageUint] = useState<undefined | Uint8Array>(undefined);
|
const [imageUint, setImageUint] = useState<undefined | Uint8Array>(undefined);
|
||||||
const [showSizeLimit, setShowSizeLimit] = useState(false);
|
const [showSizeLimit, setShowSizeLimit] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.addEventListener("click", () => setShowEmoji(false));
|
window.addEventListener("click", () => setShowEmoji(false));
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -127,18 +128,17 @@ export function ChatInput({ theme, addMessage }: ChatInputProps) {
|
||||||
/>
|
/>
|
||||||
</AddPictureInputWrapper>
|
</AddPictureInputWrapper>
|
||||||
<Row style={{ height: `${inputHeight + (image ? 73 : 0)}px` }}>
|
<Row style={{ height: `${inputHeight + (image ? 73 : 0)}px` }}>
|
||||||
{image && (
|
<InputWrapper>
|
||||||
<ImagePreviewWrapper>
|
{image && (
|
||||||
<ImagePreviewOverlay />
|
|
||||||
<ImagePreview src={image} onClick={() => setImageUint(undefined)} />
|
<ImagePreview src={image} onClick={() => setImageUint(undefined)} />
|
||||||
</ImagePreviewWrapper>
|
)}
|
||||||
)}
|
<Input
|
||||||
<Input
|
placeholder="Message"
|
||||||
placeholder="Message"
|
value={content}
|
||||||
value={content}
|
onChange={onInputChange}
|
||||||
onChange={onInputChange}
|
onKeyPress={onInputKeyPress}
|
||||||
onKeyPress={onInputKeyPress}
|
/>
|
||||||
/>
|
</InputWrapper>
|
||||||
<InputButtons>
|
<InputButtons>
|
||||||
<ChatButton
|
<ChatButton
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
@ -160,6 +160,12 @@ export function ChatInput({ theme, addMessage }: ChatInputProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InputWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
const View = styled.div`
|
const View = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -187,28 +193,7 @@ const InputButtons = styled.div`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ImagePreviewWrapper = styled.div`
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 82px;
|
|
||||||
z-index: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ImagePreviewOverlay = styled.div`
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: #eef2f5;
|
|
||||||
border-radius: 16px 16px 4px 16px;
|
|
||||||
opacity: 0.9;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ImagePreview = styled.img`
|
const ImagePreview = styled.img`
|
||||||
position: relative;
|
|
||||||
width: 64px;
|
width: 64px;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
border-radius: 16px 16px 4px 16px;
|
border-radius: 16px 16px 4px 16px;
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Identity } from "status-communities/dist/cjs";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { CommunityData } from "../../models/CommunityData";
|
import { Contact } from "../../models/Contact";
|
||||||
|
|
||||||
import { MembersList } from "./MembersList";
|
import { MembersList } from "./MembersList";
|
||||||
|
|
||||||
interface MembersProps {
|
interface MembersProps {
|
||||||
community: CommunityData;
|
identity: Identity;
|
||||||
|
contacts: Contact[];
|
||||||
setShowChannels: (val: boolean) => void;
|
setShowChannels: (val: boolean) => void;
|
||||||
setMembersList: any;
|
setMembersList: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Members({
|
export function Members({
|
||||||
community,
|
identity,
|
||||||
|
contacts,
|
||||||
setShowChannels,
|
setShowChannels,
|
||||||
setMembersList,
|
setMembersList,
|
||||||
}: MembersProps) {
|
}: MembersProps) {
|
||||||
|
@ -20,7 +23,8 @@ export function Members({
|
||||||
<MembersWrapper>
|
<MembersWrapper>
|
||||||
<MemberHeading>Members</MemberHeading>
|
<MemberHeading>Members</MemberHeading>
|
||||||
<MembersList
|
<MembersList
|
||||||
community={community}
|
identity={identity}
|
||||||
|
contacts={contacts}
|
||||||
setShowChannels={setShowChannels}
|
setShowChannels={setShowChannels}
|
||||||
setMembersList={setMembersList}
|
setMembersList={setMembersList}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Identity, utils } from "status-communities/dist/cjs";
|
||||||
|
import { bufToHex } from "status-communities/dist/cjs/utils";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { CommunityData } from "../../models/CommunityData";
|
import { Contact } from "../../models/Contact";
|
||||||
import { UserIcon } from "../Icons/UserIcon";
|
import { UserIcon } from "../Icons/UserIcon";
|
||||||
|
|
||||||
import { Member, MemberData, MemberIcon } from "./Member";
|
import { Member, MemberData, MemberIcon } from "./Member";
|
||||||
|
|
||||||
interface MembersListProps {
|
interface MembersListProps {
|
||||||
community: CommunityData;
|
identity: Identity;
|
||||||
|
contacts: Contact[];
|
||||||
setShowChannels: (val: boolean) => void;
|
setShowChannels: (val: boolean) => void;
|
||||||
setShowMembers?: (val: boolean) => void;
|
setShowMembers?: (val: boolean) => void;
|
||||||
setMembersList: any;
|
setMembersList: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MembersList({
|
export function MembersList({
|
||||||
community,
|
identity,
|
||||||
|
contacts,
|
||||||
setShowChannels,
|
setShowChannels,
|
||||||
setShowMembers,
|
setShowMembers,
|
||||||
setMembersList,
|
setMembersList,
|
||||||
|
@ -27,18 +31,19 @@ export function MembersList({
|
||||||
<MemberIcon>
|
<MemberIcon>
|
||||||
<UserIcon memberView={true} />
|
<UserIcon memberView={true} />
|
||||||
</MemberIcon>
|
</MemberIcon>
|
||||||
<MemberName>Guest564732</MemberName>
|
<MemberName>{utils.bufToHex(identity.publicKey)}</MemberName>
|
||||||
</MemberData>
|
</MemberData>
|
||||||
</MemberCategory>
|
</MemberCategory>
|
||||||
<MemberCategory>
|
<MemberCategory>
|
||||||
<MemberCategoryName>Online</MemberCategoryName>
|
<MemberCategoryName>Online</MemberCategoryName>
|
||||||
{community.membersList
|
{contacts
|
||||||
.filter(() => false)
|
.filter((e) => e.id != bufToHex(identity.publicKey))
|
||||||
.map((member) => (
|
.filter((e) => e.online)
|
||||||
|
.map((contact) => (
|
||||||
<Member
|
<Member
|
||||||
key={member}
|
key={contact.id}
|
||||||
member={member}
|
member={contact.id}
|
||||||
isOnline={false}
|
isOnline={contact.online}
|
||||||
setShowChannels={setShowChannels}
|
setShowChannels={setShowChannels}
|
||||||
setShowMembers={setShowMembers}
|
setShowMembers={setShowMembers}
|
||||||
setMembersList={setMembersList}
|
setMembersList={setMembersList}
|
||||||
|
@ -47,16 +52,19 @@ export function MembersList({
|
||||||
</MemberCategory>
|
</MemberCategory>
|
||||||
<MemberCategory>
|
<MemberCategory>
|
||||||
<MemberCategoryName>Offline</MemberCategoryName>
|
<MemberCategoryName>Offline</MemberCategoryName>
|
||||||
{community.membersList.map((member) => (
|
{contacts
|
||||||
<Member
|
.filter((e) => e.id != bufToHex(identity.publicKey))
|
||||||
key={member}
|
.filter((e) => !e.online)
|
||||||
member={member}
|
.map((contact) => (
|
||||||
isOnline={false}
|
<Member
|
||||||
setShowChannels={setShowChannels}
|
key={contact.id}
|
||||||
setShowMembers={setShowMembers}
|
member={contact.id}
|
||||||
setMembersList={setMembersList}
|
isOnline={contact.online}
|
||||||
/>
|
setShowChannels={setShowChannels}
|
||||||
))}
|
setShowMembers={setShowMembers}
|
||||||
|
setMembersList={setMembersList}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</MemberCategory>
|
</MemberCategory>
|
||||||
</MembersListWrap>
|
</MembersListWrap>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,20 +1,26 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Identity } from "status-communities/dist/cjs";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { CommunityData } from "../../models/CommunityData";
|
import { CommunityData } from "../../models/CommunityData";
|
||||||
|
import { Contact } from "../../models/Contact";
|
||||||
import { MembersList } from "../Members/MembersList";
|
import { MembersList } from "../Members/MembersList";
|
||||||
|
|
||||||
import { NarrowTopbar } from "./NarrowTopbar";
|
import { NarrowTopbar } from "./NarrowTopbar";
|
||||||
|
|
||||||
interface NarrowMembersProps {
|
interface NarrowMembersProps {
|
||||||
|
identity: Identity;
|
||||||
community: CommunityData;
|
community: CommunityData;
|
||||||
|
contacts: Contact[];
|
||||||
setShowChannels: (val: boolean) => void;
|
setShowChannels: (val: boolean) => void;
|
||||||
setShowMembersList: (val: boolean) => void;
|
setShowMembersList: (val: boolean) => void;
|
||||||
setMembersList: any;
|
setMembersList: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NarrowMembers({
|
export function NarrowMembers({
|
||||||
|
identity,
|
||||||
community,
|
community,
|
||||||
|
contacts,
|
||||||
setShowChannels,
|
setShowChannels,
|
||||||
setShowMembersList,
|
setShowMembersList,
|
||||||
setMembersList,
|
setMembersList,
|
||||||
|
@ -23,7 +29,8 @@ export function NarrowMembers({
|
||||||
<ListWrapper>
|
<ListWrapper>
|
||||||
<NarrowTopbar list="Community members" community={community.name} />
|
<NarrowTopbar list="Community members" community={community.name} />
|
||||||
<MembersList
|
<MembersList
|
||||||
community={community}
|
identity={identity}
|
||||||
|
contacts={contacts}
|
||||||
setShowChannels={setShowChannels}
|
setShowChannels={setShowChannels}
|
||||||
setShowMembers={setShowMembersList}
|
setShowMembers={setShowMembersList}
|
||||||
setMembersList={setMembersList}
|
setMembersList={setMembersList}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import { useCallback, useMemo, useState } from "react";
|
import { useCallback, useMemo, useState } from "react";
|
||||||
import { ApplicationMetadataMessage } from "status-communities/dist/cjs";
|
import {
|
||||||
|
ApplicationMetadataMessage,
|
||||||
|
Contacts,
|
||||||
|
} from "status-communities/dist/cjs";
|
||||||
|
|
||||||
import { ChatMessage } from "../../models/ChatMessage";
|
import { ChatMessage } from "../../models/ChatMessage";
|
||||||
import { binarySetInsert } from "../../utils";
|
import { binarySetInsert } from "../../utils";
|
||||||
|
|
||||||
import { useNotifications } from "./useNotifications";
|
import { useNotifications } from "./useNotifications";
|
||||||
|
|
||||||
export function useMessages(chatId: string) {
|
export function useMessages(chatId: string, contacts?: Contacts) {
|
||||||
const [messages, setMessages] = useState<{ [chatId: string]: ChatMessage[] }>(
|
const [messages, setMessages] = useState<{ [chatId: string]: ChatMessage[] }>(
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
@ -17,6 +20,9 @@ export function useMessages(chatId: string) {
|
||||||
(msg: ApplicationMetadataMessage, id: string, date: Date) => {
|
(msg: ApplicationMetadataMessage, id: string, date: Date) => {
|
||||||
const newMessage = ChatMessage.fromMetadataMessage(msg, date);
|
const newMessage = ChatMessage.fromMetadataMessage(msg, date);
|
||||||
if (newMessage) {
|
if (newMessage) {
|
||||||
|
if (contacts) {
|
||||||
|
contacts.addContact(newMessage.sender);
|
||||||
|
}
|
||||||
setMessages((prev) => {
|
setMessages((prev) => {
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
|
@ -31,7 +37,7 @@ export function useMessages(chatId: string) {
|
||||||
incNotification(id);
|
incNotification(id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[]
|
[contacts]
|
||||||
);
|
);
|
||||||
|
|
||||||
const activeMessages = useMemo(
|
const activeMessages = useMemo(
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
// import { StoreCodec } from "js-waku";
|
// import { StoreCodec } from "js-waku";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { Community, Identity, Messenger } from "status-communities/dist/cjs";
|
import {
|
||||||
|
Community,
|
||||||
|
Contacts,
|
||||||
|
Identity,
|
||||||
|
Messenger,
|
||||||
|
utils,
|
||||||
|
} from "status-communities/dist/cjs";
|
||||||
|
|
||||||
import { createCommunityMessenger } from "../../utils/createCommunityMessenger";
|
import { Contact } from "../../models/Contact";
|
||||||
|
import { createCommunity } from "../../utils/createCommunity";
|
||||||
|
import { createMessenger } from "../../utils/createMessenger";
|
||||||
|
|
||||||
import { useLoadPrevDay } from "./useLoadPrevDay";
|
import { useLoadPrevDay } from "./useLoadPrevDay";
|
||||||
import { useMessages } from "./useMessages";
|
import { useMessages } from "./useMessages";
|
||||||
|
@ -13,27 +21,65 @@ export function useMessenger(
|
||||||
identity: Identity
|
identity: Identity
|
||||||
) {
|
) {
|
||||||
const [messenger, setMessenger] = useState<Messenger | undefined>(undefined);
|
const [messenger, setMessenger] = useState<Messenger | undefined>(undefined);
|
||||||
|
|
||||||
|
const [internalContacts, setInternalContacts] = useState<{
|
||||||
|
[id: string]: number;
|
||||||
|
}>({});
|
||||||
|
|
||||||
|
const contactsClass = useMemo(() => {
|
||||||
|
if (messenger) {
|
||||||
|
const newContacts = new Contacts(
|
||||||
|
identity,
|
||||||
|
messenger.waku,
|
||||||
|
(id, clock) => {
|
||||||
|
setInternalContacts((prev) => {
|
||||||
|
return { ...prev, [id]: clock };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
newContacts.addContact(utils.bufToHex(identity.publicKey));
|
||||||
|
return newContacts;
|
||||||
|
}
|
||||||
|
}, [messenger]);
|
||||||
|
|
||||||
|
const contacts = useMemo<Contact[]>(() => {
|
||||||
|
const now = Date.now();
|
||||||
|
const newContacts: Contact[] = [];
|
||||||
|
Object.entries(internalContacts).forEach(([id, clock]) => {
|
||||||
|
newContacts.push({
|
||||||
|
id,
|
||||||
|
online: clock > now - 301000,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return newContacts;
|
||||||
|
}, [internalContacts]);
|
||||||
|
|
||||||
const { addMessage, clearNotifications, notifications, messages } =
|
const { addMessage, clearNotifications, notifications, messages } =
|
||||||
useMessages(chatId);
|
useMessages(chatId, contactsClass);
|
||||||
const [community, setCommunity] = useState<Community | undefined>(undefined);
|
const [community, setCommunity] = useState<Community | undefined>(undefined);
|
||||||
const { loadPrevDay, loadingMessages } = useLoadPrevDay(chatId, messenger);
|
const { loadPrevDay, loadingMessages } = useLoadPrevDay(chatId, messenger);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
createCommunityMessenger(communityKey, addMessage, identity).then(
|
createMessenger(identity).then((e) => {
|
||||||
(result) => {
|
setMessenger(e);
|
||||||
setCommunity(result.community);
|
});
|
||||||
setMessenger(result.messenger);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (messenger && contactsClass) {
|
||||||
|
createCommunity(communityKey, addMessage, messenger).then((e) => {
|
||||||
|
setCommunity(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [messenger, communityKey, addMessage, contactsClass]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (messenger && community?.chats) {
|
if (messenger && community?.chats) {
|
||||||
Array.from(community?.chats.values()).forEach(({ id }) =>
|
Array.from(community?.chats.values()).forEach(({ id }) =>
|
||||||
loadPrevDay(id)
|
loadPrevDay(id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [messenger]);
|
}, [messenger, community]);
|
||||||
|
|
||||||
const sendMessage = useCallback(
|
const sendMessage = useCallback(
|
||||||
async (messageText?: string, image?: Uint8Array) => {
|
async (messageText?: string, image?: Uint8Array) => {
|
||||||
|
@ -63,5 +109,6 @@ export function useMessenger(
|
||||||
loadPrevDay,
|
loadPrevDay,
|
||||||
loadingMessages,
|
loadingMessages,
|
||||||
community,
|
community,
|
||||||
|
contacts,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export function useRefBreak(dimension: number, sizeThreshold: number) {
|
export function useRefBreak(dimension: number, sizeThreshold: number) {
|
||||||
const [widthBreak, setWidthBreak] = useState(false);
|
const [widthBreak, setWidthBreak] = useState(dimension < sizeThreshold);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkDimensions = () => {
|
const checkDimensions = () => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ApplicationMetadataMessage } from "status-communities/dist/cjs";
|
import { ApplicationMetadataMessage, utils } from "status-communities/dist/cjs";
|
||||||
|
|
||||||
import { uintToImgUrl } from "../utils";
|
import { uintToImgUrl } from "../utils";
|
||||||
|
|
||||||
|
@ -29,10 +29,7 @@ export class ChatMessage {
|
||||||
if (msg.chatMessage?.image) {
|
if (msg.chatMessage?.image) {
|
||||||
image = uintToImgUrl(msg.chatMessage?.image.payload);
|
image = uintToImgUrl(msg.chatMessage?.image.payload);
|
||||||
}
|
}
|
||||||
const sender = msg.signer.reduce(
|
const sender = utils.bufToHex(msg.signer);
|
||||||
(p: string, c: number): string => p + c.toString(16),
|
|
||||||
"0x"
|
|
||||||
);
|
|
||||||
return new ChatMessage(content, date, sender, image);
|
return new ChatMessage(content, date, sender, image);
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
export type Contact = {
|
||||||
|
id: string;
|
||||||
|
online: boolean;
|
||||||
|
};
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { Community, Messenger } from "status-communities/dist/cjs";
|
||||||
|
import { ApplicationMetadataMessage } from "status-communities/dist/cjs";
|
||||||
|
|
||||||
|
export async function createCommunity(
|
||||||
|
communityKey: string,
|
||||||
|
addMessage: (msg: ApplicationMetadataMessage, id: string, date: Date) => void,
|
||||||
|
messenger: Messenger
|
||||||
|
) {
|
||||||
|
const community = await Community.instantiateCommunity(
|
||||||
|
communityKey,
|
||||||
|
messenger.waku
|
||||||
|
);
|
||||||
|
await Promise.all(
|
||||||
|
Array.from(community.chats.values()).map(async (chat) => {
|
||||||
|
await messenger.joinChat(chat);
|
||||||
|
messenger.addObserver(
|
||||||
|
(msg, date) => addMessage(msg, chat.id, date),
|
||||||
|
chat.id
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return community;
|
||||||
|
}
|
|
@ -1,44 +0,0 @@
|
||||||
import { StoreCodec } from "js-waku";
|
|
||||||
import { Community, Identity, Messenger } from "status-communities/dist/cjs";
|
|
||||||
import { ApplicationMetadataMessage } from "status-communities/dist/cjs";
|
|
||||||
|
|
||||||
const WAKU_OPTIONS = {
|
|
||||||
libp2p: {
|
|
||||||
config: {
|
|
||||||
pubsub: {
|
|
||||||
enabled: true,
|
|
||||||
emitSelf: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function createCommunityMessenger(
|
|
||||||
communityKey: string,
|
|
||||||
addMessage: (msg: ApplicationMetadataMessage, id: string, date: Date) => void,
|
|
||||||
identity: Identity
|
|
||||||
) {
|
|
||||||
const messenger = await Messenger.create(identity, WAKU_OPTIONS);
|
|
||||||
await new Promise((resolve) => {
|
|
||||||
messenger.waku.libp2p.peerStore.on("change:protocols", ({ protocols }) => {
|
|
||||||
if (protocols.includes(StoreCodec)) {
|
|
||||||
resolve("");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const community = await Community.instantiateCommunity(
|
|
||||||
communityKey,
|
|
||||||
messenger.waku
|
|
||||||
);
|
|
||||||
await Promise.all(
|
|
||||||
Array.from(community.chats.values()).map(async (chat) => {
|
|
||||||
await messenger.joinChat(chat);
|
|
||||||
messenger.addObserver(
|
|
||||||
(msg, date) => addMessage(msg, chat.id, date),
|
|
||||||
chat.id
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return { messenger, community, identity };
|
|
||||||
}
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { StoreCodec } from "js-waku";
|
||||||
|
import { Identity, Messenger } from "status-communities/dist/cjs";
|
||||||
|
|
||||||
|
const WAKU_OPTIONS = {
|
||||||
|
libp2p: {
|
||||||
|
config: {
|
||||||
|
pubsub: {
|
||||||
|
enabled: true,
|
||||||
|
emitSelf: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function createMessenger(identity: Identity) {
|
||||||
|
const messenger = await Messenger.create(identity, WAKU_OPTIONS);
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
messenger.waku.libp2p.peerStore.on("change:protocols", ({ protocols }) => {
|
||||||
|
if (protocols.includes(StoreCodec)) {
|
||||||
|
resolve("");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return messenger;
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package communities.v1;
|
||||||
|
|
||||||
|
/* Specs:
|
||||||
|
:AUTOMATIC
|
||||||
|
To Send - "AUTOMATIC" status ping every 5 minutes
|
||||||
|
Display - Online for up to 5 minutes from the last clock, after that Offline
|
||||||
|
:ALWAYS_ONLINE
|
||||||
|
To Send - "ALWAYS_ONLINE" status ping every 5 minutes
|
||||||
|
Display - Online for up to 2 weeks from the last clock, after that Offline
|
||||||
|
:INACTIVE
|
||||||
|
To Send - A single "INACTIVE" status ping
|
||||||
|
Display - Offline forever
|
||||||
|
Note: Only send pings if the user interacted with the app in the last x minutes. */
|
||||||
|
message StatusUpdate {
|
||||||
|
|
||||||
|
uint64 clock = 1;
|
||||||
|
|
||||||
|
StatusType status_type = 2;
|
||||||
|
|
||||||
|
string custom_text = 3;
|
||||||
|
|
||||||
|
enum StatusType {
|
||||||
|
UNKNOWN_STATUS_TYPE = 0;
|
||||||
|
AUTOMATIC = 1;
|
||||||
|
DO_NOT_DISTURB = 2;
|
||||||
|
ALWAYS_ONLINE = 3;
|
||||||
|
INACTIVE = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { Waku, WakuMessage } from "js-waku";
|
||||||
|
|
||||||
|
import { idToContactCodeTopic } from "./contentTopic";
|
||||||
|
import { Identity } from "./identity";
|
||||||
|
import { StatusUpdate_StatusType } from "./proto/communities/v1/status_update";
|
||||||
|
import { bufToHex } from "./utils";
|
||||||
|
import { StatusUpdate } from "./wire/status_update";
|
||||||
|
|
||||||
|
export class Contacts {
|
||||||
|
waku: Waku;
|
||||||
|
identity: Identity;
|
||||||
|
private callback: (id: string, clock: number) => void;
|
||||||
|
private contacts: string[] = [];
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
identity: Identity,
|
||||||
|
waku: Waku,
|
||||||
|
callback: (id: string, clock: number) => void
|
||||||
|
) {
|
||||||
|
this.waku = waku;
|
||||||
|
this.identity = identity;
|
||||||
|
this.callback = callback;
|
||||||
|
this.startBroadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
public addContact(id: string): void {
|
||||||
|
if (!this.contacts.find((e) => id === e)) {
|
||||||
|
const now = new Date();
|
||||||
|
const callback = (wakuMessage: WakuMessage): void => {
|
||||||
|
if (wakuMessage.payload) {
|
||||||
|
const msg = StatusUpdate.decode(wakuMessage.payload);
|
||||||
|
this.callback(id, msg.clock ?? 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.contacts.push(id);
|
||||||
|
this.callback(id, 0);
|
||||||
|
this.waku.store.queryHistory([idToContactCodeTopic(id)], {
|
||||||
|
callback: (msgs) => msgs.forEach((e) => callback(e)),
|
||||||
|
timeFilter: {
|
||||||
|
startTime: new Date(now.getTime() - 400000),
|
||||||
|
endTime: now,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.waku.relay.addObserver(callback, [idToContactCodeTopic(id)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private startBroadcast(): void {
|
||||||
|
const send = async (): Promise<void> => {
|
||||||
|
const statusUpdate = StatusUpdate.create(
|
||||||
|
StatusUpdate_StatusType.AUTOMATIC,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
const msg = await WakuMessage.fromBytes(
|
||||||
|
statusUpdate.encode(),
|
||||||
|
idToContactCodeTopic(bufToHex(this.identity.publicKey))
|
||||||
|
);
|
||||||
|
this.waku.relay.send(msg);
|
||||||
|
};
|
||||||
|
send();
|
||||||
|
setInterval(send, 300000);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,3 +16,7 @@ export function idToContentTopic(id: string): string {
|
||||||
|
|
||||||
return "/waku/1/" + "0x" + topic.toString("hex") + "/rfc26";
|
return "/waku/1/" + "0x" + topic.toString("hex") + "/rfc26";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function idToContactCodeTopic(id: string): string {
|
||||||
|
return idToContentTopic(id + "-contact-code");
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
export { Identity } from "./identity";
|
export { Identity } from "./identity";
|
||||||
export { Messenger } from "./messenger";
|
export { Messenger } from "./messenger";
|
||||||
export { Community } from "./community";
|
export { Community } from "./community";
|
||||||
|
export { Contacts } from "./contacts";
|
||||||
export { Chat } from "./chat";
|
export { Chat } from "./chat";
|
||||||
export * as utils from "./utils";
|
export * as utils from "./utils";
|
||||||
export { ApplicationMetadataMessage } from "./wire/application_metadata_message";
|
export { ApplicationMetadataMessage } from "./wire/application_metadata_message";
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
import Long from "long";
|
||||||
|
import _m0 from "protobufjs/minimal";
|
||||||
|
|
||||||
|
export const protobufPackage = "communities.v1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specs:
|
||||||
|
* :AUTOMATIC
|
||||||
|
* To Send - "AUTOMATIC" status ping every 5 minutes
|
||||||
|
* Display - Online for up to 5 minutes from the last clock, after that Offline
|
||||||
|
* :ALWAYS_ONLINE
|
||||||
|
* To Send - "ALWAYS_ONLINE" status ping every 5 minutes
|
||||||
|
* Display - Online for up to 2 weeks from the last clock, after that Offline
|
||||||
|
* :INACTIVE
|
||||||
|
* To Send - A single "INACTIVE" status ping
|
||||||
|
* Display - Offline forever
|
||||||
|
* Note: Only send pings if the user interacted with the app in the last x minutes.
|
||||||
|
*/
|
||||||
|
export interface StatusUpdate {
|
||||||
|
clock: number;
|
||||||
|
statusType: StatusUpdate_StatusType;
|
||||||
|
customText: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum StatusUpdate_StatusType {
|
||||||
|
UNKNOWN_STATUS_TYPE = 0,
|
||||||
|
AUTOMATIC = 1,
|
||||||
|
DO_NOT_DISTURB = 2,
|
||||||
|
ALWAYS_ONLINE = 3,
|
||||||
|
INACTIVE = 4,
|
||||||
|
UNRECOGNIZED = -1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function statusUpdate_StatusTypeFromJSON(
|
||||||
|
object: any
|
||||||
|
): StatusUpdate_StatusType {
|
||||||
|
switch (object) {
|
||||||
|
case 0:
|
||||||
|
case "UNKNOWN_STATUS_TYPE":
|
||||||
|
return StatusUpdate_StatusType.UNKNOWN_STATUS_TYPE;
|
||||||
|
case 1:
|
||||||
|
case "AUTOMATIC":
|
||||||
|
return StatusUpdate_StatusType.AUTOMATIC;
|
||||||
|
case 2:
|
||||||
|
case "DO_NOT_DISTURB":
|
||||||
|
return StatusUpdate_StatusType.DO_NOT_DISTURB;
|
||||||
|
case 3:
|
||||||
|
case "ALWAYS_ONLINE":
|
||||||
|
return StatusUpdate_StatusType.ALWAYS_ONLINE;
|
||||||
|
case 4:
|
||||||
|
case "INACTIVE":
|
||||||
|
return StatusUpdate_StatusType.INACTIVE;
|
||||||
|
case -1:
|
||||||
|
case "UNRECOGNIZED":
|
||||||
|
default:
|
||||||
|
return StatusUpdate_StatusType.UNRECOGNIZED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function statusUpdate_StatusTypeToJSON(
|
||||||
|
object: StatusUpdate_StatusType
|
||||||
|
): string {
|
||||||
|
switch (object) {
|
||||||
|
case StatusUpdate_StatusType.UNKNOWN_STATUS_TYPE:
|
||||||
|
return "UNKNOWN_STATUS_TYPE";
|
||||||
|
case StatusUpdate_StatusType.AUTOMATIC:
|
||||||
|
return "AUTOMATIC";
|
||||||
|
case StatusUpdate_StatusType.DO_NOT_DISTURB:
|
||||||
|
return "DO_NOT_DISTURB";
|
||||||
|
case StatusUpdate_StatusType.ALWAYS_ONLINE:
|
||||||
|
return "ALWAYS_ONLINE";
|
||||||
|
case StatusUpdate_StatusType.INACTIVE:
|
||||||
|
return "INACTIVE";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseStatusUpdate: object = { clock: 0, statusType: 0, customText: "" };
|
||||||
|
|
||||||
|
export const StatusUpdate = {
|
||||||
|
encode(
|
||||||
|
message: StatusUpdate,
|
||||||
|
writer: _m0.Writer = _m0.Writer.create()
|
||||||
|
): _m0.Writer {
|
||||||
|
if (message.clock !== 0) {
|
||||||
|
writer.uint32(8).uint64(message.clock);
|
||||||
|
}
|
||||||
|
if (message.statusType !== 0) {
|
||||||
|
writer.uint32(16).int32(message.statusType);
|
||||||
|
}
|
||||||
|
if (message.customText !== "") {
|
||||||
|
writer.uint32(26).string(message.customText);
|
||||||
|
}
|
||||||
|
return writer;
|
||||||
|
},
|
||||||
|
|
||||||
|
decode(input: _m0.Reader | Uint8Array, length?: number): StatusUpdate {
|
||||||
|
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
|
||||||
|
let end = length === undefined ? reader.len : reader.pos + length;
|
||||||
|
const message = { ...baseStatusUpdate } as StatusUpdate;
|
||||||
|
while (reader.pos < end) {
|
||||||
|
const tag = reader.uint32();
|
||||||
|
switch (tag >>> 3) {
|
||||||
|
case 1:
|
||||||
|
message.clock = longToNumber(reader.uint64() as Long);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
message.statusType = reader.int32() as any;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
message.customText = reader.string();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reader.skipType(tag & 7);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
|
||||||
|
fromJSON(object: any): StatusUpdate {
|
||||||
|
const message = { ...baseStatusUpdate } as StatusUpdate;
|
||||||
|
if (object.clock !== undefined && object.clock !== null) {
|
||||||
|
message.clock = Number(object.clock);
|
||||||
|
} else {
|
||||||
|
message.clock = 0;
|
||||||
|
}
|
||||||
|
if (object.statusType !== undefined && object.statusType !== null) {
|
||||||
|
message.statusType = statusUpdate_StatusTypeFromJSON(object.statusType);
|
||||||
|
} else {
|
||||||
|
message.statusType = 0;
|
||||||
|
}
|
||||||
|
if (object.customText !== undefined && object.customText !== null) {
|
||||||
|
message.customText = String(object.customText);
|
||||||
|
} else {
|
||||||
|
message.customText = "";
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
|
||||||
|
toJSON(message: StatusUpdate): unknown {
|
||||||
|
const obj: any = {};
|
||||||
|
message.clock !== undefined && (obj.clock = message.clock);
|
||||||
|
message.statusType !== undefined &&
|
||||||
|
(obj.statusType = statusUpdate_StatusTypeToJSON(message.statusType));
|
||||||
|
message.customText !== undefined && (obj.customText = message.customText);
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
fromPartial(object: DeepPartial<StatusUpdate>): StatusUpdate {
|
||||||
|
const message = { ...baseStatusUpdate } as StatusUpdate;
|
||||||
|
if (object.clock !== undefined && object.clock !== null) {
|
||||||
|
message.clock = object.clock;
|
||||||
|
} else {
|
||||||
|
message.clock = 0;
|
||||||
|
}
|
||||||
|
if (object.statusType !== undefined && object.statusType !== null) {
|
||||||
|
message.statusType = object.statusType;
|
||||||
|
} else {
|
||||||
|
message.statusType = 0;
|
||||||
|
}
|
||||||
|
if (object.customText !== undefined && object.customText !== null) {
|
||||||
|
message.customText = object.customText;
|
||||||
|
} else {
|
||||||
|
message.customText = "";
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
declare var self: any | undefined;
|
||||||
|
declare var window: any | undefined;
|
||||||
|
declare var global: any | undefined;
|
||||||
|
var globalThis: any = (() => {
|
||||||
|
if (typeof globalThis !== "undefined") return globalThis;
|
||||||
|
if (typeof self !== "undefined") return self;
|
||||||
|
if (typeof window !== "undefined") return window;
|
||||||
|
if (typeof global !== "undefined") return global;
|
||||||
|
throw "Unable to locate global object";
|
||||||
|
})();
|
||||||
|
|
||||||
|
type Builtin =
|
||||||
|
| Date
|
||||||
|
| Function
|
||||||
|
| Uint8Array
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| undefined;
|
||||||
|
export type DeepPartial<T> = T extends Builtin
|
||||||
|
? T
|
||||||
|
: T extends Array<infer U>
|
||||||
|
? Array<DeepPartial<U>>
|
||||||
|
: T extends ReadonlyArray<infer U>
|
||||||
|
? ReadonlyArray<DeepPartial<U>>
|
||||||
|
: T extends {}
|
||||||
|
? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||||
|
: Partial<T>;
|
||||||
|
|
||||||
|
function longToNumber(long: Long): number {
|
||||||
|
if (long.gt(Number.MAX_SAFE_INTEGER)) {
|
||||||
|
throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
|
||||||
|
}
|
||||||
|
return long.toNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_m0.util.Long !== Long) {
|
||||||
|
_m0.util.Long = Long as any;
|
||||||
|
_m0.configure();
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { Reader } from "protobufjs";
|
||||||
|
|
||||||
|
import * as proto from "../proto/communities/v1/status_update";
|
||||||
|
|
||||||
|
export class StatusUpdate {
|
||||||
|
public constructor(public proto: proto.StatusUpdate) {}
|
||||||
|
|
||||||
|
public static create(
|
||||||
|
statusType: proto.StatusUpdate_StatusType,
|
||||||
|
customText: string
|
||||||
|
): StatusUpdate {
|
||||||
|
const clock = Date.now();
|
||||||
|
|
||||||
|
const proto = {
|
||||||
|
clock,
|
||||||
|
statusType,
|
||||||
|
customText,
|
||||||
|
};
|
||||||
|
|
||||||
|
return new StatusUpdate(proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the payload as CommunityChat message.
|
||||||
|
*
|
||||||
|
* @throws
|
||||||
|
*/
|
||||||
|
static decode(bytes: Uint8Array): StatusUpdate {
|
||||||
|
const protoBuf = proto.StatusUpdate.decode(Reader.create(bytes));
|
||||||
|
|
||||||
|
return new StatusUpdate(protoBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
encode(): Uint8Array {
|
||||||
|
return proto.StatusUpdate.encode(this.proto).finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get clock(): number | undefined {
|
||||||
|
return this.proto.clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get statusType(): proto.StatusUpdate_StatusType | undefined {
|
||||||
|
return this.proto.statusType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get customText(): string | undefined {
|
||||||
|
return this.proto.customText;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue