mirror of
https://github.com/balzack/databag.git
synced 2025-03-13 00:50:03 +00:00
show loading indicator as channels loading
This commit is contained in:
parent
f120524531
commit
b23598b364
@ -38,13 +38,17 @@
|
||||
color: var(--mantine-color-text-6);
|
||||
}
|
||||
|
||||
.steps {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.step {
|
||||
font-size: 16px;
|
||||
color: var(--mantine-color-text-6);
|
||||
.instructions {
|
||||
height: 32px;
|
||||
|
||||
.steps {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.step {
|
||||
font-size: 16px;
|
||||
color: var(--mantine-color-text-6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,19 +16,21 @@ export function Base() {
|
||||
<Text className={classes.label}>{ state.strings.communication }</Text>
|
||||
</div>
|
||||
<Image className={classes.image} src={state.scheme === 'dark' ? dark : light} fit="contain" />
|
||||
{ (state.profileSet === false || state.cardSet === false || state.channelSet === false) && (
|
||||
<div className={classes.steps}>
|
||||
{ (state.profileSet === false) && (
|
||||
<Text className={classes.step}>{ state.strings.setupProfile }</Text>
|
||||
)}
|
||||
<IconChevronRight className={classes.icon} />
|
||||
{ (state.profileSet === false || state.cardSet === false) && (
|
||||
<Text className={classes.step}>{ state.strings.connectPeople }</Text>
|
||||
)}
|
||||
<IconChevronRight className={classes.icon} />
|
||||
<Text className={classes.step}>{ state.strings.startConversation }</Text>
|
||||
</div>
|
||||
)}
|
||||
<div className={classes.instructions}>
|
||||
{ state.contentSet && (state.profileSet === false || state.cardSet === false || state.channelSet === false) && (
|
||||
<div className={classes.steps}>
|
||||
{ (state.profileSet === false) && (
|
||||
<Text className={classes.step}>{ state.strings.setupProfile }</Text>
|
||||
)}
|
||||
<IconChevronRight className={classes.icon} />
|
||||
{ (state.profileSet === false || state.cardSet === false) && (
|
||||
<Text className={classes.step}>{ state.strings.connectPeople }</Text>
|
||||
)}
|
||||
<IconChevronRight className={classes.icon} />
|
||||
<Text className={classes.step}>{ state.strings.startConversation }</Text>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { useState, useContext, useEffect } from 'react'
|
||||
import { AppContext } from '../context/AppContext'
|
||||
import { DisplayContext } from '../context/DisplayContext'
|
||||
import { ContextType } from '../context/ContextType'
|
||||
import { Card, Channel, Profile } from 'databag-client-sdk';
|
||||
|
||||
export function useBase() {
|
||||
const app = useContext(AppContext) as ContextType
|
||||
@ -12,6 +13,7 @@ export function useBase() {
|
||||
profileSet: null as null | boolean,
|
||||
cardSet: null as null | boolean,
|
||||
channelSet: null as null | boolean,
|
||||
contentSet: null as null | boolean,
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@ -34,16 +36,21 @@ export function useBase() {
|
||||
const setChannels = ({ channels, cardId }: { channels: Channel[]; cardId: string | null }) => {
|
||||
updateState({ channelSet: channels.length > 0 });
|
||||
}
|
||||
const setContent = (loaded: boolean) => {
|
||||
updateState({ contentSet: loaded });
|
||||
}
|
||||
|
||||
const { identity, contact, content } = app.state.session
|
||||
identity.addProfileListener(setProfile)
|
||||
contact.addCardListener(setCards)
|
||||
content.addChannelListener(setChannels)
|
||||
content.addLoadedListener(setContent);
|
||||
|
||||
return () => {
|
||||
identity.removeProfileListener(setProfile);
|
||||
contact.removeCardListener(setCards);
|
||||
content.removeChannelListener(setChannels);
|
||||
content.removeLoadedListener(setContent);
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useContent } from './useContent.hook'
|
||||
import { Modal, Text, Switch, TextInput, Button } from '@mantine/core'
|
||||
import { Modal, Box, LoadingOverlay, Text, Switch, TextInput, Button } from '@mantine/core'
|
||||
import { IconSearch, IconMessagePlus, IconLabel } from '@tabler/icons-react'
|
||||
import classes from './Content.module.css'
|
||||
import { Channel } from '../channel/Channel'
|
||||
import { Card } from '../card/Card'
|
||||
import { modals } from '@mantine/modals'
|
||||
import { Colors } from '../constants/Colors';
|
||||
|
||||
export function Content({ textCard }: { textCard: { cardId: null|string }}) {
|
||||
const { state, actions } = useContent()
|
||||
@ -122,8 +123,11 @@ export function Content({ textCard }: { textCard: { cardId: null|string }}) {
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{channels.length === 0 && <div className={classes.none}>{state.strings.noTopics}</div>}
|
||||
{channels.length !== 0 && <div className={classes.channels}>{channels}</div>}
|
||||
<Box className={classes.channels} pos="relative" onClick={actions.setLoaded}>
|
||||
{channels.length === 0 && <div className={classes.none}>{state.strings.noTopics}</div>}
|
||||
{channels.length !== 0 && <div className={classes.channels}>{channels}</div>}
|
||||
<LoadingOverlay visible={!state.loaded} zIndex={1000} overlayProps={{ radius: 'sm', blur: 1 }} loaderProps={{ color: Colors.primary, type: 'dots' }}/>
|
||||
</Box>
|
||||
{state.layout === 'large' && (
|
||||
<div className={classes.bar}>
|
||||
<Button className={classes.add} leftSection={<IconMessagePlus size={20} />} onClick={() => setAdd(true)}>
|
||||
|
@ -34,6 +34,7 @@ export function useContent() {
|
||||
topic: '',
|
||||
sealSet: false,
|
||||
focused: null as null|{cardId: null|string, channelId: string},
|
||||
loaded: null as null | boolean,
|
||||
})
|
||||
|
||||
const compare = (a: Card, b: Card) => {
|
||||
@ -180,6 +181,9 @@ export function useContent() {
|
||||
const { sealSet, sealUnlocked } = config
|
||||
updateState({ sealSet: sealSet && sealUnlocked })
|
||||
}
|
||||
const setLoaded = (loaded: boolean) => {
|
||||
updateState({ loaded });
|
||||
}
|
||||
const setProfile = (profile: Profile) => {
|
||||
const { guid } = profile
|
||||
updateState({ guid })
|
||||
@ -228,12 +232,14 @@ export function useContent() {
|
||||
identity.addProfileListener(setProfile)
|
||||
contact.addCardListener(setCards)
|
||||
content.addChannelListener(setChannels)
|
||||
content.addLoadedListener(setLoaded)
|
||||
settings.addConfigListener(setConfig)
|
||||
|
||||
return () => {
|
||||
identity.removeProfileListener(setProfile)
|
||||
contact.removeCardListener(setCards)
|
||||
content.removeChannelListener(setChannels)
|
||||
content.removeLoadedListener(setLoaded)
|
||||
settings.removeConfigListener(setConfig)
|
||||
}
|
||||
}, [])
|
||||
@ -248,6 +254,9 @@ export function useContent() {
|
||||
setFocus: async (cardId: string | null, channelId: string) => {
|
||||
await app.actions.setFocus(cardId, channelId)
|
||||
},
|
||||
setLoaded: () => {
|
||||
updateState({ loaded: true });
|
||||
},
|
||||
openTopic: async (cardId: string) => {
|
||||
const content = app.state.session.getContent()
|
||||
const card = state.cards.find(card => card.cardId === cardId)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { useRing } from './useRing.hook';
|
||||
import classes from './Ring.module.css';
|
||||
import { Card as Contact } from '../card/Card';
|
||||
@ -6,7 +6,7 @@ import { Card } from 'databag-client-sdk';
|
||||
import { Colors } from '../constants/Colors';
|
||||
import { modals } from '@mantine/modals'
|
||||
import { Loader, Image, Text, ActionIcon } from '@mantine/core'
|
||||
import { IconVideoPlus, IconEyeX, IconPhone, IconPhoneOff, IconArrowsMaximize, IconMicrophone, IconMicrophoneOff } from '@tabler/icons-react'
|
||||
import { IconBell, IconVideoPlus, IconEyeX, IconPhone, IconPhoneOff, IconArrowsMaximize, IconMicrophone, IconMicrophoneOff } from '@tabler/icons-react'
|
||||
|
||||
export function Ring() {
|
||||
const { state, actions } = useRing();
|
||||
@ -15,6 +15,16 @@ export function Ring() {
|
||||
const [accepting, setAccepting] = useState(null as null|string);
|
||||
const [ignoring, setIgnoring] = useState(null as null|string);
|
||||
const [declining, setDeclining] = useState(null as null|string);
|
||||
const [ringing, setRinging] = useState(0);
|
||||
const counter = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
const count = setInterval(() => {
|
||||
counter.current += 1;
|
||||
setRinging(counter.current);
|
||||
}, 500);
|
||||
return () => clearInterval(count);
|
||||
}, []);
|
||||
|
||||
const showError = () => {
|
||||
modals.openConfirmModal({
|
||||
@ -154,7 +164,7 @@ export function Ring() {
|
||||
<Text className={classes.duration}>{ `${Math.floor(state.duration/60)}:${(state.duration % 60).toString().padStart(2, '0')}` }</Text>
|
||||
)}
|
||||
{ !state.connected && (
|
||||
<Loader size={18} />
|
||||
<IconBell size={18} color={Colors.primary} style={{ rotate: ringing % 2 == 0 ? '15deg' : '-15deg' }} />
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.end}>
|
||||
|
@ -192,8 +192,6 @@ export class ContactModule implements Contact {
|
||||
this.unsealAll = true;
|
||||
this.syncing = false;
|
||||
await this.sync();
|
||||
|
||||
this.loaded = true;
|
||||
this.emitLoaded();
|
||||
}
|
||||
|
||||
@ -554,6 +552,7 @@ export class ContactModule implements Contact {
|
||||
this.emitCards();
|
||||
await this.store.setContactRevision(guid, nextRev);
|
||||
this.revision = nextRev;
|
||||
this.emitLoaded();
|
||||
if (this.nextRevision === nextRev) {
|
||||
this.nextRevision = null;
|
||||
}
|
||||
@ -777,7 +776,10 @@ export class ContactModule implements Contact {
|
||||
}
|
||||
|
||||
private emitLoaded() {
|
||||
this.emitter.emit('loaded', this.loaded);
|
||||
if (!this.loaded) {
|
||||
this.loaded = Boolean(this.revision);
|
||||
this.emitter.emit('loaded', this.loaded);
|
||||
}
|
||||
}
|
||||
|
||||
public async setFocus(cardId: string, channelId: string): Promise<Focus> {
|
||||
|
@ -143,7 +143,7 @@ export class ContentModule implements Content {
|
||||
}
|
||||
|
||||
private emitLoaded() {
|
||||
if (this.streamLoaded && this.contentLoaded) {
|
||||
if (this.streamLoaded && this.contactLoaded) {
|
||||
this.emitter.emit('loaded', true);
|
||||
}
|
||||
}
|
||||
|
@ -104,8 +104,6 @@ export class StreamModule {
|
||||
this.unsealAll = true;
|
||||
this.syncing = false;
|
||||
await this.sync();
|
||||
|
||||
this.loaded = true;
|
||||
this.emitLoaded();
|
||||
}
|
||||
|
||||
@ -217,6 +215,7 @@ export class StreamModule {
|
||||
this.emitChannels();
|
||||
await this.store.setContentRevision(guid, nextRev);
|
||||
this.revision = nextRev;
|
||||
this.emitLoaded();
|
||||
if (this.nextRevision === nextRev) {
|
||||
this.nextRevision = null;
|
||||
}
|
||||
@ -284,7 +283,10 @@ export class StreamModule {
|
||||
}
|
||||
|
||||
private emitLoaded() {
|
||||
this.emitter.emit('loaded', this.loaded);
|
||||
if (!this.loaded) {
|
||||
this.loaded = Boolean(this.revision);
|
||||
this.emitter.emit('loaded', this.loaded);
|
||||
}
|
||||
}
|
||||
|
||||
public async close(): Promise<void> {
|
||||
@ -301,6 +303,7 @@ export class StreamModule {
|
||||
public async setRevision(rev: number): Promise<void> {
|
||||
this.nextRevision = rev;
|
||||
await this.sync();
|
||||
this.emitLoaded();
|
||||
}
|
||||
|
||||
public async addSealedChannel(type: string, subject: any, cardIds: string[], aesKeyHex: string, seals: { publicKey: string; sealedKey: string }[]): Promise<string> {
|
||||
|
Loading…
Reference in New Issue
Block a user