mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-05-18 13:28:12 -04:00
UI tweaks (#771)
This commit is contained in:
@@ -439,6 +439,10 @@ export default function AddEditCredentialScreen() : React.ReactNode {
|
||||
padding: 10,
|
||||
paddingLeft: 0,
|
||||
},
|
||||
headerLeftButtonText: {
|
||||
color: colors.primary,
|
||||
fontSize: 20,
|
||||
},
|
||||
headerRightButton: {
|
||||
padding: 10,
|
||||
paddingRight: 0,
|
||||
@@ -492,7 +496,7 @@ export default function AddEditCredentialScreen() : React.ReactNode {
|
||||
onPress={() => router.back()}
|
||||
style={styles.headerLeftButton}
|
||||
>
|
||||
<ThemedText style={{ color: colors.primary }}>Cancel</ThemedText>
|
||||
<ThemedText style={styles.headerLeftButtonText}>Cancel</ThemedText>
|
||||
</TouchableOpacity>
|
||||
),
|
||||
/**
|
||||
@@ -507,7 +511,7 @@ export default function AddEditCredentialScreen() : React.ReactNode {
|
||||
</TouchableOpacity>
|
||||
),
|
||||
});
|
||||
}, [navigation, mode, handleSubmit, onSubmit, colors.primary, isEditMode, router, styles.headerLeftButton, styles.headerRightButton]);
|
||||
}, [navigation, mode, handleSubmit, onSubmit, colors.primary, isEditMode, router, styles.headerLeftButton, styles.headerLeftButtonText, styles.headerRightButton]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -190,13 +190,12 @@ export default function CredentialsScreen() : React.ReactNode {
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
marginTop: 36,
|
||||
padding: 16,
|
||||
paddingTop: 0,
|
||||
},
|
||||
contentContainer: {
|
||||
paddingBottom: 40,
|
||||
paddingTop: 4,
|
||||
paddingTop: 42,
|
||||
},
|
||||
emptyText: {
|
||||
color: colors.textMuted,
|
||||
|
||||
@@ -165,12 +165,11 @@ export default function EmailsScreen() : React.ReactNode {
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
marginTop: 22,
|
||||
padding: 16,
|
||||
},
|
||||
contentContainer: {
|
||||
paddingBottom: 40,
|
||||
paddingTop: 4,
|
||||
paddingTop: 26,
|
||||
},
|
||||
emptyText: {
|
||||
color: colors.textMuted,
|
||||
|
||||
@@ -56,13 +56,16 @@ export default function AutoLockScreen() : React.ReactNode {
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
flexDirection: 'row',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 16,
|
||||
paddingVertical: 14,
|
||||
},
|
||||
optionContainer: {
|
||||
backgroundColor: colors.accentBackground,
|
||||
borderRadius: 10,
|
||||
margin: 16,
|
||||
},
|
||||
optionLast: {
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
optionText: {
|
||||
color: colors.text,
|
||||
flex: 1,
|
||||
@@ -83,21 +86,24 @@ export default function AutoLockScreen() : React.ReactNode {
|
||||
</ThemedText>
|
||||
</View>
|
||||
<View style={styles.optionContainer}>
|
||||
{timeoutOptions.map((option) => (
|
||||
<TouchableOpacity
|
||||
key={option.value}
|
||||
style={styles.option}
|
||||
onPress={() => {
|
||||
setAutoLockTimeout(option.value);
|
||||
setAutoLockTimeoutState(option.value);
|
||||
}}
|
||||
>
|
||||
<ThemedText style={styles.optionText}>{option.label}</ThemedText>
|
||||
{autoLockTimeout === option.value && (
|
||||
<Ionicons name="checkmark" size={24} style={styles.selectedIcon} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
{timeoutOptions.map((option, index) => {
|
||||
const isLast = index === timeoutOptions.length - 1;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={option.value}
|
||||
style={[styles.option, isLast && styles.optionLast]}
|
||||
onPress={() => {
|
||||
setAutoLockTimeout(option.value);
|
||||
setAutoLockTimeoutState(option.value);
|
||||
}}
|
||||
>
|
||||
<ThemedText style={styles.optionText}>{option.label}</ThemedText>
|
||||
{autoLockTimeout === option.value && (
|
||||
<Ionicons name="checkmark" size={20} style={styles.selectedIcon} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</ThemedScrollView>
|
||||
</ThemedView>
|
||||
|
||||
@@ -111,12 +111,11 @@ export default function SettingsScreen() : React.ReactNode {
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
marginTop: 22,
|
||||
padding: 16,
|
||||
},
|
||||
scrollContent: {
|
||||
paddingBottom: 40,
|
||||
paddingTop: 4,
|
||||
paddingTop: 26,
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
@@ -159,7 +158,7 @@ export default function SettingsScreen() : React.ReactNode {
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
paddingVertical: 12,
|
||||
paddingVertical: 10,
|
||||
},
|
||||
settingItemIcon: {
|
||||
alignItems: 'center',
|
||||
|
||||
@@ -115,16 +115,6 @@ export default function IosAutofillScreen() : React.ReactNode {
|
||||
Open iOS Settings
|
||||
</ThemedText>
|
||||
</TouchableOpacity>
|
||||
{shouldShowIosAutofillReminder && (
|
||||
<TouchableOpacity
|
||||
style={styles.secondaryButton}
|
||||
onPress={handleAlreadyConfigured}
|
||||
>
|
||||
<ThemedText style={styles.secondaryButtonText}>
|
||||
I already configured it
|
||||
</ThemedText>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
<ThemedText style={styles.instructionStep}>
|
||||
2. Go to "General"
|
||||
@@ -141,6 +131,18 @@ export default function IosAutofillScreen() : React.ReactNode {
|
||||
<ThemedText style={styles.warningText}>
|
||||
Note: You'll need to authenticate with Face ID/Touch ID or your device passcode when using autofill.
|
||||
</ThemedText>
|
||||
<View style={styles.buttonContainer}>
|
||||
{shouldShowIosAutofillReminder && (
|
||||
<TouchableOpacity
|
||||
style={styles.secondaryButton}
|
||||
onPress={handleAlreadyConfigured}
|
||||
>
|
||||
<ThemedText style={styles.secondaryButtonText}>
|
||||
I already configured it
|
||||
</ThemedText>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</ThemedScrollView>
|
||||
</ThemedView>
|
||||
|
||||
@@ -156,6 +156,9 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 4,
|
||||
},
|
||||
optionLast: {
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
optionText: {
|
||||
color: colors.text,
|
||||
fontSize: 16,
|
||||
@@ -197,7 +200,7 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.option}>
|
||||
<View style={[styles.option, styles.optionLast]}>
|
||||
<View style={styles.optionHeader}>
|
||||
<ThemedText style={styles.optionText}>Password</ThemedText>
|
||||
<Switch
|
||||
|
||||
@@ -44,9 +44,7 @@ export function EmailCard({ email }: EmailCardProps) : React.ReactNode {
|
||||
const styles = StyleSheet.create({
|
||||
emailCard: {
|
||||
backgroundColor: colors.accentBackground,
|
||||
borderColor: colors.accentBorder,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
elevation: 3,
|
||||
marginBottom: 12,
|
||||
padding: 12,
|
||||
|
||||
@@ -37,9 +37,7 @@ export function CredentialCard({ credential }: CredentialCardProps) : React.Reac
|
||||
const styles = StyleSheet.create({
|
||||
credentialCard: {
|
||||
backgroundColor: colors.accentBackground,
|
||||
borderColor: colors.accentBorder,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
marginBottom: 8,
|
||||
padding: 12,
|
||||
},
|
||||
|
||||
@@ -52,9 +52,7 @@ const FormInputCopyToClipboard: React.FC<FormInputCopyToClipboardProps> = ({
|
||||
},
|
||||
inputContainer: {
|
||||
backgroundColor: colors.accentBackground,
|
||||
borderColor: colors.accentBorder,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
marginBottom: 12,
|
||||
padding: 12,
|
||||
},
|
||||
|
||||
@@ -77,7 +77,7 @@ const ValidatedFormFieldComponent = forwardRef<ValidatedFormFieldRef, ValidatedF
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.background,
|
||||
borderColor: colors.accentBorder,
|
||||
borderRadius: 4,
|
||||
borderRadius: 6,
|
||||
borderWidth: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, Platform, Animated, TouchableOpacity } from 'react-native';
|
||||
import { StyleSheet, Platform, Animated, TouchableOpacity, useColorScheme } from 'react-native';
|
||||
import { Stack } from 'expo-router';
|
||||
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
||||
import { BlurView } from 'expo-blur';
|
||||
|
||||
import { ThemedText } from '@/components/themed/ThemedText';
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
|
||||
const AnimatedBlurView = Animated.createAnimatedComponent(BlurView);
|
||||
|
||||
type HeaderButton = {
|
||||
icon: keyof typeof MaterialIcons.glyphMap;
|
||||
onPress: () => void;
|
||||
@@ -29,10 +32,11 @@ export function CollapsibleHeader({
|
||||
showNavigationHeader = false,
|
||||
alwaysVisible = false,
|
||||
headerButtons = []
|
||||
}: CollapsibleHeaderProps) : React.ReactNode {
|
||||
}: CollapsibleHeaderProps): React.ReactNode {
|
||||
const colors = useColors();
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
// Calculate header opacity based on scroll position and transform
|
||||
// Calculate header opacity and transforms based on scroll
|
||||
const headerOpacity = scrollY.interpolate({
|
||||
inputRange: [10, 60],
|
||||
outputRange: [0, 1],
|
||||
@@ -45,12 +49,13 @@ export function CollapsibleHeader({
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
|
||||
const headerTransform = alwaysVisible ? 0 : headerOpacity.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [-20, 0],
|
||||
});
|
||||
const headerTransform = alwaysVisible
|
||||
? 0
|
||||
: headerOpacity.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [-20, 0],
|
||||
});
|
||||
|
||||
// Interpolate the header background color and border
|
||||
const headerBackground = headerOpacity.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [colors.background, colors.accentBackground],
|
||||
@@ -63,6 +68,7 @@ export function CollapsibleHeader({
|
||||
height: Platform.OS === 'ios' ? 100 : 64,
|
||||
justifyContent: 'center',
|
||||
left: 0,
|
||||
overflow: 'hidden',
|
||||
paddingBottom: Platform.OS === 'ios' ? 12 : 16,
|
||||
paddingTop: Platform.OS === 'ios' ? 60 : 0,
|
||||
position: 'absolute',
|
||||
@@ -92,7 +98,6 @@ export function CollapsibleHeader({
|
||||
},
|
||||
headerButton: {
|
||||
bottom: Platform.OS === 'ios' ? 6 : 16,
|
||||
color: colors.primary,
|
||||
padding: 4,
|
||||
position: 'absolute',
|
||||
},
|
||||
@@ -106,37 +111,53 @@ export function CollapsibleHeader({
|
||||
|
||||
return (
|
||||
<>
|
||||
{showNavigationHeader ? (
|
||||
<Stack.Screen options={{
|
||||
title: title,
|
||||
headerShown: false,
|
||||
}} />
|
||||
) : null}
|
||||
{showNavigationHeader && (
|
||||
<Stack.Screen options={{ title, headerShown: false }} />
|
||||
)}
|
||||
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.floatingHeader,
|
||||
{
|
||||
backgroundColor: headerBackground,
|
||||
transform: [{
|
||||
translateY: headerTransform
|
||||
}]
|
||||
}
|
||||
transform: [{ translateY: headerTransform }],
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Animated.View style={[
|
||||
styles.floatingTitleContainer,
|
||||
{ opacity: alwaysVisible ? titleOpacity : headerOpacity },
|
||||
]}>
|
||||
{Platform.OS === 'ios' ? (
|
||||
colorScheme === 'dark' ? (
|
||||
<AnimatedBlurView
|
||||
tint="dark"
|
||||
intensity={80}
|
||||
style={[StyleSheet.absoluteFill, { opacity: headerOpacity }]}
|
||||
/>
|
||||
) : (
|
||||
<AnimatedBlurView
|
||||
tint="light"
|
||||
intensity={100}
|
||||
style={[StyleSheet.absoluteFill, { opacity: headerOpacity }]}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Animated.View
|
||||
style={[StyleSheet.absoluteFill, { backgroundColor: headerBackground }]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.floatingTitleContainer,
|
||||
{ opacity: alwaysVisible ? titleOpacity : headerOpacity },
|
||||
]}
|
||||
>
|
||||
<ThemedText style={styles.floatingTitle}>{title}</ThemedText>
|
||||
</Animated.View>
|
||||
|
||||
{headerButtons.map((button, index) => (
|
||||
{headerButtons.map((button, idx) => (
|
||||
<TouchableOpacity
|
||||
key={`${button.icon}-${index}`}
|
||||
key={`${button.icon}-${idx}`}
|
||||
style={[
|
||||
styles.headerButton,
|
||||
button.position === 'left' ? styles.leftButton : styles.rightButton
|
||||
button.position === 'left' ? styles.leftButton : styles.rightButton,
|
||||
]}
|
||||
onPress={button.onPress}
|
||||
>
|
||||
@@ -147,12 +168,10 @@ export function CollapsibleHeader({
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.headerBorder,
|
||||
{
|
||||
opacity: headerOpacity
|
||||
}
|
||||
{ opacity: headerOpacity },
|
||||
]}
|
||||
/>
|
||||
</Animated.View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ export const Colors = {
|
||||
white: '#ffffff',
|
||||
text: '#ECEDEE',
|
||||
textMuted: '#9BA1A6',
|
||||
background: '#111827',
|
||||
accentBackground: '#1f2937',
|
||||
accentBorder: '#4b5563',
|
||||
background: '#000',
|
||||
accentBackground: '#202020',
|
||||
accentBorder: '#444',
|
||||
errorBackground: '#3d1a1e',
|
||||
errorBorder: '#9c2530',
|
||||
errorText: '#fae1e3',
|
||||
@@ -40,8 +40,8 @@ export const Colors = {
|
||||
icon: '#9BA1A6',
|
||||
tabIconDefault: '#9BA1A6',
|
||||
tabIconSelected: '#f49541',
|
||||
headerBackground: '#1f2937',
|
||||
tabBarBackground: '#1f2937',
|
||||
headerBackground: '#202020',
|
||||
tabBarBackground: '#202020',
|
||||
primary: '#f49541',
|
||||
primarySurfaceText: '#ffffff',
|
||||
secondary: '#6b7280',
|
||||
|
||||
Reference in New Issue
Block a user