refactored details page

This commit is contained in:
Roland Osborne 2023-09-25 14:35:09 -07:00
parent 408a16f018
commit fa2927d5ba
7 changed files with 159 additions and 73 deletions

View File

@ -109,6 +109,7 @@ const Strings = [
actionDelete: 'Delete', actionDelete: 'Delete',
actionBlock: 'Block', actionBlock: 'Block',
actionReport: 'Report', actionReport: 'Report',
actionLeave: 'Leave',
// contact list page // contact list page
add: 'Add', add: 'Add',
@ -137,6 +138,10 @@ const Strings = [
members: 'Members', members: 'Members',
editSubject: 'Edit Subject', editSubject: 'Edit Subject',
topicMembers: 'Topic Members', topicMembers: 'Topic Members',
leaveTopic: 'Leave Topic',
deleteTopic: 'Delete Topic',
blockTopic: 'Block Topic',
reportTopic: 'Report Topic',
}, },
{ {
visibleRegistry: 'Visible dans le Registre', visibleRegistry: 'Visible dans le Registre',
@ -271,6 +276,10 @@ const Strings = [
members: 'Membres', members: 'Membres',
editSubject: 'Modifier le Title', editSubject: 'Modifier le Title',
topicMembers: 'Membres du Sujet', topicMembers: 'Membres du Sujet',
leaveTopic: 'Quitter le Sujet',
deleteTopic: 'Supprimer le Sujet',
blockTopic: 'Bloquer le Sujet',
reportTopic: 'Signaler le Sujet',
}, },
{ {
visibleRegistry: 'Visible en el Registro', visibleRegistry: 'Visible en el Registro',
@ -405,6 +414,10 @@ const Strings = [
members: 'Miembros', members: 'Miembros',
editSubject: 'Editar Título', editSubject: 'Editar Título',
topicMembers: 'Miembros del Tema', topicMembers: 'Miembros del Tema',
leaveTopic: 'Dejar el Tema',
deleteTopic: 'Borrar el Tema',
blockTopic: 'Bloquer el Tema',
reportTopic: 'Reportar el Tema',
}, },
{ {
visibleRegistry: 'Sichtbar in der Registrierung', visibleRegistry: 'Sichtbar in der Registrierung',
@ -539,6 +552,10 @@ const Strings = [
members: 'Mitglieder', members: 'Mitglieder',
editSubject: 'Titel bearbeiten', editSubject: 'Titel bearbeiten',
topicMembers: 'Themenmitglieder', topicMembers: 'Themenmitglieder',
leaveTopic: 'Verlasse das Thema',
deleteTopic: 'Das Thema Löschen',
blockTopic: 'Blockiere das Thema',
reportTopic: 'Das Thema Melden',
} }
]; ];

View File

@ -39,7 +39,7 @@ export function useChannels() {
const setChannelItem = async (loginTimestamp, cardId, channelId, item) => { const setChannelItem = async (loginTimestamp, cardId, channelId, item) => {
const timestamp = item.summary.lastTopic.created; const timestamp = item.summary.lastTopic.created;
const { readRevision, topicRevision } = item; const { readRevision, topicRevision, blocked } = item;
// decrypt subject and message // decrypt subject and message
let locked = false; let locked = false;
@ -113,7 +113,7 @@ export function useChannels() {
const updated = (loginTimestamp < timestamp) && (readRevision < topicRevision); const updated = (loginTimestamp < timestamp) && (readRevision < topicRevision);
return { cardId, channelId, subject, message, logo, timestamp, updated, locked, unlocked }; return { cardId, channelId, subject, message, logo, timestamp, updated, locked, unlocked, blocked };
} }
useEffect(() => { useEffect(() => {
@ -176,7 +176,6 @@ export function useChannels() {
items.push({ loginTimestamp, channelId, channelItem: item }); items.push({ loginTimestamp, channelId, channelItem: item });
}); });
card.state.cards.forEach((cardItem, cardId) => { card.state.cards.forEach((cardItem, cardId) => {
cardItem.channels.forEach((channelItem, channelId) => { cardItem.channels.forEach((channelItem, channelId) => {
items.push({ loginTimestamp, cardId, channelId, channelItem }); items.push({ loginTimestamp, cardId, channelId, channelItem });
}); });
@ -187,6 +186,9 @@ export function useChannels() {
channels.push(await setChannelItem(loginTimestamp, cardId, channelId, channelItem)); channels.push(await setChannelItem(loginTimestamp, cardId, channelId, channelItem));
} }
const filtered = channels.filter(item => { const filtered = channels.filter(item => {
if (item.blocked) {
return false;
}
if (!filter.current) { if (!filter.current) {
return true; return true;
} }

View File

@ -1,4 +1,5 @@
import { ActivityIndicator, KeyboardAvoidingView, FlatList, Alert, Modal, View, Text, Switch, TouchableOpacity, TextInput } from 'react-native'; import { ActivityIndicator, KeyboardAvoidingView, FlatList, Alert, Modal, View, Text, Switch, TouchableOpacity, TextInput } from 'react-native';
import { useState } from 'react';
import { styles } from './Details.styled'; import { styles } from './Details.styled';
import { useDetails } from './useDetails.hook'; import { useDetails } from './useDetails.hook';
import { Logo } from 'utils/Logo'; import { Logo } from 'utils/Logo';
@ -11,7 +12,8 @@ import { InputField } from 'utils/InputField';
export function Details({ channel, clearConversation }) { export function Details({ channel, clearConversation }) {
const { state, actions } = useDetails(); const [busy, setBusy] = useState(false);
const { state, actions } = useDetails(clearConversation);
const toggle = async (cardId, selected) => { const toggle = async (cardId, selected) => {
try { try {
@ -58,6 +60,27 @@ export function Details({ channel, clearConversation }) {
} }
} }
const promptAction = (prompt, action) => {
prompt(async () => {
if (!busy) {
try {
setBusy(true);
await action();
setBusy(false);
}
catch (err) {
console.log(err);
setBusy(false);
Alert.alert(
state.strings.error,
state.strings.tryAgain,
);
throw err;
}
}
});
}
const remove = () => { const remove = () => {
Alert.alert( Alert.alert(
"Removing Topic", "Removing Topic",
@ -164,45 +187,6 @@ export function Details({ channel, clearConversation }) {
</View> </View>
<View style={styles.controls}> <View style={styles.controls}>
{ !state.hostId && (
<TouchableOpacity style={styles.button} onPress={remove}>
{ state.deleteBusy && (
<ActivityIndicator color={Colors.white} />
)}
{ !state.deleteBusy && (
<Text style={styles.buttonText}>Delete Topic</Text>
)}
</TouchableOpacity>
)}
{ state.hostId && (
<TouchableOpacity style={styles.button} onPress={remove}>
{ state.deleteBusy && (
<ActivityIndicator color={Colors.white} />
)}
{ !state.deleteBusy && (
<Text style={styles.buttonText}>Leave Topic</Text>
)}
</TouchableOpacity>
)}
<TouchableOpacity style={styles.button} onPress={block}>
{ state.blockBusy && (
<ActivityIndicator color={Colors.white} />
)}
{ !state.blockBusy && (
<Text style={styles.buttonText}>Block Topic</Text>
)}
</TouchableOpacity>
{ state.hostId && (
<TouchableOpacity style={styles.button} onPress={report}>
<Text style={styles.buttonText}>Report Topic</Text>
</TouchableOpacity>
)}
{ !state.hostId && !state.locked && (
<TouchableOpacity style={styles.button} onPress={actions.showEditMembers}>
<Text style={styles.buttonText}>Edit Membership</Text>
</TouchableOpacity>
)}
<View style={styles.notify}> <View style={styles.notify}>
<TouchableOpacity onPress={() => setNotifications(!state.notification)} activeOpacity={1}> <TouchableOpacity onPress={() => setNotifications(!state.notification)} activeOpacity={1}>
<Text style={styles.notifyText}>{ state.strings.enableNotifications }</Text> <Text style={styles.notifyText}>{ state.strings.enableNotifications }</Text>
@ -211,7 +195,42 @@ export function Details({ channel, clearConversation }) {
<Switch style={styles.switch} value={state.notification} onValueChange={setNotifications} trackColor={styles.track}/> <Switch style={styles.switch} value={state.notification} onValueChange={setNotifications} trackColor={styles.track}/>
)} )}
</View> </View>
</View>
<View style={styles.control}>
{ busy && (
<ActivityIndicator animating={true} color={Colors.text} size={'large'} />
)}
{ !busy && (
<View style={styles.drawerActions}>
{ !state.hostId && !state.locked && (
<TouchableOpacity style={styles.action} activeOpacity={1} onPress={actions.showEditMembers}>
<MatIcons name="account-group-outline" style={styles.actionIcon} size={44} color={Colors.linkText} />
<Text style={styles.actionLabel}>{ state.strings.members }</Text>
</TouchableOpacity>
)}
{ !state.hostId && (
<TouchableOpacity style={styles.action} activeOpacity={1} onPress={() => promptAction(actions.deletePrompt, actions.removeTopic)}>
<MatIcons name="text-box-remove-outline" style={styles.actionIcon} size={44} color={Colors.linkText} />
<Text style={styles.actionLabel}>{ state.strings.delete }</Text>
</TouchableOpacity>
)}
{ state.hostId && (
<TouchableOpacity style={styles.action} activeOpacity={1} onPress={() => promptAction(actions.leavePrompt, actions.removeTopic)}>
<MatIcons name="text-box-minus-outline" style={styles.actionIcon} size={44} color={Colors.linkText} />
<Text style={styles.actionLabel}>{ state.strings.leave }</Text>
</TouchableOpacity>
)}
<TouchableOpacity style={styles.action} activeOpacity={1} onPress={() => promptAction(actions.blockPrompt, actions.blockTopic)}>
<MatIcons name="comment-remove-outline" style={styles.actionIcon} size={44} color={Colors.linkText} />
<Text style={styles.actionLabel}>{ state.strings.actionBlock }</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.action} activeOpacity={1} onPress={() => promptAction(actions.reportPrompt, actions.reportTopic)}>
<MatIcons name="comment-alert-outline" style={styles.actionIcon} size={44} color={Colors.linkText} />
<Text style={styles.actionLabel}>{ state.strings.actionReport }</Text>
</TouchableOpacity>
</View>
)}
</View> </View>
<View style={styles.members}> <View style={styles.members}>

View File

@ -249,4 +249,38 @@ export const styles = StyleSheet.create({
width: '100%', width: '100%',
}, },
}, },
control: {
width: '100%',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingTop: 12,
},
drawerActions: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-end',
justifyContent: 'center',
width: '80%',
borderRadius: 8,
paddingTop: 8,
paddingBottom: 8,
},
actionList: {
alignItems: 'flex-end',
},
action: {
display: 'flex',
alignItems: 'center',
paddingRight: 12,
paddingLeft: 12,
paddingBottom: 12,
},
actionIcon: {
},
actionLabel: {
color: Colors.linkText,
fontSize: 10,
},
}) })

View File

@ -14,7 +14,7 @@ export function MemberItem({ item, hostId, toggle }) {
return ( return (
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={select}> <TouchableOpacity style={styles.container} activeOpacity={1} onPress={select}>
<Logo src={item.logo} width={32} height={32} radius={6} /> <Logo src={item.logo} width={48} height={48} radius={6} />
<View style={styles.detail}> <View style={styles.detail}>
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text> <Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text>
<Text style={styles.handle} numberOfLines={1} ellipsizeMode={'tail'}>{ item.handle }</Text> <Text style={styles.handle} numberOfLines={1} ellipsizeMode={'tail'}>{ item.handle }</Text>

View File

@ -6,7 +6,7 @@ export const styles = StyleSheet.create({
width: '100%', width: '100%',
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
height: 48, height: 64,
alignItems: 'center', alignItems: 'center',
borderBottomWidth: 1, borderBottomWidth: 1,
borderColor: Colors.itemDivider, borderColor: Colors.itemDivider,

View File

@ -8,9 +8,10 @@ import { getChannelSubjectLogo } from 'context/channelUtil';
import { getCardByGuid } from 'context/cardUtil'; import { getCardByGuid } from 'context/cardUtil';
import { getChannelSeals, isUnsealed, getContentKey, updateChannelSubject } from 'context/sealUtil'; import { getChannelSeals, isUnsealed, getContentKey, updateChannelSubject } from 'context/sealUtil';
import { getLanguageStrings } from 'constants/Strings'; import { getLanguageStrings } from 'constants/Strings';
import { DisplayContext } from 'context/DisplayContext';
import moment from 'moment'; import moment from 'moment';
export function useDetails() { export function useDetails(clear) {
const [state, setState] = useState({ const [state, setState] = useState({
strings: getLanguageStrings(), strings: getLanguageStrings(),
@ -38,6 +39,7 @@ export function useDetails() {
const account = useContext(AccountContext); const account = useContext(AccountContext);
const conversation = useContext(ConversationContext); const conversation = useContext(ConversationContext);
const profile = useContext(ProfileContext); const profile = useContext(ProfileContext);
const display = useContext(DisplayContext);
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
@ -200,41 +202,53 @@ export function useDetails() {
await conversation.actions.setChannelSubject('superbasic', subject); await conversation.actions.setChannelSubject('superbasic', subject);
} }
}, },
remove: async () => { removeTopic: async () => {
if (!state.deleteBusy) {
try {
updateState({ deleteBusy: true });
await conversation.actions.removeChannel(); await conversation.actions.removeChannel();
updateState({ deleteBusy: false }); clear();
}
catch(err) {
console.log(err);
updateState({ deleteBusy: false });
throw new Error("delete failed");
}
}
}, },
block: async() => { blockTopic: async() => {
if (!state.deleteBusy) {
try {
updateState({ blockBusy: true });
await conversation.actions.setChannelFlag(); await conversation.actions.setChannelFlag();
updateState({ blockBusy: false }); clear();
}
catch(err) {
console.log(err);
updateState({ blockBusy: false });
throw new Error("block failed");
}
}
}, },
report: async() => { reportTopic: async() => {
await conversation.actions.addChannelAlert(); await conversation.actions.addChannelAlert();
}, },
setNotifications: async (notification) => { setNotifications: async (notification) => {
await conversation.actions.setNotifications(notification); await conversation.actions.setNotifications(notification);
updateState({ notification }); updateState({ notification });
}, },
deletePrompt: (action) => {
display.actions.showPrompt({
title: state.strings.deleteTopic,
centerButtons: true,
ok: { label: state.strings.confirmDelete, action, failed: () => {}},
cancel: { label: state.strings.cancel },
});
},
leavePrompt: (action) => {
display.actions.showPrompt({
title: state.strings.leaveTopic,
centerButtons: true,
ok: { label: state.strings.leave, action, failed: () => {}},
cancel: { label: state.strings.cancel },
});
},
blockPrompt: (action) => {
display.actions.showPrompt({
title: state.strings.blockTopic,
centerButtons: true,
ok: { label: state.strings.confirmBlock, action, failed: () => {}},
cancel: { label: state.strings.cancel },
});
},
reportPrompt: (action) => {
display.actions.showPrompt({
title: state.strings.reportTopic,
centerButtons: true,
ok: { label: state.strings.confirmReport, action, failed: () => {}},
cancel: { label: state.strings.cancel },
});
},
}; };
return { state, actions }; return { state, actions };