mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
adding profile settings drawer for tablet
This commit is contained in:
parent
4e380a8e05
commit
10925079bf
@ -17,6 +17,7 @@ const LightColors = {
|
|||||||
descriptionText: '#888888',
|
descriptionText: '#888888',
|
||||||
text: '#444444',
|
text: '#444444',
|
||||||
screenBase: '#dddddd',
|
screenBase: '#dddddd',
|
||||||
|
drawerBase: '#eeeeee',
|
||||||
areaBase: '#ffffff',
|
areaBase: '#ffffff',
|
||||||
modalBase: '#ffffff',
|
modalBase: '#ffffff',
|
||||||
modalOverlay: 'rgba(52,52,52,0.8)',
|
modalOverlay: 'rgba(52,52,52,0.8)',
|
||||||
@ -69,6 +70,7 @@ const DarkColors = {
|
|||||||
descriptionText: '#bbbbbb',
|
descriptionText: '#bbbbbb',
|
||||||
text: '#ffffff',
|
text: '#ffffff',
|
||||||
screenBase: '#222222',
|
screenBase: '#222222',
|
||||||
|
drawerBase: '#333333',
|
||||||
areaBase: '#444444',
|
areaBase: '#444444',
|
||||||
modalBase: '#111111',
|
modalBase: '#111111',
|
||||||
modalOverlay: 'rgba(88,88,88,0.8)',
|
modalOverlay: 'rgba(88,88,88,0.8)',
|
||||||
@ -124,6 +126,7 @@ export const Colors = {
|
|||||||
descriptionText: getColor('descriptionText'),
|
descriptionText: getColor('descriptionText'),
|
||||||
text: getColor('text'),
|
text: getColor('text'),
|
||||||
screenBase: getColor('screenBase'),
|
screenBase: getColor('screenBase'),
|
||||||
|
drawerBase: getColor('drawerBase'),
|
||||||
areaBase: getColor('areaBase'),
|
areaBase: getColor('areaBase'),
|
||||||
modalOverlay: getColor('modalOverlay'),
|
modalOverlay: getColor('modalOverlay'),
|
||||||
modalBase: getColor('modalBase'),
|
modalBase: getColor('modalBase'),
|
||||||
|
@ -11,6 +11,7 @@ import { useSession } from './useSession.hook';
|
|||||||
import { styles } from './Session.styled';
|
import { styles } from './Session.styled';
|
||||||
import Colors from 'constants/Colors';
|
import Colors from 'constants/Colors';
|
||||||
import { Profile } from './profile/Profile';
|
import { Profile } from './profile/Profile';
|
||||||
|
import { ProfileSettings } from './profileSettings/ProfileSettings';
|
||||||
import { CardsHeader, CardsBody, Cards } from './cards/Cards';
|
import { CardsHeader, CardsBody, Cards } from './cards/Cards';
|
||||||
import { RegistryHeader, RegistryBody, Registry } from './registry/Registry';
|
import { RegistryHeader, RegistryBody, Registry } from './registry/Registry';
|
||||||
import { ContactHeader, ContactBody, Contact } from './contact/Contact';
|
import { ContactHeader, ContactBody, Contact } from './contact/Contact';
|
||||||
@ -433,7 +434,7 @@ export function Session({ sharing, clearSharing }) {
|
|||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
{ state.tabbed === false && (
|
{ state.tabbed === false && (
|
||||||
<ProfileDrawer.Navigator screenOptions={{ ...drawerParams, drawerStyle: { width: '45%' } }} drawerContent={(props) => (
|
<ProfileDrawer.Navigator screenOptions={{ ...drawerParams, drawerStyle: { width: '45%' } }} drawerContent={(props) => (
|
||||||
<ScrollView style={styles.drawer}><SafeAreaView edges={['top', 'bottom', 'right']}><Profile /></SafeAreaView></ScrollView>
|
<ProfileSettings />
|
||||||
)}>
|
)}>
|
||||||
<ProfileDrawer.Screen name="detail">
|
<ProfileDrawer.Screen name="detail">
|
||||||
{(props) => <DetailDrawerScreen navParams={{ profileNav: props.navigation, state, actions, addChannel, dmChannel, shareChannel, shareIntent, setShareIntent }} />}
|
{(props) => <DetailDrawerScreen navParams={{ profileNav: props.navigation, state, actions, addChannel, dmChannel, shareChannel, shareIntent, setShareIntent }} />}
|
||||||
|
@ -95,7 +95,7 @@ export const styles = StyleSheet.create({
|
|||||||
paddingTop: 8,
|
paddingTop: 8,
|
||||||
paddingLeft: 8,
|
paddingLeft: 8,
|
||||||
paddingRight: 8,
|
paddingRight: 8,
|
||||||
backgroundColor: Colors.formBackground,
|
backgroundColor: Colors.drawerBase,
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -13,7 +13,7 @@ import { useProfile } from './useProfile.hook';
|
|||||||
import { styles } from './Profile.styled';
|
import { styles } from './Profile.styled';
|
||||||
import avatar from 'images/avatar.png';
|
import avatar from 'images/avatar.png';
|
||||||
|
|
||||||
export function Profile() {
|
export function Profile({ drawer }) {
|
||||||
|
|
||||||
const [busyDetail, setBusyDetail] = useState(false);
|
const [busyDetail, setBusyDetail] = useState(false);
|
||||||
const { state, actions } = useProfile();
|
const { state, actions } = useProfile();
|
||||||
@ -71,79 +71,87 @@ export function Profile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<>
|
||||||
<Image source={state.imageSource} style={{ ...styles.logo, width: state.imageWidth, height: state.imageHeight }} resizeMode={'contain'} />
|
{ drawer && (
|
||||||
|
<View style={styles.drawerContainer}>
|
||||||
<View style={styles.content}>
|
<Text style={styles.drawerHeader} adjustsFontSizeToFit={true}>{ state.username }</Text>
|
||||||
<View style={{ width: state.imageWidth, height: state.imageHeight - OVERLAP }} />
|
<View style={styles.drawerFrame}>
|
||||||
|
<Image source={state.imageSource} style={styles.drawerLogo} resizeMode={'contain'} />
|
||||||
<View style={styles.control}>
|
<View style={styles.drawerLogoEdit}>
|
||||||
<Menu>
|
<Text style={styles.editLabel}>{ state.strings.edit }</Text>
|
||||||
<MenuTrigger customStyles={styles.trigger}>
|
<MatIcons name="square-edit-outline" size={14} color={Colors.linkText} />
|
||||||
<View style={styles.edit}>
|
|
||||||
<Text style={styles.editLabel}>{ state.strings.edit }</Text>
|
|
||||||
<MatIcons name="square-edit-outline" size={14} color={Colors.linkText} />
|
|
||||||
</View>
|
|
||||||
</MenuTrigger>
|
|
||||||
<MenuOptions optionsContainerStyle={{ width: 'auto' }} style={styles.options}>
|
|
||||||
<MenuOption onSelect={onGallery}>
|
|
||||||
<Text style={styles.option}>{ state.strings.editImage }</Text>
|
|
||||||
</MenuOption>
|
|
||||||
<MenuOption onSelect={actions.showDetails}>
|
|
||||||
<Text style={styles.option}>{ state.strings.editDetails }</Text>
|
|
||||||
</MenuOption>
|
|
||||||
</MenuOptions>
|
|
||||||
</Menu>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
|
|
||||||
<View style={{ ...styles.details, width: state.detailWidth }}>
|
|
||||||
|
|
||||||
{ state.name && (
|
|
||||||
<Text style={styles.nameSet} numberOfLines={1} adjustsFontSizeToFit={true}>{ state.name }</Text>
|
|
||||||
)}
|
|
||||||
{ !state.name && (
|
|
||||||
<Text style={styles.nameUnset}>{ state.strings.name }</Text>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Text style={styles.username} numberOfLines={1}>{ state.username }</Text>
|
|
||||||
|
|
||||||
<View style={styles.attributes}>
|
|
||||||
<View style={styles.entry}>
|
|
||||||
<AntIcons name="enviromento" style={styles.icon} size={20} color={Colors.text} />
|
|
||||||
{ state.location && (
|
|
||||||
<Text style={styles.locationSet}>{ state.location }</Text>
|
|
||||||
)}
|
|
||||||
{ !state.location && (
|
|
||||||
<Text style={styles.locationUnset}>Location</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
<View style={styles.divider} />
|
|
||||||
<ScrollView style={styles.description}>
|
|
||||||
<View style={styles.entry}>
|
|
||||||
<MatIcons name="book-open-outline" style={styles.descriptionIcon} size={20} color={Colors.text} />
|
|
||||||
{ state.description && (
|
|
||||||
<Text style={styles.descriptionSet}>{ state.description }</Text>
|
|
||||||
)}
|
|
||||||
{ !state.description && (
|
|
||||||
<Text style={styles.descriptionUnset}>Description</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
)}
|
||||||
<View style={styles.group}>
|
{ !drawer && (
|
||||||
<TouchableOpacity style={styles.entry} activeOpacity={1}>
|
<View style={styles.container}>
|
||||||
<MatIcons name="eye-outline" style={styles.icon} size={20} color={Colors.text} />
|
<Image source={state.imageSource} style={{ ...styles.logo, width: state.imageWidth, height: state.imageHeight }} resizeMode={'contain'} />
|
||||||
<TouchableOpacity activeOpacity={1} onPress={() => setVisible(!state.searchable)}>
|
<View style={styles.content}>
|
||||||
<Text style={styles.visibleLabel}>{ state.strings.visibleRegistry }</Text>
|
<View style={{ width: state.imageWidth, height: state.imageHeight - OVERLAP }} />
|
||||||
</TouchableOpacity>
|
<View style={styles.control}>
|
||||||
<Switch value={state.searchable} style={Platform.OS==='ios' ? styles.visibleSwitch : {}} thumbColor={Colors.sliderGrip} ios_backgroundColor={Colors.disabledIndicator}
|
<Menu>
|
||||||
trackColor={styles.track} onValueChange={setVisible} />
|
<MenuTrigger customStyles={styles.trigger}>
|
||||||
</TouchableOpacity>
|
<View style={styles.edit}>
|
||||||
|
<Text style={styles.editLabel}>{ state.strings.edit }</Text>
|
||||||
|
<MatIcons name="square-edit-outline" size={14} color={Colors.linkText} />
|
||||||
|
</View>
|
||||||
|
</MenuTrigger>
|
||||||
|
<MenuOptions optionsContainerStyle={{ width: 'auto' }} style={styles.options}>
|
||||||
|
<MenuOption onSelect={onGallery}>
|
||||||
|
<Text style={styles.option}>{ state.strings.editImage }</Text>
|
||||||
|
</MenuOption>
|
||||||
|
<MenuOption onSelect={actions.showDetails}>
|
||||||
|
<Text style={styles.option}>{ state.strings.editDetails }</Text>
|
||||||
|
</MenuOption>
|
||||||
|
</MenuOptions>
|
||||||
|
</Menu>
|
||||||
|
</View>
|
||||||
|
<View style={{ ...styles.details, width: state.detailWidth }}>
|
||||||
|
{ state.name && (
|
||||||
|
<Text style={styles.nameSet} numberOfLines={1} adjustsFontSizeToFit={true}>{ state.name }</Text>
|
||||||
|
)}
|
||||||
|
{ !state.name && (
|
||||||
|
<Text style={styles.nameUnset}>{ state.strings.name }</Text>
|
||||||
|
)}
|
||||||
|
<Text style={styles.username} numberOfLines={1}>{ state.username }</Text>
|
||||||
|
<View style={styles.attributes}>
|
||||||
|
<View style={styles.entry}>
|
||||||
|
<AntIcons name="enviromento" style={styles.icon} size={20} color={Colors.text} />
|
||||||
|
{ state.location && (
|
||||||
|
<Text style={styles.locationSet}>{ state.location }</Text>
|
||||||
|
)}
|
||||||
|
{ !state.location && (
|
||||||
|
<Text style={styles.locationUnset}>Location</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<View style={styles.divider} />
|
||||||
|
<ScrollView style={styles.description}>
|
||||||
|
<View style={styles.entry}>
|
||||||
|
<MatIcons name="book-open-outline" style={styles.descriptionIcon} size={20} color={Colors.text} />
|
||||||
|
{ state.description && (
|
||||||
|
<Text style={styles.descriptionSet}>{ state.description }</Text>
|
||||||
|
)}
|
||||||
|
{ !state.description && (
|
||||||
|
<Text style={styles.descriptionUnset}>Description</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
<View style={styles.group}>
|
||||||
|
<TouchableOpacity style={styles.entry} activeOpacity={1}>
|
||||||
|
<MatIcons name="eye-outline" style={styles.icon} size={20} color={Colors.text} />
|
||||||
|
<TouchableOpacity activeOpacity={1} onPress={() => setVisible(!state.searchable)}>
|
||||||
|
<Text style={styles.visibleLabel}>{ state.strings.visibleRegistry }</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<Switch value={state.searchable} style={Platform.OS==='ios' ? styles.visibleSwitch : {}} thumbColor={Colors.sliderGrip} ios_backgroundColor={Colors.disabledIndicator}
|
||||||
|
trackColor={styles.track} onValueChange={setVisible} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
animationType="fade"
|
animationType="fade"
|
||||||
@ -212,8 +220,7 @@ export function Profile() {
|
|||||||
</View>
|
</View>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
</View>
|
</>
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,43 @@ import { StyleSheet } from 'react-native';
|
|||||||
import { Colors } from 'constants/Colors';
|
import { Colors } from 'constants/Colors';
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
|
drawerContainer: {
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
drawerHeader: {
|
||||||
|
fontFamily: 'roboto',
|
||||||
|
color: Colors.text,
|
||||||
|
fontSize: 20,
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
drawerFrame: {
|
||||||
|
width: '50%',
|
||||||
|
maxWidth: 400,
|
||||||
|
paddingBottom: 16,
|
||||||
|
},
|
||||||
|
drawerLogo: {
|
||||||
|
aspectRatio: 1,
|
||||||
|
resizeMode: 'contain',
|
||||||
|
borderRadius: 8,
|
||||||
|
width: null,
|
||||||
|
height: null,
|
||||||
|
},
|
||||||
|
drawerLogoEdit: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
alignSelf: 'center',
|
||||||
|
backgroundColor: 'rgba(255,255,255,0.6)',
|
||||||
|
paddingLeft: 8,
|
||||||
|
paddingRight: 8,
|
||||||
|
borderBottomLeftRadius: 6,
|
||||||
|
borderBottomRightRadius: 6,
|
||||||
|
},
|
||||||
|
|
||||||
container: {
|
container: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
import { FlatList, View, Alert, TouchableOpacity, Text } from 'react-native';
|
|
||||||
import { styles } from './BlockedContacts.styled';
|
|
||||||
import { useBlockedContacts } from './useBlockedContacts.hook';
|
|
||||||
import { Logo } from 'utils/Logo';
|
|
||||||
|
|
||||||
export function BlockedContacts() {
|
|
||||||
|
|
||||||
const { state, actions } = useBlockedContacts();
|
|
||||||
|
|
||||||
const unblock = (cardId) => {
|
|
||||||
Alert.alert(
|
|
||||||
'Unblocking Contact',
|
|
||||||
'Confirm?',
|
|
||||||
[
|
|
||||||
{ text: "Cancel", onPress: () => {}, },
|
|
||||||
{ text: "Unblock", onPress: () => actions.unblock(cardId) },
|
|
||||||
],
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const BlockedItem = ({ item }) => {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity style={styles.item} onPress={() => unblock(item.cardId)}>
|
|
||||||
<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>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.container}>
|
|
||||||
{ state.cards.length === 0 && (
|
|
||||||
<Text style={styles.default}>No Blocked Contacts</Text>
|
|
||||||
)}
|
|
||||||
{ state.cards.length !== 0 && (
|
|
||||||
<FlatList
|
|
||||||
data={state.cards}
|
|
||||||
renderItem={({item}) => <BlockedItem item={item} />}
|
|
||||||
keyExtractor={item => item.cardId}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
|
||||||
import { Colors } from 'constants/Colors';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
display: 'flex',
|
|
||||||
width: '100%',
|
|
||||||
justifyContent: 'center',
|
|
||||||
fontSize: 14,
|
|
||||||
height: 200,
|
|
||||||
},
|
|
||||||
default: {
|
|
||||||
textAlign: 'center',
|
|
||||||
color: Colors.grey,
|
|
||||||
},
|
|
||||||
item: {
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: 48,
|
|
||||||
paddingLeft: 16,
|
|
||||||
alignItems: 'center',
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderColor: Colors.itemDivider,
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
paddingLeft: 12,
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'center',
|
|
||||||
flexGrow: 1,
|
|
||||||
flexShrink: 1,
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
color: Colors.text,
|
|
||||||
fontSize: 14,
|
|
||||||
},
|
|
||||||
handle: {
|
|
||||||
color: Colors.text,
|
|
||||||
fontSize: 12,
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,53 +0,0 @@
|
|||||||
import { useState, useEffect, useContext } from 'react';
|
|
||||||
import { CardContext } from 'context/CardContext';
|
|
||||||
|
|
||||||
export function useBlockedContacts() {
|
|
||||||
|
|
||||||
const [state, setState] = useState({
|
|
||||||
cards: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const card = useContext(CardContext);
|
|
||||||
|
|
||||||
const updateState = (value) => {
|
|
||||||
setState((s) => ({ ...s, ...value }));
|
|
||||||
}
|
|
||||||
|
|
||||||
const setCardItem = (item) => {
|
|
||||||
const { profile } = item;
|
|
||||||
return {
|
|
||||||
cardId: item.cardId,
|
|
||||||
name: profile?.name,
|
|
||||||
handle: `${profile?.handle}@${profile?.node}`,
|
|
||||||
blocked: item.blocked,
|
|
||||||
logo: profile?.imageSet ? card.actions.getCardImageUrl(item.cardId) : 'avatar',
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const cards = Array.from(card.state.cards.values());
|
|
||||||
const items = cards.map(setCardItem);
|
|
||||||
const filtered = items.filter(item => {
|
|
||||||
return item.blocked;
|
|
||||||
});
|
|
||||||
filtered.sort((a, b) => {
|
|
||||||
if (a.name === b.name) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!a.name || (a.name < b.name)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
});
|
|
||||||
updateState({ cards: filtered });
|
|
||||||
}, [card.state]);
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
unblock: async (cardId) => {
|
|
||||||
await card.actions.clearCardFlag(cardId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return { state, actions };
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
import { FlatList, View, Alert, TouchableOpacity, Text } from 'react-native';
|
|
||||||
import { styles } from './BlockedMessages.styled';
|
|
||||||
import { useBlockedMessages } from './useBlockedMessages.hook';
|
|
||||||
import { Logo } from 'utils/Logo';
|
|
||||||
|
|
||||||
export function BlockedMessages() {
|
|
||||||
|
|
||||||
const { state, actions } = useBlockedMessages();
|
|
||||||
|
|
||||||
const unblock = (cardId, channelId, topicId) => {
|
|
||||||
Alert.alert(
|
|
||||||
'Unblocking Message',
|
|
||||||
'Confirm?',
|
|
||||||
[
|
|
||||||
{ text: "Cancel", onPress: () => {}, },
|
|
||||||
{ text: "Unblock", onPress: () => actions.unblock(cardId, channelId, topicId) },
|
|
||||||
],
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const BlockedItem = ({ item }) => {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity style={styles.item} onPress={() => unblock(item.cardId, item.channelId, item.topicId)}>
|
|
||||||
<View style={styles.detail}>
|
|
||||||
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text>
|
|
||||||
<Text style={styles.created} numberOfLines={1} ellipsizeMode={'tail'}>{ item.timestamp }</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.container}>
|
|
||||||
{ state.messages.length === 0 && (
|
|
||||||
<Text style={styles.default}>No Blocked Messages</Text>
|
|
||||||
)}
|
|
||||||
{ state.messages.length !== 0 && (
|
|
||||||
<FlatList
|
|
||||||
data={state.messages}
|
|
||||||
renderItem={({item}) => <BlockedItem item={item} />}
|
|
||||||
keyExtractor={item => item.id}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
|
||||||
import { Colors } from 'constants/Colors';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
display: 'flex',
|
|
||||||
width: '100%',
|
|
||||||
justifyContent: 'center',
|
|
||||||
fontSize: 14,
|
|
||||||
height: 200,
|
|
||||||
},
|
|
||||||
default: {
|
|
||||||
textAlign: 'center',
|
|
||||||
color: Colors.grey,
|
|
||||||
},
|
|
||||||
item: {
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: 32,
|
|
||||||
paddingLeft: 16,
|
|
||||||
alignItems: 'center',
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderColor: Colors.itemDivider,
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
paddingLeft: 12,
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'center',
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
color: Colors.text,
|
|
||||||
fontSize: 14,
|
|
||||||
flexGrow: 1,
|
|
||||||
flexShrink: 1,
|
|
||||||
minWidth: 0,
|
|
||||||
},
|
|
||||||
created: {
|
|
||||||
color: Colors.text,
|
|
||||||
fontSize: 12,
|
|
||||||
paddingRight: 16,
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,121 +0,0 @@
|
|||||||
import { useState, useEffect, useContext } from 'react';
|
|
||||||
import { StoreContext } from 'context/StoreContext';
|
|
||||||
import { ChannelContext } from 'context/ChannelContext';
|
|
||||||
import { CardContext } from 'context/CardContext';
|
|
||||||
import { ProfileContext } from 'context/ProfileContext';
|
|
||||||
import { getCardByGuid } from 'context/cardUtil';
|
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
export function useBlockedMessages() {
|
|
||||||
|
|
||||||
const [state, setState] = useState({
|
|
||||||
messages: []
|
|
||||||
});
|
|
||||||
|
|
||||||
const store = useContext(StoreContext);
|
|
||||||
const card = useContext(CardContext);
|
|
||||||
const channel = useContext(ChannelContext);
|
|
||||||
const profile = useContext(ProfileContext);
|
|
||||||
|
|
||||||
const updateState = (value) => {
|
|
||||||
setState((s) => ({ ...s, ...value }));
|
|
||||||
}
|
|
||||||
|
|
||||||
const setTopicItem = (cardId, channelId, topic) => {
|
|
||||||
let name, nameSet
|
|
||||||
if (topic.detail.guid === profile.state.identity.guid) {
|
|
||||||
const identity = profile.state.identity;
|
|
||||||
if (identity.name) {
|
|
||||||
name = identity.name;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
name = `${identity.handle}@${identity.node}`;
|
|
||||||
}
|
|
||||||
nameSet = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const contact = getCardByGuid(card.state.cards, topic.detail.guid);
|
|
||||||
if (contact) {
|
|
||||||
if (contact?.card?.profile?.name) {
|
|
||||||
name = contact.card.profile.name;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
name = `${contact.card.profile.handle}@${contact.card.profile.node}`;
|
|
||||||
}
|
|
||||||
nameSet = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
name = 'unknown';
|
|
||||||
nameSet = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let timestamp;
|
|
||||||
const date = new Date(topic.detail.created * 1000);
|
|
||||||
const now = new Date();
|
|
||||||
const offset = now.getTime() - date.getTime();
|
|
||||||
if(offset < 86400000) {
|
|
||||||
timestamp = moment(date).format('h:mma');
|
|
||||||
}
|
|
||||||
else if (offset < 31449600000) {
|
|
||||||
timestamp = moment(date).format('M/DD');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
timestamp = moment(date).format('M/DD/YYYY');
|
|
||||||
}
|
|
||||||
|
|
||||||
const { topicId } = topic;
|
|
||||||
return { name, nameSet, timestamp, cardId, channelId, topicId, id: `${cardId}:${channelId}:${topicId}` };
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadBlocked = async () => {
|
|
||||||
const channels = [];
|
|
||||||
channel.state.channels.forEach((channelItem, channelId, map) => {
|
|
||||||
channels.push({ channelId });
|
|
||||||
});
|
|
||||||
card.state.cards.forEach((cardItem, cardId, map) => {
|
|
||||||
cardItem.channels.forEach((channelItem, channelId, map) => {
|
|
||||||
channels.push({ cardId, channelId });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const merged = [];
|
|
||||||
for(let i = 0; i < channels.length; i++) {
|
|
||||||
let topics;
|
|
||||||
const { cardId, channelId } = channels[i];
|
|
||||||
if (cardId) {
|
|
||||||
topics = await card.actions.getTopicItems(cardId, channelId);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
topics = await channel.actions.getTopicItems(channelId);
|
|
||||||
}
|
|
||||||
topics.forEach((topic) => {
|
|
||||||
if (topic.blocked) {
|
|
||||||
merged.push(setTopicItem(cardId, channelId, topic));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateState({ messages: merged });
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
loadBlocked();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
unblock: async (cardId, channelId, topicId) => {
|
|
||||||
const id = `${cardId}:${channelId}:${topicId}`;
|
|
||||||
if (cardId) {
|
|
||||||
card.actions.clearTopicFlag(cardId, channelId, topicId);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
channel.actions.clearTopicFlag(channelId, topicId);
|
|
||||||
}
|
|
||||||
updateState({ messages: state.messages.filter(item => item.id !== id) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return { state, actions };
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
import { FlatList, View, Alert, TouchableOpacity, Text } from 'react-native';
|
|
||||||
import { styles } from './BlockedTopics.styled';
|
|
||||||
import { useBlockedTopics } from './useBlockedTopics.hook';
|
|
||||||
import { Logo } from 'utils/Logo';
|
|
||||||
|
|
||||||
export function BlockedTopics() {
|
|
||||||
|
|
||||||
const { state, actions } = useBlockedTopics();
|
|
||||||
|
|
||||||
const unblock = (cardId, channelId) => {
|
|
||||||
Alert.alert(
|
|
||||||
'Unblocking Contact',
|
|
||||||
'Confirm?',
|
|
||||||
[
|
|
||||||
{ text: "Cancel", onPress: () => {}, },
|
|
||||||
{ text: "Unblock", onPress: () => actions.unblock(cardId, channelId) },
|
|
||||||
],
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const BlockedItem = ({ item }) => {
|
|
||||||
return (
|
|
||||||
<TouchableOpacity style={styles.item} onPress={() => unblock(item.cardId, item.channelId)}>
|
|
||||||
<View style={styles.detail}>
|
|
||||||
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text>
|
|
||||||
<Text style={styles.created} numberOfLines={1} ellipsizeMode={'tail'}>{ item.created }</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.container}>
|
|
||||||
{ state.channels.length === 0 && (
|
|
||||||
<Text style={styles.default}>No Blocked Topics</Text>
|
|
||||||
)}
|
|
||||||
{ state.channels.length !== 0 && (
|
|
||||||
<FlatList
|
|
||||||
data={state.channels}
|
|
||||||
renderItem={({item}) => <BlockedItem item={item} />}
|
|
||||||
keyExtractor={item => item.id}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
|
||||||
import { Colors } from 'constants/Colors';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
display: 'flex',
|
|
||||||
width: '100%',
|
|
||||||
justifyContent: 'center',
|
|
||||||
fontSize: 14,
|
|
||||||
height: 200,
|
|
||||||
},
|
|
||||||
default: {
|
|
||||||
textAlign: 'center',
|
|
||||||
color: Colors.grey,
|
|
||||||
},
|
|
||||||
item: {
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: 32,
|
|
||||||
paddingLeft: 16,
|
|
||||||
alignItems: 'center',
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderColor: Colors.itemDivider,
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
paddingLeft: 12,
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'center',
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
color: Colors.text,
|
|
||||||
fontSize: 14,
|
|
||||||
flexGrow: 1,
|
|
||||||
flexShrink: 1,
|
|
||||||
minWidth: 0,
|
|
||||||
},
|
|
||||||
created: {
|
|
||||||
color: Colors.text,
|
|
||||||
fontSize: 12,
|
|
||||||
paddingRight: 16,
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,92 +0,0 @@
|
|||||||
import { useState, useEffect, useContext } from 'react';
|
|
||||||
import { CardContext } from 'context/CardContext';
|
|
||||||
import { ChannelContext } from 'context/ChannelContext';
|
|
||||||
import { ProfileContext } from 'context/ProfileContext';
|
|
||||||
import { getCardByGuid } from 'context/cardUtil';
|
|
||||||
import { getChannelSubjectLogo } from 'context/channelUtil';
|
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
export function useBlockedTopics() {
|
|
||||||
|
|
||||||
const [state, setState] = useState({
|
|
||||||
channels: []
|
|
||||||
});
|
|
||||||
|
|
||||||
const profile = useContext(ProfileContext);
|
|
||||||
const card = useContext(CardContext);
|
|
||||||
const channel = useContext(ChannelContext);
|
|
||||||
|
|
||||||
const updateState = (value) => {
|
|
||||||
setState((s) => ({ ...s, ...value }));
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCard = (guid) => {
|
|
||||||
let contact = null
|
|
||||||
card.state.cards.forEach((card, cardId, map) => {
|
|
||||||
if (card?.profile?.guid === guid) {
|
|
||||||
contact = card;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return contact;
|
|
||||||
}
|
|
||||||
|
|
||||||
const setChannelItem = (item) => {
|
|
||||||
let timestamp;
|
|
||||||
const date = new Date(item.channel.detail.created * 1000);
|
|
||||||
const now = new Date();
|
|
||||||
const offset = now.getTime() - date.getTime();
|
|
||||||
if(offset < 86400000) {
|
|
||||||
timestamp = moment(date).format('h:mma');
|
|
||||||
}
|
|
||||||
else if (offset < 31449600000) {
|
|
||||||
timestamp = moment(date).format('M/DD');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
timestamp = moment(date).format('M/DD/YYYY');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const profileGuid = profile.state?.identity?.guid;
|
|
||||||
const { logo, subject } = getChannelSubjectLogo(item.cardId, profileGuid, item.channel, card.state.cards, card.actions.getCardImageUrl);
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: `${item.cardId}:${item.channel.channelId}`,
|
|
||||||
cardId: item.cardId,
|
|
||||||
channelId: item.channel.channelId,
|
|
||||||
name: subject,
|
|
||||||
created: timestamp,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let merged = [];
|
|
||||||
card.state.cards.forEach((cardItem, cardId, map) => {
|
|
||||||
cardItem.channels.forEach((channelItem) => {
|
|
||||||
if (channelItem.blocked) {
|
|
||||||
merged.push({ cardId, channel: channelItem });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
channel.state.channels.forEach((channelItem, channelId, map) => {
|
|
||||||
if (channelItem.blocked) {
|
|
||||||
merged.push({ channel: channelItem });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const items = merged.map(setChannelItem);
|
|
||||||
updateState({ channels: items });
|
|
||||||
}, [card.state, channel.state]);
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
unblock: async (cardId, channelId) => {
|
|
||||||
if (cardId) {
|
|
||||||
await card.actions.clearChannelFlag(cardId, channelId);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
await channel.actions.clearChannelFlag(channelId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return { state, actions };
|
|
||||||
}
|
|
||||||
|
|
@ -49,7 +49,7 @@ export function useProfile() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { name, handle, node, location, description, image } = profile.state.identity;
|
const { name, handle, node, location, description, image } = profile.state.identity;
|
||||||
const imageSource = image ? { uri: profile.state.imageUrl } : avatar;
|
const imageSource = image ? { uri: profile.state.imageUrl } : avatar;
|
||||||
const username = `${handle} / ${node}`
|
const username = `${handle}/${node}`
|
||||||
updateState({ name, username, location, description, imageSource });
|
updateState({ name, username, location, description, imageSource });
|
||||||
}, [profile.state]);
|
}, [profile.state]);
|
||||||
|
|
||||||
|
18
app/mobile/src/session/profileSettings/ProfileSettings.jsx
Normal file
18
app/mobile/src/session/profileSettings/ProfileSettings.jsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { ScrollView, View } from 'react-native';
|
||||||
|
import { Profile } from '../profile/Profile';
|
||||||
|
import { Settings } from '../settings/Settings';
|
||||||
|
import { styles } from './ProfileSettings.styled';
|
||||||
|
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
|
export function ProfileSettings() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView style={styles.drawer}>
|
||||||
|
<SafeAreaView style={styles.container} edges={['top', 'right']}>
|
||||||
|
<Profile drawer={true} />
|
||||||
|
<Settings drawer={true} />
|
||||||
|
</SafeAreaView>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
|||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import { Colors } from 'constants/Colors';
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
drawer: {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
backgroundColor: Colors.drawerBase,
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user