From 9742dc7ab45a0c0f232fa338da13cbaac6217efa Mon Sep 17 00:00:00 2001 From: ameer2468 <33054370+ameer2468@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:12:11 +0300 Subject: [PATCH] [MOB-58] Settings routes new design & more (#2103) * wip: redesigning settings pages * Edit location redesign & more * right actions * cleanup --- .../src/components/browse/BrowseTags.tsx | 148 +++++++++++---- apps/mobile/src/components/header/Header.tsx | 68 ++++--- .../src/components/overview/Categories.tsx | 6 +- .../src/components/overview/OverviewStats.tsx | 2 +- .../src/components/overview/StatCard.tsx | 2 +- .../src/components/primitive/Button.tsx | 1 + .../components/settings/SettingsButton.tsx | 46 +++++ .../components/settings/SettingsContainer.tsx | 8 +- .../components/settings/SettingsToggle.tsx | 65 +++++++ .../src/navigation/tabs/SettingsStack.tsx | 38 ++-- apps/mobile/src/screens/Locations.tsx | 165 ++++++++++++----- apps/mobile/src/screens/Tags.tsx | 46 +++-- apps/mobile/src/screens/network/index.tsx | 2 +- apps/mobile/src/screens/settings/Settings.tsx | 4 +- .../settings/client/AppearanceSettings.tsx | 60 +++---- .../settings/client/ExtensionsSettings.tsx | 5 +- .../settings/client/GeneralSettings.tsx | 11 +- .../settings/client/LibrarySettings.tsx | 37 ++-- .../settings/client/PrivacySettings.tsx | 5 +- .../src/screens/settings/info/About.tsx | 19 +- .../settings/library/EditLocationSettings.tsx | 160 +++++++---------- .../library/LibraryGeneralSettings.tsx | 66 +++++-- .../settings/library/LocationSettings.tsx | 169 +----------------- .../settings/library/NodesSettings.tsx | 8 +- .../screens/settings/library/TagsSettings.tsx | 101 +---------- 25 files changed, 655 insertions(+), 587 deletions(-) create mode 100644 apps/mobile/src/components/settings/SettingsButton.tsx create mode 100644 apps/mobile/src/components/settings/SettingsToggle.tsx diff --git a/apps/mobile/src/components/browse/BrowseTags.tsx b/apps/mobile/src/components/browse/BrowseTags.tsx index 3bcbcfb88..006c73301 100644 --- a/apps/mobile/src/components/browse/BrowseTags.tsx +++ b/apps/mobile/src/components/browse/BrowseTags.tsx @@ -1,55 +1,135 @@ import { useNavigation } from '@react-navigation/native'; -import { DotsThreeOutlineVertical, Eye, Plus } from 'phosphor-react-native'; -import React, { useRef } from 'react'; -import { Pressable, Text, View } from 'react-native'; -import { FlatList } from 'react-native-gesture-handler'; import { Tag, useCache, useLibraryQuery, useNodes } from '@sd/client'; +import { DotsThreeOutlineVertical, Eye, Pen, Plus, Trash } from 'phosphor-react-native'; +import React, { useRef } from 'react'; +import { Animated, Pressable, Text, View } from 'react-native'; +import { FlatList, Swipeable } from 'react-native-gesture-handler'; +import { ClassInput } from 'twrnc/dist/esm/types'; import { ModalRef } from '~/components/layout/Modal'; import { tw, twStyle } from '~/lib/tailwind'; import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack'; import { Icon } from '../icons/Icon'; import Fade from '../layout/Fade'; +import DeleteTagModal from '../modal/confirmModals/DeleteTagModal'; import CreateTagModal from '../modal/tag/CreateTagModal'; import { TagModal } from '../modal/tag/TagModal'; +import UpdateTagModal from '../modal/tag/UpdateTagModal'; +import { AnimatedButton, FakeButton } from '../primitive/Button'; -type BrowseTagItemProps = { +type TagItemProps = { tag: Tag; onPress: () => void; - tagStyle?: string; + tagStyle?: ClassInput; + viewStyle?: 'grid' | 'list'; + rightActions?: () => void; }; -export const BrowseTagItem: React.FC = ({ tag, onPress, tagStyle }) => { +export const TagItem = ({ + tag, + onPress, + rightActions, + tagStyle, + viewStyle = 'grid' +}: TagItemProps) => { const modalRef = useRef(null); + + const renderTagView = () => ( + + + + modalRef.current?.present()}> + + + + + {tag.name} + + + ); + + const renderRightActions = ( + progress: Animated.AnimatedInterpolation, + _dragX: Animated.AnimatedInterpolation, + swipeable: Swipeable + ) => { + const translate = progress.interpolate({ + inputRange: [0, 1], + outputRange: [100, 0], + extrapolate: 'clamp' + }); + + return ( + + swipeable.close()} /> + modalRef.current?.present()}> + + + + + + } + /> + + ); + }; + return ( - - - - modalRef.current?.present()}> - - - - - {tag.name} - - + + + + + {tag.name} + + + modalRef.current?.present()}> + + + + + )} ); @@ -102,7 +182,7 @@ const BrowseTags = () => { )} renderItem={({ item }) => ( - navigation.navigate('Tag', { id: item.id, color: item.color! }) diff --git a/apps/mobile/src/components/header/Header.tsx b/apps/mobile/src/components/header/Header.tsx index 0c48c07a0..0984f40cb 100644 --- a/apps/mobile/src/components/header/Header.tsx +++ b/apps/mobile/src/components/header/Header.tsx @@ -44,33 +44,6 @@ export default function Header({ const explorerStore = useExplorerStore(); const routeParams = route?.route.params as any; - const SearchType = () => { - switch (searchType) { - case 'explorer': - return 'Explorer'; //TODO - case 'location': - return ; - default: - return null; - } - }; - const HeaderIconKind = () => { - switch (headerKind) { - case 'location': - return ; - case 'tag': - return ( - - ); - default: - return null; - } - }; - return ( )} - + {showLibrary && } - {searchType && } + {searchType && } ); } + +interface HeaderSearchTypeProps { + searchType: HeaderProps['searchType']; +} + +const HeaderSearchType = ({ searchType }: HeaderSearchTypeProps) => { + switch (searchType) { + case 'explorer': + return 'Explorer'; //TODO + case 'location': + return ; + default: + return null; + } +}; + +interface HeaderIconKindProps { + headerKind: HeaderProps['headerKind']; + routeParams?: any; +} + +const HeaderIconKind = ({ headerKind, routeParams }: HeaderIconKindProps) => { + switch (headerKind) { + case 'location': + return ; + case 'tag': + return ( + + ); + default: + return null; + } +}; diff --git a/apps/mobile/src/components/overview/Categories.tsx b/apps/mobile/src/components/overview/Categories.tsx index 88d12d416..fd9a6b642 100644 --- a/apps/mobile/src/components/overview/Categories.tsx +++ b/apps/mobile/src/components/overview/Categories.tsx @@ -16,7 +16,7 @@ interface Props { const Categories = ({ kinds }: Props) => { return ( - Categories + Categories @@ -29,7 +29,7 @@ const Categories = ({ kinds }: Props) => { key={kinds.data?.statistics ? 'kinds' : '_'} //needed to update numColumns when data is available keyExtractor={(item) => item.name} scrollEnabled={false} - ItemSeparatorComponent={() => } + ItemSeparatorComponent={() => } showsHorizontalScrollIndicator={false} renderItem={({ item }) => { const { kind, name, count } = item; @@ -79,7 +79,7 @@ const KindItem = ({ name, icon, items }: KindItemProps) => { }} > - + {name} {items !== undefined && ( diff --git a/apps/mobile/src/components/overview/OverviewStats.tsx b/apps/mobile/src/components/overview/OverviewStats.tsx index 6eeca0150..642a14bf2 100644 --- a/apps/mobile/src/components/overview/OverviewStats.tsx +++ b/apps/mobile/src/components/overview/OverviewStats.tsx @@ -39,7 +39,7 @@ const StatItem = ({ title, bytes, isLoading, style }: StatItemProps) => { )} > {title} - + {count} {unit} diff --git a/apps/mobile/src/components/overview/StatCard.tsx b/apps/mobile/src/components/overview/StatCard.tsx index 190a824a0..adeaacc8e 100644 --- a/apps/mobile/src/components/overview/StatCard.tsx +++ b/apps/mobile/src/components/overview/StatCard.tsx @@ -58,7 +58,7 @@ const StatCard = ({ icon, name, connectionType, ...stats }: StatCardProps) => { - + {fill.toFixed(0)} diff --git a/apps/mobile/src/components/primitive/Button.tsx b/apps/mobile/src/components/primitive/Button.tsx index 29820c231..bce4674f0 100644 --- a/apps/mobile/src/components/primitive/Button.tsx +++ b/apps/mobile/src/components/primitive/Button.tsx @@ -30,6 +30,7 @@ const button = cva(['items-center justify-center rounded-md border shadow-sm'], }); type ButtonProps = VariantProps & PressableProps; +export type ButtonVariants = ButtonProps['variant']; export const Button: FC = ({ variant, size, disabled, ...props }) => { const { style, ...otherProps } = props; diff --git a/apps/mobile/src/components/settings/SettingsButton.tsx b/apps/mobile/src/components/settings/SettingsButton.tsx new file mode 100644 index 000000000..6fd6c886c --- /dev/null +++ b/apps/mobile/src/components/settings/SettingsButton.tsx @@ -0,0 +1,46 @@ +import { Text, View } from 'react-native'; +import { ClassInput } from 'twrnc/dist/esm/types'; +import { tw, twStyle } from '~/lib/tailwind'; + +import { Button, ButtonVariants } from '../primitive/Button'; + +interface Props { + buttonText: string; + title: string; + description?: string; + buttonPress?: () => void; + buttonVariant?: ButtonVariants; + buttonTextStyle?: string; + buttonIcon?: JSX.Element; + infoContainerStyle?: ClassInput; +} + +const SettingsButton = ({ + buttonText, + title, + description, + buttonVariant, + buttonTextStyle, + buttonIcon, + infoContainerStyle, + buttonPress +}: Props) => { + return ( + + + {title} + {description && {description}} + + + + ); +}; + +export default SettingsButton; diff --git a/apps/mobile/src/components/settings/SettingsContainer.tsx b/apps/mobile/src/components/settings/SettingsContainer.tsx index c24165ece..a67cca1c7 100644 --- a/apps/mobile/src/components/settings/SettingsContainer.tsx +++ b/apps/mobile/src/components/settings/SettingsContainer.tsx @@ -10,14 +10,12 @@ type SettingsContainerProps = PropsWithChildren<{ export function SettingsContainer({ children, title, description }: SettingsContainerProps) { return ( - {title && ( - {title} - )} + {title && {title}} {children} - {description && {description}} + {description && {description}} ); } -export const SettingsTitle = styled(Text, 'text-ink mb-1.5 ml-1 text-sm font-medium'); +export const SettingsTitle = styled(Text, 'text-ink text-sm font-medium'); export const SettingsInputInfo = styled(Text, 'mt-2 text-xs text-ink-faint'); diff --git a/apps/mobile/src/components/settings/SettingsToggle.tsx b/apps/mobile/src/components/settings/SettingsToggle.tsx new file mode 100644 index 000000000..bd672c048 --- /dev/null +++ b/apps/mobile/src/components/settings/SettingsToggle.tsx @@ -0,0 +1,65 @@ +import { useState } from 'react'; +import { Control, Controller } from 'react-hook-form'; +import { Switch, Text, View } from 'react-native'; +import { tw } from '~/lib/tailwind'; + +type Props = + | { + title: string; // Title of the setting + description?: string; // This is to display a description below the title + onEnabledChange?: (enabled: boolean) => void; // This is to receive the value of the toggle when it changes + control: Control; //Zod form control + name: string; //Name of the field for zod form controller + } + | { + title: string; + description?: string; + onEnabledChange?: (enabled: boolean) => void; + control?: never; + name?: never; + }; + +const SettingsToggle = ({ title, description, onEnabledChange, control, name }: Props) => { + const [isEnabled, setIsEnabled] = useState(false); + + return ( + + + {title} + {description && {description}} + + {control && name ? ( + ( + { + setIsEnabled(val); + onChange(val); + onEnabledChange?.(val); + }} + /> + )} + /> + ) : ( + { + setIsEnabled((prev) => !prev); + onEnabledChange?.(!isEnabled); + }} + /> + )} + + ); +}; + +export default SettingsToggle; diff --git a/apps/mobile/src/navigation/tabs/SettingsStack.tsx b/apps/mobile/src/navigation/tabs/SettingsStack.tsx index 99c3c082c..57a39ed8f 100644 --- a/apps/mobile/src/navigation/tabs/SettingsStack.tsx +++ b/apps/mobile/src/navigation/tabs/SettingsStack.tsx @@ -43,55 +43,55 @@ export default function SettingsStack() {
}} />
}} />
}} />
}} />
}} /> {/* Library */}
}} />
+ }} />
}} />
}} />
}} /> {/* */} {/* Info */} - +
}} + />
}} + /> +
}} /> - ); } diff --git a/apps/mobile/src/screens/Locations.tsx b/apps/mobile/src/screens/Locations.tsx index c20400d8a..1cbc565e5 100644 --- a/apps/mobile/src/screens/Locations.tsx +++ b/apps/mobile/src/screens/Locations.tsx @@ -1,7 +1,8 @@ import { useNavigation } from '@react-navigation/native'; -import { DotsThreeOutlineVertical } from 'phosphor-react-native'; +import { DotsThreeOutlineVertical, Pen, Plus, Trash } from 'phosphor-react-native'; import { useMemo, useRef } from 'react'; -import { FlatList, Pressable, Text, View } from 'react-native'; +import { Animated, FlatList, Pressable, Text, View } from 'react-native'; +import { Swipeable } from 'react-native-gesture-handler'; import { useDebounce } from 'use-debounce'; import { arraysEqual, @@ -16,17 +17,24 @@ import FolderIcon from '~/components/icons/FolderIcon'; import Fade from '~/components/layout/Fade'; import { ModalRef } from '~/components/layout/Modal'; import ScreenContainer from '~/components/layout/ScreenContainer'; +import DeleteLocationModal from '~/components/modal/confirmModals/DeleteLocationModal'; +import ImportModal from '~/components/modal/ImportModal'; import { LocationModal } from '~/components/modal/location/LocationModal'; import { tw, twStyle } from '~/lib/tailwind'; import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack'; import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; import { useSearchStore } from '~/stores/searchStore'; -export const Locations = () => { +interface Props { + redirectToLocationSettings?: boolean; +} + +export const Locations = ({ redirectToLocationSettings }: Props) => { const locationsQuery = useLibraryQuery(['locations.list']); useNodes(locationsQuery.data?.nodes); const locations = useCache(locationsQuery.data?.items); const { search } = useSearchStore(); + const modalRef = useRef(null); const [debouncedSearch] = useDebounce(search, 200); const filteredLocations = useMemo( () => @@ -41,7 +49,15 @@ export const Locations = () => { SettingsStackScreenProps<'Settings'>['navigation'] >(); return ( - + + { + modalRef.current?.present(); + }} + > + + { showsVerticalScrollIndicator={false} renderItem={({ item }) => ( navigation.navigate('SettingsStack', { screen: 'EditLocationSettings', params: { id: item.id } }) } - onPress={() => navigation.navigate('Location', { id: item.id })} + onPress={() => { + if (redirectToLocationSettings) { + navigation.navigate('SettingsStack', { + screen: 'EditLocationSettings', + params: { id: item.id } + }); + } else { + navigation.navigate('BrowseStack', { + screen: 'Location', + params: { id: item.id } + }); + } + }} location={item} /> )} /> + ); }; @@ -77,56 +107,109 @@ interface LocationItemProps { location: Location; onPress: () => void; editLocation: () => void; + navigation: SettingsStackScreenProps<'LocationSettings'>['navigation']; } -const LocationItem: React.FC = ({ +export const LocationItem = ({ location, editLocation, - onPress + onPress, + navigation }: LocationItemProps) => { const onlineLocations = useOnlineLocations(); const online = onlineLocations.some((l) => arraysEqual(location.pub_id, l)); const modalRef = useRef(null); + + const renderRightActions = ( + progress: Animated.AnimatedInterpolation, + _: any, + swipeable: Swipeable + ) => { + const translate = progress.interpolate({ + inputRange: [0, 1], + outputRange: [100, 0], + extrapolate: 'clamp' + }); + + return ( + + { + navigation.navigate('EditLocationSettings', { id: location.id }); + swipeable.close(); + }} + > + + + + + + } + /> + + ); + }; + return ( - - - - - + + + + + + + + + {location.name} + + + {location.path} + + - - {location.name} - - - - - - {`${byteSize(location.size_in_bytes)}`} - + + + + {`${byteSize(location.size_in_bytes)}`} + + + modalRef.current?.present()}> + + - modalRef.current?.present()}> - - - + { editLocation(); diff --git a/apps/mobile/src/screens/Tags.tsx b/apps/mobile/src/screens/Tags.tsx index e092e5bd8..805237210 100644 --- a/apps/mobile/src/screens/Tags.tsx +++ b/apps/mobile/src/screens/Tags.tsx @@ -1,21 +1,38 @@ import { useNavigation } from '@react-navigation/native'; -import { View } from 'react-native'; +import { Plus } from 'phosphor-react-native'; +import { useRef } from 'react'; +import { Pressable, View } from 'react-native'; import { FlatList } from 'react-native-gesture-handler'; import { useCache, useLibraryQuery, useNodes } from '@sd/client'; -import { BrowseTagItem } from '~/components/browse/BrowseTags'; +import { TagItem } from '~/components/browse/BrowseTags'; import Fade from '~/components/layout/Fade'; +import { ModalRef } from '~/components/layout/Modal'; import ScreenContainer from '~/components/layout/ScreenContainer'; -import { tw } from '~/lib/tailwind'; +import CreateTagModal from '~/components/modal/tag/CreateTagModal'; +import { tw, twStyle } from '~/lib/tailwind'; import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack'; -export default function Tags() { +interface Props { + viewStyle?: 'grid' | 'list'; +} + +export default function Tags({ viewStyle = 'list' }: Props) { const tags = useLibraryQuery(['tags.list']); const navigation = useNavigation['navigation']>(); + const modalRef = useRef(null); useNodes(tags.data?.nodes); const tagData = useCache(tags.data?.items); return ( - + + { + modalRef.current?.present(); + }} + > + + ( - - navigation.navigate('Tag', { id: item.id, color: item.color! }) - } + onPress={() => { + navigation.navigate('BrowseStack', { + screen: 'Tag', + params: { id: item.id, color: item.color! } + }); + }} /> )} - numColumns={3} - columnWrapperStyle={tw`gap-2.5`} + numColumns={viewStyle === 'grid' ? 3 : 1} + columnWrapperStyle={viewStyle === 'grid' && tw`justify-between`} horizontal={false} keyExtractor={(item) => item.id.toString()} showsHorizontalScrollIndicator={false} @@ -43,6 +64,7 @@ export default function Tags() { contentContainerStyle={tw`py-5`} /> + ); } diff --git a/apps/mobile/src/screens/network/index.tsx b/apps/mobile/src/screens/network/index.tsx index 61397c3d0..92e7ed22c 100644 --- a/apps/mobile/src/screens/network/index.tsx +++ b/apps/mobile/src/screens/network/index.tsx @@ -9,7 +9,7 @@ export default function NetworkScreen({ navigation }: NetworkStackScreenProps<'N Your Local Network - + Other Spacedrive nodes on your LAN will appear here, along with your default OS network mounts. diff --git a/apps/mobile/src/screens/settings/Settings.tsx b/apps/mobile/src/screens/settings/Settings.tsx index 69f446903..1fadbf874 100644 --- a/apps/mobile/src/screens/settings/Settings.tsx +++ b/apps/mobile/src/screens/settings/Settings.tsx @@ -141,10 +141,10 @@ export default function SettingsScreen({ navigation }: SettingsStackScreenProps< const debugState = useDebugState(); return ( - + ( + @@ -103,7 +104,7 @@ function SystemTheme(props: { isSelected: boolean }) { {/* Checkmark */} {props.isSelected && ( - - Theme - - - {themes.map((theme) => ( - setSelectedTheme(theme.themeValue)} - > - {theme.themeValue === 'system' ? ( - - ) : ( - - )} - - {theme.themeName} - - - ))} - - - + + Theme + + {themes.map((theme) => ( + setSelectedTheme(theme.themeValue)} + > + {theme.themeValue === 'system' ? ( + + ) : ( + + )} + + {theme.themeName} + + + ))} + + ); }; diff --git a/apps/mobile/src/screens/settings/client/ExtensionsSettings.tsx b/apps/mobile/src/screens/settings/client/ExtensionsSettings.tsx index 3f4fae101..8dbb36cfa 100644 --- a/apps/mobile/src/screens/settings/client/ExtensionsSettings.tsx +++ b/apps/mobile/src/screens/settings/client/ExtensionsSettings.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { Text, View } from 'react-native'; +import ScreenContainer from '~/components/layout/ScreenContainer'; import { tw } from '~/lib/tailwind'; import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; @@ -7,9 +8,9 @@ const ExtensionsSettingsScreen = ({ navigation }: SettingsStackScreenProps<'ExtensionsSettings'>) => { return ( - + TODO - + ); }; diff --git a/apps/mobile/src/screens/settings/client/GeneralSettings.tsx b/apps/mobile/src/screens/settings/client/GeneralSettings.tsx index 9e5c5f24e..6cfce95cb 100644 --- a/apps/mobile/src/screens/settings/client/GeneralSettings.tsx +++ b/apps/mobile/src/screens/settings/client/GeneralSettings.tsx @@ -2,6 +2,7 @@ import { Text, View } from 'react-native'; import { useBridgeQuery, useDebugState } from '@sd/client'; import { Input } from '~/components/form/Input'; import Card from '~/components/layout/Card'; +import ScreenContainer from '~/components/layout/ScreenContainer'; import { Divider } from '~/components/primitive/Divider'; import { SettingsTitle } from '~/components/settings/SettingsContainer'; import { tw } from '~/lib/tailwind'; @@ -15,7 +16,7 @@ const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'General if (!node) return null; return ( - + {/* Card Header */} @@ -34,9 +35,9 @@ const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'General {/* Divider */} {/* Node Name and Port */} - Node Name + Node Name - Node Port + Node Port {debugState.enabled && ( @@ -45,12 +46,12 @@ const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'General Debug {/* Divider */} - Data Folder + Data Folder {/* Useful for simulator, not so for real devices. */} )} - + ); }; diff --git a/apps/mobile/src/screens/settings/client/LibrarySettings.tsx b/apps/mobile/src/screens/settings/client/LibrarySettings.tsx index a4b5c742c..fa8c9a1de 100644 --- a/apps/mobile/src/screens/settings/client/LibrarySettings.tsx +++ b/apps/mobile/src/screens/settings/client/LibrarySettings.tsx @@ -3,7 +3,9 @@ import React, { useEffect, useRef } from 'react'; import { Animated, FlatList, Text, View } from 'react-native'; import { Swipeable } from 'react-native-gesture-handler'; import { LibraryConfigWrapped, useBridgeQuery, useCache, useNodes } from '@sd/client'; +import Fade from '~/components/layout/Fade'; import { ModalRef } from '~/components/layout/Modal'; +import ScreenContainer from '~/components/layout/ScreenContainer'; import DeleteLibraryModal from '~/components/modal/confirmModals/DeleteLibraryModal'; import { AnimatedButton, FakeButton } from '~/components/primitive/Button'; import { tw, twStyle } from '~/lib/tailwind'; @@ -56,12 +58,12 @@ function LibraryItem({ enableTrackpadTwoFingerGesture renderRightActions={renderRightActions} > - + - {library.config.name} - {library.uuid} + {library.config.name} + {library.uuid} - + ); @@ -90,15 +92,24 @@ const LibrarySettingsScreen = ({ navigation }: SettingsStackScreenProps<'Library const modalRef = useRef(null); return ( - - item.uuid} - renderItem={({ item, index }) => ( - - )} - /> - + + + item.uuid} + renderItem={({ item, index }) => ( + + )} + /> + + ); }; diff --git a/apps/mobile/src/screens/settings/client/PrivacySettings.tsx b/apps/mobile/src/screens/settings/client/PrivacySettings.tsx index dcd8cc609..944a350a7 100644 --- a/apps/mobile/src/screens/settings/client/PrivacySettings.tsx +++ b/apps/mobile/src/screens/settings/client/PrivacySettings.tsx @@ -1,12 +1,13 @@ import React from 'react'; import { Text, View } from 'react-native'; +import ScreenContainer from '~/components/layout/ScreenContainer'; import { tw } from '~/lib/tailwind'; const PrivacySettingsScreen = () => { return ( - + TODO - + ); }; diff --git a/apps/mobile/src/screens/settings/info/About.tsx b/apps/mobile/src/screens/settings/info/About.tsx index 0ad8610f5..5e790745e 100644 --- a/apps/mobile/src/screens/settings/info/About.tsx +++ b/apps/mobile/src/screens/settings/info/About.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { Image, Linking, Platform, Text, View } from 'react-native'; import { useBridgeQuery } from '@sd/client'; import { DiscordIcon, GitHubIcon } from '~/components/icons/Brands'; +import ScreenContainer from '~/components/layout/ScreenContainer'; import { Button } from '~/components/primitive/Button'; import { Divider } from '~/components/primitive/Divider'; import { tw } from '~/lib/tailwind'; @@ -11,7 +12,7 @@ const AboutScreen = () => { const buildInfo = useBridgeQuery(['buildInfo']); return ( - + { - Join Discord + Join Discord {/* GitHub Button */} {/* Website Button */} @@ -68,9 +69,9 @@ const AboutScreen = () => { variant="accent" > - + - Website + Website @@ -92,16 +93,16 @@ const AboutScreen = () => { Meet the contributors behind Spacedrive - {/* For some reason, it won't load. ¯\_(ツ)_/¯ */} + {/* Temporary image url approach until a solution is reached */} - + ); }; diff --git a/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx b/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx index 0ddb12afa..c497237a7 100644 --- a/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx +++ b/apps/mobile/src/screens/settings/library/EditLocationSettings.tsx @@ -2,20 +2,16 @@ import { useQueryClient } from '@tanstack/react-query'; import { Archive, ArrowsClockwise, Trash } from 'phosphor-react-native'; import { useEffect } from 'react'; import { Controller } from 'react-hook-form'; -import { Alert, ScrollView, Text, View } from 'react-native'; +import { Alert, Text, View } from 'react-native'; import { z } from 'zod'; import { useLibraryMutation, useLibraryQuery, useNormalisedCache, useZodForm } from '@sd/client'; import { Input } from '~/components/form/Input'; -import { Switch } from '~/components/form/Switch'; -import DeleteLocationModal from '~/components/modal/confirmModals/DeleteLocationModal'; -import { AnimatedButton, FakeButton } from '~/components/primitive/Button'; +import ScreenContainer from '~/components/layout/ScreenContainer'; +import { AnimatedButton } from '~/components/primitive/Button'; import { Divider } from '~/components/primitive/Divider'; -import { - SettingsContainer, - SettingsInputInfo, - SettingsTitle -} from '~/components/settings/SettingsContainer'; -import { SettingsItem } from '~/components/settings/SettingsItem'; +import SettingsButton from '~/components/settings/SettingsButton'; +import { SettingsInputInfo, SettingsTitle } from '~/components/settings/SettingsContainer'; +import SettingsToggle from '~/components/settings/SettingsToggle'; import { tw, twStyle } from '~/lib/tailwind'; import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; @@ -113,10 +109,10 @@ const EditLocationSettingsScreen = ({ const fullRescan = useLibraryMutation('locations.fullRescan'); return ( - + {/* Inputs */} - - Display Name + + Display Name - Local Path + Local Path {/* Switches */} - - ( - - )} - /> - } - /> - ( - - )} - /> - } - /> - ( - - )} - /> - } - /> - + + + - {/* Indexer Rules */} - TODO: Indexer Rules {/* Buttons */} - - - fullRescan.mutate({ location_id: id, reidentify_objects: true }) - } - > - - - } - /> - - - Alert.alert('Archiving locations is coming soon...')} - > - - - } - /> - - - - - - } - /> - } - /> - + + fullRescan.mutate({ location_id: id, reidentify_objects: true }) + } + buttonText="Full Reindex" + buttonIcon={} + buttonTextStyle="text-white font-bold" + buttonVariant="outline" + infoContainerStyle={'w-[50%]'} + /> + } + buttonPress={() => Alert.alert('Archiving locations is coming soon...')} + buttonVariant="outline" + buttonTextStyle="text-white font-bold" + infoContainerStyle={'w-[60%]'} + /> + } + buttonPress={() => Alert.alert('Deleting locations is coming soon...')} + buttonVariant="danger" + buttonTextStyle="text-white font-bold" + infoContainerStyle={'w-[60%]'} + /> + {/* Indexer Rules */} + + TODO: Indexer Rules + - + ); }; diff --git a/apps/mobile/src/screens/settings/library/LibraryGeneralSettings.tsx b/apps/mobile/src/screens/settings/library/LibraryGeneralSettings.tsx index 51686d538..9b3d31faf 100644 --- a/apps/mobile/src/screens/settings/library/LibraryGeneralSettings.tsx +++ b/apps/mobile/src/screens/settings/library/LibraryGeneralSettings.tsx @@ -1,16 +1,16 @@ -import { Trash } from 'phosphor-react-native'; -import React from 'react'; import { Controller } from 'react-hook-form'; -import { Alert, Text, View } from 'react-native'; +import { Text, View } from 'react-native'; +import { TouchableOpacity } from 'react-native-gesture-handler'; import { z } from 'zod'; import { useBridgeMutation, useLibraryContext, useZodForm } from '@sd/client'; import { Input } from '~/components/form/Input'; -import { Switch } from '~/components/form/Switch'; +import ScreenContainer from '~/components/layout/ScreenContainer'; import DeleteLibraryModal from '~/components/modal/confirmModals/DeleteLibraryModal'; -import { FakeButton } from '~/components/primitive/Button'; +import { Button } from '~/components/primitive/Button'; import { Divider } from '~/components/primitive/Divider'; -import { SettingsContainer, SettingsTitle } from '~/components/settings/SettingsContainer'; -import { SettingsItem } from '~/components/settings/SettingsItem'; +import SettingsButton from '~/components/settings/SettingsButton'; +import { SettingsTitle } from '~/components/settings/SettingsContainer'; +import SettingsToggle from '~/components/settings/SettingsToggle'; import { useAutoForm } from '~/hooks/useAutoForm'; import { tw } from '~/lib/tailwind'; import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; @@ -37,9 +37,9 @@ const LibraryGeneralSettingsScreen = (_: SettingsStackScreenProps<'LibraryGenera }); return ( - - - Name + + + Name )} /> - {/* Description */} - Description + Description {/* Encrypt */} - - } /> - + { + //TODO: Enable encryption + }} + title="Encrypt Library" + description="Enable encryption for this library, this will only encrypt the Spacedrive database, not the files themselves." + /> {/* Export */} - Alert.alert('TODO')} /> + { + //TODO: Export library + }} + buttonTextStyle="font-bold text-ink-dull" + title="Export Library" + /> {/* Delete Library */} - Delete} libraryUuid={library.uuid} /> + + + Delete Library + + This is permanent, your files not be deleted, only the Spacedrive + library. + + + + + + } + libraryUuid={library.uuid} + /> + - + ); }; diff --git a/apps/mobile/src/screens/settings/library/LocationSettings.tsx b/apps/mobile/src/screens/settings/library/LocationSettings.tsx index 1b1299432..e963ca390 100644 --- a/apps/mobile/src/screens/settings/library/LocationSettings.tsx +++ b/apps/mobile/src/screens/settings/library/LocationSettings.tsx @@ -1,170 +1,7 @@ -import { CaretRight, Pen, Repeat, Trash } from 'phosphor-react-native'; -import { useEffect, useRef } from 'react'; -import { Animated, FlatList, Pressable, Text, View } from 'react-native'; -import { Swipeable } from 'react-native-gesture-handler'; -import { - arraysEqual, - Location, - useCache, - useLibraryMutation, - useLibraryQuery, - useNodes, - useOnlineLocations -} from '@sd/client'; -import FolderIcon from '~/components/icons/FolderIcon'; -import { ModalRef } from '~/components/layout/Modal'; -import DeleteLocationModal from '~/components/modal/confirmModals/DeleteLocationModal'; -import ImportModal from '~/components/modal/ImportModal'; -import { AnimatedButton } from '~/components/primitive/Button'; -import { tw, twStyle } from '~/lib/tailwind'; -import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; +import { Locations } from '~/screens/Locations'; -type LocationItemProps = { - location: Location; - index: number; - navigation: SettingsStackScreenProps<'LocationSettings'>['navigation']; -}; - -function LocationItem({ location, index, navigation }: LocationItemProps) { - const fullRescan = useLibraryMutation('locations.fullRescan', { - onMutate: () => { - // TODO: Show Toast - } - }); - - const onlineLocations = useOnlineLocations(); - - const renderRightActions = ( - progress: Animated.AnimatedInterpolation, - _: any, - swipeable: Swipeable - ) => { - const translate = progress.interpolate({ - inputRange: [0, 1], - outputRange: [100, 0], - extrapolate: 'clamp' - }); - - return ( - - { - navigation.navigate('EditLocationSettings', { id: location.id }); - swipeable.close(); - }} - > - - - - - - } - /> - {/* Full Re-scan IS too much here */} - - fullRescan.mutate({ location_id: location.id, reidentify_objects: true }) - } - > - - - - ); - }; - - return ( - - - - - {/* Online/Offline Indicator */} - arraysEqual(location.pub_id, l)) - ? 'bg-green-500' - : 'bg-red-500' - )} - /> - - - - {location.name} - - {/* // TODO: This is ephemeral so it should not come from the DB. Eg. a external USB can move between nodes */} - {/* {location.node && ( - - - {location.node.name} - - - )} */} - - {location.path} - - - - - - ); -} - -const LocationSettingsScreen = ({ navigation }: SettingsStackScreenProps<'LocationSettings'>) => { - const result = useLibraryQuery(['locations.list']); - useNodes(result.data?.nodes); - const locations = useCache(result.data?.items); - - useEffect(() => { - navigation.setOptions({ - headerRight: () => ( - modalRef.current?.present()} - > - New - - ) - }); - }, [navigation]); - - const modalRef = useRef(null); - - return ( - - item.id.toString()} - renderItem={({ item, index }) => ( - - )} - /> - - - ); +const LocationSettingsScreen = () => { + return ; }; export default LocationSettingsScreen; diff --git a/apps/mobile/src/screens/settings/library/NodesSettings.tsx b/apps/mobile/src/screens/settings/library/NodesSettings.tsx index dfc07b0e2..51ee8e642 100644 --- a/apps/mobile/src/screens/settings/library/NodesSettings.tsx +++ b/apps/mobile/src/screens/settings/library/NodesSettings.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Text, View } from 'react-native'; -import { isEnabled, useBridgeMutation, useDiscoveredPeers } from '@sd/client'; -import { Button } from '~/components/primitive/Button'; +import { useDiscoveredPeers } from '@sd/client'; +import ScreenContainer from '~/components/layout/ScreenContainer'; import { tw } from '~/lib/tailwind'; import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; @@ -9,7 +9,7 @@ const NodesSettingsScreen = ({ navigation }: SettingsStackScreenProps<'NodesSett const onlineNodes = useDiscoveredPeers(); return ( - + Pairing {[...onlineNodes.entries()].map(([id, node]) => ( @@ -17,7 +17,7 @@ const NodesSettingsScreen = ({ navigation }: SettingsStackScreenProps<'NodesSett {node.name} ))} - + ); }; diff --git a/apps/mobile/src/screens/settings/library/TagsSettings.tsx b/apps/mobile/src/screens/settings/library/TagsSettings.tsx index b33bc46b7..320f814a2 100644 --- a/apps/mobile/src/screens/settings/library/TagsSettings.tsx +++ b/apps/mobile/src/screens/settings/library/TagsSettings.tsx @@ -1,105 +1,16 @@ -import { CaretRight, Pen, Trash } from 'phosphor-react-native'; -import { useEffect, useRef } from 'react'; -import { Animated, FlatList, Text, View } from 'react-native'; -import { Swipeable } from 'react-native-gesture-handler'; -import { Tag, useCache, useLibraryQuery, useNodes } from '@sd/client'; +import { useRef } from 'react'; import { ModalRef } from '~/components/layout/Modal'; -import DeleteTagModal from '~/components/modal/confirmModals/DeleteTagModal'; import CreateTagModal from '~/components/modal/tag/CreateTagModal'; -import UpdateTagModal from '~/components/modal/tag/UpdateTagModal'; -import { AnimatedButton, FakeButton } from '~/components/primitive/Button'; -import { tw, twStyle } from '~/lib/tailwind'; -import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack'; - -function TagItem({ tag, index }: { tag: Tag; index: number }) { - const modalRef = useRef(null); - - const renderRightActions = ( - progress: Animated.AnimatedInterpolation, - _dragX: Animated.AnimatedInterpolation, - swipeable: Swipeable - ) => { - const translate = progress.interpolate({ - inputRange: [0, 1], - outputRange: [100, 0], - extrapolate: 'clamp' - }); - - return ( - - swipeable.close()} /> - modalRef.current?.present()}> - - - - - - } - /> - - ); - }; - - return ( - - - - - {tag.name} - - - - - ); -} - -// TODO: Add "New Tag" button - -const TagsSettingsScreen = ({ navigation }: SettingsStackScreenProps<'TagsSettings'>) => { - const result = useLibraryQuery(['tags.list']); - useNodes(result.data?.nodes); - const tags = useCache(result.data?.items); - - useEffect(() => { - navigation.setOptions({ - headerRight: () => ( - modalRef.current?.present()} - > - New - - ) - }); - }, [navigation]); +import Tags from '~/screens/Tags'; +const TagsSettingsScreen = () => { const modalRef = useRef(null); return ( - - item.id.toString()} - renderItem={({ item, index }) => } - /> + <> + - + ); };