diff --git a/app/mobile/src/context/useConversationContext.hook.js b/app/mobile/src/context/useConversationContext.hook.js index c9712b67..cfa03fae 100644 --- a/app/mobile/src/context/useConversationContext.hook.js +++ b/app/mobile/src/context/useConversationContext.hook.js @@ -87,16 +87,18 @@ export function useConversationContext() { if (!curTopicMarker.current) { const delta = await getTopicDelta(cardId, channelId, null, COUNT, null, null); await setTopicDelta(cardId, channelId, delta.topics); - await setMarkerAndSync(cardId, channelId, delta.marker, delta.revision); - curTopicMarker.current = delta.marker; + const marker = delta.marker ? delta.marker : 1; + await setMarkerAndSync(cardId, channelId, marker, delta.revision); + curTopicMarker.current = marker; curSyncRevision.current = delta.revision; updateState({ loaded: true, offsync: false, topics: topics.current, card: cardValue, channel: channelValue }); } else if (loadMore && marker) { const delta = await getTopicDelta(cardId, channelId, null, COUNT, null, curTopicMarker.current); + const marker = delta.marker ? delta.marker : 1; await setTopicDelta(cardId, channelId, delta.topics); - await setTopicMarker(cardId, channelId, delta.marker); - curTopicMarker.current = delta.marker; + await setTopicMarker(cardId, channelId, marker); + curTopicMarker.current = marker; updateState({ loaded: true, offsync: false, topics: topics.current, card: cardValue, channel: channelValue }); } else if (ignoreRevision || topicRevision > curSyncRevision.current) { @@ -105,8 +107,6 @@ export function useConversationContext() { await setSyncRevision(cardId, channelId, delta.revision); curSyncRevision.current = delta.revision; updateState({ loaded: true, offsync: false, topics: topics.current, card: cardValue, channel: channelValue }); - -console.log("HEADER", delta); } else { updateState({ loaded: true, offsync: false, topics: topics.current, card: cardValue, channel: channelValue }); @@ -419,7 +419,6 @@ console.log("HEADER", delta); topic[field] = value; } topics.current.set(topicId, { ...topic }); - updateState({ topics: topics.current }); }; return { state, actions } diff --git a/app/mobile/src/context/useStoreContext.hook.js b/app/mobile/src/context/useStoreContext.hook.js index a66dbfa9..494f2023 100644 --- a/app/mobile/src/context/useStoreContext.hook.js +++ b/app/mobile/src/context/useStoreContext.hook.js @@ -1,7 +1,7 @@ import { useEffect, useState, useRef, useContext } from 'react'; import SQLite from "react-native-sqlite-storage"; -const DATABAG_DB = 'db_v_123.db'; +const DATABAG_DB = 'db_v_126.db'; export function useStoreContext() { const [state, setState] = useState({}); diff --git a/app/mobile/src/session/conversation/Conversation.jsx b/app/mobile/src/session/conversation/Conversation.jsx index cca13115..9a73cb46 100644 --- a/app/mobile/src/session/conversation/Conversation.jsx +++ b/app/mobile/src/session/conversation/Conversation.jsx @@ -56,7 +56,7 @@ export function Conversation({ navigation, cardId, channelId, closeConversation, ), }); } - }, [navigation, state.subject]); + }, [navigation, state.subject, state.loaded]); useEffect(() => { return () => { closeConversation(); }; @@ -85,7 +85,7 @@ export function Conversation({ navigation, cardId, channelId, closeConversation, )} - { state.loaded && ( + { state.loaded && state.topics.length !== 0 && ( actions.setFocus(item.topicId)} hosting={state.host == null} - sealed={state.sealed} sealKey={state.sealKey} remove={actions.removeTopic} update={actions.editTopic} block={actions.blockTopic} - report={actions.reportTopic} />} + report={actions.reportTopic} contentKey={state.contentKey} /> } keyExtractor={item => item.topicId} /> )} + { state.loaded && state.topics.length === 0 && ( + + Empty Topic + + )} - + ); diff --git a/app/mobile/src/session/conversation/Conversation.styled.js b/app/mobile/src/session/conversation/Conversation.styled.js index 18b595a6..0284f4b4 100644 --- a/app/mobile/src/session/conversation/Conversation.styled.js +++ b/app/mobile/src/session/conversation/Conversation.styled.js @@ -67,5 +67,15 @@ export const styles = StyleSheet.create({ alignItems: 'center', justifyContent: 'center', }, + empty: { + display: 'flex', + flexGrow: 1, + alignItems: 'center', + justifyContent: 'center', + }, + emptytext: { + fontSize: 18, + color: Colors.disabled, + }, }); diff --git a/app/mobile/src/session/conversation/addTopic/AddTopic.jsx b/app/mobile/src/session/conversation/addTopic/AddTopic.jsx index 5d5a4a0a..254dcc1d 100644 --- a/app/mobile/src/session/conversation/addTopic/AddTopic.jsx +++ b/app/mobile/src/session/conversation/addTopic/AddTopic.jsx @@ -13,9 +13,9 @@ import { VideoFile } from './videoFile/VideoFile'; import { AudioFile } from './audioFile/AudioFile'; import { ImageFile } from './imageFile/ImageFile'; -export function AddTopic({ sealed, sealKey }) { +export function AddTopic({ contentKey }) { - const { state, actions } = useAddTopic(sealed, sealKey); + const { state, actions } = useAddTopic(contentKey); const message = useRef(); const addImage = async () => { @@ -132,22 +132,22 @@ export function AddTopic({ sealed, sealKey }) { onSubmitEditing={sendMessage} returnKeyType="send" autoCapitalize="sentences" placeholder="New Message" multiline={true} /> - { !sealed && state.enableImage && ( + { !state.locked && state.enableImage && ( )} - { !sealed && state.enableVideo && ( + { !state.locked && state.enableVideo && ( )} - { !sealed && state.enableAudio && ( + { !state.locked && state.enableAudio && ( )} - { !sealed && ( + { !state.locked && ( )} @@ -161,10 +161,13 @@ export function AddTopic({ sealed, sealKey }) { { state.busy && ( )} - { !state.busy && (state.message || state.assets.length > 0) && ( + { state.locked && !contentKey && ( + + )} + { !state.busy && (!state.locked || contentKey) && (state.message || state.assets.length > 0) && ( )} - { !state.busy && !(state.message || state.assets.length > 0) && ( + { !state.busy && (!state.locked || contentKey) && !(state.message || state.assets.length > 0) && ( )} diff --git a/app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js b/app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js index 596cfebf..92388275 100644 --- a/app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js +++ b/app/mobile/src/session/conversation/addTopic/useAddTopic.hook.js @@ -5,7 +5,7 @@ import Colors from 'constants/Colors'; import { getChannelSeals, getContentKey, encryptTopicSubject } from 'context/sealUtil'; import { AccountContext } from 'context/AccountContext'; -export function useAddTopic(sealed, sealKey) { +export function useAddTopic(contentKey) { const [state, setState] = useState({ message: null, @@ -21,6 +21,7 @@ export function useAddTopic(sealed, sealKey) { enableImage: false, enableAudio: false, enableVideo: false, + locked: true, }); const assetId = useRef(0); @@ -33,7 +34,8 @@ export function useAddTopic(sealed, sealKey) { useEffect(() => { const { enableVideo, enableAudio, enableImage } = conversation.state.channel?.detail || {}; - updateState({ enableImage, enableAudio, enableVideo }); + const locked = conversation.state.channel?.detail?.dataType === 'superbasic' ? false : true; + updateState({ enableImage, enableAudio, enableVideo, locked }); }, [conversation.state]); const actions = { @@ -107,20 +109,12 @@ export function useAddTopic(sealed, sealKey) { updateState({ color, colorSet: true }); }, addTopic: async () => { - if (!state.busy) { + if (!state.busy && (!state.locked || contentKey)) { try { updateState({ busy: true }); - let contentKey; - const type = conversation.state.channel?.detail?.dataType === 'superbasic' ? 'superbasictopic' : 'sealedtopic'; - if (type === 'sealedtopic') { - const channelDetail = conversation.state.channel?.detail; - const seals = getChannelSeals(channelDetail?.data); - const sealKey = account.state.sealKey; - contentKey = await getContentKey(seals, sealKey); - } const assemble = (assets) => { - if (type === 'superbasictopic') { + if (!state.locked) { if (assets?.length) { return { assets, @@ -146,6 +140,7 @@ export function useAddTopic(sealed, sealKey) { return encryptTopicSubject({ message }, contentKey); } }; + const type = state.locked ? "sealedtopic" : "superbasictopic"; await conversation.actions.addTopic(type, assemble, state.assets); updateState({ busy: false, assets: [], message: null, size: 'medium', sizeSet: false, textSize: 14, diff --git a/app/mobile/src/session/conversation/topicItem/useTopicItem.hook.js b/app/mobile/src/session/conversation/topicItem/useTopicItem.hook.js index c1029ca2..1a74bc48 100644 --- a/app/mobile/src/session/conversation/topicItem/useTopicItem.hook.js +++ b/app/mobile/src/session/conversation/topicItem/useTopicItem.hook.js @@ -7,7 +7,7 @@ import moment from 'moment'; import { useWindowDimensions } from 'react-native'; import Colors from 'constants/Colors'; import { getCardByGuid } from 'context/cardUtil'; -import { getChannelSeals, isUnsealed, getContentKey, decryptTopicSubject } from 'context/sealUtil'; +import { decryptTopicSubject } from 'context/sealUtil'; export function useTopicItem(item, hosting, remove, contentKey) { @@ -118,9 +118,26 @@ export function useTopicItem(item, hosting, remove, contentKey) { } } else if (dataType === 'sealedtopic') { - if (unsealedDetail) { + let unsealed = unsealedDetail; + if (!unsealed && contentKey) { + try { + unsealed = decryptTopicSubject(detail?.data, contentKey); + (async () => { + try { + await conversation.actions.unsealTopic(topicId, revision, unsealed); + } + catch(err) { + console.log(err); + } + })(); + } + catch(err) { + console.log(err); + } + } + if (unsealed) { sealed = false; - parsed = unsealedDetail.message; + parsed = unsealed.message; message = parsed?.text; if (parsed?.textSize === 'small') { fontSize = 10; @@ -140,7 +157,6 @@ export function useTopicItem(item, hosting, remove, contentKey) { } else { sealed = true; - unsealTopic(topicId, revision, detail); } } @@ -162,18 +178,15 @@ export function useTopicItem(item, hosting, remove, contentKey) { const deletable = editable || hosting; updateState({ logo, name, nameSet, known, sealed, message, fontSize, fontColor, timestamp, transform, status, assets, deletable, editable, editData: parsed, editMessage: message }); - }, [conversation.state, card.state, account.state, item]); + }, [conversation.state, card.state, account.state, item, contentKey]); const unsealTopic = async (topicId, revision, topicDetail) => { try { -console.log("UNSEAL", topicId); const channelDetail = conversation.state.channel?.detail; const seals = getChannelSeals(channelDetail?.data); const sealKey = account.state.sealKey; if (isUnsealed(seals, sealKey)) { const contentKey = await getContentKey(seals, sealKey); - const unsealed = decryptTopicSubject(topicDetail.data, contentKey); - await conversation.actions.unsealTopic(topicId, revision, unsealed); } } catch(err) { diff --git a/app/mobile/src/session/conversation/useConversation.hook.js b/app/mobile/src/session/conversation/useConversation.hook.js index 7c6abd6d..b3cc807d 100644 --- a/app/mobile/src/session/conversation/useConversation.hook.js +++ b/app/mobile/src/session/conversation/useConversation.hook.js @@ -4,6 +4,7 @@ import { CardContext } from 'context/CardContext'; import { AccountContext } from 'context/AccountContext'; import { ConversationContext } from 'context/ConversationContext'; import { getChannelSubjectLogo } from 'context/channelUtil'; +import { getChannelSeals, isUnsealed, getContentKey, decryptTopicSubject } from 'context/sealUtil'; export function useConversation() { const [state, setState] = useState({ @@ -11,6 +12,7 @@ export function useConversation() { logo: null, topic: [], loaded: false, + contentKey: null, }); const updateState = (value) => { @@ -22,6 +24,42 @@ export function useConversation() { const conversation = useContext(ConversationContext); const account = useContext(AccountContext); + const contentKey = useRef(); + const keyId = useRef(); + + useEffect(() => { + setContentKey(); + }, [conversation.state, account.state]); + + const setContentKey = async () => { + const type = conversation.state.channel?.detail?.dataType; + if (type === 'sealed') { + const cardId = conversation.state.card?.card?.cardId; + const channelId = conversation.state.channel?.channelId; + const contentId = `${cardId}:${channelId}`; + if (contentId !== keyId.current) { + const channelDetail = conversation.state.channel?.detail; + const seals = getChannelSeals(channelDetail?.data); + const sealKey = account.state.sealKey; + if (isUnsealed(seals, sealKey)) { + contentKey.current = await getContentKey(seals, sealKey); + keyId.current = contentId; + updateState({ contentKey: contentKey.current }); + } + else if (keyId.current != null) { + contentKey.current = null; + keyId.current = null; + updateState({ contentKey: null }); + } + } + } + else if (keyId.current != null) { + contentKey.current = null; + keyId.current = null; + updateState({ contentKey: null }); + } + }; + useEffect(() => { const loaded = conversation.state.loaded; const cardId = conversation.state.card?.cardId;