Add onboarding component
This commit is contained in:
BIN
src/assets/app-icon-white.png
Normal file
BIN
src/assets/app-icon-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
@@ -11,6 +11,8 @@ const Background = styled.View`
|
||||
const Container = styled.View`
|
||||
border-radius: 20px;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const Modal: React.FC = ({ children }) => {
|
||||
|
||||
76
src/screens/Onboarding/index.tsx
Normal file
76
src/screens/Onboarding/index.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { Button } from 'react-native';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { NavigationProp } from 'screens';
|
||||
import { useTypedSelector } from 'store';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { setOnboardingStatus } from 'store/settings/actions';
|
||||
|
||||
const Container = styled.SafeAreaView`
|
||||
background-color: ${THEME_COLOR};
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const TextContainer = styled.ScrollView`
|
||||
padding: 25px;
|
||||
`;
|
||||
|
||||
const Text = styled.Text`
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 10px;
|
||||
`;
|
||||
|
||||
const ButtonContainer = styled.View`
|
||||
margin-top: 50px;
|
||||
`;
|
||||
|
||||
const Logo = styled.Image`
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: 0 auto 50px auto;
|
||||
`;
|
||||
|
||||
function Onboarding() {
|
||||
// Get account from Redux and dispatcher
|
||||
const account = useTypedSelector(state => state.settings.jellyfin);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Also retrieve the navigation handler so that we can open the modal in
|
||||
// which the Jellyfin server is set
|
||||
const navigation = useNavigation<NavigationProp>();
|
||||
const handleClick = useCallback(() => navigation.navigate('SetJellyfinServer'), [navigation]);
|
||||
|
||||
// We'll also respond to any change in the account, setting the onboarding
|
||||
// status to true, so that the app becomes available.
|
||||
useEffect(() => {
|
||||
if (account) {
|
||||
dispatch(setOnboardingStatus(true));
|
||||
}
|
||||
}, [account, dispatch]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<TextContainer contentContainerStyle={{ flexGrow: 1, justifyContent: 'center' }}>
|
||||
<Logo source={require('../../assets/app-icon-white.png')} />
|
||||
<Text >
|
||||
Welcome!
|
||||
</Text>
|
||||
<Text>
|
||||
Jellyfin Audio Player will allow you to stream your music library from anywhere, with full support for background audio and casting.
|
||||
</Text>
|
||||
<Text>
|
||||
In order to get started, you need a Jellyfin server. Click the button below to enter your Jellyfin server address and login to it.
|
||||
</Text>
|
||||
<ButtonContainer>
|
||||
<Button title="Set Jellyfin Server" color="#ffffff" onPress={handleClick} />
|
||||
</ButtonContainer>
|
||||
</TextContainer>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default Onboarding;
|
||||
@@ -10,6 +10,8 @@ import PlayPauseIcon from 'assets/play-pause-fill.svg';
|
||||
import NotesIcon from 'assets/notes.svg';
|
||||
import GearIcon from 'assets/gear.svg';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { useTypedSelector } from 'store';
|
||||
import Onboarding from './Onboarding';
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
const Tab = createBottomTabNavigator();
|
||||
@@ -34,6 +36,14 @@ function getIcon(route: string): React.FC<any> | null {
|
||||
}
|
||||
|
||||
function Screens() {
|
||||
const isOnboardingComplete = useTypedSelector(state => state.settings.isOnboardingComplete);
|
||||
|
||||
// GUARD: If onboarding has not been completed, we instead render the
|
||||
// onboarding component, so that the user can get setup in the app.
|
||||
if (!isOnboardingComplete) {
|
||||
return <Onboarding />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tab.Navigator
|
||||
screenOptions={({ route }) => ({
|
||||
|
||||
@@ -33,7 +33,9 @@ export default function SetJellyfinServer() {
|
||||
/>
|
||||
) : (
|
||||
<View style={{ padding: 20 }}>
|
||||
<Text style={colors.text}>Please enter your Jellyfin server URL first. Make sure to include the protocol and port</Text>
|
||||
<Text style={colors.text}>
|
||||
Please enter your Jellyfin server URL. Make sure to include the protocol and port
|
||||
</Text>
|
||||
<Input
|
||||
placeholder="https://jellyfin.yourserver.io/"
|
||||
onChangeText={setServerUrl}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { configureStore, getDefaultMiddleware, combineReducers } from '@reduxjs/toolkit';
|
||||
import { useSelector, TypedUseSelectorHook } from 'react-redux';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import { persistStore, persistReducer } from 'redux-persist';
|
||||
import { persistStore, persistReducer, PersistConfig } from 'redux-persist';
|
||||
import autoMergeLevel2 from 'redux-persist/es/stateReconciler/autoMergeLevel2';
|
||||
// import logger from 'redux-logger';
|
||||
|
||||
const persistConfig = {
|
||||
const persistConfig: PersistConfig<AppState> = {
|
||||
key: 'root',
|
||||
storage: AsyncStorage,
|
||||
stateReconciler: autoMergeLevel2
|
||||
};
|
||||
|
||||
import settings from './settings';
|
||||
@@ -26,7 +28,7 @@ const store = configureStore({
|
||||
),
|
||||
});
|
||||
|
||||
export type AppState = ReturnType<typeof store.getState>;
|
||||
export type AppState = ReturnType<typeof reducers>;
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
export type AsyncThunkAPI = { state: AppState, dispatch: AppDispatch };
|
||||
export const useTypedSelector: TypedUseSelectorHook<AppState> = useSelector;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
export const setJellyfinCredentials = createAction<{ access_token: string, user_id: string, uri: string, deviced_id: string; }>('SET_JELLYFIN_CREDENTIALS');
|
||||
export const setBitrate = createAction<number>('SET_BITRATE');
|
||||
export const setBitrate = createAction<number>('SET_BITRATE');
|
||||
export const setOnboardingStatus = createAction<boolean>('SET_ONBOARDING_STATUS');
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { setBitrate, setJellyfinCredentials } from './actions';
|
||||
import { setBitrate, setJellyfinCredentials, setOnboardingStatus } from './actions';
|
||||
|
||||
interface State {
|
||||
jellyfin?: {
|
||||
@@ -9,10 +9,12 @@ interface State {
|
||||
device_id: string;
|
||||
}
|
||||
bitrate: number;
|
||||
isOnboardingComplete: boolean;
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
bitrate: 140000000
|
||||
bitrate: 140000000,
|
||||
isOnboardingComplete: false,
|
||||
};
|
||||
|
||||
const settings = createReducer(initialState, {
|
||||
@@ -24,6 +26,10 @@ const settings = createReducer(initialState, {
|
||||
...state,
|
||||
bitrate: action.payload,
|
||||
}),
|
||||
[setOnboardingStatus.type]: (state, action) => ({
|
||||
...state,
|
||||
isOnboardingComplete: action.payload,
|
||||
})
|
||||
});
|
||||
|
||||
export default settings;
|
||||
Reference in New Issue
Block a user