Add generic ThemedContainer component (#846)

This commit is contained in:
Leendert de Borst
2025-05-23 16:27:50 +02:00
parent e6b7d1afa1
commit 574b5ff693
23 changed files with 119 additions and 171 deletions

View File

@@ -17,6 +17,7 @@ import { EmailPreview } from '@/components/credentials/details/EmailPreview';
import { TotpSection } from '@/components/credentials/details/TotpSection';
import { useColors } from '@/hooks/useColorScheme';
import emitter from '@/utils/EventEmitter';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Credential details screen.
@@ -107,28 +108,30 @@ export default function CredentialDetailsScreen() : React.ReactNode {
}
return (
<ThemedScrollView>
<ThemedView style={styles.header}>
<CredentialIcon logo={credential.Logo} style={styles.logo} />
<View style={styles.headerText}>
<ThemedText type="title" style={styles.serviceName}>
{credential.ServiceName}
</ThemedText>
{credential.ServiceUrl && (
<TouchableOpacity onPress={() => Linking.openURL(credential.ServiceUrl!)}>
<Text style={[styles.serviceUrl, { color: colors.primary }]}>
{credential.ServiceUrl}
</Text>
</TouchableOpacity>
)}
</View>
</ThemedView>
<EmailPreview email={credential.Alias.Email} />
<TotpSection credential={credential} />
<NotesSection credential={credential} />
<LoginCredentials credential={credential} />
<AliasDetails credential={credential} />
</ThemedScrollView>
<ThemedContainer>
<ThemedScrollView>
<ThemedView style={styles.header}>
<CredentialIcon logo={credential.Logo} style={styles.logo} />
<View style={styles.headerText}>
<ThemedText type="title" style={styles.serviceName}>
{credential.ServiceName}
</ThemedText>
{credential.ServiceUrl && (
<TouchableOpacity onPress={() => Linking.openURL(credential.ServiceUrl!)}>
<Text style={[styles.serviceUrl, { color: colors.primary }]}>
{credential.ServiceUrl}
</Text>
</TouchableOpacity>
)}
</View>
</ThemedView>
<EmailPreview email={credential.Alias.Email} />
<TotpSection credential={credential} />
<NotesSection credential={credential} />
<LoginCredentials credential={credential} />
<AliasDetails credential={credential} />
</ThemedScrollView>
</ThemedContainer>
);
}
@@ -137,8 +140,7 @@ const styles = StyleSheet.create({
alignItems: 'center',
flexDirection: 'row',
gap: 12,
marginTop: 6,
padding: 16,
paddingTop: 16,
},
headerRightButton: {
padding: 10,

View File

@@ -1,9 +1,7 @@
import { Stack } from 'expo-router';
import { Platform, Text } from 'react-native';
import { useRouter } from 'expo-router';
import { Platform } from 'react-native';
import { defaultHeaderOptions } from '@/components/themed/ThemedHeader';
import { AndroidHeader } from '@/components/ui/AndroidHeader';
/**
* Credentials layout.

View File

@@ -9,7 +9,6 @@ import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view
import * as Haptics from 'expo-haptics';
import { ThemedText } from '@/components/themed/ThemedText';
import { ThemedView } from '@/components/themed/ThemedView';
import { useColors } from '@/hooks/useColorScheme';
import { useDb } from '@/context/DbContext';
import { useWebApi } from '@/context/WebApiContext';
@@ -24,6 +23,7 @@ import { ValidatedFormField, ValidatedFormFieldRef } from '@/components/form/Val
import { credentialSchema } from '@/utils/validationSchema';
import LoadingOverlay from '@/components/LoadingOverlay';
import { useAuth } from '@/context/AuthContext';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
type CredentialMode = 'random' | 'manual';
@@ -422,14 +422,6 @@ export default function AddEditCredentialScreen() : React.ReactNode {
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
flex: 1,
padding: 16,
paddingTop: 0,
},
contentContainer: {
paddingBottom: 40,
paddingTop: Platform.OS === 'ios' ? 76 : 56,
@@ -547,7 +539,7 @@ export default function AddEditCredentialScreen() : React.ReactNode {
style={styles.container}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<ThemedView style={styles.content}>
<ThemedContainer>
<KeyboardAwareScrollView
enableOnAndroid={true}
contentContainerStyle={styles.contentContainer}
@@ -691,7 +683,7 @@ export default function AddEditCredentialScreen() : React.ReactNode {
</>
)}
</KeyboardAwareScrollView>
</ThemedView>
</ThemedContainer>
<AliasVaultToast />
</KeyboardAvoidingView>
</>

View File

@@ -4,7 +4,6 @@ import { useNavigation } from '@react-navigation/native';
import { useRouter } from 'expo-router';
import Toast from 'react-native-toast-message';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import * as Haptics from 'expo-haptics';
import { ThemedText } from '@/components/themed/ThemedText';
@@ -22,6 +21,7 @@ import { AndroidHeader } from '@/components/ui/AndroidHeader';
import emitter from '@/utils/EventEmitter';
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
import { useWebApi } from '@/context/WebApiContext';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Credentials screen.
@@ -39,7 +39,6 @@ export default function CredentialsScreen() : React.ReactNode {
const [credentialsList, setCredentialsList] = useState<Credential[]>([]);
const [isLoadingCredentials, setIsLoadingCredentials] = useMinDurationLoading(false, 200);
const [refreshing, setRefreshing] = useMinDurationLoading(false, 200);
const insets = useSafeAreaInsets();
const authContext = useAuth();
const dbContext = useDb();
@@ -219,15 +218,9 @@ export default function CredentialsScreen() : React.ReactNode {
color: colors.textMuted,
fontSize: 20,
},
container: {
flex: 1,
paddingBottom: insets.bottom,
paddingHorizontal: 14,
paddingTop: Platform.OS === 'android' ? insets.top + 24 : insets.top,
},
contentContainer: {
paddingBottom: 40,
paddingTop: 42,
paddingTop: Platform.OS === 'ios' ? 42 : 0,
},
emptyText: {
color: colors.textMuted,
@@ -274,7 +267,7 @@ export default function CredentialsScreen() : React.ReactNode {
}, [navigation, headerButtons]);
return (
<ThemedView style={styles.container}>
<ThemedContainer>
<CollapsibleHeader
title="Credentials"
scrollY={scrollY}
@@ -354,6 +347,6 @@ export default function CredentialsScreen() : React.ReactNode {
}
/>
</ThemedView>
</ThemedView>
</ThemedContainer>
);
}

View File

@@ -1,7 +1,6 @@
import React, { useEffect, useState, useCallback, useRef } from 'react';
import { StyleSheet, View, ScrollView, RefreshControl, Animated , Platform } from 'react-native';
import { useNavigation } from 'expo-router';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import Toast from 'react-native-toast-message';
import * as Haptics from 'expo-haptics';
@@ -14,12 +13,12 @@ import { CollapsibleHeader } from '@/components/ui/CollapsibleHeader';
import { MailboxBulkRequest, MailboxBulkResponse } from '@/utils/types/webapi/MailboxBulk';
import EncryptionUtility from '@/utils/EncryptionUtility';
import { useColors } from '@/hooks/useColorScheme';
import { ThemedView } from '@/components/themed/ThemedView';
import { EmailCard } from '@/components/EmailCard';
import { SkeletonLoader } from '@/components/ui/SkeletonLoader';
import emitter from '@/utils/EventEmitter';
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
import { useAuth } from '@/context/AuthContext';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Emails screen.
*/
@@ -36,7 +35,6 @@ export default function EmailsScreen() : React.ReactNode {
const [isLoading, setIsLoading] = useMinDurationLoading(true, 200);
const [isRefreshing, setIsRefreshing] = useMinDurationLoading(false, 200);
const [isTabFocused, setIsTabFocused] = useState(false);
const insets = useSafeAreaInsets();
/**
* Load emails.
@@ -155,15 +153,9 @@ export default function EmailsScreen() : React.ReactNode {
justifyContent: 'center',
padding: 20,
},
container: {
flex: 1,
paddingBottom: insets.bottom,
paddingHorizontal: 14,
paddingTop: Platform.OS === 'android' ? insets.top + 24 : insets.top,
},
contentContainer: {
paddingBottom: 40,
paddingTop: 42,
paddingTop: Platform.OS === 'ios' ? 42 : 0,
},
emptyText: {
color: colors.textMuted,
@@ -223,7 +215,7 @@ export default function EmailsScreen() : React.ReactNode {
};
return (
<ThemedView style={styles.container}>
<ThemedContainer>
<CollapsibleHeader
title="Emails"
scrollY={scrollY}
@@ -250,6 +242,6 @@ export default function EmailsScreen() : React.ReactNode {
<TitleContainer title="Emails" />
{renderContent()}
</Animated.ScrollView>
</ThemedView>
</ThemedContainer>
);
}

View File

@@ -3,10 +3,10 @@ import { Ionicons } from '@expo/vector-icons';
import { useEffect, useState } from 'react';
import { ThemedText } from '@/components/themed/ThemedText';
import { ThemedView } from '@/components/themed/ThemedView';
import { useColors } from '@/hooks/useColorScheme';
import { useAuth } from '@/context/AuthContext';
import { ThemedScrollView } from '@/components/themed/ThemedScrollView';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Auto-lock screen.
@@ -40,12 +40,8 @@ export default function AutoLockScreen() : React.ReactNode {
];
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
padding: 16,
paddingBottom: 0,
paddingTop: 12,
},
headerText: {
color: colors.textMuted,
@@ -62,7 +58,7 @@ export default function AutoLockScreen() : React.ReactNode {
optionContainer: {
backgroundColor: colors.accentBackground,
borderRadius: 10,
margin: 16,
marginTop: 16,
},
optionLast: {
borderBottomWidth: 0,
@@ -79,7 +75,7 @@ export default function AutoLockScreen() : React.ReactNode {
});
return (
<ThemedView style={styles.container}>
<ThemedContainer>
<ThemedScrollView>
<View style={styles.header}>
<ThemedText style={styles.headerText}>
@@ -107,6 +103,6 @@ export default function AutoLockScreen() : React.ReactNode {
})}
</View>
</ThemedScrollView>
</ThemedView>
</ThemedContainer>
);
}

View File

@@ -2,10 +2,8 @@ import { StyleSheet, View, ScrollView, TouchableOpacity, Animated, Platform, Ale
import { router, useFocusEffect } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { useRef, useState, useCallback } from 'react';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ThemedText } from '@/components/themed/ThemedText';
import { ThemedView } from '@/components/themed/ThemedView';
import { useWebApi } from '@/context/WebApiContext';
import { AppInfo } from '@/utils/AppInfo';
import { useColors } from '@/hooks/useColorScheme';
@@ -15,6 +13,7 @@ import { CollapsibleHeader } from '@/components/ui/CollapsibleHeader';
import { InlineSkeletonLoader } from '@/components/ui/InlineSkeletonLoader';
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
import { UsernameDisplay } from '@/components/ui/UsernameDisplay';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Settings screen.
@@ -29,7 +28,6 @@ export default function SettingsScreen() : React.ReactNode {
const [autoLockDisplay, setAutoLockDisplay] = useState<string>('');
const [authMethodDisplay, setAuthMethodDisplay] = useState<string>('');
const [isFirstLoad, setIsFirstLoad] = useMinDurationLoading(true, 100);
const insets = useSafeAreaInsets();
useFocusEffect(
useCallback(() => {
@@ -126,15 +124,9 @@ export default function SettingsScreen() : React.ReactNode {
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingBottom: insets.bottom,
paddingHorizontal: 14,
paddingTop: Platform.OS === 'android' ? insets.top + 24 : insets.top,
},
scrollContent: {
paddingBottom: 40,
paddingTop: 42,
paddingTop: Platform.OS === 'ios' ? 42 : 0,
},
scrollView: {
flex: 1,
@@ -212,7 +204,7 @@ export default function SettingsScreen() : React.ReactNode {
});
return (
<ThemedView style={styles.container}>
<ThemedContainer>
<CollapsibleHeader
title="Settings"
scrollY={scrollY}
@@ -324,6 +316,6 @@ export default function SettingsScreen() : React.ReactNode {
<ThemedText style={styles.versionText}>App version {AppInfo.VERSION}</ThemedText>
</View>
</Animated.ScrollView>
</ThemedView>
</ThemedContainer>
);
}

View File

@@ -2,10 +2,10 @@ import { StyleSheet, View, TouchableOpacity, Linking } from 'react-native';
import { router } from 'expo-router';
import { ThemedText } from '@/components/themed/ThemedText';
import { ThemedView } from '@/components/themed/ThemedView';
import { useColors } from '@/hooks/useColorScheme';
import { useAuth } from '@/context/AuthContext';
import { ThemedScrollView } from '@/components/themed/ThemedScrollView';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* iOS autofill screen.
@@ -47,19 +47,15 @@ export default function IosAutofillScreen() : React.ReactNode {
fontSize: 16,
fontWeight: '600',
},
container: {
flex: 1,
},
header: {
padding: 16,
paddingBottom: 0,
paddingTop: 12,
},
headerText: {
color: colors.textMuted,
fontSize: 13,
},
instructionContainer: {
padding: 16,
paddingTop: 16,
},
instructionStep: {
color: colors.text,
@@ -94,7 +90,7 @@ export default function IosAutofillScreen() : React.ReactNode {
});
return (
<ThemedView style={styles.container}>
<ThemedContainer>
<ThemedScrollView>
<View style={styles.header}>
<ThemedText style={styles.headerText}>
@@ -146,6 +142,6 @@ export default function IosAutofillScreen() : React.ReactNode {
</View>
</View>
</ThemedScrollView>
</ThemedView>
</ThemedContainer>
);
}

View File

@@ -5,12 +5,12 @@ import * as Haptics from 'expo-haptics';
import Toast from 'react-native-toast-message';
import { ThemedText } from '@/components/themed/ThemedText';
import { ThemedView } from '@/components/themed/ThemedView';
import { useColors } from '@/hooks/useColorScheme';
import { useWebApi } from '@/context/WebApiContext';
import { RefreshToken } from '@/utils/types/webapi/RefreshToken';
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
import { SkeletonLoader } from '@/components/ui/SkeletonLoader';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Active sessions screen.
*/
@@ -24,15 +24,9 @@ export default function ActiveSessionsScreen() : React.ReactNode {
const [isRefreshing, setIsRefreshing] = useMinDurationLoading(false, 200);
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 42,
paddingBottom: insets.bottom,
paddingHorizontal: 14,
paddingTop: insets.top,
},
contentContainer: {
paddingBottom: 40,
paddingTop: Platform.OS === 'ios' ? insets.top : 0,
},
detailText: {
color: colors.textMuted,
@@ -57,7 +51,7 @@ export default function ActiveSessionsScreen() : React.ReactNode {
textAlign: 'center',
},
header: {
paddingTop: 16
paddingTop: 12
},
headerText: {
color: colors.textMuted,
@@ -175,7 +169,7 @@ export default function ActiveSessionsScreen() : React.ReactNode {
};
return (
<ThemedView style={styles.container}>
<ThemedContainer>
<ScrollView
contentContainerStyle={styles.contentContainer}
refreshControl={
@@ -217,6 +211,6 @@ export default function ActiveSessionsScreen() : React.ReactNode {
)}
</View>
</ScrollView>
</ThemedView>
</ThemedContainer>
);
}

View File

@@ -5,13 +5,13 @@ import * as Haptics from 'expo-haptics';
import Toast from 'react-native-toast-message';
import { ThemedText } from '@/components/themed/ThemedText';
import { ThemedView } from '@/components/themed/ThemedView';
import { useColors } from '@/hooks/useColorScheme';
import { useWebApi } from '@/context/WebApiContext';
import { SkeletonLoader } from '@/components/ui/SkeletonLoader';
import { AuthLogModel } from '@/utils/types/webapi/AuthLog';
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
import { AuthEventType } from '@/utils/types/webapi/AuthEventType';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Auth logs screen.
@@ -26,15 +26,9 @@ export default function AuthLogsScreen() : React.ReactNode {
const [isRefreshing, setIsRefreshing] = useMinDurationLoading(false, 200);
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 42,
paddingBottom: insets.bottom,
paddingHorizontal: 14,
paddingTop: insets.top,
},
contentContainer: {
paddingBottom: 40,
paddingTop: Platform.OS === 'ios' ? insets.top : 0,
},
detailText: {
color: colors.textMuted,
@@ -57,7 +51,7 @@ export default function AuthLogsScreen() : React.ReactNode {
fontWeight: '600',
},
header: {
paddingTop: 16,
paddingTop: 12,
},
headerText: {
color: colors.textMuted,
@@ -188,7 +182,7 @@ export default function AuthLogsScreen() : React.ReactNode {
};
return (
<ThemedView style={styles.container}>
<ThemedContainer>
<ScrollView
contentContainerStyle={styles.contentContainer}
refreshControl={
@@ -209,6 +203,6 @@ export default function AuthLogsScreen() : React.ReactNode {
{renderContent()}
</View>
</ScrollView>
</ThemedView>
</ThemedContainer>
);
}

View File

@@ -4,7 +4,6 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { router } from 'expo-router';
import { ThemedText } from '@/components/themed/ThemedText';
import { ThemedView } from '@/components/themed/ThemedView';
import { useColors } from '@/hooks/useColorScheme';
import { ThemedTextInput } from '@/components/themed/ThemedTextInput';
import { ThemedButton } from '@/components/themed/ThemedButton';
@@ -12,6 +11,7 @@ import { useAuth } from '@/context/AuthContext';
import { useVaultMutate } from '@/hooks/useVaultMutate';
import LoadingOverlay from '@/components/LoadingOverlay';
import { UsernameDisplay } from '@/components/ui/UsernameDisplay';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Change password screen.
@@ -33,15 +33,9 @@ export default function ChangePasswordScreen(): React.ReactNode {
button: {
marginTop: 8,
},
container: {
flex: 1,
marginTop: 42,
paddingBottom: insets.bottom,
paddingHorizontal: 14,
paddingTop: insets.top,
},
contentContainer: {
paddingBottom: 40,
paddingTop: Platform.OS === 'ios' ? insets.top : 0,
},
form: {
backgroundColor: colors.accentBackground,
@@ -50,7 +44,7 @@ export default function ChangePasswordScreen(): React.ReactNode {
padding: 16,
},
header: {
paddingTop: 16,
paddingTop: 12,
},
headerText: {
color: colors.textMuted,
@@ -132,7 +126,7 @@ export default function ChangePasswordScreen(): React.ReactNode {
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={styles.keyboardAvoidingView}
>
<ThemedView style={styles.container}>
<ThemedContainer>
<ScrollView
contentContainerStyle={styles.contentContainer}
keyboardShouldPersistTaps="handled"
@@ -182,7 +176,7 @@ export default function ChangePasswordScreen(): React.ReactNode {
/>
</View>
</ScrollView>
</ThemedView>
</ThemedContainer>
</KeyboardAvoidingView>
</>
);

View File

@@ -5,7 +5,6 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
import srp from 'secure-remote-password/client';
import { ThemedText } from '@/components/themed/ThemedText';
import { ThemedView } from '@/components/themed/ThemedView';
import { useColors } from '@/hooks/useColorScheme';
import { ThemedTextInput } from '@/components/themed/ThemedTextInput';
import { ThemedButton } from '@/components/themed/ThemedButton';
@@ -15,6 +14,7 @@ import { DeleteAccountInitiateRequest, DeleteAccountInitiateResponse } from '@/u
import { DeleteAccountRequest } from '@/utils/types/webapi/DeleteAccountRequest';
import { UsernameDisplay } from '@/components/ui/UsernameDisplay';
import LoadingOverlay from '@/components/LoadingOverlay';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Delete account screen.
@@ -35,15 +35,9 @@ export default function DeleteAccountScreen(): React.ReactNode {
button: {
marginTop: 16,
},
container: {
flex: 1,
marginTop: 42,
paddingBottom: insets.bottom,
paddingHorizontal: 16,
paddingTop: insets.top,
},
contentContainer: {
paddingBottom: 40,
paddingTop: Platform.OS === 'ios' ? insets.top : 0,
},
form: {
backgroundColor: colors.accentBackground,
@@ -54,7 +48,7 @@ export default function DeleteAccountScreen(): React.ReactNode {
padding: 20,
},
header: {
paddingTop: 16,
paddingTop: 12,
},
headerText: {
color: colors.textMuted,
@@ -238,7 +232,7 @@ export default function DeleteAccountScreen(): React.ReactNode {
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={styles.keyboardAvoidingView}
>
<ThemedView style={styles.container}>
<ThemedContainer>
<ScrollView
contentContainerStyle={styles.contentContainer}
keyboardShouldPersistTaps="handled"
@@ -298,7 +292,7 @@ export default function DeleteAccountScreen(): React.ReactNode {
)}
</View>
</ScrollView>
</ThemedView>
</ThemedContainer>
</KeyboardAvoidingView>
</>
);

View File

@@ -1,33 +1,25 @@
import { StyleSheet, View, TouchableOpacity, Animated, ScrollView } from 'react-native';
import { StyleSheet, View, TouchableOpacity, Animated, ScrollView, Platform } from 'react-native';
import { router } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { useRef } from 'react';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ThemedText } from '@/components/themed/ThemedText';
import { ThemedView } from '@/components/themed/ThemedView';
import { useColors } from '@/hooks/useColorScheme';
import { SettingsHeader } from '@/components/ui/SettingsHeader';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Security settings screen.
*/
export default function SecuritySettingsScreen() : React.ReactNode {
const colors = useColors();
const insets = useSafeAreaInsets();
const scrollY = useRef(new Animated.Value(0)).current;
const scrollViewRef = useRef<ScrollView>(null);
const styles = StyleSheet.create({
container: {
flex: 1,
paddingBottom: insets.bottom,
paddingHorizontal: 14,
paddingTop: insets.top,
},
scrollContent: {
paddingBottom: 40,
paddingTop: 42,
paddingTop: Platform.OS === 'ios' ? 42 : 0,
},
scrollView: {
flex: 1,
@@ -71,7 +63,7 @@ export default function SecuritySettingsScreen() : React.ReactNode {
});
return (
<ThemedView style={styles.container}>
<ThemedContainer>
<Animated.ScrollView
ref={scrollViewRef}
onScroll={Animated.event(
@@ -141,6 +133,6 @@ export default function SecuritySettingsScreen() : React.ReactNode {
</TouchableOpacity>
</View>
</Animated.ScrollView>
</ThemedView>
</ThemedContainer>
);
}

View File

@@ -7,7 +7,7 @@ import { ThemedText } from '@/components/themed/ThemedText';
import { useColors } from '@/hooks/useColorScheme';
import { AuthMethod, useAuth } from '@/context/AuthContext';
import { ThemedScrollView } from '@/components/themed/ThemedScrollView';
import { ThemedView } from '@/components/themed/ThemedView';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
/**
* Vault unlock settings screen.
@@ -134,16 +134,12 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
}, [hasBiometrics, setAuthMethods, biometricDisplayName]);
const styles = StyleSheet.create({
container: {
flex: 1,
},
disabledText: {
color: colors.textMuted,
opacity: 0.5,
},
header: {
padding: 16,
paddingBottom: 0,
paddingTop: 12,
},
headerText: {
color: colors.textMuted,
@@ -163,7 +159,7 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
optionContainer: {
backgroundColor: colors.accentBackground,
borderRadius: 10,
margin: 16,
marginTop: 16,
},
optionHeader: {
alignItems: 'center',
@@ -181,7 +177,7 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
});
return (
<ThemedView style={styles.container}>
<ThemedContainer>
<ThemedScrollView>
<View style={styles.header}>
<ThemedText style={styles.headerText}>
@@ -229,6 +225,6 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
</View>
</View>
</ThemedScrollView>
</ThemedView>
</ThemedContainer>
);
}

View File

@@ -58,8 +58,7 @@ export const AliasDetails: React.FC<AliasDetailsProps> = ({ credential }) : Reac
const styles = {
section: {
padding: 16,
paddingBottom: 0,
paddingTop: 16,
gap: 8,
},
};

View File

@@ -181,8 +181,7 @@ export const EmailPreview: React.FC<EmailPreviewProps> = ({ email }) : React.Rea
marginBottom: 8,
},
section: {
padding: 16,
paddingBottom: 0,
paddingTop: 16,
},
subject: {
color: colors.text,

View File

@@ -50,8 +50,7 @@ export const LoginCredentials: React.FC<LoginCredentialsProps> = ({ credential }
const styles = {
section: {
padding: 16,
paddingBottom: 0,
paddingTop: 16,
gap: 8,
},
};

View File

@@ -93,8 +93,7 @@ export const NotesSection: React.FC<NotesSectionProps> = ({ credential }) : Reac
},
section: {
gap: 8,
padding: 16,
paddingBottom: 8,
paddingTop: 16,
},
});

View File

@@ -146,8 +146,7 @@ export const TotpSection: React.FC<TotpSectionProps> = ({ credential }) : React.
justifyContent: 'space-between',
},
container: {
marginTop: 16,
padding: 16,
paddingTop: 16,
},
content: {
backgroundColor: colors.accentBackground,

View File

@@ -0,0 +1,24 @@
import { Platform, StyleSheet, type ViewProps } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ThemedView } from '@/components/themed/ThemedView';
export type ThemedContainerProps = ViewProps;
/**
* Themed container component which should be the outermost component of a screen.
* It handles the safe area insets and the padding for the screen.
*/
export function ThemedContainer({ style, ...otherProps }: ThemedContainerProps): React.ReactNode {
const insets = useSafeAreaInsets();
const styles = StyleSheet.create({
container: {
flex: 1,
paddingBottom: insets.bottom,
paddingHorizontal: 14,
paddingTop: Platform.OS === 'ios' ? insets.top : 0,
},
});
return <ThemedView style={[styles.container, style]} {...otherProps} />;
}

View File

@@ -41,8 +41,7 @@ export function ThemedHeader(): React.ReactNode {
<View style={[styles.headerBorder, { backgroundColor: colors.headerBorder }]} />
</View>
);
}
else if (Platform.OS === 'android') {
} else if (Platform.OS === 'android') {
return (
<View style={[styles.header, styles.androidHeader]}>
<View style={[styles.headerBorder, { backgroundColor: colors.headerBorder }]} />
@@ -59,7 +58,11 @@ export function ThemedHeader(): React.ReactNode {
* @returns {Object} The default header options
*/
export const defaultHeaderOptions = {
headerTransparent: true,
/**
* On iOS, we want the header to be transparent.
* On Android, we want the header to be opaque.
*/
headerTransparent: Platform.OS === 'ios' ? true : false,
/**
* Header background component that provides consistent styling.
* @returns {React.ReactNode} The themed header background component

View File

@@ -16,7 +16,7 @@ type ThemedScrollViewProps = {
export function ThemedScrollView({ style, lightColor, darkColor, ...otherProps }: ThemedScrollViewProps): React.ReactNode {
const insets = useSafeAreaInsets();
const paddingTop = Platform.OS === 'ios' ? insets.top + 36 : 64;
const paddingTop = Platform.OS === 'ios' ? insets.top : 0;
const paddingBottom = Platform.OS === 'ios' ? insets.bottom + 60 : 0;
return (

View File

@@ -1,5 +1,6 @@
import { SymbolView, SymbolWeight } from 'expo-symbols';
import { StyleProp, ViewStyle } from 'react-native';
import { IconSymbolName } from './IconSymbolName';
/**