Add iOS Dark Mode

This commit is contained in:
Lei Nelissen
2020-07-26 14:45:32 +02:00
parent ea91b083c3
commit 6978a4dfea
20 changed files with 4253 additions and 4157 deletions

View File

@@ -245,6 +245,8 @@ PODS:
- React-cxxreact (= 0.63.2)
- React-jsi (= 0.63.2)
- React-jsinspector (0.63.2)
- react-native-appearance (0.3.4):
- React
- react-native-safe-area-context (3.1.1):
- React
- react-native-slider (3.0.3):
@@ -378,6 +380,7 @@ DEPENDENCIES:
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- react-native-appearance (from `../node_modules/react-native-appearance`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-track-player (from `../node_modules/react-native-track-player`)
@@ -451,6 +454,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
React-jsinspector:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
react-native-appearance:
:path: "../node_modules/react-native-appearance"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-slider:
@@ -526,6 +531,7 @@ SPEC CHECKSUMS:
React-jsi: 54245e1d5f4b690dec614a73a3795964eeef13a8
React-jsiexecutor: 8ca588cc921e70590820ce72b8789b02c67cce38
React-jsinspector: b14e62ebe7a66e9231e9581279909f2fc3db6606
react-native-appearance: fc2014516054585d531e07aa0b40ab0de1d2be85
react-native-safe-area-context: 4c3249e4840225c61fcd215b136af0a737bccb79
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
react-native-track-player: ba2416753b58f3cdf9db5a07daa65876d659f925
@@ -540,7 +546,7 @@ SPEC CHECKSUMS:
React-RCTText: 1b6773e776e4b33f90468c20fe3b16ca3e224bb8
React-RCTVibration: 4d2e726957f4087449739b595f107c0d4b6c2d2d
ReactCommon: a0a1edbebcac5e91338371b72ffc66aa822792ce
RNCAsyncStorage: d059c3ee71738c39834a627476322a5a8cd5bf36
RNCAsyncStorage: db711e29e5e0500d9bd21aa0c2e397efa45302b1
RNCMaskedView: f5c7d14d6847b7b44853f7acb6284c1da30a3459
RNCPicker: 55b9b4240d0a9eba8733d02616775d4040de2e7d
RNFastImage: e19ba191922e7dab9d932a4d59d62d76660aa222

8097
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,7 @@
"lodash": "^4.17.19",
"react": "^16.13.1",
"react-native": "^0.63.2",
"react-native-appearance": "^0.3.4",
"react-native-fast-image": "^8.3.2",
"react-native-gesture-handler": "^1.7.0",
"react-native-reanimated": "^1.10.1",

View File

@@ -2,9 +2,14 @@ import React, { Component } from 'react';
import { Provider } from 'react-redux';
import TrackPlayer from 'react-native-track-player';
import { PersistGate } from 'redux-persist/integration/react';
import { NavigationContainer } from '@react-navigation/native';
import { AppearanceProvider, Appearance } from 'react-native-appearance';
import Routes from '../screens';
import store, { persistedStore } from 'store';
import {
NavigationContainer,
DefaultTheme,
DarkTheme,
} from '@react-navigation/native';
interface State {
isReady: boolean;
@@ -32,6 +37,7 @@ export default class App extends Component<State> {
render() {
const { isReady } = this.state;
const scheme = Appearance.getColorScheme();
if (!isReady) {
return null;
@@ -40,9 +46,11 @@ export default class App extends Component<State> {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistedStore}>
<NavigationContainer>
<Routes />
</NavigationContainer>
<AppearanceProvider>
<NavigationContainer theme={scheme === 'dark' ? DarkTheme : DefaultTheme}>
<Routes />
</NavigationContainer>
</AppearanceProvider>
</PersistGate>
</Provider>
);

76
src/components/Colors.tsx Normal file
View File

@@ -0,0 +1,76 @@
import { StyleSheet, PlatformColor, Platform, DynamicColorIOS } from 'react-native';
import { THEME_COLOR } from 'CONSTANTS';
export const colors = StyleSheet.create({
text: {
...Platform.select({
ios: {
color: PlatformColor('label'),
},
android: {
color: PlatformColor('?android:attr/textColorPrimary'),
}
}),
},
view: {
...Platform.select({
ios: {
backgroundColor: PlatformColor('systemBackground'),
},
android: {
backgroundColor: PlatformColor('?android:attr/backgroundTint'),
}
}),
},
border: {
...Platform.select({
ios: {
borderColor: PlatformColor('systemGray5Color'),
},
android: {
borderColor: PlatformColor('?android:attr/backgroundTint'),
}
}),
},
activeBackground: {
...Platform.select({
ios: {
backgroundColor: DynamicColorIOS({ light: `${THEME_COLOR}16`, dark: `${THEME_COLOR}66` })
},
android: {
backgroundColor: PlatformColor('?android:attr/backgroundTint'),
}
}),
},
imageBackground: {
...Platform.select({
ios: {
backgroundColor: PlatformColor('systemGray5Color')
},
android: {
backgroundColor: PlatformColor('?android:attr/backgroundTint'),
}
}),
},
modal: {
...Platform.select({
ios: {
backgroundColor: DynamicColorIOS({ light: '#eeeeeeee', dark: '#222222ee' })
},
android: {
backgroundColor: PlatformColor('?android:attr/backgroundTint'),
}
}),
},
input: {
...Platform.select({
ios: {
backgroundColor: PlatformColor('systemGray5Color'),
color: PlatformColor('label'),
},
android: {
backgroundColor: PlatformColor('?android:attr/backgroundTint'),
}
}),
}
});

View File

@@ -2,7 +2,6 @@ import styled from 'styled-components/native';
const Input = styled.TextInput`
margin: 10px 0;
background-color: #f6f6f6;
border-radius: 5px;
padding: 15px;
`;

View File

@@ -3,20 +3,20 @@ import { TouchableOpacityProps, Text } from 'react-native';
import ChevronRight from 'assets/chevron-right.svg';
import styled from 'styled-components/native';
import { THEME_COLOR } from 'CONSTANTS';
import { colors } from './Colors';
const BUTTON_SIZE = 14;
const Container = styled.TouchableOpacity`
padding: 18px 0;
border-bottom-width: 1px;
border-bottom-color: #eee;
flex-direction: row;
justify-content: space-between;
`;
const ListButton: React.FC<TouchableOpacityProps> = ({ children, ...props }) => {
return (
<Container {...props}>
<Container {...props} style={colors.borderColor}>
<Text style={{ color: THEME_COLOR, fontSize: 16 }}>{children}</Text>
<ChevronRight width={BUTTON_SIZE} height={BUTTON_SIZE} fill={THEME_COLOR} />
</Container>

View File

@@ -1,24 +1,23 @@
import React from 'react';
import styled from 'styled-components/native';
import { SafeAreaView } from 'react-native';
import { colors } from './Colors';
const Background = styled.View`
background-color: #eeeeeeee;
padding: 100px 25px;
flex: 1;
`;
const Container = styled.View`
background-color: white;
border-radius: 20px;
flex: 1;
`;
const Modal: React.FC = ({ children }) => {
return (
<Background>
<SafeAreaView style={{ flex: 1}}>
<Container>
<Background style={colors.modal}>
<SafeAreaView style={{ flex: 1 }}>
<Container style={colors.view}>
{children}
</Container>
</SafeAreaView>

View File

@@ -1,6 +1,6 @@
import React, { useCallback, useEffect } from 'react';
import { StackParams } from '../types';
import { Text, ScrollView, Dimensions, Button, RefreshControl } from 'react-native';
import { Text, ScrollView, Dimensions, Button, RefreshControl, StyleSheet } from 'react-native';
import { useGetImage } from 'utility/JellyfinApi';
import styled, { css } from 'styled-components/native';
import { useRoute, RouteProp } from '@react-navigation/native';
@@ -14,11 +14,32 @@ import usePlayAlbum from 'utility/usePlayAlbum';
import usePlayTrack from 'utility/usePlayTrack';
import TouchableHandler from 'components/TouchableHandler';
import useCurrentTrack from 'utility/useCurrentTrack';
import { colors } from 'components/Colors';
type Route = RouteProp<StackParams, 'Album'>;
const Screen = Dimensions.get('screen');
const styles = StyleSheet.create({
name: {
...colors.text,
fontSize: 36,
fontWeight: 'bold'
},
artist: {
...colors.text,
fontSize: 24,
opacity: 0.5,
marginBottom: 24
},
index: {
...colors.text,
width: 20,
opacity: 0.5,
marginRight: 5
}
});
const AlbumImage = styled(FastImage)`
border-radius: 10px;
width: ${Screen.width * 0.6}px;
@@ -29,7 +50,6 @@ const AlbumImage = styled(FastImage)`
const TrackContainer = styled.View<{isPlaying: boolean}>`
padding: 15px;
border-bottom-width: 1px;
border-bottom-color: #eee;
flex-direction: row;
${props => props.isPlaying && css`
@@ -71,23 +91,22 @@ const Album: React.FC = () => {
return (
<ScrollView
style={{ backgroundColor: '#f6f6f6' }}
contentContainerStyle={{ padding: 20, paddingBottom: 50 }}
refreshControl={
<RefreshControl refreshing={isLoading} onRefresh={refresh} />
}
>
<AlbumImage source={{ uri: getImage(album?.Id) }} />
<Text style={{ fontSize: 36, fontWeight: 'bold' }} >{album?.Name}</Text>
<Text style={{ fontSize: 24, opacity: 0.5, marginBottom: 24 }}>{album?.AlbumArtist}</Text>
<AlbumImage source={{ uri: getImage(album?.Id) }} style={colors.imageBackground} />
<Text style={styles.name} >{album?.Name}</Text>
<Text style={styles.artist}>{album?.AlbumArtist}</Text>
<Button title="Play Album" onPress={selectAlbum} color={THEME_COLOR} />
{album?.Tracks?.length ? album.Tracks.map((trackId) =>
<TouchableHandler key={trackId} id={trackId} onPress={selectTrack}>
<TrackContainer isPlaying={currentTrack?.id.startsWith(trackId) || false}>
<Text style={{ width: 20, opacity: 0.5, marginRight: 5 }}>
<TrackContainer isPlaying={currentTrack?.id.startsWith(trackId) || false} style={colors.border}>
<Text style={styles.index}>
{tracks[trackId]?.IndexNumber}
</Text>
<Text>{tracks[trackId]?.Name}</Text>
<Text style={colors.text}>{tracks[trackId]?.Name}</Text>
</TrackContainer>
</TouchableHandler>
) : undefined}

View File

@@ -15,6 +15,7 @@ import { selectAlbumsByAlphabet, SectionedId } from 'store/music/selectors';
import AlphabetScroller from 'components/AlphabetScroller';
import { EntityId } from '@reduxjs/toolkit';
import styled from 'styled-components/native';
import { colors } from 'components/Colors';
interface VirtualizedItemInfo {
section: SectionedId,
@@ -39,8 +40,6 @@ function generateSection({ section }: { section: SectionedId }) {
}
const SectionContainer = styled.View`
background-color: #f6f6f6;
border-bottom-color: #eee;
border-bottom-width: 1px;
height: 50px;
justify-content: center;
@@ -56,8 +55,8 @@ class SectionHeading extends PureComponent<{ label: string }> {
const { label } = this.props;
return (
<SectionContainer>
<SectionText>{label}</SectionText>
<SectionContainer style={colors.view}>
<SectionText style={colors.text}>{label}</SectionText>
</SectionContainer>
);
}
@@ -82,9 +81,9 @@ class GeneratedAlbumItem extends PureComponent<GeneratedAlbumItemProps> {
return (
<TouchableHandler id={id as string} onPress={onPress}>
<AlbumItem>
<AlbumImage source={{ uri: imageUrl }} />
<Text numberOfLines={1}>{name}</Text>
<HalfOpacity numberOfLines={1}>{artist}</HalfOpacity>
<AlbumImage source={{ uri: imageUrl }} style={colors.imageBackground} />
<Text numberOfLines={1} style={colors.text}>{name}</Text>
<HalfOpacity style={colors.text} numberOfLines={1}>{artist}</HalfOpacity>
</AlbumItem>
</TouchableHandler>
);

View File

@@ -1,7 +1,7 @@
import React, { useCallback, useEffect } from 'react';
import { useGetImage } from 'utility/JellyfinApi';
import { Album, NavigationProp } from '../types';
import { Text, SafeAreaView, FlatList } from 'react-native';
import { Text, SafeAreaView, FlatList, StyleSheet } from 'react-native';
import { useDispatch } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
import { useTypedSelector } from 'store';
@@ -12,6 +12,14 @@ import AlbumImage, { AlbumItem } from './components/AlbumImage';
import { useRecentAlbums } from 'store/music/selectors';
import { Header } from 'components/Typography';
import ListButton from 'components/ListButton';
import { colors } from 'components/Colors';
const styles = StyleSheet.create({
artist: {
...colors.text,
opacity: 0.5,
}
});
const NavigationHeader: React.FC = () => {
const navigation = useNavigation();
@@ -22,7 +30,7 @@ const NavigationHeader: React.FC = () => {
<ListContainer>
<ListButton onPress={handleAllAlbumsClick}>All Albums</ListButton>
<ListButton onPress={handleSearchClick}>Search</ListButton>
<Header>Recent Albums</Header>
<Header style={colors.text}>Recent Albums</Header>
</ListContainer>
);
};
@@ -58,9 +66,9 @@ const RecentAlbums: React.FC = () => {
renderItem={({ item }) => (
<TouchableHandler id={item} onPress={selectAlbum}>
<AlbumItem>
<AlbumImage source={{ uri: getImage(item) }} />
<Text numberOfLines={1}>{albums[item]?.Name}</Text>
<Text numberOfLines={1} style={{ opacity: 0.5 }}>{albums[item]?.AlbumArtist}</Text>
<AlbumImage source={{ uri: getImage(item) }} style={colors.imageBackground} />
<Text style={colors.text} numberOfLines={1}>{albums[item]?.Name}</Text>
<Text style={styles.artist} numberOfLines={1}>{albums[item]?.AlbumArtist}</Text>
</AlbumItem>
</TouchableHandler>
)}

View File

@@ -11,6 +11,7 @@ import { useNavigation } from '@react-navigation/native';
import { useGetImage } from 'utility/JellyfinApi';
import { NavigationProp } from '../types';
import FastImage from 'react-native-fast-image';
import { colors } from 'components/Colors';
const Container = styled.View`
padding: 0 20px;
@@ -20,7 +21,6 @@ const AlbumImage = styled(FastImage)`
border-radius: 4px;
width: 25px;
height: 25px;
background-color: #fefefe;
margin-right: 10px;
`;
@@ -33,7 +33,6 @@ const HalfOpacity = styled.Text`
const SearchResult = styled.View`
flex-direction: row;
align-items: center;
border-bottom-color: #ddd;
border-bottom-width: 1px;
margin-left: 15px;
padding-right: 15px;
@@ -51,7 +50,7 @@ export default function Search() {
const [searchTerm, setSearchTerm] = useState('');
const albums = useTypedSelector(state => state.music.albums.entities);
const [results, setResults] = useState<Fuse.FuseResult<Album>[]>([]);
let fuse = useRef<Fuse<Album, typeof fuseOptions>>();
const fuse = useRef<Fuse<Album, typeof fuseOptions>>();
// Prepare helpers
const navigation = useNavigation<NavigationProp>();
@@ -89,7 +88,7 @@ export default function Search() {
const HeaderComponent = React.useMemo(() => (
<Container>
<Input value={searchTerm} onChangeText={setSearchTerm} placeholder="Search..." />
<Input value={searchTerm} onChangeText={setSearchTerm} style={colors.input} placeholder="Search..." />
{(searchTerm.length && !results.length) ? <Text>No results...</Text> : null}
</Container>
), [searchTerm, results, setSearchTerm]);
@@ -105,13 +104,13 @@ export default function Search() {
data={results}
renderItem={({ item: { item: album } }) =>(
<TouchableHandler id={album.Id} onPress={selectAlbum}>
<SearchResult>
<SearchResult style={colors.border}>
<AlbumImage source={{ uri: getImage(album.Id) }} />
<View>
<Text numberOfLines={1} ellipsizeMode="tail">
<Text numberOfLines={1} ellipsizeMode="tail" style={colors.text}>
{album.Name} - {album.AlbumArtist}
</Text>
<HalfOpacity>Album</HalfOpacity>
<HalfOpacity style={colors.text}>Album</HalfOpacity>
</View>
</SearchResult>
</TouchableHandler>

View File

@@ -14,7 +14,6 @@ const AlbumImage = styled(FastImage)`
border-radius: 10px;
width: ${Screen.width / 2 - 40}px;
height: ${Screen.width / 2 - 40}px;
background-color: #fefefe;
margin-bottom: 5px;
`;

View File

@@ -2,7 +2,6 @@ import styled from 'styled-components/native';
const ListContainer = styled.View`
padding: 10px;
background-color: #f6f6f6;
`;
export default ListContainer;

View File

@@ -1,29 +1,47 @@
import React from 'react';
import { Text, Dimensions, View } from 'react-native';
import { Text, Dimensions, View, StyleSheet } from 'react-native';
import useCurrentTrack from 'utility/useCurrentTrack';
import styled from 'styled-components/native';
import FastImage from 'react-native-fast-image';
import { colors } from 'components/Colors';
const Screen = Dimensions.get('screen');
const Artwork = styled(FastImage)`
border-radius: 10px;
background-color: #fbfbfb;
width: ${Screen.width * 0.8}px;
height: ${Screen.width * 0.8}px;
margin: 25px auto;
display: flex;
flex: 1;
`;
const styles = StyleSheet.create({
artist: {
...colors.text,
fontWeight: 'bold',
fontSize: 24,
marginBottom: 12,
},
title: {
...colors.text,
fontSize: 18,
marginBottom: 12,
textAlign: 'center',
paddingLeft: 20,
paddingRight: 20,
}
});
export default function NowPlaying() {
const track = useCurrentTrack();
return (
<View style={{ alignItems: 'center' }}>
<Artwork style={{ flex: 1 }} source={{ uri: track?.artwork }} />
<Text style={{ fontWeight: 'bold', fontSize: 24, marginBottom: 12 }} >{track?.artist}</Text>
<Text style={{ fontSize: 18, marginBottom: 12, textAlign: 'center', paddingLeft: 20, paddingRight: 20 }}>{track?.title}</Text>
<Artwork style={colors.imageBackground} source={{ uri: track?.artwork }} />
<Text style={styles.artist} >{track?.artist}</Text>
<Text style={styles.title}>{track?.title}</Text>
</View>
);
}

View File

@@ -4,6 +4,7 @@ import styled from 'styled-components/native';
import { Text, Platform } from 'react-native';
import Slider from '@react-native-community/slider';
import { THEME_COLOR } from 'CONSTANTS';
import { colors } from 'components/Colors';
const NumberBar = styled.View`
flex-direction: row;
@@ -78,8 +79,8 @@ export default class ProgressBar extends Component<{}, State> {
disabled={!duration}
/>
<NumberBar>
<Text>{getMinutes(gesture || position)}:{getSeconds(gesture || position)}</Text>
<Text>{getMinutes(duration)}:{getSeconds(duration)}</Text>
<Text style={colors.text}>{getMinutes(gesture || position)}:{getSeconds(gesture || position)}</Text>
<Text style={colors.text}>{getMinutes(duration)}:{getSeconds(duration)}</Text>
</NumberBar>
</>
);

View File

@@ -1,29 +1,39 @@
import React, { useCallback } from 'react';
import useQueue from 'utility/useQueue';
import { View, Text } from 'react-native';
import { View, Text, StyleSheet } from 'react-native';
import styled, { css } from 'styled-components/native';
import useCurrentTrack from 'utility/useCurrentTrack';
import TouchableHandler from 'components/TouchableHandler';
import TrackPlayer from 'react-native-track-player';
import { THEME_COLOR } from 'CONSTANTS';
import { colors } from 'components/Colors';
const QueueItem = styled.View<{ active?: boolean, alreadyPlayed?: boolean }>`
const QueueItem = styled.View<{ active?: boolean, alreadyPlayed?: boolean, isDark?: boolean }>`
padding: 10px;
border-bottom-width: 1px;
border-bottom-color: #eee;
${props => props.active && css`
font-weight: 900;
background-color: ${THEME_COLOR}16;
padding: 20px 35px;
margin: 0 -25px;
`}
${props => props.alreadyPlayed && css`
opacity: 0.25;
opacity: 0.5;
`}
`;
const styles = StyleSheet.create({
title: {
...colors.text,
marginBottom: 2,
},
artist: {
...colors.text,
opacity: 0.5,
}
});
export default function Queue() {
const queue = useQueue();
const currentTrack = useCurrentTrack();
@@ -38,9 +48,17 @@ export default function Queue() {
<Text style={{ marginTop: 20, marginBottom: 20 }}>Queue</Text>
{queue.map((track, i) => (
<TouchableHandler id={track.id} onPress={playTrack} key={i}>
<QueueItem active={currentTrack?.id === track.id} key={i} alreadyPlayed={i < currentIndex}>
<Text style={{marginBottom: 2}}>{track.title}</Text>
<Text style={{ opacity: 0.5 }}>{track.artist}</Text>
<QueueItem
active={currentTrack?.id === track.id}
key={i}
alreadyPlayed={i < currentIndex}
style={{
...colors.border,
...currentTrack?.id === track.id ? colors.activeBackground : {},
}}
>
<Text style={styles.title}>{track.title}</Text>
<Text style={styles.artist}>{track.artist}</Text>
</QueueItem>
</TouchableHandler>
))}

View File

@@ -1,25 +1,35 @@
import React from 'react';
import { DynamicColorIOS, StyleSheet, ScrollView, Platform, PlatformColor } from 'react-native';
import MediaControls from './components/MediaControls';
import ProgressBar from './components/ProgressBar';
import NowPlaying from './components/NowPlaying';
import styled from 'styled-components/native';
import Queue from './components/Queue';
const Container = styled.ScrollView`
background-color: #fff;
`;
const containerStyle = {
padding: 25,
};
const styles = StyleSheet.create({
outer: {
...Platform.select({
ios: {
color: PlatformColor('label'),
backgroundColor: PlatformColor('systemBackground'),
},
android: {
color: PlatformColor('?android:attr/textColorPrimary'),
backgroundColor: PlatformColor('?android:attr/backgroundTint'),
}
}),
},
inner: {
padding: 25,
}
});
export default function Player() {
return (
<Container contentContainerStyle={containerStyle}>
<ScrollView contentContainerStyle={styles.inner} style={styles.outer}>
<NowPlaying />
<MediaControls />
<ProgressBar />
<Queue />
</Container>
</ScrollView>
);
}

View File

@@ -8,6 +8,8 @@ import { AppState } from 'store';
import { useNavigation } from '@react-navigation/native';
import { NavigationProp } from '..';
import { THEME_COLOR } from 'CONSTANTS';
import { Header } from 'components/Typography';
import { colors } from 'components/Colors';
const InputContainer = styled.View`
margin: 10px 0;
@@ -29,22 +31,22 @@ export default function Settings() {
<ScrollView>
<SafeAreaView>
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 36, marginBottom: 24, fontWeight: 'bold' }}>Settings</Text>
<Header style={colors.text}>Settings</Header>
<InputContainer>
<Text>Jellyfin Server URL</Text>
<Text style={colors.text}>Jellyfin Server URL</Text>
<Input placeholder="https://jellyfin.yourserver.com/" value={jellyfin?.uri} editable={false} />
</InputContainer>
<InputContainer>
<Text>Jellyfin Access Token</Text>
<Text style={colors.text}>Jellyfin Access Token</Text>
<Input placeholder="deadbeefdeadbeefdeadbeef" value={jellyfin?.access_token} editable={false} />
</InputContainer>
<InputContainer>
<Text>Jellyfin User ID</Text>
<Text style={colors.text}>Jellyfin User ID</Text>
<Input placeholder="deadbeefdeadbeefdeadbeef" value={jellyfin?.user_id} editable={false} />
</InputContainer>
<Button title="Set Jellyfin server" onPress={handleClick} color={THEME_COLOR} />
<InputContainer>
<Text>Bitrate</Text>
<Text style={colors.text}>Bitrate</Text>
<Picker selectedValue={bitrate}>
<Picker.Item label="320kbps" value={140000000} />
</Picker>

View File

@@ -7,6 +7,7 @@ import { useDispatch } from 'react-redux';
import { useNavigation, StackActions } from '@react-navigation/native';
import CredentialGenerator from './components/CredentialGenerator';
import { THEME_COLOR } from 'CONSTANTS';
import { colors } from 'components/Colors';
export default function SetJellyfinServer() {
// State for first screen
@@ -31,8 +32,8 @@ export default function SetJellyfinServer() {
onCredentialsRetrieved={saveCredentials}
/>
) : (
<View style={{ padding: 20}}>
<Text>Please enter your Jellyfin server URL first. Make sure to include the protocol and port</Text>
<View style={{ padding: 20 }}>
<Text style={colors.text}>Please enter your Jellyfin server URL first. Make sure to include the protocol and port</Text>
<Input
placeholder="https://jellyfin.yourserver.io/"
onChangeText={setServerUrl}
@@ -40,6 +41,7 @@ export default function SetJellyfinServer() {
keyboardType="url"
autoCapitalize="none"
autoCorrect={false}
style={colors.input}
/>
<Button
title="Set server"