mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-03-11 20:06:16 +00:00
wip
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
import { router, Tabs } from "expo-router";
|
||||
import React, { useEffect } from "react";
|
||||
import * as NavigationBar from "expo-navigation-bar";
|
||||
import { TabBarIcon } from "@/components/navigation/TabBarIcon";
|
||||
import { Colors } from "@/constants/Colors";
|
||||
import { Platform, TouchableOpacity, View } from "react-native";
|
||||
import { Feather } from "@expo/vector-icons";
|
||||
import { Chromecast } from "@/components/Chromecast";
|
||||
import { BlurView } from "expo-blur";
|
||||
import { StyleSheet } from "react-native";
|
||||
import * as NavigationBar from "expo-navigation-bar";
|
||||
import { Tabs } from "expo-router";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform, StyleSheet } from "react-native";
|
||||
|
||||
export default function TabLayout() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (Platform.OS === "android") {
|
||||
NavigationBar.setBackgroundColorAsync("#121212");
|
||||
@@ -53,7 +53,7 @@ export default function TabLayout() {
|
||||
name="home"
|
||||
options={{
|
||||
headerShown: false,
|
||||
title: "Home",
|
||||
title: t("tabs.home"),
|
||||
tabBarIcon: ({ color, focused }) => (
|
||||
<TabBarIcon
|
||||
name={focused ? "home" : "home-outline"}
|
||||
@@ -66,7 +66,7 @@ export default function TabLayout() {
|
||||
name="search"
|
||||
options={{
|
||||
headerShown: false,
|
||||
title: "Search",
|
||||
title: t("tabs.search"),
|
||||
tabBarIcon: ({ color, focused }) => (
|
||||
<TabBarIcon name={focused ? "search" : "search"} color={color} />
|
||||
),
|
||||
@@ -76,7 +76,7 @@ export default function TabLayout() {
|
||||
name="library"
|
||||
options={{
|
||||
headerShown: false,
|
||||
title: "Library",
|
||||
title: t("tabs.library"),
|
||||
tabBarIcon: ({ color, focused }) => (
|
||||
<TabBarIcon
|
||||
name={focused ? "apps" : "apps-outline"}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Chromecast } from "@/components/Chromecast";
|
||||
import { Feather } from "@expo/vector-icons";
|
||||
import { Stack, useRouter } from "expo-router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform, View } from "react-native";
|
||||
import { TouchableOpacity } from "react-native";
|
||||
|
||||
export default function IndexLayout() {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Stack>
|
||||
<Stack.Screen
|
||||
@@ -13,7 +15,7 @@ export default function IndexLayout() {
|
||||
options={{
|
||||
headerShown: true,
|
||||
headerLargeTitle: true,
|
||||
headerTitle: "Home",
|
||||
headerTitle: t("home.home"),
|
||||
headerBlurEffect: "prominent",
|
||||
headerTransparent: Platform.OS === "ios" ? true : false,
|
||||
headerShadowVisible: false,
|
||||
|
||||
@@ -20,12 +20,15 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useRouter } from "expo-router";
|
||||
import { useAtom } from "jotai";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { RefreshControl, ScrollView, View } from "react-native";
|
||||
|
||||
export default function index() {
|
||||
const router = useRouter();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const [api] = useAtom(apiAtom);
|
||||
const [user] = useAtom(userAtom);
|
||||
|
||||
@@ -216,9 +219,9 @@ export default function index() {
|
||||
if (isConnected === false) {
|
||||
return (
|
||||
<View className="flex flex-col items-center justify-center h-full -mt-6 px-8">
|
||||
<Text className="text-3xl font-bold mb-2">No Internet</Text>
|
||||
<Text className="text-3xl font-bold mb-2">{t("home.noInternet")}</Text>
|
||||
<Text className="text-center opacity-70">
|
||||
No worries, you can still watch{"\n"}downloaded content.
|
||||
{t("home.noInternetMessage")}
|
||||
</Text>
|
||||
<View className="mt-4">
|
||||
<Button
|
||||
@@ -229,7 +232,7 @@ export default function index() {
|
||||
<Ionicons name="arrow-forward" size={20} color="white" />
|
||||
}
|
||||
>
|
||||
Go to downloads
|
||||
{t("home.goToDownloads")}
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
@@ -239,10 +242,8 @@ export default function index() {
|
||||
if (isError)
|
||||
return (
|
||||
<View className="flex flex-col items-center justify-center h-full -mt-6">
|
||||
<Text className="text-3xl font-bold mb-2">Oops!</Text>
|
||||
<Text className="text-center opacity-70">
|
||||
Something went wrong.{"\n"}Please log out and in again.
|
||||
</Text>
|
||||
<Text className="text-3xl font-bold mb-2">{t("home.oops")}</Text>
|
||||
<Text className="text-center opacity-70">{t("home.errorMessage")}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -265,14 +266,14 @@ export default function index() {
|
||||
<LargeMovieCarousel />
|
||||
|
||||
<ScrollingCollectionList
|
||||
title="Continue Watching"
|
||||
title={t("home.continueWatching")}
|
||||
data={data}
|
||||
loading={isLoading}
|
||||
orientation="horizontal"
|
||||
/>
|
||||
|
||||
<ScrollingCollectionList
|
||||
title="Next Up"
|
||||
title={t("home.nextUp")}
|
||||
data={nextUpData}
|
||||
loading={isLoadingNextUp}
|
||||
orientation="horizontal"
|
||||
@@ -283,19 +284,19 @@ export default function index() {
|
||||
))}
|
||||
|
||||
<ScrollingCollectionList
|
||||
title="Recently Added in Movies"
|
||||
title={t("home.recentlyAddedMovies")}
|
||||
data={recentlyAddedInMovies}
|
||||
loading={isLoadingRecentlyAddedMovies}
|
||||
/>
|
||||
|
||||
<ScrollingCollectionList
|
||||
title="Recently Added in TV-Shows"
|
||||
title={t("home.recentlyAddedTVShows")}
|
||||
data={recentlyAddedInTVShows}
|
||||
loading={isLoadingRecentlyAddedTVShows}
|
||||
/>
|
||||
|
||||
<ScrollingCollectionList
|
||||
title="Suggestions"
|
||||
title={t("home.suggestions")}
|
||||
data={suggestions}
|
||||
loading={isLoadingSuggestions}
|
||||
orientation="horizontal"
|
||||
|
||||
@@ -17,6 +17,9 @@ import { useKeepAwake } from "expo-keep-awake";
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
|
||||
import { I18nextProvider, useTranslation } from "react-i18next";
|
||||
import i18n from "@/i18n";
|
||||
import { getLocales } from "expo-localization";
|
||||
|
||||
// Prevent the splash screen from auto-hiding before asset loading is complete.
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
@@ -42,7 +45,9 @@ export default function RootLayout() {
|
||||
|
||||
return (
|
||||
<JotaiProvider>
|
||||
<Layout />
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<Layout />
|
||||
</I18nextProvider>
|
||||
</JotaiProvider>
|
||||
);
|
||||
}
|
||||
@@ -52,6 +57,8 @@ function Layout() {
|
||||
|
||||
useKeepAwake();
|
||||
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
const queryClientRef = useRef<QueryClient>(
|
||||
new QueryClient({
|
||||
defaultOptions: {
|
||||
@@ -75,6 +82,12 @@ function Layout() {
|
||||
);
|
||||
}, [settings]);
|
||||
|
||||
useEffect(() => {
|
||||
i18n.changeLanguage(
|
||||
settings?.preferedLanguage || getLocales()[0].languageCode || "en"
|
||||
);
|
||||
}, [settings]);
|
||||
|
||||
return (
|
||||
<GestureHandlerRootView style={{ flex: 1 }}>
|
||||
<QueryClientProvider client={queryClientRef.current}>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Button } from "@/components/Button";
|
||||
import { Input } from "@/components/common/Input";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { LanguageSwitcher } from "@/components/LanguageSwitcher";
|
||||
import { apiAtom, useJellyfin } from "@/providers/JellyfinProvider";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { AxiosError } from "axios";
|
||||
import { useAtom } from "jotai";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
Alert,
|
||||
KeyboardAvoidingView,
|
||||
@@ -21,6 +23,7 @@ const CredentialsSchema = z.object({
|
||||
});
|
||||
|
||||
const Login: React.FC = () => {
|
||||
const { t, i18n } = useTranslation();
|
||||
const { setServer, login, removeServer } = useJellyfin();
|
||||
const [api] = useAtom(apiAtom);
|
||||
|
||||
@@ -72,7 +75,7 @@ const Login: React.FC = () => {
|
||||
<View className="mb-4">
|
||||
<Text className="text-3xl font-bold mb-2">Streamyfin</Text>
|
||||
<Text className="text-neutral-500 mb-2">
|
||||
Server: {api.basePath}
|
||||
{t("server.server_label", { serverURL: api.basePath })}
|
||||
</Text>
|
||||
<Button
|
||||
color="black"
|
||||
@@ -89,17 +92,17 @@ const Login: React.FC = () => {
|
||||
/>
|
||||
}
|
||||
>
|
||||
Change server
|
||||
{t("server.change_server")}
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
<View className="flex flex-col space-y-2">
|
||||
<Text className="text-2xl font-bold">Log in</Text>
|
||||
<Text className="text-2xl font-bold">{t("login.login")}</Text>
|
||||
<Text className="text-neutral-500">
|
||||
Log in to any user account
|
||||
{t("login.login_subtitle")}
|
||||
</Text>
|
||||
<Input
|
||||
placeholder="Username"
|
||||
placeholder={t("login.username_placeholder")}
|
||||
onChangeText={(text) =>
|
||||
setCredentials({ ...credentials, username: text })
|
||||
}
|
||||
@@ -116,7 +119,7 @@ const Login: React.FC = () => {
|
||||
|
||||
<Input
|
||||
className="mb-2"
|
||||
placeholder="Password"
|
||||
placeholder={t("login.password_placeholder")}
|
||||
onChangeText={(text) =>
|
||||
setCredentials({ ...credentials, password: text })
|
||||
}
|
||||
@@ -139,7 +142,7 @@ const Login: React.FC = () => {
|
||||
loading={loading}
|
||||
className="mt-auto mb-2"
|
||||
>
|
||||
Log in
|
||||
{t("login.login_button")}
|
||||
</Button>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
@@ -158,10 +161,10 @@ const Login: React.FC = () => {
|
||||
<View className="flex flex-col gap-y-2">
|
||||
<Text className="text-3xl font-bold">Streamyfin</Text>
|
||||
<Text className="text-neutral-500">
|
||||
Connect to your Jellyfin server
|
||||
{t("server.connect_to_server")}
|
||||
</Text>
|
||||
<Input
|
||||
placeholder="Server URL"
|
||||
placeholder={t("server.server_url_placeholder")}
|
||||
onChangeText={setServerURL}
|
||||
value={serverURL}
|
||||
keyboardType="url"
|
||||
@@ -170,12 +173,11 @@ const Login: React.FC = () => {
|
||||
textContentType="URL"
|
||||
maxLength={500}
|
||||
/>
|
||||
<Text className="opacity-30">
|
||||
Server URL requires http or https
|
||||
</Text>
|
||||
<Text className="opacity-30">{t("server.server_url_hint")}</Text>
|
||||
<LanguageSwitcher />
|
||||
</View>
|
||||
<Button onPress={() => handleConnect(serverURL)} className="mb-2">
|
||||
Connect
|
||||
{t("server.connect_button")}
|
||||
</Button>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
|
||||
Reference in New Issue
Block a user