don't use i18n namespaces

there's no need to keep reloading different parts of the object we already cached
This commit is contained in:
austinried 2022-04-16 18:06:06 +09:00
parent b8948fb646
commit 52e95dc959
14 changed files with 120 additions and 79 deletions

View File

@ -164,12 +164,12 @@ const OptionStar = withSuspenseMemo<{
additionalText?: string additionalText?: string
}>(({ id, type, additionalText: text }) => { }>(({ id, type, additionalText: text }) => {
const { query, toggle } = useStar(id, type) const { query, toggle } = useStar(id, type)
const { t } = useTranslation('context.actions') const { t } = useTranslation()
return ( return (
<ContextMenuIconTextOption <ContextMenuIconTextOption
IconComponentRaw={<Star starred={!!query.data} size={26} />} IconComponentRaw={<Star starred={!!query.data} size={26} />}
text={(query.data ? t('unstar') : t('star')) + (text ? ` ${text}` : '')} text={(query.data ? t('unstar') : t('context.actions.star')) + (text ? ` ${text}` : '')}
onSelect={() => toggle.mutate()} onSelect={() => toggle.mutate()}
/> />
) )
@ -180,7 +180,7 @@ const OptionViewArtist = withSuspenseMemo<{
artist?: string artist?: string
artistId?: string artistId?: string
}>(({ navigation, artist, artistId }) => { }>(({ navigation, artist, artistId }) => {
const { t } = useTranslation('resources.artist.actions') const { t } = useTranslation()
if (!artist || !artistId) { if (!artist || !artistId) {
return <></> return <></>
@ -192,7 +192,7 @@ const OptionViewArtist = withSuspenseMemo<{
name="microphone" name="microphone"
size={26} size={26}
text={t('view')} text={t('view')}
onSelect={() => navigation.navigate('artist', { id: artistId, title: artist })} onSelect={() => navigation.navigate('resources.artist.actions.artist', { id: artistId, title: artist })}
/> />
) )
}) })
@ -202,7 +202,7 @@ const OptionViewAlbum = withSuspenseMemo<{
album?: string album?: string
albumId?: string albumId?: string
}>(({ navigation, album, albumId }) => { }>(({ navigation, album, albumId }) => {
const { t } = useTranslation('resources.album.actions') const { t } = useTranslation()
if (!album || !albumId) { if (!album || !albumId) {
return <></> return <></>
@ -214,7 +214,7 @@ const OptionViewAlbum = withSuspenseMemo<{
name="compact-disc" name="compact-disc"
size={26} size={26}
text={t('view')} text={t('view')}
onSelect={() => navigation.navigate('album', { id: albumId, title: album })} onSelect={() => navigation.navigate('resources.album.actions.album', { id: albumId, title: album })}
/> />
) )
}) })

View File

@ -17,7 +17,7 @@ const ListPlayerControls = withSuspenseMemo<{
disabled?: boolean disabled?: boolean
}>(({ listType, style, play, shuffle, disabled }) => { }>(({ listType, style, play, shuffle, disabled }) => {
const [downloaded, setDownloaded] = useState(false) const [downloaded, setDownloaded] = useState(false)
const { t } = useTranslation('resources') const { t } = useTranslation()
return ( return (
<View style={[styles.controls, style]}> <View style={[styles.controls, style]}>
@ -34,7 +34,7 @@ const ListPlayerControls = withSuspenseMemo<{
</Button> </Button>
</View> </View>
<View style={styles.controlsCenter}> <View style={styles.controlsCenter}>
<Button title={t(`${listType}.actions.play`)} disabled={disabled} onPress={play} /> <Button title={t(`resources.${listType}.actions.play`)} disabled={disabled} onPress={play} />
</View> </View>
<View style={styles.controlsSide}> <View style={styles.controlsSide}>
<Button disabled={disabled} onPress={shuffle}> <Button disabled={disabled} onPress={shuffle}>

View File

@ -10,7 +10,7 @@ const NothingHere = withSuspenseMemo<{
width?: number width?: number
style?: ViewStyle style?: ViewStyle
}>(({ height, width, style }) => { }>(({ height, width, style }) => {
const { t } = useTranslation('messages') const { t } = useTranslation()
height = height || 200 height = height || 200
width = width || 200 width = width || 200
@ -18,7 +18,7 @@ const NothingHere = withSuspenseMemo<{
<View style={[styles.container, { height, width }, style]}> <View style={[styles.container, { height, width }, style]}>
<Icon name="music-rest-quarter" color={styles.text.color} size={width / 2} /> <Icon name="music-rest-quarter" color={styles.text.color} size={width / 2} />
<Text style={[styles.text, { fontSize: width / 8 }]} numberOfLines={3}> <Text style={[styles.text, { fontSize: width / 8 }]} numberOfLines={3}>
{t('nothingHere')} {t('messages.nothingHere')}
</Text> </Text>
</View> </View>
) )

View File

@ -174,7 +174,7 @@ const SettingsTab = () => {
const Tab = createBottomTabNavigator() const Tab = createBottomTabNavigator()
const BottomTabNavigator = withSuspense(() => { const BottomTabNavigator = withSuspense(() => {
const { t } = useTranslation('navigation.tabs') const { t } = useTranslation()
const firstRun = useFirstRun() const firstRun = useFirstRun()
const resetServer = useStore(store => store.resetServer) const resetServer = useStore(store => store.resetServer)
@ -184,12 +184,12 @@ const BottomTabNavigator = withSuspense(() => {
<></> <></>
) : ( ) : (
<> <>
<Tab.Screen name="home" component={HomeTab} options={{ tabBarLabel: t('home') }} /> <Tab.Screen name="home" component={HomeTab} options={{ tabBarLabel: t('navigation.tabs.home') }} />
<Tab.Screen name="library" component={LibraryTab} options={{ tabBarLabel: t('library') }} /> <Tab.Screen name="library" component={LibraryTab} options={{ tabBarLabel: t('navigation.tabs.library') }} />
<Tab.Screen name="search" component={SearchTab} options={{ tabBarLabel: t('search') }} /> <Tab.Screen name="search" component={SearchTab} options={{ tabBarLabel: t('navigation.tabs.search') }} />
</> </>
)} )}
<Tab.Screen name="settings" component={SettingsTab} options={{ tabBarLabel: t('settings') }} /> <Tab.Screen name="settings" component={SettingsTab} options={{ tabBarLabel: t('navigation.tabs.settings') }} />
</Tab.Navigator> </Tab.Navigator>
) )
}) })

View File

@ -14,9 +14,11 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'
const Tab = createMaterialTopTabNavigator() const Tab = createMaterialTopTabNavigator()
const LibraryTopTabNavigator = withSuspense(() => { const LibraryTopTabNavigator = withSuspense(() => {
const { t } = useTranslation('resources') const { t } = useTranslation()
const marginTop = useSafeAreaInsets().top const marginTop = useSafeAreaInsets().top
console.log('Albums:', t('resources.album.name', { count: 2 }))
return ( return (
<Tab.Navigator <Tab.Navigator
tabBarOptions={{ tabBarOptions={{
@ -25,12 +27,20 @@ const LibraryTopTabNavigator = withSuspense(() => {
indicatorStyle: styles.tabindicatorStyle, indicatorStyle: styles.tabindicatorStyle,
}} }}
initialRouteName="albums"> initialRouteName="albums">
<Tab.Screen name="albums" component={AlbumsTab} options={{ tabBarLabel: t('album.name', { count: 2 }) }} /> <Tab.Screen
<Tab.Screen name="artists" component={ArtistsTab} options={{ tabBarLabel: t('artist.name', { count: 2 }) }} /> name="albums"
component={AlbumsTab}
options={{ tabBarLabel: t('resources.album.name', { count: 2 }) }}
/>
<Tab.Screen
name="artists"
component={ArtistsTab}
options={{ tabBarLabel: t('resources.artist.name', { count: 2 }) }}
/>
<Tab.Screen <Tab.Screen
name="playlists" name="playlists"
component={PlaylistsTab} component={PlaylistsTab}
options={{ tabBarLabel: t('playlist.name', { count: 2 }) }} options={{ tabBarLabel: t('resources.playlist.name', { count: 2 }) }}
/> />
</Tab.Navigator> </Tab.Navigator>
) )

View File

@ -12,7 +12,7 @@ import { createNativeStackNavigator } from 'react-native-screens/native-stack'
const NowPlayingStack = createNativeStackNavigator() const NowPlayingStack = createNativeStackNavigator()
const NowPlayingNavigator = withSuspense(() => { const NowPlayingNavigator = withSuspense(() => {
const { t } = useTranslation('resources.queue') const { t } = useTranslation()
return ( return (
<NowPlayingStack.Navigator> <NowPlayingStack.Navigator>
@ -21,7 +21,7 @@ const NowPlayingNavigator = withSuspense(() => {
name="queue" name="queue"
component={NowPlayingQueue} component={NowPlayingQueue}
options={{ options={{
title: t('name'), title: t('resources.queue.name'),
headerStyle: { headerStyle: {
backgroundColor: colors.gradient.high, backgroundColor: colors.gradient.high,
}, },

View File

@ -50,11 +50,11 @@ const TopSongs = withSuspenseMemo<{
}>( }>(
({ songs, name }) => { ({ songs, name }) => {
const { setQueue, isReady, contextId } = useSetQueue('artist', songs) const { setQueue, isReady, contextId } = useSetQueue('artist', songs)
const { t } = useTranslation('resources.song.lists') const { t } = useTranslation()
return ( return (
<> <>
<Header>{t('artistTopSongs')}</Header> <Header>{t('resources.song.lists.artistTopSongs')}</Header>
{songs.slice(0, 5).map((s, i) => ( {songs.slice(0, 5).map((s, i) => (
<ListItem <ListItem
key={i} key={i}
@ -79,7 +79,7 @@ const ArtistAlbums = withSuspenseMemo<{
}>( }>(
({ albums }) => { ({ albums }) => {
const albumsLayout = useLayout() const albumsLayout = useLayout()
const { t } = useTranslation('resources.album') const { t } = useTranslation()
const sortedAlbums = [...albums] const sortedAlbums = [...albums]
.sort((a, b) => a.name.localeCompare(b.name)) .sort((a, b) => a.name.localeCompare(b.name))
@ -89,7 +89,7 @@ const ArtistAlbums = withSuspenseMemo<{
return ( return (
<> <>
<Header>{t('name', { count: 2 })}</Header> <Header>{t('resources.album.name', { count: 2 })}</Header>
<View style={styles.albums} onLayout={albumsLayout.onLayout}> <View style={styles.albums} onLayout={albumsLayout.onLayout}>
{sortedAlbums.map(a => ( {sortedAlbums.map(a => (
<AlbumItem key={a.id} album={a} height={albumSize} width={albumSize} /> <AlbumItem key={a.id} album={a} height={albumSize} width={albumSize} />

View File

@ -45,9 +45,9 @@ const AlbumItem = React.memo<{
}, equal) }, equal)
const CategoryHeader = withSuspenseMemo<{ type: string }>(({ type }) => { const CategoryHeader = withSuspenseMemo<{ type: string }>(({ type }) => {
const { t } = useTranslation('resources.album.lists') const { t } = useTranslation()
console.log('type', type, t(type)) console.log('type', type, t(`resources.album.lists.${type}`))
return <Header style={styles.header}>{t(type)}</Header> return <Header style={styles.header}>{t(`resources.album.lists.${type}`)}</Header>
}) })
const Category = React.memo<{ const Category = React.memo<{

View File

@ -66,18 +66,18 @@ const filterValues: GetAlbumList2TypeBase[] = [
] ]
const AlbumFilterButton = withSuspenseMemo(() => { const AlbumFilterButton = withSuspenseMemo(() => {
const { t } = useTranslation('resources.album.lists') const { t } = useTranslation()
const filterType = useStoreDeep(store => store.settings.screens.library.albumsFilter.type) const filterType = useStoreDeep(store => store.settings.screens.library.albumsFilter.type)
const setFilterType = useStore(store => store.setLibraryAlbumFilterType) const setFilterType = useStore(store => store.setLibraryAlbumFilterType)
return ( return (
<FilterButton <FilterButton
data={filterValues.map(value => ({ value, text: t(value) }))} data={filterValues.map(value => ({ value, text: t(`resources.album.lists.${value}`) }))}
value={filterType} value={filterType}
onSelect={selection => { onSelect={selection => {
setFilterType(selection as GetAlbumList2TypeBase) setFilterType(selection as GetAlbumList2TypeBase)
}} }}
title={t('sort')} title={t('resources.album.lists.sort')}
/> />
) )
}) })

View File

@ -21,16 +21,16 @@ const filterValues: ArtistFilterType[] = [
] ]
const ArtistFilterButton = withSuspenseMemo(() => { const ArtistFilterButton = withSuspenseMemo(() => {
const { t } = useTranslation('resources.artist.lists') const { t } = useTranslation()
const filterType = useStoreDeep(store => store.settings.screens.library.artistsFilter.type) const filterType = useStoreDeep(store => store.settings.screens.library.artistsFilter.type)
const setFilterType = useStore(store => store.setLibraryArtistFilterType) const setFilterType = useStore(store => store.setLibraryArtistFilterType)
return ( return (
<FilterButton <FilterButton
data={filterValues.map(value => ({ value, text: t(value) }))} data={filterValues.map(value => ({ value, text: t(`resources.artist.lists.${value}`) }))}
value={filterType} value={filterType}
onSelect={selection => setFilterType(selection as ArtistFilterType)} onSelect={selection => setFilterType(selection as ArtistFilterType)}
title={t('sort')} title={t('resources.artist.lists.sort')}
/> />
) )
}) })

View File

@ -49,7 +49,7 @@ const ResultsCategory = withSuspenseMemo<{
}>( }>(
({ name, query, type, items }) => { ({ name, query, type, items }) => {
const navigation = useNavigation() const navigation = useNavigation()
const { t } = useTranslation('search') const { t } = useTranslation()
if (items.length === 0) { if (items.length === 0) {
return <></> return <></>
@ -67,7 +67,7 @@ const ResultsCategory = withSuspenseMemo<{
)} )}
{items.length === 5 && ( {items.length === 5 && (
<Button <Button
title={t('moreResults')} title={t('search.moreResults')}
buttonStyle="hollow" buttonStyle="hollow"
style={styles.more} style={styles.more}
onPress={() => navigation.navigate('results', { query, type: items[0].itemType })} onPress={() => navigation.navigate('results', { query, type: items[0].itemType })}
@ -85,13 +85,28 @@ const Results = withSuspenseMemo<{
query: string query: string
}>( }>(
({ results, query }) => { ({ results, query }) => {
const { t } = useTranslation('resources') const { t } = useTranslation()
return ( return (
<> <>
<ResultsCategory name={t('artist.name', { count: 2 })} query={query} type={'artist'} items={results.artists} /> <ResultsCategory
<ResultsCategory name={t('album.name', { count: 2 })} query={query} type={'album'} items={results.albums} /> name={t('resources.artist.name', { count: 2 })}
<ResultsCategory name={t('song.name', { count: 2 })} query={query} type={'song'} items={results.songs} /> query={query}
type={'artist'}
items={results.artists}
/>
<ResultsCategory
name={t('resources.album.name', { count: 2 })}
query={query}
type={'album'}
items={results.albums}
/>
<ResultsCategory
name={t('resources.song.name', { count: 2 })}
query={query}
type={'song'}
items={results.songs}
/>
</> </>
) )
}, },
@ -102,7 +117,7 @@ const Results = withSuspenseMemo<{
const Search = withSuspense(() => { const Search = withSuspense(() => {
const [query, setQuery] = useState('') const [query, setQuery] = useState('')
const { data, isLoading } = useQuerySearchResults({ query, albumCount: 5, artistCount: 5, songCount: 5 }) const { data, isLoading } = useQuerySearchResults({ query, albumCount: 5, artistCount: 5, songCount: 5 })
const { t } = useTranslation('search') const { t } = useTranslation()
const [text, setText] = useState('') const [text, setText] = useState('')
const searchBarRef = useRef<ReactTextInput>(null) const searchBarRef = useRef<ReactTextInput>(null)
@ -154,7 +169,7 @@ const Search = withSuspense(() => {
<TextInput <TextInput
ref={searchBarRef} ref={searchBarRef}
style={styles.textInput} style={styles.textInput}
placeholder={t('inputPlaceholder')} placeholder={t('search.inputPlaceholder')}
value={text} value={text}
onChangeText={onChangeText} onChangeText={onChangeText}
/> />

View File

@ -59,7 +59,7 @@ const SearchResultsView = withSuspense<{
type: 'album' | 'artist' | 'song' type: 'album' | 'artist' | 'song'
}>(({ query, type }) => { }>(({ query, type }) => {
const navigation = useNavigation() const navigation = useNavigation()
const { t } = useTranslation('search') const { t } = useTranslation()
const size = 100 const size = 100
const params: Search3Params = { query } const params: Search3Params = { query }
@ -85,7 +85,7 @@ const SearchResultsView = withSuspense<{
useEffect(() => { useEffect(() => {
navigation.setOptions({ navigation.setOptions({
title: t('headerTitle', { query }), title: t('search.headerTitle', { query }),
}) })
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []) }, [])

View File

@ -20,7 +20,7 @@ const ServerView = withSuspense<{
id?: string id?: string
title?: string title?: string
}>(({ id, title }) => { }>(({ id, title }) => {
const { t } = useTranslation('settings.servers') const { t } = useTranslation()
const navigation = useNavigation() const navigation = useNavigation()
const activeServerId = useStore(store => store.settings.activeServerId) const activeServerId = useStore(store => store.settings.activeServerId)
const servers = useStoreDeep(store => store.settings.servers) const servers = useStoreDeep(store => store.settings.servers)
@ -143,7 +143,7 @@ const ServerView = withSuspense<{
const ping = async () => { const ping = async () => {
const res = await pingServer(potential) const res = await pingServer(potential)
toast( toast(
t(`messages.${res ? 'connectionOk' : 'connectionFailed'}`, { t(`settings.servers.messages.${res ? 'connectionOk' : 'connectionFailed'}`, {
address: potential.address, address: potential.address,
interpolation: { escapeValue: false }, interpolation: { escapeValue: false },
}), }),
@ -178,7 +178,7 @@ const ServerView = withSuspense<{
return ( return (
<GradientScrollView style={styles.scroll}> <GradientScrollView style={styles.scroll}>
<View style={styles.content}> <View style={styles.content}>
<Text style={styles.inputTitle}>{t('fields.address')}</Text> <Text style={styles.inputTitle}>{t('settings.servers.fields.address')}</Text>
<TextInput <TextInput
style={styles.input} style={styles.input}
placeholderTextColor="grey" placeholderTextColor="grey"
@ -191,7 +191,7 @@ const ServerView = withSuspense<{
onChangeText={setAddress} onChangeText={setAddress}
onBlur={formatAddress} onBlur={formatAddress}
/> />
<Text style={styles.inputTitle}>{t('fields.username')}</Text> <Text style={styles.inputTitle}>{t('settings.servers.fields.username')}</Text>
<TextInput <TextInput
style={styles.input} style={styles.input}
placeholderTextColor="grey" placeholderTextColor="grey"
@ -204,7 +204,7 @@ const ServerView = withSuspense<{
value={username} value={username}
onChangeText={setUsername} onChangeText={setUsername}
/> />
<Text style={styles.inputTitle}>{t('fields.password')}</Text> <Text style={styles.inputTitle}>{t('settings.servers.fields.password')}</Text>
<TextInput <TextInput
style={styles.input} style={styles.input}
placeholderTextColor="grey" placeholderTextColor="grey"
@ -219,11 +219,11 @@ const ServerView = withSuspense<{
onChangeText={setPassword} onChangeText={setPassword}
/> />
<SettingsSwitch <SettingsSwitch
title={t('options.forcePlaintextPassword.title')} title={t('settings.servers.options.forcePlaintextPassword.title')}
subtitle={ subtitle={
usePlainPassword usePlainPassword
? t('options.forcePlaintextPassword.descriptionOn') ? t('settings.servers.options.forcePlaintextPassword.descriptionOn')
: t('options.forcePlaintextPassword.descriptionOff') : t('settings.servers.options.forcePlaintextPassword.descriptionOff')
} }
value={usePlainPassword} value={usePlainPassword}
setValue={togglePlainPassword} setValue={togglePlainPassword}
@ -231,17 +231,22 @@ const ServerView = withSuspense<{
<Button <Button
disabled={disableControls()} disabled={disableControls()}
style={styles.button} style={styles.button}
title={t('actions.testConnection')} title={t('settings.servers.actions.testConnection')}
buttonStyle="hollow" buttonStyle="hollow"
onPress={test} onPress={test}
/> />
<Button <Button
disabled={disableControls()} disabled={disableControls()}
style={[styles.button, styles.delete, deleteStyle]} style={[styles.button, styles.delete, deleteStyle]}
title={t('actions.delete')} title={t('settings.servers.actions.delete')}
onPress={remove} onPress={remove}
/> />
<Button disabled={disableControls()} style={styles.button} title={t('actions.save')} onPress={save} /> <Button
disabled={disableControls()}
style={styles.button}
title={t('settings.servers.actions.save')}
onPress={save}
/>
</View> </View>
</GradientScrollView> </GradientScrollView>
) )

View File

@ -26,7 +26,7 @@ const ServerItem = withSuspenseMemo<{
const activeServerId = useStore(store => store.settings.activeServerId) const activeServerId = useStore(store => store.settings.activeServerId)
const switchActiveServer = useSwitchActiveServer() const switchActiveServer = useSwitchActiveServer()
const navigation = useNavigation() const navigation = useNavigation()
const { t } = useTranslation('settings.servers.actions') const { t } = useTranslation()
const setActive = useCallback(() => { const setActive = useCallback(() => {
switchActiveServer(server.id) switchActiveServer(server.id)
@ -36,7 +36,7 @@ const ServerItem = withSuspenseMemo<{
<SettingsItem <SettingsItem
title={server.address} title={server.address}
subtitle={server.username} subtitle={server.username}
onPress={() => navigation.navigate('server', { id: server.id, title: t('edit') })}> onPress={() => navigation.navigate('server', { id: server.id, title: t('settings.servers.actions.edit') })}>
<PressableOpacity style={styles.serverActive} onPress={setActive}> <PressableOpacity style={styles.serverActive} onPress={setActive}>
{activeServerId === server.id ? ( {activeServerId === server.id ? (
<Icon name="checkbox-marked-circle" size={30} color={colors.accent} /> <Icon name="checkbox-marked-circle" size={30} color={colors.accent} />
@ -81,12 +81,16 @@ const BitrateModal = withSuspenseMemo<{
bitrate: number bitrate: number
setBitrate: (bitrate: number) => void setBitrate: (bitrate: number) => void
}>(({ title, bitrate, setBitrate }) => { }>(({ title, bitrate, setBitrate }) => {
const { t } = useTranslation('settings.network.values') const { t } = useTranslation()
const [visible, setVisible] = useState(false) const [visible, setVisible] = useState(false)
const toggleModal = useCallback(() => setVisible(!visible), [visible]) const toggleModal = useCallback(() => setVisible(!visible), [visible])
const bitrateText = useCallback((value: number) => (value === 0 ? t('unlimitedKbps') : t('kbps', { value })), [t]) const bitrateText = useCallback(
(value: number) =>
value === 0 ? t('settings.network.values.unlimitedKbps') : t('settings.network.values.kbps', { value }),
[t],
)
const BitrateChoice: React.FC<{ value: number }> = useCallback( const BitrateChoice: React.FC<{ value: number }> = useCallback(
({ value }) => { ({ value }) => {
@ -178,7 +182,7 @@ const SettingsTextModal = React.memo<{
}) })
const SettingsContent = withSuspenseMemo(() => { const SettingsContent = withSuspenseMemo(() => {
const { t } = useTranslation('settings') const { t } = useTranslation()
const servers = useStoreDeep(store => store.settings.servers) const servers = useStoreDeep(store => store.settings.servers)
const scrobble = useStore(store => store.settings.scrobble) const scrobble = useStore(store => store.settings.scrobble)
@ -209,77 +213,84 @@ const SettingsContent = withSuspenseMemo(() => {
const setMinBufferText = useCallback((text: string) => setMinBuffer(parseFloat(text)), [setMinBuffer]) const setMinBufferText = useCallback((text: string) => setMinBuffer(parseFloat(text)), [setMinBuffer])
const setMaxBufferText = useCallback((text: string) => setMaxBuffer(parseFloat(text)), [setMaxBuffer]) const setMaxBufferText = useCallback((text: string) => setMaxBuffer(parseFloat(text)), [setMaxBuffer])
const secondsText = useCallback((value: string) => t('network.values.seconds', { value }), [t]) const secondsText = useCallback((value: string) => t('settings.network.values.seconds', { value }), [t])
return ( return (
<View style={styles.content}> <View style={styles.content}>
<Header>{t('servers.name')}</Header> <Header>{t('settings.servers.name')}</Header>
{Object.values(servers).map(s => ( {Object.values(servers).map(s => (
<ServerItem key={s.id} server={s} /> <ServerItem key={s.id} server={s} />
))} ))}
<Button <Button
style={styles.button} style={styles.button}
title={t('servers.actions.add')} title={t('settings.servers.actions.add')}
onPress={() => navigation.navigate('server', { title: t('servers.actions.add') })} onPress={() => navigation.navigate('server', { title: t('settings.servers.actions.add') })}
buttonStyle="hollow" buttonStyle="hollow"
/> />
<Header style={styles.header}>{t('network.name')}</Header> <Header style={styles.header}>{t('settings.network.name')}</Header>
<BitrateModal <BitrateModal
title={t('network.options.maxBitrateWifi.title')} title={t('settings.network.options.maxBitrateWifi.title')}
bitrate={maxBitrateWifi} bitrate={maxBitrateWifi}
setBitrate={setMaxBitrateWifi} setBitrate={setMaxBitrateWifi}
/> />
<BitrateModal <BitrateModal
title={t('network.options.maxBitrateMobile.title')} title={t('settings.network.options.maxBitrateMobile.title')}
bitrate={maxBitrateMobile} bitrate={maxBitrateMobile}
setBitrate={setMaxBitrateMobile} setBitrate={setMaxBitrateMobile}
/> />
<SettingsTextModal <SettingsTextModal
title={t('network.options.minBuffer.title')} title={t('settings.network.options.minBuffer.title')}
value={minBuffer.toString()} value={minBuffer.toString()}
setValue={setMinBufferText} setValue={setMinBufferText}
subtitle={secondsText} subtitle={secondsText}
keyboardType="numeric" keyboardType="numeric"
/> />
<SettingsTextModal <SettingsTextModal
title={t('network.options.maxBuffer.title')} title={t('settings.network.options.maxBuffer.title')}
value={maxBuffer.toString()} value={maxBuffer.toString()}
setValue={setMaxBufferText} setValue={setMaxBufferText}
subtitle={secondsText} subtitle={secondsText}
keyboardType="numeric" keyboardType="numeric"
/> />
<Header style={styles.header}>{t('music.name')}</Header> <Header style={styles.header}>{t('settings.music.name')}</Header>
<SettingsSwitch <SettingsSwitch
title={t('music.options.scrobble.title')} title={t('settings.music.options.scrobble.title')}
subtitle={scrobble ? t('music.options.scrobble.descriptionOn') : t('music.options.scrobble.descriptionOff')} subtitle={
scrobble
? t('settings.music.options.scrobble.descriptionOn')
: t('settings.music.options.scrobble.descriptionOff')
}
value={scrobble} value={scrobble}
setValue={setScrobble} setValue={setScrobble}
/> />
<Header style={styles.header}>{t('reset.name')}</Header> <Header style={styles.header}>{t('settings.reset.name')}</Header>
<Button <Button
disabled={clearing} disabled={clearing}
style={styles.button} style={styles.button}
title={t('reset.actions.clearImageCache')} title={t('settings.reset.actions.clearImageCache')}
onPress={clear} onPress={clear}
buttonStyle="hollow" buttonStyle="hollow"
/> />
<Header style={styles.header}>{t('about.name')}</Header> <Header style={styles.header}>{t('settings.about.name')}</Header>
<Text style={styles.text}> <Text style={styles.text}>
<Text style={styles.bold}>Subtracks</Text> {t('about.version', { version })} <Text style={styles.bold}>Subtracks</Text> {t('settings.about.version', { version })}
</Text> </Text>
<Button <Button
disabled={clearing} disabled={clearing}
style={styles.button} style={styles.button}
title={t('about.actions.projectHomepage')} title={t('settings.about.actions.projectHomepage')}
onPress={() => Linking.openURL('https://github.com/austinried/subtracks')} onPress={() => Linking.openURL('https://github.com/austinried/subtracks')}
buttonStyle="hollow" buttonStyle="hollow"
/> />
<Button <Button
disabled={clearing} disabled={clearing}
style={styles.button} style={styles.button}
title={t('about.actions.licenses')} title={t('settings.about.actions.licenses')}
onPress={() => onPress={() =>
navigation.navigate('web', { uri: 'file:///android_asset/licenses.html', title: t('about.actions.licenses') }) navigation.navigate('web', {
uri: 'file:///android_asset/licenses.html',
title: t('settings.about.actions.licenses'),
})
} }
buttonStyle="hollow" buttonStyle="hollow"
/> />