diff --git a/apps/mobile-app/app/(tabs)/_layout.tsx b/apps/mobile-app/app/(tabs)/_layout.tsx index 0695c815b..4af3abc74 100644 --- a/apps/mobile-app/app/(tabs)/_layout.tsx +++ b/apps/mobile-app/app/(tabs)/_layout.tsx @@ -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 }) => , + tabBarIcon: ({ color }) => , }} /> , + tabBarIcon: ({ color }) => , }} /> ( - + {Platform.OS === 'ios' && authContext.shouldShowIosAutofillReminder && ( 1 diff --git a/apps/mobile-app/app/(tabs)/emails/[id].tsx b/apps/mobile-app/app/(tabs)/emails/[id].tsx index 9d2950274..a924041cf 100644 --- a/apps/mobile-app/app/(tabs)/emails/[id].tsx +++ b/apps/mobile-app/app/(tabs)/emails/[id].tsx @@ -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 && ( <> - + {associatedCredential.ServiceName} diff --git a/apps/mobile-app/components/EmailCard.tsx b/apps/mobile-app/components/EmailCard.tsx index 506f2c317..c93546fbf 100644 --- a/apps/mobile-app/components/EmailCard.tsx +++ b/apps/mobile-app/components/EmailCard.tsx @@ -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 { {associatedCredential && ( - + {associatedCredential.ServiceName} diff --git a/apps/mobile-app/components/ui/IconSymbol.ios.tsx b/apps/mobile-app/components/ui/IconSymbol.ios.tsx index 555085d9d..5df07a46b 100644 --- a/apps/mobile-app/components/ui/IconSymbol.ios.tsx +++ b/apps/mobile-app/components/ui/IconSymbol.ios.tsx @@ -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.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; @@ -22,7 +39,7 @@ export function IconSymbol({ weight={weight} tintColor={color} resizeMode="scaleAspectFit" - name={name} + name={SF_SYMBOLS_MAPPING[name]} style={[ { width: size, diff --git a/apps/mobile-app/components/ui/IconSymbol.tsx b/apps/mobile-app/components/ui/IconSymbol.tsx index 920b55b1e..411daf228 100644 --- a/apps/mobile-app/components/ui/IconSymbol.tsx +++ b/apps/mobile-app/components/ui/IconSymbol.tsx @@ -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['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['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; + style?: StyleProp; }): React.ReactNode { - return ; + return ; } diff --git a/apps/mobile-app/components/ui/IconSymbolName.ts b/apps/mobile-app/components/ui/IconSymbolName.ts new file mode 100644 index 000000000..572650791 --- /dev/null +++ b/apps/mobile-app/components/ui/IconSymbolName.ts @@ -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, +}