From 6a556a457d3b91b74761af905666df5f19520369 Mon Sep 17 00:00:00 2001 From: ameer2468 <33054370+ameer2468@users.noreply.github.com> Date: Wed, 24 Apr 2024 01:21:31 +0300 Subject: [PATCH] [MOB-85] Better headers (#2375) * wip * improve headers * cleanup --- .../src/components/browse/BrowseLocations.tsx | 4 +- .../src/components/browse/BrowseTags.tsx | 4 +- .../src/components/explorer/Explorer.tsx | 34 ++++- .../src/components/explorer/menu/Menu.tsx | 1 - apps/mobile/src/components/header/Header.tsx | 130 ++++++++++++------ apps/mobile/src/components/layout/Fade.tsx | 13 +- .../src/components/layout/ScreenContainer.tsx | 77 ++++++----- .../src/components/locations/LocationItem.tsx | 4 +- .../src/components/overview/Locations.tsx | 4 +- .../components/overview/OverviewSection.tsx | 2 +- .../src/components/reanimated/components.tsx | 4 + apps/mobile/src/components/search/Search.tsx | 4 +- .../components/search/filters/FiltersBar.tsx | 3 - apps/mobile/src/components/tags/GridTag.tsx | 4 +- apps/mobile/src/navigation/SearchStack.tsx | 15 +- .../src/navigation/tabs/BrowseStack.tsx | 42 ++---- .../src/navigation/tabs/NetworkStack.tsx | 6 +- .../src/navigation/tabs/OverviewStack.tsx | 11 +- .../src/navigation/tabs/SettingsStack.tsx | 44 +++--- apps/mobile/src/screens/browse/Browse.tsx | 9 +- apps/mobile/src/screens/browse/Library.tsx | 8 +- apps/mobile/src/screens/browse/Location.tsx | 20 ++- apps/mobile/src/screens/browse/Locations.tsx | 22 ++- apps/mobile/src/screens/browse/Tag.tsx | 20 ++- apps/mobile/src/screens/browse/Tags.tsx | 45 +++--- apps/mobile/src/screens/network/Network.tsx | 6 +- .../src/screens/overview/Categories.tsx | 25 +++- apps/mobile/src/screens/overview/Overview.tsx | 11 +- apps/mobile/src/screens/search/Filters.tsx | 8 +- apps/mobile/src/screens/search/Search.tsx | 4 +- apps/mobile/src/screens/settings/Settings.tsx | 54 ++++---- .../settings/client/AppearanceSettings.tsx | 7 +- .../settings/client/ExtensionsSettings.tsx | 8 +- .../settings/client/GeneralSettings.tsx | 12 +- .../settings/client/LibrarySettings.tsx | 16 ++- .../settings/client/PrivacySettings.tsx | 5 +- .../src/screens/settings/info/About.tsx | 10 +- .../src/screens/settings/info/Debug.tsx | 14 +- .../src/screens/settings/info/Support.tsx | 12 +- .../settings/library/EditLocationSettings.tsx | 10 +- .../library/LibraryGeneralSettings.tsx | 10 +- .../settings/library/NodesSettings.tsx | 7 +- 42 files changed, 462 insertions(+), 287 deletions(-) create mode 100644 apps/mobile/src/components/reanimated/components.tsx diff --git a/apps/mobile/src/components/browse/BrowseLocations.tsx b/apps/mobile/src/components/browse/BrowseLocations.tsx index 6ceadd16c..7fa413581 100644 --- a/apps/mobile/src/components/browse/BrowseLocations.tsx +++ b/apps/mobile/src/components/browse/BrowseLocations.tsx @@ -1,8 +1,8 @@ import { useNavigation } from '@react-navigation/native'; +import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import { DotsThreeOutline, Plus } from 'phosphor-react-native'; import { useRef } from 'react'; import { Text, View } from 'react-native'; -import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import { ModalRef } from '~/components/layout/Modal'; import { tw } from '~/lib/tailwind'; import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack'; @@ -64,7 +64,7 @@ const BrowseLocations = () => { initial: false }) } - onPress={() => navigation.navigate('Location', { id: location.id })} + onPress={() => navigation.navigate('Location', { id: location.id, title: location.name })} /> ))} diff --git a/apps/mobile/src/components/browse/BrowseTags.tsx b/apps/mobile/src/components/browse/BrowseTags.tsx index fa74e98d8..42f5fe7d1 100644 --- a/apps/mobile/src/components/browse/BrowseTags.tsx +++ b/apps/mobile/src/components/browse/BrowseTags.tsx @@ -1,8 +1,8 @@ import { useNavigation } from '@react-navigation/native'; +import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import { DotsThreeOutline, Plus } from 'phosphor-react-native'; import React, { useRef } from 'react'; import { Text, View } from 'react-native'; -import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import { ModalRef } from '~/components/layout/Modal'; import { tw } from '~/lib/tailwind'; import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack'; @@ -57,7 +57,7 @@ const BrowseTags = () => { key={tag.id} tag={tag} onPress={() => - navigation.navigate('Tag', { id: tag.id, color: tag.color! }) + navigation.navigate('Tag', { id: tag.id, color: tag.color!, title: tag.name }) } /> )) diff --git a/apps/mobile/src/components/explorer/Explorer.tsx b/apps/mobile/src/components/explorer/Explorer.tsx index e9ba6ae4d..3a6dbb478 100644 --- a/apps/mobile/src/components/explorer/Explorer.tsx +++ b/apps/mobile/src/components/explorer/Explorer.tsx @@ -1,19 +1,22 @@ import { useNavigation } from '@react-navigation/native'; +import { NativeStackHeaderProps } from '@react-navigation/native-stack'; +import { SearchData, isPath, type ExplorerItem } from '@sd/client'; import { FlashList } from '@shopify/flash-list'; import { UseInfiniteQueryResult } from '@tanstack/react-query'; import { ActivityIndicator, Pressable } from 'react-native'; -import { isPath, SearchData, type ExplorerItem } from '@sd/client'; +import { SharedValue } from 'react-native-reanimated'; import Layout from '~/constants/Layout'; import { tw } from '~/lib/tailwind'; import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack'; import { useExplorerStore } from '~/stores/explorerStore'; import { useActionsModalStore } from '~/stores/modalStore'; - +import { HeaderProps } from '../header/Header'; import ScreenContainer from '../layout/ScreenContainer'; import FileItem from './FileItem'; import FileRow from './FileRow'; import Menu from './menu/Menu'; + type ExplorerProps = { tabHeight?: boolean; items: ExplorerItem[] | null; @@ -21,13 +24,15 @@ type ExplorerProps = { loadMore: () => void; query: UseInfiniteQueryResult>; count?: number; + scrollY?: SharedValue; + route?: NativeStackHeaderProps['route']; + headerKind?: HeaderProps['headerKind']; + hideHeader?: boolean; }; const Explorer = (props: ExplorerProps) => { const navigation = useNavigation['navigation']>(); - const store = useExplorerStore(); - const { modalRef, setData } = useActionsModalStore(); function handlePress(data: ExplorerItem) { @@ -43,8 +48,20 @@ const Explorer = (props: ExplorerProps) => { } return ( - - + + {/* Items */} { )} )} + scrollEventThrottle={1} + onScroll={(e) => { + if (!props.scrollY) return; + props.scrollY.value = e.nativeEvent.contentOffset.y; + }} contentContainerStyle={tw`px-2 py-5`} extraData={store.layoutMode} estimatedItemSize={ diff --git a/apps/mobile/src/components/explorer/menu/Menu.tsx b/apps/mobile/src/components/explorer/menu/Menu.tsx index 76e090d6c..3c149ef2a 100644 --- a/apps/mobile/src/components/explorer/menu/Menu.tsx +++ b/apps/mobile/src/components/explorer/menu/Menu.tsx @@ -9,7 +9,6 @@ import SortByMenu from './SortByMenu'; const Menu = () => { const store = useExplorerStore(); - return ( {store.toggleMenu && ( diff --git a/apps/mobile/src/components/header/Header.tsx b/apps/mobile/src/components/header/Header.tsx index 3fca1ef08..21e4c152a 100644 --- a/apps/mobile/src/components/header/Header.tsx +++ b/apps/mobile/src/components/header/Header.tsx @@ -2,32 +2,42 @@ import { DrawerNavigationHelpers } from '@react-navigation/drawer/lib/typescript import { useNavigation } from '@react-navigation/native'; import { NativeStackHeaderProps } from '@react-navigation/native-stack'; import { ArrowLeft, DotsThreeOutline, List, MagnifyingGlass } from 'phosphor-react-native'; -import { Platform, Pressable, Text, View } from 'react-native'; +import React from 'react'; +import { Platform, Pressable, View } from 'react-native'; +import Animated, { + Extrapolation, + SharedValue, + interpolate, + useAnimatedStyle +} from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { tw, twStyle } from '~/lib/tailwind'; import { getExplorerStore, useExplorerStore } from '~/stores/explorerStore'; import { Icon } from '../icons/Icon'; +import { AnimatedPressable } from '../reanimated/components'; import Search from '../search/Search'; -type HeaderProps = { + +type Props = { title?: string; //title of the page showSearch?: boolean; //show the search button showDrawer?: boolean; //show the drawer button - searchType?: 'explorer' | 'location' | 'categories'; //Temporary + searchType?: 'location' | 'categories' | 'tags'; //Temporary navBack?: boolean; //navigate back to the previous screen headerKind?: 'default' | 'location' | 'tag'; //kind of header route?: never; - routeTitle?: never; + scrollY?: SharedValue; //scrollY of screen }; //you can pass in a routeTitle only if route is passed in -type Props = - | HeaderProps +export type HeaderProps = + | Props | ({ - route: NativeStackHeaderProps; + route: NativeStackHeaderProps['route']; routeTitle?: boolean; - } & Omit); + } & Omit); + // Default header with search bar and button to open drawer export default function Header({ @@ -35,55 +45,94 @@ export default function Header({ searchType, navBack, route, - routeTitle, headerKind = 'default', showDrawer = false, - showSearch = true -}: Props) { + showSearch = false, + scrollY +}: HeaderProps) { const navigation = useNavigation(); const explorerStore = useExplorerStore(); - const routeParams = route?.route.params as any; - const headerHeight = useSafeAreaInsets().top; + const routeParams = route?.params as any; + const headerSafeArea = useSafeAreaInsets(); const isAndroid = Platform.OS === 'android'; + const scrollYTitle = useAnimatedStyle(() => { + return { + fontSize: interpolate(scrollY?.value || 0, [0, 50], [20, 16], Extrapolation.CLAMP) + }; + }); + + const scrollYHeader = useAnimatedStyle(() => { + // this makes sure the header looks good on different devices + const outputRange = [headerSafeArea.top + (isAndroid ? 56 : 40), headerSafeArea.top + (isAndroid ? 44 : 32)]; + return { + height: interpolate( + scrollY?.value || 0, + [0, 50], + outputRange, + Extrapolation.CLAMP + ) + }; + }); + + const scrollYIcon = useAnimatedStyle(() => { + return { + transform: [ + { + scale: interpolate(scrollY?.value || 0, [0, 50], [1, 0.95], Extrapolation.CLAMP) + } + ] + }; + }); + return ( - - + - + {navBack && ( - { - navigation.goBack(); - }} + onPress={() => navigation.goBack()} > - + )} - - + + + + {showDrawer && ( - navigation.openDrawer()}> - - + navigation.openDrawer()} + > + + )} - - {title || (routeTitle && route?.options.title)} - + {title || routeParams?.title} + {showSearch && ( - { navigation.navigate('SearchStack', { @@ -92,11 +141,10 @@ export default function Header({ }} > - + )} {(headerKind === 'location' || headerKind === 'tag') && ( @@ -118,7 +166,7 @@ export default function Header({ {searchType && } - + ); } @@ -128,10 +176,10 @@ interface HeaderSearchTypeProps { const HeaderSearchType = ({ searchType }: HeaderSearchTypeProps) => { switch (searchType) { - case 'explorer': - return 'Explorer'; //TODO case 'location': return ; + case 'tags': + return ; case 'categories': return ; default: @@ -147,11 +195,11 @@ interface HeaderIconKindProps { const HeaderIconKind = ({ headerKind, routeParams }: HeaderIconKindProps) => { switch (headerKind) { case 'location': - return ; + return ; case 'tag': return ( diff --git a/apps/mobile/src/components/layout/Fade.tsx b/apps/mobile/src/components/layout/Fade.tsx index 6eab661d0..17acb3e76 100644 --- a/apps/mobile/src/components/layout/Fade.tsx +++ b/apps/mobile/src/components/layout/Fade.tsx @@ -1,9 +1,7 @@ -import { useRoute } from '@react-navigation/native'; import { DimensionValue, Platform } from 'react-native'; import LinearGradient from 'react-native-linear-gradient'; import { ClassInput } from 'twrnc'; import { tw, twStyle } from '~/lib/tailwind'; -import { useExplorerStore } from '~/stores/explorerStore'; interface Props { children: React.ReactNode; // children of fade @@ -13,7 +11,6 @@ interface Props { orientation?: 'horizontal' | 'vertical'; // orientation of fade fadeSides?: 'left-right' | 'top-bottom'; // which sides to fade screenFade?: boolean; // if true, the fade will consider the bottom tab bar height - noConditions?: boolean; // if true, the fade will be rendered as is bottomFadeStyle?: ClassInput; // tailwind style for bottom fade topFadeStyle?: ClassInput; // tailwind style for top fade } @@ -25,20 +22,15 @@ const Fade = ({ height, bottomFadeStyle, topFadeStyle, - noConditions = false, screenFade = false, fadeSides = 'left-right', orientation = 'horizontal' }: Props) => { - const route = useRoute(); - const { toggleMenu } = useExplorerStore(); const bottomTabBarHeight = Platform.OS === 'ios' ? 80 : 60; const gradientStartEndMap = { 'left-right': { start: { x: 0, y: 0 }, end: { x: 1, y: 0 } }, 'top-bottom': { start: { x: 0, y: 1 }, end: { x: 0, y: 0 } } }; - const menuHeight = 57; // height of the explorer menu - const routesWithMenu = ['Location', 'Search', 'Tag']; // routes that are associated with the explorer return ( <> ; + /* Header properties */ + header?: HeaderProps; + hideHeader?: boolean; // Hide the header } const ScreenContainer = ({ children, style, - topFadeStyle, - bottomFadeStyle, + header, + scrollY, + hideHeader = false, scrollview = true, tabHeight = true, - scrollToBottomOnChange = false + scrollToBottomOnChange = false, }: Props) => { - const ref = useRef(null); + const ref = useRef(null); const bottomTabBarHeight = Platform.OS === 'ios' ? 80 : 60; + const scrollHandler = useAnimatedScrollHandler((e) => { + if (scrollY) scrollY.value = e.contentOffset.y; + }); + + const navigation = useNavigation(); + +// Reset scroll position to 0 whenever the tab blurs or focuses +useEffect(() => { + const resetScroll = () => { + ref.current?.scrollTo({ y: 0, animated: false }); + if (scrollY) scrollY.value = 0; + }; + + // Subscribe to blur and focus events + const unsubscribeBlur = navigation.addListener('blur', resetScroll); + const unsubscribeFocus = navigation.addListener('focus', resetScroll); + + // Cleanup function to remove event listeners + return () => { + unsubscribeBlur(); + unsubscribeFocus(); + }; +}, [navigation, scrollY]); + + return scrollview ? ( - - } + { if (!scrollToBottomOnChange) return; ref.current?.scrollToEnd({ animated: true }); }} + scrollEventThrottle={1} + onScroll={scrollHandler} contentContainerStyle={twStyle('justify-between gap-10 py-6', style)} style={twStyle( 'flex-1 bg-black', @@ -54,21 +80,11 @@ const ScreenContainer = ({ )} > {children} - - + ) : ( - + {!hideHeader &&
} {children} - ); }; diff --git a/apps/mobile/src/components/locations/LocationItem.tsx b/apps/mobile/src/components/locations/LocationItem.tsx index fae5729db..6ff2c5505 100644 --- a/apps/mobile/src/components/locations/LocationItem.tsx +++ b/apps/mobile/src/components/locations/LocationItem.tsx @@ -1,6 +1,6 @@ +import { Location } from '@sd/client'; import { useRef } from 'react'; import { Pressable } from 'react-native'; -import { Location } from '@sd/client'; import { twStyle } from '~/lib/tailwind'; import { ModalRef } from '../layout/Modal'; @@ -23,7 +23,6 @@ export const LocationItem = ({ }: LocationItemProps) => { const modalRef = useRef(null); return ( - <> )} - ); }; diff --git a/apps/mobile/src/components/overview/Locations.tsx b/apps/mobile/src/components/overview/Locations.tsx index 8a53c4dfc..395aa77bb 100644 --- a/apps/mobile/src/components/overview/Locations.tsx +++ b/apps/mobile/src/components/overview/Locations.tsx @@ -1,8 +1,8 @@ import { useNavigation } from '@react-navigation/native'; +import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import React, { useRef } from 'react'; import { Pressable, Text, View } from 'react-native'; import { FlatList } from 'react-native-gesture-handler'; -import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import { tw, twStyle } from '~/lib/tailwind'; import { OverviewStackScreenProps } from '~/navigation/tabs/OverviewStack'; @@ -63,7 +63,7 @@ const Locations = () => { navigation.jumpTo('BrowseStack', { initial: false, screen: 'Location', - params: { id: item.id } + params: { id: item.id, title: item.name } }) } > diff --git a/apps/mobile/src/components/overview/OverviewSection.tsx b/apps/mobile/src/components/overview/OverviewSection.tsx index 126e5d7e0..212b561b2 100644 --- a/apps/mobile/src/components/overview/OverviewSection.tsx +++ b/apps/mobile/src/components/overview/OverviewSection.tsx @@ -14,7 +14,7 @@ const OverviewSection = ({ title, count, children }: Props) => { {title} {count} diff --git a/apps/mobile/src/components/reanimated/components.tsx b/apps/mobile/src/components/reanimated/components.tsx new file mode 100644 index 000000000..a22e5c6ed --- /dev/null +++ b/apps/mobile/src/components/reanimated/components.tsx @@ -0,0 +1,4 @@ +import { Pressable } from 'react-native'; +import Animated from 'react-native-reanimated'; + +export const AnimatedPressable = Animated.createAnimatedComponent(Pressable); diff --git a/apps/mobile/src/components/search/Search.tsx b/apps/mobile/src/components/search/Search.tsx index 3b70fc2c8..6e917b33f 100644 --- a/apps/mobile/src/components/search/Search.tsx +++ b/apps/mobile/src/components/search/Search.tsx @@ -18,12 +18,12 @@ export default function Search({ placeholder }: Props) { }, [searchStore]); return ( searchStore.setSearch(text)} placeholderTextColor={tw.color('text-ink-dull')} - style={tw`w-[90%] text-white`} + style={tw`leading-0 w-[90%] text-sm text-white`} placeholder={placeholder} /> diff --git a/apps/mobile/src/components/search/filters/FiltersBar.tsx b/apps/mobile/src/components/search/filters/FiltersBar.tsx index bf019f3e0..446d04a68 100644 --- a/apps/mobile/src/components/search/filters/FiltersBar.tsx +++ b/apps/mobile/src/components/search/filters/FiltersBar.tsx @@ -11,7 +11,6 @@ import { import { useEffect, useRef } from 'react'; import { FlatList, Pressable, Text, View } from 'react-native'; import { Icon } from '~/components/icons/Icon'; -import Fade from '~/components/layout/Fade'; import { Button } from '~/components/primitive/Button'; import { tw, twStyle } from '~/lib/tailwind'; import { SearchStackScreenProps } from '~/navigation/SearchStack'; @@ -47,7 +46,6 @@ const FiltersBar = () => { - { )} contentContainerStyle={tw`flex-row gap-2 pl-4 pr-4`} /> - ); diff --git a/apps/mobile/src/components/tags/GridTag.tsx b/apps/mobile/src/components/tags/GridTag.tsx index 723831526..20dfe9fb0 100644 --- a/apps/mobile/src/components/tags/GridTag.tsx +++ b/apps/mobile/src/components/tags/GridTag.tsx @@ -1,6 +1,6 @@ +import { Tag } from '@sd/client'; import { DotsThreeOutlineVertical } from 'phosphor-react-native'; import { Pressable, Text, View } from 'react-native'; -import { Tag } from '@sd/client'; import { tw, twStyle } from '~/lib/tailwind'; import Card from '../layout/Card'; @@ -20,7 +20,7 @@ const GridTag = ({ tag, modalRef }: GridTagProps) => { backgroundColor: tag.color! })} /> - modalRef.current?.present()}> + modalRef.current?.present()}> (); export default function SearchStack() { return ( - + { - return
; - } - }} /> ); diff --git a/apps/mobile/src/navigation/tabs/BrowseStack.tsx b/apps/mobile/src/navigation/tabs/BrowseStack.tsx index 6c5091013..cd15858f5 100644 --- a/apps/mobile/src/navigation/tabs/BrowseStack.tsx +++ b/apps/mobile/src/navigation/tabs/BrowseStack.tsx @@ -1,6 +1,5 @@ import { CompositeScreenProps } from '@react-navigation/native'; import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack'; -import Header from '~/components/header/Header'; import BrowseScreen from '~/screens/browse/Browse'; import LibraryScreen from '~/screens/browse/Library'; import LocationScreen from '~/screens/browse/Location'; @@ -14,48 +13,35 @@ const Stack = createNativeStackNavigator(); export default function BrowseStack() { return ( - +
}} /> ( -
- ) - }} - /> + > + {(props) => } +
- }} />
- }} - /> + component={LocationsScreen}/>
- }} - /> + > + {(props) => } +
- }} /> ); @@ -63,9 +49,9 @@ export default function BrowseStack() { export type BrowseStackParamList = { Browse: undefined; - Location: { id: number; path?: string }; + Location: { id: number; path?: string, title?: string | null }; Locations: undefined; - Tag: { id: number; color: string }; + Tag: { id: number; color: string, title?: string | null }; Tags: undefined; Library: undefined; }; diff --git a/apps/mobile/src/navigation/tabs/NetworkStack.tsx b/apps/mobile/src/navigation/tabs/NetworkStack.tsx index 6ef75cfd3..ee3f5ffc5 100644 --- a/apps/mobile/src/navigation/tabs/NetworkStack.tsx +++ b/apps/mobile/src/navigation/tabs/NetworkStack.tsx @@ -1,6 +1,5 @@ import { CompositeScreenProps } from '@react-navigation/native'; import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack'; -import Header from '~/components/header/Header'; import NetworkScreen from '~/screens/network/Network'; import { TabScreenProps } from '../TabNavigator'; @@ -9,11 +8,12 @@ const Stack = createNativeStackNavigator(); export default function NetworkStack() { return ( - +
}} /> ); diff --git a/apps/mobile/src/navigation/tabs/OverviewStack.tsx b/apps/mobile/src/navigation/tabs/OverviewStack.tsx index 3837d8e32..1fcc51982 100644 --- a/apps/mobile/src/navigation/tabs/OverviewStack.tsx +++ b/apps/mobile/src/navigation/tabs/OverviewStack.tsx @@ -1,27 +1,24 @@ import { CompositeScreenProps } from '@react-navigation/native'; import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack'; -import Header from '~/components/header/Header'; import CategoriesScreen from '~/screens/overview/Categories'; import OverviewScreen from '~/screens/overview/Overview'; import { TabScreenProps } from '../TabNavigator'; const Stack = createNativeStackNavigator(); - export default function OverviewStack() { return ( - +
}} />
- }} /> ); diff --git a/apps/mobile/src/navigation/tabs/SettingsStack.tsx b/apps/mobile/src/navigation/tabs/SettingsStack.tsx index 7655a0764..43f27a0d7 100644 --- a/apps/mobile/src/navigation/tabs/SettingsStack.tsx +++ b/apps/mobile/src/navigation/tabs/SettingsStack.tsx @@ -2,7 +2,7 @@ import { CompositeScreenProps } from '@react-navigation/native'; // import KeysSettingsScreen from '~/screens/settings/library/KeysSettings'; import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack'; -import Header from '~/components/header/Header'; +import LocationsScreen from '~/screens/browse/Locations'; import AppearanceSettingsScreen from '~/screens/settings/client/AppearanceSettings'; import ExtensionsSettingsScreen from '~/screens/settings/client/ExtensionsSettings'; import GeneralSettingsScreen from '~/screens/settings/client/GeneralSettings'; @@ -13,7 +13,6 @@ import DebugScreen from '~/screens/settings/info/Debug'; import SupportScreen from '~/screens/settings/info/Support'; import EditLocationSettingsScreen from '~/screens/settings/library/EditLocationSettings'; import LibraryGeneralSettingsScreen from '~/screens/settings/library/LibraryGeneralSettings'; -import LocationSettingsScreen from '~/screens/settings/library/LocationSettings'; import NodesSettingsScreen from '~/screens/settings/library/NodesSettings'; import TagsSettingsScreen from '~/screens/settings/library/TagsSettings'; import SettingsScreen from '~/screens/settings/Settings'; @@ -24,65 +23,59 @@ const Stack = createNativeStackNavigator(); export default function SettingsStack() { return ( - +
}} - /> + > + {(props) => } + {/* Client */}
}} />
}} - /> + > + {(props) => } +
}} />
}} />
}} /> {/* Library */}
}} />
- }} + component={LocationsScreen} />
}} - /> + > + {(props) => } +
}} />
}} /> {/*
}} - /> + />
}} />
}} /> ); diff --git a/apps/mobile/src/screens/browse/Browse.tsx b/apps/mobile/src/screens/browse/Browse.tsx index e7a3b39b2..7eb1d1223 100644 --- a/apps/mobile/src/screens/browse/Browse.tsx +++ b/apps/mobile/src/screens/browse/Browse.tsx @@ -1,11 +1,18 @@ +import { useSharedValue } from 'react-native-reanimated'; import BrowseCategories from '~/components/browse/BrowseCategories'; import BrowseLocations from '~/components/browse/BrowseLocations'; import BrowseTags from '~/components/browse/BrowseTags'; import ScreenContainer from '~/components/layout/ScreenContainer'; export default function BrowseScreen() { + const scrollY = useSharedValue(0); return ( - + diff --git a/apps/mobile/src/screens/browse/Library.tsx b/apps/mobile/src/screens/browse/Library.tsx index 3a192d4f0..dafee18e4 100644 --- a/apps/mobile/src/screens/browse/Library.tsx +++ b/apps/mobile/src/screens/browse/Library.tsx @@ -6,7 +6,13 @@ import { tw } from '~/lib/tailwind'; export default function LibraryScreen() { return ( - + ) { - const { id, path } = route.params; +interface Props { + route: RouteProp; + navigation: NativeStackNavigationProp; +} +export default function LocationScreen({ navigation, route }: Props) { + const { id, path } = route.params; + const scrollY = useSharedValue(0); const location = useLibraryQuery(['locations.get', route.params.id]); useNodes(location.data?.nodes); const locationData = useCache(location.data?.item); @@ -59,5 +67,7 @@ export default function LocationScreen({ navigation, route }: BrowseStackScreenP getExplorerStore().path = path ?? ''; }, [id, path]); - return ; + return ( + + ); } diff --git a/apps/mobile/src/screens/browse/Locations.tsx b/apps/mobile/src/screens/browse/Locations.tsx index d90cf3546..5daca0550 100644 --- a/apps/mobile/src/screens/browse/Locations.tsx +++ b/apps/mobile/src/screens/browse/Locations.tsx @@ -1,9 +1,10 @@ import { useNavigation } from '@react-navigation/native'; +import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import { Plus } from 'phosphor-react-native'; import { useMemo, useRef } from 'react'; -import { FlatList, Pressable, View } from 'react-native'; +import { Pressable, View } from 'react-native'; +import Animated, { useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated'; import { useDebounce } from 'use-debounce'; -import { useCache, useLibraryQuery, useNodes } from '@sd/client'; import Empty from '~/components/layout/Empty'; import { ModalRef } from '~/components/layout/Modal'; import ScreenContainer from '~/components/layout/ScreenContainer'; @@ -19,6 +20,7 @@ interface Props { } export default function LocationsScreen({ viewStyle }: Props) { + const scrollY = useSharedValue(0); const locationsQuery = useLibraryQuery(['locations.list']); useNodes(locationsQuery.data?.nodes); const locations = useCache(locationsQuery.data?.items); @@ -37,8 +39,17 @@ export default function LocationsScreen({ viewStyle }: Props) { BrowseStackScreenProps<'Browse'>['navigation'] & SettingsStackScreenProps<'Settings'>['navigation'] >(); + const scrollHandler = useAnimatedScrollHandler((e) => { + scrollY.value = e.contentOffset.y; + }); return ( - + { @@ -47,12 +58,13 @@ export default function LocationsScreen({ viewStyle }: Props) { > - location.id.toString()} ItemSeparatorComponent={() => } showsVerticalScrollIndicator={false} @@ -71,7 +83,7 @@ export default function LocationsScreen({ viewStyle }: Props) { onPress={() => navigation.navigate('BrowseStack', { screen: 'Location', - params: { id: item.id } + params: { id: item.id, title: item.name } }) } editLocation={() => diff --git a/apps/mobile/src/screens/browse/Tag.tsx b/apps/mobile/src/screens/browse/Tag.tsx index 6f8374565..ca7de30a1 100644 --- a/apps/mobile/src/screens/browse/Tag.tsx +++ b/apps/mobile/src/screens/browse/Tag.tsx @@ -1,11 +1,21 @@ -import { useEffect } from 'react'; import { useCache, useLibraryQuery, useNodes, useObjectsExplorerQuery } from '@sd/client'; +import { useEffect } from 'react'; +import { useSharedValue } from 'react-native-reanimated'; import Explorer from '~/components/explorer/Explorer'; import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack'; -export default function TagScreen({ navigation, route }: BrowseStackScreenProps<'Tag'>) { - const { id } = route.params; +interface Props { + route: BrowseStackScreenProps<'Tag'>['route']; + navigation: BrowseStackScreenProps<'Tag'>['navigation']; +} + +export default function TagScreen({ + navigation, + route, +}: Props) { + const { id } = route.params; + const scrollY = useSharedValue(0); const tag = useLibraryQuery(['tags.get', id]); useNodes(tag.data?.nodes); const tagData = useCache(tag.data?.item); @@ -22,5 +32,7 @@ export default function TagScreen({ navigation, route }: BrowseStackScreenProps< }); }, [tagData?.name, navigation]); - return ; + return ( + + ); } diff --git a/apps/mobile/src/screens/browse/Tags.tsx b/apps/mobile/src/screens/browse/Tags.tsx index 476cc4fef..558a34e20 100644 --- a/apps/mobile/src/screens/browse/Tags.tsx +++ b/apps/mobile/src/screens/browse/Tags.tsx @@ -1,17 +1,18 @@ import { useNavigation } from '@react-navigation/native'; -import { Plus } from 'phosphor-react-native'; -import { useRef } from 'react'; -import { Pressable, View } from 'react-native'; -import { FlatList } from 'react-native-gesture-handler'; import { useCache, useLibraryQuery, useNodes } from '@sd/client'; +import { Plus } from 'phosphor-react-native'; +import { useMemo, useRef } from 'react'; +import { Pressable, View } from 'react-native'; +import Animated from 'react-native-reanimated'; +import { useDebounce } from 'use-debounce'; import Empty from '~/components/layout/Empty'; -import Fade from '~/components/layout/Fade'; import { ModalRef } from '~/components/layout/Modal'; import ScreenContainer from '~/components/layout/ScreenContainer'; import CreateTagModal from '~/components/modal/tag/CreateTagModal'; import { TagItem } from '~/components/tags/TagItem'; import { tw, twStyle } from '~/lib/tailwind'; import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack'; +import { useSearchStore } from '~/stores/searchStore'; interface Props { viewStyle?: 'grid' | 'list'; @@ -20,13 +21,32 @@ interface Props { export default function TagsScreen({ viewStyle = 'list' }: Props) { const navigation = useNavigation['navigation']>(); const modalRef = useRef(null); + const { search } = useSearchStore(); + const tags = useLibraryQuery(['tags.list']); useNodes(tags.data?.nodes); const tagData = useCache(tags.data?.items); + const [debouncedSearch] = useDebounce(search, 200); + const filteredTags = useMemo( + () => + tagData?.filter((tag) => + tag.name?.toLowerCase().includes(debouncedSearch.toLowerCase()) + ) ?? [], + [debouncedSearch, tagData] + ); + return ( - + - - ( - ); diff --git a/apps/mobile/src/screens/network/Network.tsx b/apps/mobile/src/screens/network/Network.tsx index 92e7ed22c..c4377df32 100644 --- a/apps/mobile/src/screens/network/Network.tsx +++ b/apps/mobile/src/screens/network/Network.tsx @@ -6,7 +6,11 @@ import { NetworkStackScreenProps } from '~/navigation/tabs/NetworkStack'; export default function NetworkScreen({ navigation }: NetworkStackScreenProps<'Network'>) { return ( - + Your Local Network diff --git a/apps/mobile/src/screens/overview/Categories.tsx b/apps/mobile/src/screens/overview/Categories.tsx index 97a9cf479..058564d5f 100644 --- a/apps/mobile/src/screens/overview/Categories.tsx +++ b/apps/mobile/src/screens/overview/Categories.tsx @@ -1,7 +1,8 @@ -import { useMemo } from 'react'; -import { FlatList, View } from 'react-native'; -import { useDebounce } from 'use-debounce'; import { useLibraryQuery } from '@sd/client'; +import { useMemo } from 'react'; +import { View } from 'react-native'; +import Animated, { useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated'; +import { useDebounce } from 'use-debounce'; import { IconName } from '~/components/icons/Icon'; import ScreenContainer from '~/components/layout/ScreenContainer'; import CategoryItem from '~/components/overview/CategoryItem'; @@ -9,6 +10,7 @@ import { tw } from '~/lib/tailwind'; import { useSearchStore } from '~/stores/searchStore'; const CategoriesScreen = () => { + const scrollY = useSharedValue(0); const kinds = useLibraryQuery(['library.kindStatistics']); const { search } = useSearchStore(); const [debouncedSearch] = useDebounce(search, 200); @@ -19,13 +21,26 @@ const CategoriesScreen = () => { ) ?? [], [debouncedSearch, kinds] ); + const scrollHandler = useAnimatedScrollHandler((e) => { + scrollY.value = e.contentOffset.y; + }); return ( - - + b.count - a.count).filter((i) => i.kind !== 0)} numColumns={3} + onScroll={scrollHandler} contentContainerStyle={tw`py-6`} keyExtractor={(item) => item.name} + scrollEventThrottle={1} ItemSeparatorComponent={() => } showsVerticalScrollIndicator={false} showsHorizontalScrollIndicator={false} diff --git a/apps/mobile/src/screens/overview/Overview.tsx b/apps/mobile/src/screens/overview/Overview.tsx index 86cde76b0..fbfe86bb8 100644 --- a/apps/mobile/src/screens/overview/Overview.tsx +++ b/apps/mobile/src/screens/overview/Overview.tsx @@ -1,4 +1,5 @@ import { useBridgeQuery, useLibraryQuery } from '@sd/client'; +import { useSharedValue } from 'react-native-reanimated'; import ScreenContainer from '~/components/layout/ScreenContainer'; import Categories from '~/components/overview/Categories'; import Cloud from '~/components/overview/Cloud'; @@ -20,13 +21,19 @@ const EMPTY_STATISTICS = { export default function OverviewScreen() { const { data: node } = useBridgeQuery(['nodeState']); - + const scrollY = useSharedValue(0); const stats = useLibraryQuery(['library.statistics'], { initialData: { ...EMPTY_STATISTICS } }); return ( - + diff --git a/apps/mobile/src/screens/search/Filters.tsx b/apps/mobile/src/screens/search/Filters.tsx index d7cb48798..6812d8d86 100644 --- a/apps/mobile/src/screens/search/Filters.tsx +++ b/apps/mobile/src/screens/search/Filters.tsx @@ -5,7 +5,13 @@ import SaveAdd from '~/components/search/filters/SaveAdd'; const FiltersScreen = () => { return ( <> - + diff --git a/apps/mobile/src/screens/search/Search.tsx b/apps/mobile/src/screens/search/Search.tsx index 56ac99730..baae9ed6b 100644 --- a/apps/mobile/src/screens/search/Search.tsx +++ b/apps/mobile/src/screens/search/Search.tsx @@ -1,8 +1,8 @@ +import { SearchFilterArgs, useObjectsExplorerQuery } from '@sd/client'; import { ArrowLeft, DotsThreeOutline, FunnelSimple, MagnifyingGlass } from 'phosphor-react-native'; import { Suspense, useDeferredValue, useMemo, useState } from 'react'; import { ActivityIndicator, Platform, Pressable, TextInput, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { SearchFilterArgs, useObjectsExplorerQuery } from '@sd/client'; import Explorer from '~/components/explorer/Explorer'; import FiltersBar from '~/components/search/filters/FiltersBar'; import { tw, twStyle } from '~/lib/tailwind'; @@ -124,7 +124,7 @@ const SearchScreen = ({ navigation }: SearchStackScreenProps<'Search'>) => { {/* Content */} }> - + diff --git a/apps/mobile/src/screens/settings/Settings.tsx b/apps/mobile/src/screens/settings/Settings.tsx index 2579eafa8..b6da48c39 100644 --- a/apps/mobile/src/screens/settings/Settings.tsx +++ b/apps/mobile/src/screens/settings/Settings.tsx @@ -1,3 +1,4 @@ +import { DebugState, useDebugState, useDebugStateEnabler } from '@sd/client'; import { Books, FlyingSaucer, @@ -12,9 +13,8 @@ import { ShieldCheck, TagSimple } from 'phosphor-react-native'; -import React from 'react'; -import { Platform, SectionList, Text, TouchableWithoutFeedback, View } from 'react-native'; -import { DebugState, useDebugState, useDebugStateEnabler } from '@sd/client'; +import { Platform, Text, TouchableWithoutFeedback, View } from 'react-native'; +import { useSharedValue } from 'react-native-reanimated'; import ScreenContainer from '~/components/layout/ScreenContainer'; import { SettingsItem } from '~/components/settings/SettingsItem'; import { tw, twStyle } from '~/lib/tailwind'; @@ -129,7 +129,7 @@ function renderSectionHeader({ section }: { section: { title: string } }) { {section.title} @@ -137,28 +137,34 @@ function renderSectionHeader({ section }: { section: { title: string } }) { ); } -export default function SettingsScreen({ navigation }: SettingsStackScreenProps<'Settings'>) { +export default function SettingsScreen({ + navigation, +}: SettingsStackScreenProps<'Settings'>) { const debugState = useDebugState(); - + const scrollY = useSharedValue(0); return ( - - ( - navigation.navigate(item.navigateTo as any)} - rounded={item.rounded} - /> - )} - renderSectionHeader={renderSectionHeader} - ListFooterComponent={} - showsVerticalScrollIndicator={false} - stickySectionHeadersEnabled={false} - initialNumToRender={50} - /> + + {sections(debugState).map((section, i) => ( + + {renderSectionHeader({ section })} + {section.data.map((item, i) => ( + navigation.navigate(item.navigateTo as any)} + rounded={item.rounded} + /> + ))} + + ))} + ); } diff --git a/apps/mobile/src/screens/settings/client/AppearanceSettings.tsx b/apps/mobile/src/screens/settings/client/AppearanceSettings.tsx index 6ac88c2e8..7ca91e265 100644 --- a/apps/mobile/src/screens/settings/client/AppearanceSettings.tsx +++ b/apps/mobile/src/screens/settings/client/AppearanceSettings.tsx @@ -1,7 +1,7 @@ +import { Themes, useThemeStore } from '@sd/client'; import { CheckCircle } from 'phosphor-react-native'; import React, { useState } from 'react'; import { ColorValue, Pressable, ScrollView, Text, View, ViewStyle } from 'react-native'; -import { Themes, useThemeStore } from '@sd/client'; import ScreenContainer from '~/components/layout/ScreenContainer'; import { SettingsTitle } from '~/components/settings/SettingsContainer'; import Colors from '~/constants/style/Colors'; @@ -126,7 +126,10 @@ const AppearanceSettingsScreen = ({ // TODO: Hook this up to the theme store once light theme is fixed. return ( - + Theme ) => { return ( - + TODO ); diff --git a/apps/mobile/src/screens/settings/client/GeneralSettings.tsx b/apps/mobile/src/screens/settings/client/GeneralSettings.tsx index bcfa70823..0c16e5f29 100644 --- a/apps/mobile/src/screens/settings/client/GeneralSettings.tsx +++ b/apps/mobile/src/screens/settings/client/GeneralSettings.tsx @@ -1,14 +1,13 @@ -import { Text, View } from 'react-native'; import { useBridgeQuery, useDebugState } from '@sd/client'; +import { Text, View } from 'react-native'; import Card from '~/components/layout/Card'; import ScreenContainer from '~/components/layout/ScreenContainer'; import { Divider } from '~/components/primitive/Divider'; import { Input } from '~/components/primitive/Input'; import { SettingsTitle } from '~/components/settings/SettingsContainer'; import { tw } from '~/lib/tailwind'; -import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; -const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'GeneralSettings'>) => { +const GeneralSettingsScreen = () => { const { data: node } = useBridgeQuery(['nodeState']); const debugState = useDebugState(); @@ -16,7 +15,12 @@ const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'General if (!node) return null; return ( - + {/* Card Header */} diff --git a/apps/mobile/src/screens/settings/client/LibrarySettings.tsx b/apps/mobile/src/screens/settings/client/LibrarySettings.tsx index 58dda7faf..6ec74aff5 100644 --- a/apps/mobile/src/screens/settings/client/LibrarySettings.tsx +++ b/apps/mobile/src/screens/settings/client/LibrarySettings.tsx @@ -1,8 +1,9 @@ +import { LibraryConfigWrapped, useBridgeQuery, useCache, useNodes } from '@sd/client'; import { DotsThreeOutlineVertical, Pen, Trash } from 'phosphor-react-native'; import React, { useEffect, useRef } from 'react'; -import { Animated, FlatList, Pressable, Text, View } from 'react-native'; +import { Animated, Pressable, Text, View } from 'react-native'; import { Swipeable } from 'react-native-gesture-handler'; -import { LibraryConfigWrapped, useBridgeQuery, useCache, useNodes } from '@sd/client'; +import { default as Reanimated } from 'react-native-reanimated'; import Fade from '~/components/layout/Fade'; import { ModalRef } from '~/components/layout/Modal'; import ScreenContainer from '~/components/layout/ScreenContainer'; @@ -78,7 +79,9 @@ function LibraryItem({ ); } -const LibrarySettingsScreen = ({ navigation }: SettingsStackScreenProps<'LibrarySettings'>) => { +const LibrarySettingsScreen = ({ + navigation, +}: SettingsStackScreenProps<'LibrarySettings'>) => { const libraryList = useBridgeQuery(['library.list']); useNodes(libraryList.data?.nodes); const libraries = useCache(libraryList.data?.items); @@ -101,7 +104,10 @@ const LibrarySettingsScreen = ({ navigation }: SettingsStackScreenProps<'Library const modalRef = useRef(null); return ( - + - item.uuid} diff --git a/apps/mobile/src/screens/settings/client/PrivacySettings.tsx b/apps/mobile/src/screens/settings/client/PrivacySettings.tsx index 486fa38bc..bea89b6f2 100644 --- a/apps/mobile/src/screens/settings/client/PrivacySettings.tsx +++ b/apps/mobile/src/screens/settings/client/PrivacySettings.tsx @@ -5,7 +5,10 @@ import { tw } from '~/lib/tailwind'; const PrivacySettingsScreen = () => { return ( - + TODO ); diff --git a/apps/mobile/src/screens/settings/info/About.tsx b/apps/mobile/src/screens/settings/info/About.tsx index 71550e2e9..17c86531a 100644 --- a/apps/mobile/src/screens/settings/info/About.tsx +++ b/apps/mobile/src/screens/settings/info/About.tsx @@ -1,8 +1,8 @@ +import { useBridgeQuery } from '@sd/client'; import { Image } from 'expo-image'; import { Globe } from 'phosphor-react-native'; import React from 'react'; import { Linking, Platform, Text, View } from 'react-native'; -import { useBridgeQuery } from '@sd/client'; import { DiscordIcon, GitHubIcon } from '~/components/icons/Brands'; import ScreenContainer from '~/components/layout/ScreenContainer'; import { Button } from '~/components/primitive/Button'; @@ -11,14 +11,16 @@ import { tw } from '~/lib/tailwind'; const AboutScreen = () => { const buildInfo = useBridgeQuery(['buildInfo']); - return ( - + diff --git a/apps/mobile/src/screens/settings/info/Debug.tsx b/apps/mobile/src/screens/settings/info/Debug.tsx index 83a5f5973..b6abc957f 100644 --- a/apps/mobile/src/screens/settings/info/Debug.tsx +++ b/apps/mobile/src/screens/settings/info/Debug.tsx @@ -1,7 +1,8 @@ +import { useDebugState, useFeatureFlags } from '@sd/client'; import React from 'react'; -import { Text, View } from 'react-native'; -import { toggleFeatureFlag, useDebugState, useFeatureFlags } from '@sd/client'; +import { Text } from 'react-native'; import Card from '~/components/layout/Card'; +import ScreenContainer from '~/components/layout/ScreenContainer'; import { Button } from '~/components/primitive/Button'; import { tw } from '~/lib/tailwind'; import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; @@ -11,15 +12,16 @@ const DebugScreen = ({ navigation }: SettingsStackScreenProps<'Debug'>) => { const featureFlags = useFeatureFlags(); return ( - - + + Debug - {JSON.stringify(featureFlags)} {JSON.stringify(debugState)} - + ); }; diff --git a/apps/mobile/src/screens/settings/info/Support.tsx b/apps/mobile/src/screens/settings/info/Support.tsx index f1d462161..44d581ecf 100644 --- a/apps/mobile/src/screens/settings/info/Support.tsx +++ b/apps/mobile/src/screens/settings/info/Support.tsx @@ -1,12 +1,18 @@ import React from 'react'; -import { Text, View } from 'react-native'; +import { Text } from 'react-native'; +import ScreenContainer from '~/components/layout/ScreenContainer'; import { tw } from '~/lib/tailwind'; const SupportScreen = () => { return ( - + TODO - + ); }; diff --git a/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx b/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx index f2675ea42..5d32606a5 100644 --- a/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx +++ b/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx @@ -1,10 +1,10 @@ +import { useLibraryMutation, useLibraryQuery, useNormalisedCache, useZodForm } from '@sd/client'; import { useQueryClient } from '@tanstack/react-query'; import { Archive, ArrowsClockwise, Trash } from 'phosphor-react-native'; import { useEffect } from 'react'; import { Controller } from 'react-hook-form'; import { Alert, Text, View } from 'react-native'; import { z } from 'zod'; -import { useLibraryMutation, useLibraryQuery, useNormalisedCache, useZodForm } from '@sd/client'; import ScreenContainer from '~/components/layout/ScreenContainer'; import { AnimatedButton } from '~/components/primitive/Button'; import { Divider } from '~/components/primitive/Divider'; @@ -28,10 +28,9 @@ const schema = z.object({ const EditLocationSettingsScreen = ({ route, - navigation + navigation, }: SettingsStackScreenProps<'EditLocationSettings'>) => { const { id } = route.params; - const queryClient = useQueryClient(); const cache = useNormalisedCache(); @@ -111,7 +110,10 @@ const EditLocationSettingsScreen = ({ const fullRescan = useLibraryMutation('locations.fullRescan'); return ( - + {/* Inputs */} Display Name diff --git a/apps/mobile/src/screens/settings/library/LibraryGeneralSettings.tsx b/apps/mobile/src/screens/settings/library/LibraryGeneralSettings.tsx index e849d0382..8b8a344e1 100644 --- a/apps/mobile/src/screens/settings/library/LibraryGeneralSettings.tsx +++ b/apps/mobile/src/screens/settings/library/LibraryGeneralSettings.tsx @@ -1,8 +1,8 @@ +import { useBridgeMutation, useLibraryContext, useZodForm } from '@sd/client'; import { Controller } from 'react-hook-form'; import { Text, View } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; import { z } from 'zod'; -import { useBridgeMutation, useLibraryContext, useZodForm } from '@sd/client'; import ScreenContainer from '~/components/layout/ScreenContainer'; import DeleteLibraryModal from '~/components/modal/confirmModals/DeleteLibraryModal'; import { Button } from '~/components/primitive/Button'; @@ -14,11 +14,10 @@ import { SettingsTitle } from '~/components/settings/SettingsContainer'; import SettingsToggle from '~/components/settings/SettingsToggle'; import { useAutoForm } from '~/hooks/useAutoForm'; import { tw } from '~/lib/tailwind'; -import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; const schema = z.object({ name: z.string(), description: z.string() }); -const LibraryGeneralSettingsScreen = (_: SettingsStackScreenProps<'LibraryGeneralSettings'>) => { +const LibraryGeneralSettingsScreen = () => { const { library } = useLibraryContext(); const form = useZodForm({ @@ -38,7 +37,10 @@ const LibraryGeneralSettingsScreen = (_: SettingsStackScreenProps<'LibraryGenera }); return ( - + Name + Pairing {[...onlineNodes.entries()].map(([id, node]) => (