mobile: redesign onboarding (#2633)

This commit is contained in:
Ammar Ahmed
2023-06-05 15:13:19 +05:00
committed by GitHub
parent c2ab5ded47
commit 25bf4fee82
26 changed files with 623 additions and 500 deletions

View File

@@ -126,11 +126,11 @@ const AuthModal = () => {
{initialAuthMode.current !== AuthMode.welcomeSignup ? null : (
<Button
title="Skip for now"
title="Skip"
onPress={() => {
hideAuth();
}}
iconSize={20}
iconSize={16}
type="gray"
iconPosition="right"
icon="chevron-right"

View File

@@ -18,9 +18,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useEffect, useState } from "react";
import { View } from "react-native";
import { TouchableOpacity, View } from "react-native";
import { SheetManager } from "react-native-actions-sheet";
import Animated, { FadeInDown, FadeOutUp } from "react-native-reanimated";
import { DDS } from "../../services/device-detection";
import { eSendEvent } from "../../services/event-manager";
import { useThemeStore } from "../../stores/use-theme-store";
@@ -30,13 +29,12 @@ import SheetProvider from "../sheet-provider";
import { Progress } from "../sheets/progress";
import { Button } from "../ui/button";
import Input from "../ui/input";
import { SvgView } from "../ui/svg";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { SVG } from "./background";
import { hideAuth } from "./common";
import { ForgotPassword } from "./forgot-password";
import { useLogin } from "./use-login";
import { useSettingStore } from "../../stores/use-setting-store";
const LoginSteps = {
emailAuth: 1,
@@ -64,6 +62,7 @@ export const Login = ({ changeMode }) => {
await sleep(500);
Progress.present();
});
const deviceMode = useSettingStore((state) => state.deviceMode);
useEffect(() => {
async () => {
@@ -82,62 +81,70 @@ export const Login = ({ changeMode }) => {
<>
<ForgotPassword />
<SheetProvider context="two_factor_verify" />
<Animated.View
entering={FadeInDown}
exiting={FadeOutUp}
<View
style={{
borderRadius: DDS.isTab ? 5 : 0,
backgroundColor: colors.bg,
zIndex: 10,
width: "100%",
alignSelf: "center",
height: "100%",
minHeight: "100%"
}}
>
<View
style={{
height: 250,
overflow: "hidden"
}}
>
<SvgView
src={SVG(colors.night ? colors.icon : "black")}
height={700}
/>
</View>
<View
style={{
width: "100%",
justifyContent: "center",
alignSelf: "center",
paddingHorizontal: 12,
marginBottom: 30,
marginTop: 15
flex: 0.45,
justifyContent: "flex-end",
paddingHorizontal: 20,
backgroundColor: colors.nav,
marginBottom: 20,
borderBottomWidth: 1,
borderBottomColor: colors.border,
alignSelf: deviceMode !== "mobile" ? "center" : undefined,
borderWidth: deviceMode !== "mobile" ? 1 : null,
borderColor: deviceMode !== "mobile" ? colors.border : null,
borderRadius: deviceMode !== "mobile" ? 20 : null,
marginTop: deviceMode !== "mobile" ? 50 : null,
width: deviceMode === "mobile" ? null : "50%"
}}
>
<View
style={{
flexDirection: "row"
}}
>
<View
style={{
width: 100,
height: 5,
backgroundColor: colors.accent,
borderRadius: 2,
marginRight: 7
}}
/>
<View
style={{
width: 20,
height: 5,
backgroundColor: colors.nav,
borderRadius: 2
}}
/>
</View>
<Heading
style={{
textAlign: "center"
marginBottom: 25,
marginTop: 10
}}
size={30}
color={colors.heading}
extraBold
size={SIZE.xxl}
>
Welcome back!
Login to your {"\n"}account
</Heading>
<Paragraph
style={{
textDecorationLine: "underline",
textAlign: "center",
marginTop: 5
}}
onPress={() => {
if (loading) return;
changeMode(1);
}}
size={SIZE.md}
>
{"Don't have an account? Sign up"}
</Paragraph>
</View>
<View
style={{
width: DDS.isTab
@@ -147,10 +154,9 @@ export const Login = ({ changeMode }) => {
: focused
? "100%"
: "99.9%",
padding: 12,
backgroundColor: colors.bg,
flexGrow: 1,
alignSelf: "center"
alignSelf: "center",
paddingHorizontal: 20
}}
>
<Input
@@ -217,28 +223,22 @@ export const Login = ({ changeMode }) => {
<View
style={{
marginTop: 25,
alignSelf: "center"
marginTop: 25
}}
>
<Button
style={{
width: 250,
borderRadius: 100
}}
loading={loading}
onPress={() => {
if (loading) return;
login();
}}
style={{
width: 250,
borderRadius: 100
}}
fontSize={SIZE.md}
type="accent"
title={
loading
? null
: step === LoginSteps.emailAuth
? "Login"
: "Continue"
}
title={!loading ? "Continue" : null}
/>
{step === LoginSteps.passwordAuth && (
@@ -261,9 +261,34 @@ export const Login = ({ changeMode }) => {
type="errorShade"
/>
)}
{!loading ? (
<TouchableOpacity
onPress={() => {
if (loading) return;
changeMode(1);
}}
activeOpacity={0.8}
style={{
alignSelf: "center",
marginTop: 12,
paddingVertical: 12
}}
>
<Paragraph size={SIZE.xs + 1} color={colors.icon}>
Don't have an account?{" "}
<Paragraph
size={SIZE.xs + 1}
style={{ color: colors.accent }}
>
Sign up
</Paragraph>
</Paragraph>
</TouchableOpacity>
) : null}
</View>
</View>
</Animated.View>
</View>
</>
);
};

View File

@@ -18,8 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useRef, useState } from "react";
import { Dimensions, View } from "react-native";
import Animated, { FadeInDown, FadeOutUp } from "react-native-reanimated";
import { TouchableOpacity, View } from "react-native";
import { db } from "../../common/database";
import { DDS } from "../../services/device-detection";
import { ToastEvent } from "../../services/event-manager";
@@ -32,11 +31,10 @@ import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import { Button } from "../ui/button";
import Input from "../ui/input";
import { SvgView } from "../ui/svg";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { SVG } from "./background";
import { hideAuth } from "./common";
import { useSettingStore } from "../../stores/use-setting-store";
export const Signup = ({ changeMode, trial }) => {
const colors = useThemeStore((state) => state.colors);
@@ -50,6 +48,7 @@ export const Signup = ({ changeMode, trial }) => {
const [loading, setLoading] = useState(false);
const setUser = useUserStore((state) => state.setUser);
const setLastSynced = useUserStore((state) => state.setLastSynced);
const deviceMode = useSettingStore((state) => state.deviceMode);
const validateInfo = () => {
if (!password.current || !email.current || !confirmPassword.current) {
@@ -96,69 +95,77 @@ export const Signup = ({ changeMode, trial }) => {
return (
<>
<Animated.View
entering={FadeInDown}
exiting={FadeOutUp}
<View
style={{
borderRadius: DDS.isTab ? 5 : 0,
backgroundColor: colors.bg,
zIndex: 10,
width: "100%",
alignSelf: "center",
height: "100%",
minHeight: "100%"
}}
>
<View
style={{
height: 250,
overflow: "hidden"
flex: 0.35,
justifyContent: "flex-end",
paddingHorizontal: 20,
backgroundColor: colors.nav,
marginBottom: 20,
borderBottomWidth: 1,
borderBottomColor: colors.border,
alignSelf: deviceMode !== "mobile" ? "center" : undefined,
borderWidth: deviceMode !== "mobile" ? 1 : null,
borderColor: deviceMode !== "mobile" ? colors.border : null,
borderRadius: deviceMode !== "mobile" ? 20 : null,
marginTop: deviceMode !== "mobile" ? 50 : null,
width: deviceMode === "mobile" ? null : "50%"
}}
>
<SvgView
src={SVG(colors.night ? colors.icon : "black")}
height={700}
/>
<View
style={{
flexDirection: "row"
}}
>
<View
style={{
width: 100,
height: 5,
backgroundColor: colors.accent,
borderRadius: 2,
marginRight: 7
}}
/>
<View
style={{
width: 20,
height: 5,
backgroundColor: colors.nav,
borderRadius: 2
}}
/>
</View>
<Heading
extraBold
style={{
marginBottom: 25,
marginTop: 10
}}
size={SIZE.xxl}
>
Create your {"\n"}account
</Heading>
</View>
<View
style={{
width: "100%",
justifyContent: "center",
alignSelf: "center",
paddingHorizontal: 12,
marginBottom: 30,
marginTop: Dimensions.get("window").height < 700 ? -75 : 15
}}
>
<Heading
style={{
textAlign: "center"
}}
size={30}
color={colors.heading}
>
Create your account
</Heading>
<Paragraph
style={{
textDecorationLine: "underline",
textAlign: "center"
}}
onPress={() => {
if (loading) return;
changeMode(0);
}}
size={SIZE.md}
>
Already have an account? Log in
</Paragraph>
</View>
<View
style={{
width: DDS.isTab ? "50%" : "100%",
padding: 12,
paddingHorizontal: 20,
backgroundColor: colors.bg,
flexGrow: 1,
alignSelf: "center"
alignSelf: "center",
flex: 0.6
}}
>
<Input
@@ -217,37 +224,13 @@ export const Signup = ({ changeMode, trial }) => {
validationType="confirmPassword"
customValidator={() => password.current}
placeholder="Confirm password"
marginBottom={5}
marginBottom={12}
onSubmit={signup}
/>
<View
style={{
marginTop: 25,
alignSelf: "center"
}}
>
<Button
style={{
width: 250,
borderRadius: 100
}}
loading={loading}
onPress={() => {
if (loading) return;
signup();
}}
type="accent"
title={loading ? null : "Agree and continue"}
/>
</View>
<Paragraph
style={{
textAlign: "center",
position: "absolute",
bottom: 0,
alignSelf: "center",
marginBottom: 20
marginBottom: 25
}}
size={SIZE.xs}
color={colors.icon}
@@ -263,7 +246,7 @@ export const Signup = ({ changeMode, trial }) => {
}}
color={colors.accent}
>
terms of service{" "}
Terms of Service{" "}
</Paragraph>
and{" "}
<Paragraph
@@ -276,11 +259,46 @@ export const Signup = ({ changeMode, trial }) => {
}}
color={colors.accent}
>
privacy policy.
</Paragraph>
Privacy Policy.
</Paragraph>{" "}
You also agree to recieve marketing emails from us which you can
opt-out of from app settings.
</Paragraph>
<Button
title={!loading ? "Continue" : null}
type="accent"
loading={loading}
onPress={signup}
fontSize={SIZE.md}
style={{
marginRight: 12,
width: 250,
borderRadius: 100
}}
/>
<TouchableOpacity
onPress={() => {
if (loading) return;
changeMode(0);
}}
activeOpacity={0.8}
style={{
alignSelf: "center",
marginTop: 12,
paddingVertical: 12
}}
>
<Paragraph size={SIZE.xs + 1} color={colors.icon}>
Already have an account?{" "}
<Paragraph size={SIZE.xs + 1} style={{ color: colors.accent }}>
Login
</Paragraph>
</Paragraph>
</TouchableOpacity>
</View>
</Animated.View>
</View>
</>
);
};

File diff suppressed because one or more lines are too long

View File

@@ -42,7 +42,6 @@ import { eOpenAnnouncementDialog } from "../../utils/events";
import { getGithubVersion } from "../../utils/github-version";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import { SVG } from "../auth/background";
import Migrate from "../sheets/migrate";
import NewFeature from "../sheets/new-feature/index";
import { Update } from "../sheets/update";
@@ -50,7 +49,6 @@ import { Button } from "../ui/button";
import { IconButton } from "../ui/icon-button";
import Input from "../ui/input";
import Seperator from "../ui/seperator";
import { SvgView } from "../ui/svg";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { Walkthrough } from "../walkthroughs";
@@ -89,7 +87,7 @@ const Launcher = React.memo(
const init = useCallback(async () => {
if (!db.isInitialized) {
await RNBootSplash.hide({ fade: true });
RNBootSplash.hide({ fade: true });
DatabaseLogger.info("Initializing database");
await db.init();
}
@@ -132,7 +130,6 @@ const Launcher = React.memo(
if (NewFeature.present()) return;
if (await checkAppUpdateAvailable()) return;
if (await checkForRateAppRequest()) return;
if (await checkNeedsBackup()) return;
if (await PremiumService.getRemainingTrialDaysStatus()) return;
if (introCompleted) {
@@ -175,23 +172,6 @@ const Launcher = React.memo(
return false;
};
const checkNeedsBackup = async () => {
return false;
// let { nextBackupRequestTime, reminder } = SettingsService.get();
// if (reminder === 'off' || !reminder) {
// if (nextBackupRequestTime < Date.now()) {
// presentSheet({
// title: 'Backup & restore',
// paragraph: 'Please enable automatic backups to keep your data safe',
// component: <SettingsBackupAndRestore isSheet={true} />
// });
// return true;
// }
// }
// return false;
};
const onUnlockBiometrics = useCallback(async () => {
if (!(await BiometricService.isBiometryAvailable())) return;
if (Platform.OS === "android") {
@@ -247,18 +227,10 @@ const Launcher = React.memo(
width: "100%",
height: "100%",
position: "absolute",
zIndex: 999
zIndex: 999,
justifyContent: "center"
}}
>
<View
style={{
height: 250,
overflow: "hidden"
}}
>
<SvgView src={SVG(colors.night ? "white" : "black")} height={700} />
</View>
<View
style={{
flex: 1,
@@ -294,14 +266,13 @@ const Launcher = React.memo(
textAlign: "center"
}}
>
Unlock to access your notes
Unlock your notes
</Heading>
<Paragraph
style={{
alignSelf: "center",
textAlign: "center",
fontSize: SIZE.md,
maxWidth: "90%"
}}
>
@@ -312,8 +283,7 @@ const Launcher = React.memo(
style={{
width: "100%",
padding: 12,
backgroundColor: colors.bg,
flexGrow: 1
backgroundColor: colors.bg
}}
>
{user ? (
@@ -353,14 +323,9 @@ const Launcher = React.memo(
<Button
title="Unlock with Biometrics"
width={250}
height={45}
style={{
borderRadius: 100
}}
onPress={onUnlockBiometrics}
icon={"fingerprint"}
type={user ? "grayAccent" : "accent"}
fontSize={SIZE.md}
/>
</View>
</View>

View File

@@ -18,13 +18,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { ScrollView } from "react-native";
import { FeatureBlock } from "./feature";
import { ScrollView } from "react-native-actions-sheet";
export const CompactFeatures = ({
vertical,
features = [],
maxHeight = 500,
maxHeight = 600,
scrollRef
}) => {
let data = vertical
@@ -80,14 +80,11 @@ export const CompactFeatures = ({
return (
<ScrollView
horizontal={!vertical}
nestedScrollEnabled
onMomentumScrollEnd={() => {
scrollRef?.current?.handleChildScrollEnd();
}}
showsHorizontalScrollIndicator={false}
style={{
width: "100%",
maxHeight: maxHeight
maxHeight: maxHeight,
paddingHorizontal: 12
}}
>
{data.map((item) => (

View File

@@ -41,18 +41,19 @@ export const FeatureBlock = ({
flexDirection: "row",
alignItems: "center",
paddingHorizontal: 12,
marginBottom: 10
marginBottom: 10,
backgroundColor: colors.nav,
borderRadius: 10,
paddingVertical: 12
}}
>
<Icon color={colors.accent} name="check" size={SIZE.lg} />
<Paragraph
style={{
flexWrap: "wrap",
marginLeft: 5,
flexShrink: 1
}}
size={SIZE.md}
size={SIZE.sm}
>
{content}
</Paragraph>

View File

@@ -232,8 +232,7 @@ export const PricingPlans = ({
width={250}
style={{
paddingHorizontal: 12,
marginBottom: 15,
borderRadius: 100
marginBottom: 15
}}
/>
</>
@@ -398,8 +397,7 @@ export const PricingPlans = ({
style={{
paddingHorizontal: 12,
marginTop: 30,
marginBottom: 10,
borderRadius: 100
marginBottom: 10
}}
/>
{Platform.OS !== "ios" &&

View File

@@ -196,12 +196,11 @@ const SheetProvider = ({ context = "global" }) => {
accentColor={data.iconColor || "accent"}
accentText="light"
type="accent"
height={45}
height={40}
width={250}
style={{
borderRadius: 100
marginBottom: 25
}}
fontSize={SIZE.md}
/>
) : null}

View File

@@ -309,7 +309,6 @@ export class AddNotebookSheet extends React.Component {
borderRadius: 100,
paddingHorizontal: 24
}}
fontSize={SIZE.md}
onPress={this.addNewNotebook}
/>
</View>

View File

@@ -243,7 +243,6 @@ export default function ReminderSheet({
borderRadius: 100,
paddingHorizontal: 24
}}
fontSize={SIZE.md}
onPress={saveReminder}
/>
</View>

View File

@@ -65,7 +65,6 @@ import { deleteItems } from "../../../utils/functions";
import { presentDialog } from "../../dialog/functions";
import { Properties } from "../../properties";
import Sort from "../sort";
import Heading from "../../ui/typography/heading";
type ConfigItem = { id: string; type: string };
class TopicSheetConfig {

View File

@@ -302,6 +302,7 @@ export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
translateX.value = value;
})
.onEnd((event) => {
if (locked.value || forcedLock.value) return;
if (currentTab.value === 2 && Platform.OS === "android") return;
const velocityX =
event.velocityX < 0 ? event.velocityX * -1 : event.velocityX;

View File

@@ -119,7 +119,7 @@ const Input = ({
? colors.red
: focus
? customColor || colors.accent
: colors.nav;
: colors.border;
const validate = async (value: string) => {
if (!validationType) return;

View File

@@ -105,6 +105,9 @@ const SheetWrapper = ({
defaultOverlayOpacity={overlayOpacity}
overlayColor={pitchBlack ? "#585858" : "#2b2b2b"}
keyboardShouldPersistTaps="always"
openAnimationConfig={{
friction: 9
}}
ExtraOverlayComponent={
<>
{overlay}

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useMemo } from "react";
import { Platform, Text, TextProps } from "react-native";
import { Platform, Text, TextProps, ViewStyle } from "react-native";
import Animated, {
ComplexAnimationBuilder,
Layout
@@ -30,15 +30,26 @@ interface HeadingProps extends TextProps {
size?: number;
layout?: ComplexAnimationBuilder;
animated?: boolean;
extraBold?: boolean;
}
const AnimatedText = Animated.createAnimatedComponent(Text);
const extraBoldStyle = {
fontFamily: Platform.OS === "android" ? "OpenSans-Bold" : undefined,
fontWeight: Platform.OS === "ios" ? "800" : undefined
};
const boldStyle = {
fontFamily: Platform.OS === "android" ? "OpenSans-SemiBold" : undefined,
fontWeight: Platform.OS === "ios" ? "600" : undefined
};
const Heading = ({
color,
size = SIZE.xl,
style,
animated,
extraBold,
...restProps
}: HeadingProps) => {
const colors = useThemeStore((state) => state.colors);
@@ -53,11 +64,9 @@ const Heading = ({
style={[
{
fontSize: size || SIZE.xl,
color: color || colors.heading,
fontFamily:
Platform.OS === "android" ? "OpenSans-SemiBold" : undefined,
fontWeight: Platform.OS === "ios" ? "600" : undefined
color: color || colors.heading
},
extraBold ? (extraBoldStyle as ViewStyle) : (boldStyle as ViewStyle),
style
]}
></Component>

View File

@@ -50,6 +50,7 @@ import { useSettingStore } from "../stores/use-setting-store";
import { useThemeStore } from "../stores/use-theme-store";
import { history } from "../utils";
import { rootNavigatorRef } from "../utils/global-refs";
import Auth from "../components/auth";
const NativeStack = createNativeStackNavigator();
const IntroStack = createNativeStackNavigator();
@@ -64,6 +65,7 @@ const IntroStack = createNativeStackNavigator();
const IntroStackNavigator = () => {
const colors = useThemeStore((state) => state.colors);
const height = useSettingStore((state) => state.dimensions.height);
return (
<IntroStack.Navigator
screenOptions={{
@@ -71,12 +73,14 @@ const IntroStackNavigator = () => {
lazy: false,
animation: "none",
contentStyle: {
backgroundColor: colors.bg
backgroundColor: colors.bg,
minHeight: height
}
}}
initialRouteName={"Intro"}
>
<NativeStack.Screen name="Intro" component={Intro} />
<NativeStack.Screen name="Auth" component={Auth} />
<NativeStack.Screen name="AppLock" component={AppLock} />
</IntroStack.Navigator>
);
@@ -120,7 +124,7 @@ const _Tabs = () => {
animation: "none",
contentStyle: {
backgroundColor: colors.bg,
height: !introCompleted ? undefined : screenHeight
minHeight: !introCompleted ? undefined : screenHeight
}
}}
>

View File

@@ -271,13 +271,13 @@ const _TabsHolder = () => {
setTimeout(() => {
switch (current) {
case "tablet":
introCompleted && tabBarRef.current?.goToIndex(0, false);
tabBarRef.current?.goToIndex(0, false);
break;
case "smallTablet":
if (!fullscreen) {
introCompleted && tabBarRef.current?.closeDrawer(false);
tabBarRef.current?.closeDrawer(false);
} else {
introCompleted && tabBarRef.current?.openDrawer(false);
tabBarRef.current?.openDrawer(false);
}
break;
case "mobile":
@@ -416,64 +416,66 @@ const _TabsHolder = () => {
backgroundColor="transparent"
/>
{deviceMode && widths[deviceMode] ? (
<FluidTabs
ref={tabBarRef}
dimensions={dimensions}
widths={!introCompleted ? widths["mobile"] : widths[deviceMode]}
enabled={deviceMode !== "tablet" && !fullscreen}
onScroll={onScroll}
onChangeTab={onChangeTab}
onDrawerStateChange={() => true}
>
<View
key="1"
style={{
height: "100%",
width: fullscreen
? 0
: widths[!introCompleted ? "mobile" : deviceMode]?.a
}}
>
<SideMenu />
</View>
<View
key="2"
style={{
height: "100%",
width: fullscreen
? 0
: widths[!introCompleted ? "mobile" : deviceMode]?.b
}}
>
{deviceMode === "mobile" ? (
<Animated.View
onTouchEnd={() => {
tabBarRef.current?.closeDrawer();
animatedOpacity.value = withTiming(0);
animatedTranslateY.value = withTiming(-9999);
{!introCompleted ? (
<NavigationStack />
) : (
<>
{deviceMode && widths[deviceMode] ? (
<FluidTabs
ref={tabBarRef}
dimensions={dimensions}
widths={widths[deviceMode]}
enabled={deviceMode !== "tablet" && !fullscreen}
onScroll={onScroll}
onChangeTab={onChangeTab}
onDrawerStateChange={() => true}
>
<View
key="1"
style={{
height: "100%",
width: fullscreen ? 0 : widths[deviceMode]?.a
}}
style={[
{
position: "absolute",
width: "100%",
height: "100%",
zIndex: 999,
backgroundColor: "rgba(0,0,0,0.2)"
},
animatedStyle
]}
ref={overlayRef}
/>
) : null}
>
<SideMenu />
</View>
<NavigationStack />
</View>
<View
key="2"
style={{
height: "100%",
width: fullscreen ? 0 : widths[deviceMode]?.b
}}
>
{deviceMode === "mobile" ? (
<Animated.View
onTouchEnd={() => {
tabBarRef.current?.closeDrawer();
animatedOpacity.value = withTiming(0);
animatedTranslateY.value = withTiming(-9999);
}}
style={[
{
position: "absolute",
width: "100%",
height: "100%",
zIndex: 999,
backgroundColor: "rgba(0,0,0,0.2)"
},
animatedStyle
]}
ref={overlayRef}
/>
) : null}
<EditorWrapper key="3" width={widths} dimensions={dimensions} />
</FluidTabs>
) : null}
<NavigationStack />
</View>
<EditorWrapper key="3" width={widths} dimensions={dimensions} />
</FluidTabs>
) : null}
</>
)}
</View>
);
};

View File

@@ -28,7 +28,8 @@
"zustand": "^3.6.0",
"fflate": "^0.7.3",
"timeago.js": "4.0.2",
"react-native-blob-util": "0.17.3"
"react-native-blob-util": "0.17.3",
"react-native-swiper-flatlist": "3.2.2"
},
"sideEffects": false
}

View File

@@ -17,34 +17,36 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useState } from "react";
import { Dimensions, LayoutAnimation, Platform, View } from "react-native";
import React from "react";
import { Platform, View } from "react-native";
import Animated, { FadeInDown, FadeOutUp } from "react-native-reanimated";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { SVG_Z } from "../../components/intro";
import { WelcomeNotice } from "../../components/intro/welcome";
import { AuthMode } from "../../components/auth";
import { Button } from "../../components/ui/button";
import { PressableButton } from "../../components/ui/pressable";
import Seperator from "../../components/ui/seperator";
import { SvgView } from "../../components/ui/svg";
import { BouncingView } from "../../components/ui/transitions/bouncing-view";
import Heading from "../../components/ui/typography/heading";
import Paragraph from "../../components/ui/typography/paragraph";
import BiometicService from "../../services/biometrics";
import { DDS } from "../../services/device-detection";
import { presentSheet, ToastEvent } from "../../services/event-manager";
import {
ToastEvent,
eSendEvent,
presentSheet
} from "../../services/event-manager";
import Navigation from "../../services/navigation";
import SettingsService from "../../services/settings";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeStore } from "../../stores/use-theme-store";
import { useUserStore } from "../../stores/use-user-store";
import { getElevation } from "../../utils";
import { eOpenLoginDialog } from "../../utils/events";
import { SIZE } from "../../utils/size";
import { requestInAppReview } from "../../services/app-review";
const AppLock = ({ route }) => {
const colors = useThemeStore((state) => state.colors);
const appLockMode = useSettingStore((state) => state.settings.appLockMode);
const [step, setStep] = useState(0);
const welcome = route?.params?.welcome;
const deviceMode = useSettingStore((state) => state.deviceMode);
const modes = [
{
@@ -77,13 +79,12 @@ const AppLock = ({ route }) => {
exiting={!welcome ? undefined : FadeOutUp}
entering={!welcome ? undefined : FadeInDown}
style={{
justifyContent: !welcome ? undefined : "center",
height: !welcome ? undefined : "100%",
width: !welcome ? undefined : "100%"
}}
>
{step === 0 ? (
<>
<>
{!welcome ? (
<View
style={{
flexDirection: "row",
@@ -126,124 +127,164 @@ const AppLock = ({ route }) => {
</Paragraph>
</View>
</View>
<Seperator />
) : (
<View
style={{
paddingHorizontal: 12,
width: DDS.isTab && welcome ? "50%" : "100%",
alignSelf: "center"
flex: 0.35,
justifyContent: "flex-end",
paddingHorizontal: 20,
backgroundColor: colors.nav,
marginBottom: 20,
borderBottomWidth: 1,
borderBottomColor: colors.border,
alignSelf: deviceMode !== "mobile" ? "center" : undefined,
borderWidth: deviceMode !== "mobile" ? 1 : null,
borderColor: deviceMode !== "mobile" ? colors.border : null,
borderRadius: deviceMode !== "mobile" ? 20 : null,
marginTop: deviceMode !== "mobile" ? 50 : null,
width: deviceMode === "mobile" ? null : "50%"
}}
>
{modes.map((item) => (
<PressableButton
key={item.title}
type={appLockMode === item.value ? "grayBg" : "transparent"}
onPress={async () => {
if (
!(await BiometicService.isBiometryAvailable()) &&
!useUserStore.getState().user
) {
ToastEvent.show({
heading: "Biometrics not enrolled",
type: "error",
message:
"To use app lock, you must enable biometrics such as Fingerprint lock or Face ID on your phone or create an account."
});
return;
}
SettingsService.set({ appLockMode: item.value });
if (!welcome) {
requestInAppReview();
}
}}
customStyle={{
justifyContent: "flex-start",
alignItems: "flex-start",
paddingHorizontal: 12,
paddingVertical: 12,
marginTop: 0,
marginBottom: 12,
borderWidth: 1,
borderColor:
appLockMode === item.value ? item.activeColor : colors.nav
}}
<View
style={{
flexDirection: "row"
}}
>
<View
style={{
marginBottom: 10
width: 100,
height: 5,
backgroundColor: colors.accent,
borderRadius: 2,
marginRight: 7
}}
>
<Heading
color={
appLockMode === item.value ? item.activeColor : colors.pri
}
style={{ maxWidth: "95%" }}
size={SIZE.md}
>
{item.title}
</Heading>
<Paragraph
color={
appLockMode === item.value
? item.activeColor
: colors.icon
}
style={{ maxWidth: "95%" }}
size={SIZE.sm}
>
{item.desc}
</Paragraph>
</PressableButton>
))}
{welcome && (
<Button
fontSize={SIZE.md}
height={45}
width={250}
onPress={async () => {
LayoutAnimation.configureNext({
...LayoutAnimation.Presets.linear,
delete: {
duration: 50,
property: "opacity",
type: "linear"
}
});
setStep(1);
}}
style={{
paddingHorizontal: 24,
alignSelf: "center",
borderRadius: 100,
...getElevation(5),
marginTop: 30
}}
type="accent"
title="Next"
/>
)}
</View>
</>
) : (
<WelcomeNotice />
)}
{welcome && !colors.night ? (
<BouncingView
<View
style={{
width: 20,
height: 5,
backgroundColor: colors.nav,
borderRadius: 2
}}
/>
</View>
<Heading
style={{
marginTop: 10
}}
extraBold
size={SIZE.xxl}
>
Protect your notes
</Heading>
<Paragraph
style={{
marginBottom: 25
}}
>
Choose how you want to secure your notes locally.
</Paragraph>
</View>
)}
<Seperator />
<View
style={{
position: "absolute",
bottom: DDS.isTab ? -300 : -130,
zIndex: -1
paddingHorizontal: 12,
width: DDS.isTab && welcome ? "50%" : "100%",
alignSelf: "center",
flex: 0.65
}}
animated={false}
duration={3000}
>
<SvgView
width={Dimensions.get("window").width}
height={Dimensions.get("window").width}
src={SVG_Z}
/>
</BouncingView>
) : null}
{modes.map((item) => (
<PressableButton
key={item.title}
type={appLockMode === item.value ? "grayBg" : "transparent"}
onPress={async () => {
if (
!(await BiometicService.isBiometryAvailable()) &&
!useUserStore.getState().user
) {
ToastEvent.show({
heading: "Biometrics not enrolled",
type: "error",
message:
"To use app lock, you must enable biometrics such as Fingerprint lock or Face ID on your phone or create an account."
});
return;
}
SettingsService.set({ appLockMode: item.value });
}}
customStyle={{
justifyContent: "flex-start",
alignItems: "flex-start",
paddingHorizontal: 12,
paddingVertical: 12,
marginTop: 0,
marginBottom: 12,
borderWidth: 1,
borderColor:
appLockMode === item.value ? item.activeColor : colors.nav
}}
style={{
marginBottom: 10
}}
>
<Heading
color={
appLockMode === item.value ? item.activeColor : colors.pri
}
style={{ maxWidth: "95%" }}
size={SIZE.md}
>
{item.title}
</Heading>
<Paragraph
color={
appLockMode === item.value ? item.activeColor : colors.icon
}
style={{ maxWidth: "95%" }}
size={SIZE.sm}
>
{item.desc}
</Paragraph>
</PressableButton>
))}
{welcome && (
<Button
fontSize={SIZE.md}
width={250}
onPress={async () => {
eSendEvent(eOpenLoginDialog, AuthMode.welcomeSignup);
setTimeout(() => {
SettingsService.set({
introCompleted: true
});
Navigation.replace(
{
name: "Notes"
},
{
canGoBack: false
}
);
}, 1000);
}}
style={{
paddingHorizontal: 24,
alignSelf: "center",
...getElevation(5),
marginTop: 30,
borderRadius: 100
}}
type="accent"
title="Next"
/>
)}
</View>
</>
</Animated.View>
</>
);

View File

@@ -179,7 +179,6 @@ const onUserStatusCheck = async (type) => {
const showVerifyEmailDialog = () => {
presentSheet({
title: "Confirm your email",
icon: "email",
paragraph:
"We have sent you an email confirmation link. Please check your email inbox. If you cannot find the email, check your spam folder.",
action: async () => {
@@ -369,7 +368,7 @@ const features_list = [
"Rich note editing experience with markdown, tables, checklists and more"
},
{
content: "Export your notes in Pdf, markdown and html formats"
content: "Export your notes in PDF, markdown and html formats"
}
];
@@ -388,7 +387,7 @@ const sheet = (context, promo, trial) => {
<Seperator />
<CompactFeatures
scrollRef={ref}
maxHeight={300}
maxHeight={400}
features={features_list}
vertical
/>

View File

@@ -46,6 +46,7 @@
</dict>
<key>UIAppFonts</key>
<array>
<string>OpenSans-Bold.ttf</string>
<string>OpenSans-SemiBold.ttf</string>
<string>OpenSans-Regular.ttf</string>
<string>MaterialCommunityIcons.ttf</string>

View File

@@ -23,6 +23,8 @@
6515C42F2580AA3000E83E39 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6515C42E2580AA2F00E83E39 /* StoreKit.framework */; };
6529A13E279BC4C70048D4A8 /* BootSplash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6529A13D279BC4C70048D4A8 /* BootSplash.storyboard */; };
6593E4A3281C345400492C50 /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6593E4A2281C345400492C50 /* AppDelegate.mm */; };
659670B22A2754FD00C5D2AF /* OpenSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 659670B12A2754FD00C5D2AF /* OpenSans-Bold.ttf */; };
659670B32A2754FD00C5D2AF /* OpenSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 659670B12A2754FD00C5D2AF /* OpenSans-Bold.ttf */; };
659BE46725E11A5100E05671 /* notesnook-text.png in Resources */ = {isa = PBXBuildFile; fileRef = 659BE46625E11A5100E05671 /* notesnook-text.png */; };
65AA857925E6DDEC00772A01 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65AA857825E6DDEC00772A01 /* WidgetKit.framework */; };
65AA857B25E6DDEC00772A01 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65AA857A25E6DDEC00772A01 /* SwiftUI.framework */; };
@@ -116,6 +118,7 @@
6552012E27019F6E00A43C51 /* OpenSans-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-SemiBold.ttf"; path = "../android/app/src/main/assets/fonts/OpenSans-SemiBold.ttf"; sourceTree = "<group>"; };
6552012F27019F7700A43C51 /* OpenSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Regular.ttf"; path = "../android/app/src/main/assets/fonts/OpenSans-Regular.ttf"; sourceTree = "<group>"; };
6593E4A2281C345400492C50 /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = Notesnook/AppDelegate.mm; sourceTree = "<group>"; };
659670B12A2754FD00C5D2AF /* OpenSans-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Bold.ttf"; path = "../android/app/src/main/assets/fonts/OpenSans-Bold.ttf"; sourceTree = "<group>"; };
659BE46625E11A5100E05671 /* notesnook-text.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "notesnook-text.png"; path = "Notesnook/Images.xcassets/notesnook-text.png"; sourceTree = "<group>"; };
65A7F34F255689AD00699170 /* Notesnook.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Notesnook.entitlements; path = Notesnook/Notesnook.entitlements; sourceTree = "<group>"; };
65AA857725E6DDEC00772A01 /* NotesWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotesWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -294,6 +297,7 @@
6510E6D62877215700DACAA9 /* build.bundle */,
65EC5B71272A7EE200FB3748 /* NotesWidgetExtensionDebug.entitlements */,
6552012F27019F7700A43C51 /* OpenSans-Regular.ttf */,
659670B12A2754FD00C5D2AF /* OpenSans-Bold.ttf */,
6552012E27019F6E00A43C51 /* OpenSans-SemiBold.ttf */,
65D145C429DC30470056FE7D /* MaterialCommunityIcons.ttf */,
13B07FAE1A68108700A75B9A /* Notesnook */,
@@ -538,6 +542,7 @@
files = (
6510626F27042891009661C3 /* OpenSans-Regular.ttf in Resources */,
65D145C529DC30470056FE7D /* MaterialCommunityIcons.ttf in Resources */,
659670B22A2754FD00C5D2AF /* OpenSans-Bold.ttf in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
6529A13E279BC4C70048D4A8 /* BootSplash.storyboard in Resources */,
6510E6D72877215700DACAA9 /* build.bundle in Resources */,
@@ -575,6 +580,7 @@
files = (
6510E6D82877215700DACAA9 /* build.bundle in Resources */,
65D145C629DC30470056FE7D /* MaterialCommunityIcons.ttf in Resources */,
659670B32A2754FD00C5D2AF /* OpenSans-Bold.ttf in Resources */,
6510627727042896009661C3 /* OpenSans-SemiBold.ttf in Resources */,
6510627527042893009661C3 /* OpenSans-Regular.ttf in Resources */,
65B5014725A672B200E2D264 /* MainInterface.storyboard in Resources */,

View File

@@ -58,11 +58,11 @@
"@bam.tech/react-native-image-resizer": "3.0.5",
"react-native-navigation-bar-color": "2.0.2",
"react-native-actions-shortcuts": "^1.0.1",
"react-native-in-app-review": "4.3.3",
"react-native-zip-archive": "6.0.9",
"react-native-vector-icons": "9.2.0",
"react-native-pdf": "6.6.2",
"react-native-blob-util": "0.17.3"
"react-native-blob-util": "0.17.3",
"react-native-in-app-review": "4.3.3"
},
"devDependencies": {
"@babel/core": "^7.12.9",

View File

@@ -14,7 +14,8 @@
],
"dependencies": {
"react": "18.0.0",
"react-native": "0.69.7"
"react-native": "0.69.7",
"react-native-swiper-flatlist": "3.2.2"
},
"devDependencies": {
"otplib": "12.0.1",
@@ -48,6 +49,7 @@
"react-native-qrcode-svg": "^6.0.6",
"react-native-reanimated-material-menu": "github:ammarahm-ed/react-native-reanimated-material-menu",
"react-native-reanimated-progress-bar": "1.0.1",
"react-native-swiper-flatlist": "3.2.2",
"timeago.js": "4.0.2",
"toggle-switch-react-native": "3.2.0",
"url": "^0.11.0",
@@ -18167,6 +18169,14 @@
"react-native": ">=0.50.0"
}
},
"node_modules/react-native-swiper-flatlist": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/react-native-swiper-flatlist/-/react-native-swiper-flatlist-3.2.2.tgz",
"integrity": "sha512-VVtxJCb2QHGA3ZpLiFqEHv6wyTlnlov5kL0dPKCb9Kc/W1wx8x2ZRFJU2Xja60CKbXDr5zwpxRayBm3bLgFEPg==",
"peerDependencies": {
"react-native": ">=0.59.0"
}
},
"node_modules/react-native-tooltips": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/react-native-tooltips/-/react-native-tooltips-1.0.3.tgz",

View File

@@ -34,6 +34,7 @@
"@notesnook/core": "*",
"@notesnook/editor": "*",
"@notesnook/editor-mobile": "*",
"react-native-swiper-flatlist": "3.2.2",
"@notesnook/logger": "*"
}
}