refactoring conversation context in mobiel app

This commit is contained in:
Roland Osborne 2023-02-13 16:09:31 -08:00
parent 7e03cdcc97
commit eca43835be
4 changed files with 364 additions and 643 deletions

View File

@ -82,12 +82,15 @@ export function useCardContext() {
};
};
const setCardChannelField = (cardId, channelId, field, value) => {
const setCardChannelField = (cardId, channelId, field, value, field2, value2) => {
const card = cards.current.get(cardId);
if (card) {
const channel = card.channels.get(channelId);
if (channel) {
channel[field] = value;
if(field2) {
channel[field2] = value2;
}
card.channels.set(channelId, { ...channel });
cards.current.set(cardId, { ...card });
}
@ -374,7 +377,7 @@ export function useCardContext() {
getTopics: async (cardId, channelId, revision, count, begin, end) => {
const { detail, profile } = cards.current.get(cardId) || {};
const cardToken = `${profile?.guid}.${detail?.token}`;
return await store.actions.getCardChannelTopicItems(guid, cardId, channelId);
return await getContactChannelTopics(profile?.node, cardToken, channelId);
},
getChannelTopic: async (cardId, channelId, topicId) => {
const { detail, profile } = cards.current.get(cardId) || {};
@ -401,6 +404,11 @@ export function useCardContext() {
await store.actions.setCardChannelItemTopicMarker(guid, cardId, channelId, marker);
setCardField(cardId, 'topicMarker', marker);
},
setChannelMarkerAndSync: async (cardId, channelId, marker, revision) => {
const { guid } = access.current;
await store.actions.setCardChannelItemMarkerAndSync(guid, cardId, channelId, marker, revision);
setCardField(cardId, 'topicMarker', marker, 'syncRevision', revision);
},
setCardFlag: async (cardId) => {
const { guid } = acccess.current;
await store.actions.setCardItemBlocked(guid, cardId);
@ -451,15 +459,15 @@ export function useCardContext() {
const { guid } = access.current;
return await store.actions.getCardChannelTopicItems(guid, cardId, channelId);
},
setChannelTopicItem: async (cardId, channelId, topicId, topic) => {
setTopicItem: async (cardId, channelId, topicId, topic) => {
const { guid } = access.current;
return await store.actions.setCardChannelTopicItem(guid, cardId, channelId, topicId, topic);
},
clearChannelTopicItem: async (cardId, channelId, topicId) => {
clearTopicItem: async (cardId, channelId, topicId) => {
const { guid } = access.current;
return await store.actions.clearCardChannelTopicItem(guid, cardId, channelId, topicId);
},
clearChannelTopicItems: async (cardId, channelId) => {
clearTopicItems: async (cardId, channelId) => {
const { guid } = access.current;
return await store.actions.clearCardChannelTopicItems(guid, cardId, channelId);
},

View File

@ -47,9 +47,12 @@ export function useChannelContext() {
}
}
const setChannelField = (channelId, field, value) => {
const setChannelField = (channelId, field, value, field2, value2) => {
const channel = channels.get(channelId) || {};
channel[field] = value;
if (field2) {
channel[field2] = value2;
}
channels.set(channelId, { ...channel });
updateState({ channels: channels.current });
};
@ -223,6 +226,11 @@ export function useChannelContext() {
await store.actions.setChannelItemTopicMarker(guid, channelId, revision);
setChannelField(channelId, 'topicMarker', marker);
},
setMarkerAndSync: async (channelId, marker, revision) => {
const { guid } = access.current;
await store.actions.setChannelItemMarkerAndSync(guid, channelId, revision);
setChannelField(channelId, 'topicMarker', marker, 'syncRevision', revision);
},
setChannelFlag: async (channelId) => {
const { guid } = access.current;
await store.actions.setChannelItemBlocked(guid, channelId);
@ -249,7 +257,7 @@ export function useChannelContext() {
const { server, guid } = access.current;
return await addFlag(server, guid, channelId, topicId);
},
getTopicItems: async (channelId, revision, count, begin, end) => {
getTopicItems: async (channelId) => {
const { guid } = access.current;
return await store.actions.getChannelTopicItems(guid, channelId);
},

View File

@ -8,670 +8,402 @@ import moment from 'moment';
import CryptoJS from 'crypto-js';
export function useConversationContext() {
const COUNT = 64;
const [state, setState] = useState({
topic: null,
subject: null,
logo: null,
revision: null,
contacts: [],
offsync: false,
topics: new Map(),
created: null,
host: null,
init: false,
progress: null,
cardId: null,
channelId: null,
pushEnabled: null,
locked: false,
unlocked: false,
seals: null,
card: null,
channel: null,
});
const store = useContext(StoreContext);
const upload = useContext(UploadContext);
const card = useContext(CardContext);
const channel = useContext(ChannelContext);
const profile = useContext(ProfileContext);
const topics = useRef(null);
const revision = useRef(null);
const force = useRef(false);
const more = useRef(false);
const detailRevision = useRef(0);
const syncing = useRef(false);
const conversationId = useRef(null);
const reset = useRef(false);
const setView = useRef(0);
const transfer = useRef(null);
const more = useRef(false);
const force = useRef(false);
const syncing = useRef(false);
const update = useRef(false);
const loaded = useRef(false);
const conversationId = useRef(null);
const topics = useRef(new Map());
const updateState = (value) => {
setState((s) => ({ ...s, ...value }))
}
useEffect(() => {
const { cardId, channelId } = state;
const key = cardId ? `${cardId}:${channelId}` : `:${channelId}`
const progress = upload.state.progress.get(key);
if (progress) {
let count = 0;
let complete = 0;
let active = 0;
let loaded = 0;
let total = 0;
let error = false;
progress.forEach(post => {
count += post.count;
complete += (post.index - 1);
if (post.active) {
active += 1;
loaded += post.active.loaded;
total += post.active.total;
}
if (post.error) {
error = true;
}
});
percent = Math.floor(((((loaded / total) * active) + complete) / count) * 100);
if (transfer.current == null || error || Math.abs(transfer.current - percent) > 5) {
updateState({ progress: percent, uploadError: error });
transfer.current = percent;
}
if (error) {
setTimeout(() => {
upload.actions.clearErrors(cardId, channelId);
updateState({ progress: null, uploadError: false });
transfer.current = null;
}, 2000);
}
}
else {
updateState({ progress: null });
transfer.current = null;
}
}, [upload, state.cardId, state.channelId]);
const getTopicItems = async (cardId, channelId) => {
if (cardId) {
return await card.actions.getChannelTopicItems(cardId, channelId);
}
return await channel.actions.getTopicItems(channelId);
}
const setTopicItem = async (cardId, channelId, topic) => {
if (cardId) {
return await card.actions.setChannelTopicItem(cardId, channelId, topic);
}
return await channel.actions.setTopicItem(channelId, topic);
}
const clearTopicItem = async (cardId, channelId, topicId) => {
if (cardId) {
return await card.actions.clearChannelTopicItem(cardId, channelId, topicId);
}
return await channel.actions.clearTopicItem(channelId, topicId);
}
const getTopic = async (cardId, channelId, topicId) => {
if (cardId) {
return await card.actions.getChannelTopic(cardId, channelId, topicId);
}
return await channel.actions.getTopic(channelId, topicId);
}
const getTopics = async (cardId, channelId, revision, begin, end) => {
if (cardId) {
return await card.actions.getChannelTopics(cardId, channelId, revision, 16, begin, end);
}
return await channel.actions.getTopics(channelId, revision, 16, begin, end)
}
const getTopicAssetUrl = (cardId, channelId, assetId) => {
if (cardId) {
return card.actions.getChannelTopicAssetUrl(cardId, channelId, topicId, assetId);
}
return channel.actions.getTopicAssetUrl(channelId, assetId);
}
const addTopic = async (cardId, channelId, message, asssets) => {
if (cardId) {
return await card.actions.addChannelTopic(cardId, channelId, message, assetId);
}
return await channel.actions.addTopic(channelId, message, assetId);
}
const setTopicSubject = async (cardId, channelId, topicId, dataType, data) => {
if (cardId) {
return await card.actions.setChannelTopicSubject(cardId, channelId, topicId, dataType, data);
}
return await channel.actions.setTopicSubject(channelId, topicId, dataType, data);
}
const remove = async (cardId, channelId) => {
if (cardId) {
return await card.actions.removeChannel(cardId, channelId);
}
return await channel.actions.remove(channelId);
}
const removeTopic = async (cardId, channelId, topicId) => {
if (cardId) {
return await card.actions.removeChannelTopic(cardId, channelId, topicId);
}
return await channel.actions.removeTopic(channelId, topicId);
}
const setNotifications = async (cardId, channelId, notify) => {
if (cardId) {
return await card.actions.setChannelNotifications(cardId, channelId, notify);
}
return await channel.actions.setNotifications(channelId, notify);
}
const getNotifications = async (cardId, channelId) => {
if (cardId) {
return await card.actions.getChannelNotifications(cardId, channelId);
}
return await channel.actions.getNotifications(channelId);
}
const setSyncRevision = async (cardId, channelId, revision) => {
if (cardId) {
return await card.actions.setSyncRevision(cardId, channelId, revision);
}
return await channel.actions.setSyncRevision(channelId, revision);
}
const setTopicMarker = async (cardId, channelId, marker) => {
if (cardId) {
return await card.actions.setTopicMarker(cardId, channelId, marker);
}
return await channel.actions.setTopicMarker(channelId, marker);
}
useEffect(() => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
const channelItem = getChannel(cardId, channelId);
if (channelItem) {
setChannel(channelItem);
}
}
}, [card, channel]);
const sync = async () => {
const curView = setView.current;
if (!syncing.current) {
if (reset.current) {
revision.current = null;
detailRevision.current = null;
topics.current = null;
reset.current = false;
}
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
const channelItem = getChannel(cardId, channelId);
if (!syncing.current && (reset.current || update.current || force.current || more.current)) {
const loadMore = more.current;
const ignoreRevision = force.current;
const conversation = converstaionId.current;
let curRevision, setRevision, marker;
if (channelItem && (channelItem.revision !== revision.current || force.current || more.current)) {
syncing.current = true;
try {
// sync from server
let res;
if (!topics.current) {
topics.current = new Map();
const items = await getTopicItems(cardId, channelId);
items.forEach(item => {
topics.current.set(item.topicId, item);
});
await setChannel(channelItem);
detailRevision.current = channelItem.detailRevision;
}
else if (detailRevision.current != channelItem.detailRevision) {
await setChannel(channelItem);
detailRevision.current = channelItem.detailRevision;
}
else if (more.current) {
more.current = false;
res = await getTopics(cardId, channelId, null, null, channelItem.topicMarker)
}
else if (channelItem.topicRevision !== channelItem.syncRevision || force.current) {
update.current = false;
force.current = false;
res = await getTopics(cardId, channelId, channelItem.syncRevision, channelItem.topicMarker)
loadMore.current = false;
if (reset.current) {
reset.current = false;
loaded.current = false;
topics.current = new Map();
updateState({ offsync: false, channel: null, card: null, topics: topics.current });
}
if (conversation) {
const { cardId, channelId } = conversation;
if (loaded.current) {
const cardValue = cardId ? card.state.cards.get(cardId) : null;
const channelValue = cardId ? cardValue?.get(channelId) : channel.state.channels.get(channelId);
if (channelValue) {
const { topicRevision, syncRevision, topicMarker } = channelValue;
curRevision = topicRevision;
setRevision = syncRevision;
marker = topicMarker;
updateState({ card: cardValue, channel: channelValue });
}
else {
if (cardId) {
card.actions.setChannelReadRevision(cardId, channelId, revision.current);
}
else {
channel.actions.setReadRevision(channelId, channelItem.revision);
}
revision.current = channelItem.revision;
}
if (res?.topics) {
for (const topic of res.topics) {
if (!topic.data) {
topics.current.delete(topic.id);
await clearTopicItem(cardId, channelId, topic.id);
}
else {
const cached = topics.current.get(topic.id);
if (!cached || cached.detailRevision != topic.data.detailRevision) {
if (!topic.data.topicDetail) {
const updated = await getTopic(cardId, channelId, topic.id);
topic.data = updated.data;
}
if (!topic.data) {
topics.current.delete(topic.id);
await clearTopicItem(cardId, channelId, topic.id);
}
else {
await setTopicItem(cardId, channelId, topic);
const { id, revision, data } = topic;
topics.current.set(id, { topicId: id, revision: revision, detailRevision: topic.data.detailRevision, detail: topic.data.topicDetail });
}
}
}
}
}
if (res?.marker) {
await setTopicMarker(cardId, channelId, res.marker);
}
if (res?.revision) {
await setSyncRevision(cardId, channelId, res.revision);
}
if (curView == setView.current) {
updateState({ topics: topics.current, init: true, error: false });
}
syncing.current = false;
sync();
}
catch(err) {
console.log(err);
syncing.current = false;
updateState({ error: true });
}
}
}
}
}
const getCard = (guid) => {
let contact = null
card.state.cards.forEach((card, cardId, map) => {
if (card?.profile?.guid === guid) {
contact = card;
}
});
return contact;
}
const getChannel = (cardId, channelId) => {
if (cardId) {
const entry = card.state.cards.get(cardId);
return entry?.channels.get(channelId);
}
return channel.state.channels.get(channelId);
}
const setChannel = async (item) => {
let contacts = [];
let logo = null;
let topic = null;
let subject = null;
let locked = false;
let unlocked = false;
let seals = null;
let timestamp;
const date = new Date(item.detail.created * 1000);
const now = new Date();
const offset = now.getTime() - date.getTime();
if(offset < 86400000) {
timestamp = moment(date).format('h:mma');
}
else if (offset < 31449600000) {
timestamp = moment(date).format('M/DD');
}
else {
timestamp = moment(date).format('M/DD/YYYY');
}
if (!item) {
updateState({ contacts, logo, subject, topic });
console.log("failed to load conversation");
sysncing.current = false;
return;
}
if (item.cardId) {
contacts.push(card.state.cards.get(item.cardId));
}
if (item?.detail?.members) {
const profileGuid = profile.state.identity.guid;
item.detail.members.forEach(guid => {
if (profileGuid !== guid) {
const contact = getCard(guid);
contacts.push(contact);
}
})
}
if (contacts.length === 0) {
logo = 'solution';
if (!loaded.current) {
const cardValue = cardId ? card.state.cards.get(cardId) : null;
const channelValue = cardId ? cardValue?.get(channelId) : channel.state.channels.get(channelId);
if (channelValue) {
const { topicRevision, syncRevision, topicMarker } = channelValue;
curRevision = topicRevision;
setRevision = syncRevision;
marker = topicMarker;
const topicItems = await getTopicItems(cardId, channelId);
for (let topic: topicItems) {
topics.current.set(topic.topicId, topic);
}
else if (contacts.length === 1) {
if (contacts[0]?.profile?.imageSet) {
logo = card.actions.getCardLogo(contacts[0].cardId, contacts[0].profileRevision);
updateState({ card: cardValue, channel: channelValue, topics: topics.current });
loaded.current = true;
}
else {
logo = 'avatar';
console.log("failed to load conversation");
syncing.current = false;
return;
}
}
else {
logo = 'appstore';
}
if (item?.detail?.dataType === 'sealed') {
locked = true;
unlocked = item.unsealedDetail != null;
if (item.unsealedDetail?.subject) {
topic = item.unsealedDetail.subject;
subject = topic;
}
try {
seals = JSON.parse(item.detail.data).seals;
if (!marker) {
const delta = await getTopicDelta(cardId, channelId, null, COUNT, null, null);
await setTopicDelta(cardId, channelId, delta.topics);
setMarkerAndSync(cardId, channelId, topicMarker, topicRevision);
}
if (loadMore && marker) {
const delta = await getTopicDelta(cardId, channelId, null, COUNT, null, marker);
await setTopicDelta(cardId, channelId, delta.topics);
setTopicMarker(cardId, channelId, delta.topicMarker);
}
if (ignoreRevision || curTopicRevision.current !== setTopicRevision.current) {
const delta = await getTopicDelta(cardId, channelId, setRevision, null, marker, null);
await setTopicDelta(cardId, channelId, delta.topics);
setSyncRevision(cardid, channelId, delta.topicRevision);
}
}
catch(err) {
console.log(err);
updateState({ offysnc: true });
syncing.current = false;
return
}
syncing.current = false;
await sync();
}
else {
if (item?.detail?.data) {
try {
topic = JSON.parse(item?.detail?.data).subject;
subject = topic;
}
catch (err) {
console.log(err);
}
}
}
if (!subject) {
if (contacts.length) {
let names = [];
for (let contact of contacts) {
if (contact?.profile?.name) {
names.push(contact.profile.name);
}
else if (contact?.profile?.handle) {
names.push(contact?.profile?.handle);
}
}
subject = names.join(', ');
}
else {
subject = "Notes";
}
}
const pushEnabled = await getNotifications(item.cardId, item.channelId);
const { enableImage, enableAudio, enableVideo } = item.detail;
updateState({ topic, subject, logo, contacts, host: item.cardId, created: timestamp,
enableImage, enableAudio, enableVideo, pushEnabled, locked, unlocked, seals });
const setTopicDelta(cardId, channelId, entries) => {
for (let entry of entries) {
if (entry.data) {
if (entry.data.detail) {
const item = mapTopicEntry(entry);
topics.current.set(item.topicId, item);
}
else {
const topic = await getTopic(cardId, channelId, entry.id);
const item = mapTopicEntry(entry);
topics.current.set(item.topicId, item);
}
}
else {
clearTopicItem(entry.id);
}
}
updateState({ offsync: false, topics: topics.current });
}
useEffect(() => {
update.current = true;
sync();
}, [card, channel]);
// eslint-disable-next-line
}, [card.state, channel.state]);
const actions = {
setChannel: (selected) => {
if (selected == null) {
setView.current++;
setConversation: async (cardId, channelId) => {
conversationId.current = { cardId, channelId };
reset.current = true;
await sync();
},
clearConversation: async ()
conversationId.current = null;
reset.current = true;
updateState({ subject: null, logo: null, locked: true, unlocked: false, contacts: [], topics: new Map() });
}
else if (selected.cardId !== conversationId.current?.cardId || selected.channelId !== conversationId.current?.channelId) {
setView.current++;
conversationId.current = selected;
reset.current = true;
updateState({ subject: null, logo: null, contacts: [], topics: new Map(), init: false,
cardId: selected.cardId, channelId: selected.channelId });
sync();
const { cardId, channelId, revision } = selected;
if (cardId) {
card.actions.setChannelReadRevision(cardId, channelId, revision);
}
else {
channel.actions.setReadRevision(channelId, revision);
}
}
await sync();
},
getTopicAssetUrl: (topicId, assetId) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
return card.actions.getChannelTopicAssetUrl(cardId, channelId, topicId, assetId);
}
else {
return channel.actions.getTopicAssetUrl(channelId, topicId, assetId);
}
}
return null;
},
addTopic: async (message, files) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
await card.actions.addChannelTopic(cardId, channelId, message, files);
}
else {
await channel.actions.addTopic(channelId, message, files);
}
force.current = true;
sync();
}
},
addSealedTopic: async (message, sealKey) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
await card.actions.addSealedChannelTopic(cardId, channelId, message, sealKey);
}
else {
await channel.actions.addSealedTopic(channelId, message, sealKey);
}
force.current = true;
sync();
}
},
unsealTopic: async (topicId, sealKey) => {
try {
const topic = topics.current.get(topicId);
const { messageEncrypted, messageIv } = JSON.parse(topic.detail.data);
const iv = CryptoJS.enc.Hex.parse(messageIv);
const key = CryptoJS.enc.Hex.parse(sealKey);
const enc = CryptoJS.enc.Base64.parse(messageEncrypted);
let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
topic.unsealedDetail = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
topics.current.set(topicId, { ...topic });
updateState({ topics: topics.current });
const { cardId, channelId } = conversationId.current;
if (cardId) {
await card.actions.setChannelTopicUnsealedDetail(cardId, channelId, topic.topicId, topic.detailRevision, topic.unsealedDetail);
}
else {
await channel.actions.setTopicUnsealedDetail(channelId, topic.topicId, topic.detailRevision, topic.unsealedDetail);
}
}
catch(err) {
console.log(err);
}
},
setSubject: async (subject) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
setChannelSubject: async (type, subject) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
throw new Error("can only set hosted channel subjects");
}
await channel.actions.setSubject(channelId, subject);
else if(channelId) {
await channel.actions.setSubject(channelId, type, subject);
}
},
setSealedSubject: async (subject, sealKey) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
removeChannel: async () => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
throw new Error("can only set hosted channel subjects");
await card.actions.removeChannel(cardId, channelId);
}
await channel.actions.setSealedSubject(channelId, subject, sealKey);
else if (channelId) {
await channel.actions.removeChannel(channelId);
}
},
remove: async () => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
await remove(cardId, channelId);
getNotifications: async () => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
await card.actions.getChannelNotifications(cardId, channelId);
}
else if (channelId) {
await channel.actions.getNotifications(channelId);
}
},
setNotifications: async (notify) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
await setNotifications(cardId, channelId, notify);
updateState({ pushEnabled: notify });
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
await card.actions.setChannelNotifications(cardId, channelId);
}
else if (channelId) {
await channel.actions.setNotifications(channelId, notify);
}
},
removeTopic: async (topicId) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
setChannelCard: async (id) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
await card.actions.removeChannelTopic(cardId, channelId, topicId);
throw new Error("can only set members on hosted channel");
}
else if (channelId) {
await channel.actions.setChannelCard(channelId, id);
}
},
clearChannelCard: async (id) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
throw new Error("can only clear members on hosted channel");
}
else if (channelId) {
await channel.actions.clearChannelCard(channelId, id);
}
},
addChannelAlert: async () => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
return await card.actions.addChannelAlert(cardId, channelId);
}
else if (channelId) {
return await channel.actions.addChannelAlert(channelId);
}
}
},
setChannelFlag: async () => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
await card.actions.setChannelFlag(cardId, channelId);
}
else if (channelId) {
await channel.actions.setChannelFlag(channelId);
}
},
clearChannelFlag: async () => {
const { cardId, channelId } = conversationId.current || {};
if (cardid) {
await card.actions.clearChannelFlag(cardId, channelId);
}
else if (channelId) {
await channel.actions.clearChannelFlag(channelId);
}
},
addTopic: async (type, message, files) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
await card.actions.addTopic(cardId, channelId, type, message, files);
}
else if (channelId) {
await channel.actions.addTopic(channelId, type, message, files);
}
force.current = true;
await sync();
},
removeTopic: async (topicId) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
await card.actions.removeTopic(cardId, channelId, topicId);
}
else {
await channel.actions.removeTopic(channelId, topicId);
}
force.current = true;
sync();
}
await sync();
},
setTopicSubject: async (topicId, data) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
unsealTopic: async (topicId, revision, unsealed) => {
const { cardId, channelId } = conversationId.current || {}
if (cardId) {
return await card.actions.setChannelTopicSubject(cardId, channelId, topicId, 'superbasictopic', data);
await card.actions.setUnsealedTopicSubject(cardId, channelId, topicId, revision, unsealed);
}
else {
return await channel.actions.setTopicSubject(channelId, topicId, 'superbasictopic', data);
else {channelId) {
await channel.actions.setUnsealedTopicSubject(channelId, topicId, revision, unsealed);
}
setTopicField(topicId, 'unsaledDetail', unsealed);
},
setTopicSubject: async (topicId, type, subject) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
await card.actions.setTopicSubject(cardId, channelId, topicId, type, subject);
}
else if (channelId) {
await channel.actions.setTopicSubject(channelId, topicId, type, subject);
}
force.current = true;
sync();
await sync();
},
setSealedTopicSubject: async (topicId, data, sealKey) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
const iv = CryptoJS.lib.WordArray.random(128 / 8);
const key = CryptoJS.enc.Hex.parse(sealKey);
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ message: data }), key, { iv: iv });
const messageEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
const messageIv = iv.toString();
addTopicAlert: async (topicId) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
return await card.actions.setChannelTopicSubject(cardId, channelId, topicId, 'sealedtopic', { messageEncrypted, messageIv });
return await card.actions.addTopicAlert(cardId, channelId, topicId);
}
else {
return await channel.actions.setTopicSubject(channelId, topicId, 'sealedtopic', { messageEncrypted, messageIv });
}
else if (channelId) {
return await channel.actions.addTopicAlert(channelId, topicId);
}
},
setCard: async (id) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
setTopicFlag: async (topicId) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
throw new Error("can only set members on hosted channel");
card.actions.setTopicFlag(cardId, channelId, topicId);
}
await channel.actions.setCard(channelId, id);
else if (channelId) {
channel.actions.setTopicFlag(channelId, topicId);
}
setTopicField(topicId, 'blocked', true);
},
clearCard: async (id) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
clearTopicFlag: async (topicId) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
throw new Error("can only clear members on hosted channel");
card.actions.clearTopicFlag(cardId, channelId, topicId);
}
await channel.actions.clearCard(channelId, id);
else if (channelId) {
channel.actions.clearTopicFlag(channelId, topicId);
}
setTopicField(topicId, 'blocked', false);
},
addReport: async () => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
return await card.actions.addChannelReport(cardId, channelId);
}
else {
return await channel.actions.addReport(channelId);
}
}
},
addTopicReport: async(topicId) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
return await card.actions.addChannelTopicReport(cardId, channelId, topicId);
}
else {
return await channel.actions.addTopicReport(channelId, topicId);
}
}
},
setBlocked: async () => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
await card.actions.setChannelBlocked(cardId, channelId);
}
else {
await channel.actions.setBlocked(channelId);
}
}
},
blockTopic: async (topicId) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
await card.actions.setChannelTopicBlocked(cardId, channelId, topicId);
}
else {
await channel.actions.setTopicBlocked(channelId, topicId);
}
const topic = topics.current.get(topicId);
if (topic) {
topic.blocked = 1;
force.current = true;
sync();
}
}
},
unblockTopic: async (cardId, channelId, topicId) => {
if (conversationId.current) {
if (conversationId.current.cardId == cardId && conversationId.current.channelId == channelId) {
const topic = topics.current.get(topicId);
if (topic) {
topic.blocked = 0;
force.current = true;
sync();
}
}
}
getTopicAssetUrl: (topicId, assetId) => {
const { cardId, channelId } = conversationId.current || {};
return getTopicAssetUrl(cardId, channelId, topicId, assetId);
},
loadMore: () => {
if (conversationId.current) {
more.current = true;
sync();
}
},
resync: () => {
if (conversationId.current) {
force.current = true;
sync();
}
},
}
const getTopicItems = async (cardId, channelId) => {
if (cardId) {
return await card.actions.getTopicItems(cardId, channelId);
}
return await channel.actions.getTopicItems(channelId);
}
const setTopicItem = async (cardId, channelId, topic) => {
if (cardId) {
return await card.actions.setTopicItem(cardId, channelId, topic);
}
return await channel.actions.setTopicItem(channelId, topic);
}
const clearTopicItem = async (cardId, channelId, topicId) => {
if (cardId) {
return await card.actions.clearTopicItem(cardId, channelId, topicId);
}
return await channel.actions.clearTopicItem(channelId, topicId);
}
const setTopicMarker = async (cardId, channelId, marker) => {
if (cardId) {
return await card.actions.setChannelTopicMarker(cardId, channelId, marker);
}
return await channel.actions.setTopicMarker(channelId, marker);
}
const setSyncRevision = async (cardId, channelId, revision) => {
if (cardId) {
return await card.actions.setChannelSyncRevision(cardId, channelId, revision);
}
return await channel.actions.setSyncRevision(channelid, revision);
}
const setMarkerAndSync = async (cardId, channelId, marker, revision) => {
if (cardId) {
return await card.actions.setChannelMarkerAndSync(cardId, channelId, marker, revision);
}
return await channel.actions.setMarkerAndSync(channelId, marker, revision);
}
const getTopicDelta = async (cardId, channelId, revision, count, begin, end) => {
if (cardId) {
return await card.actions.getTopics(cardId, channelId, revision, count, begin, end);
}
return await channel.actions.getTopics(channelId, revision, count, begin, end);
}
const getTopic = async (cardId, channelId, topicId) => {
if (cardId) {
return await card.actions.getTopic(cardId, channelId, topicId);
}
return await channel.actions.getTopic(channelId, topicId);
}
const mapTopicItem = (entry) => {
return {
topicId: entry.id,
revision: entry.revision,
detailRevision = entry.data?.detailRevision,
detail = entry.data?.topicDetail,
};
};
const setTopicField = (topicId, field, value) => {
const topic = topics.current.get(topicId);
if (topic) {
topic[field] = value;
}
topics.current.set(topicId, topic);
updateState({ topics: topics.current });
};
return { state, actions }
}

View File

@ -159,17 +159,6 @@ export function useStoreContext() {
blocked: values[0].blocked,
};
},
getCardItemView: async (guid, cardId) => {
const values = await getAppValues(db.current, `SELECT revision, detail_revision, profile_revision FROM card_${guid} WHERE card_id=?`, [cardId]);
if (!values.length) {
return null;
}
return {
revision: values[0].revision,
detailRevision: values[0].detail_revision,
profileRevision: values[0].profile_revision,
};
},
getCardItems: async (guid) => {
const values = await getAppValues(db.current, `SELECT card_id, revision, detail_revision, profile_revision, detail, profile, offsync, blocked, notified_view, notified_profile, notified_article, notified_channel FROM card_${guid}`, []);
return values.map(card => ({
@ -215,6 +204,9 @@ export function useStoreContext() {
setChannelItemTopicMarker: async (guid, channelId, marker) => {
await db.current.executeSql(`UPDATE channel_${guid} set topic_marker=? where channel_id=?`, [marker, channelId]);
},
setChannelItemMarkerAndSync: async (guid, channelId, marker, revision) => {
await db.current.executeSql(`UPDATE channel_${guid} set sync_revision=?, topic_marker=? where channel_id=?`, [revision, maker, channelId]);
},
setChannelItemBlocked: async (guid, channelId) => {
await db.current.executeSql(`UPDATE channel_${guid} set blocked=? where channel_id=?`, [1, channelId]);
},
@ -233,17 +225,6 @@ export function useStoreContext() {
setChannelItemUnsealedSummary: async (guid, channelId, revision, unsealed) => {
await db.current.executeSql(`UPDATE channel_${guid} set unsealed_summary=? where topic_revision=? AND channel_id=?`, [encodeObject(unsealed), revision, channelId]);
},
getChannelItemView: async (guid, channelId) => {
const values = await getAppValues(db.current, `SELECT revision, detail_revision, topic_revision FROM channel_${guid} WHERE channel_id=?`, [channelId]);
if (!values.length) {
return null;
}
return {
revision: values[0].revision,
detailRevision: values[0].detail_revision,
topicRevision: values[0].topic_revision,
};
},
getChannelItems: async (guid) => {
const values = await getAppValues(db.current, `SELECT channel_id, read_revision, revision, sync_revision, blocked, detail_revision, topic_revision, topic_marker, detail, unsealed_detail, summary, unsealed_summary FROM channel_${guid}`, []);
return values.map(channel => ({
@ -318,6 +299,9 @@ export function useStoreContext() {
setCardChannelItemTopicMarker: async (guid, cardId, channelId, marker) => {
await db.current.executeSql(`UPDATE card_channel_${guid} set topic_marker=? where card_id=? and channel_id=?`, [marker, cardId, channelId]);
},
setCardChannelItemMakerAndSync: async (guid, cardId, channelId, marker, revision) => {
await db.current.executeSql(`UPDATE card_channel_${guid} set topic_marker=?, sync_revision=? where card_id=? and channel_id=?`, [marker, revision, cardId, channelId]);
},
setCardChannelItemDetail: async (guid, cardId, channelId, revision, detail) => {
await db.current.executeSql(`UPDATE card_channel_${guid} set detail_revision=?, detail=?, unsealed_detail=null where card_id=? and channel_id=?`, [revision, encodeObject(detail), cardId, channelId]);
},
@ -330,17 +314,6 @@ export function useStoreContext() {
setCardChannelItemUnsealedSummary: async (guid, cardId, channelId, revision, unsealed) => {
await db.current.executeSql(`UPDATE card_channel_${guid} set unsealed_summary=? where topic_revision=? AND card_id=? AND channel_id=?`, [encodeObject(unsealed), revision, cardId, channelId]);
},
getCardChannelItemView: async (guid, cardId, channelId) => {
const values = await getAppValues(db.current, `SELECT revision, detail_revision, topic_revision FROM card_channel_${guid} WHERE card_id=? and channel_id=?`, [cardId, channelId]);
if (!values.length) {
return null;
}
return {
revision: values[0].revision,
detailRevision: values[0].detail_revision,
topicRevision: values[0].topic_revision,
};
},
getCardChannelItems: async (guid) => {
const values = await getAppValues(db.current, `SELECT card_id, channel_id, read_revision, sync_revision, revision, blocked, detail_revision, topic_revision, topic_marker, detail, unsealed_detail, summary, unsealed_summary FROM card_channel_${guid}`, []);
return values.map(channel => ({