mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-05-11 08:48:33 -04:00
Make icon symbols generic between Android and iOS platforms (#846)
This commit is contained in:
@@ -3,6 +3,7 @@ import React, { useEffect } from 'react';
|
||||
import { Platform, StyleSheet, View } from 'react-native';
|
||||
|
||||
import { IconSymbol } from '@/components/ui/IconSymbol';
|
||||
import { IconSymbolName } from '@/components/ui/IconSymbolName';
|
||||
import TabBarBackground from '@/components/ui/TabBarBackground';
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
@@ -94,7 +95,7 @@ export default function TabLayout() : React.ReactNode {
|
||||
/**
|
||||
* Icon for the credentials tab.
|
||||
*/
|
||||
tabBarIcon: ({ color }) => <IconSymbol size={28} name="key.fill" color={color} />,
|
||||
tabBarIcon: ({ color }) => <IconSymbol size={28} name={IconSymbolName.Key} color={color} />,
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
@@ -104,7 +105,7 @@ export default function TabLayout() : React.ReactNode {
|
||||
/**
|
||||
* Icon for the emails tab.
|
||||
*/
|
||||
tabBarIcon: ({ color }) => <IconSymbol size={28} name="envelope.fill" color={color} />,
|
||||
tabBarIcon: ({ color }) => <IconSymbol size={28} name={IconSymbolName.Envelope} color={color} />,
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
@@ -116,7 +117,7 @@ export default function TabLayout() : React.ReactNode {
|
||||
*/
|
||||
tabBarIcon: ({ color }) => (
|
||||
<View style={styles.iconContainer}>
|
||||
<IconSymbol size={28} name="gear" color={color} />
|
||||
<IconSymbol size={28} name={IconSymbolName.Gear} color={color} />
|
||||
{Platform.OS === 'ios' && authContext.shouldShowIosAutofillReminder && (
|
||||
<View style={styles.iconNotificationContainer}>
|
||||
<ThemedText style={styles.iconNotificationText}>1</ThemedText>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ThemedText } from '@/components/themed/ThemedText';
|
||||
import EncryptionUtility from '@/utils/EncryptionUtility';
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
import { IconSymbol } from '@/components/ui/IconSymbol';
|
||||
import { IconSymbolName } from '@/components/ui/IconSymbolName';
|
||||
import emitter from '@/utils/EventEmitter';
|
||||
import { ThemedView } from '@/components/themed/ThemedView';
|
||||
|
||||
@@ -384,7 +385,7 @@ export default function EmailDetailsScreen() : React.ReactNode {
|
||||
{associatedCredential && (
|
||||
<>
|
||||
<TouchableOpacity onPress={handleOpenCredential} style={styles.metadataCredential}>
|
||||
<IconSymbol size={16} name="key.fill" color={colors.primary} style={styles.metadataCredentialIcon} />
|
||||
<IconSymbol size={16} name={IconSymbolName.Key} color={colors.primary} style={styles.metadataCredentialIcon} />
|
||||
<ThemedText style={[styles.metadataText, { color: colors.primary }]}>
|
||||
{associatedCredential.ServiceName}
|
||||
</ThemedText>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { MailboxEmail } from '@/utils/types/webapi/MailboxEmail';
|
||||
import { useDb } from '@/context/DbContext';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
import { IconSymbol } from '@/components/ui/IconSymbol';
|
||||
import { IconSymbolName } from '@/components/ui/IconSymbolName';
|
||||
|
||||
type EmailCardProps = {
|
||||
email: MailboxEmail;
|
||||
@@ -138,7 +139,7 @@ export function EmailCard({ email }: EmailCardProps) : React.ReactNode {
|
||||
</ThemedText>
|
||||
{associatedCredential && (
|
||||
<View style={styles.serviceContainer}>
|
||||
<IconSymbol size={14} name="key.fill" color={colors.primary} style={styles.serviceIcon} />
|
||||
<IconSymbol size={14} name={IconSymbolName.Key} color={colors.primary} style={styles.serviceIcon} />
|
||||
<ThemedText style={styles.serviceName}>
|
||||
{associatedCredential.ServiceName}
|
||||
</ThemedText>
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
import { SymbolView, SymbolViewProps, SymbolWeight } from 'expo-symbols';
|
||||
import { SymbolView, SymbolWeight } from 'expo-symbols';
|
||||
import { StyleProp, ViewStyle } from 'react-native';
|
||||
import { IconSymbolName } from './IconSymbolName';
|
||||
|
||||
/**
|
||||
* Icon symbol component.
|
||||
* Mapping from IconSymbolName to SF Symbols names.
|
||||
* This is the iOS-specific translation layer.
|
||||
*/
|
||||
const SF_SYMBOLS_MAPPING: Record<IconSymbolName, import('expo-symbols').SymbolViewProps['name']> = {
|
||||
[IconSymbolName.Key]: 'key.fill',
|
||||
[IconSymbolName.Envelope]: 'envelope.fill',
|
||||
[IconSymbolName.Gear]: 'gear',
|
||||
[IconSymbolName.House]: 'house.fill',
|
||||
[IconSymbolName.Paperplane]: 'paperplane.fill',
|
||||
[IconSymbolName.ChevronRight]: 'chevron.right',
|
||||
[IconSymbolName.ChevronLeftRight]: 'chevron.left.forwardslash.chevron.right',
|
||||
};
|
||||
|
||||
/**
|
||||
* Icon symbol component for iOS.
|
||||
* Uses native SF Symbols for optimal performance and consistency.
|
||||
* Handles translation from IconSymbolName to SF Symbols names.
|
||||
*/
|
||||
export function IconSymbol({
|
||||
name,
|
||||
@@ -11,7 +28,7 @@ export function IconSymbol({
|
||||
style,
|
||||
weight = 'regular',
|
||||
}: {
|
||||
name: SymbolViewProps['name'];
|
||||
name: IconSymbolName;
|
||||
size?: number;
|
||||
color: string;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
@@ -22,7 +39,7 @@ export function IconSymbol({
|
||||
weight={weight}
|
||||
tintColor={color}
|
||||
resizeMode="scaleAspectFit"
|
||||
name={name}
|
||||
name={SF_SYMBOLS_MAPPING[name]}
|
||||
style={[
|
||||
{
|
||||
width: size,
|
||||
|
||||
@@ -2,31 +2,28 @@
|
||||
|
||||
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
||||
import React from 'react';
|
||||
import { OpaqueColorValue, StyleProp, ViewStyle } from 'react-native';
|
||||
import { OpaqueColorValue, StyleProp, TextStyle } from 'react-native';
|
||||
|
||||
// Add your SFSymbol to MaterialIcons mappings here.
|
||||
const MAPPING = {
|
||||
/*
|
||||
* See MaterialIcons here: https://icons.expo.fyi
|
||||
* See SF Symbols in the SF Symbols app on Mac.
|
||||
*/
|
||||
'house.fill': 'home',
|
||||
'paperplane.fill': 'send',
|
||||
'chevron.left.forwardslash.chevron.right': 'code',
|
||||
'chevron.right': 'chevron-right',
|
||||
} as Partial<
|
||||
Record<
|
||||
import('expo-symbols').SymbolViewProps['name'],
|
||||
React.ComponentProps<typeof MaterialIcons>['name']
|
||||
>
|
||||
>;
|
||||
|
||||
export type IconSymbolName = keyof typeof MAPPING;
|
||||
import { IconSymbolName } from './IconSymbolName';
|
||||
|
||||
/**
|
||||
* An icon component that uses native SFSymbols on iOS, and MaterialIcons on Android and web. This ensures a consistent look across platforms, and optimal resource usage.
|
||||
*
|
||||
* Icon `name`s are based on SFSymbols and require manual mapping to MaterialIcons.
|
||||
* Mapping from IconSymbolName to MaterialIcons names.
|
||||
* This is the Android-specific translation layer.
|
||||
*/
|
||||
const MATERIAL_ICONS_MAPPING: Record<IconSymbolName, React.ComponentProps<typeof MaterialIcons>['name']> = {
|
||||
[IconSymbolName.Key]: 'key',
|
||||
[IconSymbolName.Envelope]: 'mail',
|
||||
[IconSymbolName.Gear]: 'settings',
|
||||
[IconSymbolName.House]: 'home',
|
||||
[IconSymbolName.Paperplane]: 'send',
|
||||
[IconSymbolName.ChevronRight]: 'chevron-right',
|
||||
[IconSymbolName.ChevronLeftRight]: 'code',
|
||||
};
|
||||
|
||||
/**
|
||||
* An icon component that uses MaterialIcons on Android and web.
|
||||
* This ensures a consistent look across platforms, and optimal resource usage.
|
||||
* Handles translation from IconSymbolName to MaterialIcons names.
|
||||
*/
|
||||
export function IconSymbol({
|
||||
name,
|
||||
@@ -37,7 +34,7 @@ export function IconSymbol({
|
||||
name: IconSymbolName;
|
||||
size?: number;
|
||||
color: string | OpaqueColorValue;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
style?: StyleProp<TextStyle>;
|
||||
}): React.ReactNode {
|
||||
return <MaterialIcons color={color} size={size} name={MAPPING[name]} style={style} />;
|
||||
return <MaterialIcons color={color} size={size} name={MATERIAL_ICONS_MAPPING[name]} style={style} />;
|
||||
}
|
||||
|
||||
15
apps/mobile-app/components/ui/IconSymbolName.ts
Normal file
15
apps/mobile-app/components/ui/IconSymbolName.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Enum representing all available icon names in the app.
|
||||
* This provides type safety and consistency across platforms.
|
||||
* The actual icon names for each platform are defined in their respective IconSymbol implementations.
|
||||
*/
|
||||
export enum IconSymbolName {
|
||||
// Navigation icons
|
||||
Key,
|
||||
Envelope,
|
||||
Gear,
|
||||
House,
|
||||
Paperplane,
|
||||
ChevronRight,
|
||||
ChevronLeftRight,
|
||||
}
|
||||
Reference in New Issue
Block a user