styling admin screen for dark mode

This commit is contained in:
balzack 2023-09-30 10:20:33 -07:00
parent fd60909768
commit f26373e99c
5 changed files with 256 additions and 160 deletions

View File

@ -18,7 +18,7 @@ export const styles = StyleSheet.create({
modalContainer: {
width: '100%',
height: '100%',
backgroundColor: Colors.grey,
backgroundColor: Colors.modalBase,
alignItems: 'center',
justifyContent: 'center',
},
@ -53,7 +53,7 @@ export const styles = StyleSheet.create({
maxHeight: '80%',
padding: 8,
margin: 16,
backgroundColor: Colors.formBackground,
backgroundColor: Colors.modalBase,
},
done: {
paddingTop: 8,

View File

@ -1,4 +1,4 @@
import { TextInput, Alert, Switch, TouchableOpacity, View, Text, Modal, FlatList, KeyboardAvoidingView } from 'react-native';
import { ScrollView, TextInput, Alert, Switch, TouchableOpacity, View, Text, Modal, FlatList, KeyboardAvoidingView } from 'react-native';
import Clipboard from '@react-native-clipboard/clipboard';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
import AntIcon from 'react-native-vector-icons/AntDesign';
@ -7,6 +7,8 @@ import { styles } from './Dashboard.styled';
import { useLocation } from 'react-router-dom';
import { useDashboard } from './useDashboard.hook';
import { Logo } from 'utils/Logo';
import { BlurView } from "@react-native-community/blur";
import { InputField } from 'utils/InputField';
export function Dashboard(props) {
@ -55,25 +57,7 @@ export function Dashboard(props) {
}
const removeUser = (accountId) => {
Alert.alert(
"Deleting Account",
"Confirm?",
[
{ text: "Cancel", onPress: () => {}, },
{ text: "Delete", onPress: async() => {
try {
await actions.removeUser(accountId);
}
catch (err) {
console.log(err);
Alert.alert(
"Failed to Delete Account",
"Please try again.",
);
}
}}
]
)
actions.promptRemove(accountId);
}
const enableUser = async (accountId, enabled) => {
@ -149,94 +133,134 @@ export function Dashboard(props) {
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideEditConfig}
>
<KeyboardAvoidingView behavior="height" style={styles.modalBackground}>
<View style={styles.modalContainer}>
<View style={styles.modalHeader}>
<Text style={styles.modalHeaderText}>Settings:</Text>
</View>
<View style={styles.modalBody}>
<TextInput style={styles.input} value={state.domain} onChangeText={actions.setDomain}
autoCorrect={false} autoCapitalize="none" placeholder="Federated Host" />
<TextInput style={styles.input} value={state.storage}
<View style={styles.modalOverlay}>
<BlurView style={styles.modalOverlay} blurType={'dark'} blurAmount={2} reducedTransparencyFallbackColor='black' />
<KeyboardAvoidingView style={styles.modalBase} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<View style={styles.modalContainer}>
<View style={styles.modalHeader}>
<Text style={styles.modalHeaderText}>Settings:</Text>
</View>
<ScrollView style={styles.modalBody}>
<InputField style={styles.field}
label={'Federated Host'}
value={state.domain}
autoCapitalize={'none'}
spellCheck={false}
onChangeText={actions.setDomain}
/>
<InputField style={styles.field}
label={'Storage Limit (GB) / Account'}
value={state.storage}
autoCapitalize={'none'}
spellCheck={false}
keyboardType={'numeric'}
onChangeText={actions.setStorage}
keyboardType='numeric' placeholder="Storage Limit (GB) / Account" />
<Text style={styles.modalLabel}>Account Key Type:</Text>
<View style={styles.keyType}>
<TouchableOpacity style={styles.optionLeft} activeOpacity={1}
onPress={() => actions.setKeyType('RSA2048')}>
{ state.keyType === 'RSA2048' && (
<View style={styles.selected} />
)}
{ state.keyType === 'RSA4096' && (
<View style={styles.radio} />
)}
<Text style={styles.option}>RSA 2048</Text>
/>
<Text style={styles.modalLabel}>Account Key Type:</Text>
<View style={styles.keyType}>
<TouchableOpacity style={styles.optionLeft} activeOpacity={1}
onPress={() => actions.setKeyType('RSA2048')}>
{ state.keyType === 'RSA2048' && (
<View style={styles.selected} />
)}
{ state.keyType === 'RSA4096' && (
<View style={styles.radio} />
)}
<Text style={styles.option}>RSA 2048</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.optionRight} activeOpacity={1}
onPress={() => actions.setKeyType('RSA4096')}>
{ state.keyType === 'RSA2048' && (
<View style={styles.radio} />
)}
{ state.keyType === 'RSA4096' && (
<View style={styles.selected} />
)}
<Text style={styles.option}>RSA 4096</Text>
</TouchableOpacity>
</View>
<TouchableOpacity style={styles.media} activeOpacity={1}
onPress={() => actions.setPushSupported(!state.pushSupported)}>
<Text style={styles.modalLabel}>Enable Push Notifications: </Text>
<Switch style={styles.switch} value={state.pushSupported}
onValueChange={actions.setPushSupported} trackColor={styles.track}/>
</TouchableOpacity>
<TouchableOpacity style={styles.optionRight} activeOpacity={1}
onPress={() => actions.setKeyType('RSA4096')}>
{ state.keyType === 'RSA2048' && (
<View style={styles.radio} />
)}
{ state.keyType === 'RSA4096' && (
<View style={styles.selected} />
)}
<Text style={styles.option}>RSA 4096</Text>
<View style={styles.label}></View>
<TouchableOpacity style={styles.media} activeOpacity={1}
onPress={() => actions.setEnableImage(!state.enableImage)}>
<Text style={styles.modalLabel}>Enable Image Queue: </Text>
<Switch style={styles.switch} value={state.enableImage}
onValueChange={actions.setEnableImage} trackColor={styles.track}/>
</TouchableOpacity>
<TouchableOpacity style={styles.media} activeOpacity={1}
onPress={() => actions.setEnableAudio(!state.enableAudio)}>
<Text style={styles.modalLabel}>Enable Audio Queue: </Text>
<Switch style={styles.switch} value={state.enableAudio}
onValueChange={actions.setEnableAudio} trackColor={styles.track}/>
</TouchableOpacity>
<TouchableOpacity style={styles.media} activeOpacity={1}
onPress={() => actions.setEnableVideo(!state.enableVideo)}>
<Text style={styles.modalLabel}>Enable Video Queue: </Text>
<Switch style={styles.switch} value={state.enableVideo}
onValueChange={actions.setEnableVideo} trackColor={styles.track}/>
</TouchableOpacity>
<View style={styles.label}></View>
<TouchableOpacity style={styles.ice} activeOpacity={1}
onPress={() => actions.setEnableIce(!state.enableIce)}>
<Text style={styles.modalLabel}>Enable WebRTC Calls: </Text>
<Switch style={styles.switch} value={state.enableIce}
onValueChange={actions.setEnableIce} trackColor={styles.track}/>
</TouchableOpacity>
<InputField style={styles.field}
label={'Relay URL'}
value={state.iceUrl}
autoCapitalize={'none'}
spellCheck={false}
disabled={!state.enableIce}
onChangeText={actions.setIceUrl}
/>
<InputField style={styles.field}
label={'Relay Username'}
value={state.iceUsername}
autoCapitalize={'none'}
spellCheck={false}
disabled={!state.enableIce}
onChangeText={actions.setIceUsername}
/>
<InputField style={styles.field}
label={'Relay Password'}
value={state.icePassword}
autoCapitalize={'none'}
spellCheck={false}
disabled={!state.enableIce}
onChangeText={actions.setIcePassword}
/>
<View style={styles.pad} />
</ScrollView>
<View style={styles.modalControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideEditConfig}>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.save} onPress={saveConfig}>
<Text style={styles.saveText}>Save</Text>
</TouchableOpacity>
</View>
<TouchableOpacity style={styles.media} activeOpacity={1}
onPress={() => actions.setPushSupported(!state.pushSupported)}>
<Text style={styles.modalLabel}>Enable Push Notifications: </Text>
<Switch style={styles.switch} value={state.pushSupported}
onValueChange={actions.setPushSupported} trackColor={styles.track}/>
</TouchableOpacity>
<View style={styles.label}></View>
<TouchableOpacity style={styles.media} activeOpacity={1}
onPress={() => actions.setEnableImage(!state.enableImage)}>
<Text style={styles.modalLabel}>Enable Image Queue: </Text>
<Switch style={styles.switch} value={state.enableImage}
onValueChange={actions.setEnableImage} trackColor={styles.track}/>
</TouchableOpacity>
<TouchableOpacity style={styles.media} activeOpacity={1}
onPress={() => actions.setEnableAudio(!state.enableAudio)}>
<Text style={styles.modalLabel}>Enable Audio Queue: </Text>
<Switch style={styles.switch} value={state.enableAudio}
onValueChange={actions.setEnableAudio} trackColor={styles.track}/>
</TouchableOpacity>
<TouchableOpacity style={styles.media} activeOpacity={1}
onPress={() => actions.setEnableVideo(!state.enableVideo)}>
<Text style={styles.modalLabel}>Enable Video Queue: </Text>
<Switch style={styles.switch} value={state.enableVideo}
onValueChange={actions.setEnableVideo} trackColor={styles.track}/>
</TouchableOpacity>
<View style={styles.label}></View>
<TouchableOpacity style={styles.ice} activeOpacity={1}
onPress={() => actions.setEnableIce(!state.enableIce)}>
<Text style={styles.modalLabel}>Enable WebRTC Calls: </Text>
<Switch style={styles.switch} value={state.enableIce}
onValueChange={actions.setEnableIce} trackColor={styles.track}/>
</TouchableOpacity>
<TextInput style={styles.input} value={state.iceUrl} onChangeText={actions.setIceUrl}
editable={state.enableIce} autoCorrect={false} autoCapitalize="none" placeholder="Relay URL" />
<TextInput style={styles.input} value={state.iceUsername} onChangeText={actions.setIceUsername}
editable={state.enableIce} autoCorrect={false} autoCapitalize="none" placeholder="Relay Username" />
<TextInput style={styles.input} value={state.icePassword} onChangeText={actions.setIcePassword}
editable={state.enableIce} autoCorrect={false} autoCapitalize="none" placeholder="Relay Password" />
</View>
<View style={styles.modalControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideEditConfig}>
<Text>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.save} onPress={saveConfig}>
<Text style={styles.saveText}>Save</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</KeyboardAvoidingView>
</View>
</Modal>
<Modal
@ -246,25 +270,28 @@ export function Dashboard(props) {
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideAddUser}
>
<KeyboardAvoidingView behavior="height" style={styles.modalBackground}>
<View style={styles.modalContainer}>
<View style={styles.modalHeader}>
<Text style={styles.modalHeaderText}>Create Account:</Text>
</View>
<View style={styles.accessToken}>
<Text style={styles.tokenLabel}>Token:</Text>
<TouchableOpacity style={styles.copy} onPress={() => Clipboard.setString(state.createToken)}>
<Text style={styles.token}>{ state.createToken }</Text>
<AntIcon style={styles.icon} name={'copy1'} size={20} />
</TouchableOpacity>
</View>
<View style={styles.modalControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideAddUser}>
<Text>Done</Text>
</TouchableOpacity>
<View style={styles.modalOverlay}>
<BlurView style={styles.modalOverlay} blurType={'dark'} blurAmount={2} reducedTransparencyFallbackColor='black' />
<View style={styles.modalBase}>
<View style={styles.modalContainer}>
<View style={styles.modalHeader}>
<Text style={styles.modalHeaderText}>Create Account:</Text>
</View>
<View style={styles.accessToken}>
<Text style={styles.tokenLabel}>Token:</Text>
<TouchableOpacity style={styles.copy} onPress={() => Clipboard.setString(state.createToken)}>
<Text style={styles.token}>{ state.createToken }</Text>
<AntIcon style={styles.icon} name={'copy1'} size={20} />
</TouchableOpacity>
</View>
<View style={styles.modalControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideAddUser}>
<Text style={styles.cancelText}>Done</Text>
</TouchableOpacity>
</View>
</View>
</View>
</KeyboardAvoidingView>
</View>
</Modal>
<Modal
@ -274,25 +301,28 @@ export function Dashboard(props) {
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideAccessUser}
>
<KeyboardAvoidingView behavior="height" style={styles.modalBackground}>
<View style={styles.modalContainer}>
<View style={styles.modalHeader}>
<Text style={styles.modalHeaderText}>Access Account:</Text>
</View>
<View style={styles.accessToken}>
<Text style={styles.tokenLabel}>Token:</Text>
<TouchableOpacity style={styles.copy} onPress={() => Clipboard.setString(state.accessToken)}>
<Text style={styles.token}>{ state.accessToken }</Text>
<AntIcon style={styles.icon} name={'copy1'} size={20} />
</TouchableOpacity>
</View>
<View style={styles.modalControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideAccessUser}>
<Text>Done</Text>
</TouchableOpacity>
<View style={styles.modalOverlay}>
<BlurView style={styles.modalOverlay} blurType={'dark'} blurAmount={2} reducedTransparencyFallbackColor='black' />
<View style={styles.modalBase}>
<View style={styles.modalContainer}>
<View style={styles.modalHeader}>
<Text style={styles.modalHeaderText}>Access Account:</Text>
</View>
<View style={styles.accessToken}>
<Text style={styles.tokenLabel}>Token:</Text>
<TouchableOpacity style={styles.copy} onPress={() => Clipboard.setString(state.accessToken)}>
<Text style={styles.token}>{ state.accessToken }</Text>
<AntIcon style={styles.icon} name={'copy1'} size={20} />
</TouchableOpacity>
</View>
<View style={styles.modalControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideAccessUser}>
<Text style={styles.cancelText}>Done</Text>
</TouchableOpacity>
</View>
</View>
</View>
</KeyboardAvoidingView>
</View>
</Modal>
</SafeAreaView>

View File

@ -7,7 +7,7 @@ export const styles = StyleSheet.create({
height: '100%',
display: 'flex',
flexDirection: 'column',
backgroundColor: Colors.formBackground,
backgroundColor: Colors.screenBase,
},
header: {
paddingTop: 24,
@ -16,15 +16,18 @@ export const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: Colors.grey,
borderColor: Colors.horizontalDivider,
},
headerLabel: {
paddingLeft: 16,
fontSize: 20,
color: Colors.text,
},
pad: {
height: 32,
},
icon: {
color: Colors.primary,
color: Colors.linkText,
paddingLeft: 16,
},
end: {
@ -36,7 +39,7 @@ export const styles = StyleSheet.create({
},
accounts: {
borderBottomWidth: 1,
borderColor: Colors.grey,
borderColor: Colors.itemDivider,
flexGrow: 1,
flexShrink: 1,
minHeight: 0,
@ -50,7 +53,7 @@ export const styles = StyleSheet.create({
paddingRight: 24,
alignItems: 'center',
borderBottomWidth: 1,
borderColor: Colors.divider,
borderColor: Colors.itemDivider,
},
details: {
paddingLeft: 16,
@ -87,7 +90,7 @@ export const styles = StyleSheet.create({
paddingLeft: 16,
},
saveText: {
color: Colors.white,
color: Colors.primaryButtonText,
},
save: {
backgroundColor: Colors.primary,
@ -108,6 +111,9 @@ export const styles = StyleSheet.create({
display: 'flex',
alignItems: 'center',
},
cancelText: {
color: Colors.cancelButtonText,
},
modalBackground: {
display: 'flex',
width: '100%',
@ -120,27 +126,45 @@ export const styles = StyleSheet.create({
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
paddingTop: 16,
padding: 16,
borderTopWidth: 1,
borderColor: Colors.divider,
},
modalContainer: {
backgroundColor: Colors.formBackground,
padding: 16,
backgroundColor: Colors.modalBase,
width: '80%',
maxWidth: 400,
maxHeight: '80%',
borderRadius: 8,
borderWidth: 1,
borderColor: Colors.modalBorder,
},
modalHeader: {
paddingBottom: 4,
borderBottomWidth: 1,
borderColor: Colors.divider,
paddingLeft: 8,
padding: 16,
},
modalHeaderText: {
fontSize: 18,
color: Colors.text,
},
modalBase: {
display: 'flex',
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
top: 0,
left: 0,
},
modalOverlay: {
width: '100%',
height: '100%',
},
modalBody: {
padding: 8,
padding: 16,
},
accessToken: {
padding: 16,
@ -148,6 +172,9 @@ export const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
},
token: {
color: Colors.text,
},
modalLabel: {
paddingTop: 8,
color: Colors.text,
@ -239,5 +266,28 @@ export const styles = StyleSheet.create({
marginTop: 8,
alignItems: 'center',
paddingBottom: 8,
}
},
field: {
input: {
backgroundColor: Colors.inputBase,
borderRadius: 8,
minHeight: 32,
maxHeight: 128,
},
inputText: {
color: Colors.inputText,
},
label: {
height: 16,
paddingLeft: 8,
},
labelText: {
color: Colors.inputPlaceholder,
fontSize: 12,
},
container: {
width: '100%',
marginBottom: 8,
},
},
});

View File

@ -1,4 +1,5 @@
import { useState, useEffect, useContext } from 'react';
import { Alert } from 'react-native';
import { useNavigate } from 'react-router-dom';
import { AppContext } from 'context/AppContext';
import { getNodeStatus } from 'api/getNodeStatus';
@ -11,10 +12,13 @@ import { removeAccount } from 'api/removeAccount';
import { addAccountCreate } from 'api/addAccountCreate';
import { setAccountStatus } from 'api/setAccountStatus';
import { addAccountAccess } from 'api/addAccountAccess';
import { DisplayContext } from 'context/DisplayContext';
import { getLanguageStrings } from 'constants/Strings';
export function useDashboard(config, server, token) {
const [state, setState] = useState({
strings: getLanguageStrings(),
config: null,
accounts: [],
editConfig: false,
@ -35,6 +39,7 @@ export function useDashboard(config, server, token) {
});
const navigate = useNavigate();
const display = useContext(DisplayContext);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
@ -98,7 +103,7 @@ export function useDashboard(config, server, token) {
updateState({ domain });
},
setStorage: (storage) => {
updateState({ storage: Number(storage.replace(/[^0-9]/g, '')) });
updateState({ storage: storage.replace(/[^0-9]/g, '') });
},
setPushSupported: (pushSupported) => {
updateState({ pushSupported });
@ -136,9 +141,20 @@ export function useDashboard(config, server, token) {
await setAccountStatus(server, token, accountId, !enabled);
await refreshAccounts();
},
removeUser: async (accountId) => {
await removeAccount(server, token, accountId);
await refreshAccounts();
promptRemove: (accountId) => {
display.actions.showPrompt({
title: 'Delete User',
ok: { label: 'Delete', action: async () => {
await removeAccount(server, token, accountId);
await refreshAccounts();
} , failed: () => {
Alert.alert(
state.strings.error,
state.strings.tryAgain,
);
}},
cancel: { label: state.strings.cancel },
});
},
};

View File

@ -2,21 +2,21 @@ import { TextInput, Text, View, TouchableOpacity } from 'react-native';
import { useState } from 'react';
import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons';
export function InputField({ label, value, secret, autoCapitalize, spellCheck, multiline, onChangeText, style }) {
export function InputField({ label, value, secret, autoCapitalize, spellCheck, keyboardType, disabled, multiline, onChangeText, style }) {
const [hidden, setHidden] = useState(true);
return (
<View style={style?.container}>
<View style={style?.label}>
{ !(value == null || value.length == 0) && (
{ !(value == null || value.length == 0 || disabled) && (
<Text style={style?.labelText}>{ label }</Text>
)}
</View>
<View style={{...style?.input, paddingLeft: 8, display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
<View style={{...style?.input, paddingLeft: 8, display: 'flex', flexDirection: 'row', alignItems: 'center', opacity: disabled ? 0.5 : 1 }}>
<View style={{ flexGrow: 1 }}>
<TextInput placeholder={label} placeholderTextColor={style?.labelText?.color} value={value}
autoCapitalize={autoCapitalize} spellCheck={spellCheck} multiline={multiline}
<TextInput placeholder={label} placeholderTextColor={style?.labelText?.color} value={ disabled ? null : value} editable={!disabled}
autoCapitalize={autoCapitalize} spellCheck={spellCheck} multiline={multiline} keyboardType={keyboardType}
secureTextEntry={secret && hidden} onChangeText={onChangeText} style={{ ...style?.inputText, padding: 8 }} />
</View>
{ secret && !hidden && (