adding ability to switch user on library selection screen

adding backend to support loading libraries
This commit is contained in:
Violet Caulfield
2024-10-20 06:09:18 -05:00
parent 7c2e60f7a2
commit b139cf1c7b
11 changed files with 81 additions and 45 deletions

View File

@@ -1,6 +1,6 @@
import { Api } from "@jellyfin/sdk";
import { client } from "../../queries";
import { fetchCredentials } from "./storage";
import { client } from "../../client";
/**
* A promise to build an authenticated Jellyfin API client

View File

@@ -0,0 +1,14 @@
import { Api } from "@jellyfin/sdk";
import { getItemsApi } from "@jellyfin/sdk/lib/utils/api/items-api";
import _ from "lodash";
export const fetchMusicLibraries = async (api: Api) => {
let libraries = await getItemsApi(api).getItems();
if (_.isUndefined(libraries.data.Items))
return Promise.reject("No libraries found on Jellyfin");
return libraries.data.Items!.filter(library => library.CollectionType == 'music')
}

View File

@@ -0,0 +1,9 @@
import { useQuery } from "@tanstack/react-query";
import { QueryKeys } from "../../enums/query-keys";
import { fetchMusicLibraries } from "./functions/libraries";
import { Api } from "@jellyfin/sdk";
export const useLibraries = (api: Api) => useQuery({
queryKey: [QueryKeys.Libraries],
queryFn: () => fetchMusicLibraries(api)
});

View File

@@ -1,6 +1,5 @@
import { useQuery } from "@tanstack/react-query";
import { QueryKeys } from "../../enums/query-keys";
import { usePublicApi } from "../queries";
import { getSystemApi } from "@jellyfin/sdk/lib/utils/api/system-api";
import { createPublicApi } from "./functions/api";

View File

@@ -0,0 +1,17 @@
import { H1, ScrollView, YStack } from "tamagui";
import { useApiClientContext } from "../jellyfin-api-provider";
import _ from "lodash";
export default function Home(): React.JSX.Element {
const { apiClient, username } = useApiClientContext();
return (
<ScrollView paddingLeft={10}>
<YStack alignContent='flex-start'>
<H1>Hi { _.isUndefined(username) ? "there" : `, ${username}`}</H1>
</YStack>
</ScrollView>
);
}

View File

@@ -7,7 +7,7 @@ import ServerLibrary from "./helpers/server-library";
export default function Login(): React.JSX.Element {
const { server, changeServer, username } = useApiClientContext();
const { server, changeServer, changeUser, username } = useApiClientContext();
const Stack = createStackNavigator();
@@ -25,7 +25,7 @@ export default function Login(): React.JSX.Element {
/>
) : (
(_.isUndefined(username)) ? (
(_.isUndefined(username) || changeUser) ? (
<Stack.Screen
name="ServerAuthentication"
options={{

View File

@@ -17,10 +17,10 @@ const https = "https://"
export default function ServerAddress(): React.JSX.Element {
const { setChangeServer, setServer, setApiClient } = useApiClientContext();
const { setChangeServer, server, setServer, setApiClient } = useApiClientContext();
const [useHttps, setUseHttps] = useState(true)
const [serverAddress, setServerAddress] = useState("");
const [serverAddress, setServerAddress] = useState(server?.name ?? undefined);
const theme = useTheme();
@@ -37,7 +37,7 @@ export default function ServerAddress(): React.JSX.Element {
// TODO: Rename url to address
let jellifyServer: JellifyServer = {
url: serverAddress,
url: serverAddress!,
name: publicSystemInfoResponse.data.ServerName!,
version: publicSystemInfoResponse.data.Version!,
startUpComplete: publicSystemInfoResponse.data.StartupWizardCompleted!
@@ -72,6 +72,7 @@ export default function ServerAddress(): React.JSX.Element {
onChangeText={setServerAddress} />
</XStack>
<Button
disabled={_.isEmpty(serverAddress)}
marginVertical={30}
onPress={() => {
useServerMutation.mutate(`${useHttps ? "https" : "http"}://${serverAddress}`);

View File

@@ -1,33 +1,40 @@
import { useMutation } from "@tanstack/react-query";
import React from "react";
import { View } from "react-native";
import { AsyncStorageKeys } from "../../../enums/async-storage-keys";
import React, { useEffect, useState } from "react";
import { useApiClientContext } from "../../jellyfin-api-provider";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { Button, Text } from "tamagui";
import { Button, H2, Select, Text, View } from "tamagui";
import { JellifyLibrary } from "../../../types/JellifyLibrary";
import { useLibraries } from "../../../api/queries/libraries";
export default function ServerLibrary(): React.JSX.Element {
const { setServer, setChangeServer, setUsername } = useApiClientContext();
const [musicLibrary, setMusicLibrary] = useState<JellifyLibrary | undefined>(undefined);
const clearServer = useMutation({
const [musicLibraryName, setMusicLibraryName] = useState<string>("")
const { apiClient, setChangeUser } = useApiClientContext();
const { data: musicLibraries, isPending: musicLibrariesPending } = useLibraries(apiClient!);
const clearUser = useMutation({
mutationFn: async () => {
setServer(undefined)
setUsername(undefined)
setChangeServer(true);
return await AsyncStorage.setItem(AsyncStorageKeys.ServerUrl, "");
setChangeUser(true);
return Promise.resolve();
}
});
return (
<View>
<Text style={{fontSize: 30 }}>Select Music Library</Text>
<View marginHorizontal={10} flex={1} justifyContent='center'>
<H2 marginVertical={30}>Select Music Library</H2>
<Button
onPress={() => {
clearServer.mutate();
clearUser.mutate();
}}
>Switch Server</Button>
<Select value={musicLibraryName}></Select>
</View>
)
}

View File

@@ -5,10 +5,8 @@ import _ from "lodash";
import { JellyfinApiClientProvider, useApiClientContext } from "./jellyfin-api-provider";
import React, { } from "react";
import { DarkTheme, DefaultTheme, NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import Navigation from "./navigation";
import Login from "./Login/component";
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
export default function Jellify(): React.JSX.Element {
@@ -33,17 +31,11 @@ function conditionalHomeRender(): React.JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
const { libraryId } = useApiClientContext();
const Stack = createNativeStackNavigator()
const Tab = createBottomTabNavigator();
return (
<NavigationContainer theme={isDarkMode ? DarkTheme : DefaultTheme}>
{ !_.isUndefined(libraryId) ? (
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen name="Navigation" options={{ headerShown: false }} component={Navigation} />
</Stack.Navigator>
<Navigation />
) : (
<Login />
)}

View File

@@ -1,20 +1,16 @@
import { createStackNavigator } from "@react-navigation/stack";
import Player from "./Player/component";
import Login from "./Login/component";
import createBottomTabNavigator from "@react-navigation/bottom-tabs/lib/typescript/src/navigators/createBottomTabNavigator";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import Home from "./Home/component";
export default function Navigation(): React.JSX.Element {
const RootStack = createStackNavigator();
const Stack = createNativeStackNavigator()
const Tab = createBottomTabNavigator();
return (
<RootStack.Navigator>
<RootStack.Group>
<RootStack.Screen name="Jellify" component={Login} />
</RootStack.Group>
<RootStack.Group screenOptions={{ presentation: 'modal' }}>
<RootStack.Screen name="Player" component={Player} />
</RootStack.Group>
</RootStack.Navigator>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen name="Home" options={{ headerShown: false }} component={Home} />
</Stack.Navigator>
)
}

View File

@@ -6,17 +6,18 @@ export enum QueryKeys {
ArtistById = "ARTIST_BY_ID",
Credentials = "CREDENTIALS",
ImageByItemId = "IMAGE_BY_ITEM_ID",
Libraries = "LIBRARIES",
Pause = "PAUSE",
Play = "PLAY",
Playlists = "PLAYLISTS",
Progress = "PROGRESS",
PlayQueue = "PLAY_QUEUE",
PublicApi = "PUBLIC_API",
PublicSystemInfo = "PUBLIC_SYSTEM_INFO",
RemoveFromQueue = "REMOVE_FROM_QUEUE",
RemoveMultipleFromQueue = "REMOVE_MULTIPLE_FROM_QUEUE",
ReportPlaybackPosition = "REPORT_PLAYBACK_POSITION",
ReportPlaybackStarted = "REPORT_PLAYBACK_STARTED",
ReportPlaybackStopped = "REPORT_PLAYBACK_STOPPED",
ServerUrl = "SERVER_URL",
PublicSystemInfo = "PublicSystemInfo",
PublicApi = "PublicApi",
}