lazy load components

This commit is contained in:
Ammar Ahmed
2022-07-06 12:17:08 +05:00
parent add9473157
commit 5ecf2929c6
33 changed files with 654 additions and 254 deletions

View File

@@ -2,6 +2,7 @@ package com.streetwriters.notesnook;
import android.app.Application;
import android.content.Context;
import android.util.Log;
import com.dooboolab.RNIap.RNIapModule;
import com.facebook.react.PackageList;
@@ -34,6 +35,7 @@ import com.streetwriters.notesnook.newarchitecture.MainApplicationReactNativeHos
import cl.json.RNShareModule;
import px.tooltips.RNTooltipsModule;
import io.csie.kudo.reactnative.v8.executor.V8ExecutorFactory;
import androidx.annotation.Nullable;
public class MainApplication extends MultiDexApplication implements ReactApplication {
@@ -47,6 +49,17 @@ public class MainApplication extends MultiDexApplication implements ReactApplica
return BuildConfig.DEBUG;
}
@Nullable
@Override
protected String getBundleAssetName() {
final String v8BundleAssetName = V8ExecutorFactory.getBundleAssetName(getApplicationContext(), getUseDeveloperSupport());
if (v8BundleAssetName != null) {
return v8BundleAssetName;
}
Log.d("Notesnook:::", "LOADED" + v8BundleAssetName + super.getBundleAssetName());
return super.getBundleAssetName();
}
@Override
protected JavaScriptExecutorFactory getJavaScriptExecutorFactory() {
return new V8ExecutorFactory(

View File

@@ -6,9 +6,7 @@
<item name="android:windowDisablePreview">true</item>
<item name="android:editTextBackground">@drawable/edit_text</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
<style name="Share.Window" parent="Theme.AppCompat">

View File

@@ -41,5 +41,5 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
newArchEnabled=false
# V8 Cache Mode Config
v8.cacheMode=normal
v8.cacheMode=normalWithStubBundle
v8.android.tools.dir=/home/ammarahm-ed/Repos/notesnook-mobile/node_modules/v8-android-jit-nointl/dist/tools/android

View File

@@ -18,7 +18,7 @@ const configs = {
production: {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'transform-remove-console',
//'transform-remove-console',
'@babel/plugin-transform-named-capturing-groups-regex',
'react-native-reanimated/plugin'
]

View File

@@ -1,5 +1,63 @@
/* eslint-disable @typescript-eslint/no-var-requires */
global.Buffer = require('buffer').Buffer;
import { DOMParser } from './worker';
import { ScriptManager, Script } from '@callstack/repack/client';
import './src/utils/logger/index';
global.DOMParser = DOMParser;
class DOM {
static domparser;
parseFromString(markupLanguage, mimeType, globals) {
return DOM.domparser?.parseFromString(markupLanguage, mimeType, globals);
}
static async prepare() {
if (!DOM.domparser) {
let module = await import('./worker.js');
DOM.domparser = new module.DOMParser();
}
}
}
global.DOMParser = DOM;
try {
const shared = ScriptManager.shared;
} catch (e) {
new ScriptManager({
resolve: async (scriptId, caller) => {
if (__DEV__) {
return {
url: Script.getDevServerURL(scriptId),
cache: false
};
}
return {
url: Script.getFileSystemURL(scriptId)
};
}
});
}
ScriptManager.shared.on('resolving', (...args) => {
console.log('DEBUG/resolving', ...args);
});
ScriptManager.shared.on('resolved', (...args) => {
console.log('DEBUG/resolved', ...args);
});
ScriptManager.shared.on('prefetching', (...args) => {
console.log('DEBUG/prefetching', ...args);
});
ScriptManager.shared.on('loading', (...args) => {
console.log('DEBUG/loading', ...args);
});
ScriptManager.shared.on('loaded', (...args) => {
console.log('DEBUG/loaded', ...args);
});
ScriptManager.shared.on('error', (...args) => {
console.log('DEBUG/error', ...args);
});

View File

@@ -10,7 +10,6 @@ import { SafeAreaProvider } from 'react-native-safe-area-context';
import { enableScreens } from 'react-native-screens';
import appJson from './app.json';
import Notifications from './src/services/notifications';
enableLayoutAnimations(true);
const appName = appJson.name;
if (Config.isTesting) {

View File

@@ -1,6 +1,5 @@
import React from 'react';
import { TouchableOpacity, View } from 'react-native';
import * as Progress from 'react-native-progress';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { useAttachmentStore } from '../../stores/use-attachment-store';
import { useThemeStore } from '../../stores/use-theme-store';
@@ -10,6 +9,7 @@ import { useAttachmentProgress } from '../../utils/hooks/use-attachment-progress
import { SIZE } from '../../utils/size';
import SheetProvider from '../sheet-provider';
import { IconButton } from '../ui/icon-button';
import { ProgressCircleComponent } from '../ui/svg/lazy';
import Paragraph from '../ui/typography/paragraph';
import Actions from './actions';
@@ -113,24 +113,26 @@ export const AttachmentItem = ({ attachment, encryption, setAttachments }) => {
marginRight: -5
}}
>
<Progress.Circle
size={SIZE.xxl}
progress={
encryptionProgress
? encryptionProgress
: currentProgress?.value
? currentProgress?.value / 100
: 0
}
showsText
textStyle={{
fontSize: 10
}}
color={colors.accent}
formatText={progress => (progress * 100).toFixed(0)}
borderWidth={0}
thickness={2}
/>
<React.Suspense fallback={<View />}>
<ProgressCircleComponent
size={SIZE.xxl}
progress={
encryptionProgress
? encryptionProgress
: currentProgress?.value
? currentProgress?.value / 100
: 0
}
showsText
textStyle={{
fontSize: 10
}}
color={colors.accent}
formatText={progress => (progress * 100).toFixed(0)}
borderWidth={0}
thickness={2}
/>
</React.Suspense>
</TouchableOpacity>
) : (
<>

View File

@@ -1,14 +1,14 @@
import React, { useEffect, useRef, useState } from 'react';
import { Platform, StatusBar } from 'react-native';
import { Platform } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
import { eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
import { useThemeStore } from '../../stores/use-theme-store';
import { eCloseLoginDialog, eOpenLoginDialog } from '../../utils/events';
import { sleep } from '../../utils/time';
import BaseDialog from '../dialog/base-dialog';
import { Toast } from '../toast';
import { IconButton } from '../ui/icon-button';
import { initialAuthMode } from './common';
import { hideAuth, initialAuthMode } from './common';
import { Login } from './login';
import { Signup } from './signup';
@@ -37,7 +37,7 @@ const AuthModal = () => {
async function open(mode) {
setCurrentAuthMode(mode ? mode : AuthMode.login);
initialAuthMode.current = -1;
initialAuthMode.current = mode ? mode : AuthMode.login;
setVisible(true);
await sleep(10);
actionSheetRef.current?.show();
@@ -60,30 +60,36 @@ const AuthModal = () => {
bounce={false}
background={colors.bg}
transparent={false}
animated={false}
>
{currentAuthMode !== AuthMode.login ? (
<Signup
changeMode={mode => setCurrentAuthMode(mode)}
trial={AuthMode.trialSignup === currentAuthMode}
welcome={currentAuthMode === AuthMode.welcomeSignup}
welcome={initialAuthMode.current === AuthMode.welcomeSignup}
/>
) : (
<Login changeMode={mode => setCurrentAuthMode(mode)} />
<Login
welcome={initialAuthMode.current === AuthMode.welcomeSignup}
changeMode={mode => setCurrentAuthMode(mode)}
/>
)}
<IconButton
name="arrow-left"
onPress={() => {
eSendEvent(eCloseLoginDialog);
}}
color={colors.pri}
customStyle={{
position: 'absolute',
zIndex: 999,
left: 12,
top: Platform.OS === 'ios' ? 12 + insets.top : 12
}}
/>
{initialAuthMode.current === AuthMode.welcomeSignup ? null : (
<IconButton
name="arrow-left"
onPress={() => {
hideAuth();
}}
color={colors.pri}
customStyle={{
position: 'absolute',
zIndex: 999,
left: 12,
top: Platform.OS === 'ios' ? 12 + insets.top : insets.top
}}
/>
)}
<Toast context="local" />
</BaseDialog>

View File

@@ -7,27 +7,20 @@ import { tabBarRef } from '../../utils/global-refs';
export const initialAuthMode = createRef(0);
export function hideAuth() {
if (initialAuthMode.current === -1) {
eSendEvent(eCloseLoginDialog);
return;
}
if (initialAuthMode.current === 2) {
Navigation.replace(
{
name: 'Notes'
},
{
menu: true
}
);
} else {
Navigation.goBack();
}
eSendEvent(eCloseLoginDialog);
tabBarRef.current?.unlock();
if (!SettingsService.get().introCompleted) {
SettingsService.set({
introCompleted: true
});
}
// if (initialAuthMode.current === 2) {
// Navigation.replace(
// {
// name: 'Notes'
// },
// {
// menu: true
// }
// );
// } else {
// Navigation.goBack();
// }
// tabBarRef.current?.unlock();
}

View File

@@ -23,7 +23,7 @@ const Auth = ({ navigation, route }) => {
initialAuthMode.current = route?.params.mode || AuthMode.login;
useNavigationFocus(navigation, {
onFocus: () => {
tabBarRef?.current.lock();
//tabBarRef?.current.lock();
initialAuthMode.current = route?.params.mode || AuthMode.login;
}
});

View File

@@ -20,10 +20,7 @@ export const RightMenus = () => {
return (
<View style={styles.rightBtnContainer}>
{!currentScreen.startsWith('Settings') &&
currentScreen !== 'Auth' &&
currentScreen !== 'Signup' &&
currentScreen !== 'Login' ? (
{!currentScreen.startsWith('Settings') ? (
<IconButton
onPress={async () => {
SearchService.prepareSearch();

View File

@@ -1,9 +1,12 @@
import React from 'react';
import Animated, { FadeInDown } from 'react-native-reanimated';
import { eSendEvent } from '../../services/event-manager';
import Navigation from '../../services/navigation';
import SettingsService from '../../services/settings';
import { useThemeStore } from '../../stores/use-theme-store';
import { getElevation } from '../../utils';
import umami from '../../utils/analytics';
import { eOpenLoginDialog } from '../../utils/events';
import { SIZE } from '../../utils/size';
import { AuthMode } from '../auth';
import { Button } from '../ui/button';
@@ -44,14 +47,20 @@ export const WelcomeNotice = () => {
height={45}
width={250}
onPress={async () => {
Navigation.navigate(
{
name: 'Auth'
},
{
mode: AuthMode.welcomeSignup
}
);
eSendEvent(eOpenLoginDialog, AuthMode.welcomeSignup);
SettingsService.set({
introCompleted: true
});
setTimeout(() => {
Navigation.replace(
{
name: 'Notes'
},
{
canGoBack: false
}
);
}, 1000);
umami.pageView('/encryptionnotice', '/welcome/privacymode');
}}
style={{

View File

@@ -16,7 +16,7 @@ import { useNoteStore } from '../../stores/use-notes-store';
import { useSettingStore } from '../../stores/use-setting-store';
import { useThemeStore } from '../../stores/use-theme-store';
import { useUserStore } from '../../stores/use-user-store';
import { db } from '../../utils/database';
import { db, loadDatabase } from '../../utils/database';
import { MMKV } from '../../utils/database/mmkv';
import { eOpenAnnouncementDialog } from '../../utils/events';
import { tabBarRef } from '../../utils/global-refs';
@@ -68,7 +68,8 @@ const Launcher = React.memo(
const init = async () => {
if (!dbInitCompleted.current) {
await RNBootSplash.hide();
if (!verifyUser) await RNBootSplash.hide({ fade: true });
await loadDatabase();
await db.init();
dbInitCompleted.current = true;
}
@@ -125,18 +126,16 @@ const Launcher = React.memo(
};
const checkAppUpdateAvailable = async () => {
return;
// try {
// const version = await checkVersion();
// if (!version.needsUpdate) return false;
// presentSheet({
// component: ref => <Update version={version} fwdRef={ref} />
// });
// return true;
// } catch (e) {
// return false;
// }
try {
const version = await checkVersion();
if (!version.needsUpdate) return false;
presentSheet({
component: ref => <Update version={version} fwdRef={ref} />
});
return true;
} catch (e) {
return false;
}
};
const restoreEditorState = async () => {

View File

@@ -1,11 +1,11 @@
import React, { useEffect, useState } from 'react';
import { View } from 'react-native';
import * as ProgressBar from 'react-native-progress';
import { presentSheet } from '../../../services/event-manager';
import { useThemeStore } from '../../../stores/use-theme-store';
import useSyncProgress from '../../../utils/hooks/use-sync-progress';
import { SIZE } from '../../../utils/size';
import Seperator from '../../ui/seperator';
import { ProgressBarComponent } from '../../ui/svg/lazy';
import Heading from '../../ui/typography/heading';
import Paragraph from '../../ui/typography/paragraph';
@@ -41,16 +41,18 @@ export const Progress = () => {
width: 200
}}
>
<ProgressBar.Bar
height={5}
width={null}
animated={true}
useNativeDriver
progress={currentProgress || 0.1}
unfilledColor={colors.nav}
color={colors.accent}
borderWidth={0}
/>
<React.Suspense fallback={<View />}>
<ProgressBarComponent
height={5}
width={null}
animated={true}
useNativeDriver
progress={currentProgress || 0.1}
unfilledColor={colors.nav}
color={colors.accent}
borderWidth={0}
/>
</React.Suspense>
</View>
{progress ? (

View File

@@ -2,7 +2,6 @@ import Clipboard from '@react-native-clipboard/clipboard';
import React, { createRef } from 'react';
import { Platform, View } from 'react-native';
import FileViewer from 'react-native-file-viewer';
import QRCode from 'react-native-qrcode-svg';
import * as ScopedStorage from 'react-native-scoped-storage';
import Share from 'react-native-share';
//import { LOGO_BASE64 } from '../../../assets/images/assets';
@@ -19,6 +18,7 @@ import DialogHeader from '../../dialog/dialog-header';
import { Button } from '../../ui/button';
import Seperator from '../../ui/seperator';
import SheetWrapper from '../../ui/sheet';
import { QRCode } from '../../ui/svg/lazy';
import Paragraph from '../../ui/typography/paragraph';
let RNFetchBlob;
@@ -241,13 +241,15 @@ class RecoveryKeySheet extends React.Component {
}}
>
{this.state.key ? (
<QRCode
getRef={this.svg}
size={500}
value={this.state.key}
//logo={{ uri: LOGO_BASE64 }}
logoBorderRadius={10}
/>
<React.Suspense>
<QRCode
getRef={this.svg}
size={500}
value={this.state.key}
//logo={{ uri: LOGO_BASE64 }}
logoBorderRadius={10}
/>
</React.Suspense>
) : null}
</View>

File diff suppressed because one or more lines are too long

View File

@@ -13,9 +13,9 @@ import Heading from '../ui/typography/heading';
import Paragraph from '../ui/typography/paragraph';
import { TimeSince } from '../ui/time-since';
import useSyncProgress from '../../utils/hooks/use-sync-progress';
import * as Progress from 'react-native-progress';
import Navigation from '../../services/navigation';
import { tabBarRef } from '../../utils/global-refs';
import { ProgressCircleComponent } from '../ui/svg/lazy';
export const UserStatus = () => {
const colors = useThemeStore(state => state.colors);
@@ -48,15 +48,7 @@ export const UserStatus = () => {
await Sync.run();
} else {
tabBarRef.current?.closeDrawer();
Navigation.navigate(
{
name: 'Login'
},
{
mode: 0,
canGoBack: true
}
);
eSendEvent(eOpenLoginDialog);
}
}}
type="gray"
@@ -118,18 +110,20 @@ export const UserStatus = () => {
{user ? (
syncing ? (
<>
<Progress.Circle
size={SIZE.xl}
progress={progress ? progress.current / progress.total : 0.1}
textStyle={{
fontSize: 8
}}
animated={true}
color={colors.accent}
unfilledColor={colors.nav}
borderWidth={0}
thickness={2}
/>
<React.Suspense fallback={<View />}>
<ProgressCircleComponent
size={SIZE.xl}
progress={progress ? progress.current / progress.total : 0.1}
textStyle={{
fontSize: 8
}}
animated={true}
color={colors.accent}
unfilledColor={colors.nav}
borderWidth={0}
thickness={2}
/>
</React.Suspense>
</>
) : (
<Icon color={colors.accent} name="sync" size={SIZE.lg} />

View File

@@ -21,7 +21,6 @@ import { getElevation } from '../../../utils';
import { SIZE } from '../../../utils/size';
import { IconButton } from '../icon-button';
import Paragraph from '../typography/paragraph';
import phone from 'phone';
interface InputProps extends TextInputProps {
fwdRef?: RefObject<any>;
@@ -91,7 +90,7 @@ const Input = ({
const color = error ? colors.red : focus ? customColor || colors.accent : colors.nav;
const validate = (value: string) => {
const validate = async (value: string) => {
if (!validationType) return;
if (!value || value?.length === 0) {
setError(false);
@@ -117,6 +116,8 @@ const Input = ({
isError = customValidator && value === customValidator();
break;
case 'phonenumber':
// eslint-disable-next-line no-case-declarations
const phone = await (await import('phone')).default;
// eslint-disable-next-line no-case-declarations
let result = phone(value, {
strictDetection: true,

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { View } from 'react-native';
import { SvgXml } from 'react-native-svg';
import { SvgXml } from './lazy';
export const SvgView = ({
width = 250,
@@ -19,7 +19,9 @@ export const SvgView = ({
width: height || 250
}}
>
<SvgXml xml={src} width="100%" height="100%" />
<React.Suspense fallback={<View />}>
<SvgXml xml={src} width="100%" height="100%" />
</React.Suspense>
</View>
);
};

View File

@@ -0,0 +1,29 @@
import React from 'react';
export const QRCode = React.lazy(async () => {
const module = await (await import('./module-svg')).default;
return {
default: module.QRCode
};
});
export const SvgXml = React.lazy(async () => {
const module = await (await import('./module-svg')).default;
return {
default: module.SvgXml
};
});
export const ProgressBarComponent = React.lazy(async () => {
const module = await (await import('./module-svg')).default;
return {
default: module.Progress.Bar
};
});
export const ProgressCircleComponent = React.lazy(async () => {
const module = await (await import('./module-svg')).default;
return {
default: module.Progress.Circle
};
});

View File

@@ -0,0 +1,11 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import { Bar, Circle } from 'react-native-progress';
import QRCode from 'react-native-qrcode-svg';
import { SvgXml } from 'react-native-svg';
const Progress = {
Bar,
Circle
};
export default { Progress, QRCode, SvgXml };

View File

@@ -1,17 +1,18 @@
import React from 'react';
import { View } from 'react-native';
import DelayLayout from '../components/delay-layout';
import DialogProvider from '../components/dialog-provider';
import { Header } from '../components/header';
import Intro from '../components/intro';
import { Toast } from '../components/toast';
import SettingsService from '../services/settings';
import { useNoteStore } from '../stores/use-notes-store';
import { useSettingStore } from '../stores/use-setting-store';
import { TabsHolder } from './tabs-holder';
const DialogProvider = React.lazy(() => import('../components/dialogprovider'));
export const ApplicationHolder = React.memo(
() => {
const loading = useNoteStore(state => state.loading);
const introCompleted = SettingsService.get().introCompleted;
const introCompleted = useSettingStore(state => state.settings.introCompleted);
return loading && introCompleted ? (
<>
<Header />
@@ -21,7 +22,9 @@ export const ApplicationHolder = React.memo(
<>
<TabsHolder />
<Toast />
<DialogProvider />
<React.Suspense fallback={<View />}>
<DialogProvider />
</React.Suspense>
</>
);
},

View File

@@ -1,9 +1,6 @@
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import * as React from 'react';
import Auth from '../components/auth';
import { Login } from '../components/auth/login';
import { Signup } from '../components/auth/signup';
import Container from '../components/container';
import Intro from '../components/intro';
import Favorites from '../screens/favorites';
@@ -41,7 +38,6 @@ const IntroStack = createNativeStackNavigator();
const IntroStackNavigator = () => {
const colors = useThemeStore(state => state.colors);
const introCompleted = SettingsService.get().introCompleted;
return (
<IntroStack.Navigator
screenOptions={{
@@ -56,13 +52,6 @@ const IntroStackNavigator = () => {
>
<NativeStack.Screen name="Intro" component={Intro} />
<NativeStack.Screen name="AppLock" component={AppLock} />
<NativeStack.Screen
name="Auth"
initialParams={{
mode: 0
}}
component={Auth}
/>
</IntroStack.Navigator>
);
};
@@ -92,20 +81,6 @@ const Tabs = React.memo(
}
}}
>
<NativeStack.Screen
name="Signup"
initialParams={{
mode: 1
}}
component={Auth}
/>
<NativeStack.Screen
name="Login"
initialParams={{
mode: 0
}}
component={Auth}
/>
<NativeStack.Screen name="Welcome" component={IntroStackNavigator} />
<NativeStack.Screen name="Notes" component={Home} />
<NativeStack.Screen name="Notebooks" component={Notebooks} />

View File

@@ -1,10 +1,10 @@
import React, { useEffect, useRef, useState } from 'react';
import { View } from 'react-native';
import * as Progress from 'react-native-progress';
import { useThemeStore } from '../../stores/use-theme-store';
import { useAttachmentStore } from '../../stores/use-attachment-store';
import { SIZE } from '../../utils/size';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ProgressBarComponent } from '../../components/ui/svg/lazy';
export const ProgressBar = () => {
const colors = useThemeStore(state => state.colors);
@@ -50,14 +50,16 @@ export const ProgressBar = () => {
}}
onLayout={event => setWidth(event.nativeEvent.layout.width)}
>
<Progress.Bar
size={SIZE.xxl}
progress={prog}
color={colors.accent}
borderWidth={0}
height={1}
width={width || 400}
/>
<React.Suspense fallback={<View />}>
<ProgressBarComponent
size={SIZE.xxl}
progress={prog}
color={colors.accent}
borderWidth={0}
height={1}
width={width || 400}
/>
</React.Suspense>
</View>
) : null;
};

View File

@@ -72,8 +72,8 @@ export const useEditor = (editorId = '', readonly?: boolean) => {
useEffect(() => {
console.log('sessionId:', sessionId);
async () => {
await commands.setSessionId(sessionId);
if (sessionId) {
await commands.setSessionId(sessionIdRef.current);
if (sessionIdRef.current) {
if (!state.current?.ready) return;
await onReady();
}
@@ -88,7 +88,7 @@ export const useEditor = (editorId = '', readonly?: boolean) => {
};
const onReady = useCallback(async () => {
if (!(await isEditorLoaded(editorRef, sessionId))) {
if (!(await isEditorLoaded(editorRef, sessionIdRef.current))) {
console.log('reload editor');
overlay(true);
setLoading(true);

View File

@@ -47,21 +47,18 @@ export const Notebooks = ({ navigation, route }: NavigationProps<'Notebooks'>) =
});
SearchService.prepareSearch = prepareSearch;
RightMenus.floatingButtonAction = onPressFloatingButton;
return !prev?.current;
},
onBlur: () => false,
delay: SettingsService.get().homepage === route.name ? 1 : -1
});
useEffect(() => {
if (navigation.isFocused()) {
if (notebooks.length === 0) {
Walkthrough.present('notebooks');
} else {
Walkthrough.update('notebooks');
}
}
}, [notebooks]);
return !prev?.current;
},
onBlur: () => false,
delay: SettingsService.get().homepage === route.name ? 1 : -1
});
return (
<DelayLayout>

View File

@@ -1,10 +1,10 @@
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import React, { useEffect, useRef, useState } from 'react';
import { FlatList, View } from 'react-native';
import { Bar } from 'react-native-progress';
import Animated, { FadeInDown, FadeOutDown } from 'react-native-reanimated';
import DelayLayout from '../../components/delay-layout';
import BaseDialog from '../../components/dialog/base-dialog';
import { ProgressBarComponent } from '../../components/ui/svg/lazy';
import Heading from '../../components/ui/typography/heading';
import Paragraph from '../../components/ui/typography/paragraph';
import { eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
@@ -71,17 +71,19 @@ const Home = ({ navigation, route }: NativeStackScreenProps<RouteParams, 'Settin
marginTop: 15
}}
>
<Bar
height={5}
width={100}
animated={true}
useNativeDriver
indeterminate
indeterminateAnimationDuration={2000}
unfilledColor={colors.nav}
color={colors.accent}
borderWidth={0}
/>
<React.Suspense fallback={<View />}>
<ProgressBarComponent
height={5}
width={100}
animated={true}
useNativeDriver
indeterminate
indeterminateAnimationDuration={2000}
unfilledColor={colors.nav}
color={colors.accent}
borderWidth={0}
/>
</React.Suspense>
</View>
</View>
</BaseDialog>

View File

@@ -1,9 +1,10 @@
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack';
import React from 'react';
import DelayLayout from '../../components/delay-layout';
import { Header } from '../../components/header';
import useNavigationStore from '../../stores/use-navigation-store';
import { useThemeStore } from '../../stores/use-theme-store';
import Group from './group';
import Home from './home';
import { RouteParams } from './types';
const SettingsStack = createNativeStackNavigator();
const screenListeners = {
@@ -15,6 +16,34 @@ const screenListeners = {
}
};
const Home = React.lazy(() => import(/* webpackChunkName: "settings-home" */ './home'));
const Group = React.lazy(() => import(/* webpackChunkName: "settings-group" */ './group'));
const Fallback = () => {
return (
<>
<Header />
<DelayLayout wait={true} type="settings" />
</>
);
};
const HomeScreen = (props: NativeStackScreenProps<RouteParams, 'SettingsHome'>) => {
return (
<React.Suspense fallback={<Fallback />}>
<Home {...props} />
</React.Suspense>
);
};
const GroupScreen = (props: NativeStackScreenProps<RouteParams, 'SettingsGroup'>) => {
return (
<React.Suspense fallback={<Fallback />}>
<Group {...props} />
</React.Suspense>
);
};
export const Settings = () => {
const colors = useThemeStore(state => state.colors);
return (
@@ -29,8 +58,8 @@ export const Settings = () => {
}
}}
>
<SettingsStack.Screen name="SettingsHome" component={Home} />
<SettingsStack.Screen name="SettingsGroup" component={Group} />
<SettingsStack.Screen name="SettingsHome" component={HomeScreen} />
<SettingsStack.Screen name="SettingsGroup" component={GroupScreen} />
</SettingsStack.Navigator>
);
};

View File

@@ -1,34 +1,46 @@
import Database from 'notes-core/api/index';
import { Platform } from 'react-native';
import filesystem from '../filesystem';
import EventSource from '../sse/even-source-ios';
import AndroidEventSource from '../sse/event-source';
import Storage from './storage';
export const db = new Database(
Storage,
Platform.OS === 'ios' ? EventSource : AndroidEventSource,
filesystem
);
db.host(
__DEV__
? {
API_HOST: 'https://api.notesnook.com',
AUTH_HOST: 'https://auth.streetwriters.co',
SSE_HOST: 'https://events.streetwriters.co',
SUBSCRIPTIONS_HOST: 'https://subscriptions.streetwriters.co',
ISSUES_HOST: 'https://issues.streetwriters.co'
// API_HOST: 'http://192.168.10.29:5264',
// AUTH_HOST: 'http://192.168.10.29:8264',
// SSE_HOST: 'http://192.168.10.29:7264',
// SUBSCRIPTIONS_HOST: 'http://192.168.10.29:9264',
// ISSUES_HOST: 'http://192.168.10.29:2624'
}
: {
API_HOST: 'https://api.notesnook.com',
AUTH_HOST: 'https://auth.streetwriters.co',
SSE_HOST: 'https://events.streetwriters.co',
SUBSCRIPTIONS_HOST: 'https://subscriptions.streetwriters.co',
ISSUES_HOST: 'https://issues.streetwriters.co'
}
);
/**
* @type {import("notes-core/api/index").default}
*/
export var db;
let DB = null;
export async function loadDatabase() {
if (!DB) {
let module = await import(/* webpackChunkName: "notes-core" */ 'notes-core/api/index');
DB = module.default;
}
db = new DB(Storage, Platform.OS === 'ios' ? EventSource : AndroidEventSource, filesystem);
//@ts-ignore
if (DOMParser) {
//@ts-ignore
await DOMParser.prepare();
}
db.host(
__DEV__
? {
API_HOST: 'https://api.notesnook.com',
AUTH_HOST: 'https://auth.streetwriters.co',
SSE_HOST: 'https://events.streetwriters.co',
SUBSCRIPTIONS_HOST: 'https://subscriptions.streetwriters.co',
ISSUES_HOST: 'https://issues.streetwriters.co'
// API_HOST: 'http://192.168.10.29:5264',
// AUTH_HOST: 'http://192.168.10.29:8264',
// SSE_HOST: 'http://192.168.10.29:7264',
// SUBSCRIPTIONS_HOST: 'http://192.168.10.29:9264',
// ISSUES_HOST: 'http://192.168.10.29:2624'
}
: {
API_HOST: 'https://api.notesnook.com',
AUTH_HOST: 'https://auth.streetwriters.co',
SSE_HOST: 'https://events.streetwriters.co',
SUBSCRIPTIONS_HOST: 'https://subscriptions.streetwriters.co',
ISSUES_HOST: 'https://issues.streetwriters.co'
}
);
}

View File

@@ -233,15 +233,7 @@ export const useActions = ({ close = () => {}, item }) => {
message: 'Login to publish note',
context: 'local',
func: () => {
Navigation.navigate(
{
name: 'Login'
},
{
mode: AuthMode.login,
canGoBack: true
}
);
eSendEvent(eOpenLoginDialog);
},
actionText: 'Login'
});

View File

@@ -126,7 +126,7 @@ export async function toTXT(note, notitle) {
} else {
text = await db.notes.note(note.id).content();
}
htmlToText = htmlToText || require('html-to-text');
htmlToText = htmlToText || (await import('html-to-text'));
text = htmlToText.convert(text, {
selectors: [{ selector: 'img', format: 'skip' }]
});

View File

@@ -0,0 +1,271 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const Repack = require('@callstack/repack');
/**
* More documentation, installation, usage, motivation and differences with Metro is available at:
* https://github.com/callstack/repack/blob/main/README.md
*
* The API documentation for the functions and plugins used in this file is available at:
* https://re-pack.netlify.app/
*/
/**
* Webpack configuration.
* You can also export a static object or a function returning a Promise.
*
* @param env Environment options passed from either Webpack CLI or React Native CLI
* when running with `react-native start/bundle`.
*/
module.exports = env => {
const {
mode = 'development',
context = __dirname,
entry = './index.js',
platform,
minimize = mode === 'production',
devServer = undefined,
bundleFilename = undefined,
sourceMapFilename = undefined,
assetsPath = undefined,
reactNativePath = require.resolve('react-native')
} = env;
if (!platform) {
throw new Error('Missing platform');
}
/**
* Depending on your Babel configuration you might want to keep it.
* If you don't use `env` in your Babel config, you can remove it.
*
* Keep in mind that if you remove it you should set `BABEL_ENV` or `NODE_ENV`
* to `development` or `production`. Otherwise your production code might be compiled with
* in development mode by Babel.
*/
process.env.BABEL_ENV = mode;
return {
mode,
/**
* This should be always `false`, since the Source Map configuration is done
* by `SourceMapDevToolPlugin`.
*/
devtool: false,
context,
/**
* `getInitializationEntries` will return necessary entries with setup and initialization code.
* If you don't want to use Hot Module Replacement, set `hmr` option to `false`. By default,
* HMR will be enabled in development mode.
*/
entry: [
...Repack.getInitializationEntries(reactNativePath, {
hmr: devServer && devServer.hmr
}),
entry
],
resolve: {
/**
* `getResolveOptions` returns additional resolution configuration for React Native.
* If it's removed, you won't be able to use `<file>.<platform>.<ext>` (eg: `file.ios.js`)
* convention and some 3rd-party libraries that specify `react-native` field
* in their `package.json` might not work correctly.
*/
...Repack.getResolveOptions(platform)
/**
* Uncomment this to ensure all `react-native*` imports will resolve to the same React Native
* dependency. You might need it when using workspaces/monorepos or unconventional project
* structure. For simple/typical project you won't need it.
*/
// alias: {
// 'react-native': reactNativePath,
// },
},
/**
* Configures output.
* It's recommended to leave it as it is unless you know what you're doing.
* By default Webpack will emit files into the directory specified under `path`. In order for the
* React Native app use them when bundling the `.ipa`/`.apk`, they need to be copied over with
* `Repack.OutputPlugin`, which is configured by default inside `Repack.RepackPlugin`.
*/
output: {
clean: true,
path: path.join(__dirname, 'build/generated', platform),
filename: 'index.bundle',
chunkFilename: '[name].chunk.bundle',
publicPath: Repack.getPublicPath({ platform, devServer })
},
/**
* Configures optimization of the built bundle.
*/
optimization: {
/** Enables minification based on values passed from React Native CLI or from fallback. */
minimize,
/** Configure minimizer to process the bundle. */
minimizer: [
new TerserPlugin({
test: /\.(js)?bundle(\?.*)?$/i,
/**
* Prevents emitting text file with comments, licenses etc.
* If you want to gather in-file licenses, feel free to remove this line or configure it
* differently.
*/
extractComments: false,
terserOptions: {
format: {
comments: false
}
}
})
],
chunkIds: 'named'
},
module: {
/**
* This rule will process all React Native related dependencies with Babel.
* If you have a 3rd-party dependency that you need to transpile, you can add it to the
* `include` list.
*
* You can also enable persistent caching with `cacheDirectory` - please refer to:
* https://github.com/babel/babel-loader#options
*/
rules: [
{
test: /\.[jt]sx?$/,
include: [
/node_modules(.*[/\\])+react/,
/node_modules(.*[/\\])+@react-native/,
/node_modules(.*[/\\])+@react-navigation/,
/node_modules(.*[/\\])+@react-native-community/,
/node_modules(.*[/\\])+@expo/,
/node_modules(.*[/\\])+pretty-format/,
/node_modules(.*[/\\])+metro/,
/node_modules(.*[/\\])+abort-controller/,
/node_modules(.*[/\\])+@callstack[/\\]repack/,
/node_modules(.*[/\\])+pretty-format/,
/node_modules(.*[/\\])+@react-native-masked-view\/masked-view/,
/node_modules(.*[/\\])+toggle-switch-react-native/,
/node_modules(.*[/\\])+rn-fetch-blob/,
/node_modules(.*[/\\])+notes-core/,
/node_modules(.*[/\\])+@microsoft/,
/node_modules(.*[/\\])+@msgpack/,
/node_modules(.*[/\\])+liqe/
],
use: {
loader: 'babel-loader',
options: {
configFile: false,
cacheDirectory: path.join(__dirname, 'node_modules/.webpack-cache'),
babelrc: false,
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'react-native-reanimated/plugin',
'@babel/plugin-transform-named-capturing-groups-regex'
]
}
}
},
/**
* Here you can adjust loader that will process your files.
*
* You can also enable persistent caching with `cacheDirectory` - please refer to:
* https://github.com/babel/babel-loader#options
*/
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
/** Add React Refresh transform only when HMR is enabled. */
configFile: false,
cacheDirectory: path.join(__dirname, 'node_modules/.webpack-cache'),
babelrc: false,
presets: [
['module:metro-react-native-babel-preset', { disableImportExportTransform: true }]
],
plugins:
devServer && devServer.hmr
? ['module:react-refresh/babel', 'react-native-reanimated/plugin']
: [
'react-native-reanimated/plugin',
`@babel/plugin-transform-named-capturing-groups-regex`
//'transform-remove-console'
]
}
}
},
/**
* This loader handles all static assets (images, video, audio and others), so that you can
* use (reference) them inside your application.
*
* If you wan to handle specific asset type manually, filter out the extension
* from `ASSET_EXTENSIONS`, for example:
* ```
* Repack.ASSET_EXTENSIONS.filter((ext) => ext !== 'svg')
* ```
*/
{
test: Repack.getAssetExtensionsRegExp(
Repack.ASSET_EXTENSIONS.filter(ext => ext !== 'svg')
),
use: {
loader: '@callstack/repack/assets-loader',
options: {
platform,
devServerEnabled: Boolean(devServer),
/**
* Defines which assets are scalable - which assets can have
* scale suffixes: `@1x`, `@2x` and so on.
* By default all images are scalable.
*/
scalableAssetExtensions: Repack.SCALABLE_ASSETS
}
}
},
{
test: /\.svg$/,
use: [
{
loader: '@svgr/webpack',
options: {
native: true,
dimensions: false
}
}
]
}
]
},
plugins: [
/**
* Configure other required and additional plugins to make the bundle
* work in React Native and provide good development experience with
* sensible defaults.
*
* `Repack.RepackPlugin` provides some degree of customization, but if you
* need more control, you can replace `Repack.RepackPlugin` with plugins
* from `Repack.plugins`.
*/
new Repack.RepackPlugin({
context,
mode,
platform,
devServer,
output: {
bundleFilename,
sourceMapFilename,
assetsPath
},
extraChunks: [
{
type: 'local',
include: /.*/
}
]
})
]
};
};