mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-06 23:43:32 +00:00
code cleanup, design tweaks
This commit is contained in:
parent
712ea1d411
commit
80a379d202
|
@ -1,9 +1,9 @@
|
|||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { AppLogo } from '@sd/assets/images';
|
||||
import { useLibraryMutation } from '@sd/client';
|
||||
import { Image } from 'expo-image';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Dimensions, StyleSheet, Text, View } from 'react-native';
|
||||
import { Dimensions, Text, View } from 'react-native';
|
||||
import Animated, {
|
||||
Easing,
|
||||
useAnimatedStyle,
|
||||
|
@ -12,9 +12,7 @@ import Animated, {
|
|||
withTiming
|
||||
} from 'react-native-reanimated';
|
||||
import { Circle, Defs, RadialGradient, Stop, Svg } from 'react-native-svg';
|
||||
import { useLibraryMutation, useLibraryQuery } from '@sd/client';
|
||||
import { BackfillWaitingStackScreenProps } from '~/navigation/BackfillWaitingStack';
|
||||
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
|
||||
|
@ -36,29 +34,33 @@ const BackfillWaiting = () => {
|
|||
};
|
||||
});
|
||||
|
||||
const enableSync = useLibraryMutation(['sync.backfill'], {});
|
||||
const enableSync = useLibraryMutation(['sync.backfill'], {
|
||||
onSuccess: () => {
|
||||
navigation.navigate('Root', {
|
||||
screen: 'Home',
|
||||
params: {
|
||||
screen: 'SettingsStack',
|
||||
params: {
|
||||
screen: 'SyncSettings'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
async function _() {
|
||||
await enableSync.mutateAsync(null).then(() =>
|
||||
navigation.navigate('Root', {
|
||||
screen: 'Home',
|
||||
params: {
|
||||
screen: 'SettingsStack',
|
||||
params: {
|
||||
screen: 'SyncSettings'
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
_();
|
||||
(async () => {
|
||||
await enableSync.mutateAsync(null);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Animated.View style={[styles.gradientContainer, animatedStyle]}>
|
||||
<View style={tw`flex-1 items-center justify-center bg-black`}>
|
||||
<Animated.View style={[twStyle(`absolute items-center justify-center`, {
|
||||
width: width * 2,
|
||||
height: width * 2,
|
||||
borderRadius: (width * 0.8) / 2,
|
||||
}), animatedStyle]}>
|
||||
<Svg height="100%" width="100%" viewBox="0 0 100 100">
|
||||
<Defs>
|
||||
<RadialGradient id="grad" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
|
||||
|
@ -69,47 +71,14 @@ const BackfillWaiting = () => {
|
|||
<Circle cx="50" cy="50" r="50" fill="url(#grad)" />
|
||||
</Svg>
|
||||
</Animated.View>
|
||||
<Image source={AppLogo} style={styles.icon} />
|
||||
<Text style={styles.text}>
|
||||
<Image source={AppLogo} style={tw`mb-4 h-[100px] w-[100px]`} />
|
||||
<Text style={tw`mx-10 mb-4 text-center text-md leading-6 text-ink`}>
|
||||
Library is being backfilled right now for Sync!
|
||||
<Text style={styles.boldText}> Please hold </Text>
|
||||
<Text style={tw`font-bold`}> Please hold </Text>
|
||||
while this process takes place.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#000000', // Black background
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
gradientContainer: {
|
||||
position: 'absolute',
|
||||
width: width * 2, // Adjust the size of the circular gradient
|
||||
height: width * 2, // Keep the aspect ratio to make it circular
|
||||
borderRadius: (width * 0.8) / 2,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
icon: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
marginBottom: 20
|
||||
},
|
||||
text: {
|
||||
color: '#FFFFFF',
|
||||
textAlign: 'center',
|
||||
marginHorizontal: 40,
|
||||
marginBottom: 20,
|
||||
fontSize: 16,
|
||||
lineHeight: 24
|
||||
},
|
||||
boldText: {
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
});
|
||||
|
||||
export default BackfillWaiting;
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Button } from '~/components/primitive/Button';
|
|||
import { Divider } from '~/components/primitive/Divider';
|
||||
import { SettingsTitle } from '~/components/settings/SettingsContainer';
|
||||
import { styled, tw, twStyle } from '~/lib/tailwind';
|
||||
import { cancel, login, useAuthStateSnapshot } from '~/stores/auth';
|
||||
import { cancel, login, logout, useAuthStateSnapshot } from '~/stores/auth';
|
||||
|
||||
const InfoBox = styled(View, 'rounded-md border border-app bg-transparent p-2');
|
||||
|
||||
|
@ -22,14 +22,14 @@ const CloudSettings = () => {
|
|||
const AuthSensitiveChild = () => {
|
||||
const authState = useAuthStateSnapshot();
|
||||
if (authState.status === 'loggedIn') return <Authenticated />;
|
||||
if (authState.status === 'notLoggedIn' || authState.status === 'loggingIn')
|
||||
return <Login />;
|
||||
if (authState.status === 'notLoggedIn' || authState.status === 'loggingIn') return <Login />;
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const Authenticated = () => {
|
||||
const { library } = useLibraryContext();
|
||||
const authState = useAuthStateSnapshot();
|
||||
|
||||
const cloudLibrary = useLibraryQuery(['cloud.library.get'], { suspense: true, retry: false });
|
||||
|
||||
|
@ -39,61 +39,86 @@ const Authenticated = () => {
|
|||
const thisInstance = cloudLibrary.data?.instances.find(
|
||||
(instance) => instance.uuid === library.instance_id
|
||||
);
|
||||
const cloudInstances = cloudLibrary.data?.instances
|
||||
.filter((instance) => instance.uuid !== library.instance_id)
|
||||
const cloudInstances = cloudLibrary.data?.instances.filter(
|
||||
(instance) => instance.uuid !== library.instance_id
|
||||
);
|
||||
|
||||
return (
|
||||
<ScreenContainer tabHeight={false}>
|
||||
{cloudLibrary.data ? (
|
||||
<View style={tw`flex-col items-start gap-5`}>
|
||||
<Card style={tw`w-full`}>
|
||||
<Text style={tw`font-semibold text-ink`}>Library</Text>
|
||||
<Divider style={tw`mb-4 mt-2`}/>
|
||||
<View style={tw`flex-row items-center justify-between`}>
|
||||
<Text style={tw`font-medium text-ink`}>Library</Text>
|
||||
{authState.status === 'loggedIn' && (
|
||||
<Button
|
||||
variant="gray"
|
||||
size="sm"
|
||||
onPress={logout}
|
||||
>
|
||||
<Text style={tw`text-xs font-semibold text-ink`}>Logout</Text>
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
<Divider style={tw`mt-2 mb-4`}/>
|
||||
<SettingsTitle style={tw`mb-1`}>Name</SettingsTitle>
|
||||
<InfoBox>
|
||||
<Text style={tw`text-ink`}>{cloudLibrary.data.name}</Text>
|
||||
</InfoBox>
|
||||
<Button
|
||||
disabled={syncLibrary.isLoading}
|
||||
variant="accent"
|
||||
style={tw`mt-2`}
|
||||
onPress={() => {
|
||||
syncLibrary.mutateAsync(null);
|
||||
}}
|
||||
>
|
||||
<Text style={tw`text-xs font-medium text-ink`}>Sync Library</Text>
|
||||
</Button>
|
||||
<Button
|
||||
disabled={syncLibrary.isLoading}
|
||||
variant="accent"
|
||||
style={tw`mt-2`}
|
||||
onPress={() => syncLibrary.mutateAsync(null)}
|
||||
>
|
||||
<Text style={tw`text-xs font-semibold text-ink`}>Sync Library</Text>
|
||||
</Button>
|
||||
</Card>
|
||||
{thisInstance && (
|
||||
<Card style={tw`w-full`}>
|
||||
<Text style={tw`font-semibold text-ink`}>This Instance</Text>
|
||||
<Divider style={tw`mb-4 mt-2`}/>
|
||||
<SettingsTitle style={tw`mb-1 text-ink`}>Id</SettingsTitle>
|
||||
<Card style={tw`w-full gap-4`}>
|
||||
<View>
|
||||
<Text style={tw`mb-1 font-semibold text-ink`}>This Instance</Text>
|
||||
<Divider />
|
||||
</View>
|
||||
<View>
|
||||
<SettingsTitle style={tw`mb-2 text-ink`}>Id</SettingsTitle>
|
||||
<InfoBox>
|
||||
|
||||
<Text style={tw`text-ink-dull`}>{thisInstance.id}</Text>
|
||||
</InfoBox>
|
||||
<SettingsTitle style={tw`mb-1 mt-4`}>UUID</SettingsTitle>
|
||||
</View>
|
||||
<View>
|
||||
<SettingsTitle style={tw`mb-2`}>UUID</SettingsTitle>
|
||||
<InfoBox>
|
||||
<Text style={tw`text-ink-dull`}>{thisInstance.uuid}</Text>
|
||||
</InfoBox>
|
||||
<SettingsTitle style={tw`mb-1 mt-4`}>Public Key</SettingsTitle>
|
||||
</View>
|
||||
<View>
|
||||
<SettingsTitle style={tw`mb-2`}>Public Key</SettingsTitle>
|
||||
<InfoBox>
|
||||
<Text numberOfLines={1} style={tw`text-ink-dull`}>{thisInstance.identity}</Text>
|
||||
<Text numberOfLines={1} style={tw`text-ink-dull`}>
|
||||
{thisInstance.identity}
|
||||
</Text>
|
||||
</InfoBox>
|
||||
</View>
|
||||
</Card>
|
||||
)}
|
||||
<Card style={tw`w-full`}>
|
||||
<View style={tw`flex-row items-center gap-2`}>
|
||||
<View
|
||||
style={tw`self-start rounded border border-app-lightborder bg-app-highlight px-1.5 py-[2px]`}
|
||||
<View
|
||||
style={tw`self-start rounded border border-app-lightborder bg-app-highlight px-1.5 py-[2px]`}
|
||||
>
|
||||
<Text style={tw`text-xs font-semibold text-ink`}>
|
||||
{cloudInstances?.length}
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={tw`font-semibold text-ink`}>Instances</Text>
|
||||
</View>
|
||||
<Divider style={tw`mt-2 mb-4`} />
|
||||
<VirtualizedListWrapper
|
||||
scrollEnabled={false}
|
||||
contentContainerStyle={tw`flex-1`}
|
||||
horizontal
|
||||
>
|
||||
<Text style={tw`text-xs font-semibold text-ink`}>{cloudInstances?.length}</Text>
|
||||
</View>
|
||||
<Text style={tw`font-semibold text-ink`}>Instances</Text>
|
||||
</View>
|
||||
<Divider style={tw`mb-4 mt-2`}/>
|
||||
<VirtualizedListWrapper scrollEnabled={false} contentContainerStyle={tw`flex-1`} horizontal>
|
||||
<FlatList
|
||||
data={cloudInstances}
|
||||
scrollEnabled={false}
|
||||
|
@ -102,7 +127,7 @@ const Authenticated = () => {
|
|||
renderItem={({ item }) => <Instance data={item} length={cloudInstances?.length ?? 0} />}
|
||||
keyExtractor={(item) => item.id}
|
||||
numColumns={(cloudInstances?.length ?? 0) > 1 ? 2 : 1}
|
||||
{...(cloudInstances?.length ?? 0) > 1 ? {columnWrapperStyle: tw`w-full justify-between`} : {}}
|
||||
{...(cloudInstances?.length ?? 0) > 1 ? {columnWrapperStyle: tw`justify-between w-full`} : {}}
|
||||
/>
|
||||
</VirtualizedListWrapper>
|
||||
</Card>
|
||||
|
@ -114,7 +139,9 @@ const Authenticated = () => {
|
|||
onPress={async () => await createLibrary.mutateAsync(null)}
|
||||
>
|
||||
{createLibrary.isLoading ? (
|
||||
<Text style={tw`text-ink`}>Connecting library to Spacedrive Cloud...</Text>
|
||||
<Text style={tw`text-ink`}>
|
||||
Connecting library to Spacedrive Cloud...
|
||||
</Text>
|
||||
) : (
|
||||
<Text style={tw`text-ink`}>Connect library to Spacedrive Cloud</Text>
|
||||
)}
|
||||
|
@ -132,49 +159,60 @@ interface Props {
|
|||
|
||||
const Instance = ({data, length}: Props) => {
|
||||
return (
|
||||
<InfoBox style={twStyle(length > 1 ? 'w-[49%]' : 'w-full')}>
|
||||
<SettingsTitle style={tw`mb-1`}>Id</SettingsTitle>
|
||||
<InfoBox style={twStyle(length > 1 ? 'w-[49%]' : 'w-full', 'gap-4')}>
|
||||
<View>
|
||||
<SettingsTitle style={tw`mb-2`}>Id</SettingsTitle>
|
||||
<InfoBox>
|
||||
<Text numberOfLines={1} style={tw`text-ink-dull`}>{data.id}</Text>
|
||||
</InfoBox>
|
||||
<SettingsTitle style={tw`mb-1 mt-4`}>UUID</SettingsTitle>
|
||||
</View>
|
||||
<View>
|
||||
<SettingsTitle style={tw`mb-2`}>UUID</SettingsTitle>
|
||||
<InfoBox>
|
||||
<Text numberOfLines={1} style={tw`text-ink-dull`}>{data.uuid}</Text>
|
||||
</InfoBox>
|
||||
<SettingsTitle style={tw`mb-1 mt-4`}>Public Key</SettingsTitle>
|
||||
</View>
|
||||
<View>
|
||||
<SettingsTitle style={tw`mb-2`}>Public Key</SettingsTitle>
|
||||
<InfoBox>
|
||||
<Text numberOfLines={1} style={tw`text-ink-dull`}>{data.identity}</Text>
|
||||
</InfoBox>
|
||||
</View>
|
||||
</InfoBox>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const Login = () => {
|
||||
const authState = useAuthStateSnapshot();
|
||||
const buttonText = {
|
||||
notLoggedIn: 'Login',
|
||||
loggingIn: 'Cancel',
|
||||
}
|
||||
return (
|
||||
<View style={tw`flex flex-col items-center justify-center gap-2`}>
|
||||
<Button
|
||||
variant="accent"
|
||||
disabled={authState.status === 'loggingIn'}
|
||||
onPress={async (e) => {
|
||||
e.preventDefault();
|
||||
await login();
|
||||
}}
|
||||
>
|
||||
{authState.status !== 'loggingIn' ? <Text style={tw`text-ink`}>Login</Text> : <Text style={tw`text-ink`}>Logging In</Text>}
|
||||
</Button>
|
||||
{authState.status === 'loggingIn' && (
|
||||
<Button
|
||||
<View style={tw`flex-col items-center justify-center flex-1 gap-2`}>
|
||||
<Card style={tw`items-center justify-center w-full p-6`}>
|
||||
<Text style={tw`mb-4 max-w-[60%] text-center text-ink`}>
|
||||
To access cloud related features, please login
|
||||
</Text>
|
||||
{(authState.status === 'notLoggedIn' || authState.status === 'loggingIn') && (
|
||||
<Button
|
||||
variant="accent"
|
||||
style={tw`mx-auto max-w-[50%]`}
|
||||
onPress={async (e) => {
|
||||
e.preventDefault();
|
||||
await cancel();
|
||||
if (authState.status === 'loggingIn') {
|
||||
await cancel();
|
||||
} else {
|
||||
await login();
|
||||
}
|
||||
}}
|
||||
style={tw`text-sm text-ink-faint`}
|
||||
>
|
||||
<Text style={tw`text-ink`}>Cancel</Text>
|
||||
<Text style={tw`font-medium text-ink`}>
|
||||
{buttonText[authState.status]}
|
||||
</Text>
|
||||
</Button>
|
||||
)}
|
||||
</Card>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
useLibraryQuery,
|
||||
useLibrarySubscription
|
||||
} from '@sd/client';
|
||||
import { MotiView } from 'moti';
|
||||
import { Circle } from 'phosphor-react-native';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
|
@ -20,7 +21,9 @@ const SyncSettingsScreen = ({ navigation }: SettingsStackScreenProps<'SyncSettin
|
|||
|
||||
const [startBackfill, setStart] = useState(false);
|
||||
|
||||
useLibrarySubscription(['library.actors'], { onData: setData });
|
||||
useLibrarySubscription(['library.actors'], { onData: (data) => {
|
||||
setData(data);
|
||||
} });
|
||||
|
||||
useEffect(() => {
|
||||
if (startBackfill === true) {
|
||||
|
@ -43,11 +46,11 @@ const SyncSettingsScreen = ({ navigation }: SettingsStackScreenProps<'SyncSettin
|
|||
<View style={tw`flex-row flex-wrap gap-2`}>
|
||||
{Object.keys(data).map((key) => {
|
||||
return (
|
||||
<Card style={tw`w-[48%] flex-col gap-2`} key={key}>
|
||||
<Card style={tw`w-[48%]`} key={key}>
|
||||
<OnlineIndicator online={data[key] ?? false} />
|
||||
<Text
|
||||
key={key}
|
||||
style={tw`flex flex-col items-center justify-center text-left text-white`}
|
||||
style={tw`flex-col items-center justify-center mt-1 mb-3 text-left text-white`}
|
||||
>
|
||||
{key}
|
||||
</Text>
|
||||
|
@ -68,11 +71,18 @@ const SyncSettingsScreen = ({ navigation }: SettingsStackScreenProps<'SyncSettin
|
|||
export default SyncSettingsScreen;
|
||||
|
||||
function OnlineIndicator({ online }: { online: boolean }) {
|
||||
const size = 10;
|
||||
const size = 8;
|
||||
return (
|
||||
<View style={tw`items-center justify-center w-6 h-6 p-2 mb-1 border rounded-full border-app-inputborder bg-app-input`}>
|
||||
{online ? (
|
||||
<Circle size={size} color={tw.color('green-400')} weight="fill" />
|
||||
<View style={tw`relative items-center justify-center`}>
|
||||
<MotiView
|
||||
from={{ scale: 0 }}
|
||||
animate={{ scale: 1.5, opacity: 0 }}
|
||||
transition={{ type: 'timing', duration: 500, loop: true, delay: 500}}
|
||||
style={tw`absolute z-10 items-center justify-center w-2 h-2 bg-red-500 rounded-full`} />
|
||||
<View style={tw`w-2 h-2 bg-green-500 rounded-full`} />
|
||||
</View>
|
||||
) : (
|
||||
<Circle size={size} color={tw.color('red-400')} weight="fill" />
|
||||
)}
|
||||
|
@ -85,10 +95,11 @@ function StartButton({ name }: { name: string }) {
|
|||
return (
|
||||
<Button
|
||||
variant="accent"
|
||||
size="sm"
|
||||
disabled={startActor.isLoading}
|
||||
onPress={() => startActor.mutate(name)}
|
||||
>
|
||||
<Text style={tw`font-medium text-ink`}>
|
||||
<Text style={tw`text-xs font-medium text-ink`}>
|
||||
{startActor.isLoading ? 'Starting' : 'Start'}
|
||||
</Text>
|
||||
{startActor.isLoading ? <Text>Starting</Text> : <Text>Start</Text>}
|
||||
|
@ -101,10 +112,11 @@ function StopButton({ name }: { name: string }) {
|
|||
return (
|
||||
<Button
|
||||
variant="accent"
|
||||
size="sm"
|
||||
disabled={stopActor.isLoading}
|
||||
onPress={() => stopActor.mutate(name)}
|
||||
>
|
||||
<Text style={tw`font-medium text-ink`}>
|
||||
<Text style={tw`text-xs font-medium text-ink`}>
|
||||
{stopActor.isLoading ? 'Stopping' : 'Stop'}
|
||||
</Text>
|
||||
</Button>
|
||||
|
|
Loading…
Reference in a new issue