cleanup for profile screen

This commit is contained in:
balzack 2022-11-02 09:55:39 -07:00
parent 73175d34e7
commit 6b620fa8ed
17 changed files with 830 additions and 456 deletions

View File

@ -314,7 +314,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 27;
CURRENT_PROJECT_VERSION = 30;
DEVELOPMENT_TEAM = 3P65PQ7SUR;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
@ -326,7 +326,7 @@
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.2;
MARKETING_VERSION = 1.3;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@ -352,14 +352,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 27;
CURRENT_PROJECT_VERSION = 30;
DEVELOPMENT_TEAM = 3P65PQ7SUR;
INFOPLIST_FILE = Databag/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Databag;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.2;
MARKETING_VERSION = 1.3;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",

View File

@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.2</string>
<string>1.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>

View File

@ -2,14 +2,11 @@ import { useEffect, useContext } from 'react';
import { KeyboardAvoidingView, Modal, Alert, TextInput, ScrollView, View, Switch, TouchableOpacity, Text } from 'react-native';
import { styles } from './Profile.styled';
import { useProfile } from './useProfile.hook';
import { Logo } from 'utils/Logo';
import Ionicons from '@expo/vector-icons/AntDesign';
import Colors from 'constants/Colors';
import ImagePicker from 'react-native-image-crop-picker'
import { SafeAreaView } from 'react-native-safe-area-context';
import { BlockedTopics } from './blockedTopics/BlockedTopics';
import { BlockedContacts } from './blockedContacts/BlockedContacts';
import { BlockedMessages } from './blockedMessages/BlockedMessages';
import { ProfileBody } from './profileBody/ProfileBody';
export function Profile({ navigation }) {
@ -32,47 +29,6 @@ export function Profile({ navigation }) {
}
}, [navigation, state]);
const setVisible = async (visible) => {
try {
await actions.setVisible(visible);
}
catch (err) {
console.log(err);
Alert.alert(
'Account Update Failed',
'Please try again.'
);
}
}
const saveDetails = async () => {
try {
await actions.saveDetails();
actions.hideDetailEdit();
}
catch (err) {
console.log(err);
Alert.alert(
'Failed to Save Details',
'Please try again.'
)
}
}
const saveLogin = async () => {
try {
await actions.saveLogin();
actions.hideLoginEdit();
}
catch (err) {
console.log(err);
Alert.alert(
'Failed to Change Login',
'Please try again.'
)
}
}
const remove = async () => {
try {
await actions.remove();
@ -101,108 +57,15 @@ export function Profile({ navigation }) {
);
}
const onGallery = async () => {
try {
const full = await ImagePicker.openPicker({ mediaType: 'photo', width: 256, height: 256 });
const crop = await ImagePicker.openCropper({ path: full.path, width: 256, height: 256, cropperCircleOverlay: true, includeBase64: true });
await actions.setProfileImage(crop.data);
}
catch (err) {
console.log(err);
}
}
const onCamera = async () => {
try {
const full = await ImagePicker.openCamera({ mediaType: 'photo', width: 256, height: 256 });
const crop = await ImagePicker.openCropper({ path: full.path, width: 256, height: 256, cropperCircleOverlay: true, includeBase64: true });
await actions.setProfileImage(crop.data);
}
catch (err) {
console.log(err);
}
}
const enabled = (state.checked && state.available && state.editConfirm === state.editPassword && state.editPassword);
const Body = () => {
return (
<View style={styles.container}>
<View style={{ width: 128 }}>
<Logo src={state.imageSource} width={128} height={128} radius={8} />
<TouchableOpacity style={styles.gallery} onPress={onGallery}>
<Ionicons name="picture" size={14} color={Colors.white} />
</TouchableOpacity>
</View>
{ state.disconnected > 3 && (
<View style={styles.alert}>
<Text style={styles.disconnected}>Disconnected</Text>
</View>
)}
{ !state.disconnected && (
<View style={styles.alert} />
)}
<TouchableOpacity style={styles.detail} onPress={actions.showDetailEdit}>
<View style={styles.attribute}>
{ state.name && (
<Text style={styles.nametext}>{ state.name }</Text>
)}
{ !state.name && (
<Text style={styles.nonametext}>Name</Text>
)}
<Ionicons name="edit" size={16} color={Colors.text} />
</View>
<View style={styles.attribute}>
<View style={styles.icon}>
<Ionicons name="enviromento" size={14} color={Colors.text} />
</View>
{ state.location && (
<Text style={styles.locationtext}>{ state.location }</Text>
)}
{ !state.location && (
<Text style={styles.nolocationtext}>Location</Text>
)}
</View>
<View style={styles.attribute}>
<View style={styles.icon}>
<Ionicons name="book" size={14} color={Colors.text} />
</View>
{ state.description && (
<Text style={styles.descriptiontext}>{ state.description }</Text>
)}
{ !state.description && (
<Text style={styles.nodescriptiontext}>Description</Text>
)}
</View>
</TouchableOpacity>
<View style={styles.visible}>
<TouchableOpacity onPress={() => setVisible(!state.searchable)} activeOpacity={1}>
<Text style={styles.visibleText}>Visible in Registry</Text>
</TouchableOpacity>
<Switch style={styles.visibleSwitch} value={state.searchable} onValueChange={setVisible} trackColor={styles.switch}/>
</View>
<TouchableOpacity style={styles.link} onPress={actions.showLoginEdit}>
<Text style={styles.linkText}>Change Login</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.link} onPress={actions.showBlockedCards}>
<Text style={styles.linkText}>Manage Blocked Contacts</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.link} onPress={actions.showBlockedChannels}>
<Text style={styles.linkText}>Manage Blocked Topics</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.link} onPress={actions.showBlockedMessages}>
<Text style={styles.linkText}>Manage Blocked Messages</Text>
</TouchableOpacity>
</View>
);
};
return (
<ScrollView style={styles.wrapper}>
<ScrollView style={styles.background}>
{ state.tabbed && (
<View style={styles.body}>
<Body />
</View>
<>
<ProfileBody />
<TouchableOpacity style={styles.erase} activeOpacity={1} onPress={actions.showDelete}>
<Text style={styles.eraseText}>Delete Your Account</Text>
</TouchableOpacity>
</>
)}
{ !state.tabbed && (
<SafeAreaView style={styles.drawer} edges={['top', 'bottom', 'right']}>
@ -212,184 +75,12 @@ export function Profile({ navigation }) {
<Ionicons name="logout" size={16} color={Colors.grey} />
</TouchableOpacity>
</View>
<Body />
<ProfileBody />
<TouchableOpacity style={styles.erase} activeOpacity={1} onPress={actions.showDelete}>
<Text style={styles.eraseText}>Delete Your Account</Text>
</TouchableOpacity>
</SafeAreaView>
)}
<Modal
animationType="fade"
transparent={true}
visible={state.blockedCards}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideBlockedCards}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Blocked Contacts:</Text>
<View style={styles.editList}>
<BlockedContacts />
</View>
<View style={styles.editControls}>
<TouchableOpacity style={styles.close} onPress={actions.hideBlockedCards}>
<Text>Close</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.blockedChannels}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideBlockedChannels}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Blocked Topics:</Text>
<View style={styles.editList}>
<BlockedTopics />
</View>
<View style={styles.editControls}>
<TouchableOpacity style={styles.close} onPress={actions.hideBlockedChannels}>
<Text>Close</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.blockedMessages}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideBlockedMessages}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Blocked Messages:</Text>
<View style={styles.editList}>
<BlockedMessages />
</View>
<View style={styles.editControls}>
<TouchableOpacity style={styles.close} onPress={actions.hideBlockedMessages}>
<Text>Close</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.showDetailEdit}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideDetailEdit}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Edit Details:</Text>
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editName} onChangeText={actions.setEditName}
autoCapitalize="words" placeholder="Name" placeholderTextColor={Colors.grey} />
</View>
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editLocation} onChangeText={actions.setEditLocation}
autoCapitalize="words" placeholder="Location" placeholderTextColor={Colors.grey} />
</View>
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editDescription} onChangeText={actions.setEditDescription}
autoCapitalize="sentences" placeholder="Description" multiline={true}
placeholderTextColor={Colors.grey} />
</View>
<View style={styles.editControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideDetailEdit}>
<Text>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.save} onPress={saveDetails}>
<Text style={styles.saveText}>Save</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.showLoginEdit}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideLoginEdit}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Change Login:</Text>
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editHandle} onChangeText={actions.setEditHandle}
autoCapitalize={'none'} placeholder="Username" placeholderTextColor={Colors.grey} />
{ state.checked && state.available && (
<Ionicons style={styles.icon} name="checkcircleo" size={18} color={Colors.background} />
)}
{ state.checked && !state.available && (
<Ionicons style={styles.icon} name="exclamationcircleo" size={18} color={Colors.alert} />
)}
</View>
{ !state.showPassword && (
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editPassword} onChangeText={actions.setEditPassword}
autoCapitalize={'none'} secureTextEntry={true} placeholder="Password"
placeholderTextColor={Colors.grey} />
<TouchableOpacity onPress={actions.showPassword}>
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
</TouchableOpacity>
</View>
)}
{ state.showPassword && (
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editPassword} onChangeText={actions.setEditPassword}
autoCapitalize={'none'} secureTextEntry={false} placeholder="Password"
placeholderTextColor={Colors.grey} />
<TouchableOpacity onPress={actions.hidePassword}>
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
</TouchableOpacity>
</View>
)}
{ !state.showConfirm && (
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editConfirm} onChangeText={actions.setEditConfirm}
autoCapitalize={'none'} secureTextEntry={true} placeholder="Confirm"
placeholderTextColor={Colors.grey} />
<TouchableOpacity onPress={actions.showConfirm}>
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
</TouchableOpacity>
</View>
)}
{ state.showConfirm && (
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editConfirm} onChangeText={actions.setEditConfirm}
autoCapitalize={'none'} secureTextEntry={false} placeholder="Confirm"
placeholderTextColor={Colors.grey} />
<TouchableOpacity onPress={actions.hideConfirm}>
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
</TouchableOpacity>
</View>
)}
<View style={styles.editControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideLoginEdit}>
<Text>Cancel</Text>
</TouchableOpacity>
{ enabled && (
<TouchableOpacity style={styles.save} onPress={saveLogin}>
<Text style={styles.saveText}>Save</Text>
</TouchableOpacity>
)}
{ !enabled && (
<View style={styles.disabled}>
<Text style={styles.disabledText}>Save</Text>
</View>
)}
</View>
</View>
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
@ -422,7 +113,6 @@ export function Profile({ navigation }) {
</View>
</KeyboardAvoidingView>
</Modal>
</ScrollView>
)
}

View File

@ -17,9 +17,6 @@ export const styles = StyleSheet.create({
wrapper: {
backgroundColor: Colors.formBackground,
},
drawer: {
paddingTop: 16,
},
action: {
width: 64,
display: 'flex',
@ -42,9 +39,6 @@ export const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
body: {
paddingTop: 16,
},
header: {
display: 'flex',
flexDirection: 'row',
@ -166,13 +160,19 @@ export const styles = StyleSheet.create({
borderRadius: 4,
padding: 8,
width: 72,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
removeText: {
color: Colors.white,
},
erase: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
},
switch: {
false: Colors.grey,
true: Colors.background,
@ -291,6 +291,9 @@ export const styles = StyleSheet.create({
paddingLeft: 8,
color: Colors.white,
},
eraseText: {
color: Colors.alert,
},
saveText: {
color: Colors.white,
},

View File

@ -0,0 +1,319 @@
import { useEffect, useContext } from 'react';
import { KeyboardAvoidingView, Modal, Alert, TextInput, ScrollView, View, Switch, TouchableOpacity, Text } from 'react-native';
import { styles } from './ProfileBody.styled';
import { useProfileBody } from './useProfileBody.hook';
import { Logo } from 'utils/Logo';
import Ionicons from '@expo/vector-icons/AntDesign';
import Colors from 'constants/Colors';
import ImagePicker from 'react-native-image-crop-picker'
import { SafeAreaView } from 'react-native-safe-area-context';
import { BlockedTopics } from './blockedTopics/BlockedTopics';
import { BlockedContacts } from './blockedContacts/BlockedContacts';
import { BlockedMessages } from './blockedMessages/BlockedMessages';
export function ProfileBody({ navigation }) {
const { state, actions } = useProfileBody();
const setVisible = async (visible) => {
try {
await actions.setVisible(visible);
}
catch (err) {
console.log(err);
Alert.alert(
'Account Update Failed',
'Please try again.'
);
}
}
const saveDetails = async () => {
try {
await actions.saveDetails();
actions.hideDetailEdit();
}
catch (err) {
console.log(err);
Alert.alert(
'Failed to Save Details',
'Please try again.'
)
}
}
const saveLogin = async () => {
try {
await actions.saveLogin();
actions.hideLoginEdit();
}
catch (err) {
console.log(err);
Alert.alert(
'Failed to Change Login',
'Please try again.'
)
}
}
const onGallery = async () => {
try {
const full = await ImagePicker.openPicker({ mediaType: 'photo', width: 256, height: 256 });
const crop = await ImagePicker.openCropper({ path: full.path, width: 256, height: 256, cropperCircleOverlay: true, includeBase64: true });
await actions.setProfileImage(crop.data);
}
catch (err) {
console.log(err);
}
}
const enabled = (state.checked && state.available && state.editConfirm === state.editPassword && state.editPassword);
return (
<View style={styles.container}>
<View style={{ width: 128 }}>
<Logo src={state.imageSource} width={128} height={128} radius={8} />
<TouchableOpacity style={styles.gallery} onPress={onGallery}>
<Ionicons name="picture" size={14} color={Colors.white} />
</TouchableOpacity>
</View>
{ state.disconnected > 3 && (
<View style={styles.alert}>
<Text style={styles.disconnected}>Disconnected</Text>
</View>
)}
{ !state.disconnected && (
<View style={styles.alert} />
)}
<TouchableOpacity style={styles.detail} onPress={actions.showDetailEdit}>
<View style={styles.attribute}>
{ state.name && (
<Text style={styles.nametext}>{ state.name }</Text>
)}
{ !state.name && (
<Text style={styles.nonametext}>Name</Text>
)}
<Ionicons name="edit" size={16} color={Colors.text} />
</View>
<View style={styles.attribute}>
<View style={styles.icon}>
<Ionicons name="enviromento" size={14} color={Colors.text} />
</View>
{ state.location && (
<Text style={styles.locationtext}>{ state.location }</Text>
)}
{ !state.location && (
<Text style={styles.nolocationtext}>Location</Text>
)}
</View>
<View style={styles.attribute}>
<View style={styles.icon}>
<Ionicons name="book" size={14} color={Colors.text} />
</View>
{ state.description && (
<Text style={styles.descriptiontext}>{ state.description }</Text>
)}
{ !state.description && (
<Text style={styles.nodescriptiontext}>Description</Text>
)}
</View>
</TouchableOpacity>
<View style={styles.visible}>
<TouchableOpacity onPress={() => setVisible(!state.searchable)} activeOpacity={1}>
<Text style={styles.visibleText}>Visible in Registry</Text>
</TouchableOpacity>
<Switch style={styles.visibleSwitch} value={state.searchable} onValueChange={setVisible} trackColor={styles.switch}/>
</View>
<TouchableOpacity style={styles.link} onPress={actions.showLoginEdit}>
<Text style={styles.linkText}>Change Login</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.link} onPress={actions.showBlockedCards}>
<Text style={styles.linkText}>Manage Blocked Contacts</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.link} onPress={actions.showBlockedChannels}>
<Text style={styles.linkText}>Manage Blocked Topics</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.link} onPress={actions.showBlockedMessages}>
<Text style={styles.linkText}>Manage Blocked Messages</Text>
</TouchableOpacity>
<Modal
animationType="fade"
transparent={true}
visible={state.blockedCards}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideBlockedCards}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Blocked Contacts:</Text>
<View style={styles.editList}>
<BlockedContacts />
</View>
<View style={styles.editControls}>
<TouchableOpacity style={styles.close} onPress={actions.hideBlockedCards}>
<Text>Close</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.blockedChannels}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideBlockedChannels}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Blocked Topics:</Text>
<View style={styles.editList}>
<BlockedTopics />
</View>
<View style={styles.editControls}>
<TouchableOpacity style={styles.close} onPress={actions.hideBlockedChannels}>
<Text>Close</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.blockedMessages}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideBlockedMessages}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Blocked Messages:</Text>
<View style={styles.editList}>
<BlockedMessages />
</View>
<View style={styles.editControls}>
<TouchableOpacity style={styles.close} onPress={actions.hideBlockedMessages}>
<Text>Close</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.showDetailEdit}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideDetailEdit}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Edit Details:</Text>
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editName} onChangeText={actions.setEditName}
autoCapitalize="words" placeholder="Name" placeholderTextColor={Colors.grey} />
</View>
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editLocation} onChangeText={actions.setEditLocation}
autoCapitalize="words" placeholder="Location" placeholderTextColor={Colors.grey} />
</View>
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editDescription} onChangeText={actions.setEditDescription}
autoCapitalize="sentences" placeholder="Description" multiline={true}
placeholderTextColor={Colors.grey} />
</View>
<View style={styles.editControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideDetailEdit}>
<Text>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.save} onPress={saveDetails}>
<Text style={styles.saveText}>Save</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.showLoginEdit}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideLoginEdit}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Change Login:</Text>
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editHandle} onChangeText={actions.setEditHandle}
autoCapitalize={'none'} placeholder="Username" placeholderTextColor={Colors.grey} />
{ state.checked && state.available && (
<Ionicons style={styles.icon} name="checkcircleo" size={18} color={Colors.background} />
)}
{ state.checked && !state.available && (
<Ionicons style={styles.icon} name="exclamationcircleo" size={18} color={Colors.alert} />
)}
</View>
{ !state.showPassword && (
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editPassword} onChangeText={actions.setEditPassword}
autoCapitalize={'none'} secureTextEntry={true} placeholder="Password"
placeholderTextColor={Colors.grey} />
<TouchableOpacity onPress={actions.showPassword}>
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
</TouchableOpacity>
</View>
)}
{ state.showPassword && (
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editPassword} onChangeText={actions.setEditPassword}
autoCapitalize={'none'} secureTextEntry={false} placeholder="Password"
placeholderTextColor={Colors.grey} />
<TouchableOpacity onPress={actions.hidePassword}>
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
</TouchableOpacity>
</View>
)}
{ !state.showConfirm && (
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editConfirm} onChangeText={actions.setEditConfirm}
autoCapitalize={'none'} secureTextEntry={true} placeholder="Confirm"
placeholderTextColor={Colors.grey} />
<TouchableOpacity onPress={actions.showConfirm}>
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
</TouchableOpacity>
</View>
)}
{ state.showConfirm && (
<View style={styles.inputField}>
<TextInput style={styles.input} value={state.editConfirm} onChangeText={actions.setEditConfirm}
autoCapitalize={'none'} secureTextEntry={false} placeholder="Confirm"
placeholderTextColor={Colors.grey} />
<TouchableOpacity onPress={actions.hideConfirm}>
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
</TouchableOpacity>
</View>
)}
<View style={styles.editControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideLoginEdit}>
<Text>Cancel</Text>
</TouchableOpacity>
{ enabled && (
<TouchableOpacity style={styles.save} onPress={saveLogin}>
<Text style={styles.saveText}>Save</Text>
</TouchableOpacity>
)}
{ !enabled && (
<View style={styles.disabled}>
<Text style={styles.disabledText}>Save</Text>
</View>
)}
</View>
</View>
</KeyboardAvoidingView>
</Modal>
</View>
);
};

View File

@ -0,0 +1,301 @@
import { StyleSheet } from 'react-native';
import { Colors } from 'constants/Colors';
export const styles = StyleSheet.create({
container: {
width: '100%',
display: 'flex',
flexDirection: 'column',
paddingBottom: 32,
alignItems: 'center',
justifyContent: 'center',
paddingTop: 32,
},
icon: {
paddingTop: 2,
},
wrapper: {
backgroundColor: Colors.formBackground,
},
drawer: {
paddingTop: 16,
},
action: {
width: 64,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
titleText: {
fontSize: 18,
overflow: 'hidden',
flexGrow: 1,
textAlign: 'center',
},
title: {
display: 'flex',
flexDirection: 'row',
flexGrow: 1,
flex: 1,
width: '100%',
textAlign: 'start',
alignItems: 'center',
justifyContent: 'center',
},
body: {
paddingTop: 16,
},
header: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-end',
justifyContent: 'center',
},
headerText: {
paddingLeft: 16,
fontSize: 14,
paddingRight: 8,
color: Colors.text,
},
camera: {
position: 'absolute',
bottom: 0,
left: 0,
padding: 8,
backgroundColor: Colors.lightgrey,
borderBottomLeftRadius: 8,
borderTopRightRadius: 8,
},
gallery: {
position: 'absolute',
bottom: 0,
right: 0,
padding: 8,
backgroundColor: Colors.lightgrey,
borderBottomRightRadius: 8,
borderTopLeftRadius: 8,
},
alert: {
height: 32,
},
detail: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
color: Colors.text,
paddingLeft: 32,
paddingRight: 32,
},
attribute: {
display: 'flex',
flexDirection: 'row',
paddingBottom: 8,
},
nonametext: {
fontSize: 18,
paddingRight: 8,
fontWeight: 'bold',
color: Colors.grey,
},
nametext: {
fontSize: 18,
paddingRight: 8,
fontWeight: 'bold',
},
locationtext: {
fontSize: 16,
paddingLeft: 8,
color: Colors.text,
},
nolocationtext: {
fontSize: 16,
paddingLeft: 8,
color: Colors.grey,
},
descriptiontext: {
fontSize: 16,
paddingLeft: 8,
color: Colors.text,
},
nodescriptiontext: {
fontSize: 16,
paddingLeft: 8,
color: Colors.grey,
},
visible: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
paddingTop: 16,
},
visibleText: {
fontSize: 16,
color: Colors.text,
},
visibleSwitch: {
transform: [{ scaleX: .7 }, { scaleY: .7 }],
},
logout: {
marginTop: 32,
borderRadius: 4,
backgroundColor: Colors.primary,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
paddingLeft: 8,
paddingRight: 8,
paddingTop: 8,
paddingBottom: 8,
},
logoutText: {
color: Colors.white,
paddingLeft: 8,
},
unconfirmed: {
backgroundColor: Colors.lightgrey,
borderRadius: 4,
padding: 8,
width: 72,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
remove: {
backgroundColor: Colors.error,
borderRadius: 4,
padding: 8,
width: 72,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
removeText: {
color: Colors.white,
},
switch: {
false: Colors.grey,
true: Colors.background,
},
editWrapper: {
display: 'flex',
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(52, 52, 52, 0.8)'
},
editContainer: {
backgroundColor: Colors.formBackground,
padding: 16,
width: '80%',
maxWidth: 400,
},
editHeader: {
fontSize: 18,
paddingBottom: 16,
},
editList: {
width: '100%',
borderWidth: 1,
borderColor: Colors.lightgrey,
borderRadius: 2,
},
inputField: {
width: '100%',
borderWidth: 1,
borderColor: Colors.lightgrey,
borderRadius: 4,
padding: 8,
marginBottom: 8,
maxHeight: 92,
display: 'flex',
flexDirection: 'row',
},
input: {
fontSize: 14,
flexGrow: 1,
},
editControls: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
},
close: {
borderWidth: 1,
borderColor: Colors.lightgrey,
borderRadius: 4,
padding: 8,
marginTop: 8,
width: 72,
display: 'flex',
alignItems: 'center',
},
cancel: {
borderWidth: 1,
borderColor: Colors.lightgrey,
borderRadius: 4,
padding: 8,
marginRight: 8,
width: 72,
display: 'flex',
alignItems: 'center',
},
disabled: {
borderWidth: 1,
borderColor: Colors.lightgrey,
padding: 8,
borderRadius: 4,
width: 72,
display: 'flex',
alignItems: 'center',
},
disabledText: {
color: Colors.disabled,
},
save: {
padding: 8,
borderRadius: 4,
backgroundColor: Colors.primary,
width: 72,
display: 'flex',
alignItems: 'center',
},
save: {
padding: 8,
borderRadius: 4,
backgroundColor: Colors.primary,
width: 72,
display: 'flex',
alignItems: 'center',
},
link: {
marginTop: 16,
},
linkText: {
color: Colors.primary,
},
delete: {
backgroundColor: Colors.error,
marginTop: 16,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
paddingLeft: 8,
paddingRight: 8,
paddingTop: 8,
paddingBottom: 8,
borderRadius: 4,
},
deleteText: {
paddingLeft: 8,
color: Colors.white,
},
saveText: {
color: Colors.white,
},
disconnected: {
color: Colors.alert,
},
})

View File

@ -0,0 +1,179 @@
import { useState, useEffect, useRef, useContext } from 'react';
import { useNavigate } from 'react-router-dom';
import { useWindowDimensions } from 'react-native';
import { ProfileContext } from 'context/ProfileContext';
import { AccountContext } from 'context/AccountContext';
import { AppContext } from 'context/AppContext';
import config from 'constants/Config';
export function useProfileBody() {
const [state, setState] = useState({
name: null,
handle: null,
location: null,
description: null,
node: null,
imageSource: null,
searchable: null,
showDetailEdit: false,
showLoginEdit: false,
editName: null,
editLocation: null,
editDescription: null,
editHandle: null,
editPassword: null,
editConfirm: null,
checked: true,
available: true,
showPassword: false,
showConfirm: false,
blockedChannels: false,
blockedCards: false,
blockedMessages: false,
tabbed: null,
disconnected: false,
});
const app = useContext(AppContext);
const dimensions = useWindowDimensions();
const account = useContext(AccountContext);
const profile = useContext(ProfileContext);
const navigate = useNavigate();
const debounce = useRef(null);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
useEffect(() => {
if (dimensions.width > config.tabbedWidth) {
updateState({ tabbed: false });
}
else {
updateState({ tabbed: true });
}
}, [dimensions]);
useEffect(() => {
const { name, handle, node, location, description, image } = profile.state.profile;
const imageSource = image ? profile.state.imageUrl : 'avatar';
updateState({ name, handle, node, location, description, imageSource, editHandle: handle,
editName: name, editLocation: location, editDescription: description });
}, [profile]);
useEffect(() => {
updateState({ searchable: account.state.status.searchable });
}, [account]);
useEffect(() => {
const { disconnected } = app.state;
updateState({ disconnected });
}, [app]);
const actions = {
logout: () => {
app.actions.logout();
navigate('/');
},
remove: async () => {
await app.actions.remove();
updateState({ showDelete: false });
navigate('/');
},
setVisible: async (searchable) => {
updateState({ searchable });
await account.actions.setSearchable(searchable);
},
setProfileImage: async (data) => {
await profile.actions.setProfileImage(data);
},
showBlockedChannels: () => {
updateState({ blockedChannels: true });
},
hideBlockedChannels: () => {
updateState({ blockedChannels: false });
},
showBlockedCards: () => {
updateState({ blockedCards: true });
},
hideBlockedCards: () => {
updateState({ blockedCards: false });
},
showBlockedMessages: () => {
updateState({ blockedMessages: true });
},
hideBlockedMessages: () => {
updateState({ blockedMessages: false });
},
showLoginEdit: () => {
updateState({ showLoginEdit: true });
},
hideLoginEdit: () => {
updateState({ showLoginEdit: false });
},
showDetailEdit: () => {
updateState({ showDetailEdit: true });
},
hideDetailEdit: () => {
updateState({ showDetailEdit: false });
},
setEditName: (editName) => {
updateState({ editName });
},
setEditLocation: (editLocation) => {
updateState({ editLocation });
},
setEditDescription: (editDescription) => {
updateState({ editDescription });
},
showPassword: () => {
updateState({ showPassword: true });
},
hidePassword: () => {
updateState({ showPassword: false });
},
showConfirm: () => {
updateState({ showConfirm: true });
},
hideConfirm: () => {
updateState({ showConfirm: false });
},
setEditHandle: (editHandle) => {
updateState({ editHandle, checked: false });
if (debounce.current != null) {
clearTimeout(debounce.current);
}
debounce.current = setTimeout(async () => {
try {
if (editHandle === state.handle) {
updateState({ available: true, checked: true });
}
else {
const available = await profile.actions.getHandle(editHandle);
updateState({ available, checked: true });
}
}
catch (err) {
console.log(err);
}
}, 1000);
},
setEditPassword: (editPassword) => {
updateState({ editPassword });
},
setEditConfirm: (editConfirm) => {
updateState({ editConfirm });
},
saveDetails: async () => {
await profile.actions.setProfileData(state.editName, state.editLocation, state.editDescription);
},
saveLogin: async () => {
await account.actions.setLogin(state.editHandle, state.editPassword);
},
};
return { state, actions };
}

View File

@ -2,7 +2,6 @@ import { useState, useEffect, useRef, useContext } from 'react';
import { useNavigate } from 'react-router-dom';
import { useWindowDimensions } from 'react-native';
import { ProfileContext } from 'context/ProfileContext';
import { AccountContext } from 'context/AccountContext';
import { AppContext } from 'context/AppContext';
import config from 'constants/Config';
@ -11,38 +10,16 @@ export function useProfile() {
const [state, setState] = useState({
name: null,
handle: null,
location: null,
description: null,
node: null,
imageSource: null,
searchable: null,
showDetailEdit: false,
showLoginEdit: false,
editName: null,
editLocation: null,
editDescription: null,
editHandle: null,
editPassword: null,
editConfirm: null,
checked: true,
available: true,
showPassword: false,
showConfirm: false,
showDelete: false,
blockedChannels: false,
blockedCards: false,
blockedMessages: false,
tabbed: null,
disconnected: false,
confirmDelete: null,
});
const app = useContext(AppContext);
const dimensions = useWindowDimensions();
const account = useContext(AccountContext);
const profile = useContext(ProfileContext);
const navigate = useNavigate();
const debounce = useRef(null);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
@ -64,10 +41,6 @@ export function useProfile() {
editName: name, editLocation: location, editDescription: description });
}, [profile]);
useEffect(() => {
updateState({ searchable: account.state.status.searchable });
}, [account]);
useEffect(() => {
const { disconnected } = app.state;
updateState({ disconnected });
@ -83,105 +56,14 @@ export function useProfile() {
updateState({ showDelete: false });
navigate('/');
},
setVisible: async (searchable) => {
updateState({ searchable });
await account.actions.setSearchable(searchable);
},
setProfileImage: async (data) => {
await profile.actions.setProfileImage(data);
},
showBlockedChannels: () => {
updateState({ blockedChannels: true });
},
hideBlockedChannels: () => {
updateState({ blockedChannels: false });
},
showBlockedCards: () => {
updateState({ blockedCards: true });
},
hideBlockedCards: () => {
updateState({ blockedCards: false });
},
showBlockedMessages: () => {
updateState({ blockedMessages: true });
},
hideBlockedMessages: () => {
updateState({ blockedMessages: false });
},
showLoginEdit: () => {
updateState({ showLoginEdit: true });
},
hideLoginEdit: () => {
updateState({ showLoginEdit: false });
},
showDetailEdit: () => {
updateState({ showDetailEdit: true });
},
hideDetailEdit: () => {
updateState({ showDetailEdit: false });
},
setEditName: (editName) => {
updateState({ editName });
},
setEditLocation: (editLocation) => {
updateState({ editLocation });
},
setEditDescription: (editDescription) => {
updateState({ editDescription });
},
setConfirmDelete: (confirmDelete) => {
updateState({ confirmDelete });
},
showPassword: () => {
updateState({ showPassword: true });
},
hidePassword: () => {
updateState({ showPassword: false });
},
showConfirm: () => {
updateState({ showConfirm: true });
},
hideConfirm: () => {
updateState({ showConfirm: false });
},
showDelete: () => {
updateState({ showDelete: true });
},
hideDelete: () => {
updateState({ showDelete: false });
},
setEditHandle: (editHandle) => {
updateState({ editHandle, checked: false });
if (debounce.current != null) {
clearTimeout(debounce.current);
}
debounce.current = setTimeout(async () => {
try {
if (editHandle === state.handle) {
updateState({ available: true, checked: true });
}
else {
const available = await profile.actions.getHandle(editHandle);
updateState({ available, checked: true });
}
}
catch (err) {
console.log(err);
}
}, 1000);
},
setEditPassword: (editPassword) => {
updateState({ editPassword });
},
setEditConfirm: (editConfirm) => {
updateState({ editConfirm });
},
saveDetails: async () => {
await profile.actions.setProfileData(state.editName, state.editLocation, state.editDescription);
},
saveLogin: async () => {
await account.actions.setLogin(state.editHandle, state.editPassword);
setConfirmDelete: (confirmDelete) => {
updateState({ confirmDelete });
},
};