merging refactored details

This commit is contained in:
Roland Osborne 2023-03-01 13:35:43 -08:00
parent 1e4f1cf819
commit dcc075383c
11 changed files with 193 additions and 39 deletions

View File

@ -366,7 +366,7 @@ export function useCardContext() {
return getCardImageUrl(server, token, cardId, profileRevision);
},
removeChannel: async (cardId, channelId) => {
const { detail, profile } = cards.current.get(cardId) || {};
const { detail, profile } = cards.current.get(cardId)?.card || {};
const cardToken = `${profile?.guid}.${detail?.token}`;
return await removeContactChannel(profile?.node, cardToken, channelId);
},

View File

@ -157,7 +157,6 @@ export function useConversationContext() {
clearConversation: async () => {
conversationId.current = null;
reset.current = true;
await sync();
},
setChannelSubject: async (type, subject) => {
const { cardId, channelId } = conversationId.current || {};

View File

@ -168,6 +168,8 @@ export function Session() {
useEffect(() => {
navParams.detailNav.closeDrawer();
setChannelId(null);
setCardId(null);
setChannel(false);
}, [navParams.closeCount]);
@ -263,20 +265,18 @@ export function Session() {
const DetailDrawerScreen = ({ navParams }) => {
const [closeCount, setCloseCount] = useState(0);
const closeConversation = () => {
const clearConversation = (navigation) => {
setCloseCount(closeCount+1);
};
return (
<DetailDrawer.Navigator screenOptions={{ ...drawerParams, drawerStyle: { width: '45%' } }} drawerContent={(props) => (
<ScrollView style={styles.drawer}>
<SafeAreaView edges={['top', 'bottom', 'right']}>
<Details closeConversation={closeConversation} />
</SafeAreaView>
</ScrollView>
<SafeAreaView style={styles.drawer} edges={['top', 'bottom', 'right']}>
<Details clearConversation={() => clearConversation(props.navigation)} />
</SafeAreaView>
)}>
<DetailDrawer.Screen name="contact">
{(props) => <ContactDrawerScreen navParams={{...navParams, detailNav: props.navigation}} />}
{(props) => <ContactDrawerScreen navParams={{...navParams, closeCount: closeCount, detailNav: props.navigation}} />}
</DetailDrawer.Screen>
</DetailDrawer.Navigator>
);

View File

@ -26,7 +26,8 @@ export function useChannels() {
const account = useContext(AccountContext);
const profile = useContext(ProfileContext);
const app = useContext(AppContext);
const filter = useRef();
const syncing = useRef(false);
const resync = useRef(false);
@ -154,6 +155,7 @@ export function useChannels() {
useEffect(() => {
syncChannels();
filter.current = state.filter;
}, [app.state, card.state, channel.state, state.filter, state.sealable]);
const syncChannels = async () => {
@ -179,10 +181,10 @@ export function useChannels() {
channels.push(await setChannelItem(loginTimestamp, cardId, channelId, channelItem));
}
const filtered = channels.filter(item => {
if (!state.filter) {
if (!filter.current) {
return true;
}
const filterCase = state.filter.toUpperCase();
const filterCase = filter.current.toUpperCase();
const subjectCase = item.subject.toUpperCase();
return subjectCase.includes(filterCase);
});

View File

@ -1,4 +1,4 @@
import { useEffect, useContext } from 'react';
import { useEffect, useState, useContext } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { ConversationContext } from 'context/ConversationContext';
import { useConversation } from './useConversation.hook';
@ -9,6 +9,7 @@ import { Logo } from 'utils/Logo';
export function Conversation({ navigation, cardId, channelId, closeConversation, openDetails }) {
const [ready, setReady] = useState(false);
const conversation = useContext(ConversationContext);
const { state, actions } = useConversation();
@ -30,21 +31,27 @@ export function Conversation({ navigation, cardId, channelId, closeConversation,
}, [navigation, state.subject]);
useEffect(() => {
conversation.actions.setConversation(cardId, channelId);
return () => { conversation.actions.clearConversation() };
(async () => {
setReady(false);
await conversation.actions.setConversation(cardId, channelId);
setReady(true);
})();
return () => { conversation.actions.clearConversation(); };
}, [cardId, channelId]);
return (
<View>
{ !navigation && (
<View style={styles.header}>
<TouchableOpacity style={styles.headertitle} onPress={openDetails}>
<Logo src={state.logo} width={32} height={32} radius={2} />
<Text style={styles.titletext}>{ state.subject }</Text>
<Ionicons name={'setting'} size={24} color={Colors.primary} style={styles.titlebutton} />
</TouchableOpacity>
{ ready && (
<TouchableOpacity style={styles.headertitle} onPress={openDetails}>
<Logo src={state.logo} width={32} height={32} radius={2} />
<Text style={styles.titletext} numberOfLines={1} ellipsizeMode={'tail'}>{ state.subject }</Text>
<Ionicons name={'setting'} size={24} color={Colors.primary} style={styles.titlebutton} />
</TouchableOpacity>
)}
<TouchableOpacity style={styles.headerclose} onPress={closeConversation}>
<Ionicons name={'close'} size={28} color={Colors.grey} style={styles.titlebutton} />
<Ionicons name={'close'} size={22} color={Colors.grey} style={styles.titlebutton} />
</TouchableOpacity>
</View>
)}

View File

@ -16,27 +16,31 @@ export const styles = StyleSheet.create({
flexGrow: 1,
borderBottomWidth: 1,
borderColor: Colors.divider,
height: 48,
marginLeft: 16,
marginRight: 16,
},
headertitle: {
display: 'flex',
flexShrink: 1,
flexDirection: 'row',
alignItems: 'center',
paddingLeft: 16,
paddingLeft: 8,
paddingTop: 8,
paddingBottom: 8,
},
titletext: {
fontSize: 18,
flexShrink: 1,
paddingLeft: 16,
paddingRight: 16,
},
titlebutton: {
paddingRight: 16,
paddingRight: 8,
},
headerclose: {
flexGrow: 1,
alignItems: 'flex-end',
paddingTop: 8,
},
});

View File

@ -5,11 +5,30 @@ import { Logo } from 'utils/Logo';
import AntIcons from 'react-native-vector-icons/AntDesign';
import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from 'constants/Colors';
import { MemberItem } from './memberItem/MemberItem';
export function Details({ channel, clearConversation }) {
const { state, actions } = useDetails();
const toggle = async (cardId, selected) => {
try {
if (selected) {
await actions.clearCard(cardId);
}
else {
await actions.setCard(cardId);
}
}
catch (err) {
console.log(err);
Alert.alert(
'Failed to Update Membership',
'Please try again.'
);
}
};
const saveSubject = async () => {
try {
await actions.saveSubject();
@ -199,8 +218,8 @@ export function Details({ channel, clearConversation }) {
</View>
<FlatList style={styles.cards}
data={state.contacts}
renderItem={({ item }) => <MemberItem hostId={state.hostId} editable={false} members={[]} item={item} />}
data={state.members}
renderItem={({ item }) => <MemberItem hostId={state.hostId} item={item} />}
keyExtractor={item => item.cardId}
/>
@ -242,7 +261,7 @@ export function Details({ channel, clearConversation }) {
<Text style={styles.editHeader}>Channel Members:</Text>
<FlatList style={styles.editMembers}
data={state.connected}
renderItem={({ item }) => <Text>MEMBER</Text> }
renderItem={({ item }) => <MemberItem item={item} toggle={toggle} />}
keyExtractor={item => item.cardId}
/>
<View style={styles.editControls}>

View File

@ -0,0 +1,31 @@
import { TouchableOpacity, Switch, Text, View } from 'react-native';
import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import { styles } from './MemberItem.styled';
import { Logo } from 'utils/Logo';
import { Colors } from 'constants/Colors';
export function MemberItem({ item, hostId, toggle }) {
const select = () => {
if (toggle) {
toggle(item.cardId, item.selected);
}
};
return (
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={select}>
<Logo src={item.logo} width={32} height={32} radius={6} />
<View style={styles.detail}>
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text>
<Text style={styles.handle} numberOfLines={1} ellipsizeMode={'tail'}>{ item.handle }</Text>
</View>
{ hostId === item.cardId && (
<MatIcons name="server" size={20} color={Colors.grey} />
)}
{ toggle && (
<Switch style={styles.switch} trackColor={styles.track} value={item.selected} onValueChange={select} />
)}
</TouchableOpacity>
);
}

View File

@ -0,0 +1,42 @@
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: 8,
paddingRight: 8,
},
detail: {
paddingLeft: 12,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
flexGrow: 1,
flexShrink: 1,
},
space: {
height: 64,
},
name: {
color: Colors.text,
fontSize: 14,
},
handle: {
color: Colors.text,
fontSize: 12,
},
track: {
false: Colors.grey,
true: Colors.background,
},
switch: {
transform: [{ scaleX: .7 }, { scaleY: .7 }],
},
});

View File

@ -5,6 +5,7 @@ import { CardContext } from 'context/CardContext';
import { AccountContext } from 'context/AccountContext';
import { ProfileContext } from 'context/ProfileContext';
import { getChannelSubjectLogo } from 'context/channelUtil';
import { getCardByGuid } from 'context/cardUtil';
import { getChannelSeals, isUnsealed, getContentKey, updateChannelSubject } from 'context/sealUtil';
import moment from 'moment';
@ -23,11 +24,11 @@ export function useDetails() {
pushEnabled: false,
locked: false,
unlocked: false,
count: 0,
seals: null,
sealKey: null,
deleteBusy: false,
blockBusy: false,
unknown: 0,
});
const card = useContext(CardContext);
@ -64,18 +65,49 @@ export function useDetails() {
updateState({ locked, unlocked, seals, sealKey, notification });
}, [account.state, conversation.state]);
useEffect(() => {
const connected = [];
card.state.cards.forEach(contact => {
if (contact?.card?.detail?.status === 'connected') {
connected.push(contact.card);
}
});
updateState({ connected });
}, [card.state]);
const setMemberItem = (contact, guids) => {
return {
cardId: contact?.cardId,
name: contact?.profile?.name,
handle: contact?.profile?.handle,
node: contact?.profile?.node,
logo: contact?.profile?.imageSet ? card.actions.getCardImageUrl(contact.cardId) : 'avatar',
selected: guids.includes(contact?.profile?.guid),
}
};
useEffect(() => {
const hostId = conversation.state.card?.cardId;
let unknown = 0;
let members = new Map();
const host = conversation.state.card;
if (host) {
members.set(host.card?.cardId, setMemberItem(host.card, []));
}
const guids = conversation.state.channel?.detail?.members || [];
guids.forEach(guid => {
if (guid !== profile.state.identity?.guid) {
const contact = getCardByGuid(card.state.cards, guid);
if (contact) {
members.set(contact.card?.cardId, setMemberItem(contact.card, []));
}
else {
unknown++;
}
}
});
const connected = new Map();
card.state.cards.forEach(contact => {
if (contact?.card?.detail?.status === 'connected') {
connected.set(contact.card?.cardId, setMemberItem(contact.card, guids));
}
});
updateState({ connected: Array.from(connected.values()), members: Array.from(members.values()), unknown });
}, [card.state, conversation.state]);
useEffect(() => {
const hostId = conversation.state.card?.card.cardId;
const profileGuid = profile.state.identity?.guid;
const channel = conversation.state.channel;
const cards = card.state.cards;
@ -128,6 +160,24 @@ export function useDetails() {
setSubjectUpdate: (subjectUpdate) => {
updateState({ subjectUpdate });
},
setCard: async (cardId) => {
updateState({ connected: state.connected.map(contact => {
if(contact.cardId === cardId) {
return { ...contact, selected: true }
}
return contact;
}) });
await conversation.actions.setChannelCard(cardId);
},
clearCard: async (cardId) => {
updateState({ connected: state.connected.map(contact => {
if(contact.cardId === cardId) {
return { ...contact, selected: false }
}
return contact;
}) });
await conversation.actions.clearChannelCard(cardId);
},
saveSubject: async () => {
if (state.locked) {
const contentKey = await getContentKey(state.seals, state.sealKey);

View File

@ -69,7 +69,7 @@ export function useBlockedTopics() {
});
channel.state.channels.forEach((channelItem, channelId, map) => {
if (channelItem.blocked) {
marged.push({ channel: channelItem });
merged.push({ channel: channelItem });
}
});
const items = merged.map(setChannelItem);