mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
mergin refactored channel
This commit is contained in:
parent
3efa83f1c6
commit
233bcb01e9
@ -48,7 +48,7 @@ export function useAppContext() {
|
|||||||
}
|
}
|
||||||
access.current = await store.actions.init();
|
access.current = await store.actions.init();
|
||||||
if (access.current) {
|
if (access.current) {
|
||||||
await setSession(access.current);
|
await setSession();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
updateState({ session: false });
|
updateState({ session: false });
|
||||||
@ -58,7 +58,8 @@ export function useAppContext() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setSession = async () => {
|
const setSession = async () => {
|
||||||
updateState({ session: true, status: 'connecting' });
|
const { loginTimestamp } = access.current;
|
||||||
|
updateState({ session: true, loginTimestamp, status: 'connecting' });
|
||||||
await account.actions.setSession(access.current);
|
await account.actions.setSession(access.current);
|
||||||
await profile.actions.setSession(access.current);
|
await profile.actions.setSession(access.current);
|
||||||
await card.actions.setSession(access.current);
|
await card.actions.setSession(access.current);
|
||||||
|
@ -148,6 +148,10 @@ export function Session() {
|
|||||||
conversation.actions.setConversation(cardId, channelId);
|
conversation.actions.setConversation(cardId, channelId);
|
||||||
setChannel(true);
|
setChannel(true);
|
||||||
};
|
};
|
||||||
|
const clearConversation = () => {
|
||||||
|
conversation.actions.clearConversation();
|
||||||
|
setChannel(false);
|
||||||
|
};
|
||||||
const openDetails = () => {
|
const openDetails = () => {
|
||||||
navParams.detailNav.openDrawer();
|
navParams.detailNav.openDrawer();
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { View, Text, TextInput, TouchableOpacity } from 'react-native';
|
import { View, FlatList, Text, TextInput, TouchableOpacity } from 'react-native';
|
||||||
import Ionicons from 'react-native-vector-icons/AntDesign';
|
import Ionicons from 'react-native-vector-icons/AntDesign';
|
||||||
import { styles } from './Channels.styled';
|
import { styles } from './Channels.styled';
|
||||||
import { useChannels } from './useChannels.hook';
|
import { useChannels } from './useChannels.hook';
|
||||||
import { Colors } from 'constants/Colors';
|
import { Colors } from 'constants/Colors';
|
||||||
|
import { ChannelItem } from './channelItem/ChannelItem';
|
||||||
|
|
||||||
export function Channels({ navigation, openConversation }) {
|
export function Channels({ navigation, openConversation }) {
|
||||||
|
|
||||||
@ -40,9 +41,20 @@ export function Channels({ navigation, openConversation }) {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<View style={styles.content}>
|
{ state.channels.length == 0 && (
|
||||||
<Text>Channels</Text>
|
<View style={styles.content}>
|
||||||
</View>
|
<Text style={styles.notfoundtext}>No Topics Found</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
{ state.channels.length != 0 && (
|
||||||
|
<FlatList
|
||||||
|
style={styles.content}
|
||||||
|
data={state.channels}
|
||||||
|
initialNumToRender={25}
|
||||||
|
renderItem={({ item }) => <ChannelItem item={item} openConversation={openConversation} />}
|
||||||
|
keyExtractor={item => (`${item.cardId}:${item.channelId}`)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{ !navigation && (
|
{ !navigation && (
|
||||||
<View style={styles.columnbottom}>
|
<View style={styles.columnbottom}>
|
||||||
<TouchableOpacity style={styles.addbottom} onPress={actions.showAdding}>
|
<TouchableOpacity style={styles.addbottom} onPress={actions.showAdding}>
|
||||||
|
@ -60,6 +60,8 @@ export const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
|
flexShrink: 1,
|
||||||
|
paddingLeft: 4,
|
||||||
},
|
},
|
||||||
columnbottom: {
|
columnbottom: {
|
||||||
paddingLeft: 24,
|
paddingLeft: 24,
|
||||||
|
31
app/mobile/src/session/channels/channelItem/ChannelItem.jsx
Normal file
31
app/mobile/src/session/channels/channelItem/ChannelItem.jsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Text, View } from 'react-native';
|
||||||
|
import { TouchableOpacity } from 'react-native-gesture-handler';
|
||||||
|
import { Logo } from 'utils/Logo';
|
||||||
|
import { styles } from './ChannelItem.styled';
|
||||||
|
import { useChannelItem } from './useChannelItem.hook';
|
||||||
|
import Colors from 'constants/Colors';
|
||||||
|
import Ionicons from 'react-native-vector-icons/AntDesign';
|
||||||
|
|
||||||
|
export function ChannelItem({ item, openConversation }) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={() => openConversation(item.cardId, item.channelId, item.revision)}>
|
||||||
|
<Logo src={item.logo} width={32} height={32} radius={6} />
|
||||||
|
<View style={styles.detail}>
|
||||||
|
<View style={styles.subject}>
|
||||||
|
{ item.locked && !item.unlocked && (
|
||||||
|
<Ionicons name="lock" style={styles.subjectIcon} size={16} color={Colors.text} />
|
||||||
|
)}
|
||||||
|
{ item.locked && item.unlocked && (
|
||||||
|
<Ionicons name="lock-open-variant-outline" style={styles.subjectIcon} size={16} color={Colors.grey} />
|
||||||
|
)}
|
||||||
|
<Text style={styles.subjectText} numberOfLines={1} ellipsizeMode={'tail'}>{ item.subject }</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.message} numberOfLines={1} ellipsizeMode={'tail'}>{ item.message }</Text>
|
||||||
|
</View>
|
||||||
|
{ item.updated && (
|
||||||
|
<View style={styles.dot} />
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import { Colors } from 'constants/Colors';
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
height: 48,
|
||||||
|
alignItems: 'center',
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderColor: Colors.itemDivider,
|
||||||
|
paddingLeft: 16,
|
||||||
|
paddingRight: 16,
|
||||||
|
},
|
||||||
|
detail: {
|
||||||
|
paddingLeft: 12,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexGrow: 1,
|
||||||
|
flexShrink: 1,
|
||||||
|
},
|
||||||
|
subject: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
subjectIcon: {
|
||||||
|
paddingRight: 4,
|
||||||
|
},
|
||||||
|
subjectText: {
|
||||||
|
color: Colors.text,
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
color: Colors.disabled,
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
dot: {
|
||||||
|
width: 8,
|
||||||
|
height: 8,
|
||||||
|
borderRadius: 4,
|
||||||
|
backgroundColor: Colors.background,
|
||||||
|
}
|
||||||
|
})
|
@ -1,16 +1,163 @@
|
|||||||
import { useState } from 'react';
|
import { useState, useEffect, useContext } from 'react';
|
||||||
|
import { ChannelContext } from 'context/ChannelContext';
|
||||||
|
import { CardContext } from 'context/CardContext';
|
||||||
|
import { AccountContext } from 'context/AccountContext';
|
||||||
|
import { AppContext } from 'context/AppContext';
|
||||||
|
import { ProfileContext } from 'context/ProfileContext';
|
||||||
|
import { getChannelSeals, isUnsealed } from 'context/sealUtil';
|
||||||
|
import { getCardByGuid } from 'context/cardUtil';
|
||||||
|
|
||||||
export function useChannels() {
|
export function useChannels() {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
filter: null,
|
filter: null,
|
||||||
|
channels: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const channel = useContext(ChannelContext);
|
||||||
|
const card = useContext(CardContext);
|
||||||
|
const account = useContext(AccountContext);
|
||||||
|
const profile = useContext(ProfileContext);
|
||||||
|
const app = useContext(AppContext);
|
||||||
|
|
||||||
const updateState = (value) => {
|
const updateState = (value) => {
|
||||||
setState((s) => ({ ...s, ...value }));
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setChannelItem = (loginTimestamp, cardId, channelId, item) => {
|
||||||
|
const timestamp = item.summary.lastTopic.created;
|
||||||
|
const { readRevision, topicRevision } = item;
|
||||||
|
|
||||||
|
// extract or decrypt subject
|
||||||
|
let locked;
|
||||||
|
let unlocked;
|
||||||
|
let message;
|
||||||
|
let subject;
|
||||||
|
if (item.detail.dataType === 'sealed') {
|
||||||
|
locked = true;
|
||||||
|
const seals = getChannelSeals(item.detail.data);
|
||||||
|
if (isUnsealed(seals, account.state.sealKey)) {
|
||||||
|
unlocked = true;
|
||||||
|
if (item.detail.unsealedDetail) {
|
||||||
|
subject = item.detail.unsealedDetail.subject;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// decrypt detail
|
||||||
|
}
|
||||||
|
if (item.summary.lastTopic.dataType === 'sealedtopic') {
|
||||||
|
if (item.summary.unsealedSummary) {
|
||||||
|
message = item.detail.unsealedSummary.message;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// decrypt message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.detail.dataType === 'superbasic') {
|
||||||
|
locked = false;
|
||||||
|
unlocked = false;
|
||||||
|
try {
|
||||||
|
subject = JSON.parse(item.detail.data).subject;
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
if (item.summary.lastTopic.dataType === 'superbasictopic') {
|
||||||
|
try {
|
||||||
|
message = JSON.parse(item.summary.lastTopic.data).text;
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const contacts = [];
|
||||||
|
if (cardId) {
|
||||||
|
contacts.push(cardId);
|
||||||
|
}
|
||||||
|
item.detail.members.forEach(guid => {
|
||||||
|
if (guid !== profile.state.identity.guid) {
|
||||||
|
contacts.push(getCardByGuid(card.state.cards, guid)?.cardId);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!subject) {
|
||||||
|
if (contacts.length === 0) {
|
||||||
|
subject = 'Notes';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const names = [];
|
||||||
|
contacts.forEach(id => {
|
||||||
|
const contact = card.state.cards.get(id);
|
||||||
|
if (contact?.card.profile?.name) {
|
||||||
|
names.push(contact.card.profile.name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
names.push(contact?.card.profile?.handle);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
subject = names.join(', ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contacts.length === 0) {
|
||||||
|
logo = 'solution';
|
||||||
|
}
|
||||||
|
else if (contacts.length === 1) {
|
||||||
|
const contact = card.state.cards.get(contacts[0]);
|
||||||
|
if (contact?.card?.profile?.imageSet) {
|
||||||
|
logo = card.actions.getCardImageUrl(contacts[0])
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logo = 'avatar';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logo = 'appstore';
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = (loginTimestamp < timestamp) && (readRevision < topicRevision);
|
||||||
|
|
||||||
|
return { cardId, channelId, subject, message, logo, updated, locked, unlocked };
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { loginTimestamp } = app.state;
|
||||||
|
const channels = [];
|
||||||
|
channel.state.channels.forEach((item, channelId) => {
|
||||||
|
channels.push(setChannelItem(loginTimestamp, null, channelId, item));
|
||||||
|
});
|
||||||
|
card.state.cards.forEach((cardItem, cardId) => {
|
||||||
|
cardItem.channels.forEach((channelItem, channelId) => {
|
||||||
|
channels.push(setChannelItem(loginTimestamp, cardId, channelId, channelItem));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const filtered = channels.filter(item => {
|
||||||
|
if (!state.filter) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const filterCase = state.filter.toUpperCase();
|
||||||
|
const subjectCase = item.subject.toUpperCase();
|
||||||
|
return subjectCase.includes(filterCase);
|
||||||
|
});
|
||||||
|
const sorted = filtered.sort((a, b) => {
|
||||||
|
const aCreated = a?.timestamp;
|
||||||
|
const bCreated = b?.timestamp;
|
||||||
|
if (aCreated === bCreated) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!aCreated || aCreated < bCreated) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
});
|
||||||
|
updateState({ channels: sorted });
|
||||||
|
}, [app.state, card.state, channel.state, state.filter]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
setFilter: () => {
|
setFilter: (filter) => {
|
||||||
|
updateState({ filter });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user