added blocked modals

This commit is contained in:
balzack 2025-01-10 19:56:12 -08:00
parent a534bca0a5
commit 93b20714b3
3 changed files with 322 additions and 4 deletions

View File

@ -7,6 +7,7 @@ export const styles = StyleSheet.create({
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
},
border: {
height: 2,
@ -327,4 +328,74 @@ export const styles = StyleSheet.create({
radio: {
borderRadius: 32,
},
blocked: {
minHeight: 128,
maxHeight: 256,
width: '100%',
},
blockedSurface: {
width: '80%',
maxWidth: 500,
borderRadius: 8,
paddingLeft: 16,
paddingRight: 16,
},
blockedHeader: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
blockedTitle: {
flexGrow: 1,
fontSize: 20,
paddingLeft: 8,
},
blockedClose: {
backgroundColor: 'transparent',
},
blockedDone: {
width: '100%',
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
paddingTop: 16,
paddingBottom: 16,
},
blockedButton: {
borderRadius: 8,
},
blockedError: {
color: Colors.offsync,
flexGrow: 1,
paddingLeft: 8,
},
blockedEmpty: {
width: '100%',
height: 128,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
blockedLabel: {
fontSize: 20,
color: Colors.placeholder,
},
blockedItems: {
width: '100%',
},
blockedItem: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
},
blockedAction: {
backgroundColor: 'transparent',
},
blockedValue: {
fontSize: 16,
flexGrow: 1,
paddingLeft: 16,
},
});

View File

@ -1,5 +1,5 @@
import React, {useState} from 'react';
import {Surface, Button, Text, IconButton, Divider, Icon, TextInput, RadioButton, Switch} from 'react-native-paper';
import {useTheme, Surface, Button, Text, IconButton, Divider, Icon, TextInput, RadioButton, Switch} from 'react-native-paper';
import {TouchableOpacity, Modal, View, Image, ScrollView} from 'react-native';
import {styles} from './Settings.styled';
import {useSettings} from './useSettings.hook';
@ -37,6 +37,95 @@ export function Settings({showLogout}: {showLogout: boolean}) {
const [secretCopy, setSecretCopy] = useState(false);
const [confirmingAuth, setConfirmingAuth] = useState(false);
const [authMessage, setAuthMessage] = useState('');
const [blockedMessage, setBlockedMessage] = useState(false);
const [blockedChannel, setBlockedChannel] = useState(false);
const [blockedContact, setBlockedContact] = useState(false);
const [blockedError, setBlockedError] = useState(false);
const theme = useTheme();
const showBlockedMessage = async () => {
setBlockedError(false);
try {
await actions.loadBlockedMessages();
} catch (err) {
console.log(err);
setBlockedError(true);
}
setBlockedMessage(true);
}
const unblockMessage = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
try {
setBlockedError(false);
await actions.unblockMessage(blocked.cardId, blocked.channelId, blocked.topicId);
} catch (err) {
console.log(err);
setBlockedError(true);
}
}
const blockedMessages = state.blockedMessages.map((blocked, index) => (
<View key={index} style={{ ...styles.blockedItem, borderColor: theme.colors.outlineVariant }}>
<Text style={styles.blockedValue}> { actions.getTimestamp(blocked.timestamp) }</Text>
<IconButton style={styles.blockedAction} icon="restore" size={16} onPress={() => unblockMessage(blocked)} />
</View>
));
const showBlockedChannel = async () => {
setBlockedError(false);
try {
await actions.loadBlockedChannels();
} catch (err) {
console.log(err);
setBlockedError(true);
}
setBlockedChannel(true);
}
const unblockChannel = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
try {
setBlockedError(false);
await actions.unblockChannel(blocked.cardId, blocked.channelId, blocked.topicId);
} catch (err) {
console.log(err);
setBlockedError(true);
}
}
const blockedChannels = state.blockedChannels.map((blocked, index) => (
<View key={index} style={{ ...styles.blockedItem, borderColor: theme.colors.outlineVariant }}>
<Text style={styles.blockedValue}> { actions.getTimestamp(blocked.timestamp) }</Text>
<IconButton style={styles.blockedAction} icon="restore" size={16} onPress={() => unblockChannel(blocked)} />
</View>
));
const showBlockedContact = async () => {
setBlockedError(false);
try {
await actions.loadBlockedContacts();
} catch (err) {
console.log(err);
setBlockedError(true);
}
setBlockedContact(true);
}
const unblockContact = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
try {
setBlockedError(false);
await actions.unblockContact(blocked.cardId, blocked.channelId, blocked.topicId);
} catch (err) {
console.log(err);
setBlockedError(true);
}
}
const blockedContacts = state.blockedContacts.map((blocked, index) => (
<View key={index} style={{ ...styles.blockedItem, borderColor: theme.colors.outlineVariant }}>
<Text style={styles.blockedValue}> { actions.getTimestamp(blocked.timestamp) }</Text>
<IconButton style={styles.blockedAction} icon="restore" size={16} onPress={() => unblockContact(blocked)} />
</View>
));
const alertParams = {
title: state.strings.operationFailed,
@ -469,7 +558,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
<Icon size={24} source="account-cancel-outline" />
</View>
<View style={styles.control}>
<TouchableOpacity activeOpacity={1} onPress={() => manageSeal}>
<TouchableOpacity activeOpacity={1} onPress={showBlockedContact}>
<Text style={styles.controlLabel}>{state.strings.blockedContacts}</Text>
</TouchableOpacity>
</View>
@ -479,7 +568,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
<Icon size={24} source="archive-cancel-outline" />
</View>
<View style={styles.control}>
<TouchableOpacity activeOpacity={1} onPress={() => manageSeal}>
<TouchableOpacity activeOpacity={1} onPress={showBlockedChannel}>
<Text style={styles.controlLabel}>{state.strings.blockedTopics}</Text>
</TouchableOpacity>
</View>
@ -489,7 +578,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
<Icon size={24} source="file-cancel-outline" />
</View>
<View style={styles.control}>
<TouchableOpacity activeOpacity={1} onPress={() => manageSeal}>
<TouchableOpacity activeOpacity={1} onPress={showBlockedMessage}>
<Text style={styles.controlLabel}>{state.strings.blockedMessages}</Text>
</TouchableOpacity>
</View>
@ -1028,6 +1117,99 @@ export function Settings({showLogout}: {showLogout: boolean}) {
</KeyboardAwareScrollView>
</View>
</Modal>
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={blockedMessage} onRequestClose={() => setBlockedMessage(false)}>
<View style={styles.modal}>
<BlurView style={styles.blur} blurType="dark" blurAmount={2} reducedTransparencyFallbackColor="dark" />
<Surface elevation={3} mode="flat" style={styles.blockedSurface}>
<View style={styles.blockedHeader}>
<Text style={styles.blockedTitle}>{ state.strings.blockedMessages }</Text>
<IconButton style={styles.blockedClose} icon="close" size={24} onPress={() => setBlockedMessage(false)} />
</View>
<Surface style={styles.blocked} elevation={1} mode="flat">
{ state.blockedMessages.length == 0 && (
<View style={styles.blockedEmpty}>
<Text style={styles.blockedLabel}>{ state.strings.noMessages }</Text>
</View>
)}
{ state.blockedMessages.length > 0 && (
<View>
{ blockedMessages }
</View>
)}
</Surface>
<View style={styles.blockedDone}>
{ blockedError && (
<Text style={styles.blockedError}>{ state.strings.operationFailed }</Text>
)}
<Button style={styles.blockedButton} mode="outlined" onPress={() => setBlockedMessage(false)}>
{state.strings.close}
</Button>
</View>
</Surface>
</View>
</Modal>
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={blockedChannel} onRequestClose={() => setBlockedChannel(false)}>
<View style={styles.modal}>
<BlurView style={styles.blur} blurType="dark" blurAmount={2} reducedTransparencyFallbackColor="dark" />
<Surface elevation={3} mode="flat" style={styles.blockedSurface}>
<View style={styles.blockedHeader}>
<Text style={styles.blockedTitle}>{ state.strings.blockedTopics }</Text>
<IconButton style={styles.blockedClose} icon="close" size={24} onPress={() => setBlockedChannel(false)} />
</View>
<Surface style={styles.blocked} elevation={1} mode="flat">
{ state.blockedChannels.length == 0 && (
<View style={styles.blockedEmpty}>
<Text style={styles.blockedLabel}>{ state.strings.noTopics }</Text>
</View>
)}
{ state.blockedChannels.length > 0 && (
<View>
{ blockedChannels }
</View>
)}
</Surface>
<View style={styles.blockedDone}>
{ blockedError && (
<Text style={styles.blockedError}>{ state.strings.operationFailed }</Text>
)}
<Button style={styles.blockedButton} mode="outlined" onPress={() => setBlockedChannel(false)}>
{state.strings.close}
</Button>
</View>
</Surface>
</View>
</Modal>
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={blockedContact} onRequestClose={() => setBlockedContact(false)}>
<View style={styles.modal}>
<BlurView style={styles.blur} blurType="dark" blurAmount={2} reducedTransparencyFallbackColor="dark" />
<Surface elevation={3} mode="flat" style={styles.blockedSurface}>
<View style={styles.blockedHeader}>
<Text style={styles.blockedTitle}>{ state.strings.blockedContacts }</Text>
<IconButton style={styles.blockedClose} icon="close" size={24} onPress={() => setBlockedContact(false)} />
</View>
<Surface style={styles.blocked} elevation={1} mode="flat">
{ state.blockedContacts.length == 0 && (
<View style={styles.blockedEmpty}>
<Text style={styles.blockedLabel}>{ state.strings.noContacts }</Text>
</View>
)}
{ state.blockedContacts.length > 0 && (
<View>
{ blockedContacts }
</View>
)}
</Surface>
<View style={styles.blockedDone}>
{ blockedError && (
<Text style={styles.blockedError}>{ state.strings.operationFailed }</Text>
)}
<Button style={styles.blockedButton} mode="outlined" onPress={() => setBlockedContact(false)}>
{state.strings.close}
</Button>
</View>
</Surface>
</View>
</Modal>
<Confirm show={alert} params={alertParams} />
</View>
);

View File

@ -36,6 +36,9 @@ export function useSettings() {
secretCopied: false,
monthFirstDate: true,
fullDayTime: false,
blockedContacts: [] as {cardId: string, timestamp: number}[],
blockedChannels: [] as {cardId: string | null, channelId: string, timestamp: number}[],
blockedMessages: [] as {cardId: string | null, channelId: string, topicId: string, timestamp: number}[],
});
const updateState = (value: any) => {
@ -247,6 +250,68 @@ export function useSettings() {
setMonthFirstDate: async (flag: boolean) => {
await app.actions.setMonthFirstDate(flag);
},
loadBlockedMessages: async () => {
const settings = app.state.session.getSettings();
const blockedMessages = await settings.getBlockedTopics();
updateState({ blockedMessages });
},
unblockMessage: async (cardId: string | null, channelId: string, topicId: string) => {
const content = app.state.session.getContent();
await content.clearBlockedChannelTopic(cardId, channelId, topicId);
const blockedMessages = state.blockedMessages.filter(blocked => (blocked.cardId != cardId || blocked.channelId != channelId || blocked.topicId != topicId));
updateState({ blockedMessages });
},
loadBlockedChannels: async () => {
const settings = app.state.session.getSettings();
const blockedChannels = await settings.getBlockedChannels();
updateState({ blockedChannels });
},
unblockChannel: async (cardId: string | null, channelId: string) => {
const content = app.state.session.getContent();
await content.setBlockedChannel(cardId, channelId, false);
const blockedChannels = state.blockedChannels.filter(blocked => (blocked.cardId != cardId || blocked.channelId != channelId));
updateState({ blockedChannels });
},
loadBlockedContacts: async () => {
const settings = app.state.session.getSettings();
const blockedCards = await settings.getBlockedCards();
updateState({ blockedCards });
},
unblockCard: async (cardId: string) => {
const contact = app.state.session.getContact();
await contact.setBlockedCard(cardId, false);
const blockedCards = state.blockedCards.filter(blocked => blocked.cardId != cardId);
updateState({ blockedCards });
},
getTimestamp: (created: number) => {
const now = Math.floor((new Date()).getTime() / 1000)
const date = new Date(created * 1000);
const offset = now - created;
if(offset < 43200) {
if (state.timeFormat === '12h') {
return date.toLocaleTimeString("en-US", {hour: 'numeric', minute:'2-digit'});
}
else {
return date.toLocaleTimeString("en-GB", {hour: 'numeric', minute:'2-digit'});
}
}
else if (offset < 31449600) {
if (state.dateFormat === 'mm/dd') {
return date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'});
}
else {
return date.toLocaleDateString("en-GB", {day: 'numeric', month:'numeric'});
}
}
else {
if (state.dateFormat === 'mm/dd') {
return date.toLocaleDateString("en-US");
}
else {
return date.toLocaleDateString("en-GB");
}
}
}
};
return {state, actions};