mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-08 18:44:03 +00:00
Revert "[MOB-85] Better headers" (#2376)
Revert "[MOB-85] Better headers (#2375)"
This reverts commit 6a556a457d
.
This commit is contained in:
parent
6a556a457d
commit
e009a0478c
|
@ -1,8 +1,8 @@
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
|
||||||
import { DotsThreeOutline, Plus } from 'phosphor-react-native';
|
import { DotsThreeOutline, Plus } from 'phosphor-react-native';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
|
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
||||||
import { ModalRef } from '~/components/layout/Modal';
|
import { ModalRef } from '~/components/layout/Modal';
|
||||||
import { tw } from '~/lib/tailwind';
|
import { tw } from '~/lib/tailwind';
|
||||||
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
||||||
|
@ -64,7 +64,7 @@ const BrowseLocations = () => {
|
||||||
initial: false
|
initial: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onPress={() => navigation.navigate('Location', { id: location.id, title: location.name })}
|
onPress={() => navigation.navigate('Location', { id: location.id })}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
|
||||||
import { DotsThreeOutline, Plus } from 'phosphor-react-native';
|
import { DotsThreeOutline, Plus } from 'phosphor-react-native';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
|
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
||||||
import { ModalRef } from '~/components/layout/Modal';
|
import { ModalRef } from '~/components/layout/Modal';
|
||||||
import { tw } from '~/lib/tailwind';
|
import { tw } from '~/lib/tailwind';
|
||||||
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
||||||
|
@ -57,7 +57,7 @@ const BrowseTags = () => {
|
||||||
key={tag.id}
|
key={tag.id}
|
||||||
tag={tag}
|
tag={tag}
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
navigation.navigate('Tag', { id: tag.id, color: tag.color!, title: tag.name })
|
navigation.navigate('Tag', { id: tag.id, color: tag.color! })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
|
|
@ -1,22 +1,19 @@
|
||||||
import { useNavigation } from '@react-navigation/native';
|
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 { FlashList } from '@shopify/flash-list';
|
||||||
import { UseInfiniteQueryResult } from '@tanstack/react-query';
|
import { UseInfiniteQueryResult } from '@tanstack/react-query';
|
||||||
import { ActivityIndicator, Pressable } from 'react-native';
|
import { ActivityIndicator, Pressable } from 'react-native';
|
||||||
import { SharedValue } from 'react-native-reanimated';
|
import { isPath, SearchData, type ExplorerItem } from '@sd/client';
|
||||||
import Layout from '~/constants/Layout';
|
import Layout from '~/constants/Layout';
|
||||||
import { tw } from '~/lib/tailwind';
|
import { tw } from '~/lib/tailwind';
|
||||||
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
||||||
import { useExplorerStore } from '~/stores/explorerStore';
|
import { useExplorerStore } from '~/stores/explorerStore';
|
||||||
import { useActionsModalStore } from '~/stores/modalStore';
|
import { useActionsModalStore } from '~/stores/modalStore';
|
||||||
import { HeaderProps } from '../header/Header';
|
|
||||||
import ScreenContainer from '../layout/ScreenContainer';
|
import ScreenContainer from '../layout/ScreenContainer';
|
||||||
import FileItem from './FileItem';
|
import FileItem from './FileItem';
|
||||||
import FileRow from './FileRow';
|
import FileRow from './FileRow';
|
||||||
import Menu from './menu/Menu';
|
import Menu from './menu/Menu';
|
||||||
|
|
||||||
|
|
||||||
type ExplorerProps = {
|
type ExplorerProps = {
|
||||||
tabHeight?: boolean;
|
tabHeight?: boolean;
|
||||||
items: ExplorerItem[] | null;
|
items: ExplorerItem[] | null;
|
||||||
|
@ -24,15 +21,13 @@ type ExplorerProps = {
|
||||||
loadMore: () => void;
|
loadMore: () => void;
|
||||||
query: UseInfiniteQueryResult<SearchData<ExplorerItem>>;
|
query: UseInfiniteQueryResult<SearchData<ExplorerItem>>;
|
||||||
count?: number;
|
count?: number;
|
||||||
scrollY?: SharedValue<number>;
|
|
||||||
route?: NativeStackHeaderProps['route'];
|
|
||||||
headerKind?: HeaderProps['headerKind'];
|
|
||||||
hideHeader?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Explorer = (props: ExplorerProps) => {
|
const Explorer = (props: ExplorerProps) => {
|
||||||
const navigation = useNavigation<BrowseStackScreenProps<'Location'>['navigation']>();
|
const navigation = useNavigation<BrowseStackScreenProps<'Location'>['navigation']>();
|
||||||
|
|
||||||
const store = useExplorerStore();
|
const store = useExplorerStore();
|
||||||
|
|
||||||
const { modalRef, setData } = useActionsModalStore();
|
const { modalRef, setData } = useActionsModalStore();
|
||||||
|
|
||||||
function handlePress(data: ExplorerItem) {
|
function handlePress(data: ExplorerItem) {
|
||||||
|
@ -48,20 +43,8 @@ const Explorer = (props: ExplorerProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer
|
<ScreenContainer tabHeight={props.tabHeight} scrollview={false} style={'gap-0 py-0'}>
|
||||||
hideHeader={props.hideHeader}
|
<Menu />
|
||||||
header={{
|
|
||||||
scrollY: props.scrollY,
|
|
||||||
route: props.route,
|
|
||||||
headerKind: props.headerKind,
|
|
||||||
showSearch: true,
|
|
||||||
navBack: true,
|
|
||||||
}}
|
|
||||||
tabHeight={props.tabHeight}
|
|
||||||
scrollview={false}
|
|
||||||
style={'gap-0 py-0'}
|
|
||||||
>
|
|
||||||
<Menu/>
|
|
||||||
{/* Items */}
|
{/* Items */}
|
||||||
<FlashList
|
<FlashList
|
||||||
key={store.layoutMode}
|
key={store.layoutMode}
|
||||||
|
@ -83,11 +66,6 @@ const Explorer = (props: ExplorerProps) => {
|
||||||
)}
|
)}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)}
|
)}
|
||||||
scrollEventThrottle={1}
|
|
||||||
onScroll={(e) => {
|
|
||||||
if (!props.scrollY) return;
|
|
||||||
props.scrollY.value = e.nativeEvent.contentOffset.y;
|
|
||||||
}}
|
|
||||||
contentContainerStyle={tw`px-2 py-5`}
|
contentContainerStyle={tw`px-2 py-5`}
|
||||||
extraData={store.layoutMode}
|
extraData={store.layoutMode}
|
||||||
estimatedItemSize={
|
estimatedItemSize={
|
||||||
|
|
|
@ -9,6 +9,7 @@ import SortByMenu from './SortByMenu';
|
||||||
|
|
||||||
const Menu = () => {
|
const Menu = () => {
|
||||||
const store = useExplorerStore();
|
const store = useExplorerStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{store.toggleMenu && (
|
{store.toggleMenu && (
|
||||||
|
|
|
@ -2,42 +2,32 @@ import { DrawerNavigationHelpers } from '@react-navigation/drawer/lib/typescript
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { NativeStackHeaderProps } from '@react-navigation/native-stack';
|
import { NativeStackHeaderProps } from '@react-navigation/native-stack';
|
||||||
import { ArrowLeft, DotsThreeOutline, List, MagnifyingGlass } from 'phosphor-react-native';
|
import { ArrowLeft, DotsThreeOutline, List, MagnifyingGlass } from 'phosphor-react-native';
|
||||||
import React from 'react';
|
import { Platform, Pressable, Text, View } from 'react-native';
|
||||||
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 { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import { tw, twStyle } from '~/lib/tailwind';
|
import { tw, twStyle } from '~/lib/tailwind';
|
||||||
import { getExplorerStore, useExplorerStore } from '~/stores/explorerStore';
|
import { getExplorerStore, useExplorerStore } from '~/stores/explorerStore';
|
||||||
|
|
||||||
import { Icon } from '../icons/Icon';
|
import { Icon } from '../icons/Icon';
|
||||||
import { AnimatedPressable } from '../reanimated/components';
|
|
||||||
import Search from '../search/Search';
|
import Search from '../search/Search';
|
||||||
|
|
||||||
|
type HeaderProps = {
|
||||||
type Props = {
|
|
||||||
title?: string; //title of the page
|
title?: string; //title of the page
|
||||||
showSearch?: boolean; //show the search button
|
showSearch?: boolean; //show the search button
|
||||||
showDrawer?: boolean; //show the drawer button
|
showDrawer?: boolean; //show the drawer button
|
||||||
searchType?: 'location' | 'categories' | 'tags'; //Temporary
|
searchType?: 'explorer' | 'location' | 'categories'; //Temporary
|
||||||
navBack?: boolean; //navigate back to the previous screen
|
navBack?: boolean; //navigate back to the previous screen
|
||||||
headerKind?: 'default' | 'location' | 'tag'; //kind of header
|
headerKind?: 'default' | 'location' | 'tag'; //kind of header
|
||||||
route?: never;
|
route?: never;
|
||||||
scrollY?: SharedValue<number>; //scrollY of screen
|
routeTitle?: never;
|
||||||
};
|
};
|
||||||
|
|
||||||
//you can pass in a routeTitle only if route is passed in
|
//you can pass in a routeTitle only if route is passed in
|
||||||
export type HeaderProps =
|
type Props =
|
||||||
| Props
|
| HeaderProps
|
||||||
| ({
|
| ({
|
||||||
route: NativeStackHeaderProps['route'];
|
route: NativeStackHeaderProps;
|
||||||
routeTitle?: boolean;
|
routeTitle?: boolean;
|
||||||
} & Omit<Props, 'route' | 'routeTitle'>);
|
} & Omit<HeaderProps, 'route' | 'routeTitle'>);
|
||||||
|
|
||||||
|
|
||||||
// Default header with search bar and button to open drawer
|
// Default header with search bar and button to open drawer
|
||||||
export default function Header({
|
export default function Header({
|
||||||
|
@ -45,94 +35,55 @@ export default function Header({
|
||||||
searchType,
|
searchType,
|
||||||
navBack,
|
navBack,
|
||||||
route,
|
route,
|
||||||
|
routeTitle,
|
||||||
headerKind = 'default',
|
headerKind = 'default',
|
||||||
showDrawer = false,
|
showDrawer = false,
|
||||||
showSearch = false,
|
showSearch = true
|
||||||
scrollY
|
}: Props) {
|
||||||
}: HeaderProps) {
|
|
||||||
const navigation = useNavigation<DrawerNavigationHelpers>();
|
const navigation = useNavigation<DrawerNavigationHelpers>();
|
||||||
const explorerStore = useExplorerStore();
|
const explorerStore = useExplorerStore();
|
||||||
const routeParams = route?.params as any;
|
const routeParams = route?.route.params as any;
|
||||||
const headerSafeArea = useSafeAreaInsets();
|
const headerHeight = useSafeAreaInsets().top;
|
||||||
const isAndroid = Platform.OS === 'android';
|
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 (
|
return (
|
||||||
<Animated.View
|
<View
|
||||||
style={[
|
style={twStyle('relative h-auto w-full border-b border-app-cardborder bg-app-header', {
|
||||||
twStyle('mt-0 w-full border-b border-app-cardborder bg-app-header', {
|
paddingTop: headerHeight + (isAndroid ? 15 : 0)
|
||||||
paddingTop: headerSafeArea.top + (isAndroid ? 15 : 5),
|
})}
|
||||||
}),
|
|
||||||
scrollYHeader
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<View style={tw`mx-auto h-auto w-full justify-center px-5 pb-6`}>
|
<View style={tw`mx-auto h-auto w-full justify-center px-5 pb-4`}>
|
||||||
<View style={tw`w-full flex-row items-center justify-between`}>
|
<View style={tw`w-full flex-row items-center justify-between`}>
|
||||||
<View style={tw`flex-row items-center`}>
|
<View style={tw`flex-row items-center gap-3`}>
|
||||||
{navBack && (
|
{navBack && (
|
||||||
<AnimatedPressable
|
<Pressable
|
||||||
style={scrollYIcon}
|
|
||||||
hitSlop={24}
|
hitSlop={24}
|
||||||
onPress={() => navigation.goBack()}
|
onPress={() => {
|
||||||
|
navigation.goBack();
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ArrowLeft size={23} color={tw.color('ink')} />
|
<ArrowLeft size={23} color={tw.color('ink')} />
|
||||||
</AnimatedPressable>
|
</Pressable>
|
||||||
)}
|
)}
|
||||||
<View style={tw`flex-row items-center gap-1.5`}>
|
<View style={tw`flex-row items-center gap-2`}>
|
||||||
<Animated.View style={scrollYIcon}>
|
<HeaderIconKind headerKind={headerKind} routeParams={routeParams} />
|
||||||
<HeaderIconKind headerKind={headerKind} routeParams={routeParams} />
|
|
||||||
</Animated.View>
|
|
||||||
{showDrawer && (
|
{showDrawer && (
|
||||||
<AnimatedPressable
|
<Pressable onPress={() => navigation.openDrawer()}>
|
||||||
style={scrollYIcon}
|
<List size={24} color={tw.color('text-zinc-300')} />
|
||||||
onPress={() => navigation.openDrawer()}
|
</Pressable>
|
||||||
>
|
|
||||||
<List style={twStyle({
|
|
||||||
top: isAndroid ? 2 : 0 //fixes the icon alignment on android
|
|
||||||
})} size={24} color={tw.color('text-zinc-300')} />
|
|
||||||
</AnimatedPressable>
|
|
||||||
)}
|
)}
|
||||||
<Animated.Text
|
<Text
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
style={[twStyle('max-w-[200px] text-md font-bold text-ink'), scrollYTitle]}
|
style={tw`max-w-[200px] text-xl font-bold text-white`}
|
||||||
>
|
>
|
||||||
{title || routeParams?.title}
|
{title || (routeTitle && route?.options.title)}
|
||||||
</Animated.Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={tw`relative flex-row items-center gap-3`}>
|
<View style={tw`relative flex-row items-center gap-3`}>
|
||||||
{showSearch && (
|
{showSearch && (
|
||||||
<View style={tw`flex-row items-center gap-2`}>
|
<View style={tw`flex-row items-center gap-2`}>
|
||||||
<AnimatedPressable
|
<Pressable
|
||||||
style={scrollYIcon}
|
|
||||||
hitSlop={24}
|
hitSlop={24}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
navigation.navigate('SearchStack', {
|
navigation.navigate('SearchStack', {
|
||||||
|
@ -141,10 +92,11 @@ export default function Header({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MagnifyingGlass
|
<MagnifyingGlass
|
||||||
|
size={24}
|
||||||
weight="bold"
|
weight="bold"
|
||||||
color={tw.color('text-zinc-300')}
|
color={tw.color('text-zinc-300')}
|
||||||
/>
|
/>
|
||||||
</AnimatedPressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{(headerKind === 'location' || headerKind === 'tag') && (
|
{(headerKind === 'location' || headerKind === 'tag') && (
|
||||||
|
@ -166,7 +118,7 @@ export default function Header({
|
||||||
</View>
|
</View>
|
||||||
{searchType && <HeaderSearchType searchType={searchType} />}
|
{searchType && <HeaderSearchType searchType={searchType} />}
|
||||||
</View>
|
</View>
|
||||||
</Animated.View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,10 +128,10 @@ interface HeaderSearchTypeProps {
|
||||||
|
|
||||||
const HeaderSearchType = ({ searchType }: HeaderSearchTypeProps) => {
|
const HeaderSearchType = ({ searchType }: HeaderSearchTypeProps) => {
|
||||||
switch (searchType) {
|
switch (searchType) {
|
||||||
|
case 'explorer':
|
||||||
|
return 'Explorer'; //TODO
|
||||||
case 'location':
|
case 'location':
|
||||||
return <Search placeholder="Location name..." />;
|
return <Search placeholder="Location name..." />;
|
||||||
case 'tags':
|
|
||||||
return <Search placeholder="Tag name..." />;
|
|
||||||
case 'categories':
|
case 'categories':
|
||||||
return <Search placeholder="Category name..." />;
|
return <Search placeholder="Category name..." />;
|
||||||
default:
|
default:
|
||||||
|
@ -195,11 +147,11 @@ interface HeaderIconKindProps {
|
||||||
const HeaderIconKind = ({ headerKind, routeParams }: HeaderIconKindProps) => {
|
const HeaderIconKind = ({ headerKind, routeParams }: HeaderIconKindProps) => {
|
||||||
switch (headerKind) {
|
switch (headerKind) {
|
||||||
case 'location':
|
case 'location':
|
||||||
return <Icon style={tw`ml-3`} size={30} name="Folder" />;
|
return <Icon size={30} name="Folder" />;
|
||||||
case 'tag':
|
case 'tag':
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={twStyle('ml-3 h-[24px] w-[24px] rounded-full', {
|
style={twStyle('h-[30px] w-[30px] rounded-full', {
|
||||||
backgroundColor: routeParams.color
|
backgroundColor: routeParams.color
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
import { useRoute } from '@react-navigation/native';
|
||||||
import { DimensionValue, Platform } from 'react-native';
|
import { DimensionValue, Platform } from 'react-native';
|
||||||
import LinearGradient from 'react-native-linear-gradient';
|
import LinearGradient from 'react-native-linear-gradient';
|
||||||
import { ClassInput } from 'twrnc';
|
import { ClassInput } from 'twrnc';
|
||||||
import { tw, twStyle } from '~/lib/tailwind';
|
import { tw, twStyle } from '~/lib/tailwind';
|
||||||
|
import { useExplorerStore } from '~/stores/explorerStore';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: React.ReactNode; // children of fade
|
children: React.ReactNode; // children of fade
|
||||||
|
@ -11,6 +13,7 @@ interface Props {
|
||||||
orientation?: 'horizontal' | 'vertical'; // orientation of fade
|
orientation?: 'horizontal' | 'vertical'; // orientation of fade
|
||||||
fadeSides?: 'left-right' | 'top-bottom'; // which sides to fade
|
fadeSides?: 'left-right' | 'top-bottom'; // which sides to fade
|
||||||
screenFade?: boolean; // if true, the fade will consider the bottom tab bar height
|
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
|
bottomFadeStyle?: ClassInput; // tailwind style for bottom fade
|
||||||
topFadeStyle?: ClassInput; // tailwind style for top fade
|
topFadeStyle?: ClassInput; // tailwind style for top fade
|
||||||
}
|
}
|
||||||
|
@ -22,15 +25,20 @@ const Fade = ({
|
||||||
height,
|
height,
|
||||||
bottomFadeStyle,
|
bottomFadeStyle,
|
||||||
topFadeStyle,
|
topFadeStyle,
|
||||||
|
noConditions = false,
|
||||||
screenFade = false,
|
screenFade = false,
|
||||||
fadeSides = 'left-right',
|
fadeSides = 'left-right',
|
||||||
orientation = 'horizontal'
|
orientation = 'horizontal'
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const route = useRoute();
|
||||||
|
const { toggleMenu } = useExplorerStore();
|
||||||
const bottomTabBarHeight = Platform.OS === 'ios' ? 80 : 60;
|
const bottomTabBarHeight = Platform.OS === 'ios' ? 80 : 60;
|
||||||
const gradientStartEndMap = {
|
const gradientStartEndMap = {
|
||||||
'left-right': { start: { x: 0, y: 0 }, end: { x: 1, y: 0 } },
|
'left-right': { start: { x: 0, y: 0 }, end: { x: 1, y: 0 } },
|
||||||
'top-bottom': { start: { x: 0, y: 1 }, end: { x: 0, 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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
|
@ -38,7 +46,10 @@ const Fade = ({
|
||||||
width: orientation === 'vertical' ? height : width,
|
width: orientation === 'vertical' ? height : width,
|
||||||
height: orientation === 'vertical' ? width : height,
|
height: orientation === 'vertical' ? width : height,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top:
|
||||||
|
!noConditions && toggleMenu && routesWithMenu.includes(route.name)
|
||||||
|
? menuHeight
|
||||||
|
: 0,
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
left: fadeSides === 'left-right' ? 0 : undefined,
|
left: fadeSides === 'left-right' ? 0 : undefined,
|
||||||
transform: fadeSides === 'left-right' ? undefined : [{ rotate: '180deg' }],
|
transform: fadeSides === 'left-right' ? undefined : [{ rotate: '180deg' }],
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { ReactNode, useRef } from 'react';
|
||||||
import { ReactNode, useEffect, useRef } from 'react';
|
import { Platform, ScrollView, View } from 'react-native';
|
||||||
import { Platform, View } from 'react-native';
|
|
||||||
import Animated, { SharedValue, useAnimatedScrollHandler } from 'react-native-reanimated';
|
|
||||||
import { AnimatedScrollView } from 'react-native-reanimated/lib/typescript/reanimated2/component/ScrollView';
|
|
||||||
import { ClassInput } from 'twrnc/dist/esm/types';
|
import { ClassInput } from 'twrnc/dist/esm/types';
|
||||||
import { tw, twStyle } from '~/lib/tailwind';
|
import { tw, twStyle } from '~/lib/tailwind';
|
||||||
|
|
||||||
import Header, { HeaderProps } from '../header/Header';
|
import Fade from './Fade';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
@ -19,60 +16,37 @@ interface Props {
|
||||||
/** Styling of both side fades */
|
/** Styling of both side fades */
|
||||||
topFadeStyle?: string;
|
topFadeStyle?: string;
|
||||||
bottomFadeStyle?: string;
|
bottomFadeStyle?: string;
|
||||||
scrollY?: SharedValue<number>;
|
|
||||||
/* Header properties */
|
|
||||||
header?: HeaderProps;
|
|
||||||
hideHeader?: boolean; // Hide the header
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ScreenContainer = ({
|
const ScreenContainer = ({
|
||||||
children,
|
children,
|
||||||
style,
|
style,
|
||||||
header,
|
topFadeStyle,
|
||||||
scrollY,
|
bottomFadeStyle,
|
||||||
hideHeader = false,
|
|
||||||
scrollview = true,
|
scrollview = true,
|
||||||
tabHeight = true,
|
tabHeight = true,
|
||||||
scrollToBottomOnChange = false,
|
scrollToBottomOnChange = false
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const ref = useRef<AnimatedScrollView>(null);
|
const ref = useRef<ScrollView>(null);
|
||||||
const bottomTabBarHeight = Platform.OS === 'ios' ? 80 : 60;
|
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 ? (
|
return scrollview ? (
|
||||||
<View style={tw`relative flex-1`}>
|
<View style={tw`relative flex-1`}>
|
||||||
{!hideHeader && <Header {...header} scrollY={scrollY} />}
|
<Fade
|
||||||
<Animated.ScrollView
|
topFadeStyle={topFadeStyle}
|
||||||
|
bottomFadeStyle={bottomFadeStyle}
|
||||||
|
screenFade
|
||||||
|
fadeSides="top-bottom"
|
||||||
|
orientation="vertical"
|
||||||
|
color="black"
|
||||||
|
width={30}
|
||||||
|
height="100%"
|
||||||
|
>
|
||||||
|
<ScrollView
|
||||||
ref={ref}
|
ref={ref}
|
||||||
onContentSizeChange={() => {
|
onContentSizeChange={() => {
|
||||||
if (!scrollToBottomOnChange) return;
|
if (!scrollToBottomOnChange) return;
|
||||||
ref.current?.scrollToEnd({ animated: true });
|
ref.current?.scrollToEnd({ animated: true });
|
||||||
}}
|
}}
|
||||||
scrollEventThrottle={1}
|
|
||||||
onScroll={scrollHandler}
|
|
||||||
contentContainerStyle={twStyle('justify-between gap-10 py-6', style)}
|
contentContainerStyle={twStyle('justify-between gap-10 py-6', style)}
|
||||||
style={twStyle(
|
style={twStyle(
|
||||||
'flex-1 bg-black',
|
'flex-1 bg-black',
|
||||||
|
@ -80,11 +54,21 @@ useEffect(() => {
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Animated.ScrollView>
|
</ScrollView>
|
||||||
|
</Fade>
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<View style={tw`relative flex-1`}>
|
<View style={tw`relative flex-1`}>
|
||||||
{!hideHeader && <Header {...header} />}
|
<Fade
|
||||||
|
topFadeStyle={topFadeStyle}
|
||||||
|
bottomFadeStyle={bottomFadeStyle}
|
||||||
|
screenFade
|
||||||
|
fadeSides="top-bottom"
|
||||||
|
orientation="vertical"
|
||||||
|
color="black"
|
||||||
|
width={30}
|
||||||
|
height="100%"
|
||||||
|
>
|
||||||
<View
|
<View
|
||||||
style={twStyle(
|
style={twStyle(
|
||||||
'flex-1 justify-between gap-10 bg-black py-6',
|
'flex-1 justify-between gap-10 bg-black py-6',
|
||||||
|
@ -94,6 +78,7 @@ useEffect(() => {
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</View>
|
</View>
|
||||||
|
</Fade>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Location } from '@sd/client';
|
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { Pressable } from 'react-native';
|
import { Pressable } from 'react-native';
|
||||||
|
import { Location } from '@sd/client';
|
||||||
import { twStyle } from '~/lib/tailwind';
|
import { twStyle } from '~/lib/tailwind';
|
||||||
|
|
||||||
import { ModalRef } from '../layout/Modal';
|
import { ModalRef } from '../layout/Modal';
|
||||||
|
@ -23,6 +23,7 @@ export const LocationItem = ({
|
||||||
}: LocationItemProps) => {
|
}: LocationItemProps) => {
|
||||||
const modalRef = useRef<ModalRef>(null);
|
const modalRef = useRef<ModalRef>(null);
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<Pressable
|
<Pressable
|
||||||
style={twStyle(viewStyle === 'grid' ? `w-[31.5%]` : `flex-1`)}
|
style={twStyle(viewStyle === 'grid' ? `w-[31.5%]` : `flex-1`)}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
@ -43,5 +44,6 @@ export const LocationItem = ({
|
||||||
<ListLocation location={location} />
|
<ListLocation location={location} />
|
||||||
)}
|
)}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { Pressable, Text, View } from 'react-native';
|
import { Pressable, Text, View } from 'react-native';
|
||||||
import { FlatList } from 'react-native-gesture-handler';
|
import { FlatList } from 'react-native-gesture-handler';
|
||||||
|
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
||||||
import { tw, twStyle } from '~/lib/tailwind';
|
import { tw, twStyle } from '~/lib/tailwind';
|
||||||
import { OverviewStackScreenProps } from '~/navigation/tabs/OverviewStack';
|
import { OverviewStackScreenProps } from '~/navigation/tabs/OverviewStack';
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ const Locations = () => {
|
||||||
navigation.jumpTo('BrowseStack', {
|
navigation.jumpTo('BrowseStack', {
|
||||||
initial: false,
|
initial: false,
|
||||||
screen: 'Location',
|
screen: 'Location',
|
||||||
params: { id: item.id, title: item.name }
|
params: { id: item.id }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
@ -14,7 +14,7 @@ const OverviewSection = ({ title, count, children }: Props) => {
|
||||||
<View style={tw`flex-row items-center gap-3 px-6 pb-3`}>
|
<View style={tw`flex-row items-center gap-3 px-6 pb-3`}>
|
||||||
<Text style={tw`text-lg font-bold text-white`}>{title}</Text>
|
<Text style={tw`text-lg font-bold text-white`}>{title}</Text>
|
||||||
<View
|
<View
|
||||||
style={tw`flex h-[24px] w-[24px] items-center justify-center rounded-full border border-app-button px-1`}
|
style={tw`flex h-[24px] w-[24px] items-center justify-center rounded-full border border-app-button/40 px-1`}
|
||||||
>
|
>
|
||||||
<Text style={tw`text-xs text-ink`}>{count}</Text>
|
<Text style={tw`text-xs text-ink`}>{count}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
import { Pressable } from 'react-native';
|
|
||||||
import Animated from 'react-native-reanimated';
|
|
||||||
|
|
||||||
export const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
|
|
|
@ -18,12 +18,12 @@ export default function Search({ placeholder }: Props) {
|
||||||
}, [searchStore]);
|
}, [searchStore]);
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={tw`mt-3 flex h-auto w-full flex-row items-center justify-between rounded-md border border-app-inputborder bg-app-input px-3 py-2 shadow-sm`}
|
style={tw`mt-4 flex h-11 w-full flex-row items-center justify-between rounded-md border border-app-inputborder bg-app-input px-3 shadow-sm`}
|
||||||
>
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
onChangeText={(text) => searchStore.setSearch(text)}
|
onChangeText={(text) => searchStore.setSearch(text)}
|
||||||
placeholderTextColor={tw.color('text-ink-dull')}
|
placeholderTextColor={tw.color('text-ink-dull')}
|
||||||
style={tw`leading-0 w-[90%] text-sm text-white`}
|
style={tw`w-[90%] text-white`}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<MagnifyingGlass size={20} weight="bold" color={tw.color('text-ink-dull')} />
|
<MagnifyingGlass size={20} weight="bold" color={tw.color('text-ink-dull')} />
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { FlatList, Pressable, Text, View } from 'react-native';
|
import { FlatList, Pressable, Text, View } from 'react-native';
|
||||||
import { Icon } from '~/components/icons/Icon';
|
import { Icon } from '~/components/icons/Icon';
|
||||||
|
import Fade from '~/components/layout/Fade';
|
||||||
import { Button } from '~/components/primitive/Button';
|
import { Button } from '~/components/primitive/Button';
|
||||||
import { tw, twStyle } from '~/lib/tailwind';
|
import { tw, twStyle } from '~/lib/tailwind';
|
||||||
import { SearchStackScreenProps } from '~/navigation/SearchStack';
|
import { SearchStackScreenProps } from '~/navigation/SearchStack';
|
||||||
|
@ -46,6 +47,7 @@ const FiltersBar = () => {
|
||||||
<Plus weight="bold" size={20} color={tw.color('text-ink-dull')} />
|
<Plus weight="bold" size={20} color={tw.color('text-ink-dull')} />
|
||||||
</Button>
|
</Button>
|
||||||
<View style={tw`relative flex-1`}>
|
<View style={tw`relative flex-1`}>
|
||||||
|
<Fade noConditions height={'100%'} width={30} color="app-header">
|
||||||
<FlatList
|
<FlatList
|
||||||
ref={flatListRef}
|
ref={flatListRef}
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
|
@ -58,6 +60,7 @@ const FiltersBar = () => {
|
||||||
)}
|
)}
|
||||||
contentContainerStyle={tw`flex-row gap-2 pl-4 pr-4`}
|
contentContainerStyle={tw`flex-row gap-2 pl-4 pr-4`}
|
||||||
/>
|
/>
|
||||||
|
</Fade>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Tag } from '@sd/client';
|
|
||||||
import { DotsThreeOutlineVertical } from 'phosphor-react-native';
|
import { DotsThreeOutlineVertical } from 'phosphor-react-native';
|
||||||
import { Pressable, Text, View } from 'react-native';
|
import { Pressable, Text, View } from 'react-native';
|
||||||
|
import { Tag } from '@sd/client';
|
||||||
import { tw, twStyle } from '~/lib/tailwind';
|
import { tw, twStyle } from '~/lib/tailwind';
|
||||||
|
|
||||||
import Card from '../layout/Card';
|
import Card from '../layout/Card';
|
||||||
|
@ -20,7 +20,7 @@ const GridTag = ({ tag, modalRef }: GridTagProps) => {
|
||||||
backgroundColor: tag.color!
|
backgroundColor: tag.color!
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Pressable hitSlop={12} onPress={() => modalRef.current?.present()}>
|
<Pressable hitSlop={24} onPress={() => modalRef.current?.present()}>
|
||||||
<DotsThreeOutlineVertical
|
<DotsThreeOutlineVertical
|
||||||
weight="fill"
|
weight="fill"
|
||||||
size={20}
|
size={20}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Header from '~/components/header/Header';
|
||||||
import FiltersScreen from '~/screens/search/Filters';
|
import FiltersScreen from '~/screens/search/Filters';
|
||||||
import SearchScreen from '~/screens/search/Search';
|
import SearchScreen from '~/screens/search/Search';
|
||||||
|
|
||||||
|
@ -7,18 +8,22 @@ const Stack = createNativeStackNavigator<SearchStackParamList>();
|
||||||
|
|
||||||
export default function SearchStack() {
|
export default function SearchStack() {
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Stack.Navigator initialRouteName="Search">
|
||||||
screenOptions={{
|
|
||||||
headerShown: false
|
|
||||||
}}
|
|
||||||
initialRouteName="Search">
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Search"
|
name="Search"
|
||||||
component={SearchScreen}
|
component={SearchScreen}
|
||||||
|
options={{
|
||||||
|
headerShown: false
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Filters"
|
name="Filters"
|
||||||
component={FiltersScreen}
|
component={FiltersScreen}
|
||||||
|
options={{
|
||||||
|
header: () => {
|
||||||
|
return <Header navBack showSearch={false} title="Search filters" />;
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { CompositeScreenProps } from '@react-navigation/native';
|
import { CompositeScreenProps } from '@react-navigation/native';
|
||||||
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||||
|
import Header from '~/components/header/Header';
|
||||||
import BrowseScreen from '~/screens/browse/Browse';
|
import BrowseScreen from '~/screens/browse/Browse';
|
||||||
import LibraryScreen from '~/screens/browse/Library';
|
import LibraryScreen from '~/screens/browse/Library';
|
||||||
import LocationScreen from '~/screens/browse/Location';
|
import LocationScreen from '~/screens/browse/Location';
|
||||||
|
@ -13,35 +14,48 @@ const Stack = createNativeStackNavigator<BrowseStackParamList>();
|
||||||
|
|
||||||
export default function BrowseStack() {
|
export default function BrowseStack() {
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Stack.Navigator initialRouteName="Browse">
|
||||||
screenOptions={{
|
|
||||||
headerShown: false
|
|
||||||
}}
|
|
||||||
initialRouteName="Browse">
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Browse"
|
name="Browse"
|
||||||
component={BrowseScreen}
|
component={BrowseScreen}
|
||||||
|
options={{ header: () => <Header showDrawer title="Browse" /> }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Location"
|
name="Location"
|
||||||
>
|
component={LocationScreen}
|
||||||
{(props) => <LocationScreen {...props}/>}
|
options={{
|
||||||
</Stack.Screen>
|
header: (route) => (
|
||||||
|
<Header route={route} headerKind="location" routeTitle navBack />
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Tags"
|
name="Tags"
|
||||||
component={TagsScreen}
|
component={TagsScreen}
|
||||||
|
options={{
|
||||||
|
header: () => <Header navBack title="Tags" />
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Locations"
|
name="Locations"
|
||||||
component={LocationsScreen}/>
|
component={LocationsScreen}
|
||||||
|
options={{
|
||||||
|
header: () => <Header navBack searchType="location" title="Locations" />
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Tag"
|
name="Tag"
|
||||||
>
|
component={TagScreen}
|
||||||
{(props) => <TagScreen {...props} />}
|
options={{
|
||||||
</Stack.Screen>
|
header: (route) => <Header navBack routeTitle route={route} headerKind="tag" />
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Library"
|
name="Library"
|
||||||
component={LibraryScreen}
|
component={LibraryScreen}
|
||||||
|
options={{
|
||||||
|
header: () => <Header navBack title="Library" />
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
);
|
);
|
||||||
|
@ -49,9 +63,9 @@ export default function BrowseStack() {
|
||||||
|
|
||||||
export type BrowseStackParamList = {
|
export type BrowseStackParamList = {
|
||||||
Browse: undefined;
|
Browse: undefined;
|
||||||
Location: { id: number; path?: string, title?: string | null };
|
Location: { id: number; path?: string };
|
||||||
Locations: undefined;
|
Locations: undefined;
|
||||||
Tag: { id: number; color: string, title?: string | null };
|
Tag: { id: number; color: string };
|
||||||
Tags: undefined;
|
Tags: undefined;
|
||||||
Library: undefined;
|
Library: undefined;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { CompositeScreenProps } from '@react-navigation/native';
|
import { CompositeScreenProps } from '@react-navigation/native';
|
||||||
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||||
|
import Header from '~/components/header/Header';
|
||||||
import NetworkScreen from '~/screens/network/Network';
|
import NetworkScreen from '~/screens/network/Network';
|
||||||
|
|
||||||
import { TabScreenProps } from '../TabNavigator';
|
import { TabScreenProps } from '../TabNavigator';
|
||||||
|
@ -8,12 +9,11 @@ const Stack = createNativeStackNavigator<NetworkStackParamList>();
|
||||||
|
|
||||||
export default function NetworkStack() {
|
export default function NetworkStack() {
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator screenOptions={{
|
<Stack.Navigator initialRouteName="Network">
|
||||||
headerShown: false
|
|
||||||
}} initialRouteName="Network">
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Network"
|
name="Network"
|
||||||
component={NetworkScreen}
|
component={NetworkScreen}
|
||||||
|
options={{ header: () => <Header showDrawer title="Network" /> }}
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,24 +1,27 @@
|
||||||
import { CompositeScreenProps } from '@react-navigation/native';
|
import { CompositeScreenProps } from '@react-navigation/native';
|
||||||
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||||
|
import Header from '~/components/header/Header';
|
||||||
import CategoriesScreen from '~/screens/overview/Categories';
|
import CategoriesScreen from '~/screens/overview/Categories';
|
||||||
import OverviewScreen from '~/screens/overview/Overview';
|
import OverviewScreen from '~/screens/overview/Overview';
|
||||||
|
|
||||||
import { TabScreenProps } from '../TabNavigator';
|
import { TabScreenProps } from '../TabNavigator';
|
||||||
|
|
||||||
const Stack = createNativeStackNavigator<OverviewStackParamList>();
|
const Stack = createNativeStackNavigator<OverviewStackParamList>();
|
||||||
|
|
||||||
export default function OverviewStack() {
|
export default function OverviewStack() {
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Stack.Navigator initialRouteName="Overview">
|
||||||
screenOptions={{
|
|
||||||
headerShown: false
|
|
||||||
}}>
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Overview"
|
name="Overview"
|
||||||
component={OverviewScreen}
|
component={OverviewScreen}
|
||||||
|
options={{ header: () => <Header showDrawer title="Overview" /> }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Categories"
|
name="Categories"
|
||||||
component={CategoriesScreen}
|
component={CategoriesScreen}
|
||||||
|
options={{
|
||||||
|
header: () => <Header searchType="categories" navBack title="Categories" />
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { CompositeScreenProps } from '@react-navigation/native';
|
||||||
// import KeysSettingsScreen from '~/screens/settings/library/KeysSettings';
|
// import KeysSettingsScreen from '~/screens/settings/library/KeysSettings';
|
||||||
|
|
||||||
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||||
import LocationsScreen from '~/screens/browse/Locations';
|
import Header from '~/components/header/Header';
|
||||||
import AppearanceSettingsScreen from '~/screens/settings/client/AppearanceSettings';
|
import AppearanceSettingsScreen from '~/screens/settings/client/AppearanceSettings';
|
||||||
import ExtensionsSettingsScreen from '~/screens/settings/client/ExtensionsSettings';
|
import ExtensionsSettingsScreen from '~/screens/settings/client/ExtensionsSettings';
|
||||||
import GeneralSettingsScreen from '~/screens/settings/client/GeneralSettings';
|
import GeneralSettingsScreen from '~/screens/settings/client/GeneralSettings';
|
||||||
|
@ -13,6 +13,7 @@ import DebugScreen from '~/screens/settings/info/Debug';
|
||||||
import SupportScreen from '~/screens/settings/info/Support';
|
import SupportScreen from '~/screens/settings/info/Support';
|
||||||
import EditLocationSettingsScreen from '~/screens/settings/library/EditLocationSettings';
|
import EditLocationSettingsScreen from '~/screens/settings/library/EditLocationSettings';
|
||||||
import LibraryGeneralSettingsScreen from '~/screens/settings/library/LibraryGeneralSettings';
|
import LibraryGeneralSettingsScreen from '~/screens/settings/library/LibraryGeneralSettings';
|
||||||
|
import LocationSettingsScreen from '~/screens/settings/library/LocationSettings';
|
||||||
import NodesSettingsScreen from '~/screens/settings/library/NodesSettings';
|
import NodesSettingsScreen from '~/screens/settings/library/NodesSettings';
|
||||||
import TagsSettingsScreen from '~/screens/settings/library/TagsSettings';
|
import TagsSettingsScreen from '~/screens/settings/library/TagsSettings';
|
||||||
import SettingsScreen from '~/screens/settings/Settings';
|
import SettingsScreen from '~/screens/settings/Settings';
|
||||||
|
@ -23,59 +24,65 @@ const Stack = createNativeStackNavigator<SettingsStackParamList>();
|
||||||
|
|
||||||
export default function SettingsStack() {
|
export default function SettingsStack() {
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Stack.Navigator initialRouteName="Settings">
|
||||||
screenOptions={{
|
|
||||||
headerShown: false
|
|
||||||
}}
|
|
||||||
initialRouteName="Settings">
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Settings"
|
name="Settings"
|
||||||
>
|
component={SettingsScreen}
|
||||||
{(props) => <SettingsScreen {...props}/>}
|
options={{ header: () => <Header showDrawer title="Settings" /> }}
|
||||||
</Stack.Screen>
|
/>
|
||||||
{/* Client */}
|
{/* Client */}
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="GeneralSettings"
|
name="GeneralSettings"
|
||||||
component={GeneralSettingsScreen}
|
component={GeneralSettingsScreen}
|
||||||
|
options={{ header: () => <Header navBack title="General" /> }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="LibrarySettings"
|
name="LibrarySettings"
|
||||||
>
|
component={LibrarySettingsScreen}
|
||||||
{(props) => <LibrarySettingsScreen {...props} />}
|
options={{ header: () => <Header navBack title="Libraries" /> }}
|
||||||
</Stack.Screen>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="AppearanceSettings"
|
name="AppearanceSettings"
|
||||||
component={AppearanceSettingsScreen}
|
component={AppearanceSettingsScreen}
|
||||||
|
options={{ header: () => <Header navBack title="Appearance" /> }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="PrivacySettings"
|
name="PrivacySettings"
|
||||||
component={PrivacySettingsScreen}
|
component={PrivacySettingsScreen}
|
||||||
|
options={{ header: () => <Header navBack title="Privacy" /> }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="ExtensionsSettings"
|
name="ExtensionsSettings"
|
||||||
component={ExtensionsSettingsScreen}
|
component={ExtensionsSettingsScreen}
|
||||||
|
options={{ header: () => <Header navBack title="Extensions" /> }}
|
||||||
/>
|
/>
|
||||||
{/* Library */}
|
{/* Library */}
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="LibraryGeneralSettings"
|
name="LibraryGeneralSettings"
|
||||||
component={LibraryGeneralSettingsScreen}
|
component={LibraryGeneralSettingsScreen}
|
||||||
|
options={{ header: () => <Header navBack title="Library Settings" /> }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="LocationSettings"
|
name="LocationSettings"
|
||||||
component={LocationsScreen}
|
component={LocationSettingsScreen}
|
||||||
|
options={{
|
||||||
|
header: () => <Header searchType="location" navBack title="Locations" />
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="EditLocationSettings"
|
name="EditLocationSettings"
|
||||||
>
|
component={EditLocationSettingsScreen}
|
||||||
{(props) => <EditLocationSettingsScreen {...props} />}
|
options={{ header: () => <Header navBack title="Edit Location" /> }}
|
||||||
</Stack.Screen>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="NodesSettings"
|
name="NodesSettings"
|
||||||
component={NodesSettingsScreen}
|
component={NodesSettingsScreen}
|
||||||
|
options={{ header: () => <Header navBack title="Nodes" /> }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="TagsSettings"
|
name="TagsSettings"
|
||||||
component={TagsSettingsScreen}
|
component={TagsSettingsScreen}
|
||||||
|
options={{ header: () => <Header navBack title="Tags" /> }}
|
||||||
/>
|
/>
|
||||||
{/* <Stack.Screen
|
{/* <Stack.Screen
|
||||||
name="KeysSettings"
|
name="KeysSettings"
|
||||||
|
@ -86,14 +93,17 @@ export default function SettingsStack() {
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="About"
|
name="About"
|
||||||
component={AboutScreen}
|
component={AboutScreen}
|
||||||
/>
|
options={{ header: () => <Header navBack title="About" /> }}
|
||||||
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Support"
|
name="Support"
|
||||||
component={SupportScreen}
|
component={SupportScreen}
|
||||||
|
options={{ header: () => <Header navBack title="Support" /> }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Debug"
|
name="Debug"
|
||||||
component={DebugScreen}
|
component={DebugScreen}
|
||||||
|
options={{ header: () => <Header navBack title="Debug" /> }}
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,18 +1,11 @@
|
||||||
import { useSharedValue } from 'react-native-reanimated';
|
|
||||||
import BrowseCategories from '~/components/browse/BrowseCategories';
|
import BrowseCategories from '~/components/browse/BrowseCategories';
|
||||||
import BrowseLocations from '~/components/browse/BrowseLocations';
|
import BrowseLocations from '~/components/browse/BrowseLocations';
|
||||||
import BrowseTags from '~/components/browse/BrowseTags';
|
import BrowseTags from '~/components/browse/BrowseTags';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
|
|
||||||
export default function BrowseScreen() {
|
export default function BrowseScreen() {
|
||||||
const scrollY = useSharedValue(0);
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer>
|
||||||
scrollY: scrollY,
|
|
||||||
showSearch: true,
|
|
||||||
showDrawer: true,
|
|
||||||
title: 'Browse',
|
|
||||||
}}>
|
|
||||||
<BrowseCategories />
|
<BrowseCategories />
|
||||||
<BrowseLocations />
|
<BrowseLocations />
|
||||||
<BrowseTags />
|
<BrowseTags />
|
||||||
|
|
|
@ -6,13 +6,7 @@ import { tw } from '~/lib/tailwind';
|
||||||
|
|
||||||
export default function LibraryScreen() {
|
export default function LibraryScreen() {
|
||||||
return (
|
return (
|
||||||
<ScreenContainer
|
<ScreenContainer style={tw`px-6 py-0`} scrollview={false}>
|
||||||
header={{
|
|
||||||
title: 'Library',
|
|
||||||
navBack: true,
|
|
||||||
showSearch: true,
|
|
||||||
}}
|
|
||||||
style={tw`px-6 py-0`} scrollview={false}>
|
|
||||||
<FlatList
|
<FlatList
|
||||||
data={CATEGORIES_LIST}
|
data={CATEGORIES_LIST}
|
||||||
contentContainerStyle={tw`py-6`}
|
contentContainerStyle={tw`py-6`}
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
import { RouteProp } from '@react-navigation/native';
|
|
||||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
|
||||||
import { useCache, useLibraryQuery, useNodes, usePathsExplorerQuery } from '@sd/client';
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useSharedValue } from 'react-native-reanimated';
|
import { useCache, useLibraryQuery, useNodes, usePathsExplorerQuery } from '@sd/client';
|
||||||
import Explorer from '~/components/explorer/Explorer';
|
import Explorer from '~/components/explorer/Explorer';
|
||||||
import { BrowseStackParamList } from '~/navigation/tabs/BrowseStack';
|
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
||||||
import { getExplorerStore } from '~/stores/explorerStore';
|
import { getExplorerStore } from '~/stores/explorerStore';
|
||||||
|
|
||||||
interface Props {
|
export default function LocationScreen({ navigation, route }: BrowseStackScreenProps<'Location'>) {
|
||||||
route: RouteProp<BrowseStackParamList, 'Location'>;
|
|
||||||
navigation: NativeStackNavigationProp<BrowseStackParamList, 'Location'>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function LocationScreen({ navigation, route }: Props) {
|
|
||||||
const { id, path } = route.params;
|
const { id, path } = route.params;
|
||||||
const scrollY = useSharedValue(0);
|
|
||||||
const location = useLibraryQuery(['locations.get', route.params.id]);
|
const location = useLibraryQuery(['locations.get', route.params.id]);
|
||||||
useNodes(location.data?.nodes);
|
useNodes(location.data?.nodes);
|
||||||
const locationData = useCache(location.data?.item);
|
const locationData = useCache(location.data?.item);
|
||||||
|
@ -67,7 +59,5 @@ export default function LocationScreen({ navigation, route }: Props) {
|
||||||
getExplorerStore().path = path ?? '';
|
getExplorerStore().path = path ?? '';
|
||||||
}, [id, path]);
|
}, [id, path]);
|
||||||
|
|
||||||
return (
|
return <Explorer {...paths} />;
|
||||||
<Explorer headerKind='location' route={route} scrollY={scrollY} {...paths} />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
|
||||||
import { Plus } from 'phosphor-react-native';
|
import { Plus } from 'phosphor-react-native';
|
||||||
import { useMemo, useRef } from 'react';
|
import { useMemo, useRef } from 'react';
|
||||||
import { Pressable, View } from 'react-native';
|
import { FlatList, Pressable, View } from 'react-native';
|
||||||
import Animated, { useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated';
|
|
||||||
import { useDebounce } from 'use-debounce';
|
import { useDebounce } from 'use-debounce';
|
||||||
|
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
||||||
import Empty from '~/components/layout/Empty';
|
import Empty from '~/components/layout/Empty';
|
||||||
import { ModalRef } from '~/components/layout/Modal';
|
import { ModalRef } from '~/components/layout/Modal';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
|
@ -20,7 +19,6 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function LocationsScreen({ viewStyle }: Props) {
|
export default function LocationsScreen({ viewStyle }: Props) {
|
||||||
const scrollY = useSharedValue(0);
|
|
||||||
const locationsQuery = useLibraryQuery(['locations.list']);
|
const locationsQuery = useLibraryQuery(['locations.list']);
|
||||||
useNodes(locationsQuery.data?.nodes);
|
useNodes(locationsQuery.data?.nodes);
|
||||||
const locations = useCache(locationsQuery.data?.items);
|
const locations = useCache(locationsQuery.data?.items);
|
||||||
|
@ -39,17 +37,8 @@ export default function LocationsScreen({ viewStyle }: Props) {
|
||||||
BrowseStackScreenProps<'Browse'>['navigation'] &
|
BrowseStackScreenProps<'Browse'>['navigation'] &
|
||||||
SettingsStackScreenProps<'Settings'>['navigation']
|
SettingsStackScreenProps<'Settings'>['navigation']
|
||||||
>();
|
>();
|
||||||
const scrollHandler = useAnimatedScrollHandler((e) => {
|
|
||||||
scrollY.value = e.contentOffset.y;
|
|
||||||
});
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer
|
<ScreenContainer scrollview={false} style={tw`relative px-6 py-0`}>
|
||||||
header={{
|
|
||||||
title: 'Locations',
|
|
||||||
navBack: true,
|
|
||||||
searchType: 'location',
|
|
||||||
}}
|
|
||||||
scrollview={false} style={tw`relative px-6 py-0`}>
|
|
||||||
<Pressable
|
<Pressable
|
||||||
style={tw`absolute bottom-7 right-7 z-10 h-12 w-12 items-center justify-center rounded-full bg-accent`}
|
style={tw`absolute bottom-7 right-7 z-10 h-12 w-12 items-center justify-center rounded-full bg-accent`}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
|
@ -58,13 +47,12 @@ export default function LocationsScreen({ viewStyle }: Props) {
|
||||||
>
|
>
|
||||||
<Plus size={20} weight="bold" style={tw`text-ink`} />
|
<Plus size={20} weight="bold" style={tw`text-ink`} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Animated.FlatList
|
<FlatList
|
||||||
data={filteredLocations}
|
data={filteredLocations}
|
||||||
contentContainerStyle={twStyle(
|
contentContainerStyle={twStyle(
|
||||||
`py-6`,
|
`py-6`,
|
||||||
filteredLocations.length === 0 && 'h-full items-center justify-center'
|
filteredLocations.length === 0 && 'h-full items-center justify-center'
|
||||||
)}
|
)}
|
||||||
onScroll={scrollHandler}
|
|
||||||
keyExtractor={(location) => location.id.toString()}
|
keyExtractor={(location) => location.id.toString()}
|
||||||
ItemSeparatorComponent={() => <View style={tw`h-2`} />}
|
ItemSeparatorComponent={() => <View style={tw`h-2`} />}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
|
@ -83,7 +71,7 @@ export default function LocationsScreen({ viewStyle }: Props) {
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
navigation.navigate('BrowseStack', {
|
navigation.navigate('BrowseStack', {
|
||||||
screen: 'Location',
|
screen: 'Location',
|
||||||
params: { id: item.id, title: item.name }
|
params: { id: item.id }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
editLocation={() =>
|
editLocation={() =>
|
||||||
|
|
|
@ -1,21 +1,11 @@
|
||||||
import { useCache, useLibraryQuery, useNodes, useObjectsExplorerQuery } from '@sd/client';
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useSharedValue } from 'react-native-reanimated';
|
import { useCache, useLibraryQuery, useNodes, useObjectsExplorerQuery } from '@sd/client';
|
||||||
import Explorer from '~/components/explorer/Explorer';
|
import Explorer from '~/components/explorer/Explorer';
|
||||||
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
||||||
|
|
||||||
|
export default function TagScreen({ navigation, route }: BrowseStackScreenProps<'Tag'>) {
|
||||||
interface Props {
|
|
||||||
route: BrowseStackScreenProps<'Tag'>['route'];
|
|
||||||
navigation: BrowseStackScreenProps<'Tag'>['navigation'];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function TagScreen({
|
|
||||||
navigation,
|
|
||||||
route,
|
|
||||||
}: Props) {
|
|
||||||
const { id } = route.params;
|
const { id } = route.params;
|
||||||
const scrollY = useSharedValue(0);
|
|
||||||
const tag = useLibraryQuery(['tags.get', id]);
|
const tag = useLibraryQuery(['tags.get', id]);
|
||||||
useNodes(tag.data?.nodes);
|
useNodes(tag.data?.nodes);
|
||||||
const tagData = useCache(tag.data?.item);
|
const tagData = useCache(tag.data?.item);
|
||||||
|
@ -32,7 +22,5 @@ export default function TagScreen({
|
||||||
});
|
});
|
||||||
}, [tagData?.name, navigation]);
|
}, [tagData?.name, navigation]);
|
||||||
|
|
||||||
return (
|
return <Explorer {...objects} />;
|
||||||
<Explorer headerKind='tag' route={route} scrollY={scrollY} {...objects} />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
|
||||||
import { Plus } from 'phosphor-react-native';
|
import { Plus } from 'phosphor-react-native';
|
||||||
import { useMemo, useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { Pressable, View } from 'react-native';
|
import { Pressable, View } from 'react-native';
|
||||||
import Animated from 'react-native-reanimated';
|
import { FlatList } from 'react-native-gesture-handler';
|
||||||
import { useDebounce } from 'use-debounce';
|
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
||||||
import Empty from '~/components/layout/Empty';
|
import Empty from '~/components/layout/Empty';
|
||||||
|
import Fade from '~/components/layout/Fade';
|
||||||
import { ModalRef } from '~/components/layout/Modal';
|
import { ModalRef } from '~/components/layout/Modal';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import CreateTagModal from '~/components/modal/tag/CreateTagModal';
|
import CreateTagModal from '~/components/modal/tag/CreateTagModal';
|
||||||
import { TagItem } from '~/components/tags/TagItem';
|
import { TagItem } from '~/components/tags/TagItem';
|
||||||
import { tw, twStyle } from '~/lib/tailwind';
|
import { tw, twStyle } from '~/lib/tailwind';
|
||||||
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
||||||
import { useSearchStore } from '~/stores/searchStore';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
viewStyle?: 'grid' | 'list';
|
viewStyle?: 'grid' | 'list';
|
||||||
|
@ -21,32 +20,13 @@ interface Props {
|
||||||
export default function TagsScreen({ viewStyle = 'list' }: Props) {
|
export default function TagsScreen({ viewStyle = 'list' }: Props) {
|
||||||
const navigation = useNavigation<BrowseStackScreenProps<'Browse'>['navigation']>();
|
const navigation = useNavigation<BrowseStackScreenProps<'Browse'>['navigation']>();
|
||||||
const modalRef = useRef<ModalRef>(null);
|
const modalRef = useRef<ModalRef>(null);
|
||||||
const { search } = useSearchStore();
|
|
||||||
|
|
||||||
|
|
||||||
const tags = useLibraryQuery(['tags.list']);
|
const tags = useLibraryQuery(['tags.list']);
|
||||||
useNodes(tags.data?.nodes);
|
useNodes(tags.data?.nodes);
|
||||||
const tagData = useCache(tags.data?.items);
|
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 (
|
return (
|
||||||
<ScreenContainer
|
<ScreenContainer scrollview={false} style={tw`relative px-6 py-0`}>
|
||||||
header={{
|
|
||||||
title: 'Tags',
|
|
||||||
showSearch: false,
|
|
||||||
navBack: true,
|
|
||||||
searchType: 'tags',
|
|
||||||
}}
|
|
||||||
scrollview={false}
|
|
||||||
style={tw`relative px-6 py-0`}>
|
|
||||||
<Pressable
|
<Pressable
|
||||||
style={tw`absolute bottom-7 right-7 z-10 flex h-12 w-12 items-center justify-center rounded-full bg-accent`}
|
style={tw`absolute bottom-7 right-7 z-10 flex h-12 w-12 items-center justify-center rounded-full bg-accent`}
|
||||||
testID="create-tag-modal"
|
testID="create-tag-modal"
|
||||||
|
@ -56,9 +36,15 @@ export default function TagsScreen({ viewStyle = 'list' }: Props) {
|
||||||
>
|
>
|
||||||
<Plus size={20} weight="bold" style={tw`text-ink`} />
|
<Plus size={20} weight="bold" style={tw`text-ink`} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Animated.FlatList
|
<Fade
|
||||||
data={filteredTags}
|
fadeSides="top-bottom"
|
||||||
scrollEventThrottle={1}
|
orientation="vertical"
|
||||||
|
color="black"
|
||||||
|
width={30}
|
||||||
|
height="100%"
|
||||||
|
>
|
||||||
|
<FlatList
|
||||||
|
data={tagData}
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<TagItem
|
<TagItem
|
||||||
viewStyle={viewStyle}
|
viewStyle={viewStyle}
|
||||||
|
@ -90,6 +76,7 @@ export default function TagsScreen({ viewStyle = 'list' }: Props) {
|
||||||
tagData.length === 0 && 'h-full items-center justify-center'
|
tagData.length === 0 && 'h-full items-center justify-center'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
</Fade>
|
||||||
<CreateTagModal ref={modalRef} />
|
<CreateTagModal ref={modalRef} />
|
||||||
</ScreenContainer>
|
</ScreenContainer>
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,11 +6,7 @@ import { NetworkStackScreenProps } from '~/navigation/tabs/NetworkStack';
|
||||||
|
|
||||||
export default function NetworkScreen({ navigation }: NetworkStackScreenProps<'Network'>) {
|
export default function NetworkScreen({ navigation }: NetworkStackScreenProps<'Network'>) {
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer scrollview={false} style={tw`items-center justify-center gap-0`}>
|
||||||
showDrawer: true,
|
|
||||||
title: 'Network',
|
|
||||||
showSearch: true,
|
|
||||||
}} scrollview={false} style={tw`items-center justify-center gap-0`}>
|
|
||||||
<Icon name="Globe" size={128} />
|
<Icon name="Globe" size={128} />
|
||||||
<Text style={tw`mt-4 text-lg font-bold text-white`}>Your Local Network</Text>
|
<Text style={tw`mt-4 text-lg font-bold text-white`}>Your Local Network</Text>
|
||||||
<Text style={tw`mt-1 max-w-sm text-center text-sm text-ink-dull`}>
|
<Text style={tw`mt-1 max-w-sm text-center text-sm text-ink-dull`}>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { useLibraryQuery } from '@sd/client';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { View } from 'react-native';
|
import { FlatList, View } from 'react-native';
|
||||||
import Animated, { useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated';
|
|
||||||
import { useDebounce } from 'use-debounce';
|
import { useDebounce } from 'use-debounce';
|
||||||
|
import { useLibraryQuery } from '@sd/client';
|
||||||
import { IconName } from '~/components/icons/Icon';
|
import { IconName } from '~/components/icons/Icon';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import CategoryItem from '~/components/overview/CategoryItem';
|
import CategoryItem from '~/components/overview/CategoryItem';
|
||||||
|
@ -10,7 +9,6 @@ import { tw } from '~/lib/tailwind';
|
||||||
import { useSearchStore } from '~/stores/searchStore';
|
import { useSearchStore } from '~/stores/searchStore';
|
||||||
|
|
||||||
const CategoriesScreen = () => {
|
const CategoriesScreen = () => {
|
||||||
const scrollY = useSharedValue(0);
|
|
||||||
const kinds = useLibraryQuery(['library.kindStatistics']);
|
const kinds = useLibraryQuery(['library.kindStatistics']);
|
||||||
const { search } = useSearchStore();
|
const { search } = useSearchStore();
|
||||||
const [debouncedSearch] = useDebounce(search, 200);
|
const [debouncedSearch] = useDebounce(search, 200);
|
||||||
|
@ -21,26 +19,13 @@ const CategoriesScreen = () => {
|
||||||
) ?? [],
|
) ?? [],
|
||||||
[debouncedSearch, kinds]
|
[debouncedSearch, kinds]
|
||||||
);
|
);
|
||||||
const scrollHandler = useAnimatedScrollHandler((e) => {
|
|
||||||
scrollY.value = e.contentOffset.y;
|
|
||||||
});
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer
|
<ScreenContainer scrollview={false} style={tw`relative px-6 py-0`}>
|
||||||
header={{
|
<FlatList
|
||||||
title: 'Categories',
|
|
||||||
searchType: 'categories',
|
|
||||||
navBack: true,
|
|
||||||
}}
|
|
||||||
scrollY={scrollY}
|
|
||||||
scrollview={false}
|
|
||||||
style={tw`relative px-6 py-0`}>
|
|
||||||
<Animated.FlatList
|
|
||||||
data={filteredKinds?.sort((a, b) => b.count - a.count).filter((i) => i.kind !== 0)}
|
data={filteredKinds?.sort((a, b) => b.count - a.count).filter((i) => i.kind !== 0)}
|
||||||
numColumns={3}
|
numColumns={3}
|
||||||
onScroll={scrollHandler}
|
|
||||||
contentContainerStyle={tw`py-6`}
|
contentContainerStyle={tw`py-6`}
|
||||||
keyExtractor={(item) => item.name}
|
keyExtractor={(item) => item.name}
|
||||||
scrollEventThrottle={1}
|
|
||||||
ItemSeparatorComponent={() => <View style={tw`h-2`} />}
|
ItemSeparatorComponent={() => <View style={tw`h-2`} />}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { useBridgeQuery, useLibraryQuery } from '@sd/client';
|
import { useBridgeQuery, useLibraryQuery } from '@sd/client';
|
||||||
import { useSharedValue } from 'react-native-reanimated';
|
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import Categories from '~/components/overview/Categories';
|
import Categories from '~/components/overview/Categories';
|
||||||
import Cloud from '~/components/overview/Cloud';
|
import Cloud from '~/components/overview/Cloud';
|
||||||
|
@ -21,19 +20,13 @@ const EMPTY_STATISTICS = {
|
||||||
|
|
||||||
export default function OverviewScreen() {
|
export default function OverviewScreen() {
|
||||||
const { data: node } = useBridgeQuery(['nodeState']);
|
const { data: node } = useBridgeQuery(['nodeState']);
|
||||||
const scrollY = useSharedValue(0);
|
|
||||||
const stats = useLibraryQuery(['library.statistics'], {
|
const stats = useLibraryQuery(['library.statistics'], {
|
||||||
initialData: { ...EMPTY_STATISTICS }
|
initialData: { ...EMPTY_STATISTICS }
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer
|
<ScreenContainer>
|
||||||
header={{
|
|
||||||
title: 'Overview',
|
|
||||||
showSearch: true,
|
|
||||||
showDrawer: true,
|
|
||||||
}}
|
|
||||||
scrollY={scrollY}>
|
|
||||||
<OverviewStats stats={stats} />
|
<OverviewStats stats={stats} />
|
||||||
<Categories />
|
<Categories />
|
||||||
<Devices stats={stats} node={node} />
|
<Devices stats={stats} node={node} />
|
||||||
|
|
|
@ -5,13 +5,7 @@ import SaveAdd from '~/components/search/filters/SaveAdd';
|
||||||
const FiltersScreen = () => {
|
const FiltersScreen = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ScreenContainer
|
<ScreenContainer bottomFadeStyle="bottom-0" tabHeight={false}>
|
||||||
header={{
|
|
||||||
title: 'Filters',
|
|
||||||
showSearch: false,
|
|
||||||
navBack: true,
|
|
||||||
}}
|
|
||||||
tabHeight={false}>
|
|
||||||
<FiltersList />
|
<FiltersList />
|
||||||
</ScreenContainer>
|
</ScreenContainer>
|
||||||
<SaveAdd />
|
<SaveAdd />
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { SearchFilterArgs, useObjectsExplorerQuery } from '@sd/client';
|
|
||||||
import { ArrowLeft, DotsThreeOutline, FunnelSimple, MagnifyingGlass } from 'phosphor-react-native';
|
import { ArrowLeft, DotsThreeOutline, FunnelSimple, MagnifyingGlass } from 'phosphor-react-native';
|
||||||
import { Suspense, useDeferredValue, useMemo, useState } from 'react';
|
import { Suspense, useDeferredValue, useMemo, useState } from 'react';
|
||||||
import { ActivityIndicator, Platform, Pressable, TextInput, View } from 'react-native';
|
import { ActivityIndicator, Platform, Pressable, TextInput, View } from 'react-native';
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
|
import { SearchFilterArgs, useObjectsExplorerQuery } from '@sd/client';
|
||||||
import Explorer from '~/components/explorer/Explorer';
|
import Explorer from '~/components/explorer/Explorer';
|
||||||
import FiltersBar from '~/components/search/filters/FiltersBar';
|
import FiltersBar from '~/components/search/filters/FiltersBar';
|
||||||
import { tw, twStyle } from '~/lib/tailwind';
|
import { tw, twStyle } from '~/lib/tailwind';
|
||||||
|
@ -124,7 +124,7 @@ const SearchScreen = ({ navigation }: SearchStackScreenProps<'Search'>) => {
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<View style={tw`flex-1`}>
|
<View style={tw`flex-1`}>
|
||||||
<Suspense fallback={<ActivityIndicator />}>
|
<Suspense fallback={<ActivityIndicator />}>
|
||||||
<Explorer hideHeader {...objects} tabHeight={false} />
|
<Explorer {...objects} tabHeight={false} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { DebugState, useDebugState, useDebugStateEnabler } from '@sd/client';
|
|
||||||
import {
|
import {
|
||||||
Books,
|
Books,
|
||||||
FlyingSaucer,
|
FlyingSaucer,
|
||||||
|
@ -13,8 +12,9 @@ import {
|
||||||
ShieldCheck,
|
ShieldCheck,
|
||||||
TagSimple
|
TagSimple
|
||||||
} from 'phosphor-react-native';
|
} from 'phosphor-react-native';
|
||||||
import { Platform, Text, TouchableWithoutFeedback, View } from 'react-native';
|
import React from 'react';
|
||||||
import { useSharedValue } from 'react-native-reanimated';
|
import { Platform, SectionList, Text, TouchableWithoutFeedback, View } from 'react-native';
|
||||||
|
import { DebugState, useDebugState, useDebugStateEnabler } from '@sd/client';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import { SettingsItem } from '~/components/settings/SettingsItem';
|
import { SettingsItem } from '~/components/settings/SettingsItem';
|
||||||
import { tw, twStyle } from '~/lib/tailwind';
|
import { tw, twStyle } from '~/lib/tailwind';
|
||||||
|
@ -129,7 +129,7 @@ function renderSectionHeader({ section }: { section: { title: string } }) {
|
||||||
<Text
|
<Text
|
||||||
style={twStyle(
|
style={twStyle(
|
||||||
'mb-3 text-lg font-bold text-ink',
|
'mb-3 text-lg font-bold text-ink',
|
||||||
section.title === 'Client' ? 'mt-0' : 'mt-5'
|
section.title === 'Client' ? 'mt-2' : 'mt-5'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{section.title}
|
{section.title}
|
||||||
|
@ -137,34 +137,28 @@ function renderSectionHeader({ section }: { section: { title: string } }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SettingsScreen({
|
export default function SettingsScreen({ navigation }: SettingsStackScreenProps<'Settings'>) {
|
||||||
navigation,
|
|
||||||
}: SettingsStackScreenProps<'Settings'>) {
|
|
||||||
const debugState = useDebugState();
|
const debugState = useDebugState();
|
||||||
const scrollY = useSharedValue(0);
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer
|
<ScreenContainer tabHeight={false} scrollview={false} style={tw`gap-0 px-6 py-0`}>
|
||||||
header={{
|
<SectionList
|
||||||
title: 'Settings',
|
sections={sections(debugState)}
|
||||||
showSearch: true,
|
contentContainerStyle={tw`h-auto pb-5 pt-3`}
|
||||||
showDrawer: true,
|
renderItem={({ item }) => (
|
||||||
}}
|
<SettingsItem
|
||||||
scrollY={scrollY} tabHeight={false} style={tw`gap-0 px-6`}>
|
title={item.title}
|
||||||
{sections(debugState).map((section, i) => (
|
leftIcon={item.icon}
|
||||||
<View key={i}>
|
onPress={() => navigation.navigate(item.navigateTo as any)}
|
||||||
{renderSectionHeader({ section })}
|
rounded={item.rounded}
|
||||||
{section.data.map((item, i) => (
|
/>
|
||||||
<SettingsItem
|
)}
|
||||||
key={i}
|
renderSectionHeader={renderSectionHeader}
|
||||||
title={item.title}
|
ListFooterComponent={<FooterComponent />}
|
||||||
leftIcon={item.icon}
|
showsVerticalScrollIndicator={false}
|
||||||
onPress={() => navigation.navigate(item.navigateTo as any)}
|
stickySectionHeadersEnabled={false}
|
||||||
rounded={item.rounded}
|
initialNumToRender={50}
|
||||||
/>
|
/>
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
<FooterComponent />
|
|
||||||
</ScreenContainer>
|
</ScreenContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Themes, useThemeStore } from '@sd/client';
|
|
||||||
import { CheckCircle } from 'phosphor-react-native';
|
import { CheckCircle } from 'phosphor-react-native';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { ColorValue, Pressable, ScrollView, Text, View, ViewStyle } from 'react-native';
|
import { ColorValue, Pressable, ScrollView, Text, View, ViewStyle } from 'react-native';
|
||||||
|
import { Themes, useThemeStore } from '@sd/client';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import { SettingsTitle } from '~/components/settings/SettingsContainer';
|
import { SettingsTitle } from '~/components/settings/SettingsContainer';
|
||||||
import Colors from '~/constants/style/Colors';
|
import Colors from '~/constants/style/Colors';
|
||||||
|
@ -126,10 +126,7 @@ const AppearanceSettingsScreen = ({
|
||||||
// TODO: Hook this up to the theme store once light theme is fixed.
|
// TODO: Hook this up to the theme store once light theme is fixed.
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer scrollview={false} style={tw`gap-2 px-6`}>
|
||||||
navBack: true,
|
|
||||||
title: 'Appearance'
|
|
||||||
}} scrollview={false} style={tw`gap-2 px-6`}>
|
|
||||||
<SettingsTitle>Theme</SettingsTitle>
|
<SettingsTitle>Theme</SettingsTitle>
|
||||||
<ScrollView
|
<ScrollView
|
||||||
horizontal
|
horizontal
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import { tw } from '~/lib/tailwind';
|
import { tw } from '~/lib/tailwind';
|
||||||
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
|
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
|
||||||
|
@ -8,11 +8,7 @@ const ExtensionsSettingsScreen = ({
|
||||||
navigation
|
navigation
|
||||||
}: SettingsStackScreenProps<'ExtensionsSettings'>) => {
|
}: SettingsStackScreenProps<'ExtensionsSettings'>) => {
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer style={tw`px-6`}>
|
||||||
title: 'Extensions',
|
|
||||||
navBack: true,
|
|
||||||
}}
|
|
||||||
style={tw`px-6`}>
|
|
||||||
<Text style={tw`text-ink`}>TODO</Text>
|
<Text style={tw`text-ink`}>TODO</Text>
|
||||||
</ScreenContainer>
|
</ScreenContainer>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { useBridgeQuery, useDebugState } from '@sd/client';
|
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
|
import { useBridgeQuery, useDebugState } from '@sd/client';
|
||||||
import Card from '~/components/layout/Card';
|
import Card from '~/components/layout/Card';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import { Divider } from '~/components/primitive/Divider';
|
import { Divider } from '~/components/primitive/Divider';
|
||||||
import { Input } from '~/components/primitive/Input';
|
import { Input } from '~/components/primitive/Input';
|
||||||
import { SettingsTitle } from '~/components/settings/SettingsContainer';
|
import { SettingsTitle } from '~/components/settings/SettingsContainer';
|
||||||
import { tw } from '~/lib/tailwind';
|
import { tw } from '~/lib/tailwind';
|
||||||
|
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
|
||||||
|
|
||||||
const GeneralSettingsScreen = () => {
|
const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'GeneralSettings'>) => {
|
||||||
const { data: node } = useBridgeQuery(['nodeState']);
|
const { data: node } = useBridgeQuery(['nodeState']);
|
||||||
|
|
||||||
const debugState = useDebugState();
|
const debugState = useDebugState();
|
||||||
|
@ -15,12 +16,7 @@ const GeneralSettingsScreen = () => {
|
||||||
if (!node) return null;
|
if (!node) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer
|
<ScreenContainer style={tw`justify-start gap-0 px-6`} scrollview={false}>
|
||||||
header={{
|
|
||||||
title: 'General',
|
|
||||||
navBack: true,
|
|
||||||
}}
|
|
||||||
style={tw`justify-start gap-0 px-6`} scrollview={false}>
|
|
||||||
<Card>
|
<Card>
|
||||||
{/* Card Header */}
|
{/* Card Header */}
|
||||||
<View style={tw`flex flex-row justify-between`}>
|
<View style={tw`flex flex-row justify-between`}>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { LibraryConfigWrapped, useBridgeQuery, useCache, useNodes } from '@sd/client';
|
|
||||||
import { DotsThreeOutlineVertical, Pen, Trash } from 'phosphor-react-native';
|
import { DotsThreeOutlineVertical, Pen, Trash } from 'phosphor-react-native';
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { Animated, Pressable, Text, View } from 'react-native';
|
import { Animated, FlatList, Pressable, Text, View } from 'react-native';
|
||||||
import { Swipeable } from 'react-native-gesture-handler';
|
import { Swipeable } from 'react-native-gesture-handler';
|
||||||
import { default as Reanimated } from 'react-native-reanimated';
|
import { LibraryConfigWrapped, useBridgeQuery, useCache, useNodes } from '@sd/client';
|
||||||
import Fade from '~/components/layout/Fade';
|
import Fade from '~/components/layout/Fade';
|
||||||
import { ModalRef } from '~/components/layout/Modal';
|
import { ModalRef } from '~/components/layout/Modal';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
|
@ -79,9 +78,7 @@ function LibraryItem({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const LibrarySettingsScreen = ({
|
const LibrarySettingsScreen = ({ navigation }: SettingsStackScreenProps<'LibrarySettings'>) => {
|
||||||
navigation,
|
|
||||||
}: SettingsStackScreenProps<'LibrarySettings'>) => {
|
|
||||||
const libraryList = useBridgeQuery(['library.list']);
|
const libraryList = useBridgeQuery(['library.list']);
|
||||||
useNodes(libraryList.data?.nodes);
|
useNodes(libraryList.data?.nodes);
|
||||||
const libraries = useCache(libraryList.data?.items);
|
const libraries = useCache(libraryList.data?.items);
|
||||||
|
@ -104,10 +101,7 @@ const LibrarySettingsScreen = ({
|
||||||
const modalRef = useRef<ModalRef>(null);
|
const modalRef = useRef<ModalRef>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer style={tw`justify-start gap-0 px-6 py-0`} scrollview={false}>
|
||||||
navBack: true,
|
|
||||||
title: 'Libraries',
|
|
||||||
}} scrollview={false} style={tw`justify-start gap-0 px-6 py-0`}>
|
|
||||||
<Fade
|
<Fade
|
||||||
fadeSides="top-bottom"
|
fadeSides="top-bottom"
|
||||||
orientation="vertical"
|
orientation="vertical"
|
||||||
|
@ -115,7 +109,7 @@ const LibrarySettingsScreen = ({
|
||||||
width={30}
|
width={30}
|
||||||
height="100%"
|
height="100%"
|
||||||
>
|
>
|
||||||
<Reanimated.FlatList
|
<FlatList
|
||||||
data={libraries}
|
data={libraries}
|
||||||
contentContainerStyle={tw`py-5`}
|
contentContainerStyle={tw`py-5`}
|
||||||
keyExtractor={(item) => item.uuid}
|
keyExtractor={(item) => item.uuid}
|
||||||
|
|
|
@ -5,10 +5,7 @@ import { tw } from '~/lib/tailwind';
|
||||||
|
|
||||||
const PrivacySettingsScreen = () => {
|
const PrivacySettingsScreen = () => {
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer scrollview={false} style={tw`px-6`}>
|
||||||
title: 'Privacy',
|
|
||||||
navBack: true,
|
|
||||||
}} scrollview={false} style={tw`px-6`}>
|
|
||||||
<Text style={tw`text-ink`}>TODO</Text>
|
<Text style={tw`text-ink`}>TODO</Text>
|
||||||
</ScreenContainer>
|
</ScreenContainer>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useBridgeQuery } from '@sd/client';
|
|
||||||
import { Image } from 'expo-image';
|
import { Image } from 'expo-image';
|
||||||
import { Globe } from 'phosphor-react-native';
|
import { Globe } from 'phosphor-react-native';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Linking, Platform, Text, View } from 'react-native';
|
import { Linking, Platform, Text, View } from 'react-native';
|
||||||
|
import { useBridgeQuery } from '@sd/client';
|
||||||
import { DiscordIcon, GitHubIcon } from '~/components/icons/Brands';
|
import { DiscordIcon, GitHubIcon } from '~/components/icons/Brands';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import { Button } from '~/components/primitive/Button';
|
import { Button } from '~/components/primitive/Button';
|
||||||
|
@ -11,16 +11,14 @@ import { tw } from '~/lib/tailwind';
|
||||||
|
|
||||||
const AboutScreen = () => {
|
const AboutScreen = () => {
|
||||||
const buildInfo = useBridgeQuery(['buildInfo']);
|
const buildInfo = useBridgeQuery(['buildInfo']);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer style={tw`justify-start gap-0 px-6`}>
|
||||||
title: 'About',
|
|
||||||
navBack: true,
|
|
||||||
}} style={tw`justify-start gap-0 px-6`}>
|
|
||||||
<View style={tw`flex flex-row items-center`}>
|
<View style={tw`flex flex-row items-center`}>
|
||||||
<Image
|
<Image
|
||||||
source={require('../../../../assets/icon.png')}
|
source={require('../../../../assets/icon.png')}
|
||||||
style={tw`mr-8 h-[88px] w-[88px] rounded-3xl`}
|
style={tw`mr-8 h-[88px] w-[88px] rounded-3xl`}
|
||||||
contentFit="contain"
|
resizeMode="contain"
|
||||||
/>
|
/>
|
||||||
<View style={tw`flex flex-col`}>
|
<View style={tw`flex flex-col`}>
|
||||||
<Text style={tw`text-2xl font-bold text-white`}>
|
<Text style={tw`text-2xl font-bold text-white`}>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { useDebugState, useFeatureFlags } from '@sd/client';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
|
import { toggleFeatureFlag, useDebugState, useFeatureFlags } from '@sd/client';
|
||||||
import Card from '~/components/layout/Card';
|
import Card from '~/components/layout/Card';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
|
||||||
import { Button } from '~/components/primitive/Button';
|
import { Button } from '~/components/primitive/Button';
|
||||||
import { tw } from '~/lib/tailwind';
|
import { tw } from '~/lib/tailwind';
|
||||||
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
|
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
|
||||||
|
@ -12,16 +11,15 @@ const DebugScreen = ({ navigation }: SettingsStackScreenProps<'Debug'>) => {
|
||||||
const featureFlags = useFeatureFlags();
|
const featureFlags = useFeatureFlags();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer style={tw`px-6`} header={{ title: 'Debug', navBack: true }}>
|
<View style={tw`flex-1 p-4`}>
|
||||||
<Card style={tw`gap-y-4`}>
|
<Card style={tw`gap-y-4 bg-app-box`}>
|
||||||
<Text style={tw`font-semibold text-ink`}>Debug</Text>
|
<Text style={tw`font-semibold text-ink`}>Debug</Text>
|
||||||
<Button variant="darkgray" onPress={() => (debugState.rspcLogger = !debugState.rspcLogger)}>
|
<Button onPress={() => (debugState.rspcLogger = !debugState.rspcLogger)}>
|
||||||
<Text style={tw`text-ink`}>Toggle rspc logger</Text>
|
<Text style={tw`text-ink`}>Toggle rspc logger</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Text style={tw`text-ink`}>{JSON.stringify(featureFlags)}</Text>
|
<Text style={tw`text-ink`}>{JSON.stringify(featureFlags)}</Text>
|
||||||
<Text style={tw`text-ink`}>{JSON.stringify(debugState)}</Text>
|
<Text style={tw`text-ink`}>{JSON.stringify(debugState)}</Text>
|
||||||
<Button
|
<Button
|
||||||
variant="darkgray"
|
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
navigation.popToTop();
|
navigation.popToTop();
|
||||||
navigation.replace('Settings');
|
navigation.replace('Settings');
|
||||||
|
@ -31,7 +29,7 @@ const DebugScreen = ({ navigation }: SettingsStackScreenProps<'Debug'>) => {
|
||||||
<Text style={tw`text-ink`}>Disable Debug Mode</Text>
|
<Text style={tw`text-ink`}>Disable Debug Mode</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Card>
|
</Card>
|
||||||
</ScreenContainer>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
|
||||||
import { tw } from '~/lib/tailwind';
|
import { tw } from '~/lib/tailwind';
|
||||||
|
|
||||||
const SupportScreen = () => {
|
const SupportScreen = () => {
|
||||||
return (
|
return (
|
||||||
<ScreenContainer
|
<View>
|
||||||
style={tw`justify-start px-6 py-5`}
|
|
||||||
header={{
|
|
||||||
title: 'Support',
|
|
||||||
navBack: true,
|
|
||||||
}}>
|
|
||||||
<Text style={tw`text-ink`}>TODO</Text>
|
<Text style={tw`text-ink`}>TODO</Text>
|
||||||
</ScreenContainer>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { useLibraryMutation, useLibraryQuery, useNormalisedCache, useZodForm } from '@sd/client';
|
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { Archive, ArrowsClockwise, Trash } from 'phosphor-react-native';
|
import { Archive, ArrowsClockwise, Trash } from 'phosphor-react-native';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { Controller } from 'react-hook-form';
|
import { Controller } from 'react-hook-form';
|
||||||
import { Alert, Text, View } from 'react-native';
|
import { Alert, Text, View } from 'react-native';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { useLibraryMutation, useLibraryQuery, useNormalisedCache, useZodForm } from '@sd/client';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import { AnimatedButton } from '~/components/primitive/Button';
|
import { AnimatedButton } from '~/components/primitive/Button';
|
||||||
import { Divider } from '~/components/primitive/Divider';
|
import { Divider } from '~/components/primitive/Divider';
|
||||||
|
@ -28,9 +28,10 @@ const schema = z.object({
|
||||||
|
|
||||||
const EditLocationSettingsScreen = ({
|
const EditLocationSettingsScreen = ({
|
||||||
route,
|
route,
|
||||||
navigation,
|
navigation
|
||||||
}: SettingsStackScreenProps<'EditLocationSettings'>) => {
|
}: SettingsStackScreenProps<'EditLocationSettings'>) => {
|
||||||
const { id } = route.params;
|
const { id } = route.params;
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const cache = useNormalisedCache();
|
const cache = useNormalisedCache();
|
||||||
|
|
||||||
|
@ -110,10 +111,7 @@ const EditLocationSettingsScreen = ({
|
||||||
const fullRescan = useLibraryMutation('locations.fullRescan');
|
const fullRescan = useLibraryMutation('locations.fullRescan');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer style={tw`px-6`}>
|
||||||
title: 'Edit Location',
|
|
||||||
navBack: true,
|
|
||||||
}} scrollview style={tw`px-6`}>
|
|
||||||
{/* Inputs */}
|
{/* Inputs */}
|
||||||
<View>
|
<View>
|
||||||
<SettingsTitle style={tw`mb-1`}>Display Name</SettingsTitle>
|
<SettingsTitle style={tw`mb-1`}>Display Name</SettingsTitle>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useBridgeMutation, useLibraryContext, useZodForm } from '@sd/client';
|
|
||||||
import { Controller } from 'react-hook-form';
|
import { Controller } from 'react-hook-form';
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
import { TouchableOpacity } from 'react-native-gesture-handler';
|
import { TouchableOpacity } from 'react-native-gesture-handler';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { useBridgeMutation, useLibraryContext, useZodForm } from '@sd/client';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import DeleteLibraryModal from '~/components/modal/confirmModals/DeleteLibraryModal';
|
import DeleteLibraryModal from '~/components/modal/confirmModals/DeleteLibraryModal';
|
||||||
import { Button } from '~/components/primitive/Button';
|
import { Button } from '~/components/primitive/Button';
|
||||||
|
@ -14,10 +14,11 @@ import { SettingsTitle } from '~/components/settings/SettingsContainer';
|
||||||
import SettingsToggle from '~/components/settings/SettingsToggle';
|
import SettingsToggle from '~/components/settings/SettingsToggle';
|
||||||
import { useAutoForm } from '~/hooks/useAutoForm';
|
import { useAutoForm } from '~/hooks/useAutoForm';
|
||||||
import { tw } from '~/lib/tailwind';
|
import { tw } from '~/lib/tailwind';
|
||||||
|
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
|
||||||
|
|
||||||
const schema = z.object({ name: z.string(), description: z.string() });
|
const schema = z.object({ name: z.string(), description: z.string() });
|
||||||
|
|
||||||
const LibraryGeneralSettingsScreen = () => {
|
const LibraryGeneralSettingsScreen = (_: SettingsStackScreenProps<'LibraryGeneralSettings'>) => {
|
||||||
const { library } = useLibraryContext();
|
const { library } = useLibraryContext();
|
||||||
|
|
||||||
const form = useZodForm({
|
const form = useZodForm({
|
||||||
|
@ -37,10 +38,7 @@ const LibraryGeneralSettingsScreen = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer scrollview={false} style={tw`justify-start px-6 py-0`}>
|
||||||
title: 'Library Settings',
|
|
||||||
navBack: true,
|
|
||||||
}} style={tw`justify-start px-6 py-0`}>
|
|
||||||
<View style={tw`pt-5`}>
|
<View style={tw`pt-5`}>
|
||||||
<SettingsTitle style={tw`mb-1`}>Name</SettingsTitle>
|
<SettingsTitle style={tw`mb-1`}>Name</SettingsTitle>
|
||||||
<Controller
|
<Controller
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useDiscoveredPeers } from '@sd/client';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
|
import { useDiscoveredPeers } from '@sd/client';
|
||||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||||
import { tw } from '~/lib/tailwind';
|
import { tw } from '~/lib/tailwind';
|
||||||
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
|
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
|
||||||
|
@ -9,10 +9,7 @@ const NodesSettingsScreen = ({ navigation }: SettingsStackScreenProps<'NodesSett
|
||||||
const onlineNodes = useDiscoveredPeers();
|
const onlineNodes = useDiscoveredPeers();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenContainer header={{
|
<ScreenContainer scrollview={false} style={tw`gap-0 px-6`}>
|
||||||
title: 'Nodes',
|
|
||||||
navBack: true,
|
|
||||||
}} scrollview={false} style={tw`gap-0 px-6`}>
|
|
||||||
<Text style={tw`text-ink`}>Pairing</Text>
|
<Text style={tw`text-ink`}>Pairing</Text>
|
||||||
|
|
||||||
{[...onlineNodes.entries()].map(([id, node]) => (
|
{[...onlineNodes.entries()].map(([id, node]) => (
|
||||||
|
|
Loading…
Reference in a new issue