support resyncing of contacts

This commit is contained in:
balzack 2022-10-25 00:06:39 -07:00
parent cb544071ce
commit 43bf6d0d04
9 changed files with 117 additions and 57 deletions

View File

@ -310,7 +310,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 18;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = 3P65PQ7SUR;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
@ -348,7 +348,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 18;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = 3P65PQ7SUR;
INFOPLIST_FILE = Databag/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Databag;

View File

@ -1,6 +1,7 @@
import { useState, useRef, useContext } from 'react';
import { StoreContext } from 'context/StoreContext';
import { UploadContext } from 'context/UploadContext';
import { getCard } from 'api/getCard';
import { getCards } from 'api/getCards';
import { getCardProfile } from 'api/getCardProfile';
import { setCardProfile } from 'api/setCardProfile';
@ -42,15 +43,16 @@ export function useCardContext() {
const syncing = useRef(false);
const cards = useRef(new Map());
const cardChannels = useRef(new Map());
const resync = useRef([]);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }))
}
const getCard = (cardId) => {
const getCardEntry = (cardId) => {
const card = cards.current.get(cardId);
if (!card) {
throw new Error('cared not found');
throw new Error('card not found');
}
return card;
}
@ -213,12 +215,12 @@ export function useCardContext() {
}
const sync = async () => {
if (!syncing.current && setRevision.current !== curRevision.current) {
if (!syncing.current && (setRevision.current !== curRevision.current || resync.current.length > 0)) {
syncing.current = true;
const { server, appToken, guid } = session.current;
try {
const revision = curRevision.current;
const { server, appToken, guid } = session.current;
// get and store
const delta = await getCards(server, appToken, setRevision.current);
@ -254,41 +256,7 @@ export function useCardContext() {
}
}
const status = await store.actions.getCardItemStatus(guid, card.id);
const cardServer = status.profile.node;
const cardToken = status.profile.guid + '.' + status.detail.token;
if (status.detail.status === 'connected') {
try {
const { notifiedView, notifiedProfile, notifiedArticle, notifiedChannel } = card.data;
if (status.notifiedView !== notifiedView) {
await store.actions.clearCardChannelItems(guid, card.id);
await updateCardChannelItems(card.id, cardServer, cardToken, notifiedView, null);
await store.actions.setCardItemNotifiedChannel(guid, card.id, notifiedChannel);
await store.actions.setCardItemNotifiedView(guid, card.id, notifiedView);
clearCardChannel(card.id);
}
else {
if (status.notifiedChannel != notifiedChannel) {
await updateCardChannelItems(card.id, cardServer, cardToken, status.notifiedView, status.notifiedChannel)
await store.actions.setCardItemNotifiedChannel(guid, card.id, notifiedChannel);
}
}
if (status.notifiedProfile != notifiedProfile) {
const message = await getContactProfile(cardServer, cardToken);
await setCardProfile(server, appToken, card.id, message);
await store.actions.setCardItemNotifiedProfile(guid, card.id, notifiedProfile);
}
if (status.offsync) {
await store.actions.clearCardItemOffsync(guid, card.id);
setCardOffsync(card.id, false);
}
}
catch(err) {
console.log("card1:", err);
await store.actions.setCardItemOffsync(guid, card.id);
setCardOffsync(card.id, true);
}
}
await syncCard(card);
}
else {
//TODO clear card channel topics
@ -307,12 +275,65 @@ export function useCardContext() {
return;
}
if (resync.current.length > 0) {
const ids = resync.current;
resync.current = [];
for(let i = 0; i < ids.length; i++) {
const item = cards.current.get(ids[i]);
if (item) {
const card = await getCard(server, appToken, ids[i]);
await syncCard(card);
}
}
}
updateState({ cards: cards.current });
syncing.current = false;
sync();
}
};
const syncCard = async (card) => {
const { server, appToken, guid } = session.current;
const status = await store.actions.getCardItemStatus(guid, card.id);
const cardServer = status.profile.node;
const cardToken = status.profile.guid + '.' + status.detail.token;
if (status.detail.status === 'connected') {
try {
const { notifiedView, notifiedProfile, notifiedArticle, notifiedChannel } = card.data;
if (status.notifiedView !== notifiedView) {
await store.actions.clearCardChannelItems(guid, card.id);
await updateCardChannelItems(card.id, cardServer, cardToken, notifiedView, null);
await store.actions.setCardItemNotifiedChannel(guid, card.id, notifiedChannel);
await store.actions.setCardItemNotifiedView(guid, card.id, notifiedView);
clearCardChannel(card.id);
}
else {
if (status.notifiedChannel != notifiedChannel) {
await updateCardChannelItems(card.id, cardServer, cardToken, status.notifiedView, status.notifiedChannel)
await store.actions.setCardItemNotifiedChannel(guid, card.id, notifiedChannel);
}
}
if (status.notifiedProfile != notifiedProfile) {
const message = await getContactProfile(cardServer, cardToken);
await setCardProfile(server, appToken, card.id, message);
await store.actions.setCardItemNotifiedProfile(guid, card.id, notifiedProfile);
}
if (status.offsync) {
await store.actions.clearCardItemOffsync(guid, card.id);
setCardOffsync(card.id, 0);
}
}
catch(err) {
console.log("card1:", err);
await store.actions.setCardItemOffsync(guid, card.id);
setCardOffsync(card.id, 1);
}
}
}
const updateCardChannelItems = async (cardId, cardServer, cardToken, notifiedView, notifiedChannel) => {
const { guid } = session.current;
const delta = await getContactChannels(cardServer, cardToken, notifiedView, notifiedChannel);
@ -501,19 +522,19 @@ export function useCardContext() {
return await store.actions.clearCardChannelTopicItems(guid, cardId, channelId);
},
getChannelTopic: async (cardId, channelId, topicId) => {
const { detail, profile } = getCard(cardId);
const { detail, profile } = getCardEntry(cardId);
return await getContactChannelTopic(profile.node, `${profile.guid}.${detail.token}`, channelId, topicId);
},
getChannelTopics: async (cardId, channelId, revision) => {
const { detail, profile } = getCard(cardId);
const { detail, profile } = getCardEntry(cardId);
return await getContactChannelTopics(profile.node, `${profile.guid}.${detail.token}`, channelId, revision);
},
getChannelTopicAssetUrl: (cardId, channelId, topicId, assetId) => {
const { detail, profile } = getCard(cardId);
const { detail, profile } = getCardEntry(cardId);
return getContactChannelTopicAssetUrl(profile.node, `${profile.guid}.${detail.token}`, channelId, topicId, assetId);
},
addChannelTopic: async (cardId, channelId, message, files) => {
const { detail, profile } = getCard(cardId);
const { detail, profile } = getCardEntry(cardId);
const node = profile.node;
const token = `${profile.guid}.${detail.token}`;
if (files?.length > 0) {
@ -535,17 +556,21 @@ export function useCardContext() {
}
},
setChannelTopicSubject: async (cardId, channelId, topicId, data) => {
const { detail, profile } = getCard(cardId);
const { detail, profile } = getCardEntry(cardId);
return await setContactChannelTopicSubject(profile.node, `${profile.guid}.${detail.token}`, channelId, topicId, data);
},
removeChannel: async (cardId, channelId) => {
const { detail, profile } = getCard(cardId);
const { detail, profile } = getCardEntry(cardId);
return await removeContactChannel(profile.node, `${profile.guid}.${detail.token}`, channelId);
},
removeChannelTopic: async (cardId, channelId, topicId) => {
const { detail, profile } = getCard(cardId);
const { detail, profile } = getCardEntry(cardId);
return await removeContactChannelTopic(profile.node, `${profile.guid}.${detail.token}`, channelId, topicId);
},
resync: (cardId) => {
resync.current.push(cardId);
sync();
},
}
return { state, actions }

View File

@ -1,7 +1,7 @@
import { useEffect, useState, useRef, useContext } from 'react';
import SQLite from "react-native-sqlite-storage";
const DATABAG_DB = 'databag_v046.db';
const DATABAG_DB = 'databag_v047.db';
export function useStoreContext() {
const [state, setState] = useState({});

View File

@ -20,7 +20,10 @@ export function CardItem({ item, openContact }) {
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text>
<Text style={styles.handle} numberOfLines={1} ellipsizeMode={'tail'}>{ item.handle }</Text>
</View>
{ item.status === 'connected' && (
{ item.status === 'connected' && item.offsync === 1 && (
<View style={styles.offsync} />
)}
{ item.status === 'connected' && item.offsync !== 1 && (
<View style={styles.connected} />
)}
{ item.status === 'requested' && (

View File

@ -48,6 +48,12 @@ export const styles = StyleSheet.create({
borderRadius: 4,
backgroundColor: Colors.connecting,
},
offsync: {
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: Colors.error,
},
pending: {
width: 8,
height: 8,

View File

@ -31,7 +31,7 @@ export function useCards() {
const setCardItem = (item) => {
const { profile, detail } = item;
return {
cardId: item.cardId,
name: profile.name,
@ -39,6 +39,7 @@ export function useCards() {
status: detail.status,
offsync: item.offsync,
blocked: item.blocked,
offsync: item.offsync,
updated: detail.statusUpdated,
logo: profile.imageSet ? card.actions.getCardLogo(item.cardId, profile.revision) : 'avatar',
}

View File

@ -9,7 +9,18 @@ import Colors from 'constants/Colors';
export function ContactTitle({ contact, closeContact }) {
const { state, actions } = useContact(contact, closeContact);
return (<Text style={styles.title}>{ `${state.handle}@${state.node}` }</Text>);
return (
<TouchableOpacity style={styles.resync} activeOpacity={1} onPress={actions.resync}>
<View style={styles.icon} />
<Text style={styles.title}>{ `${state.handle}@${state.node}` }</Text>
<View style={styles.icon}>
{ state.offsync === 1 && (
<Ionicons name="exclamationcircleo" size={16} color={Colors.alert} />
)}
</View>
</TouchableOpacity>
);
}
export function Contact({ contact, closeContact }) {

View File

@ -18,6 +18,16 @@ export const styles = StyleSheet.create({
title: {
fontSize: 18,
},
resync: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
icon: {
width: 32,
paddingLeft: 8
},
drawer: {
paddingTop: 16,
},

View File

@ -18,7 +18,8 @@ export function useContact(contact, close) {
status: null,
cardId: null,
guid: null,
busy: false
busy: false,
offsync: false,
});
const dimensions = useWindowDimensions();
@ -42,10 +43,10 @@ export function useContact(contact, close) {
if (contact?.card) {
const selected = card.state.cards.get(contact.card);
if (selected) {
const { profile, detail, cardId } = selected;
const { offsync, profile, detail, cardId } = selected;
const { name, handle, node, location, description, guid, imageSet, revision } = profile;
const logo = imageSet ? card.actions.getCardLogo(cardId, revision) : 'avatar';
updateState({ name, handle, node, location, description, logo, cardId, guid, status: detail.status });
updateState({ offsync, name, handle, node, location, description, logo, cardId, guid, status: detail.status });
stateSet = true;
}
}
@ -56,12 +57,12 @@ export function useContact(contact, close) {
const { cardId, profile, detail } = selected;
const { name, handle, node, location, description, guid, imageSet, revision } = profile;
const logo = imageSet ? card.actions.getCardLogo(cardId, revision) : 'avatar';
updateState({ name, handle, node, location, description, logo, cardId, guid, status: detail.status });
updateState({ offsync, name, handle, node, location, description, logo, cardId, guid, status: detail.status });
stateSet = true;
}
else {
const { name, handle, node, location, description, logo, guid } = contact.account;
updateState({ name, handle, node, location, description, logo, guid, cardId: null, status: null });
updateState({ offsync: false, name, handle, node, location, description, logo, guid, cardId: null, status: null });
stateSet = true;
}
}
@ -176,6 +177,9 @@ export function useContact(contact, close) {
close();
});
},
resync: () => {
card.actions.resync(contact.card);
},
};
return { state, actions };