syncing channels

This commit is contained in:
balzack 2022-09-20 00:50:53 -07:00
parent 450e4ff7a0
commit 8b09d214b7
9 changed files with 139 additions and 40 deletions

View File

@ -1,4 +1,4 @@
export function getCardImageUrl(token, cardId, revision) { export function getCardImageUrl(server, token, cardId, revision) {
return `/contact/cards/${cardId}/profile/image?agent=${token}&revision=${revision}` return `https://${server}/contact/cards/${cardId}/profile/image?agent=${token}&revision=${revision}`
} }

View File

@ -66,19 +66,19 @@ export function useAppContext() {
create: async (server, username, password, token) => { create: async (server, username, password, token) => {
await addAccount(server, username, password, token); await addAccount(server, username, password, token);
const access = await setLogin(username, server, password) const access = await setLogin(username, server, password)
await setSession({ ...access, server });
await store.actions.setSession({ ...access, server}); await store.actions.setSession({ ...access, server});
await setSession({ ...access, server });
}, },
access: async (server, token) => { access: async (server, token) => {
const access = await setAccountAccess(server, token); const access = await setAccountAccess(server, token);
await setSession({ ...access, server });
await store.actions.setSession({ ...access, server}); await store.actions.setSession({ ...access, server});
await setSession({ ...access, server });
}, },
login: async (username, password) => { login: async (username, password) => {
const acc = username.split('@'); const acc = username.split('@');
const access = await setLogin(acc[0], acc[1], password) const access = await setLogin(acc[0], acc[1], password)
await setSession({ ...access, server: acc[1] });
await store.actions.setSession({ ...access, server: acc[1]}); await store.actions.setSession({ ...access, server: acc[1]});
await setSession({ ...access, server: acc[1] });
}, },
logout: async () => { logout: async () => {
await clearSession(); await clearSession();

View File

@ -8,6 +8,7 @@ import { getContactChannels } from 'api/getContactChannels';
import { getContactChannelTopics } from 'api/getContactChannelTopics'; import { getContactChannelTopics } from 'api/getContactChannelTopics';
import { getContactChannelDetail } from 'api/getContactChannelDetail'; import { getContactChannelDetail } from 'api/getContactChannelDetail';
import { getContactChannelSummary } from 'api/getContactChannelSummary'; import { getContactChannelSummary } from 'api/getContactChannelSummary';
import { getCardImageUrl } from 'api/getCardImageUrl';
export function useCardContext() { export function useCardContext() {
const [state, setState] = useState({ const [state, setState] = useState({
@ -26,19 +27,38 @@ export function useCardContext() {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const setCard = (cardId, card) => {
let updated = cards.current.get(cardId);
if (updated == null) {
updated = { channels: new Map() };
}
cards.current.set(cardId, {
...updated,
cardId: cardId,
revision: card?.revision,
detailRevision: card?.data?.detailRevision,
profileRevision: card?.data?.profileRevision,
detail: card?.data?.cardDetail,
profile: card?.data?.cardProfile,
notifiedView: card?.data?.notifiedView,
notifiedProfile: card?.data?.notifiedProfile,
notifiedArtile: card?.data?.notifiedArticle,
notifiedChannel: card?.data?.notifiedChannel,
});
}
const setCardDetail = (cardId, detail, revision) => { const setCardDetail = (cardId, detail, revision) => {
let card = cards.current.get(cardId); let card = cards.current.get(cardId);
if (card?.data) { if (card) {
card.data.cardDetail = detail; card.detail = detail;
card.data.detailRevision = revision; card.detailRevision = revision;
cards.current.set(cardId, card); cards.current.set(cardId, card);
} }
} }
const setCardProfile = (cardId, profile, revision) => { const setCardProfile = (cardId, profile, revision) => {
let card = cards.current.get(cardId); let card = cards.current.get(cardId);
if (card?.data) { if (card) {
card.data.cardProfile = profile; card.profile = profile;
card.data.profileRevision = revision; card.profileRevision = revision;
cards.current.set(cardId, card); cards.current.set(cardId, card);
} }
} }
@ -64,6 +84,17 @@ export function useCardContext() {
} }
} }
const setCardChannel = (cardId, channel) => { const setCardChannel = (cardId, channel) => {
setCardChannelItem(cardId, {
cardId: cardId,
channelId: channel?.id,
revision: channel?.revision,
detailRevision: channel?.data?.detailRevision,
topicRevision: channel?.data?.topicRevision,
detail: channel?.data?.channelDetail,
summary: channel?.data?.channelSummary,
});
}
const setCardChannelItem = (cardId, channel) => {
let card = cards.current.get(cardId); let card = cards.current.get(cardId);
if (card) { if (card) {
card.channels.set(channel.id, channel); card.channels.set(channel.id, channel);
@ -74,9 +105,9 @@ export function useCardContext() {
let card = cards.current.get(cardId); let card = cards.current.get(cardId);
if (card) { if (card) {
let channel = card.channels.get(channelId); let channel = card.channels.get(channelId);
if (channel?.data) { if (channel) {
channel.data.channelDetail = detail; channel.detail = detail;
channel.data.detailRevision = revision; channel.detailRevision = revision;
card.channels.set(channelId, channel); card.channels.set(channelId, channel);
cards.current.set(cardId, card); cards.current.set(cardId, card);
} }
@ -86,9 +117,9 @@ export function useCardContext() {
let card = cards.current.get(cardId); let card = cards.current.get(cardId);
if (card) { if (card) {
let channel = card.channels.get(channelId); let channel = card.channels.get(channelId);
if (channel?.data) { if (channel) {
channel.data.channelSummary = detail; channel.summary = detail;
channel.data.topicRevision = revision; channel.topicRevision = revision;
card.channels.set(channelId, channel); card.channels.set(channelId, channel);
cards.current.set(cardId, card); cards.current.set(cardId, card);
} }
@ -128,7 +159,7 @@ export function useCardContext() {
if (card.data) { if (card.data) {
if (card.data.cardDetail && card.data.cardProfile) { if (card.data.cardDetail && card.data.cardProfile) {
await store.actions.setCardItem(guid, card); await store.actions.setCardItem(guid, card);
cards.current.set(cardId, card); setCard(card.id, card);
} }
else { else {
const view = await store.actions.getCardItemView(guid, card.id); const view = await store.actions.getCardItemView(guid, card.id);
@ -138,7 +169,7 @@ export function useCardContext() {
assembled.data.cardDetail = await getCardDetail(server, appToken, card.id); assembled.data.cardDetail = await getCardDetail(server, appToken, card.id);
assembled.data.cardProfile = await getCardProfile(server, appToken, card.id); assembled.data.cardProfile = await getCardProfile(server, appToken, card.id);
await store.actions.setCardItem(guid, assembled); await store.actions.setCardItem(guid, assembled);
cards.curent.set(assembled.id, assembled); setCard(assembled.id, assembled);
} }
else { else {
if (view.detailRevision != detailRevision) { if (view.detailRevision != detailRevision) {
@ -185,7 +216,7 @@ export function useCardContext() {
} }
} }
catch(err) { catch(err) {
console.log(err); console.log("card1:", err);
await store.actions.setCardItemOffsync(guid, card.id); await store.actions.setCardItemOffsync(guid, card.id);
setCardOffsync(card.id, true); setCardOffsync(card.id, true);
} }
@ -203,7 +234,7 @@ export function useCardContext() {
await store.actions.setCardRevision(guid, revision); await store.actions.setCardRevision(guid, revision);
} }
catch(err) { catch(err) {
console.log(err); console.log("card2:", err);
syncing.current = false; syncing.current = false;
return; return;
} }
@ -267,7 +298,7 @@ export function useCardContext() {
} }
const cardChannelItems = await store.actions.getCardChannelItems(guid); const cardChannelItems = await store.actions.getCardChannelItems(guid);
for (item of cardChannelItems) { for (item of cardChannelItems) {
setCardChannel(item.cardId, item); setCardChannelItem(item.cardId, item);
} }
const revision = await store.actions.getCardRevision(guid); const revision = await store.actions.getCardRevision(guid);
updateState({ cards: cards.current }); updateState({ cards: cards.current });
@ -283,6 +314,10 @@ export function useCardContext() {
curRevision.current = rev; curRevision.current = rev;
sync(); sync();
}, },
getCardLogo: (cardId, revision) => {
const { server, appToken } = session.current;
return getCardImageUrl(server, appToken, cardId, revision);
}
} }
return { state, actions } return { state, actions }

View File

@ -20,19 +20,29 @@ export function useChannelContext() {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const setChannelDetails = (channelId, details, revision) => { const setChannel = (channelId, channel) => {
channels.current.set(channelId, {
channelId: channel?.id,
revision: channel?.revision,
detail: channel?.data?.channelDetail,
summary: channel?.data?.channelSummary,
detailRevision: channel?.data?.detailRevision,
topicRevision: channel?.data?.topicRevision,
});
}
const setChannelDetails = (channelId, detail, revision) => {
let channel = channels.current.get(channelId); let channel = channels.current.get(channelId);
if (channel?.data) { if (channel?.data) {
channel.data.channelDetails = details; channel.detail = detail;
channel.data.detailRevision = revision; channel.detailRevision = revision;
channels.current.set(channelId, channel); channels.current.set(channelId, channel);
} }
} }
const setChannelSummary = (channelId, summary, revision) => { const setChannelSummary = (channelId, summary, revision) => {
let channel = channels.current.get(channelId); let channel = channels.current.get(channelId);
if (channel?.data) { if (channel) {
channel.data.channelSummary = summary; channel.summary = summary;
channel.data.topicRevision = revision; channel.topicRevision = revision;
channels.curent.set(channelId, channel); channels.curent.set(channelId, channel);
} }
} }
@ -58,7 +68,7 @@ export function useChannelContext() {
if (channel.data) { if (channel.data) {
if (channel.data.channelDetail && channel.data.channelSummary) { if (channel.data.channelDetail && channel.data.channelSummary) {
await store.actions.setChannelItem(guid, channel); await store.actions.setChannelItem(guid, channel);
channels.current.set(channel.id, channel); setChannel(channel.id, channel);
} }
else { else {
const { detailRevision, topicRevision, channelDetail, channelSummary } = channel.data; const { detailRevision, topicRevision, channelDetail, channelSummary } = channel.data;
@ -69,7 +79,7 @@ export function useChannelContext() {
assembled.data.channelDetail = await getChannelDetail(server, appToken, channel.id); assembled.data.channelDetail = await getChannelDetail(server, appToken, channel.id);
assembled.data.channelSummary = await getChannelSummary(server, appToken, channel.id); assembled.data.channelSummary = await getChannelSummary(server, appToken, channel.id);
await store.actions.setChannelItem(guid, assembled); await store.actions.setChannelItem(guid, assembled);
channels.current.set(assembled.id, assembled); setChannel(assembled.id, assembled);
} }
else { else {
if (view.detailRevision != detailRevision) { if (view.detailRevision != detailRevision) {

View File

@ -1,7 +1,7 @@
import { useEffect, useState, useRef, useContext } from 'react'; import { useEffect, useState, useRef, useContext } from 'react';
import SQLite from "react-native-sqlite-storage"; import SQLite from "react-native-sqlite-storage";
const DATABAG_DB = 'databag_v019.db'; const DATABAG_DB = 'databag_v025.db';
export function useStoreContext() { export function useStoreContext() {
const [state, setState] = useState({}); const [state, setState] = useState({});
@ -113,18 +113,20 @@ export function useStoreContext() {
await db.current.executeSql(`UPDATE card_${guid} set profile_revision=?, profile=? where card_id=?`, [revision, encodeObject(profile), cardId]); await db.current.executeSql(`UPDATE card_${guid} set profile_revision=?, profile=? where card_id=?`, [revision, encodeObject(profile), cardId]);
}, },
getCardItemStatus: async (guid, cardId) => { getCardItemStatus: async (guid, cardId) => {
const values = await getAppValues(db.current, `SELECT detail, profile, notified_view, notified_article, notified_profile, notified_channel, offsync FROM card_${guid} WHERE card_id=?`, [cardId]); const values = await getAppValues(db.current, `SELECT detail, profile, profile_revision, detail_revision, notified_view, notified_article, notified_profile, notified_channel, offsync FROM card_${guid} WHERE card_id=?`, [cardId]);
if (!values.length) { if (!values.length) {
return null; return null;
} }
return { return {
detail: decodeObject(values[0].detail), detail: decodeObject(values[0].detail),
profile: decodeObject(values[0].profile), profile: decodeObject(values[0].profile),
offsync: values[0].offsync, profileRevision: values[0].profile_revision,
detailRevision: values[0].detail_revision,
notifiedView: values[0].notified_view, notifiedView: values[0].notified_view,
notifiedArticle: values[0].notified_article, notifiedArticle: values[0].notified_article,
notifiedProfile: values[0].notified_profile, notifiedProfile: values[0].notified_profile,
notifiedChannel: values[0].notified_cahnnel, notifiedChannel: values[0].notified_cahnnel,
offsync: values[0].offsync,
}; };
}, },
getCardItemView: async (guid, cardId) => { getCardItemView: async (guid, cardId) => {

View File

@ -3,6 +3,7 @@ import { FlatList, ScrollView, View, TextInput, TouchableOpacity, Text } from 'r
import { styles } from './Channels.styled'; import { styles } from './Channels.styled';
import { useChannels } from './useChannels.hook'; import { useChannels } from './useChannels.hook';
import Ionicons from '@expo/vector-icons/AntDesign'; import Ionicons from '@expo/vector-icons/AntDesign';
import { ChannelItem } from './channelItem/ChannelItem';
export function Channels() { export function Channels() {
@ -18,7 +19,7 @@ export function Channels() {
</View> </View>
<FlatList style={styles.channels} <FlatList style={styles.channels}
data={state.channels} data={state.channels}
renderItem={({ item }) => <Text>{ item.channelId }</Text>} renderItem={({ item }) => <ChannelItem item={item} />}
keyExtractor={item => (`${item.cardId}:${item.channelId}`)} keyExtractor={item => (`${item.cardId}:${item.channelId}`)}
/> />
</View> </View>

View File

@ -0,0 +1,7 @@
import { Text } from 'react-native';
import { Logo } from 'utils/Logo';
export function ChannelItem({ item }) {
return <Logo src={item.logo} width={32} height={32} />
}

View File

@ -1,6 +1,7 @@
import { useState, useEffect, useContext } from 'react'; import { useState, useEffect, useContext } from 'react';
import { useWindowDimensions } from 'react-native'; import { useWindowDimensions } from 'react-native';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { CardContext } from 'context/CardContext';
import { ChannelContext } from 'context/ChannelContext'; import { ChannelContext } from 'context/ChannelContext';
import config from 'constants/Config'; import config from 'constants/Config';
@ -12,14 +13,57 @@ export function useChannels() {
}); });
const channel = useContext(ChannelContext); const channel = useContext(ChannelContext);
const card = useContext(CardContext);
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
} }
const getCard = (guid) => {
let contact = null
card.state.cards.forEach((card, cardId, map) => {
if (card?.profile?.guid === guid) {
contact = card;
}
});
return contact;
}
const setChannelEntry = (item) => {
let contacts = [];
if (item?.detail?.members) {
item.detail.members.forEach(guid => {
contacts.push(getCard(guid));
})
}
let logo = null;
if (contacts.length === 0) {
logo = 'solution';
}
else if (contacts.length === 1) {
if (contacts[0]?.profile?.imageSet) {
logo = card.actions.getCardLogo(contacts[0].cardId, contacts[0].profileRevision);
}
else {
logo = 'avatar';
}
}
else {
logo = 'appstore';
}
return {
channelId: item.channelId,
contacts: contacts,
logo: logo,
}
}
useEffect(() => { useEffect(() => {
updateState({ channels: Array.from(channel.state.channels.values()) }); const channels = Array.from(channel.state.channels.values()).map(item => setChannelEntry(item));
}, [channel]); updateState({ channels });
}, [channel, card]);
const actions = { const actions = {
setTopic: (topic) => { setTopic: (topic) => {

View File

@ -1,4 +1,4 @@
import { Image } from 'react-native'; import { Image, View } from 'react-native';
import avatar from 'images/avatar.png'; import avatar from 'images/avatar.png';
import appstore from 'images/appstore.png'; import appstore from 'images/appstore.png';
import solution from 'images/solution.png'; import solution from 'images/solution.png';
@ -6,7 +6,7 @@ import team from 'images/team.png';
export function Logo({ src, width, height, radius }) { export function Logo({ src, width, height, radius }) {
return ( return (
<div style={{ borderRadius: radius, overflow: 'hidden' }}> <View style={{ borderRadius: radius, overflow: 'hidden' }}>
{ src === 'team' && ( { src === 'team' && (
<Image source={team} style={{ width, height }} /> <Image source={team} style={{ width, height }} />
)} )}
@ -23,9 +23,9 @@ export function Logo({ src, width, height, radius }) {
<Image source={avatar} style={{ width, height }} /> <Image source={avatar} style={{ width, height }} />
)} )}
{ src && src.startsWith('http') && ( { src && src.startsWith('http') && (
<Image source={src} style={{ width, height }} /> <Image source={{ uri:src }} resizeMode={'contain'} style={{ width, height }} />
)} )}
</div> </View>
); );
} }