mirror of
https://github.com/Jellify-Music/App.git
synced 2026-01-07 19:40:19 -06:00
adding ability to switch user on library selection screen
adding backend to support loading libraries
This commit is contained in:
@@ -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
|
||||
|
||||
14
api/queries/functions/libraries.ts
Normal file
14
api/queries/functions/libraries.ts
Normal 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')
|
||||
}
|
||||
@@ -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)
|
||||
});
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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={{
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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 />
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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",
|
||||
}
|
||||
Reference in New Issue
Block a user