code cleanup, design tweaks

This commit is contained in:
ameer2468 2024-06-11 19:53:28 +03:00
parent 712ea1d411
commit 80a379d202
3 changed files with 142 additions and 123 deletions

View file

@ -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;

View file

@ -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>
);
};

View file

@ -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>