mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-05-13 18:05:28 -04:00
Display add button on android (#846)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Stack } from 'expo-router';
|
||||
import { Platform, Text } from 'react-native';
|
||||
import { useRouter } from 'expo-router';
|
||||
|
||||
import { defaultHeaderOptions } from '@/components/themed/ThemedHeader';
|
||||
import { AndroidHeader } from '@/components/ui/AndroidHeader';
|
||||
@@ -16,12 +17,6 @@ export default function CredentialsLayout(): React.ReactNode {
|
||||
options={{
|
||||
title: 'Credentials',
|
||||
headerShown: Platform.OS === 'android',
|
||||
/**
|
||||
* On Android, we use a custom header component that includes the AliasVault logo.
|
||||
* On iOS, we don't show the header as a custom collapsible header is used.
|
||||
* @returns {React.ReactNode} The header component
|
||||
*/
|
||||
headerTitle: (): React.ReactNode => Platform.OS === 'android' ? <AndroidHeader title="Credentials" /> : <Text>Credentials</Text>,
|
||||
...defaultHeaderOptions,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { StyleSheet, Text, FlatList, TouchableOpacity, TextInput, RefreshControl, Platform, Animated, Alert } from 'react-native';
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useRouter } from 'expo-router';
|
||||
import Toast from 'react-native-toast-message';
|
||||
@@ -18,6 +18,7 @@ import { CredentialCard } from '@/components/credentials/CredentialCard';
|
||||
import { TitleContainer } from '@/components/ui/TitleContainer';
|
||||
import { CollapsibleHeader } from '@/components/ui/CollapsibleHeader';
|
||||
import { SkeletonLoader } from '@/components/ui/SkeletonLoader';
|
||||
import { AndroidHeader } from '@/components/ui/AndroidHeader';
|
||||
import emitter from '@/utils/EventEmitter';
|
||||
import { useMinDurationLoading } from '@/hooks/useMinDurationLoading';
|
||||
import { useWebApi } from '@/context/WebApiContext';
|
||||
@@ -65,14 +66,14 @@ export default function CredentialsScreen() : React.ReactNode {
|
||||
}
|
||||
}, [dbContext.sqliteClient, setIsLoadingCredentials]);
|
||||
|
||||
const headerButtons = [{
|
||||
const headerButtons = useMemo(() => [{
|
||||
icon: 'add' as const,
|
||||
position: 'right' as const,
|
||||
/**
|
||||
* Add credential.
|
||||
*/
|
||||
onPress: () : void => router.push('/(tabs)/credentials/add-edit')
|
||||
}];
|
||||
}], [router]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeFocus = navigation.addListener('focus', () => {
|
||||
@@ -261,6 +262,17 @@ export default function CredentialsScreen() : React.ReactNode {
|
||||
},
|
||||
});
|
||||
|
||||
// Set header buttons
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
/**
|
||||
* Define custom header which is shown on Android. iOS displays the custom CollapsibleHeader component instead.
|
||||
* @returns
|
||||
*/
|
||||
headerTitle: (): React.ReactNode => Platform.OS === 'android' ? <AndroidHeader title="Credentials" headerButtons={headerButtons} /> : <Text>Credentials</Text>,
|
||||
});
|
||||
}, [navigation, headerButtons]);
|
||||
|
||||
return (
|
||||
<ThemedView style={styles.container}>
|
||||
<CollapsibleHeader
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import { View, StyleSheet } from 'react-native';
|
||||
import { View, StyleSheet, TouchableOpacity } from 'react-native';
|
||||
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
||||
|
||||
import { ThemedText } from '@/components/themed/ThemedText';
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
import Logo from '@/assets/images/logo.svg';
|
||||
|
||||
type HeaderButton = {
|
||||
icon: keyof typeof MaterialIcons.glyphMap;
|
||||
onPress: () => void;
|
||||
position: 'left' | 'right';
|
||||
}
|
||||
|
||||
interface IAndroidHeaderProps {
|
||||
title: string;
|
||||
headerButtons?: HeaderButton[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -11,27 +21,62 @@ interface IAndroidHeaderProps {
|
||||
* @param {IAndroidHeaderProps} props - The component props
|
||||
* @returns {React.ReactNode} The Android header component
|
||||
*/
|
||||
export function AndroidHeader({ title }: IAndroidHeaderProps): React.ReactNode {
|
||||
export function AndroidHeader({ title, headerButtons = [] }: IAndroidHeaderProps): React.ReactNode {
|
||||
const colors = useColors();
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
headerButton: {
|
||||
padding: 4,
|
||||
},
|
||||
headerContainer: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
gap: 8,
|
||||
verticalAlign: 'middle',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 22,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
leftButton: {
|
||||
marginRight: 'auto',
|
||||
},
|
||||
logo: {
|
||||
marginBottom: 0,
|
||||
},
|
||||
rightButton: {
|
||||
marginLeft: 'auto',
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.headerContainer}>
|
||||
{headerButtons.find(b => b.position === 'left') && (
|
||||
<TouchableOpacity
|
||||
style={[styles.headerButton, styles.leftButton]}
|
||||
onPress={headerButtons.find(b => b.position === 'left')?.onPress}
|
||||
>
|
||||
<MaterialIcons
|
||||
name={headerButtons.find(b => b.position === 'left')?.icon ?? 'add'}
|
||||
size={28}
|
||||
color={colors.primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<Logo width={40} height={40} style={styles.logo} />
|
||||
<ThemedText style={styles.headerTitle}>{title}</ThemedText>
|
||||
{headerButtons.find(b => b.position === 'right') && (
|
||||
<TouchableOpacity
|
||||
style={[styles.headerButton, styles.rightButton]}
|
||||
onPress={headerButtons.find(b => b.position === 'right')?.onPress}
|
||||
>
|
||||
<MaterialIcons
|
||||
name={headerButtons.find(b => b.position === 'right')?.icon ?? 'add'}
|
||||
size={28}
|
||||
color={colors.primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
headerContainer: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
gap: 8,
|
||||
verticalAlign: 'middle',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 22,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
logo: {
|
||||
marginBottom: 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -99,7 +99,7 @@ export function CollapsibleHeader({
|
||||
right: 0,
|
||||
},
|
||||
headerButton: {
|
||||
bottom: 6,
|
||||
bottom: 2,
|
||||
padding: 4,
|
||||
position: 'absolute',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user