From d52f025873c1b45245fe0ef9f9c725c7761dea81 Mon Sep 17 00:00:00 2001 From: Fredrik Burmester Date: Thu, 29 Aug 2024 08:40:55 +0200 Subject: [PATCH] fix: landscape design --- app/(auth)/(tabs)/(home)/downloads.tsx | 12 +++++- app/(auth)/(tabs)/(home)/index.tsx | 14 ++++++- app/(auth)/(tabs)/(home)/settings.tsx | 12 +++++- app/(auth)/(tabs)/(libraries)/[libraryId].tsx | 42 ++++++++++++++----- app/(auth)/(tabs)/(libraries)/index.tsx | 5 +++ app/(auth)/(tabs)/(search)/index.tsx | 6 +++ utils/jellyfin/media/getStreamUrl.ts | 2 +- 7 files changed, 77 insertions(+), 16 deletions(-) diff --git a/app/(auth)/(tabs)/(home)/downloads.tsx b/app/(auth)/(tabs)/(home)/downloads.tsx index 69467450..05765a97 100644 --- a/app/(auth)/(tabs)/(home)/downloads.tsx +++ b/app/(auth)/(tabs)/(home)/downloads.tsx @@ -13,6 +13,7 @@ import { FFmpegKit } from "ffmpeg-kit-react-native"; import { useAtom } from "jotai"; import { useMemo } from "react"; import { ScrollView, TouchableOpacity, View } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; const downloads: React.FC = () => { const [process, setProcess] = useAtom(runningProcesses); @@ -53,6 +54,8 @@ const downloads: React.FC = () => { return formatNumber(timeLeft / 10000); }, [process]); + const insets = useSafeAreaInsets(); + if (isLoading) { return ( @@ -63,7 +66,14 @@ const downloads: React.FC = () => { return ( - + Queue diff --git a/app/(auth)/(tabs)/(home)/index.tsx b/app/(auth)/(tabs)/(home)/index.tsx index 749253f0..72688d26 100644 --- a/app/(auth)/(tabs)/(home)/index.tsx +++ b/app/(auth)/(tabs)/(home)/index.tsx @@ -18,7 +18,8 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useRouter } from "expo-router"; import { useAtom } from "jotai"; import { useCallback, useEffect, useMemo, useState } from "react"; -import { RefreshControl, ScrollView, View } from "react-native"; +import { RefreshControl, SafeAreaView, ScrollView, View } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; type BaseSection = { title: string; @@ -270,6 +271,8 @@ export default function index() { // ); // } + const insets = useSafeAreaInsets(); + if (e1 || e2) return ( @@ -286,6 +289,7 @@ export default function index() { ); + return ( } > - + {sections.map((section, index) => { diff --git a/app/(auth)/(tabs)/(home)/settings.tsx b/app/(auth)/(tabs)/(home)/settings.tsx index ce8d5df5..88667016 100644 --- a/app/(auth)/(tabs)/(home)/settings.tsx +++ b/app/(auth)/(tabs)/(home)/settings.tsx @@ -9,6 +9,7 @@ import { useQuery } from "@tanstack/react-query"; import * as Haptics from "expo-haptics"; import { useAtom } from "jotai"; import { ScrollView, View } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; export default function settings() { const { logout } = useJellyfin(); @@ -23,9 +24,18 @@ export default function settings() { refetchInterval: 1000, }); + const insets = useSafeAreaInsets(); + return ( - + Information diff --git a/app/(auth)/(tabs)/(libraries)/[libraryId].tsx b/app/(auth)/(tabs)/(libraries)/[libraryId].tsx index 3f96282e..327d11b5 100644 --- a/app/(auth)/(tabs)/(libraries)/[libraryId].tsx +++ b/app/(auth)/(tabs)/(libraries)/[libraryId].tsx @@ -9,7 +9,12 @@ import React, { useMemo, useState, } from "react"; -import { FlatList, RefreshControl, View } from "react-native"; +import { + FlatList, + RefreshControl, + useWindowDimensions, + View, +} from "react-native"; import { Text } from "@/components/common/Text"; import { TouchableItemRouter } from "@/components/common/TouchableItemRouter"; @@ -39,6 +44,7 @@ import { } from "@jellyfin/sdk/lib/utils/api"; import { FlashList } from "@shopify/flash-list"; import { Loader } from "@/components/Loader"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; const MemoizedTouchableItemRouter = React.memo(TouchableItemRouter); @@ -49,6 +55,7 @@ const Page = () => { const [api] = useAtom(apiAtom); const [user] = useAtom(userAtom); const navigation = useNavigation(); + const { width: screenWidth } = useWindowDimensions(); const [selectedGenres, setSelectedGenres] = useAtom(genreFilterAtom); const [selectedYears, setSelectedYears] = useAtom(yearFilterAtom); @@ -60,6 +67,14 @@ const Page = () => { ScreenOrientation.Orientation.PORTRAIT_UP ); + const getNumberOfColumns = useCallback(() => { + if (orientation === ScreenOrientation.Orientation.PORTRAIT_UP) return 3; + if (screenWidth < 600) return 5; + if (screenWidth < 960) return 6; + if (screenWidth < 1280) return 7; + return 6; + }, [screenWidth]); + useLayoutEffect(() => { setSortBy([ { @@ -193,18 +208,19 @@ const Page = () => { key={item.Id} style={{ width: "100%", - marginBottom: - orientation === ScreenOrientation.Orientation.PORTRAIT_UP ? 4 : 16, + marginBottom: 4, }} item={item} > { ] ); + const insets = useSafeAreaInsets(); + if (isLoading || isLibraryLoading) return ( @@ -401,9 +419,7 @@ const Page = () => { renderItem={renderItem} keyExtractor={keyExtractor} estimatedItemSize={244} - numColumns={ - orientation === ScreenOrientation.Orientation.PORTRAIT_UP ? 3 : 5 - } + numColumns={getNumberOfColumns()} onEndReached={() => { if (hasNextPage) { fetchNextPage(); @@ -411,7 +427,11 @@ const Page = () => { }} onEndReachedThreshold={1} ListHeaderComponent={ListHeaderComponent} - contentContainerStyle={{ paddingBottom: 24 }} + contentContainerStyle={{ + paddingBottom: 24, + paddingLeft: insets.left, + paddingRight: insets.right, + }} ItemSeparatorComponent={() => ( @@ -76,6 +79,8 @@ export default function index() { paddingTop: 17, paddingHorizontal: settings?.libraryOptions?.display === "row" ? 0 : 17, paddingBottom: 150, + paddingLeft: insets.left, + paddingRight: insets.right, }} data={data} renderItem={({ item }) => } diff --git a/app/(auth)/(tabs)/(search)/index.tsx b/app/(auth)/(tabs)/(search)/index.tsx index 3e9dfd79..5975c9e6 100644 --- a/app/(auth)/(tabs)/(search)/index.tsx +++ b/app/(auth)/(tabs)/(search)/index.tsx @@ -28,6 +28,7 @@ import React, { useState, } from "react"; import { Platform, ScrollView, TouchableOpacity, View } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useDebounce } from "use-debounce"; const exampleSearches = [ @@ -41,6 +42,7 @@ const exampleSearches = [ export default function search() { const params = useLocalSearchParams(); + const insets = useSafeAreaInsets(); const { q, prev } = params as { q: string; prev: Href }; @@ -220,6 +222,10 @@ export default function search() { {Platform.OS === "android" && ( diff --git a/utils/jellyfin/media/getStreamUrl.ts b/utils/jellyfin/media/getStreamUrl.ts index 075d486f..38d9fb2e 100644 --- a/utils/jellyfin/media/getStreamUrl.ts +++ b/utils/jellyfin/media/getStreamUrl.ts @@ -31,7 +31,7 @@ export const getStreamUrl = async ({ subtitleStreamIndex?: number; forceDirectPlay?: boolean; height?: number; - mediaSourceId?: string | null; + mediaSourceId: string | null; }) => { if (!api || !userId || !item?.Id || !mediaSourceId) { return null;