[MOB-55] Video animation for onboarding on mobile and desktop (#2065)

* video animation for onboarding on mobile and desktop

run assets gen

cleanup

declare mp4 type

* update metro config to transform video files from sd assets

* test ci without native video exclude

* casing?

* remove to add back again due to github

* add videos back

* versions

* no need to transform

---------

Co-authored-by: Utku Bakir <74243531+utkubakir@users.noreply.github.com>
This commit is contained in:
ameer2468 2024-02-07 20:25:04 +03:00 committed by GitHub
parent da2841b37a
commit bda9a1b6ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 393 additions and 319 deletions

Binary file not shown.

View file

@ -21,7 +21,7 @@ const metroConfig = makeMetroConfig({
resolver: {
...expoDefaultConfig.resolver,
extraNodeModules: {
'react-native-svg': reactSVGPath
'react-native-svg': reactSVGPath,
},
blockList: exclusionList([reactSVGExclude, rspcClientExclude, rspcReactExclude]),
sourceExts: [...expoDefaultConfig.resolver.sourceExts, 'svg'],

View file

@ -35,7 +35,8 @@
"class-variance-authority": "^0.7.0",
"dayjs": "^1.11.10",
"event-target-polyfill": "^0.0.3",
"expo": "~50.0.5",
"expo": "~50.0.6",
"expo-av": "^13.10.5",
"expo-blur": "^12.9.1",
"expo-build-properties": "~0.11.1",
"expo-linking": "~6.2.2",
@ -49,7 +50,7 @@
"phosphor-react-native": "^2.0.0",
"react": "^18.2.0",
"react-hook-form": "^7.47.0",
"react-native": "0.73.2",
"react-native": "0.73.4",
"react-native-circular-progress": "^1.3.9",
"react-native-document-picker": "^9.0.1",
"react-native-fs": "^2.20.0",

View file

@ -77,8 +77,8 @@ export default function Header({
Platform.OS === 'android' ? 'pt-5' : 'pt-10'
)}
>
<View style={tw`mx-auto mt-5 h-auto w-full justify-center px-7 pb-5`}>
<View style={tw`w-full flex-row items-center justify-between`}>
<View style={tw`justify-center w-full h-auto pb-5 mx-auto mt-5 px-7`}>
<View style={tw`flex-row items-center justify-between w-full`}>
<View style={tw`flex-row items-center gap-5`}>
{navBack && (
<Pressable

View file

@ -24,10 +24,10 @@ export function SettingsItem(props: SettingsItemProps) {
return (
<Pressable onPress={props.onPress}>
<View style={twStyle(' border-app-input bg-sidebar-box', borderRounded, border)}>
<View style={tw`h-auto flex-row items-center`}>
<View style={tw`flex-row items-center h-auto`}>
{props.leftIcon && (
<View
style={tw`ml-4 mr-5 h-8 w-8 items-center justify-center rounded-full bg-app-input`}
style={tw`items-center justify-center w-8 h-8 ml-4 mr-5 rounded-full bg-app-input`}
>
{props.leftIcon({ size: 20, color: tw.color('ink-dull') })}
</View>

View file

@ -1,4 +1,6 @@
import { createStackNavigator, StackScreenProps } from '@react-navigation/stack';
import { useEffect } from 'react';
import { useOnboardingStore } from '@sd/client';
import { OnboardingContext, useContextValue } from '~/screens/onboarding/context';
import CreatingLibraryScreen from '~/screens/onboarding/CreatingLibrary';
import GetStartedScreen from '~/screens/onboarding/GetStarted';

View file

@ -1,8 +1,9 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import { CheckCircle } from 'phosphor-react-native';
import React from 'react';
import { ScrollView, View } from 'react-native';
import { useLibraryQuery } from '@sd/client';
import { resetOnboardingStore, useLibraryQuery } from '@sd/client';
import { PulseAnimation } from '~/components/animation/lottie';
import BrowseLocations from '~/components/browse/BrowseLocations';
import BrowseTags from '~/components/browse/BrowseTags';

View file

@ -1,10 +1,14 @@
import { useNavigation, useRoute } from '@react-navigation/native';
import { AppLogo, BloomOne } from '@sd/assets/images';
import { sdintro } from '@sd/assets/videos';
import { ResizeMode, Video } from 'expo-av';
import { MotiView } from 'moti';
import { CaretLeft } from 'phosphor-react-native';
import { useEffect } from 'react';
import { Image, KeyboardAvoidingView, Platform, Pressable, Text, View } from 'react-native';
import Animated from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useOnboardingStore } from '@sd/client';
import { FadeInUpAnimation, LogoAnimation } from '~/components/animation/layout';
import { AnimatedButton } from '~/components/primitive/Button';
import { styled, tw, twStyle } from '~/lib/tailwind';
@ -13,11 +17,31 @@ import { OnboardingStackScreenProps } from '~/navigation/OnboardingNavigator';
export function OnboardingContainer({ children }: React.PropsWithChildren) {
const navigation = useNavigation();
const route = useRoute();
const { top, bottom } = useSafeAreaInsets();
const store = useOnboardingStore();
return (
<View style={tw`flex-1`}>
<View style={tw`relative flex-1`}>
{store.showIntro && (
<View
style={twStyle(
'absolute z-50 mx-auto h-full w-full flex-1 items-center justify-center',
Platform.OS === 'ios' ? 'bg-[#1C1E27]' : 'bg-[#1E1D28]'
)}
>
<Video
style={tw`w-[700px] h-[700px]`}
shouldPlay
onPlaybackStatusUpdate={(status) => {
if (status.isLoaded && status.didJustFinish) {
store.showIntro = false;
}
}}
source={sdintro}
isMuted
resizeMode={ResizeMode.CONTAIN}
/>
</View>
)}
{route.name !== 'GetStarted' && route.name !== 'CreatingLibrary' && (
<Pressable
style={twStyle('absolute left-6 z-50', { top: top + 16 })}
@ -26,22 +50,22 @@ export function OnboardingContainer({ children }: React.PropsWithChildren) {
<CaretLeft size={24} weight="bold" color="white" />
</Pressable>
)}
<View style={tw`z-10 flex-1 items-center justify-center`}>
<View style={tw`z-10 items-center justify-center flex-1`}>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={bottom}
style={tw`w-full flex-1 items-center justify-center`}
style={tw`items-center justify-center flex-1 w-full`}
>
<MotiView style={tw`w-full items-center justify-center px-4`}>
<MotiView style={tw`items-center justify-center w-full px-4`}>
{children}
</MotiView>
</KeyboardAvoidingView>
<Text style={tw`absolute bottom-8 text-xs text-ink-dull/50`}>
<Text style={tw`absolute text-xs bottom-8 text-ink-dull/50`}>
&copy; {new Date().getFullYear()} Spacedrive Technology Inc.
</Text>
</View>
{/* Bloom */}
<Image source={BloomOne} style={tw`top-100 absolute h-screen w-screen opacity-20`} />
<Image source={BloomOne} style={tw`absolute w-screen h-screen top-100 opacity-20`} />
</View>
);
}
@ -57,6 +81,11 @@ export const OnboardingDescription = styled(
);
const GetStartedScreen = ({ navigation }: OnboardingStackScreenProps<'GetStarted'>) => {
//initial render - reset video intro value
const store = useOnboardingStore();
useEffect(() => {
store.showIntro = true;
}, []);
return (
<OnboardingContainer>
{/* Logo */}
@ -76,7 +105,7 @@ const GetStartedScreen = ({ navigation }: OnboardingStackScreenProps<'GetStarted
{/* Get Started Button */}
<FadeInUpAnimation delay={1200} style={tw`mt-8`}>
<AnimatedButton variant="accent" onPress={() => navigation.push('NewLibrary')}>
<Text style={tw`text-center text-base font-medium text-ink`}>Get Started</Text>
<Text style={tw`text-base font-medium text-center text-ink`}>Get Started</Text>
</AnimatedButton>
</FadeInUpAnimation>
</OnboardingContainer>

View file

@ -1,7 +1,7 @@
import { Trash } from 'phosphor-react-native';
import React from 'react';
import { Controller } from 'react-hook-form';
import { Alert, View } from 'react-native';
import { Alert, Text, View } from 'react-native';
import { z } from 'zod';
import { useBridgeMutation, useLibraryContext, useZodForm } from '@sd/client';
import { Input } from '~/components/form/Input';
@ -38,7 +38,7 @@ const LibraryGeneralSettingsScreen = (_: SettingsStackScreenProps<'LibraryGenera
return (
<View style={tw`gap-4`}>
<View style={tw`mt-4 px-2`}>
<View style={tw`px-2 mt-4`}>
<SettingsTitle>Name</SettingsTitle>
<Controller
name="name"
@ -66,21 +66,7 @@ const LibraryGeneralSettingsScreen = (_: SettingsStackScreenProps<'LibraryGenera
{/* Export */}
<SettingsItem title="Export Library" onPress={() => Alert.alert('TODO')} />
{/* Delete Library */}
<SettingsContainer description="This is permanent, your files will not be deleted, only the Spacedrive library.">
<SettingsItem
title="Delete Library"
rightArea={
<DeleteLibraryModal
libraryUuid={library.uuid}
trigger={
<FakeButton size="sm" variant="danger">
<Trash color={tw.color('ink')} size={20} />
</FakeButton>
}
/>
}
/>
</SettingsContainer>
<DeleteLibraryModal trigger={<Text>Delete</Text>} libraryUuid={library.uuid} />
</View>
</View>
);

View file

@ -9,3 +9,8 @@ declare module '*.png' {
const content: any;
export default content;
}
declare module '*.mp4' {
const content: any;
export default content;
}

View file

@ -1,5 +1,7 @@
import { BloomOne } from '@sd/assets/images';
import { sdintro } from '@sd/assets/videos';
import clsx from 'clsx';
import { useState } from 'react';
import { Navigate, Outlet } from 'react-router';
import { useDebugState } from '@sd/client';
import DragRegion from '~/components/DragRegion';
@ -13,7 +15,7 @@ import Progress from './Progress';
export const Component = () => {
const os = useOperatingSystem();
const debugState = useDebugState();
const [showIntro, setShowIntro] = useState(true);
const ctx = useContextValue();
if (ctx.libraries.isLoading) return null;
@ -27,20 +29,35 @@ export const Component = () => {
'flex h-screen flex-col bg-sidebar text-ink'
)}
>
{showIntro && (
<div className="absolute left-0 top-0 z-50 flex h-screen w-screen items-center justify-center bg-[#1F212C]">
<video
width={700}
className="mx-auto"
autoPlay
onEnded={() => {
setShowIntro(false);
}}
muted
controls={false}
src={sdintro}
/>
</div>
)}
<DragRegion className="z-50 h-9" />
<div className="-mt-5 flex grow flex-col gap-8 p-10">
<div className="flex grow flex-col items-center justify-center">
<div className="flex flex-col gap-8 p-10 -mt-5 grow">
<div className="flex flex-col items-center justify-center grow">
<Outlet />
</div>
<Progress />
</div>
<div className="flex justify-center p-4">
<p className="text-xs text-ink-dull opacity-50">
<p className="text-xs opacity-50 text-ink-dull">
&copy; {new Date().getFullYear()} Spacedrive Technology Inc.
</p>
</div>
<div className="absolute -z-10">
<div className="relative h-screen w-screen">
<div className="relative w-screen h-screen">
<img src={BloomOne} className="absolute h-[2000px] w-[2000px]" />
{/* <img src={BloomThree} className="absolute w-[2000px] h-[2000px] -right-[200px]" /> */}
</div>

View file

@ -4,5 +4,6 @@
*/
import fda from './fda.mp4';
import sdintro from './sdintro.mp4';
export { fda };
export { fda, sdintro };

Binary file not shown.

View file

@ -15,7 +15,8 @@ const onboardingStoreDefaults = () => ({
lastActiveScreen: null as string | null,
useCases: [] as UseCase[],
grantedFullDiskAccess: false,
data: {} as Record<string, any> | undefined
data: {} as Record<string, any> | undefined,
showIntro: true
});
export const onboardingStore = createPersistedMutable(

File diff suppressed because it is too large Load diff