Finished BackfillWaiting page + initial auth setup

Also, setting up the cloud sync page.
This commit is contained in:
Arnab Chakraborty 2024-06-07 22:53:50 +05:30
parent a9ca9a47c2
commit ca4a22cd50
10 changed files with 283 additions and 57 deletions

View file

@ -1,17 +1,26 @@
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
import React from 'react';
import DynamicHeader from '~/components/header/DynamicHeader';
import Header from '~/components/header/Header';
import LocationScreen from '~/screens/browse/Location';
import FiltersScreen from '~/screens/search/Filters';
import SearchScreen from '~/screens/search/Search';
import BackfillWaiting from '~/screens/BackfillWaiting';
const Stack = createNativeStackNavigator();
const Stack = createNativeStackNavigator<BackfillWaitingStackParamList>();
export default function BackfillWaitingStack() {
return (
<Stack.Navigator initialRouteName="BackfillWaiting">
<></>
<Stack.Screen
name="BackfillWaiting"
component={BackfillWaiting}
options={{
headerShown: false
}}
/>
</Stack.Navigator>
);
}
export type BackfillWaitingStackParamList = {
BackfillWaiting: undefined;
};
export type BackfillWaitingStackScreenProps<Screen extends keyof BackfillWaitingStackParamList> =
NativeStackScreenProps<BackfillWaitingStackParamList, Screen>;

View file

@ -4,7 +4,7 @@ import NotFoundScreen from '~/screens/NotFound';
import DrawerNavigator, { DrawerNavParamList } from './DrawerNavigator';
import SearchStack, { SearchStackParamList } from './SearchStack';
import BackfillWaiting from '~/screens/settings/library/BackfillWaiting';
import BackfillWaitingStack, { BackfillWaitingStackParamList } from './BackfillWaitingStack';
const Stack = createNativeStackNavigator<RootStackParamList>();
// This is the main navigator we nest everything under.
@ -21,7 +21,11 @@ export default function RootNavigator() {
component={SearchStack}
options={{ headerShown: false }}
/>
<Stack.Screen name="BackfillWaiting" component={BackfillWaiting} options={{ headerShown: false }} />
<Stack.Screen
name="BackfillWaitingStack"
component={BackfillWaitingStack}
options={{ headerShown: false }}
/>
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
</Stack.Navigator>
);
@ -30,7 +34,7 @@ export default function RootNavigator() {
export type RootStackParamList = {
Root: NavigatorScreenParams<DrawerNavParamList>;
SearchStack: NavigatorScreenParams<SearchStackParamList>;
BackfillWaiting: undefined;
BackfillWaitingStack: NavigatorScreenParams<BackfillWaitingStackParamList>;
NotFound: undefined;
};

View file

@ -12,7 +12,7 @@ import PrivacySettingsScreen from '~/screens/settings/client/PrivacySettings';
import AboutScreen from '~/screens/settings/info/About';
import DebugScreen from '~/screens/settings/info/Debug';
import SupportScreen from '~/screens/settings/info/Support';
import BackfillWaiting from '~/screens/settings/library/BackfillWaiting';
import Cloud from '~/screens/settings/library/Cloud';
import EditLocationSettingsScreen from '~/screens/settings/library/EditLocationSettings';
import LibraryGeneralSettingsScreen from '~/screens/settings/library/LibraryGeneralSettings';
import LocationSettingsScreen from '~/screens/settings/library/LocationSettings';
@ -95,9 +95,9 @@ export default function SettingsStack() {
options={{ header: () => <Header navBack title="Sync" /> }}
/>
<Stack.Screen
name="BackfillWaiting"
component={BackfillWaiting}
options={{ header: () => <></> }}
name="Cloud"
component={Cloud}
options={{ header: () => <Header navBack title="Cloud" /> }}
/>
{/* <Stack.Screen
name="KeysSettings"
@ -144,7 +144,7 @@ export type SettingsStackParamList = {
TagsSettings: undefined;
KeysSettings: undefined;
SyncSettings: undefined;
BackfillWaiting: undefined;
Cloud: undefined;
// Info
About: undefined;
Support: undefined;

View file

@ -0,0 +1,115 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useNavigation } from '@react-navigation/native';
import { AppLogo } from '@sd/assets/images';
import { Image } from 'expo-image';
import React, { useEffect } from 'react';
import { Dimensions, StyleSheet, Text, View } from 'react-native';
import Animated, {
Easing,
useAnimatedStyle,
useSharedValue,
withRepeat,
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';
const { width } = Dimensions.get('window');
const BackfillWaiting = () => {
const animation = useSharedValue(0);
const navigation = useNavigation();
useEffect(() => {
animation.value = withRepeat(
withTiming(1, { duration: 5000, easing: Easing.inOut(Easing.ease) }),
-1,
true
);
}, [animation]);
const animatedStyle = useAnimatedStyle(() => {
return {
opacity: animation.value
};
});
const enableSync = useLibraryMutation(['sync.backfill'], {});
useEffect(() => {
async function _() {
await enableSync.mutateAsync(null).then(() =>
navigation.navigate('Root', {
screen: 'Home',
params: {
screen: 'SettingsStack',
params: {
screen: 'SyncSettings'
}
}
})
);
}
_();
}, []);
return (
<View style={styles.container}>
<Animated.View style={[styles.gradientContainer, 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%">
<Stop offset="0%" stopColor="#4B0082" stopOpacity="1" />
<Stop offset="100%" stopColor="#000000" stopOpacity="0" />
</RadialGradient>
</Defs>
<Circle cx="50" cy="50" r="50" fill="url(#grad)" />
</Svg>
</Animated.View>
<Image source={AppLogo} style={styles.icon} />
<Text style={styles.text}>
Library is being backfilled right now for Sync!
<Text style={styles.boldText}> 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

@ -1,6 +1,7 @@
import {
ArrowsClockwise,
Books,
Cloud,
FlyingSaucer,
Gear,
GearSix,
@ -88,6 +89,11 @@ const sections: (debugState: DebugState) => SectionType[] = (debugState) => [
navigateTo: 'TagsSettings',
title: 'Tags',
},
{
icon: Cloud,
navigateTo: 'Cloud',
title: 'Cloud',
},
{
icon: ArrowsClockwise,
navigateTo: 'SyncSettings',

View file

@ -1,6 +1,14 @@
import { useQueryClient } from '@tanstack/react-query';
import React from 'react';
import { Text, View } from 'react-native';
import { toggleFeatureFlag, useDebugState, useFeatureFlags } from '@sd/client';
import {
auth,
toggleFeatureFlag,
useBridgeMutation,
useBridgeQuery,
useDebugState,
useFeatureFlags
} from '@sd/client';
import Card from '~/components/layout/Card';
import { Button } from '~/components/primitive/Button';
import { tw } from '~/lib/tailwind';
@ -9,6 +17,10 @@ import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
const DebugScreen = ({ navigation }: SettingsStackScreenProps<'Debug'>) => {
const debugState = useDebugState();
const featureFlags = useFeatureFlags();
const origin = useBridgeQuery(['cloud.getApiOrigin']);
const setOrigin = useBridgeMutation(['cloud.setApiOrigin']);
const queryClient = useQueryClient();
return (
<View style={tw`flex-1 p-4`}>
@ -28,6 +40,30 @@ const DebugScreen = ({ navigation }: SettingsStackScreenProps<'Debug'>) => {
>
<Text style={tw`text-ink`}>Disable Debug Mode</Text>
</Button>
<Button
onPress={() => {
const url =
origin.data === 'https://app.spacedrive.com'
? 'http://localhost:3000'
: 'https://app.spacedrive.com';
setOrigin.mutateAsync(url).then(() => {
auth.logout();
queryClient.invalidateQueries();
});
}}
>
<Text style={tw`text-ink`}>Toggle API Route ({origin.data})</Text>
</Button>
<Button
onPress={() => {
navigation.popToTop();
navigation.navigate('BackfillWaitingStack', {
screen: 'BackfillWaiting'
});
}}
>
<Text style={tw`text-ink`}>Go to Backfill Waiting Page</Text>
</Button>
</Card>
</View>
);

View file

@ -1,35 +0,0 @@
import { useEffect } from 'react';
import { Button, Text } from 'react-native';
import { useLibraryMutation, useLibraryQuery } from '@sd/client';
import ScreenContainer from '~/components/layout/ScreenContainer';
import { tw } from '~/lib/tailwind';
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
const BackfillWaiting = ({ navigation }: SettingsStackScreenProps<'BackfillWaiting'>) => {
const syncEnabled = useLibraryQuery(['sync.enabled']);
const enableSync = useLibraryMutation(['sync.backfill'], {});
useEffect(() => {
async function _() {
await enableSync.mutateAsync(null).then(() => navigation.navigate('SyncSettings'));
}
_();
}, []);
return (
<ScreenContainer scrollview={false} style={tw`gap-0 px-6`}>
<Text
style={tw`flex h-full w-full flex-col items-center justify-center p-5 text-center text-xl text-white`}
>
Library is being backfilled right now for Sync! Please hold while this process takes
place.
</Text>
<Button onPress={() => navigation.goBack()} title="Go Back" />
</ScreenContainer>
);
};
export default BackfillWaiting;

View file

@ -0,0 +1,65 @@
import { Linking, Text, View } from 'react-native';
import { auth } from '@sd/client';
import ScreenContainer from '~/components/layout/ScreenContainer';
import { Button } from '~/components/primitive/Button';
import { tw } from '~/lib/tailwind';
import { SettingsStackScreenProps } from '~/navigation/tabs/SettingsStack';
const Cloud = ({ navigation }: SettingsStackScreenProps<'Cloud'>) => {
const authState = auth.useStateSnapshot();
const authSensitiveChild = () => {
if (authState.status === 'loggedIn') return <Authenticated />;
if (authState.status === 'notLoggedIn' || authState.status === 'loggingIn')
return <Login />;
return null;
};
return (
<ScreenContainer scrollview={false} style={tw`gap-0 px-6`}>
{authSensitiveChild()}
</ScreenContainer>
);
};
const Authenticated = () => {
return (
<ScreenContainer scrollview={false} style={tw`gap-0 px-6`}>
<Text style={tw`text-ink`}>You are authenticated!</Text>
</ScreenContainer>
);
};
const Login = () => {
const authState = auth.useStateSnapshot();
return (
<View style={tw`flex flex-col items-center justify-center gap-2`}>
<Button
variant="accent"
disabled={authState.status === 'loggingIn'}
onPress={async () => {
await Linking.openURL('http://localhost:3000/login');
auth.set_logged_in();
}}
>
{authState.status !== 'loggingIn' ? <Text>Login</Text> : <Text>Logging In</Text>}
</Button>
{authState.status === 'loggingIn' && (
<Button
variant="accent"
onPress={(e) => {
e.preventDefault();
auth.cancel();
}}
style={tw`text-sm text-ink-faint`}
>
<Text>Cancel</Text>
</Button>
)}
</View>
);
};
export default Cloud;

View file

@ -36,13 +36,13 @@ const SyncSettingsScreen = ({ navigation }: SettingsStackScreenProps<'SyncSettin
useLibrarySubscription(['library.actors'], { onData: setData });
const cloudSync = useFeatureFlag('cloudSync');
useEffect(() => {
if (startBackfill === true) {
console.log('Starting Backfill!');
navigation.navigate('BackfillWaiting');
navigation.navigate('BackfillWaitingStack', {
screen: 'BackfillWaiting'
});
// Force re-render?
}
@ -61,7 +61,7 @@ const SyncSettingsScreen = ({ navigation }: SettingsStackScreenProps<'SyncSettin
</Button>
) : (
<View>
{/* <Text
<Text
style={tw`flex flex-col items-center justify-center text-left text-white`}
>
Ingester
@ -73,7 +73,7 @@ const SyncSettingsScreen = ({ navigation }: SettingsStackScreenProps<'SyncSettin
) : (
<StartButton name={ACTORS.Ingest} />
)}
</View> */}
</View>
<Text
style={tw`flex flex-col items-center justify-center text-left text-white`}
>
@ -87,6 +87,32 @@ const SyncSettingsScreen = ({ navigation }: SettingsStackScreenProps<'SyncSettin
<StartButton name={ACTORS.CloudSend} />
)}
</View>
<Text
style={tw`flex flex-col items-center justify-center text-left text-white`}
>
Receiver
<OnlineIndicator online={data[ACTORS.CloudReceive] ?? false} />
</Text>
<View>
{data[ACTORS.CloudReceive] ? (
<StopButton name={ACTORS.CloudReceive} />
) : (
<StartButton name={ACTORS.CloudReceive} />
)}
</View>
<Text
style={tw`flex flex-col items-center justify-center text-left text-white`}
>
Cloud Ingester
<OnlineIndicator online={data[ACTORS.CloudIngest] ?? false} />
</Text>
<View>
{data[ACTORS.CloudReceive] ? (
<StopButton name={ACTORS.CloudIngest} />
) : (
<StartButton name={ACTORS.CloudIngest} />
)}
</View>
</View>
)}
</ScreenContainer>

View file

@ -65,7 +65,7 @@ export const Select = forwardRef(
</RS.Trigger>
<RS.Portal>
<RS.Content className="z-50 rounded-md border border-app-line bg-app-box shadow-2xl shadow-app-shade/20 ">
<RS.Content className="z-[100] rounded-md border border-app-line bg-app-box shadow-2xl shadow-app-shade/20 ">
<RS.Viewport className="p-1">{props.children}</RS.Viewport>
</RS.Content>
</RS.Portal>