mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-08-31 11:08:47 +02:00
Compare commits
248 Commits
fix-editor
...
fix-cursor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2bf73935a | ||
|
|
8078c3ed3c | ||
|
|
57280f3ebb | ||
|
|
dc54644b4f | ||
|
|
ce31b0495d | ||
|
|
a62d4b5d4b | ||
|
|
6f585c5e17 | ||
|
|
ffe7d944a6 | ||
|
|
bf0d6857d3 | ||
|
|
69f117bab7 | ||
|
|
cac945501d | ||
|
|
85a0762ccf | ||
|
|
0ce51bf481 | ||
|
|
6adc5065fb | ||
|
|
3b90a6d90e | ||
|
|
aa5e6e7199 | ||
|
|
ca53ec38d1 | ||
|
|
80a3cc2fc1 | ||
|
|
32c4e987dc | ||
|
|
ce0ef0a1cf | ||
|
|
95fc9bd3d0 | ||
|
|
fb21fef82f | ||
|
|
7760f5e898 | ||
|
|
fcc9915b04 | ||
|
|
8347dd5db7 | ||
|
|
c2d3ba087a | ||
|
|
e5883f179c | ||
|
|
f7f1d3b3f0 | ||
|
|
df3674f570 | ||
|
|
a62beab172 | ||
|
|
528810155f | ||
|
|
5c80b5300e | ||
|
|
36c33160f4 | ||
|
|
5cca28daa1 | ||
|
|
5298ccd638 | ||
|
|
a5db1797e3 | ||
|
|
b1d034cf3f | ||
|
|
4620ed0c1c | ||
|
|
5c87b6f3b0 | ||
|
|
29ad783b3f | ||
|
|
3eae13e237 | ||
|
|
ee222b6302 | ||
|
|
ae795a837d | ||
|
|
0396264842 | ||
|
|
e9fcd16fb5 | ||
|
|
944fcf0567 | ||
|
|
251cc08a7d | ||
|
|
d2719123eb | ||
|
|
88c0e2a2ce | ||
|
|
b4366058dd | ||
|
|
b103cc09f2 | ||
|
|
d35c0be116 | ||
|
|
c9cf15e519 | ||
|
|
408ae26b76 | ||
|
|
3159d8fcc5 | ||
|
|
b976788f07 | ||
|
|
a0311c1516 | ||
|
|
e17351f702 | ||
|
|
ffafae9970 | ||
|
|
fa3d993ffd | ||
|
|
2b7b8d526e | ||
|
|
270394dc36 | ||
|
|
552e8f50b7 | ||
|
|
b6d0d124fd | ||
|
|
7e3abc5819 | ||
|
|
6b3065617d | ||
|
|
9752ccf7cb | ||
|
|
ad1921a938 | ||
|
|
ed2201d525 | ||
|
|
09b9719a3f | ||
|
|
673ea6da86 | ||
|
|
77d81ecc12 | ||
|
|
00c38b6bcc | ||
|
|
24d9568c5d | ||
|
|
3b89b0c436 | ||
|
|
940a3de130 | ||
|
|
81b291ae37 | ||
|
|
f5ad31f0a3 | ||
|
|
59d4b92839 | ||
|
|
530c864d10 | ||
|
|
fae6bf8f43 | ||
|
|
c395bc829f | ||
|
|
19ee33ec3a | ||
|
|
64ab6a3436 | ||
|
|
b758cd28e5 | ||
|
|
db8e21f83b | ||
|
|
c23f31f284 | ||
|
|
84d5420b51 | ||
|
|
02bdc61543 | ||
|
|
71811ebf0d | ||
|
|
b07d7e4f3f | ||
|
|
b141907066 | ||
|
|
a0b46d49d6 | ||
|
|
85386c945f | ||
|
|
9de1373bdd | ||
|
|
6f4c35672d | ||
|
|
ed32552155 | ||
|
|
88858308fb | ||
|
|
78f875ab0f | ||
|
|
9104c64170 | ||
|
|
aabb33a435 | ||
|
|
ad43591f2c | ||
|
|
8bc779d882 | ||
|
|
193bddbe9e | ||
|
|
e03d394555 | ||
|
|
72e4116773 | ||
|
|
9b682163db | ||
|
|
076312da7a | ||
|
|
856a9b16e9 | ||
|
|
9de4e3eba6 | ||
|
|
d90d263b04 | ||
|
|
0170e51843 | ||
|
|
b7f5a5dc66 | ||
|
|
20866ab2f5 | ||
|
|
4efc13a602 | ||
|
|
96303f5d0f | ||
|
|
020c9b254e | ||
|
|
24c0f2f409 | ||
|
|
1b608f01ac | ||
|
|
fd98ab0a64 | ||
|
|
3d1dc879e0 | ||
|
|
16253b8bf7 | ||
|
|
3dba3079f7 | ||
|
|
1fe4ae199f | ||
|
|
55842f1265 | ||
|
|
6644940115 | ||
|
|
dfd0dc72b8 | ||
|
|
d7c4b9c776 | ||
|
|
728553115c | ||
|
|
6ee0d28a8b | ||
|
|
ead23c36c6 | ||
|
|
e62891b9c0 | ||
|
|
9483c63cdc | ||
|
|
3eab773fd1 | ||
|
|
30dd0e8657 | ||
|
|
5d05df7f83 | ||
|
|
ebf80aacc5 | ||
|
|
55c6be4622 | ||
|
|
8f1545916f | ||
|
|
7f05043e03 | ||
|
|
e663655924 | ||
|
|
2fab9dc6f1 | ||
|
|
aba79c11d3 | ||
|
|
4e897dde47 | ||
|
|
3375439e35 | ||
|
|
89dce0b655 | ||
|
|
ff53ea322d | ||
|
|
d6f6bc2c5b | ||
|
|
905080e743 | ||
|
|
d33f3c4769 | ||
|
|
b6a1c9b73b | ||
|
|
20823f103c | ||
|
|
25a5d3277b | ||
|
|
72a80c8f57 | ||
|
|
a082c7d33a | ||
|
|
99cac4b041 | ||
|
|
f804d7848f | ||
|
|
446841e0f5 | ||
|
|
1d347fe26c | ||
|
|
abfa5d719a | ||
|
|
32bc6ed328 | ||
|
|
ea2bc359cb | ||
|
|
c540cb0fe4 | ||
|
|
1642495754 | ||
|
|
b034a59422 | ||
|
|
2486c055e4 | ||
|
|
79b43b1058 | ||
|
|
b30fa436bd | ||
|
|
9e79a311cf | ||
|
|
2f695d0b34 | ||
|
|
952a484994 | ||
|
|
74b5e42492 | ||
|
|
7f8dc88c5a | ||
|
|
c9a9b8dffb | ||
|
|
b315a834c2 | ||
|
|
8f84c85c23 | ||
|
|
707ff935fe | ||
|
|
39af23b349 | ||
|
|
318b95beec | ||
|
|
174bb9a935 | ||
|
|
f0fd20051e | ||
|
|
e3d72bd271 | ||
|
|
4dcd0cd356 | ||
|
|
e3793e67aa | ||
|
|
3f344c7249 | ||
|
|
8a1af7d01f | ||
|
|
117fc44f00 | ||
|
|
703456b808 | ||
|
|
b90cc90ea8 | ||
|
|
45730e2a07 | ||
|
|
c0272b9755 | ||
|
|
a27a8804c4 | ||
|
|
073d23aed3 | ||
|
|
7d9a795a1c | ||
|
|
8359fb8919 | ||
|
|
7c0ffff93f | ||
|
|
46d2ea508c | ||
|
|
fb48faa3af | ||
|
|
048bb36165 | ||
|
|
0f01a03587 | ||
|
|
fe17a6e9da | ||
|
|
a17414dd89 | ||
|
|
5d3f2182f0 | ||
|
|
03cd320665 | ||
|
|
2415ede4fa | ||
|
|
844efd5958 | ||
|
|
4ba88b6f03 | ||
|
|
d17d0c190b | ||
|
|
beec9fab22 | ||
|
|
710b3c412f | ||
|
|
6bf31bf0ea | ||
|
|
2f8bef5f3e | ||
|
|
2dcf886322 | ||
|
|
0a362e9ce7 | ||
|
|
e186615163 | ||
|
|
7abf19071d | ||
|
|
30838749e1 | ||
|
|
06df49d5d7 | ||
|
|
2c5e1f611b | ||
|
|
0cc33f7a81 | ||
|
|
8a431fb79b | ||
|
|
12cfc0dafd | ||
|
|
93c8a1827c | ||
|
|
ca60eda7f2 | ||
|
|
c22c51791e | ||
|
|
d5a719c9f6 | ||
|
|
904c452cfe | ||
|
|
2078ef9081 | ||
|
|
fc9ee5bee1 | ||
|
|
d27595cfd9 | ||
|
|
b618386e6b | ||
|
|
2e79b2c7a2 | ||
|
|
4e4990bd98 | ||
|
|
4c8a44353a | ||
|
|
7dd8b13bc8 | ||
|
|
e1aa3b59be | ||
|
|
d79888793a | ||
|
|
b56e381022 | ||
|
|
15b32b312d | ||
|
|
6a0a00f126 | ||
|
|
9876c2ef6d | ||
|
|
fba29e3c80 | ||
|
|
b8275f5a3f | ||
|
|
b7e8365117 | ||
|
|
8df7b5c56b | ||
|
|
04519d1db7 | ||
|
|
7b808bea0b | ||
|
|
2878f1d9cf |
11
.github/workflows/android.publish.internal.yml
vendored
11
.github/workflows/android.publish.internal.yml
vendored
@@ -4,7 +4,7 @@ on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 40
|
||||
env:
|
||||
CMAKE_C_COMPILER_LAUNCHER: ccache
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
- name: Use specific Java version for the builds
|
||||
uses: joschi/setup-jdk@v2
|
||||
with:
|
||||
java-version: "11"
|
||||
java-version: "17"
|
||||
architecture: "x64"
|
||||
|
||||
- name: Install node modules
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
ccache -p
|
||||
|
||||
- name: Cache gradle
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
@@ -129,7 +129,7 @@ jobs:
|
||||
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
|
||||
packageName: com.streetwriters.notesnook
|
||||
releaseFiles: ${{steps.sign_app.outputs.signedReleaseFile}}
|
||||
track: alpha
|
||||
track: beta
|
||||
status: completed
|
||||
whatsNewDirectory: apps/mobile/native/android/releasenotes/
|
||||
|
||||
@@ -138,7 +138,7 @@ jobs:
|
||||
with:
|
||||
draft: true
|
||||
tag_name: ${{ steps.package-version.outputs.current-version}}-beta-android
|
||||
name: Notesnook Android v${{ steps.package-version.outputs.current-version}} Beta
|
||||
name: Notesnook Android v${{ steps.package-version.outputs.current-version}}
|
||||
repository: streetwriters/notesnook
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: |
|
||||
@@ -146,6 +146,7 @@ jobs:
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-armeabi-v7a.apk
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-x86.apk
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-x86_64.apk
|
||||
${{steps.sign_app.outputs.signedReleaseFile}}
|
||||
|
||||
- name: Upload sourcemaps
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
2
.github/workflows/android.publish.yml
vendored
2
.github/workflows/android.publish.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
ccache -p
|
||||
|
||||
- name: Cache gradle
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
|
||||
4
.github/workflows/ios.publish.yml
vendored
4
.github/workflows/ios.publish.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node-with-cache
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
ccache -p
|
||||
|
||||
- name: Cache Pods
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: pods-cache
|
||||
with:
|
||||
path: apps/mobile/native/ios/Pods
|
||||
|
||||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
const pkg = require("./package.json");
|
||||
|
||||
const buildRoot = process.env.NN_BUILD_ROOT || ".";
|
||||
const buildFiles = [
|
||||
@@ -35,6 +36,7 @@ const linuxExecutableName = process.env.NN_PRODUCT_NAME
|
||||
? process.env.NN_PRODUCT_NAME.toLowerCase().replace(/\s+/g, "-")
|
||||
: "notesnook";
|
||||
const year = new Date().getFullYear();
|
||||
const isBeta = pkg.version.includes("-beta");
|
||||
|
||||
module.exports = {
|
||||
appId: appId,
|
||||
@@ -194,7 +196,8 @@ module.exports = {
|
||||
{
|
||||
provider: "github",
|
||||
repo: "notesnook",
|
||||
owner: "streetwriters"
|
||||
owner: "streetwriters",
|
||||
channel: isBeta ? "beta" : "latest"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
746
apps/desktop/package-lock.json
generated
746
apps/desktop/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.0.30",
|
||||
"version": "3.1.0",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/cjs/index.js",
|
||||
|
||||
@@ -147,6 +147,11 @@ async function createWindow() {
|
||||
await AssetManager.loadIcons();
|
||||
setupDesktopIntegration(config.desktopSettings);
|
||||
|
||||
mainWindow.webContents.session.setPermissionRequestHandler(
|
||||
(webContents, permission, callback) => {
|
||||
callback(permission === "geolocation" ? false : true);
|
||||
}
|
||||
);
|
||||
mainWindow.webContents.session.setSpellCheckerDictionaryDownloadURL(
|
||||
"http://dictionaries.notesnook.com/"
|
||||
);
|
||||
|
||||
@@ -19,26 +19,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { i18n } from "@lingui/core";
|
||||
import { I18nProvider } from "@lingui/react";
|
||||
import {
|
||||
ScopedThemeProvider,
|
||||
THEME_COMPATIBILITY_VERSION,
|
||||
useThemeEngineStore
|
||||
} from "@notesnook/theme";
|
||||
import React, { useEffect } from "react";
|
||||
import { I18nManager, View } from "react-native";
|
||||
import { Appearance, I18nManager, StatusBar } from "react-native";
|
||||
import "react-native-gesture-handler";
|
||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||
import { SafeAreaProvider } from "react-native-safe-area-context";
|
||||
import AppLockedOverlay from "./components/app-lock-overlay";
|
||||
import DialogProvider from "./components/dialog-provider";
|
||||
import { withErrorBoundry } from "./components/exception-handler";
|
||||
import GlobalSafeAreaProvider from "./components/globalsafearea";
|
||||
import { Toast } from "./components/toast";
|
||||
import { useAppEvents } from "./hooks/use-app-events";
|
||||
import { ApplicationHolder } from "./navigation";
|
||||
import { NotePreviewConfigure } from "./screens/note-preview-configure";
|
||||
import { RootNavigation } from "./navigation/navigation-stack";
|
||||
import { themeTrpcClient } from "./screens/settings/theme-selector";
|
||||
import Notifications from "./services/notifications";
|
||||
import SettingsService from "./services/settings";
|
||||
import { TipManager } from "./services/tip-manager";
|
||||
import { useThemeStore } from "./stores/use-theme-store";
|
||||
import { changeSystemBarColors, useThemeStore } from "./stores/use-theme-store";
|
||||
import { useUserStore } from "./stores/use-user-store";
|
||||
import RNBootSplash from "react-native-bootsplash";
|
||||
import AppLocked from "./components/app-lock";
|
||||
|
||||
I18nManager.allowRTL(false);
|
||||
I18nManager.forceRTL(false);
|
||||
@@ -48,11 +52,13 @@ if (appLockEnabled || appLockMode !== "none") {
|
||||
useUserStore.getState().lockApp(true);
|
||||
}
|
||||
|
||||
RNBootSplash.hide();
|
||||
const App = (props: { configureMode: "note-preview" }) => {
|
||||
useAppEvents();
|
||||
//@ts-ignore
|
||||
globalThis["IS_MAIN_APP_RUNNING"] = true;
|
||||
useEffect(() => {
|
||||
changeSystemBarColors();
|
||||
SettingsService.onFirstLaunch();
|
||||
setTimeout(async () => {
|
||||
await Notifications.get();
|
||||
@@ -64,42 +70,27 @@ const App = (props: { configureMode: "note-preview" }) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
zIndex: -1
|
||||
}}
|
||||
pointerEvents="none"
|
||||
>
|
||||
<SafeAreaProvider>
|
||||
<GlobalSafeAreaProvider />
|
||||
</SafeAreaProvider>
|
||||
</View>
|
||||
|
||||
<SafeAreaProvider>
|
||||
<StatusBar translucent={true} backgroundColor="transparent" />
|
||||
<GestureHandlerRootView
|
||||
style={{
|
||||
height: "100%",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<GlobalSafeAreaProvider />
|
||||
{props.configureMode === "note-preview" ? (
|
||||
<NotePreviewConfigure />
|
||||
) : (
|
||||
<ApplicationHolder />
|
||||
<RootNavigation />
|
||||
)}
|
||||
<ScopedThemeProvider value="dialog">
|
||||
<Toast />
|
||||
</ScopedThemeProvider>
|
||||
<DialogProvider />
|
||||
<AppLocked />
|
||||
</GestureHandlerRootView>
|
||||
<AppLockedOverlay />
|
||||
</View>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -138,16 +129,27 @@ export const withTheme = (Element: (props: any) => JSX.Element) => {
|
||||
/* empty */
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
const listener = Appearance.addChangeListener(({ colorScheme }) => {
|
||||
if (colorScheme && SettingsService.getProperty("useSystemTheme")) {
|
||||
useThemeStore.getState().setColorScheme(colorScheme);
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
listener.remove();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const nextTheme = colorScheme === "dark" ? darkTheme : lightTheme;
|
||||
if (JSON.stringify(nextTheme) !== JSON.stringify(currTheme)) {
|
||||
useThemeEngineStore
|
||||
.getState()
|
||||
.setTheme(colorScheme === "dark" ? darkTheme : lightTheme);
|
||||
currTheme = nextTheme;
|
||||
}
|
||||
useEffect(() => {
|
||||
const nextTheme = colorScheme === "dark" ? darkTheme : lightTheme;
|
||||
if (JSON.stringify(nextTheme) !== JSON.stringify(currTheme)) {
|
||||
useThemeEngineStore
|
||||
.getState()
|
||||
.setTheme(colorScheme === "dark" ? darkTheme : lightTheme);
|
||||
currTheme = nextTheme;
|
||||
}
|
||||
}, [colorScheme, darkTheme, lightTheme]);
|
||||
|
||||
return (
|
||||
<I18nProvider i18n={i18n}>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -149,7 +149,9 @@ export async function downloadFile(
|
||||
});
|
||||
}
|
||||
|
||||
await RNFetchBlob.fs.mv(tempFilePath, originalFilePath);
|
||||
await RNFetchBlob.fs.mv(tempFilePath, originalFilePath).catch(() => {
|
||||
/* empty */
|
||||
});
|
||||
|
||||
if (!(await exists(filename))) {
|
||||
throw new Error("File size mismatch");
|
||||
|
||||
@@ -231,6 +231,26 @@ export async function deleteDCacheFiles() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCachePathForFile(filename: string) {
|
||||
const path = `${cacheDir}/${filename}`;
|
||||
|
||||
const iosAppGroup =
|
||||
Platform.OS === "ios"
|
||||
? await (RNFetchBlob.fs as any).pathForAppGroup(IOS_APPGROUPID)
|
||||
: null;
|
||||
const appGroupPath = `${iosAppGroup}/${filename}`;
|
||||
|
||||
const exists = await RNFetchBlob.fs.exists(path);
|
||||
|
||||
// Check if file is present in app group path.
|
||||
let existsInAppGroup = false;
|
||||
if (!exists && Platform.OS === "ios") {
|
||||
existsInAppGroup = await RNFetchBlob.fs.exists(appGroupPath);
|
||||
}
|
||||
|
||||
return existsInAppGroup ? appGroupPath : path;
|
||||
}
|
||||
|
||||
export async function exists(filename: string) {
|
||||
const path = `${cacheDir}/${filename}`;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import { useMessageStore } from "../../stores/use-message-store";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { allowedOnPlatform, renderItem } from "./functions";
|
||||
import { getContainerBorder } from "../../utils/colors";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const Announcement = ({ color }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -36,9 +37,8 @@ export const Announcement = ({ color }) => {
|
||||
style={{
|
||||
backgroundColor: colors.primary.background,
|
||||
width: "100%",
|
||||
paddingHorizontal: 12,
|
||||
paddingTop: 12,
|
||||
paddingBottom: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@@ -54,7 +54,7 @@ export const Announcement = ({ color }) => {
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
marginTop: 12
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
{announcement?.body
|
||||
|
||||
@@ -20,12 +20,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { getStyle } from "./functions";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const Body = ({ text, style = {} }) => {
|
||||
return (
|
||||
<Paragraph
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
...getStyle(style)
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -23,12 +23,13 @@ import { Linking, View } from "react-native";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { eSendEvent, presentSheet } from "../../services/event-manager";
|
||||
import { eCloseAnnouncementDialog } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { PricingPlans } from "../premium/pricing-plans";
|
||||
import SheetProvider from "../sheet-provider";
|
||||
import { Button } from "../ui/button";
|
||||
import { allowedOnPlatform, getStyle } from "./functions";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const Cta = ({ actions, style = {}, color, inline }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -61,7 +62,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
...getStyle(style),
|
||||
flexDirection: inline ? "row" : "column"
|
||||
}}
|
||||
@@ -75,7 +76,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
|
||||
<Button
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
fontSize={SIZE.sm}
|
||||
fontSize={AppFontSize.sm}
|
||||
type="transparent"
|
||||
textStyle={{
|
||||
textDecorationLine: "underline"
|
||||
@@ -83,7 +84,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
|
||||
onPress={() => onPress(item)}
|
||||
bold
|
||||
style={{
|
||||
height: 30,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
alignSelf: "flex-start",
|
||||
paddingHorizontal: 0
|
||||
}}
|
||||
@@ -95,7 +96,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
|
||||
<Button
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
fontSize={SIZE.sm}
|
||||
fontSize={AppFontSize.sm}
|
||||
type="plain"
|
||||
onPress={() => onPress(item)}
|
||||
width={null}
|
||||
@@ -118,7 +119,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
|
||||
<Button
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
fontSize={SIZE.md}
|
||||
fontSize={AppFontSize.md}
|
||||
buttonType={{
|
||||
color: color ? color : colors.primary.accent,
|
||||
text: color
|
||||
@@ -130,7 +131,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
|
||||
onPress={() => onPress(item)}
|
||||
width={250}
|
||||
style={{
|
||||
marginBottom: 5,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
borderRadius: 100
|
||||
}}
|
||||
/>
|
||||
@@ -141,14 +142,14 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
|
||||
<Button
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xs}
|
||||
type="plain"
|
||||
onPress={() => onPress(item)}
|
||||
width={null}
|
||||
height={30}
|
||||
style={{
|
||||
minWidth: "50%",
|
||||
marginTop: 5
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
textStyle={{
|
||||
textDecorationLine: "underline"
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { getStyle } from "./functions";
|
||||
|
||||
@@ -30,7 +30,7 @@ export const Description = ({ text, style = {}, inline }) => {
|
||||
...getStyle(style),
|
||||
textAlign: inline ? "left" : style?.textAlign
|
||||
}}
|
||||
size={inline ? SIZE.sm : SIZE.md}
|
||||
size={inline ? AppFontSize.sm : AppFontSize.md}
|
||||
>
|
||||
{text}
|
||||
</Paragraph>
|
||||
|
||||
@@ -28,6 +28,7 @@ import { List } from "./list";
|
||||
import { Photo } from "./photo";
|
||||
import { SubHeading } from "./subheading";
|
||||
import { Title } from "./title";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export function allowedOnPlatform(platforms) {
|
||||
if (!platforms) return true;
|
||||
@@ -53,7 +54,7 @@ const Features = () => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
alignItems: "center",
|
||||
width: "100%"
|
||||
}}
|
||||
|
||||
@@ -22,12 +22,13 @@ import { View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { getStyle } from "./functions";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const List = ({ items, listType, style = {} }) => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingLeft: listType === "ordered" ? 25 : 25,
|
||||
...getStyle(style)
|
||||
}}
|
||||
@@ -36,7 +37,7 @@ export const List = ({ items, listType, style = {} }) => {
|
||||
<View
|
||||
key={item.text}
|
||||
style={{
|
||||
paddingVertical: 6,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -18,17 +18,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import { getStyle } from "./functions";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const SubHeading = ({ text, style = {} }) => {
|
||||
return (
|
||||
<Heading
|
||||
size={SIZE.md + 2}
|
||||
size={AppFontSize.md + 2}
|
||||
style={{
|
||||
marginHorizontal: 12,
|
||||
marginTop: 12,
|
||||
marginHorizontal: DefaultAppStyles.GAP,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
...getStyle(style)
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -20,10 +20,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { useMessageStore } from "../../stores/use-message-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import { getStyle } from "./functions";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const Title = ({ text, style = {}, inline }) => {
|
||||
const announcements = useMessageStore((state) => state.announcements);
|
||||
@@ -36,19 +37,19 @@ export const Title = ({ text, style = {}, inline }) => {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: inline ? 5 : 0
|
||||
marginBottom: inline ? DefaultAppStyles.GAP_VERTICAL_SMALL : 0
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
style={{
|
||||
marginHorizontal: 12,
|
||||
marginTop: 12,
|
||||
marginHorizontal: DefaultAppStyles.GAP,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
...getStyle(style),
|
||||
textAlign: inline ? "left" : style?.textAlign,
|
||||
flexShrink: 1
|
||||
}}
|
||||
numberOfLines={1}
|
||||
size={inline ? SIZE.md : SIZE.xl}
|
||||
size={inline ? AppFontSize.md : AppFontSize.xl}
|
||||
>
|
||||
{inline ? text?.toUpperCase() : text}
|
||||
</Heading>
|
||||
@@ -67,7 +68,7 @@ export const Title = ({ text, style = {}, inline }) => {
|
||||
right: 0
|
||||
}}
|
||||
iconSize={24}
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xs}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingVertical: 0,
|
||||
@@ -80,9 +81,9 @@ export const Title = ({ text, style = {}, inline }) => {
|
||||
) : (
|
||||
<Heading
|
||||
style={{
|
||||
marginHorizontal: 12,
|
||||
marginHorizontal: DefaultAppStyles.GAP,
|
||||
...getStyle(style),
|
||||
marginTop: style?.marginTop || 12
|
||||
marginTop: style?.marginTop || DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
|
||||
@@ -44,7 +44,6 @@ import SettingsService from "../../services/settings";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { NotesnookModule } from "../../utils/notesnook-module";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { Toast } from "../toast";
|
||||
import { Button } from "../ui/button";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
@@ -54,6 +53,9 @@ import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { editorController } from "../../screens/editor/tiptap/utils";
|
||||
import { useTabStore } from "../../screens/editor/tiptap/use-tab-store";
|
||||
|
||||
const getUser = () => {
|
||||
const user = MMKV.getString("user");
|
||||
@@ -82,7 +84,7 @@ const verifyUserPassword = async (password: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
const AppLockedOverlay = () => {
|
||||
const AppLocked = () => {
|
||||
const initialLaunchBiometricRequest = useRef(true);
|
||||
const { colors } = useThemeColors();
|
||||
const user = getUser();
|
||||
@@ -109,6 +111,9 @@ const AppLockedOverlay = () => {
|
||||
);
|
||||
|
||||
const onUnlockAppRequested = useCallback(async () => {
|
||||
editorController.current?.commands.blur(useTabStore.getState().currentTab);
|
||||
editorController.current?.commands.blurPassInput();
|
||||
|
||||
if (
|
||||
!biometricsAuthEnabled ||
|
||||
!(await BiometricService.isBiometryAvailable())
|
||||
@@ -182,7 +187,13 @@ const AppLockedOverlay = () => {
|
||||
(prevState === "background" || initialLaunchBiometricRequest.current)
|
||||
) {
|
||||
if (SettingsService.shouldLockAppOnEnterForeground()) {
|
||||
if (useSettingStore.getState().appDidEnterBackgroundForAction) {
|
||||
useSettingStore.getState().setAppDidEnterBackgroundForAction(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DatabaseLogger.info("Locking app on entering foreground");
|
||||
|
||||
useUserStore.getState().lockApp(true);
|
||||
}
|
||||
if (
|
||||
@@ -283,6 +294,16 @@ const AppLockedOverlay = () => {
|
||||
keyboardType={
|
||||
appLockHasPasswordSecurity ? keyboardType : "default"
|
||||
}
|
||||
onLayout={async () => {
|
||||
if (
|
||||
!biometricsAuthEnabled ||
|
||||
!(await BiometricService.isBiometryAvailable())
|
||||
) {
|
||||
setTimeout(() => {
|
||||
passwordInputRef.current?.focus();
|
||||
}, 32);
|
||||
}
|
||||
}}
|
||||
placeholder={
|
||||
appLockHasPasswordSecurity
|
||||
? keyboardType === "numeric"
|
||||
@@ -315,7 +336,7 @@ const AppLockedOverlay = () => {
|
||||
borderRadius: 150,
|
||||
marginBottom: 10
|
||||
}}
|
||||
fontSize={SIZE.md}
|
||||
fontSize={AppFontSize.md}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
@@ -336,4 +357,4 @@ const AppLockedOverlay = () => {
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default AppLockedOverlay;
|
||||
export default AppLocked;
|
||||
@@ -45,7 +45,7 @@ import {
|
||||
eDBItemUpdate,
|
||||
eOnLoadNote
|
||||
} from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { Dialog } from "../dialog";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
@@ -58,6 +58,7 @@ import { Pressable } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const Actions = ({
|
||||
attachment,
|
||||
@@ -226,14 +227,15 @@ const Actions = ({
|
||||
style={{
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border,
|
||||
marginBottom: notes && notes.length > 0 ? 0 : 12
|
||||
marginBottom:
|
||||
notes && notes.length > 0 ? 0 : DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
>
|
||||
{filename}
|
||||
</Heading>
|
||||
@@ -241,21 +243,21 @@ const Actions = ({
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
marginBottom: 10,
|
||||
paddingHorizontal: 12,
|
||||
marginTop: 6,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
gap: 10
|
||||
}}
|
||||
>
|
||||
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
|
||||
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
|
||||
{attachment.mimeType}
|
||||
</Paragraph>
|
||||
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
|
||||
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
|
||||
{formatBytes(attachment.size)}
|
||||
</Paragraph>
|
||||
|
||||
{notes.length ? (
|
||||
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
|
||||
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
|
||||
{strings.notes(notes.length)}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
@@ -268,7 +270,7 @@ const Actions = ({
|
||||
context: "local"
|
||||
});
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
{attachment.hash}
|
||||
@@ -283,16 +285,16 @@ const Actions = ({
|
||||
style={{
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border,
|
||||
marginBottom: 12,
|
||||
paddingVertical: 12
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<Heading
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
>
|
||||
{strings.listOf()} {strings.dataTypesPlural.note()}:
|
||||
</Heading>
|
||||
@@ -307,14 +309,14 @@ const Actions = ({
|
||||
openNote(item, (item as any).type === "trash");
|
||||
}}
|
||||
style={{
|
||||
paddingVertical: 12,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
|
||||
alignItems: "flex-start",
|
||||
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
key={item.id}
|
||||
>
|
||||
<Paragraph size={SIZE.xs}>{item.title}</Paragraph>
|
||||
<Paragraph size={AppFontSize.xs}>{item.title}</Paragraph>
|
||||
</Pressable>
|
||||
))}
|
||||
</>
|
||||
@@ -335,7 +337,7 @@ const Actions = ({
|
||||
icon={item.icon}
|
||||
loading={loading?.name === item.name}
|
||||
type="plain"
|
||||
fontSize={SIZE.sm}
|
||||
fontSize={AppFontSize.sm}
|
||||
style={{
|
||||
borderRadius: 0,
|
||||
justifyContent: "flex-start",
|
||||
@@ -347,7 +349,7 @@ const Actions = ({
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{failed ? (
|
||||
|
||||
@@ -25,13 +25,14 @@ import { TouchableOpacity, View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import { useAttachmentProgress } from "../../hooks/use-attachment-progress";
|
||||
import { useDBItem } from "../../hooks/use-db-item";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { defaultBorderRadius, AppFontSize } from "../../utils/size";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import { ProgressCircleComponent } from "../ui/svg/lazy";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import Actions from "./actions";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
function getFileExtension(filename: string) {
|
||||
const ext = /^.+\.([^.]+)$/.exec(filename);
|
||||
@@ -76,8 +77,8 @@ export const AttachmentItem = ({
|
||||
flexDirection: "row",
|
||||
marginVertical: 5,
|
||||
justifyContent: "space-between",
|
||||
padding: 12,
|
||||
paddingVertical: 6,
|
||||
padding: DefaultAppStyles.GAP,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
|
||||
minHeight: 45
|
||||
}}
|
||||
>
|
||||
@@ -101,7 +102,7 @@ export const AttachmentItem = ({
|
||||
paddingHorizontal: 2,
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 5
|
||||
borderRadius: defaultBorderRadius
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
@@ -124,7 +125,7 @@ export const AttachmentItem = ({
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
@@ -136,7 +137,10 @@ export const AttachmentItem = ({
|
||||
</Paragraph>
|
||||
|
||||
{!hideWhenNotDownloading ? (
|
||||
<Paragraph color={colors.secondary.paragraph} size={SIZE.xxs}>
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={AppFontSize.xxs}
|
||||
>
|
||||
{strings.fileSize()}: {formatBytes(attachment.size)}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
@@ -159,7 +163,7 @@ export const AttachmentItem = ({
|
||||
}}
|
||||
>
|
||||
<ProgressCircleComponent
|
||||
size={SIZE.xxl}
|
||||
size={AppFontSize.xxl}
|
||||
progress={
|
||||
currentProgress?.value ? currentProgress?.value / 100 : 0
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import { downloadAttachments } from "../../common/filesystem/download-attachment
|
||||
import { AttachmentGroupProgress } from "../../screens/settings/attachment-group-progress";
|
||||
import { presentSheet, ToastManager } from "../../services/event-manager";
|
||||
import { useAttachmentStore } from "../../stores/use-attachment-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { Dialog } from "../dialog";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
import { Header } from "../header";
|
||||
@@ -50,6 +50,7 @@ import Seperator from "../ui/seperator";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { AttachmentItem } from "./attachment-item";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const DEFAULT_SORTING: SortOptions = {
|
||||
sortBy: "dateEdited",
|
||||
@@ -325,30 +326,31 @@ export const AttachmentDialog = ({
|
||||
title={strings.manageAttachments()}
|
||||
renderedInRoute="SettingsGroup"
|
||||
canGoBack
|
||||
headerRightButtons={[
|
||||
{
|
||||
onPress() {
|
||||
onCheck();
|
||||
},
|
||||
title: strings.recheckAll()
|
||||
},
|
||||
{
|
||||
onPress() {
|
||||
if (!attachments) return;
|
||||
presentDialog({
|
||||
title: strings.doActions.download.attachment(
|
||||
attachments.placeholders.length
|
||||
),
|
||||
positiveText: strings.network.download(),
|
||||
positivePress: async () => {
|
||||
downloadAttachments(await attachments.ids());
|
||||
},
|
||||
negativeText: strings.cancel()
|
||||
});
|
||||
},
|
||||
title: strings.downloadAllAttachments()
|
||||
}
|
||||
]}
|
||||
// TODO: Add headerRightButtons
|
||||
// headerRightButtons={[
|
||||
// {
|
||||
// onPress() {
|
||||
// onCheck();
|
||||
// },
|
||||
// title: strings.recheckAll()
|
||||
// },
|
||||
// {
|
||||
// onPress() {
|
||||
// if (!attachments) return;
|
||||
// presentDialog({
|
||||
// title: strings.doActions.download.attachment(
|
||||
// attachments.placeholders.length
|
||||
// ),
|
||||
// positiveText: strings.network.download(),
|
||||
// positivePress: async () => {
|
||||
// downloadAttachments(await attachments.ids());
|
||||
// },
|
||||
// negativeText: strings.cancel()
|
||||
// });
|
||||
// },
|
||||
// title: strings.downloadAllAttachments()
|
||||
// }
|
||||
// ]}
|
||||
/>
|
||||
) : (
|
||||
<View
|
||||
@@ -356,7 +358,7 @@ export const AttachmentDialog = ({
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Heading>{strings.dataTypesPluralCamelCase.attachment()}</Heading>
|
||||
@@ -369,21 +371,15 @@ export const AttachmentDialog = ({
|
||||
<IconButton
|
||||
name="check-all"
|
||||
style={{
|
||||
height: 40,
|
||||
width: 40,
|
||||
marginRight: 10
|
||||
}}
|
||||
color={colors.primary.paragraph}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
onPress={onCheck}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
name="download"
|
||||
style={{
|
||||
height: 40,
|
||||
width: 40
|
||||
}}
|
||||
color={colors.primary.paragraph}
|
||||
onPress={() => {
|
||||
if (!attachments) return;
|
||||
@@ -398,7 +394,7 @@ export const AttachmentDialog = ({
|
||||
negativeText: strings.cancel()
|
||||
});
|
||||
}}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
@@ -408,7 +404,7 @@ export const AttachmentDialog = ({
|
||||
style={{
|
||||
width: "100%",
|
||||
alignSelf: "center",
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
@@ -428,7 +424,7 @@ export const AttachmentDialog = ({
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
borderRadius: 10,
|
||||
padding: 10,
|
||||
padding: DefaultAppStyles.GAP_SMALL,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.border,
|
||||
gap: 12,
|
||||
@@ -473,7 +469,7 @@ export const AttachmentDialog = ({
|
||||
<IconButton
|
||||
type={rechecker.isWorking ? "errorShade" : "plain"}
|
||||
name={rechecker.isWorking ? "close" : "check"}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
color={
|
||||
rechecker.isWorking ? colors.error.icon : colors.primary.accent
|
||||
}
|
||||
@@ -494,7 +490,7 @@ export const AttachmentDialog = ({
|
||||
backgroundColor: colors.primary.background,
|
||||
flexWrap: "wrap",
|
||||
flexDirection: "row",
|
||||
paddingVertical: 12
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
contentContainerStyle={{
|
||||
alignItems: "center"
|
||||
@@ -511,10 +507,10 @@ export const AttachmentDialog = ({
|
||||
}
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
fontSize={SIZE.sm}
|
||||
fontSize={AppFontSize.sm}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
height: 40,
|
||||
minWidth: 80
|
||||
}}
|
||||
|
||||
@@ -37,6 +37,7 @@ import { hideAuth, initialAuthMode } from "./common";
|
||||
import { Login } from "./login";
|
||||
import { Signup } from "./signup";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const AuthMode = {
|
||||
login: 0,
|
||||
@@ -133,7 +134,7 @@ const AuthModal = () => {
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
width: "100%",
|
||||
height: 50,
|
||||
justifyContent:
|
||||
@@ -167,7 +168,7 @@ const AuthModal = () => {
|
||||
marginTop: 2
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 6
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -36,6 +36,7 @@ import { Dialog } from "../dialog";
|
||||
import BackupService from "../../services/backup";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const ChangePassword = () => {
|
||||
const passwordInputRef = useRef();
|
||||
@@ -103,7 +104,7 @@ export const ChangePassword = () => {
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
padding: 12
|
||||
padding: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Dialog context="change-password-dialog" />
|
||||
@@ -148,7 +149,7 @@ export const ChangePassword = () => {
|
||||
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
width: "100%"
|
||||
}}
|
||||
loading={loading}
|
||||
|
||||
@@ -20,23 +20,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { createRef } from "react";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import { eCloseLoginDialog } from "../../utils/events";
|
||||
import Navigation from "../../services/navigation";
|
||||
export const AuthMode = {
|
||||
login: 0,
|
||||
signup: 1,
|
||||
welcomeSignup: 2,
|
||||
trialSignup: 3
|
||||
};
|
||||
|
||||
export const initialAuthMode = createRef(0);
|
||||
export function hideAuth() {
|
||||
eSendEvent(eCloseLoginDialog);
|
||||
|
||||
// if (initialAuthMode.current === 2) {
|
||||
// Navigation.replace(
|
||||
// {
|
||||
// name: 'Notes'
|
||||
// },
|
||||
// {
|
||||
// menu: true
|
||||
// }
|
||||
// );
|
||||
// } else {
|
||||
// Navigation.goBack();
|
||||
// }
|
||||
|
||||
// tabBarRef.current?.unlock();
|
||||
if (initialAuthMode.current === AuthMode.welcomeSignup) {
|
||||
Navigation.replace("FluidPanelsView");
|
||||
} else {
|
||||
Navigation.goBack();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import Seperator from "../ui/seperator";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const ForgotPassword = () => {
|
||||
const { colors } = useThemeColors("sheet");
|
||||
@@ -107,7 +108,7 @@ export const ForgotPassword = () => {
|
||||
{sent ? (
|
||||
<View
|
||||
style={{
|
||||
padding: 12,
|
||||
padding: DefaultAppStyles.GAP,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingBottom: 50
|
||||
@@ -138,7 +139,7 @@ export const ForgotPassword = () => {
|
||||
backgroundColor: colors.primary.background,
|
||||
zIndex: 10,
|
||||
width: "100%",
|
||||
padding: 12
|
||||
padding: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<DialogHeader title={strings.accountRecovery()} />
|
||||
@@ -164,7 +165,7 @@ export const ForgotPassword = () => {
|
||||
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
width: "100%"
|
||||
}}
|
||||
loading={loading}
|
||||
|
||||
@@ -17,35 +17,98 @@ 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 { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { Toast } from "../toast";
|
||||
import { initialAuthMode } from "./common";
|
||||
import { Button } from "../ui/button";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import { AuthMode, initialAuthMode } from "./common";
|
||||
import { Login } from "./login";
|
||||
import { Signup } from "./signup";
|
||||
|
||||
export const AuthMode = {
|
||||
login: 0,
|
||||
signup: 1,
|
||||
welcomeSignup: 2,
|
||||
trialSignup: 3
|
||||
};
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
|
||||
const Auth = ({ navigation, route }) => {
|
||||
const [currentAuthMode, setCurrentAuthMode] = useState(
|
||||
route?.params?.mode || AuthMode.login
|
||||
);
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const { colors } = useThemeColors();
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
initialAuthMode.current = route?.params.mode || AuthMode.login;
|
||||
useNavigationFocus(navigation, {
|
||||
onFocus: () => {
|
||||
//tabBarRef?.current.lock();
|
||||
initialAuthMode.current = route?.params.mode || AuthMode.login;
|
||||
}
|
||||
});
|
||||
useNavigationFocus(navigation, {});
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<View
|
||||
style={{
|
||||
position: "absolute",
|
||||
paddingTop: insets.top,
|
||||
top: 0,
|
||||
zIndex: 999,
|
||||
backgroundColor:
|
||||
deviceMode === "mobile" ? colors.secondary.background : null,
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
width: "100%",
|
||||
height: 50,
|
||||
justifyContent:
|
||||
initialAuthMode.current !== AuthMode.welcomeSignup
|
||||
? "space-between"
|
||||
: "flex-end"
|
||||
}}
|
||||
>
|
||||
{initialAuthMode.current === AuthMode.welcomeSignup ? null : (
|
||||
<IconButton
|
||||
name="arrow-left"
|
||||
onPress={() => {
|
||||
if (initialAuthMode.current === 2) {
|
||||
Navigation.replace("FluidPanelsView");
|
||||
} else {
|
||||
Navigation.goBack();
|
||||
}
|
||||
}}
|
||||
color={colors.primary.paragraph}
|
||||
/>
|
||||
)}
|
||||
|
||||
{initialAuthMode.current !== AuthMode.welcomeSignup ? null : (
|
||||
<Button
|
||||
title={strings.skip()}
|
||||
onPress={() => {
|
||||
if (initialAuthMode.current === 2) {
|
||||
Navigation.replace("FluidPanelsView");
|
||||
} else {
|
||||
Navigation.goBack();
|
||||
}
|
||||
}}
|
||||
iconSize={16}
|
||||
type="plain"
|
||||
iconPosition="right"
|
||||
icon="chevron-right"
|
||||
height={25}
|
||||
iconStyle={{
|
||||
marginTop: 2
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{currentAuthMode !== AuthMode.login ? (
|
||||
<Signup
|
||||
changeMode={(mode) => setCurrentAuthMode(mode)}
|
||||
|
||||
@@ -17,6 +17,7 @@ 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 { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { TouchableOpacity, View, useWindowDimensions } from "react-native";
|
||||
@@ -24,10 +25,9 @@ import { SheetManager } from "react-native-actions-sheet";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import Sync from "../../services/sync";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { eUserLoggedIn } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import SheetProvider from "../sheet-provider";
|
||||
import { Progress } from "../sheets/progress";
|
||||
@@ -38,7 +38,7 @@ import Paragraph from "../ui/typography/paragraph";
|
||||
import { hideAuth } from "./common";
|
||||
import { ForgotPassword } from "./forgot-password";
|
||||
import { useLogin } from "./use-login";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const LoginSteps = {
|
||||
emailAuth: 1,
|
||||
@@ -71,8 +71,8 @@ export const Login = ({ changeMode }) => {
|
||||
}
|
||||
}, 5000);
|
||||
});
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const { width, height } = useWindowDimensions();
|
||||
const isTablet = width > 600;
|
||||
useEffect(() => {
|
||||
async () => {
|
||||
setStep(LoginSteps.emailAuth);
|
||||
@@ -96,23 +96,24 @@ export const Login = ({ changeMode }) => {
|
||||
backgroundColor: colors.primary.background,
|
||||
zIndex: 10,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
alignSelf: "center"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
justifyContent: "flex-end",
|
||||
paddingHorizontal: 20,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderBottomWidth: 0.8,
|
||||
marginBottom: 12,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
borderBottomColor: colors.primary.border,
|
||||
alignSelf: deviceMode !== "mobile" ? "center" : undefined,
|
||||
borderWidth: deviceMode !== "mobile" ? 1 : null,
|
||||
borderColor: deviceMode !== "mobile" ? colors.primary.border : null,
|
||||
borderRadius: deviceMode !== "mobile" ? 20 : null,
|
||||
marginTop: deviceMode !== "mobile" ? 50 : null,
|
||||
width: deviceMode === "mobile" ? null : "50%",
|
||||
alignSelf: isTablet ? "center" : undefined,
|
||||
borderWidth: isTablet ? 1 : null,
|
||||
borderColor: isTablet ? colors.primary.border : null,
|
||||
borderRadius: isTablet ? 20 : null,
|
||||
marginTop: isTablet ? 50 : null,
|
||||
width: !isTablet ? null : "70%",
|
||||
minHeight: height * 0.4
|
||||
}}
|
||||
>
|
||||
@@ -143,10 +144,10 @@ export const Login = ({ changeMode }) => {
|
||||
<Heading
|
||||
style={{
|
||||
marginBottom: 25,
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
extraBold
|
||||
size={SIZE.xxl}
|
||||
size={AppFontSize.xxl}
|
||||
>
|
||||
{strings.loginToYourAccount()}
|
||||
</Heading>
|
||||
@@ -163,7 +164,7 @@ export const Login = ({ changeMode }) => {
|
||||
: "99.9%",
|
||||
backgroundColor: colors.primary.background,
|
||||
alignSelf: "center",
|
||||
paddingHorizontal: 20
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
@@ -216,7 +217,7 @@ export const Login = ({ changeMode }) => {
|
||||
title={strings.forgotPassword()}
|
||||
style={{
|
||||
alignSelf: "flex-end",
|
||||
height: 30,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
paddingHorizontal: 0
|
||||
}}
|
||||
onPress={() => {
|
||||
@@ -226,7 +227,7 @@ export const Login = ({ changeMode }) => {
|
||||
textStyle={{
|
||||
textDecorationLine: "underline"
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xs}
|
||||
type="plain"
|
||||
/>
|
||||
</>
|
||||
@@ -244,11 +245,8 @@ export const Login = ({ changeMode }) => {
|
||||
login();
|
||||
}}
|
||||
style={{
|
||||
width: 250,
|
||||
borderRadius: 100
|
||||
width: 250
|
||||
}}
|
||||
height={50}
|
||||
fontSize={SIZE.md}
|
||||
type="accent"
|
||||
title={!loading ? strings.continue() : null}
|
||||
/>
|
||||
@@ -258,19 +256,16 @@ export const Login = ({ changeMode }) => {
|
||||
title={strings.cancelLogin()}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
height: 30,
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
width: 250
|
||||
}}
|
||||
onPress={() => {
|
||||
if (loading) return;
|
||||
setStep(LoginSteps.emailAuth);
|
||||
setLoading(false);
|
||||
}}
|
||||
textStyle={{
|
||||
textDecorationLine: "underline"
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
type="errorShade"
|
||||
fontSize={AppFontSize.xs}
|
||||
type="secondaryAccented"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -283,17 +278,17 @@ export const Login = ({ changeMode }) => {
|
||||
activeOpacity={0.8}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
marginTop: 12,
|
||||
paddingVertical: 12
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
size={SIZE.xs + 1}
|
||||
size={AppFontSize.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
{strings.dontHaveAccount()}{" "}
|
||||
<Paragraph
|
||||
size={SIZE.xs + 1}
|
||||
size={AppFontSize.xs}
|
||||
style={{ color: colors.primary.accent }}
|
||||
>
|
||||
{strings.signUp()}
|
||||
|
||||
@@ -34,7 +34,7 @@ import Sync from "../../services/sync";
|
||||
import { clearAllStores } from "../../stores";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { eLoginSessionExpired, eUserLoggedIn } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { Dialog } from "../dialog";
|
||||
import BaseDialog from "../dialog/base-dialog";
|
||||
@@ -48,18 +48,8 @@ import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { LoginSteps, useLogin } from "./use-login";
|
||||
import { strings } from "@notesnook/intl";
|
||||
|
||||
function getObfuscatedEmail(email) {
|
||||
if (!email) return "";
|
||||
const [username, provider] = email.split("@");
|
||||
if (username.length === 1) return `****@${provider}`;
|
||||
return email.replace(/(.{1})(.*)(?=@)/, function (gp1, gp2, gp3) {
|
||||
for (let i = 0; i < gp3.length; i++) {
|
||||
gp2 += "*";
|
||||
}
|
||||
return gp2;
|
||||
});
|
||||
}
|
||||
import { getObfuscatedEmail } from "../../utils/functions";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const SessionExpired = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -168,7 +158,7 @@ export const SessionExpired = () => {
|
||||
<View
|
||||
style={{
|
||||
width: focused ? "100%" : "99.9%",
|
||||
padding: 12,
|
||||
padding: DefaultAppStyles.GAP,
|
||||
justifyContent: "center",
|
||||
flex: 1,
|
||||
backgroundColor: colors.primary.background
|
||||
@@ -193,7 +183,7 @@ export const SessionExpired = () => {
|
||||
color={colors.error.icon}
|
||||
size={50}
|
||||
/>
|
||||
<Heading size={SIZE.xxxl} color={colors.primary.heading}>
|
||||
<Heading size={AppFontSize.xxxl} color={colors.primary.heading}>
|
||||
{strings.sessionExpired()}
|
||||
</Heading>
|
||||
<Paragraph
|
||||
@@ -224,7 +214,7 @@ export const SessionExpired = () => {
|
||||
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
width: 250,
|
||||
borderRadius: 100
|
||||
}}
|
||||
@@ -236,7 +226,7 @@ export const SessionExpired = () => {
|
||||
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
width: "100%"
|
||||
}}
|
||||
onPress={() => {
|
||||
|
||||
@@ -17,6 +17,8 @@ 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 { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { TouchableOpacity, View, useWindowDimensions } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
@@ -24,19 +26,17 @@ import { DDS } from "../../services/device-detection";
|
||||
import { ToastManager } from "../../services/event-manager";
|
||||
import { clearMessage, setEmailVerifyMessage } from "../../services/message";
|
||||
import PremiumService from "../../services/premium";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import SettingsService from "../../services/settings";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { openLinkInBrowser } from "../../utils/functions";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { Button } from "../ui/button";
|
||||
import Input from "../ui/input";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { hideAuth } from "./common";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import SettingsService from "../../services/settings";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const Signup = ({ changeMode, trial }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -50,8 +50,8 @@ 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 { width, height } = useWindowDimensions();
|
||||
const isTablet = width > 600;
|
||||
const validateInfo = () => {
|
||||
if (!password.current || !email.current || !confirmPassword.current) {
|
||||
ToastManager.show({
|
||||
@@ -105,23 +105,24 @@ export const Signup = ({ changeMode, trial }) => {
|
||||
backgroundColor: colors.primary.background,
|
||||
zIndex: 10,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
alignSelf: "center"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
justifyContent: "flex-end",
|
||||
paddingHorizontal: 20,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
backgroundColor: colors.secondary.background,
|
||||
marginBottom: 20,
|
||||
borderBottomWidth: 0.8,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
borderBottomColor: colors.primary.border,
|
||||
alignSelf: deviceMode !== "mobile" ? "center" : undefined,
|
||||
borderWidth: deviceMode !== "mobile" ? 1 : null,
|
||||
borderColor: deviceMode !== "mobile" ? colors.primary.border : null,
|
||||
borderRadius: deviceMode !== "mobile" ? 20 : null,
|
||||
marginTop: deviceMode !== "mobile" ? 50 : null,
|
||||
width: deviceMode === "mobile" ? null : "50%",
|
||||
alignSelf: isTablet ? "center" : undefined,
|
||||
borderWidth: isTablet ? 1 : null,
|
||||
borderColor: isTablet ? colors.primary.border : null,
|
||||
borderRadius: isTablet ? 20 : null,
|
||||
marginTop: isTablet ? 50 : null,
|
||||
width: !isTablet ? null : "70%",
|
||||
minHeight: height * 0.4
|
||||
}}
|
||||
>
|
||||
@@ -153,9 +154,9 @@ export const Signup = ({ changeMode, trial }) => {
|
||||
extraBold
|
||||
style={{
|
||||
marginBottom: 25,
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
size={SIZE.xxl}
|
||||
size={AppFontSize.xxl}
|
||||
>
|
||||
{strings.createYourAccount()}
|
||||
</Heading>
|
||||
@@ -164,7 +165,7 @@ export const Signup = ({ changeMode, trial }) => {
|
||||
<View
|
||||
style={{
|
||||
width: DDS.isTab ? "50%" : "100%",
|
||||
paddingHorizontal: 20,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
backgroundColor: colors.primary.background,
|
||||
alignSelf: "center"
|
||||
}}
|
||||
@@ -233,12 +234,12 @@ export const Signup = ({ changeMode, trial }) => {
|
||||
style={{
|
||||
marginBottom: 25
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xxs}
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
{strings.signupAgreement[0]()}
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xxs}
|
||||
onPress={() => {
|
||||
openLinkInBrowser("https://notesnook.com/tos", colors);
|
||||
}}
|
||||
@@ -247,11 +248,12 @@ export const Signup = ({ changeMode, trial }) => {
|
||||
}}
|
||||
color={colors.primary.accent}
|
||||
>
|
||||
{" "}
|
||||
{strings.signupAgreement[1]()}
|
||||
</Paragraph>
|
||||
</Paragraph>{" "}
|
||||
{strings.signupAgreement[2]()}
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xxs}
|
||||
onPress={() => {
|
||||
openLinkInBrowser("https://notesnook.com/privacy", colors);
|
||||
}}
|
||||
@@ -260,8 +262,9 @@ export const Signup = ({ changeMode, trial }) => {
|
||||
}}
|
||||
color={colors.primary.accent}
|
||||
>
|
||||
{" "}
|
||||
{strings.signupAgreement[3]()}
|
||||
</Paragraph>
|
||||
</Paragraph>{" "}
|
||||
{strings.signupAgreement[4]()}
|
||||
</Paragraph>
|
||||
|
||||
@@ -270,11 +273,8 @@ export const Signup = ({ changeMode, trial }) => {
|
||||
type="accent"
|
||||
loading={loading}
|
||||
onPress={signup}
|
||||
fontSize={SIZE.md}
|
||||
style={{
|
||||
marginRight: 12,
|
||||
width: 250,
|
||||
borderRadius: 100
|
||||
width: 250
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -286,14 +286,14 @@ export const Signup = ({ changeMode, trial }) => {
|
||||
activeOpacity={0.8}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
marginTop: 12,
|
||||
paddingVertical: 12
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<Paragraph size={SIZE.xs + 1} color={colors.secondary.paragraph}>
|
||||
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
|
||||
{strings.alreadyHaveAccount()}{" "}
|
||||
<Paragraph
|
||||
size={SIZE.xs + 1}
|
||||
size={AppFontSize.xs}
|
||||
style={{ color: colors.primary.accent }}
|
||||
>
|
||||
{strings.login()}
|
||||
|
||||
@@ -30,13 +30,14 @@ import {
|
||||
ToastManager
|
||||
} from "../../services/event-manager";
|
||||
import { eCloseSheet } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import Input from "../ui/input";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -204,9 +205,9 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
|
||||
}}
|
||||
onSubmitEditing={onNext}
|
||||
caretHidden
|
||||
height={60}
|
||||
inputStyle={{
|
||||
fontSize: SIZE.lg,
|
||||
height: 60,
|
||||
fontSize: AppFontSize.lg,
|
||||
textAlign: "center",
|
||||
letterSpacing: 10,
|
||||
width: 250
|
||||
@@ -216,11 +217,13 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
|
||||
}
|
||||
enablesReturnKeyAutomatically
|
||||
containerStyle={{
|
||||
height: 60,
|
||||
borderWidth: 0,
|
||||
width: undefined,
|
||||
minWidth: "50%"
|
||||
}}
|
||||
wrapperStyle={{
|
||||
height: 60
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
@@ -229,9 +232,12 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
|
||||
width={250}
|
||||
loading={loading}
|
||||
onPress={onNext}
|
||||
style={{
|
||||
borderRadius: 100
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
title={strings.cancel()}
|
||||
type="secondaryAccented"
|
||||
onPress={onCancel}
|
||||
width={250}
|
||||
/>
|
||||
|
||||
<Button
|
||||
@@ -242,13 +248,6 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
|
||||
onPress={onRequestSecondaryMethod}
|
||||
height={30}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title={strings.cancel()}
|
||||
type="plain"
|
||||
onPress={onCancel}
|
||||
height={30}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@@ -262,8 +261,8 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
|
||||
marginTop: 0,
|
||||
flexDirection: "row",
|
||||
borderRadius: 0,
|
||||
@@ -275,8 +274,6 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
|
||||
<IconButton
|
||||
type="secondaryAccented"
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
marginRight: 10
|
||||
}}
|
||||
size={15}
|
||||
@@ -288,7 +285,7 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
<Paragraph size={SIZE.md}>{item.title}</Paragraph>
|
||||
<Paragraph size={AppFontSize.md}>{item.title}</Paragraph>
|
||||
</View>
|
||||
</Pressable>
|
||||
))}
|
||||
|
||||
@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import { Keyboard, View } from "react-native";
|
||||
import { Keyboard, TouchableOpacity, View, ViewStyle } from "react-native";
|
||||
import Animated, {
|
||||
Easing,
|
||||
useAnimatedStyle,
|
||||
@@ -33,20 +33,31 @@ import { editorState } from "../../screens/editor/tiptap/utils";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { getElevationStyle } from "../../utils/elevation";
|
||||
import { SIZE, normalize } from "../../utils/size";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import { AppFontSize, normalize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { hexToRGBA, RGB_Linear_Shade } from "../../utils/colors";
|
||||
|
||||
interface FloatingButtonProps {
|
||||
onPress: () => void;
|
||||
color?: string;
|
||||
shouldShow?: boolean;
|
||||
alwaysVisible?: boolean;
|
||||
icon?: string;
|
||||
testID?: string;
|
||||
position?: "left" | "right";
|
||||
size?: "small" | "large";
|
||||
style?: ViewStyle;
|
||||
}
|
||||
|
||||
const FloatingButton = ({
|
||||
onPress,
|
||||
color,
|
||||
alwaysVisible = false
|
||||
alwaysVisible = false,
|
||||
icon,
|
||||
testID,
|
||||
position = "right",
|
||||
size = "large",
|
||||
style
|
||||
}: FloatingButtonProps) => {
|
||||
const { colors } = useThemeColors();
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
@@ -108,20 +119,26 @@ const FloatingButton = ({
|
||||
style={[
|
||||
{
|
||||
position: "absolute",
|
||||
right: 12,
|
||||
right: position === "right" ? DefaultAppStyles.GAP : undefined,
|
||||
left: position === "left" ? DefaultAppStyles.GAP : undefined,
|
||||
bottom: 20,
|
||||
zIndex: 10
|
||||
zIndex: 10,
|
||||
...style
|
||||
},
|
||||
animatedStyle
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
testID={notesnook.buttons.add}
|
||||
type="accent"
|
||||
accentColor={color}
|
||||
<TouchableOpacity
|
||||
testID={testID || notesnook.buttons.add}
|
||||
activeOpacity={0.95}
|
||||
style={{
|
||||
...getElevationStyle(5),
|
||||
borderRadius: 100
|
||||
borderRadius: size === "small" ? 15 : 20,
|
||||
borderTopWidth: 0,
|
||||
borderBottomWidth: 0,
|
||||
borderLeftWidth: 0,
|
||||
borderRightWidth: 0,
|
||||
backgroundColor: colors.primary.background
|
||||
}}
|
||||
onPress={onPress}
|
||||
>
|
||||
@@ -129,23 +146,29 @@ const FloatingButton = ({
|
||||
style={{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: normalize(60),
|
||||
width: normalize(60)
|
||||
height: normalize(size === "small" ? 40 : 60),
|
||||
width: normalize(size === "small" ? 40 : 60),
|
||||
backgroundColor: color
|
||||
? RGB_Linear_Shade(0.87, hexToRGBA(color))
|
||||
: colors.primary.shade,
|
||||
borderRadius: size === "small" ? 15 : 20
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name={
|
||||
route.name === "Notebooks"
|
||||
icon
|
||||
? icon
|
||||
: route.name === "Notebooks"
|
||||
? "notebook-plus"
|
||||
: route.name === "Trash"
|
||||
? "delete"
|
||||
: "plus"
|
||||
}
|
||||
color={colors.primary.accentForeground}
|
||||
size={SIZE.xxl}
|
||||
color={color || colors.primary.accent}
|
||||
size={size === "small" ? AppFontSize.xl : AppFontSize.xxxl}
|
||||
/>
|
||||
</View>
|
||||
</Pressable>
|
||||
</TouchableOpacity>
|
||||
</Animated.View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -23,6 +23,8 @@ import { useMessageStore } from "../../stores/use-message-store";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { ColorValues } from "../../utils/colors";
|
||||
import { hexToRGBA } from "../../utils/colors";
|
||||
import { defaultBorderRadius } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -40,7 +42,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{hasAnnoucements ? (
|
||||
@@ -51,7 +53,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
borderRadius: 10,
|
||||
marginBottom: 20,
|
||||
backgroundColor: colors.secondary.background,
|
||||
padding: 12
|
||||
padding: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@@ -59,7 +61,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
width: 150,
|
||||
height: 20,
|
||||
backgroundColor: colors.primary.hover,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
marginBottom: 10
|
||||
}}
|
||||
/>
|
||||
@@ -68,7 +70,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
width: 250,
|
||||
height: 14,
|
||||
backgroundColor: colors.primary.hover,
|
||||
borderRadius: 5
|
||||
borderRadius: defaultBorderRadius
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -78,7 +80,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
height: 15,
|
||||
backgroundColor: shadeColor,
|
||||
borderRadius: 3,
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@@ -93,7 +95,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
marginBottom: 20,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 20
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@@ -111,7 +113,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
width: 150,
|
||||
height: 12,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
marginBottom: 10
|
||||
}}
|
||||
/>
|
||||
@@ -120,7 +122,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
width: 250,
|
||||
height: 16,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5
|
||||
borderRadius: defaultBorderRadius
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@@ -134,7 +136,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 10,
|
||||
marginBottom: 20,
|
||||
padding: 5,
|
||||
padding: DefaultAppStyles.GAP_SMALL,
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
@@ -179,7 +181,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
width: 200,
|
||||
height: 16,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5
|
||||
borderRadius: defaultBorderRadius
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
@@ -187,15 +189,15 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
width: "85%",
|
||||
height: 13,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5,
|
||||
marginTop: 10
|
||||
borderRadius: defaultBorderRadius,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
/>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@@ -203,7 +205,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
width: 50,
|
||||
height: 10,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5
|
||||
borderRadius: defaultBorderRadius
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
@@ -211,7 +213,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
|
||||
width: 60,
|
||||
height: 10,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
marginLeft: 10
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -17,11 +17,10 @@ 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 from "react";
|
||||
import { ViewProps } from "react-native";
|
||||
import Animated, { FadeOutUp } from "react-native-reanimated";
|
||||
import { useDelayLayout } from "../../hooks/use-delay-layout";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { View, ViewProps } from "react-native";
|
||||
import { useDelayLayout } from "../../hooks/use-delay-layout";
|
||||
import { DefaultPlaceholder } from "./default-placeholder";
|
||||
import { SettingsPlaceholder } from "./settings-placeholder";
|
||||
|
||||
@@ -49,8 +48,7 @@ export default function DelayLayout({
|
||||
const Placeholder = placeholder[props.type || "default"];
|
||||
|
||||
return loading || props.wait ? (
|
||||
<Animated.View
|
||||
exiting={animated ? FadeOutUp : undefined}
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: colors.primary.background,
|
||||
flex: 1,
|
||||
@@ -58,7 +56,7 @@ export default function DelayLayout({
|
||||
}}
|
||||
>
|
||||
<Placeholder color={props.color || colors.primary.accent} />
|
||||
</Animated.View>
|
||||
</View>
|
||||
) : (
|
||||
<>{props.children}</>
|
||||
);
|
||||
|
||||
@@ -20,6 +20,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { defaultBorderRadius } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const SettingsPlaceholder = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -31,7 +33,7 @@ export const SettingsPlaceholder = () => {
|
||||
width: 100,
|
||||
height: 12,
|
||||
backgroundColor: colors.primary.shade,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
marginLeft: 12,
|
||||
marginBottom: 12
|
||||
}}
|
||||
@@ -44,7 +46,7 @@ export const SettingsPlaceholder = () => {
|
||||
marginBottom: 20,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 16
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@@ -62,7 +64,7 @@ export const SettingsPlaceholder = () => {
|
||||
width: 150,
|
||||
height: 12,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
marginBottom: 10
|
||||
}}
|
||||
/>
|
||||
@@ -71,7 +73,7 @@ export const SettingsPlaceholder = () => {
|
||||
width: 250,
|
||||
height: 16,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5
|
||||
borderRadius: defaultBorderRadius
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@@ -85,7 +87,7 @@ export const SettingsPlaceholder = () => {
|
||||
marginBottom: 20,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 16,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
>
|
||||
@@ -104,7 +106,7 @@ export const SettingsPlaceholder = () => {
|
||||
width: 150,
|
||||
height: 12,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
marginBottom: 10
|
||||
}}
|
||||
/>
|
||||
@@ -113,7 +115,7 @@ export const SettingsPlaceholder = () => {
|
||||
width: 250,
|
||||
height: 16,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5
|
||||
borderRadius: defaultBorderRadius
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -17,6 +17,7 @@ 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 { ScopedThemeProvider } from "@notesnook/theme";
|
||||
import React, { PropsWithChildren, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
ColorValue,
|
||||
@@ -30,11 +31,8 @@ import {
|
||||
} from "react-native";
|
||||
import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { BouncingView } from "../ui/transitions/bouncing-view";
|
||||
import { ScopedThemeProvider } from "@notesnook/theme";
|
||||
import SettingsService from "../../services/settings";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { useAppState } from "../../hooks/use-app-state";
|
||||
import { BouncingView } from "../ui/transitions/bouncing-view";
|
||||
|
||||
export interface BaseDialogProps extends PropsWithChildren {
|
||||
animation?: "fade" | "none" | "slide" | undefined;
|
||||
|
||||
@@ -17,16 +17,17 @@ 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 { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { ActivityIndicator, StyleSheet, View } from "react-native";
|
||||
import { StyleSheet, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { getColorLinearShade } from "../../utils/colors";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { Button } from "../ui/button";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { getColorLinearShade } from "../../utils/colors";
|
||||
import { strings } from "@notesnook/intl";
|
||||
|
||||
const DialogButtons = ({
|
||||
onPressPositive,
|
||||
@@ -46,9 +47,7 @@ const DialogButtons = ({
|
||||
{
|
||||
backgroundColor: colors.secondary.background,
|
||||
height: 60,
|
||||
borderBottomRightRadius: 5,
|
||||
borderBottomLeftRadius: 5,
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
borderTopWidth: 0.7,
|
||||
borderTopColor: getColorLinearShade(
|
||||
colors.secondary.background,
|
||||
@@ -58,9 +57,7 @@ const DialogButtons = ({
|
||||
}
|
||||
]}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color={colors.primary.accent} size={SIZE.lg} />
|
||||
) : doneText ? (
|
||||
{doneText ? (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
@@ -70,7 +67,7 @@ const DialogButtons = ({
|
||||
<Icon
|
||||
color={colors.primary.accent}
|
||||
name="check-circle-outline"
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
/>
|
||||
<Paragraph color={colors.primary.accent}>{" " + doneText}</Paragraph>
|
||||
</View>
|
||||
@@ -86,7 +83,7 @@ const DialogButtons = ({
|
||||
>
|
||||
<Button
|
||||
onPress={onPressNegative}
|
||||
fontSize={SIZE.md}
|
||||
fontSize={AppFontSize.sm}
|
||||
testID={notesnook.ids.default.dialog.no}
|
||||
type="plain"
|
||||
bold
|
||||
@@ -95,11 +92,12 @@ const DialogButtons = ({
|
||||
{onPressPositive ? (
|
||||
<Button
|
||||
onPress={onPressPositive}
|
||||
fontSize={SIZE.md}
|
||||
fontSize={AppFontSize.sm}
|
||||
testID={notesnook.ids.default.dialog.yes}
|
||||
style={{
|
||||
marginLeft: 10
|
||||
}}
|
||||
loading={loading}
|
||||
bold
|
||||
type={positiveType || "transparent"}
|
||||
title={positiveTitle}
|
||||
@@ -117,6 +115,6 @@ const styles = StyleSheet.create({
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}
|
||||
});
|
||||
|
||||
@@ -20,11 +20,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { Text, View, ViewStyle } from "react-native";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import { PressableProps } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
type DialogHeaderProps = {
|
||||
icon?: string;
|
||||
@@ -82,7 +83,7 @@ const DialogHeader = ({
|
||||
>
|
||||
<Heading
|
||||
style={{ textAlign: centered ? "center" : "left" }}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
>
|
||||
{title}{" "}
|
||||
{titlePart ? (
|
||||
@@ -97,7 +98,7 @@ const DialogHeader = ({
|
||||
onPress={button.onPress}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
loading={button.loading}
|
||||
fontSize={13}
|
||||
|
||||
@@ -17,33 +17,35 @@ 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, { useEffect, useRef, useState } from "react";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import {
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { getContainerBorder } from "../../utils/colors";
|
||||
import { getElevationStyle } from "../../utils/elevation";
|
||||
import { eCloseSimpleDialog, eOpenSimpleDialog } from "../../utils/events";
|
||||
import { defaultBorderRadius } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { Toast } from "../toast";
|
||||
import { Button } from "../ui/button";
|
||||
import Input from "../ui/input";
|
||||
import { Notice } from "../ui/notice";
|
||||
import Seperator from "../ui/seperator";
|
||||
import BaseDialog from "./base-dialog";
|
||||
import DialogButtons from "./dialog-buttons";
|
||||
import DialogHeader from "./dialog-header";
|
||||
import { useCallback } from "react";
|
||||
import { Button } from "../ui/button";
|
||||
import { getContainerBorder } from "../../utils/colors";
|
||||
import { Notice } from "../ui/notice";
|
||||
import { strings } from "@notesnook/intl";
|
||||
|
||||
export const Dialog = ({ context = "global" }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [checked, setChecked] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const values = useRef({
|
||||
inputValue: undefined
|
||||
});
|
||||
@@ -72,14 +74,23 @@ export const Dialog = ({ context = "global" }) => {
|
||||
const onPressPositive = async () => {
|
||||
if (dialogInfo.positivePress) {
|
||||
inputRef.current?.blur();
|
||||
let result = await dialogInfo.positivePress(
|
||||
values.current.inputValue || dialogInfo.defaultValue,
|
||||
checked
|
||||
);
|
||||
setLoading(true);
|
||||
let result;
|
||||
try {
|
||||
result = await dialogInfo.positivePress(
|
||||
values.current.inputValue || dialogInfo.defaultValue,
|
||||
checked
|
||||
);
|
||||
} catch (e) {
|
||||
/** Empty */
|
||||
}
|
||||
setLoading(false);
|
||||
|
||||
if (result === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setChecked(false);
|
||||
values.current.inputValue = undefined;
|
||||
setVisible(false);
|
||||
@@ -125,10 +136,11 @@ export const Dialog = ({ context = "global" }) => {
|
||||
...getElevationStyle(5),
|
||||
width: DDS.isTab ? 400 : "85%",
|
||||
maxHeight: 450,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
backgroundColor: colors.primary.background,
|
||||
paddingTop: 12,
|
||||
...getContainerBorder(colors.primary.border, 0.5)
|
||||
...getContainerBorder(colors.primary.border, 0.5),
|
||||
overflow: "hidden"
|
||||
};
|
||||
|
||||
return visible ? (
|
||||
@@ -164,7 +176,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
{dialogInfo.input ? (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
@@ -188,7 +200,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
{dialogInfo?.notice ? (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Notice
|
||||
@@ -209,6 +221,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
? "check-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
iconColor={checked ? colors.secondary.icon : colors.primary.icon}
|
||||
style={{
|
||||
justifyContent: "flex-start"
|
||||
}}
|
||||
@@ -224,6 +237,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
<DialogButtons
|
||||
onPressNegative={onNegativePress}
|
||||
onPressPositive={dialogInfo.positivePress && onPressPositive}
|
||||
loading={loading}
|
||||
positiveTitle={dialogInfo.positiveText}
|
||||
negativeTitle={dialogInfo.negativeText}
|
||||
positiveType={dialogInfo.positiveType}
|
||||
|
||||
@@ -39,7 +39,7 @@ import {
|
||||
eCloseAppLocKPasswordDailog,
|
||||
eOpenAppLockPasswordDialog
|
||||
} from "../../../utils/events";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import BaseDialog from "../../dialog/base-dialog";
|
||||
import DialogButtons from "../../dialog/dialog-buttons";
|
||||
@@ -50,6 +50,7 @@ import { IconButton } from "../../ui/icon-button";
|
||||
import Input from "../../ui/input";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
export const AppLockPassword = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -128,7 +129,7 @@ export const AppLockPassword = () => {
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{mode === "change" ? (
|
||||
@@ -192,7 +193,7 @@ export const AppLockPassword = () => {
|
||||
height: 25,
|
||||
marginRight: 5
|
||||
}}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -248,7 +249,7 @@ export const AppLockPassword = () => {
|
||||
setSecureTextEntry(true);
|
||||
});
|
||||
}}
|
||||
iconSize={SIZE.lg}
|
||||
iconSize={AppFontSize.lg}
|
||||
type="plain"
|
||||
iconColor={
|
||||
accountPass ? colors.primary.accent : colors.primary.icon
|
||||
@@ -259,7 +260,7 @@ export const AppLockPassword = () => {
|
||||
alignSelf: "flex-start",
|
||||
justifyContent: "flex-start",
|
||||
paddingHorizontal: 0,
|
||||
height: 30
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -27,12 +27,13 @@ import {
|
||||
import { Image as ImageType } from "react-native-image-crop-picker";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { presentSheet } from "../../../services/event-manager";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { defaultBorderRadius, AppFontSize } from "../../../utils/size";
|
||||
import { Button } from "../../ui/button";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { Notice } from "../../ui/notice";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
export default function AttachImage({
|
||||
response,
|
||||
@@ -50,21 +51,26 @@ export default function AttachImage({
|
||||
<View
|
||||
style={{
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: colors.secondary.background,
|
||||
marginBottom: 12,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
height: 140,
|
||||
width: "100%",
|
||||
borderRadius: 10,
|
||||
padding: 5,
|
||||
paddingHorizontal: 12
|
||||
padding: DefaultAppStyles.GAP_SMALL,
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL
|
||||
}}
|
||||
>
|
||||
<Paragraph style={{ color: colors.primary.paragraph, marginBottom: 6 }}>
|
||||
<Paragraph
|
||||
style={{
|
||||
color: colors.primary.paragraph,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
>
|
||||
{strings.attachImageHeading(response?.length || 1)}
|
||||
</Paragraph>
|
||||
<ScrollView horizontal>
|
||||
@@ -80,7 +86,7 @@ export default function AttachImage({
|
||||
style={{
|
||||
width: 100,
|
||||
height: 100,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
backgroundColor: "black",
|
||||
marginRight: 6
|
||||
}}
|
||||
@@ -96,7 +102,7 @@ export default function AttachImage({
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignSelf: "center",
|
||||
marginBottom: 12,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
alignItems: "center",
|
||||
width: "100%"
|
||||
}}
|
||||
@@ -105,7 +111,7 @@ export default function AttachImage({
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
name={compress ? "checkbox-marked" : "checkbox-blank-outline"}
|
||||
color={compress ? colors.primary.accent : colors.primary.icon}
|
||||
style={{
|
||||
@@ -122,7 +128,7 @@ export default function AttachImage({
|
||||
flexShrink: 1,
|
||||
marginLeft: 3
|
||||
}}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
>
|
||||
{strings.compress()} ({strings.recommended().toLowerCase()})
|
||||
</Paragraph>
|
||||
@@ -135,7 +141,7 @@ export default function AttachImage({
|
||||
size="small"
|
||||
style={{
|
||||
width: "100%",
|
||||
marginBottom: 12
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
@@ -145,7 +151,7 @@ export default function AttachImage({
|
||||
size="small"
|
||||
style={{
|
||||
width: "100%",
|
||||
marginBottom: 12
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -34,6 +34,7 @@ import { Button } from "../../ui/button";
|
||||
import Input from "../../ui/input";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
const HEX_COLOR_REGEX_ALPHA =
|
||||
/^#(?:(?:[\da-fA-F]{3}){1,2}|(?:[\da-fA-F]{4}){1,2})$/;
|
||||
@@ -105,16 +106,16 @@ const ColorPicker = ({
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingTop: 10,
|
||||
columnGap: 10,
|
||||
marginBottom: 10
|
||||
paddingTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
columnGap: DefaultAppStyles.GAP_VERTICAL,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
@@ -155,7 +156,7 @@ const ColorPicker = ({
|
||||
<Button
|
||||
title={strings.addColor()}
|
||||
style={{
|
||||
marginBottom: 10
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
onPress={async () => {
|
||||
if (!selectedColor)
|
||||
|
||||
@@ -39,10 +39,11 @@ import {
|
||||
eOpenJumpToDialog,
|
||||
eScrollEvent
|
||||
} from "../../../utils/events";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import BaseDialog from "../../dialog/base-dialog";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
const JumpToSectionDialog = () => {
|
||||
const scrollRef = useRef<RefObject<FlatList>>();
|
||||
@@ -152,13 +153,13 @@ const JumpToSectionDialog = () => {
|
||||
maxHeight: "65%",
|
||||
borderRadius: 10,
|
||||
alignSelf: "center",
|
||||
padding: 10,
|
||||
padding: DefaultAppStyles.GAP_SMALL,
|
||||
paddingTop: 30
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
color={colors.primary.accent}
|
||||
style={{
|
||||
marginBottom: 20
|
||||
@@ -188,15 +189,15 @@ const JumpToSectionDialog = () => {
|
||||
style={{
|
||||
minWidth: "20%",
|
||||
width: null,
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
margin: 5,
|
||||
borderRadius: 100,
|
||||
height: 30,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
marginVertical: 10
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
color={
|
||||
currentIndex === index
|
||||
? colors.static.white
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
} from "../../../services/event-manager";
|
||||
import { useState } from "react";
|
||||
import { eCloseLoading, eOpenLoading } from "../../../utils/events";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
export const LoadingDialog = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -67,7 +68,7 @@ export const LoadingDialog = () => {
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: 100,
|
||||
marginTop: 15
|
||||
marginTop: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<ProgressBarComponent
|
||||
|
||||
@@ -19,10 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Dimensions, TextInput, View } from "react-native";
|
||||
import {
|
||||
addOrientationListener,
|
||||
removeOrientationListener
|
||||
} from "react-native-orientation";
|
||||
import Orientation from "react-native-orientation-locker";
|
||||
import Pdf from "react-native-pdf";
|
||||
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
|
||||
import downloadAttachment from "../../../common/filesystem/download-attachment";
|
||||
@@ -34,7 +31,7 @@ import {
|
||||
eUnSubscribeEvent
|
||||
} from "../../../services/event-manager";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { Dialog } from "../../dialog";
|
||||
import BaseDialog from "../../dialog/base-dialog";
|
||||
import { presentDialog } from "../../dialog/functions";
|
||||
@@ -46,6 +43,7 @@ import { sleep } from "../../../utils/time";
|
||||
import { MMKV } from "../../../common/database/mmkv";
|
||||
import { deleteCacheFileByPath } from "../../../common/filesystem/io";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
const WIN_WIDTH = Dimensions.get("window").width;
|
||||
const WIN_HEIGHT = Dimensions.get("window").height;
|
||||
@@ -98,9 +96,9 @@ const PDFPreview = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
addOrientationListener(onOrientationChange);
|
||||
Orientation.addDeviceOrientationListener(onOrientationChange);
|
||||
return () => {
|
||||
removeOrientationListener(onOrientationChange);
|
||||
Orientation.removeDeviceOrientationListener(onOrientationChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -184,7 +182,7 @@ const PDFPreview = () => {
|
||||
/>
|
||||
<Paragraph
|
||||
style={{
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
color={colors.static.white}
|
||||
>
|
||||
@@ -200,7 +198,7 @@ const PDFPreview = () => {
|
||||
marginTop: insets.top,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingLeft: 6
|
||||
}}
|
||||
>
|
||||
@@ -216,7 +214,7 @@ const PDFPreview = () => {
|
||||
style={{
|
||||
marginRight: 12
|
||||
}}
|
||||
size={SIZE.xxl}
|
||||
size={AppFontSize.xxl}
|
||||
/>
|
||||
</View>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useEffect } from "react";
|
||||
import { View } from "react-native";
|
||||
import { eSendEvent, eSubscribeEvent } from "../../../services/event-manager";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { Dialog } from "../../dialog";
|
||||
import BaseDialog from "../../dialog/base-dialog";
|
||||
import DialogContainer from "../../dialog/dialog-container";
|
||||
@@ -29,6 +29,7 @@ import { Button } from "../../ui/button";
|
||||
import { ProgressBarComponent } from "../../ui/svg/lazy";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
export type ProgressOptions = {
|
||||
progress?: string;
|
||||
@@ -111,7 +112,7 @@ export default function Progress() {
|
||||
>
|
||||
<DialogContainer
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingBottom: 10
|
||||
}}
|
||||
noBorder={data?.fillBackground ? true : false}
|
||||
@@ -121,7 +122,7 @@ export default function Progress() {
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
gap: 10,
|
||||
paddingBottom: 20
|
||||
}}
|
||||
@@ -131,7 +132,7 @@ export default function Progress() {
|
||||
textAlign: "center"
|
||||
}}
|
||||
color={colors.primary.paragraph}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
>
|
||||
{data?.title}
|
||||
</Heading>
|
||||
@@ -148,7 +149,7 @@ export default function Progress() {
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: 100,
|
||||
paddingVertical: 12
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<ProgressBarComponent
|
||||
|
||||
@@ -27,13 +27,14 @@ import {
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { getElevationStyle } from "../../../utils/elevation";
|
||||
import { eCloseResultDialog, eOpenResultDialog } from "../../../utils/events";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import BaseDialog from "../../dialog/base-dialog";
|
||||
import { Button } from "../../ui/button";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { ProFeatures } from "./pro-features";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
const ResultDialog = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -78,15 +79,15 @@ const ResultDialog = () => {
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
textBreakStrategy="balanced"
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
textAlign: "center",
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
maxWidth: "100%",
|
||||
marginBottom: 10,
|
||||
paddingHorizontal: 12
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{dialogData.title}
|
||||
@@ -94,12 +95,12 @@ const ResultDialog = () => {
|
||||
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
textAlign: "center",
|
||||
maxWidth: "80%",
|
||||
lineHeight: SIZE.sm + 5
|
||||
lineHeight: AppFontSize.sm + 5
|
||||
}}
|
||||
>
|
||||
{dialogData.paragraph}
|
||||
@@ -109,7 +110,7 @@ const ResultDialog = () => {
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
alignItems: "center",
|
||||
width: "100%"
|
||||
}}
|
||||
@@ -124,17 +125,17 @@ const ResultDialog = () => {
|
||||
width: "100%",
|
||||
borderBottomRightRadius: 10,
|
||||
borderBottomLeftRadius: 10,
|
||||
paddingVertical: 10
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
title={dialogData.button}
|
||||
width={null}
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
onPress={close}
|
||||
fontSize={SIZE.md + 2}
|
||||
fontSize={AppFontSize.md + 2}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -27,9 +27,10 @@ import {
|
||||
eCloseResultDialog,
|
||||
eOpenPremiumDialog
|
||||
} from "../../../utils/events";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { defaultBorderRadius, AppFontSize } from "../../../utils/size";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
export const ProFeatures = ({ count = 6 }) => {
|
||||
const { colors } = useThemeColors();
|
||||
|
||||
@@ -67,13 +68,17 @@ export const ProFeatures = ({ count = 6 }) => {
|
||||
width: "100%",
|
||||
height: 40,
|
||||
paddingHorizontal: 0,
|
||||
marginBottom: 10,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
alignItems: "center",
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
justifyContent: "flex-start"
|
||||
}}
|
||||
>
|
||||
<Icon size={SIZE.lg} color={colors.primary.accent} name="check" />
|
||||
<Icon
|
||||
size={AppFontSize.lg}
|
||||
color={colors.primary.accent}
|
||||
name="check"
|
||||
/>
|
||||
<Paragraph style={{ marginLeft: 5, flexShrink: 1 }}>
|
||||
{item.content}
|
||||
</Paragraph>
|
||||
@@ -86,7 +91,7 @@ export const ProFeatures = ({ count = 6 }) => {
|
||||
await sleep(300);
|
||||
eSendEvent(eOpenPremiumDialog);
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
textDecorationLine: "underline",
|
||||
color: colors.secondary.paragraph
|
||||
|
||||
@@ -41,7 +41,7 @@ import {
|
||||
eUpdateNoteInEditor
|
||||
} from "../../../utils/events";
|
||||
import { deleteItems } from "../../../utils/functions";
|
||||
import { tabBarRef } from "../../../utils/global-refs";
|
||||
import { fluidTabsRef } from "../../../utils/global-refs";
|
||||
import { convertNoteToText } from "../../../utils/note-to-text";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import BaseDialog from "../../dialog/base-dialog";
|
||||
@@ -53,6 +53,7 @@ import Input from "../../ui/input";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
export class VaultDialog extends Component {
|
||||
constructor(props) {
|
||||
@@ -553,7 +554,7 @@ export class VaultDialog extends Component {
|
||||
item: note
|
||||
});
|
||||
if (!DDS.isTab) {
|
||||
tabBarRef.current?.goToPage(1);
|
||||
fluidTabsRef.current?.goToPage("editor");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -677,7 +678,7 @@ export class VaultDialog extends Component {
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{(novault ||
|
||||
@@ -750,7 +751,7 @@ export class VaultDialog extends Component {
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
style={{
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
width="100%"
|
||||
title={strings.deleteAllNotes()}
|
||||
@@ -847,7 +848,7 @@ export class VaultDialog extends Component {
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
icon="fingerprint"
|
||||
width="100%"
|
||||
|
||||
@@ -37,12 +37,13 @@ import Animated, {
|
||||
WithSpringConfig,
|
||||
withTiming
|
||||
} from "react-native-reanimated";
|
||||
import { useTabStore } from "../../screens/editor/tiptap/use-tab-store";
|
||||
import { getAppState } from "../../screens/editor/tiptap/utils";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { eClearEditor } from "../../utils/events";
|
||||
import { useSideBarDraggingStore } from "../side-menu/dragging-store";
|
||||
import { useTabStore } from "../../screens/editor/tiptap/use-tab-store";
|
||||
import { rootNavigatorRef } from "../../utils/global-refs";
|
||||
|
||||
interface TabProps extends ViewProps {
|
||||
dimensions: { width: number; height: number };
|
||||
@@ -53,20 +54,22 @@ interface TabProps extends ViewProps {
|
||||
onDrawerStateChange: (state: boolean) => void;
|
||||
}
|
||||
|
||||
type FluidTabPage = "home" | "editor";
|
||||
|
||||
export interface TabsRef {
|
||||
goToPage: (page: number, animated?: boolean) => void;
|
||||
goToPage: (page: FluidTabPage, animated?: boolean) => void;
|
||||
goToIndex: (index: number, animated?: boolean) => 0 | undefined;
|
||||
unlock: () => boolean;
|
||||
lock: () => boolean;
|
||||
openDrawer: (animated?: boolean) => void;
|
||||
closeDrawer: (animated?: boolean) => void;
|
||||
page: () => number;
|
||||
page: () => FluidTabPage;
|
||||
setScrollEnabled: () => true;
|
||||
isDrawerOpen: () => boolean;
|
||||
node: RefObject<Animated.View>;
|
||||
}
|
||||
|
||||
export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
{
|
||||
children,
|
||||
dimensions,
|
||||
@@ -81,9 +84,6 @@ export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
const appState = useMemo(() => getAppState(), []);
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const fullscreen = useSettingStore((state) => state.fullscreen);
|
||||
const introCompleted = useSettingStore(
|
||||
(state) => state.settings.introCompleted
|
||||
);
|
||||
const translateX = useSharedValue(
|
||||
widths
|
||||
? appState &&
|
||||
@@ -118,26 +118,40 @@ export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
const isIPhone = Platform.OS === "ios";
|
||||
|
||||
useEffect(() => {
|
||||
if (introCompleted) {
|
||||
if (deviceMode === "tablet" || fullscreen) {
|
||||
translateX.value = 0;
|
||||
} else {
|
||||
if (prevWidths.current?.sidebar !== widths.sidebar) {
|
||||
translateX.value =
|
||||
appState && appState?.movedAway === false
|
||||
? editorPosition
|
||||
: widths.sidebar;
|
||||
if (translateX.value === editorPosition) {
|
||||
onChangeTab?.({ i: 2, from: 1 });
|
||||
}
|
||||
if (deviceMode === "tablet" || fullscreen) {
|
||||
translateX.value = 0;
|
||||
} else {
|
||||
if (prevWidths.current?.sidebar !== widths.sidebar) {
|
||||
translateX.value =
|
||||
appState && appState?.movedAway === false
|
||||
? editorPosition
|
||||
: widths.sidebar;
|
||||
if (translateX.value === editorPosition) {
|
||||
onChangeTab?.({ i: 2, from: 1 });
|
||||
}
|
||||
}
|
||||
isLoaded.current = true;
|
||||
prevWidths.current = widths;
|
||||
}
|
||||
isLoaded.current = true;
|
||||
prevWidths.current = widths;
|
||||
}, [
|
||||
deviceMode,
|
||||
widths,
|
||||
fullscreen,
|
||||
translateX,
|
||||
editorPosition,
|
||||
appState,
|
||||
onChangeTab
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const sub = BackHandler.addEventListener("hardwareBackPress", () => {
|
||||
if (isDrawerOpen.value) {
|
||||
if (isDrawerOpen.value && !forcedLock.value) {
|
||||
const routeNames = rootNavigatorRef.current?.getState().routes;
|
||||
if (routeNames) {
|
||||
const currentRoute = routeNames[routeNames.length - 1].name;
|
||||
if (currentRoute !== "FluidPanelsView") return false;
|
||||
}
|
||||
|
||||
translateX.value = withTiming(homePosition);
|
||||
onDrawerStateChange(false);
|
||||
isDrawerOpen.value = false;
|
||||
@@ -149,34 +163,28 @@ export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
sub && sub.remove();
|
||||
};
|
||||
}, [
|
||||
introCompleted,
|
||||
deviceMode,
|
||||
widths,
|
||||
fullscreen,
|
||||
translateX,
|
||||
isDrawerOpen,
|
||||
forcedLock.value,
|
||||
homePosition,
|
||||
isDrawerOpen,
|
||||
onDrawerStateChange,
|
||||
editorPosition,
|
||||
appState
|
||||
translateX
|
||||
]);
|
||||
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
(): TabsRef => ({
|
||||
goToPage: (page: number, animated = true) => {
|
||||
goToPage: (page: FluidTabPage, animated = true) => {
|
||||
if (deviceMode === "tablet") {
|
||||
translateX.value = animated ? withTiming(0) : 0;
|
||||
return;
|
||||
}
|
||||
page = page + 1;
|
||||
if (page === 1) {
|
||||
if (page === "home") {
|
||||
onDrawerStateChange(false);
|
||||
translateX.value = !animated
|
||||
? homePosition
|
||||
: withTiming(homePosition);
|
||||
currentTab.value = 1;
|
||||
} else if (page === 2) {
|
||||
} else if (page === "editor") {
|
||||
onDrawerStateChange(false);
|
||||
translateX.value = !animated
|
||||
? editorPosition
|
||||
@@ -242,7 +250,7 @@ export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
onDrawerStateChange(false);
|
||||
isDrawerOpen.value = false;
|
||||
},
|
||||
page: () => currentTab.value,
|
||||
page: () => (currentTab.value === 1 ? "home" : "editor"),
|
||||
setScrollEnabled: () => true,
|
||||
node: node
|
||||
}),
|
||||
@@ -295,7 +303,7 @@ export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
.maxPointers(1)
|
||||
.enabled(enabled && !disabled)
|
||||
.activeOffsetX([-5, 5])
|
||||
.failOffsetY([-15, 15])
|
||||
.failOffsetY([-10, 10])
|
||||
.onBegin((event) => {
|
||||
locked.value = false;
|
||||
gestureStartValue.value = {
|
||||
@@ -17,60 +17,52 @@ 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 { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Platform, StyleSheet, View } from "react-native";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { View } from "react-native";
|
||||
import {
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
import useNavigationStore, {
|
||||
RouteName
|
||||
} from "../../stores/use-navigation-store";
|
||||
import { RouteName } from "../../stores/use-navigation-store";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { eScrollEvent } from "../../utils/events";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { IconButtonProps } from "../ui/icon-button";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { LeftMenus } from "./left-menus";
|
||||
import { RightMenus } from "./right-menus";
|
||||
import { Title } from "./title";
|
||||
|
||||
type HeaderRightButton = {
|
||||
title: string;
|
||||
onPress: () => void;
|
||||
};
|
||||
|
||||
export const Header = ({
|
||||
renderedInRoute,
|
||||
onLeftMenuButtonPress,
|
||||
title,
|
||||
titleHiddenOnRender,
|
||||
headerRightButtons,
|
||||
id,
|
||||
accentColor,
|
||||
isBeta,
|
||||
canGoBack,
|
||||
onPressDefaultRightButton,
|
||||
hasSearch,
|
||||
onSearch
|
||||
onSearch,
|
||||
rightButton
|
||||
}: {
|
||||
onLeftMenuButtonPress?: () => void;
|
||||
renderedInRoute?: RouteName;
|
||||
id?: string;
|
||||
title: string;
|
||||
headerRightButtons?: HeaderRightButton[];
|
||||
titleHiddenOnRender?: boolean;
|
||||
accentColor?: string;
|
||||
isBeta?: boolean;
|
||||
canGoBack?: boolean;
|
||||
onPressDefaultRightButton?: () => void;
|
||||
hasSearch?: boolean;
|
||||
onSearch?: () => void;
|
||||
rightButton?: IconButtonProps;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const [borderHidden, setBorderHidden] = useState(true);
|
||||
const selectionMode = useSelectionStore((state) => state.selectionMode);
|
||||
const isFocused = useNavigationStore((state) => state.focusedRouteId === id);
|
||||
const [selectedItemsList, selectionMode] = useSelectionStore((state) => [
|
||||
state.selectedItemsList,
|
||||
state.selectionMode
|
||||
]);
|
||||
|
||||
const onScroll = useCallback(
|
||||
(data: { x: number; y: number; id?: string; route: string }) => {
|
||||
@@ -93,88 +85,48 @@ export const Header = ({
|
||||
};
|
||||
}, [borderHidden, onScroll]);
|
||||
|
||||
return selectionMode && isFocused ? null : (
|
||||
<>
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
marginTop: Platform.OS === "android" ? insets.top : null,
|
||||
backgroundColor: colors.primary.background,
|
||||
overflow: "hidden",
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: borderHidden
|
||||
? "transparent"
|
||||
: colors.secondary.background,
|
||||
justifyContent: "space-between"
|
||||
}
|
||||
]}
|
||||
>
|
||||
<>
|
||||
<View style={styles.leftBtnContainer}>
|
||||
<LeftMenus
|
||||
canGoBack={canGoBack}
|
||||
onLeftButtonPress={onLeftMenuButtonPress}
|
||||
/>
|
||||
const HeaderWrapper = hasSearch ? Pressable : View;
|
||||
|
||||
<Title
|
||||
isHiddenOnRender={titleHiddenOnRender}
|
||||
renderedInRoute={renderedInRoute}
|
||||
id={id}
|
||||
accentColor={accentColor}
|
||||
title={title}
|
||||
isBeta={isBeta}
|
||||
/>
|
||||
</View>
|
||||
<RightMenus
|
||||
renderedInRoute={renderedInRoute}
|
||||
id={id}
|
||||
headerRightButtons={headerRightButtons}
|
||||
onPressDefaultRightButton={onPressDefaultRightButton}
|
||||
search={hasSearch}
|
||||
onSearch={onSearch}
|
||||
/>
|
||||
</>
|
||||
</View>
|
||||
</>
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<HeaderWrapper
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: DefaultAppStyles.GAP_SMALL,
|
||||
borderRadius: 10,
|
||||
paddingVertical: 3,
|
||||
borderWidth: hasSearch ? 1 : 0,
|
||||
borderColor: colors.primary.border,
|
||||
paddingHorizontal: !hasSearch ? 0 : DefaultAppStyles.GAP_SMALL,
|
||||
alignItems: "center"
|
||||
}}
|
||||
testID="search-header"
|
||||
onPress={() => {
|
||||
onSearch?.();
|
||||
}}
|
||||
>
|
||||
<LeftMenus
|
||||
canGoBack={canGoBack}
|
||||
onLeftButtonPress={onLeftMenuButtonPress}
|
||||
/>
|
||||
|
||||
{hasSearch ? (
|
||||
<Paragraph>
|
||||
{selectionMode
|
||||
? `${selectedItemsList.length} selected`
|
||||
: strings.searchInRoute(title)}
|
||||
</Paragraph>
|
||||
) : (
|
||||
<Heading size={AppFontSize.lg}>{title}</Heading>
|
||||
)}
|
||||
|
||||
<RightMenus rightButton={rightButton} />
|
||||
</HeaderWrapper>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: "row",
|
||||
zIndex: 11,
|
||||
height: 50,
|
||||
maxHeight: 50,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
width: "100%"
|
||||
},
|
||||
leftBtnContainer: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
flexShrink: 1
|
||||
},
|
||||
leftBtn: {
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 40,
|
||||
width: 40,
|
||||
borderRadius: 100,
|
||||
marginLeft: -5,
|
||||
marginRight: 25
|
||||
},
|
||||
rightBtnContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
},
|
||||
rightBtn: {
|
||||
justifyContent: "center",
|
||||
alignItems: "flex-end",
|
||||
height: 40,
|
||||
width: 40,
|
||||
paddingRight: 0
|
||||
}
|
||||
});
|
||||
|
||||
@@ -20,10 +20,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
import { fluidTabsRef } from "../../utils/global-refs";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
|
||||
export const LeftMenus = ({
|
||||
@@ -41,7 +40,7 @@ export const LeftMenus = ({
|
||||
if (onLeftButtonPress) return onLeftButtonPress();
|
||||
|
||||
if (!canGoBack) {
|
||||
if (tabBarRef.current?.isDrawerOpen()) {
|
||||
if (fluidTabsRef.current?.isDrawerOpen()) {
|
||||
Navigation.closeDrawer();
|
||||
} else {
|
||||
Navigation.openDrawer();
|
||||
@@ -54,23 +53,14 @@ export const LeftMenus = ({
|
||||
return isTablet && !canGoBack ? null : (
|
||||
<IconButton
|
||||
testID={notesnook.ids.default.header.buttons.left}
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 40,
|
||||
width: 40,
|
||||
borderRadius: 100,
|
||||
marginRight: DDS.isLargeTablet() ? 10 : 7
|
||||
}}
|
||||
left={40}
|
||||
top={40}
|
||||
right={DDS.isLargeTablet() ? 10 : 10}
|
||||
onPress={_onLeftButtonPress}
|
||||
onLongPress={() => {
|
||||
Navigation.popToTop();
|
||||
}}
|
||||
name={canGoBack ? "arrow-left" : "menu"}
|
||||
color={colors.primary.paragraph}
|
||||
color={colors.primary.icon}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,127 +17,30 @@ 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, { useRef } from "react";
|
||||
import { Platform, StyleSheet, View } from "react-native";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { Menu } from "react-native-material-menu";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import {
|
||||
HeaderRightButton,
|
||||
RouteName
|
||||
} from "../../stores/use-navigation-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { Button } from "../ui/button";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import React from "react";
|
||||
import { StyleSheet, View } from "react-native";
|
||||
import { IconButton, IconButtonProps } from "../ui/icon-button";
|
||||
|
||||
export const RightMenus = ({
|
||||
headerRightButtons,
|
||||
renderedInRoute,
|
||||
id,
|
||||
onPressDefaultRightButton,
|
||||
search,
|
||||
onSearch
|
||||
rightButton
|
||||
}: {
|
||||
headerRightButtons?: HeaderRightButton[];
|
||||
renderedInRoute?: RouteName;
|
||||
id?: string;
|
||||
onPressDefaultRightButton?: () => void;
|
||||
search?: boolean;
|
||||
onSearch?: () => void;
|
||||
rightButton?: IconButtonProps;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const { colors: contextMenuColors } = useThemeColors("contextMenu");
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const menuRef = useRef<Menu>(null);
|
||||
|
||||
return (
|
||||
<View style={styles.rightBtnContainer}>
|
||||
{search ? (
|
||||
<IconButton
|
||||
onPress={onSearch}
|
||||
testID="icon-search"
|
||||
name="magnify"
|
||||
color={colors.primary.paragraph}
|
||||
style={styles.rightBtn}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{deviceMode !== "mobile" ? (
|
||||
<Button
|
||||
onPress={onPressDefaultRightButton}
|
||||
testID={notesnook.ids.default.addBtn}
|
||||
icon={renderedInRoute === "Trash" ? "delete" : "plus"}
|
||||
iconSize={SIZE.xl}
|
||||
type="accent"
|
||||
hitSlop={{
|
||||
top: 10,
|
||||
right: 10,
|
||||
bottom: 10,
|
||||
left: 0
|
||||
}}
|
||||
{rightButton ? (
|
||||
<IconButton {...rightButton} color={colors.primary.icon} />
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
marginLeft: 10,
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 0,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.accent
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{headerRightButtons && headerRightButtons.length > 0 ? (
|
||||
<Menu
|
||||
ref={menuRef}
|
||||
animationDuration={200}
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
backgroundColor: contextMenuColors.primary.background,
|
||||
marginTop: 35
|
||||
}}
|
||||
onRequestClose={() => {
|
||||
//@ts-ignore
|
||||
menuRef.current?.hide();
|
||||
}}
|
||||
anchor={
|
||||
<IconButton
|
||||
onPress={() => {
|
||||
//@ts-ignore
|
||||
menuRef.current?.show();
|
||||
}}
|
||||
name="dots-vertical"
|
||||
color={colors.primary.paragraph}
|
||||
style={styles.rightBtn}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{headerRightButtons.map((item) => (
|
||||
<Button
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
borderRadius: 0,
|
||||
alignSelf: "flex-start",
|
||||
width: "100%"
|
||||
}}
|
||||
type="plain"
|
||||
buttonType={{
|
||||
text: contextMenuColors.primary.paragraph
|
||||
}}
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
onPress={async () => {
|
||||
//@ts-ignore
|
||||
menuRef.current?.hide();
|
||||
if (Platform.OS === "ios") await sleep(300);
|
||||
item.onPress();
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Menu>
|
||||
) : null}
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -149,10 +52,6 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
rightBtn: {
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 40,
|
||||
width: 40,
|
||||
marginLeft: 10,
|
||||
paddingRight: 0
|
||||
alignItems: "center"
|
||||
}
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
import { eScrollEvent } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import Tag from "../ui/tag";
|
||||
import Heading from "../ui/typography/heading";
|
||||
|
||||
@@ -75,7 +75,7 @@ export const Title = ({
|
||||
{!visible ? (
|
||||
<Heading
|
||||
numberOfLines={1}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
style={{
|
||||
flexWrap: "wrap",
|
||||
marginTop: Platform.OS === "ios" ? -1 : 0
|
||||
@@ -83,7 +83,7 @@ export const Title = ({
|
||||
color={accentColor || colors.primary.heading}
|
||||
>
|
||||
{isTag ? (
|
||||
<Heading size={SIZE.xl} color={colors.primary.accent}>
|
||||
<Heading size={AppFontSize.xl} color={colors.primary.accent}>
|
||||
#
|
||||
</Heading>
|
||||
) : null}
|
||||
|
||||
@@ -38,6 +38,7 @@ import RNFetchBlob from "react-native-blob-util";
|
||||
import Share from "react-native-share";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const ImagePreview = () => {
|
||||
const { colors } = useThemeColors("dialog");
|
||||
@@ -124,7 +125,7 @@ const ImagePreview = () => {
|
||||
justifyContent: "flex-end",
|
||||
alignItems: "center",
|
||||
height: 50,
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
gap: 10
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -23,31 +23,28 @@ import React from "react";
|
||||
import { Linking, ScrollView, useWindowDimensions, View } from "react-native";
|
||||
import { SwiperFlatList } from "react-native-swiper-flatlist";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import Navigation from "../../services/navigation";
|
||||
import SettingsService from "../../services/settings";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { getElevationStyle } from "../../utils/elevation";
|
||||
import { eOpenLoginDialog } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AuthMode } from "../auth";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import SettingsService from "../../services/settings";
|
||||
import { AuthMode } from "../auth/common";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const Intro = ({ navigation }) => {
|
||||
const Intro = () => {
|
||||
const { colors } = useThemeColors();
|
||||
const { width, height } = useWindowDimensions();
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const isTablet = width > 600;
|
||||
|
||||
const renderItem = React.useCallback(
|
||||
({ item }) => (
|
||||
({ item }: { item: (typeof strings.introData)[0] }) => (
|
||||
<View
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
width: deviceMode !== "mobile" ? width / 2 : width,
|
||||
paddingHorizontal:
|
||||
deviceMode !== "mobile" ? (width / 2) * 0.05 : width * 0.05
|
||||
width: isTablet ? width / 2 : width,
|
||||
paddingHorizontal: isTablet ? (width / 2) * 0.05 : width * 0.05
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@@ -76,7 +73,7 @@ const Intro = ({ navigation }) => {
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
maxWidth: "90%",
|
||||
width: "100%"
|
||||
}}
|
||||
@@ -88,21 +85,21 @@ const Intro = ({ navigation }) => {
|
||||
marginBottom: 5
|
||||
}}
|
||||
extraBold
|
||||
size={SIZE.xxl}
|
||||
size={AppFontSize.xxl}
|
||||
>
|
||||
{heading()}
|
||||
</Heading>
|
||||
))}
|
||||
|
||||
{item.body ? (
|
||||
<Paragraph size={SIZE.sm}>{item.body()}</Paragraph>
|
||||
<Paragraph size={AppFontSize.sm}>{item.body()}</Paragraph>
|
||||
) : null}
|
||||
|
||||
{item.tesimonial ? (
|
||||
<Paragraph
|
||||
style={{
|
||||
fontStyle: "italic",
|
||||
fontSize: SIZE.lg
|
||||
fontSize: AppFontSize.lg
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL(item.link);
|
||||
@@ -114,31 +111,37 @@ const Intro = ({ navigation }) => {
|
||||
</View>
|
||||
</View>
|
||||
),
|
||||
[colors.primary.accent, colors.secondary.background, deviceMode, width]
|
||||
[colors.primary.accent, colors.secondary.background, isTablet, width]
|
||||
);
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
testID="notesnook.splashscreen"
|
||||
style={{
|
||||
width: "100%"
|
||||
width: "100%",
|
||||
backgroundColor: colors.primary.background
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
width: deviceMode !== "mobile" ? width / 2 : "100%",
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border,
|
||||
alignSelf: deviceMode !== "mobile" ? "center" : undefined,
|
||||
borderWidth: deviceMode !== "mobile" ? 1 : null,
|
||||
borderColor: deviceMode !== "mobile" ? colors.primary.border : null,
|
||||
borderRadius: deviceMode !== "mobile" ? 20 : null,
|
||||
marginTop: deviceMode !== "mobile" ? 50 : null,
|
||||
paddingTop: insets.top + 10,
|
||||
paddingBottom: insets.top + 10,
|
||||
minHeight: height * 0.7 - (insets.top + insets.bottom)
|
||||
}}
|
||||
style={[
|
||||
{
|
||||
width: "100%",
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border,
|
||||
paddingTop: insets.top + 10,
|
||||
paddingBottom: insets.top + 10,
|
||||
minHeight: height * 0.7 - (insets.top + insets.bottom)
|
||||
},
|
||||
isTablet && {
|
||||
width: width / 2,
|
||||
alignSelf: "center",
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.border,
|
||||
borderRadius: 20,
|
||||
marginTop: 50
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SwiperFlatList
|
||||
autoplay
|
||||
@@ -170,23 +173,12 @@ const Intro = ({ navigation }) => {
|
||||
<Button
|
||||
width={250}
|
||||
onPress={async () => {
|
||||
eSendEvent(eOpenLoginDialog, AuthMode.welcomeSignup);
|
||||
setTimeout(() => {
|
||||
SettingsService.set({
|
||||
introCompleted: true
|
||||
});
|
||||
Navigation.replace("Notes", {
|
||||
canGoBack: false
|
||||
});
|
||||
}, 1000);
|
||||
SettingsService.set({ introCompleted: true });
|
||||
Navigation.push("Auth", {
|
||||
mode: AuthMode.welcomeSignup
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 24,
|
||||
alignSelf: "center",
|
||||
...getElevationStyle(5),
|
||||
borderRadius: 100
|
||||
}}
|
||||
fontSize={SIZE.md}
|
||||
fontSize={AppFontSize.md}
|
||||
type="accent"
|
||||
title={strings.getStarted()}
|
||||
/>
|
||||
File diff suppressed because one or more lines are too long
@@ -24,12 +24,13 @@ import { useMessageStore } from "../../../stores/use-message-store";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { Announcement } from "../../announcements/announcement";
|
||||
import { Card } from "../../list/card";
|
||||
import { RouteParams } from "../../../stores/use-navigation-store";
|
||||
|
||||
export type ListHeaderProps = {
|
||||
noAnnouncement?: boolean;
|
||||
color?: string;
|
||||
messageCard?: boolean;
|
||||
screen?: string;
|
||||
screen?: keyof RouteParams;
|
||||
shouldShow?: boolean;
|
||||
};
|
||||
|
||||
@@ -50,19 +51,11 @@ export const Header = React.memo(
|
||||
{announcements.length !== 0 && !noAnnouncement ? (
|
||||
<Announcement color={color || colors.primary.accent} />
|
||||
) : (screen as any) === "Search" ? null : !shouldShow ? (
|
||||
<View
|
||||
style={{
|
||||
marginBottom: 5,
|
||||
padding: 0,
|
||||
width: "100%",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<>
|
||||
{messageCard ? (
|
||||
<Card color={color || colors.primary.accent} />
|
||||
) : null}
|
||||
</View>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -17,140 +17,115 @@ 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 { getFormattedDate } from "@notesnook/common";
|
||||
import { Notebook } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { db } from "../../../common/database";
|
||||
import { ToastManager } from "../../../services/event-manager";
|
||||
import { useMenuStore } from "../../../stores/use-menu-store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import AppIcon from "../../ui/AppIcon";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { getFormattedDate } from "@notesnook/common";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import NotebookScreen from "../../../screens/notebook";
|
||||
import { db } from "../../../common/database";
|
||||
|
||||
export const NotebookHeader = ({
|
||||
notebook,
|
||||
onEditNotebook,
|
||||
totalNotes = 0
|
||||
totalNotes = 0,
|
||||
breadcrumbs
|
||||
}: {
|
||||
notebook: Notebook;
|
||||
onEditNotebook: () => void;
|
||||
totalNotes: number;
|
||||
breadcrumbs: { id: string; title: string }[];
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [isPinnedToMenu, setIsPinnedToMenu] = useState(
|
||||
db.shortcuts.exists(notebook.id)
|
||||
);
|
||||
const setMenuPins = useMenuStore((state) => state.setMenuPins);
|
||||
|
||||
const onPinNotebook = async () => {
|
||||
try {
|
||||
if (isPinnedToMenu) {
|
||||
await db.shortcuts.remove(notebook.id);
|
||||
} else {
|
||||
await db.shortcuts.add({
|
||||
item: {
|
||||
id: notebook.id,
|
||||
type: "notebook"
|
||||
}
|
||||
});
|
||||
ToastManager.show({
|
||||
heading: strings.shortcutCreated(),
|
||||
type: "success"
|
||||
});
|
||||
}
|
||||
setIsPinnedToMenu(db.shortcuts.exists(notebook.id));
|
||||
setMenuPins();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
marginBottom: 5,
|
||||
padding: 0,
|
||||
width: "100%",
|
||||
paddingVertical: 15,
|
||||
paddingHorizontal: 12,
|
||||
alignSelf: "center",
|
||||
borderRadius: 10,
|
||||
paddingTop: 25
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginTop: DefaultAppStyles.GAP,
|
||||
backgroundColor: colors.secondary.background
|
||||
}}
|
||||
>
|
||||
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
|
||||
{getFormattedDate(notebook.dateModified, "date-time")}
|
||||
</Paragraph>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center"
|
||||
width: "100%",
|
||||
gap: DefaultAppStyles.GAP_VERTICAL,
|
||||
paddingVertical: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
style={{
|
||||
flexShrink: 1
|
||||
}}
|
||||
size={SIZE.lg}
|
||||
>
|
||||
{notebook.title}
|
||||
</Heading>
|
||||
{breadcrumbs && breadcrumbs.length > 0 ? (
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
paddingBottom: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
>
|
||||
{breadcrumbs.map((item, index) => (
|
||||
<Pressable
|
||||
onPress={async () => {
|
||||
const notebook = await db.notebooks.notebook(item.id);
|
||||
if (!notebook) return;
|
||||
NotebookScreen.navigate(notebook, true);
|
||||
}}
|
||||
key={item.id}
|
||||
style={{
|
||||
width: undefined,
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: 0,
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{index === 0 ? null : (
|
||||
<IconButton
|
||||
name="chevron-right"
|
||||
size={16}
|
||||
top={0}
|
||||
left={0}
|
||||
right={0}
|
||||
bottom={0}
|
||||
style={{ width: 20, height: 25 }}
|
||||
/>
|
||||
)}
|
||||
<Paragraph size={AppFontSize.xs}>{item.title}</Paragraph>
|
||||
</Pressable>
|
||||
))}
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
<AppIcon name="notebook" size={AppFontSize.xxl} />
|
||||
|
||||
<View>
|
||||
<Heading size={AppFontSize.lg}>{notebook.title}</Heading>
|
||||
{notebook.description ? (
|
||||
<Paragraph size={AppFontSize.sm} color={colors.primary.paragraph}>
|
||||
{notebook.description}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row"
|
||||
flexDirection: "row",
|
||||
gap: DefaultAppStyles.GAP_SMALL
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
name={isPinnedToMenu ? "link-variant-off" : "link-variant"}
|
||||
onPress={onPinNotebook}
|
||||
tooltipText={"Create shortcut in side menu"}
|
||||
style={{
|
||||
marginRight: 15,
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
type="transparent"
|
||||
color={isPinnedToMenu ? colors.primary.accent : colors.primary.icon}
|
||||
size={SIZE.lg}
|
||||
/>
|
||||
<IconButton
|
||||
size={SIZE.lg}
|
||||
onPress={onEditNotebook}
|
||||
tooltipText="Edit this notebook"
|
||||
name="pencil"
|
||||
type="transparent"
|
||||
color={colors.primary.icon}
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
<Paragraph size={AppFontSize.xxs} color={colors.secondary.paragraph}>
|
||||
{strings.notes(totalNotes || 0)}
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph color={colors.secondary.paragraph} size={AppFontSize.xxs}>
|
||||
{getFormattedDate(notebook.dateModified, "date-time")}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{notebook.description ? (
|
||||
<Paragraph size={SIZE.sm} color={colors.primary.paragraph}>
|
||||
{notebook.description}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
|
||||
<Paragraph
|
||||
style={{
|
||||
marginTop: 10,
|
||||
fontStyle: "italic",
|
||||
fontFamily: undefined
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
{strings.notes(totalNotes || 0)}
|
||||
</Paragraph>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -21,16 +21,16 @@ import { GroupHeader, GroupOptions, ItemType } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { TouchableOpacity, View, useWindowDimensions } from "react-native";
|
||||
import { View } from "react-native";
|
||||
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
|
||||
import { presentSheet } from "../../../services/event-manager";
|
||||
import SettingsService from "../../../services/settings";
|
||||
import { RouteName } from "../../../stores/use-navigation-store";
|
||||
import { getContainerBorder } from "../../../utils/colors";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import Sort from "../../sheets/sort";
|
||||
import { Button } from "../../ui/button";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
|
||||
type SectionHeaderProps = {
|
||||
@@ -56,8 +56,6 @@ export const SectionHeader = React.memo<
|
||||
onOpenJumpToDialog
|
||||
}: SectionHeaderProps) {
|
||||
const { colors } = useThemeColors();
|
||||
const { fontScale } = useWindowDimensions();
|
||||
const groupBy = strings.groupByStrings[groupOptions.groupBy]();
|
||||
const isCompactModeEnabled = useIsCompactModeEnabled(
|
||||
dataType as "note" | "notebook"
|
||||
);
|
||||
@@ -65,104 +63,126 @@ export const SectionHeader = React.memo<
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
width: "95%",
|
||||
justifyContent: "space-between",
|
||||
paddingHorizontal: 12,
|
||||
height: 35 * fontScale,
|
||||
backgroundColor: colors.secondary.background,
|
||||
alignSelf: "center",
|
||||
borderRadius: 5,
|
||||
marginVertical: 5,
|
||||
...getContainerBorder(colors.secondary.background, 0.8)
|
||||
width: "100%",
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
onOpenJumpToDialog();
|
||||
}}
|
||||
activeOpacity={0.9}
|
||||
hitSlop={{ top: 10, left: 10, right: 30, bottom: 15 }}
|
||||
style={{
|
||||
height: "100%",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
color={color || colors.primary.accent}
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
textAlignVertical: "center"
|
||||
}}
|
||||
>
|
||||
{!item.title || item.title === "" ? strings.pinned() : item.title}
|
||||
</Heading>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
alignSelf: "center",
|
||||
justifyContent: "space-between",
|
||||
borderBottomWidth: 1,
|
||||
borderColor: colors.primary.border,
|
||||
paddingBottom: 1,
|
||||
paddingTop:
|
||||
index === 0
|
||||
? DefaultAppStyles.GAP_VERTICAL
|
||||
: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
>
|
||||
{index === 0 ? (
|
||||
<>
|
||||
<Button
|
||||
onPress={() => {
|
||||
presentSheet({
|
||||
component: <Sort screen={screen} type={dataType} />
|
||||
});
|
||||
}}
|
||||
title={groupBy}
|
||||
icon={
|
||||
groupOptions.sortDirection === "asc"
|
||||
? "sort-ascending"
|
||||
: "sort-descending"
|
||||
}
|
||||
height={25}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 0,
|
||||
backgroundColor: "transparent",
|
||||
marginRight:
|
||||
dataType === "note" ||
|
||||
screen === "Notes" ||
|
||||
dataType === "notebook"
|
||||
? 10
|
||||
: 0
|
||||
}}
|
||||
type="plain"
|
||||
iconPosition="right"
|
||||
/>
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
onOpenJumpToDialog();
|
||||
}}
|
||||
hitSlop={{ top: 10, left: 10, right: 30, bottom: 15 }}
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
flexDirection: "row",
|
||||
width: "auto"
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
size={AppFontSize.xxs}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
textAlignVertical: "center"
|
||||
}}
|
||||
color={color || colors.primary.accent}
|
||||
>
|
||||
{!item.title || item.title === ""
|
||||
? strings.pinned().toUpperCase()
|
||||
: item.title.toUpperCase()}
|
||||
</Heading>
|
||||
</Pressable>
|
||||
|
||||
<IconButton
|
||||
style={{
|
||||
width: 25,
|
||||
height: 25
|
||||
}}
|
||||
hidden={
|
||||
dataType !== "note" &&
|
||||
dataType !== "notebook" &&
|
||||
screen !== "Notes"
|
||||
}
|
||||
testID="icon-compact-mode"
|
||||
color={colors.secondary.icon}
|
||||
name={isCompactModeEnabled ? "view-list" : "view-list-outline"}
|
||||
onPress={() => {
|
||||
SettingsService.set({
|
||||
[dataType !== "notebook"
|
||||
? "notesListMode"
|
||||
: "notebooksListMode"]: !isCompactModeEnabled
|
||||
? "compact"
|
||||
: "normal"
|
||||
});
|
||||
}}
|
||||
size={SIZE.lg - 2}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: DefaultAppStyles.GAP_SMALL
|
||||
}}
|
||||
>
|
||||
{index === 0 ? (
|
||||
<>
|
||||
<IconButton
|
||||
name={
|
||||
groupOptions.sortDirection === "asc"
|
||||
? "sort-ascending"
|
||||
: "sort-descending"
|
||||
}
|
||||
color={colors.secondary.icon}
|
||||
testID="icon-sort"
|
||||
onPress={() => {
|
||||
if (!screen) return;
|
||||
presentSheet({
|
||||
component: (
|
||||
<Sort
|
||||
screen={screen}
|
||||
type={dataType}
|
||||
hideGroupOptions={screen === "Reminders"}
|
||||
/>
|
||||
)
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
width: 25,
|
||||
height: 25
|
||||
}}
|
||||
size={AppFontSize.lg - 2}
|
||||
/>
|
||||
<IconButton
|
||||
hidden={
|
||||
dataType !== "note" &&
|
||||
dataType !== "notebook" &&
|
||||
screen !== "Notes"
|
||||
}
|
||||
style={{
|
||||
width: 25,
|
||||
height: 25
|
||||
}}
|
||||
testID="icon-compact-mode"
|
||||
color={colors.secondary.icon}
|
||||
name={
|
||||
isCompactModeEnabled ? "view-list" : "view-list-outline"
|
||||
}
|
||||
onPress={() => {
|
||||
SettingsService.set({
|
||||
[dataType !== "notebook"
|
||||
? "notesListMode"
|
||||
: "notebooksListMode"]: !isCompactModeEnabled
|
||||
? "compact"
|
||||
: "normal"
|
||||
});
|
||||
}}
|
||||
size={AppFontSize.lg - 2}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{/* <IconButton
|
||||
style={{
|
||||
width: 25,
|
||||
height: 25
|
||||
}}
|
||||
color={colors.secondary.icon}
|
||||
name={"chevron-down"}
|
||||
size={SIZE.lg - 2}
|
||||
/> */}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -29,24 +29,32 @@ import { EntityLevel, decode } from "entities";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
|
||||
import NotebookScreen from "../../../screens/notebook";
|
||||
import { TaggedNotes } from "../../../screens/notes/tagged";
|
||||
import useNavigationStore from "../../../stores/use-navigation-store";
|
||||
import useNavigationStore, {
|
||||
RouteParams
|
||||
} from "../../../stores/use-navigation-store";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
|
||||
import {
|
||||
getFormattedDate,
|
||||
NotebooksWithDateEdited,
|
||||
TagsWithDateEdited
|
||||
} from "@notesnook/common";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import useIsSelected from "../../../hooks/use-selected";
|
||||
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
|
||||
import { NotebooksWithDateEdited, TagsWithDateEdited } from "@notesnook/common";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import { Properties } from "../../properties";
|
||||
import { Button } from "../../ui/button";
|
||||
import AppIcon from "../../ui/AppIcon";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { ReminderTime } from "../../ui/reminder-time";
|
||||
import { TimeSince } from "../../ui/time-since";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
type NoteItemProps = {
|
||||
item: Note | BaseTrashItem<Note>;
|
||||
@@ -60,6 +68,7 @@ type NoteItemProps = {
|
||||
isTrash?: boolean;
|
||||
noOpen?: boolean;
|
||||
locked?: boolean;
|
||||
renderedInRoute?: keyof RouteParams;
|
||||
};
|
||||
|
||||
const NoteItem = ({
|
||||
@@ -72,7 +81,8 @@ const NoteItem = ({
|
||||
tags,
|
||||
attachmentsCount,
|
||||
locked,
|
||||
noOpen = false
|
||||
noOpen = false,
|
||||
renderedInRoute
|
||||
}: NoteItemProps) => {
|
||||
const isEditingNote = useTabStore(
|
||||
(state) =>
|
||||
@@ -85,7 +95,8 @@ const NoteItem = ({
|
||||
);
|
||||
const _update = useRelationStore((state) => state.updater);
|
||||
const primaryColors = isEditingNote ? colors.selected : colors.primary;
|
||||
|
||||
const selectionMode = useSelectionStore((state) => state.selectionMode);
|
||||
const [selected] = useIsSelected(item);
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
@@ -94,69 +105,27 @@ const NoteItem = ({
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
{!compactMode ? (
|
||||
<View
|
||||
{compactMode ? null : (
|
||||
<Paragraph
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
zIndex: 10,
|
||||
elevation: 10,
|
||||
marginBottom: 2.5,
|
||||
flexWrap: "wrap"
|
||||
fontSize: AppFontSize.xxxs,
|
||||
color: colors.secondary.paragraph
|
||||
}}
|
||||
>
|
||||
{notebooks?.items
|
||||
?.filter(
|
||||
(item) =>
|
||||
item.id !== useNavigationStore.getState().focusedRouteId
|
||||
)
|
||||
.map((item) => (
|
||||
<Button
|
||||
title={
|
||||
item.title.length > 25
|
||||
? item.title.slice(0, 25) + "..."
|
||||
: item.title
|
||||
}
|
||||
tooltipText={item.title}
|
||||
key={item.id}
|
||||
height={25}
|
||||
icon="book-outline"
|
||||
type="secondary"
|
||||
fontSize={SIZE.xs}
|
||||
iconSize={SIZE.sm}
|
||||
textStyle={{
|
||||
marginRight: 0
|
||||
}}
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
marginRight: 5,
|
||||
paddingHorizontal: 6,
|
||||
marginBottom: 5
|
||||
}}
|
||||
onPress={() => {
|
||||
NotebookScreen.navigate(item, true);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
<ReminderTime
|
||||
reminder={reminder}
|
||||
color={color?.colorCode}
|
||||
onPress={() => {
|
||||
Properties.present(reminder);
|
||||
}}
|
||||
style={{
|
||||
height: 25
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
{getFormattedDate(
|
||||
date,
|
||||
dayjs(date).isBefore(dayjs().subtract(1, "day").hour(23))
|
||||
? "date"
|
||||
: "time"
|
||||
)}
|
||||
</Paragraph>
|
||||
)}
|
||||
|
||||
{compactMode ? (
|
||||
<Paragraph
|
||||
numberOfLines={1}
|
||||
color={color?.colorCode || primaryColors.heading}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
paddingRight: 10
|
||||
}}
|
||||
@@ -167,7 +136,7 @@ const NoteItem = ({
|
||||
<Heading
|
||||
numberOfLines={1}
|
||||
color={color?.colorCode || primaryColors.heading}
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
paddingRight: 10
|
||||
}}
|
||||
@@ -197,8 +166,10 @@ const NoteItem = ({
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
marginTop: 5,
|
||||
height: SIZE.md + 2
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
columnGap: 8,
|
||||
rowGap: 4,
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
>
|
||||
{!isTrash ? (
|
||||
@@ -206,10 +177,7 @@ const NoteItem = ({
|
||||
{item.conflicted ? (
|
||||
<Icon
|
||||
name="alert-circle"
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
color={colors.error.accent}
|
||||
/>
|
||||
) : null}
|
||||
@@ -218,10 +186,7 @@ const NoteItem = ({
|
||||
<Icon
|
||||
testID="sync-off"
|
||||
name="sync-off"
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
size={AppFontSize.sm}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
) : null}
|
||||
@@ -230,41 +195,27 @@ const NoteItem = ({
|
||||
<Icon
|
||||
testID="pencil-lock"
|
||||
name="pencil-lock"
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
size={AppFontSize.sm}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<TimeSince
|
||||
style={{
|
||||
fontSize: SIZE.xs,
|
||||
color: colors.secondary.paragraph,
|
||||
marginRight: 6
|
||||
}}
|
||||
time={date}
|
||||
updateFrequency={Date.now() - date < 60000 ? 2000 : 60000}
|
||||
/>
|
||||
|
||||
{attachmentsCount > 0 ? (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginRight: 6,
|
||||
gap: 2
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="attachment"
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xxs}
|
||||
>
|
||||
{attachmentsCount}
|
||||
</Paragraph>
|
||||
@@ -275,10 +226,7 @@ const NoteItem = ({
|
||||
<Icon
|
||||
testID="icon-pinned"
|
||||
name="pin-outline"
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
size={AppFontSize.sm}
|
||||
color={color?.colorCode || primaryColors.accent}
|
||||
/>
|
||||
) : null}
|
||||
@@ -287,10 +235,7 @@ const NoteItem = ({
|
||||
<Icon
|
||||
name="lock"
|
||||
testID="note-locked-icon"
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
size={AppFontSize.sm}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
) : null}
|
||||
@@ -299,37 +244,83 @@ const NoteItem = ({
|
||||
<Icon
|
||||
testID="icon-star"
|
||||
name="star-outline"
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
size={AppFontSize.sm}
|
||||
color="orange"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{reminder ? (
|
||||
<ReminderTime
|
||||
reminder={reminder}
|
||||
disabled
|
||||
color={color?.colorCode}
|
||||
textStyle={{
|
||||
fontSize: AppFontSize.xxxs
|
||||
}}
|
||||
iconSize={AppFontSize.xxxs}
|
||||
style={{
|
||||
height: "auto"
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{notebooks?.items
|
||||
?.filter(
|
||||
(item) =>
|
||||
renderedInRoute !== "Notebook" ||
|
||||
item.id !== useNavigationStore.getState().focusedRouteId
|
||||
)
|
||||
.map((item) => (
|
||||
<View
|
||||
key={item.id}
|
||||
style={{
|
||||
borderRadius: 4,
|
||||
backgroundColor: colors.secondary.background,
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL / 2,
|
||||
borderWidth: 0.5,
|
||||
borderColor: primaryColors.border,
|
||||
paddingVertical: 1,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: DefaultAppStyles.GAP_SMALL / 2
|
||||
}}
|
||||
>
|
||||
<AppIcon
|
||||
name="book-outline"
|
||||
size={AppFontSize.xxxs}
|
||||
color={colors.secondary.icon}
|
||||
/>
|
||||
<Paragraph
|
||||
size={AppFontSize.xxxs}
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
{item.title}
|
||||
</Paragraph>
|
||||
</View>
|
||||
))}
|
||||
|
||||
{!isTrash && !compactMode && tags
|
||||
? tags.items?.map((item) =>
|
||||
item.id ? (
|
||||
<Button
|
||||
title={"#" + item.title}
|
||||
<View
|
||||
key={item.id}
|
||||
height={23}
|
||||
type="plain"
|
||||
textStyle={{
|
||||
textDecorationLine: "underline",
|
||||
color: colors.secondary.paragraph
|
||||
}}
|
||||
hitSlop={{ top: 8, bottom: 12, left: 0, right: 0 }}
|
||||
fontSize={SIZE.xs}
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
paddingHorizontal: 6,
|
||||
marginRight: 4,
|
||||
zIndex: 10,
|
||||
maxWidth: tags.items?.length > 1 ? 130 : null
|
||||
borderRadius: 4,
|
||||
backgroundColor: colors.secondary.background,
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL / 2,
|
||||
borderWidth: 0.5,
|
||||
borderColor:
|
||||
color?.colorCode || primaryColors.border,
|
||||
paddingVertical: 1
|
||||
}}
|
||||
onPress={() => TaggedNotes.navigate(item, true)}
|
||||
/>
|
||||
>
|
||||
<Paragraph
|
||||
size={AppFontSize.xxxs}
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
#{item.title}
|
||||
</Paragraph>
|
||||
</View>
|
||||
) : null
|
||||
)
|
||||
: null}
|
||||
@@ -338,7 +329,7 @@ const NoteItem = ({
|
||||
<>
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xxs}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
@@ -352,7 +343,7 @@ const NoteItem = ({
|
||||
|
||||
<Paragraph
|
||||
color={primaryColors.accent}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xxs}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
@@ -378,7 +369,7 @@ const NoteItem = ({
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
color={colors.error.accent}
|
||||
/>
|
||||
) : null}
|
||||
@@ -387,11 +378,11 @@ const NoteItem = ({
|
||||
<Icon
|
||||
name="lock"
|
||||
testID="note-locked-icon"
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
color={colors.secondary.background}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -399,17 +390,17 @@ const NoteItem = ({
|
||||
<Icon
|
||||
testID="icon-star"
|
||||
name="star-outline"
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
color="orange"
|
||||
color={colors.static.orange}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<TimeSince
|
||||
style={{
|
||||
fontSize: SIZE.xs,
|
||||
fontSize: AppFontSize.xxs,
|
||||
color: colors.secondary.paragraph,
|
||||
marginRight: 6
|
||||
}}
|
||||
@@ -419,20 +410,39 @@ const NoteItem = ({
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<IconButton
|
||||
testID={notesnook.listitem.menu}
|
||||
color={primaryColors.paragraph}
|
||||
name="dots-horizontal"
|
||||
size={SIZE.xl}
|
||||
onPress={() => !noOpen && Properties.present(item)}
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
height: 35,
|
||||
width: 35,
|
||||
borderRadius: 100,
|
||||
alignItems: "center"
|
||||
}}
|
||||
/>
|
||||
{selectionMode === "note" || selectionMode === "trash" ? (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
height: 35,
|
||||
width: 35,
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<AppIcon
|
||||
name={selected ? "checkbox-outline" : "checkbox-blank-outline"}
|
||||
color={selected ? colors.selected.icon : colors.primary.icon}
|
||||
size={AppFontSize.lg}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<IconButton
|
||||
testID={notesnook.listitem.menu}
|
||||
color={colors.secondary.icon}
|
||||
name="dots-horizontal"
|
||||
size={AppFontSize.lg}
|
||||
onPress={() => !noOpen && Properties.present(item)}
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
height: 35,
|
||||
width: 35,
|
||||
borderRadius: 100,
|
||||
alignItems: "center"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -29,11 +29,12 @@ import {
|
||||
presentSheet
|
||||
} from "../../../services/event-manager";
|
||||
import { eOnLoadNote, eShowMergeDialog } from "../../../utils/events";
|
||||
import { tabBarRef } from "../../../utils/global-refs";
|
||||
import { fluidTabsRef } from "../../../utils/global-refs";
|
||||
|
||||
import { NotebooksWithDateEdited, TagsWithDateEdited } from "@notesnook/common";
|
||||
import NotePreview from "../../note-history/preview";
|
||||
import SelectionWrapper, { selectItem } from "../selection-wrapper";
|
||||
import { RouteParams } from "../../../stores/use-navigation-store";
|
||||
|
||||
export const openNote = async (
|
||||
item: Note,
|
||||
@@ -66,7 +67,7 @@ export const openNote = async (
|
||||
item: note
|
||||
});
|
||||
if (!DDS.isTab) {
|
||||
tabBarRef.current?.goToPage(1);
|
||||
fluidTabsRef.current?.goToPage("editor");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -82,6 +83,7 @@ type NoteWrapperProps = {
|
||||
date: number;
|
||||
isRenderedInActionSheet: boolean;
|
||||
locked?: boolean;
|
||||
renderedInRoute?: keyof RouteParams;
|
||||
};
|
||||
|
||||
export const NoteWrapper = React.memo<
|
||||
@@ -101,6 +103,7 @@ export const NoteWrapper = React.memo<
|
||||
onPress={() => openNote(item as Note, isTrash, isRenderedInActionSheet)}
|
||||
isSheet={isRenderedInActionSheet}
|
||||
item={item}
|
||||
index={index}
|
||||
color={restProps.color?.colorCode}
|
||||
>
|
||||
<NoteItem {...restProps} item={item} index={index} isTrash={isTrash} />
|
||||
|
||||
@@ -19,18 +19,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { getFormattedDate } from "@notesnook/common";
|
||||
import { BaseTrashItem, Notebook, TrashItem } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import useIsSelected from "../../../hooks/use-selected";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { Properties } from "../../properties";
|
||||
import AppIcon from "../../ui/AppIcon";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
type NotebookItemProps = {
|
||||
item: Notebook | BaseTrashItem<Notebook>;
|
||||
@@ -50,6 +54,8 @@ export const NotebookItem = ({
|
||||
const compactMode = useIsCompactModeEnabled(
|
||||
(item as TrashItem).itemType || item.type
|
||||
);
|
||||
const selectionMode = useSelectionStore((state) => state.selectionMode);
|
||||
const [selected] = useIsSelected(item);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -61,7 +67,7 @@ export const NotebookItem = ({
|
||||
>
|
||||
{compactMode ? (
|
||||
<Paragraph
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
@@ -71,7 +77,7 @@ export const NotebookItem = ({
|
||||
</Paragraph>
|
||||
) : (
|
||||
<Heading
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
@@ -83,7 +89,7 @@ export const NotebookItem = ({
|
||||
|
||||
{!item.description || compactMode ? null : (
|
||||
<Paragraph
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
numberOfLines={2}
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
@@ -99,15 +105,15 @@ export const NotebookItem = ({
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
marginTop: 5,
|
||||
height: SIZE.md + 2
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
height: AppFontSize.md + 2
|
||||
}}
|
||||
>
|
||||
{isTrash ? (
|
||||
<>
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
textAlignVertical: "center",
|
||||
marginRight: 6
|
||||
@@ -121,7 +127,7 @@ export const NotebookItem = ({
|
||||
</Paragraph>
|
||||
<Paragraph
|
||||
color={colors.primary.accent}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
textAlignVertical: "center",
|
||||
marginRight: 6
|
||||
@@ -134,7 +140,7 @@ export const NotebookItem = ({
|
||||
) : (
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
@@ -144,7 +150,7 @@ export const NotebookItem = ({
|
||||
)}
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
@@ -155,7 +161,7 @@ export const NotebookItem = ({
|
||||
{item.pinned ? (
|
||||
<Icon
|
||||
name="pin-outline"
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
marginRight: 10,
|
||||
marginTop: 2
|
||||
@@ -176,7 +182,7 @@ export const NotebookItem = ({
|
||||
<>
|
||||
<Paragraph
|
||||
color={colors.primary.icon}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
@@ -185,21 +191,39 @@ export const NotebookItem = ({
|
||||
</Paragraph>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<IconButton
|
||||
color={colors.primary.heading}
|
||||
name="dots-horizontal"
|
||||
testID={notesnook.ids.notebook.menu}
|
||||
size={SIZE.xl}
|
||||
onPress={() => Properties.present(item)}
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
height: 35,
|
||||
width: 35,
|
||||
borderRadius: 100,
|
||||
alignItems: "center"
|
||||
}}
|
||||
/>
|
||||
{selectionMode === "notebook" || selectionMode === "trash" ? (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
height: 35,
|
||||
width: 35,
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<AppIcon
|
||||
name={selected ? "checkbox-outline" : "checkbox-blank-outline"}
|
||||
color={selected ? colors.selected.icon : colors.primary.icon}
|
||||
size={AppFontSize.lg}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<IconButton
|
||||
color={colors.primary.heading}
|
||||
name="dots-horizontal"
|
||||
testID={notesnook.ids.notebook.menu}
|
||||
size={AppFontSize.xl}
|
||||
onPress={() => Properties.present(item)}
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
height: 35,
|
||||
width: 35,
|
||||
borderRadius: 100,
|
||||
alignItems: "center"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -22,7 +22,7 @@ import React from "react";
|
||||
import { View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { defaultBorderRadius, AppFontSize } from "../../../utils/size";
|
||||
import { Properties } from "../../properties";
|
||||
import ReminderSheet from "../../sheets/reminder";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
@@ -31,6 +31,10 @@ import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import SelectionWrapper, { selectItem } from "../selection-wrapper";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import useIsSelected from "../../../hooks/use-selected";
|
||||
import AppIcon from "../../ui/AppIcon";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
const ReminderItem = React.memo(
|
||||
({
|
||||
@@ -48,6 +52,8 @@ const ReminderItem = React.memo(
|
||||
|
||||
ReminderSheet.present(item, undefined, isSheet);
|
||||
};
|
||||
const selectionMode = useSelectionStore((state) => state.selectionMode);
|
||||
const [selected] = useIsSelected(item);
|
||||
return (
|
||||
<SelectionWrapper onPress={openReminder} item={item} isSheet={isSheet}>
|
||||
<View
|
||||
@@ -62,7 +68,7 @@ const ReminderItem = React.memo(
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
>
|
||||
{item.title}
|
||||
</Heading>
|
||||
@@ -82,18 +88,18 @@ const ReminderItem = React.memo(
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
marginTop: 5
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
>
|
||||
{item.disabled ? (
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: 6,
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
|
||||
alignItems: "center",
|
||||
marginTop: 5,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
justifyContent: "flex-start",
|
||||
alignSelf: "flex-start",
|
||||
marginRight: 10,
|
||||
@@ -102,11 +108,11 @@ const ReminderItem = React.memo(
|
||||
>
|
||||
<Icon
|
||||
name="bell-off-outline"
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
color={colors.error.icon}
|
||||
/>
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
style={{ marginLeft: 5 }}
|
||||
>
|
||||
@@ -118,24 +124,24 @@ const ReminderItem = React.memo(
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: 6,
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
|
||||
alignItems: "center",
|
||||
marginTop: 5,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
justifyContent: "flex-start",
|
||||
alignSelf: "flex-start",
|
||||
marginRight: 10,
|
||||
marginRight: DefaultAppStyles.GAP_SMALL,
|
||||
height: 30
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="reload"
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
color={colors.primary.accent}
|
||||
/>
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
style={{ marginLeft: 5 }}
|
||||
>
|
||||
@@ -147,29 +153,49 @@ const ReminderItem = React.memo(
|
||||
<ReminderTime
|
||||
reminder={item}
|
||||
checkIsActive={false}
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xxs}
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
height: 25,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
|
||||
alignSelf: "flex-start"
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<IconButton
|
||||
testID={notesnook.listitem.menu}
|
||||
color={colors.primary.paragraph}
|
||||
name="dots-horizontal"
|
||||
size={SIZE.xl}
|
||||
onPress={() => Properties.present(item, [], isSheet)}
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
height: 35,
|
||||
width: 35,
|
||||
borderRadius: 100,
|
||||
alignItems: "center"
|
||||
}}
|
||||
/>
|
||||
|
||||
{selectionMode === "note" || selectionMode === "trash" ? (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
height: 35,
|
||||
width: 35,
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<AppIcon
|
||||
name={selected ? "checkbox-outline" : "checkbox-blank-outline"}
|
||||
color={selected ? colors.selected.icon : colors.primary.icon}
|
||||
size={AppFontSize.lg}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<IconButton
|
||||
testID={notesnook.listitem.menu}
|
||||
color={colors.primary.paragraph}
|
||||
name="dots-horizontal"
|
||||
size={AppFontSize.xl}
|
||||
onPress={() => Properties.present(item, isSheet)}
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
height: 35,
|
||||
width: 35,
|
||||
borderRadius: 100,
|
||||
alignItems: "center"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</SelectionWrapper>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -39,16 +39,15 @@ export const Filler = ({ item, color }: { item: Item; color?: string }) => {
|
||||
style={{
|
||||
position: "absolute",
|
||||
width: "110%",
|
||||
height: "150%",
|
||||
backgroundColor: colors.selected.background,
|
||||
borderLeftWidth: 5,
|
||||
borderLeftColor: isEditingNote
|
||||
? color
|
||||
? color
|
||||
: colors.selected.accent
|
||||
: "transparent"
|
||||
height: "100%",
|
||||
backgroundColor: colors.selected.accent
|
||||
// borderLeftWidth: 5,
|
||||
// borderLeftColor: isEditingNote
|
||||
// ? color
|
||||
// ? color
|
||||
// : colors.selected.accent
|
||||
// : "transparent"
|
||||
}}
|
||||
collapsable={false}
|
||||
/>
|
||||
) : null;
|
||||
};
|
||||
|
||||
@@ -17,14 +17,15 @@ 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 { Item, TrashItem } from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { PropsWithChildren, useRef } from "react";
|
||||
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
|
||||
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import { Filler } from "./back-fill";
|
||||
import { SelectionIcon } from "./selection";
|
||||
import { Item, TrashItem } from "@notesnook/core";
|
||||
import { View } from "react-native";
|
||||
|
||||
export function selectItem(item: Item) {
|
||||
if (useSelectionStore.getState().selectionMode === item.type) {
|
||||
@@ -49,6 +50,7 @@ type SelectionWrapperProps = PropsWithChildren<{
|
||||
testID?: string;
|
||||
isSheet?: boolean;
|
||||
color?: string;
|
||||
index?: number;
|
||||
}>;
|
||||
|
||||
const SelectionWrapper = ({
|
||||
@@ -57,10 +59,16 @@ const SelectionWrapper = ({
|
||||
testID,
|
||||
isSheet,
|
||||
children,
|
||||
color
|
||||
color,
|
||||
index = 0
|
||||
}: SelectionWrapperProps) => {
|
||||
const itemId = useRef(item.id);
|
||||
const { colors, isDark } = useThemeColors();
|
||||
const isEditingNote = useTabStore(
|
||||
(state) =>
|
||||
state.tabs.find((t) => t.id === state.currentTab)?.session?.noteId ===
|
||||
item.id
|
||||
);
|
||||
const compactMode = useIsCompactModeEnabled(
|
||||
(item as TrashItem).itemType || item.type
|
||||
);
|
||||
@@ -79,7 +87,13 @@ const SelectionWrapper = ({
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
customColor={isSheet ? colors.secondary.background : "transparent"}
|
||||
customColor={
|
||||
isEditingNote
|
||||
? colors.selected.background
|
||||
: isSheet
|
||||
? colors.primary.hover
|
||||
: "transparent"
|
||||
}
|
||||
testID={testID}
|
||||
onLongPress={onLongPress}
|
||||
onPress={onPress}
|
||||
@@ -91,15 +105,26 @@ const SelectionWrapper = ({
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
alignSelf: "center",
|
||||
overflow: "hidden",
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: compactMode ? 4 : 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingVertical: compactMode ? 4 : DefaultAppStyles.GAP_VERTICAL,
|
||||
borderRadius: isSheet ? 10 : 0,
|
||||
marginBottom: isSheet ? 12 : undefined
|
||||
marginBottom: isSheet ? DefaultAppStyles.GAP_VERTICAL : undefined
|
||||
}}
|
||||
>
|
||||
{item.type === "note" ? <Filler item={item} color={color} /> : null}
|
||||
<SelectionIcon item={item} />
|
||||
{isEditingNote ? (
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: color || colors.selected.accent,
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: 5
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{children}
|
||||
</Pressable>
|
||||
);
|
||||
|
||||
@@ -24,7 +24,7 @@ import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
|
||||
import useIsSelected from "../../../hooks/use-selected";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { Item, TrashItem } from "@notesnook/core";
|
||||
|
||||
export const SelectionIcon = ({ item }: { item: Item }) => {
|
||||
@@ -52,7 +52,7 @@ export const SelectionIcon = ({ item }: { item: Item }) => {
|
||||
>
|
||||
{selected ? (
|
||||
<Icon
|
||||
size={compactMode ? SIZE.xl - 2 : SIZE.xl}
|
||||
size={compactMode ? AppFontSize.xl - 2 : AppFontSize.xl}
|
||||
color={selected ? colors.selected.accent : colors.primary.icon}
|
||||
name={"check"}
|
||||
/>
|
||||
|
||||
@@ -23,13 +23,14 @@ import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { TaggedNotes } from "../../../screens/notes/tagged";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { Properties } from "../../properties";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import SelectionWrapper, { selectItem } from "../selection-wrapper";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
const TagItem = React.memo(
|
||||
({
|
||||
@@ -60,9 +61,9 @@ const TagItem = React.memo(
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
<Heading size={SIZE.md}>
|
||||
<Heading size={AppFontSize.md}>
|
||||
<Heading
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
style={{
|
||||
color: colors.primary.accent
|
||||
}}
|
||||
@@ -73,9 +74,9 @@ const TagItem = React.memo(
|
||||
</Heading>
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
marginTop: 5
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
>
|
||||
{strings.notes(totalNotes)}
|
||||
@@ -85,7 +86,7 @@ const TagItem = React.memo(
|
||||
<IconButton
|
||||
color={colors.primary.heading}
|
||||
name="dots-horizontal"
|
||||
size={SIZE.xl}
|
||||
size={AppFontSize.xl}
|
||||
onPress={() => {
|
||||
Properties.present(item);
|
||||
}}
|
||||
|
||||
@@ -17,20 +17,28 @@ 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 { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { Dimensions, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { useMessageStore } from "../../stores/use-message-store";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { getContainerBorder, hexToRGBA } from "../../utils/colors";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { Message, useMessageStore } from "../../stores/use-message-store";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
|
||||
export const Card = ({ color }: { color?: string }) => {
|
||||
export const Card = ({
|
||||
color,
|
||||
customMessage
|
||||
}: {
|
||||
color?: string;
|
||||
customMessage?: Omit<Message, "data">;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
color = color ? color : colors.primary.accent;
|
||||
const messageBoardState = useMessageStore((state) => state.message);
|
||||
const messageBoardState = useMessageStore(
|
||||
(state) => customMessage || state.message
|
||||
);
|
||||
const announcements = useMessageStore((state) => state.announcements);
|
||||
const fontScale = Dimensions.get("window").fontScale;
|
||||
|
||||
@@ -38,18 +46,19 @@ export const Card = ({ color }: { color?: string }) => {
|
||||
(announcements && announcements.length) ? null : (
|
||||
<View
|
||||
style={{
|
||||
width: "95%"
|
||||
width: "100%",
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<Pressable
|
||||
onPress={messageBoardState.onPress}
|
||||
type="plain"
|
||||
style={{
|
||||
paddingVertical: 12,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
paddingHorizontal: 0,
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
@@ -57,30 +66,20 @@ export const Card = ({ color }: { color?: string }) => {
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexShrink: 1
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
width: 40 * fontScale,
|
||||
backgroundColor:
|
||||
messageBoardState.type === "error"
|
||||
? hexToRGBA(colors.error.accent, 0.15)
|
||||
: hexToRGBA(color, 0.15),
|
||||
height: 40 * fontScale,
|
||||
borderRadius: 100,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
...getContainerBorder(
|
||||
messageBoardState.type === "error"
|
||||
? colors.error.accent
|
||||
: color || colors.primary.accent,
|
||||
0.4
|
||||
)
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.xxxl}
|
||||
color={
|
||||
messageBoardState.type === "error" ? colors.error.icon : color
|
||||
}
|
||||
@@ -95,39 +94,21 @@ export const Card = ({ color }: { color?: string }) => {
|
||||
marginRight: 10
|
||||
}}
|
||||
>
|
||||
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
|
||||
{messageBoardState.message}
|
||||
</Paragraph>
|
||||
<Paragraph
|
||||
style={{
|
||||
flexWrap: "nowrap",
|
||||
flexShrink: 1
|
||||
}}
|
||||
size={AppFontSize.sm}
|
||||
color={colors.primary.heading}
|
||||
>
|
||||
{messageBoardState.actionText}
|
||||
</Paragraph>
|
||||
<Paragraph color={colors.secondary.paragraph} size={AppFontSize.xs}>
|
||||
{messageBoardState.message}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{fontScale > 1 ? null : (
|
||||
<View
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="chevron-right"
|
||||
color={
|
||||
messageBoardState.type === "error" ? colors.error.icon : color
|
||||
}
|
||||
size={SIZE.lg}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</Pressable>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -19,12 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { ActivityIndicator, useWindowDimensions, View } from "react-native";
|
||||
import { ActivityIndicator, View } from "react-native";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { TTip, useTip } from "../../services/tip-manager";
|
||||
import { RouteParams } from "../../stores/use-navigation-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { Tip } from "../tip";
|
||||
import { Button } from "../ui/button";
|
||||
import Seperator from "../ui/seperator";
|
||||
@@ -46,7 +46,7 @@ type EmptyListProps = {
|
||||
title?: string;
|
||||
color?: string;
|
||||
dataType: string;
|
||||
screen?: string;
|
||||
screen?: keyof RouteParams;
|
||||
};
|
||||
|
||||
export const Empty = React.memo(function Empty({
|
||||
@@ -58,8 +58,6 @@ export const Empty = React.memo(function Empty({
|
||||
screen
|
||||
}: EmptyListProps) {
|
||||
const { colors } = useThemeColors();
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const { height } = useWindowDimensions();
|
||||
const introCompleted = useSettingStore(
|
||||
(state) => state.settings.introCompleted
|
||||
);
|
||||
@@ -74,7 +72,7 @@ export const Empty = React.memo(function Empty({
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
height: height - (140 + insets.top),
|
||||
flex: 1,
|
||||
width: "80%",
|
||||
justifyContent: "center",
|
||||
alignSelf: "center"
|
||||
@@ -98,18 +96,13 @@ export const Empty = React.memo(function Empty({
|
||||
{placeholder?.button && (
|
||||
<Button
|
||||
testID={notesnook.buttons.add}
|
||||
type="accent"
|
||||
type="secondaryAccented"
|
||||
title={placeholder?.button}
|
||||
iconPosition="right"
|
||||
icon="arrow-right"
|
||||
onPress={placeholder?.action}
|
||||
buttonType={{
|
||||
text: "white"
|
||||
}}
|
||||
style={{
|
||||
alignSelf: "flex-start",
|
||||
borderRadius: 5,
|
||||
height: 40
|
||||
alignSelf: "flex-start"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -124,12 +117,12 @@ export const Empty = React.memo(function Empty({
|
||||
}}
|
||||
>
|
||||
<Heading>{placeholder?.title}</Heading>
|
||||
<Paragraph size={SIZE.sm} textBreakStrategy="balanced">
|
||||
<Paragraph size={AppFontSize.sm} textBreakStrategy="balanced">
|
||||
{placeholder?.loading}
|
||||
</Paragraph>
|
||||
<Seperator />
|
||||
<ActivityIndicator
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
color={color || colors.primary.accent}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -24,9 +24,9 @@ import React, { useEffect, useRef } from "react";
|
||||
import {
|
||||
NativeScrollEvent,
|
||||
NativeSyntheticEvent,
|
||||
RefreshControl
|
||||
RefreshControl,
|
||||
View
|
||||
} from "react-native";
|
||||
import Animated, { FadeInDown } from "react-native-reanimated";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import { useGroupOptions } from "../../hooks/use-group-options";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
@@ -34,8 +34,7 @@ import Sync from "../../services/sync";
|
||||
import { RouteName } from "../../stores/use-navigation-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { eScrollEvent } from "../../utils/events";
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
import { Footer } from "../list-items/footer";
|
||||
import { fluidTabsRef } from "../../utils/global-refs";
|
||||
import { Header } from "../list-items/headers/header";
|
||||
import { Empty, PlaceholderData } from "./empty";
|
||||
import { ListItemWrapper } from "./list-item.wrapper";
|
||||
@@ -43,6 +42,7 @@ import { ListItemWrapper } from "./list-item.wrapper";
|
||||
type ListProps = {
|
||||
data: VirtualizedGrouping<Item> | undefined;
|
||||
dataType: Item["type"];
|
||||
mode?: "drawer" | "sheet";
|
||||
onRefresh?: () => void;
|
||||
loading?: boolean;
|
||||
headerTitle?: string;
|
||||
@@ -145,70 +145,80 @@ export default function List(props: ListProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Animated.View
|
||||
<View
|
||||
style={{
|
||||
flex: 1
|
||||
}}
|
||||
entering={props.renderedInRoute === "Search" ? undefined : FadeInDown}
|
||||
>
|
||||
<ListView
|
||||
style={styles}
|
||||
ref={scrollRef}
|
||||
testID={notesnook.list.id}
|
||||
data={props.data?.placeholders || []}
|
||||
renderItem={renderItem}
|
||||
onScroll={onListScroll}
|
||||
nestedScrollEnabled={true}
|
||||
onMomentumScrollEnd={() => {
|
||||
tabBarRef.current?.unlock();
|
||||
}}
|
||||
getItemType={(item: number, index: number) => {
|
||||
return props.data?.type(index);
|
||||
}}
|
||||
estimatedItemSize={isCompactModeEnabled ? 60 : 120}
|
||||
directionalLockEnabled={true}
|
||||
keyboardShouldPersistTaps="always"
|
||||
keyboardDismissMode="interactive"
|
||||
refreshControl={
|
||||
props.isRenderedInActionSheet ? null : (
|
||||
<RefreshControl
|
||||
tintColor={colors.primary.accent}
|
||||
colors={[colors.primary.accent]}
|
||||
progressBackgroundColor={colors.secondary.background}
|
||||
onRefresh={_onRefresh}
|
||||
refreshing={false}
|
||||
/>
|
||||
)
|
||||
}
|
||||
ListEmptyComponent={
|
||||
props.placeholder ? (
|
||||
<Empty
|
||||
loading={props.loading}
|
||||
title={props.headerTitle}
|
||||
dataType={props.dataType}
|
||||
{props.data?.placeholders?.length === 0 ? (
|
||||
<>
|
||||
{props.CustomLisHeader ? (
|
||||
props.CustomLisHeader
|
||||
) : !props.headerTitle ? null : (
|
||||
<Header
|
||||
color={props.customAccentColor}
|
||||
placeholder={props.placeholder}
|
||||
screen={props.renderedInRoute}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
ListFooterComponent={
|
||||
<Footer height={props.renderedInRoute === "Notebook" ? 300 : 150} />
|
||||
}
|
||||
ListHeaderComponent={
|
||||
<>
|
||||
{props.CustomLisHeader ? (
|
||||
props.CustomLisHeader
|
||||
) : !props.headerTitle ? null : (
|
||||
<Header
|
||||
color={props.customAccentColor}
|
||||
screen={props.renderedInRoute}
|
||||
)}
|
||||
<Empty
|
||||
loading={props.loading}
|
||||
title={props.headerTitle}
|
||||
dataType={props.dataType}
|
||||
color={props.customAccentColor}
|
||||
placeholder={props.placeholder}
|
||||
screen={props.renderedInRoute}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<ListView
|
||||
style={styles}
|
||||
ref={scrollRef}
|
||||
testID={notesnook.list.id}
|
||||
data={props.data?.placeholders || []}
|
||||
renderItem={renderItem}
|
||||
onScroll={onListScroll}
|
||||
nestedScrollEnabled={true}
|
||||
onMomentumScrollEnd={() => {
|
||||
fluidTabsRef.current?.unlock();
|
||||
}}
|
||||
getItemType={(item: number, index: number) => {
|
||||
return props.data?.type(index);
|
||||
}}
|
||||
estimatedItemSize={isCompactModeEnabled ? 60 : 120}
|
||||
directionalLockEnabled={true}
|
||||
keyboardShouldPersistTaps="always"
|
||||
keyboardDismissMode="interactive"
|
||||
ListFooterComponent={
|
||||
<View
|
||||
style={{ height: props.data?.placeholders?.length ? 100 : 0 }}
|
||||
/>
|
||||
}
|
||||
refreshControl={
|
||||
props.isRenderedInActionSheet ? null : (
|
||||
<RefreshControl
|
||||
tintColor={colors.primary.accent}
|
||||
colors={[colors.primary.accent]}
|
||||
progressBackgroundColor={colors.secondary.background}
|
||||
onRefresh={_onRefresh}
|
||||
refreshing={false}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
ListHeaderComponent={
|
||||
<>
|
||||
{props.CustomLisHeader ? (
|
||||
props.CustomLisHeader
|
||||
) : !props.headerTitle ? null : (
|
||||
<Header
|
||||
color={props.customAccentColor}
|
||||
screen={props.renderedInRoute}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -200,6 +200,7 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
isRenderedInActionSheet={isSheet}
|
||||
index={index}
|
||||
locked={locked.current}
|
||||
renderedInRoute={props.renderedInRoute}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -26,8 +26,8 @@ import {
|
||||
DraxListRenderItemContent
|
||||
} from "react-native-drax";
|
||||
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { fluidTabsRef } from "../../utils/global-refs";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { useSideBarDraggingStore } from "../side-menu/dragging-store";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
|
||||
@@ -61,9 +61,9 @@ function ReorderableList<T extends { id: string }>({
|
||||
const listRef = useRef<FlatList | null>(null);
|
||||
|
||||
if (dragging) {
|
||||
tabBarRef.current?.lock();
|
||||
fluidTabsRef.current?.lock();
|
||||
} else {
|
||||
tabBarRef.current?.unlock();
|
||||
fluidTabsRef.current?.unlock();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -79,13 +79,14 @@ function ReorderableList<T extends { id: string }>({
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: 12
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
opacity: isHidden ? 0.4 : 1,
|
||||
flexGrow: 1,
|
||||
opacity: isHidden ? 0.4 : 1
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
{renderDraggableItem(info, props)}
|
||||
@@ -94,13 +95,12 @@ function ReorderableList<T extends { id: string }>({
|
||||
<IconButton
|
||||
name={!isHidden ? "minus" : "plus"}
|
||||
color={colors.primary.icon}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
top={0}
|
||||
bottom={0}
|
||||
onPress={() => {
|
||||
const _hiddenItems = hiddenItemsState.slice();
|
||||
const index = _hiddenItems.indexOf(info.item.id);
|
||||
|
||||
if (index === -1) {
|
||||
_hiddenItems.push(info.item?.id);
|
||||
} else {
|
||||
|
||||
@@ -38,7 +38,7 @@ import Navigation from "../../services/navigation";
|
||||
import Sync from "../../services/sync";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { eOnLoadNote, eShowMergeDialog } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import BaseDialog from "../dialog/base-dialog";
|
||||
import DialogButtons from "../dialog/dialog-buttons";
|
||||
import DialogContainer from "../dialog/dialog-container";
|
||||
@@ -49,6 +49,7 @@ import Seperator from "../ui/seperator";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { diff } from "diffblazer";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const MergeConflicts = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -142,7 +143,7 @@ const MergeConflicts = () => {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingLeft: 6
|
||||
}}
|
||||
>
|
||||
@@ -164,7 +165,7 @@ const MergeConflicts = () => {
|
||||
<Paragraph
|
||||
style={{ flexWrap: "wrap" }}
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
@@ -201,9 +202,9 @@ const MergeConflicts = () => {
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xs}
|
||||
/>
|
||||
) : null}
|
||||
<View style={{ width: 10 }} />
|
||||
@@ -218,9 +219,9 @@ const MergeConflicts = () => {
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xs}
|
||||
color={colors.error.paragraph}
|
||||
onPress={() => {
|
||||
setDialogVisible(true);
|
||||
@@ -233,12 +234,12 @@ const MergeConflicts = () => {
|
||||
height={30}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
minWidth: 60,
|
||||
marginLeft: 10
|
||||
}}
|
||||
type="accent"
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xs}
|
||||
title={
|
||||
keeping && !isDiscarded ? strings.undo() : strings.keep()
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import { db } from "../../common/database";
|
||||
import { useDBItem } from "../../hooks/use-db-item";
|
||||
import { presentSheet } from "../../services/event-manager";
|
||||
import { openLinkInBrowser } from "../../utils/functions";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import DialogHeader from "../dialog/dialog-header";
|
||||
import SheetProvider from "../sheet-provider";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
@@ -38,6 +38,7 @@ import Seperator from "../ui/seperator";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import NotePreview from "./preview";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const HistoryItem = ({
|
||||
index,
|
||||
@@ -88,16 +89,16 @@ const HistoryItem = ({
|
||||
style={{
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
height: 45,
|
||||
marginBottom: 10,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
{!item ? null : (
|
||||
<>
|
||||
<Paragraph>{getDate(item.dateCreated, item.dateModified)}</Paragraph>
|
||||
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
|
||||
<Paragraph color={colors.secondary.paragraph} size={AppFontSize.xs}>
|
||||
{getTimeAgo(item.dateModified)}
|
||||
</Paragraph>
|
||||
</>
|
||||
@@ -148,7 +149,7 @@ export default function NoteHistory({
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
height: !history?.placeholders.length
|
||||
? 300
|
||||
: (history.placeholders.length + 1) * 55,
|
||||
@@ -170,7 +171,7 @@ export default function NoteHistory({
|
||||
>
|
||||
{_loading ? (
|
||||
<ActivityIndicator
|
||||
size={SIZE.xl}
|
||||
size={AppFontSize.xl}
|
||||
color={colors.primary.accent}
|
||||
/>
|
||||
) : (
|
||||
@@ -187,7 +188,7 @@ export default function NoteHistory({
|
||||
/>
|
||||
</View>
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
style={{
|
||||
alignSelf: "center"
|
||||
|
||||
@@ -36,6 +36,7 @@ import { Button } from "../ui/button";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { diff } from "diffblazer";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -158,7 +159,7 @@ export default function NotePreview({ session, content, note }) {
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
@@ -173,7 +174,7 @@ export default function NotePreview({ session, content, note }) {
|
||||
type="error"
|
||||
width="100%"
|
||||
style={{
|
||||
marginTop: 12
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { FeatureBlock } from "./feature";
|
||||
import { ScrollView } from "react-native-actions-sheet";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const CompactFeatures = ({
|
||||
vertical,
|
||||
@@ -84,7 +85,7 @@ export const CompactFeatures = ({
|
||||
style={{
|
||||
width: "100%",
|
||||
maxHeight: maxHeight,
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{data.map((item) => (
|
||||
|
||||
@@ -17,6 +17,7 @@ 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 { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useState } from "react";
|
||||
import { ActivityIndicator, Platform, ScrollView, View } from "react-native";
|
||||
import { LAUNCH_ROCKET } from "../../assets/images/assets";
|
||||
@@ -24,17 +25,13 @@ import { db } from "../../common/database";
|
||||
import { usePricing } from "../../hooks/use-pricing";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { eSendEvent, presentSheet } from "../../services/event-manager";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { getElevationStyle } from "../../utils/elevation";
|
||||
import {
|
||||
eClosePremiumDialog,
|
||||
eCloseSheet,
|
||||
eOpenLoginDialog
|
||||
} from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { eClosePremiumDialog, eCloseSheet } from "../../utils/events";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { AuthMode } from "../auth";
|
||||
import { AuthMode } from "../auth/common";
|
||||
import SheetProvider from "../sheet-provider";
|
||||
import { Toast } from "../toast";
|
||||
import { Button } from "../ui/button";
|
||||
@@ -47,6 +44,7 @@ import { Walkthrough } from "../walkthroughs";
|
||||
import { features } from "./features";
|
||||
import { Group } from "./group";
|
||||
import { PricingPlans } from "./pricing-plans";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const Component = ({ close, promo }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -66,9 +64,9 @@ export const Component = ({ close, promo }) => {
|
||||
});
|
||||
} else {
|
||||
close();
|
||||
setTimeout(() => {
|
||||
eSendEvent(eOpenLoginDialog, AuthMode.trialSignup);
|
||||
}, 400);
|
||||
Navigation.navigate("Auth", {
|
||||
mode: AuthMode.trialSignup
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -137,14 +135,14 @@ export const Component = ({ close, promo }) => {
|
||||
|
||||
<Heading
|
||||
key="heading"
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
paddingTop: 20
|
||||
}}
|
||||
>
|
||||
Notesnook{" "}
|
||||
<Heading size={SIZE.lg} color={colors.primary.accent}>
|
||||
<Heading size={AppFontSize.lg} color={colors.primary.accent}>
|
||||
Pro
|
||||
</Heading>
|
||||
</Heading>
|
||||
@@ -154,7 +152,7 @@ export const Component = ({ close, promo }) => {
|
||||
style={{
|
||||
marginBottom: 20
|
||||
}}
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
color={colors.primary.accent}
|
||||
/>
|
||||
) : (
|
||||
@@ -163,7 +161,7 @@ export const Component = ({ close, promo }) => {
|
||||
alignSelf: "center",
|
||||
marginBottom: 20
|
||||
}}
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
>
|
||||
(
|
||||
{Platform.OS === "android"
|
||||
@@ -176,9 +174,9 @@ export const Component = ({ close, promo }) => {
|
||||
|
||||
<Paragraph
|
||||
key="description"
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
textAlign: "center",
|
||||
alignSelf: "center",
|
||||
paddingBottom: 20,
|
||||
@@ -206,7 +204,7 @@ export const Component = ({ close, promo }) => {
|
||||
type="accent"
|
||||
width={250}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginBottom: 15,
|
||||
borderRadius: 100
|
||||
}}
|
||||
@@ -222,7 +220,7 @@ export const Component = ({ close, promo }) => {
|
||||
type={userCanRequestTrial ? "secondaryAccented" : "accent"}
|
||||
width={250}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginBottom: 15,
|
||||
borderRadius: 100
|
||||
}}
|
||||
@@ -231,18 +229,18 @@ export const Component = ({ close, promo }) => {
|
||||
{!user || userCanRequestTrial ? (
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
textAlign: "center",
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
maxWidth: "80%"
|
||||
}}
|
||||
>
|
||||
{user
|
||||
? 'On clicking "Try free for 14 days", your free trial will be activated.'
|
||||
: "After sign up you will be asked to activate your free trial."}{" "}
|
||||
<Paragraph size={SIZE.xs} style={{ fontWeight: "bold" }}>
|
||||
<Paragraph size={AppFontSize.xs} style={{ fontWeight: "bold" }}>
|
||||
No credit card is required.
|
||||
</Paragraph>
|
||||
</Paragraph>
|
||||
@@ -257,7 +255,7 @@ export const Component = ({ close, promo }) => {
|
||||
<View
|
||||
key="plans"
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<PricingPlans showTrialOption={false} promo={promo} />
|
||||
@@ -272,7 +270,7 @@ export const Component = ({ close, promo }) => {
|
||||
}
|
||||
type="accent"
|
||||
style={{
|
||||
paddingHorizontal: 24,
|
||||
paddingHorizontal: DefaultAppStyles.GAP * 2,
|
||||
position: "absolute",
|
||||
borderRadius: 100,
|
||||
bottom: 30,
|
||||
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
eOpenResultDialog,
|
||||
eOpenTrialEndingDialog
|
||||
} from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import BaseDialog from "../dialog/base-dialog";
|
||||
import DialogContainer from "../dialog/dialog-container";
|
||||
@@ -42,6 +42,7 @@ import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { CompactFeatures } from "./compact-features";
|
||||
import { Offer } from "./offer";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const Expiring = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -94,7 +95,7 @@ export const Expiring = () => {
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
@@ -127,7 +128,7 @@ export const Expiring = () => {
|
||||
paddingTop: 0,
|
||||
paddingBottom: 20
|
||||
}}
|
||||
size={SIZE.md + 2}
|
||||
size={AppFontSize.md + 2}
|
||||
>
|
||||
Upgrade now to continue using all the pro features after
|
||||
your trial ends
|
||||
@@ -143,11 +144,11 @@ export const Expiring = () => {
|
||||
await sleep(300);
|
||||
eSendEvent(eOpenPremiumDialog, promo);
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
textDecorationLine: "underline",
|
||||
color: colors.secondary.paragraph,
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
{"See what's included in Basic & Pro plans"}
|
||||
@@ -176,11 +177,11 @@ export const Expiring = () => {
|
||||
promo?.discount > 30 ? null : promo
|
||||
);
|
||||
}}
|
||||
fontSize={SIZE.md + 2}
|
||||
fontSize={AppFontSize.md + 2}
|
||||
style={{
|
||||
marginBottom: status.extend ? 0 : 10,
|
||||
marginTop: 10,
|
||||
paddingHorizontal: 24
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
paddingHorizontal: DefaultAppStyles.GAP * 2
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -201,10 +202,10 @@ export const Expiring = () => {
|
||||
button: "Continue"
|
||||
});
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xs}
|
||||
height={30}
|
||||
style={{
|
||||
marginBottom: 10
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -21,9 +21,10 @@ import React from "react";
|
||||
import { Text, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { defaultBorderRadius, AppFontSize } from "../../utils/size";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { ProTag } from "./pro-tag";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const FeatureBlock = ({
|
||||
vertical,
|
||||
@@ -40,11 +41,11 @@ export const FeatureBlock = ({
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
marginBottom: 10,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL,
|
||||
backgroundColor: colors.secondary.background,
|
||||
borderRadius: 10,
|
||||
paddingVertical: 12
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
@@ -53,7 +54,7 @@ export const FeatureBlock = ({
|
||||
marginLeft: 5,
|
||||
flexShrink: 1
|
||||
}}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
>
|
||||
{content}
|
||||
</Paragraph>
|
||||
@@ -63,14 +64,14 @@ export const FeatureBlock = ({
|
||||
style={{
|
||||
height: 100,
|
||||
justifyContent: "center",
|
||||
padding: 10,
|
||||
padding: DefaultAppStyles.GAP_SMALL,
|
||||
marginRight: 10,
|
||||
borderRadius: 5,
|
||||
borderRadius: defaultBorderRadius,
|
||||
minWidth: 100
|
||||
}}
|
||||
>
|
||||
<Icon color={colors.primary.icon} name={icon} size={SIZE.xl} />
|
||||
<Paragraph size={SIZE.md}>
|
||||
<Icon color={colors.primary.icon} name={icon} size={AppFontSize.xl} />
|
||||
<Paragraph size={AppFontSize.md}>
|
||||
<Text style={{ color: colors.primary.accent }}>{highlight}</Text>
|
||||
{content ? "\n" + content : null}
|
||||
</Paragraph>
|
||||
@@ -78,14 +79,14 @@ export const FeatureBlock = ({
|
||||
{pro ? (
|
||||
<>
|
||||
<View style={{ height: 5 }} />
|
||||
<ProTag width={50} size={SIZE.xs} background={proTagBg} />
|
||||
<ProTag width={50} size={AppFontSize.xs} background={proTagBg} />
|
||||
</>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
width: 30,
|
||||
height: 3,
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
borderRadius: 100,
|
||||
backgroundColor: colors.primary.accent
|
||||
}}
|
||||
|
||||
@@ -20,11 +20,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { ScrollView, View } from "react-native";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { FeatureBlock } from "./feature";
|
||||
import { ProTag } from "./pro-tag";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const Group = ({ item, index }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -32,24 +33,31 @@ export const Group = ({ item, index }) => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
backgroundColor: index % 2 !== 0 ? colors.primary.background : colors.secondary.background,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
backgroundColor:
|
||||
index % 2 !== 0
|
||||
? colors.primary.background
|
||||
: colors.secondary.background,
|
||||
paddingVertical: 40
|
||||
}}
|
||||
>
|
||||
{item?.pro ? (
|
||||
<ProTag
|
||||
size={SIZE.sm}
|
||||
background={index % 2 === 0 ? colors.primary.background : colors.secondary.background}
|
||||
size={AppFontSize.sm}
|
||||
background={
|
||||
index % 2 === 0
|
||||
? colors.primary.background
|
||||
: colors.secondary.background
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
<Heading>{item.title}</Heading>
|
||||
<Paragraph size={SIZE.md}>{item.detail}</Paragraph>
|
||||
<Paragraph size={AppFontSize.md}>{item.detail}</Paragraph>
|
||||
|
||||
{item.features && (
|
||||
<ScrollView
|
||||
style={{
|
||||
marginTop: 20
|
||||
marginTop: DefaultAppStyles.GAP
|
||||
}}
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
@@ -60,7 +68,11 @@ export const Group = ({ item, index }) => {
|
||||
{...item}
|
||||
detail={item.detail}
|
||||
pro={item.pro}
|
||||
proTagBg={index % 2 === 0 ? colors.primary.background : colors.secondary.background}
|
||||
proTagBg={
|
||||
index % 2 === 0
|
||||
? colors.primary.background
|
||||
: colors.secondary.background
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</ScrollView>
|
||||
@@ -68,9 +80,9 @@ export const Group = ({ item, index }) => {
|
||||
{item.info ? (
|
||||
<Paragraph
|
||||
style={{
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
{item.info}
|
||||
|
||||
@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { Text } from "react-native";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
|
||||
export const Offer = ({
|
||||
@@ -36,7 +36,7 @@ export const Offer = ({
|
||||
textAlign: "center",
|
||||
paddingVertical: padding
|
||||
}}
|
||||
size={SIZE.xxxl}
|
||||
size={AppFontSize.xxxl}
|
||||
>
|
||||
GET {off}
|
||||
<Text style={{ color: colors.primary.accent }}>%</Text> OFF!{"\n"}
|
||||
|
||||
@@ -35,11 +35,12 @@ import {
|
||||
eOpenPremiumDialog,
|
||||
eShowGetPremium
|
||||
} from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -95,7 +96,7 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
backgroundColor: colors.secondary.background,
|
||||
zIndex: 999,
|
||||
...getElevationStyle(20),
|
||||
padding: 12,
|
||||
padding: DefaultAppStyles.GAP,
|
||||
borderRadius: 10,
|
||||
flexDirection: "row",
|
||||
alignSelf: "center",
|
||||
@@ -120,7 +121,7 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
color={colors.primary.accent}
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
>
|
||||
{msg.title}
|
||||
</Heading>
|
||||
@@ -129,7 +130,7 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
color={colors.primary.paragraph}
|
||||
>
|
||||
{msg.desc}
|
||||
|
||||
@@ -19,11 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Platform, View } from "react-native";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import RNIap from "react-native-iap";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const PricingItem = ({
|
||||
product,
|
||||
@@ -49,7 +50,7 @@ export const PricingItem = ({
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingVertical: compact ? 15 : 10,
|
||||
width: compact ? null : "100%",
|
||||
minWidth: 150,
|
||||
@@ -59,13 +60,13 @@ export const PricingItem = ({
|
||||
>
|
||||
{!compact && (
|
||||
<View>
|
||||
<Heading size={SIZE.lg - 2}>
|
||||
<Heading size={AppFontSize.lg - 2}>
|
||||
{product?.type === "yearly" || product?.offerType === "yearly"
|
||||
? "Yearly"
|
||||
: "Monthly"}
|
||||
</Heading>
|
||||
{product?.info && (
|
||||
<Paragraph size={SIZE.xs}>{product.info}</Paragraph>
|
||||
<Paragraph size={AppFontSize.xs}>{product.info}</Paragraph>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
@@ -75,13 +76,13 @@ export const PricingItem = ({
|
||||
style={{
|
||||
textDecorationLine: strikethrough ? "line-through" : undefined
|
||||
}}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
>
|
||||
<Heading
|
||||
style={{
|
||||
textDecorationLine: strikethrough ? "line-through" : undefined
|
||||
}}
|
||||
size={SIZE.lg - 2}
|
||||
size={AppFontSize.lg - 2}
|
||||
>
|
||||
{Platform.OS === "android"
|
||||
? (product.data as RNIap.SubscriptionAndroid | undefined)
|
||||
|
||||
@@ -17,6 +17,8 @@ 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 { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { ActivityIndicator, Platform, Text, View } from "react-native";
|
||||
import * as RNIap from "react-native-iap";
|
||||
@@ -27,18 +29,19 @@ import {
|
||||
presentSheet,
|
||||
ToastManager
|
||||
} from "../../services/event-manager";
|
||||
import Navigation from "../../services/navigation";
|
||||
import PremiumService from "../../services/premium";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import {
|
||||
eClosePremiumDialog,
|
||||
eCloseSheet,
|
||||
eCloseSimpleDialog,
|
||||
eOpenLoginDialog
|
||||
eCloseSimpleDialog
|
||||
} from "../../utils/events";
|
||||
import { openLinkInBrowser } from "../../utils/functions";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { AuthMode } from "../auth/common";
|
||||
import { Dialog } from "../dialog";
|
||||
import BaseDialog from "../dialog/base-dialog";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
@@ -47,8 +50,7 @@ import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { Walkthrough } from "../walkthroughs";
|
||||
import { PricingItem } from "./pricing-item";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const UUID_PREFIX = "0bdaea";
|
||||
const UUID_VERSION = "4";
|
||||
@@ -264,7 +266,7 @@ export const PricingPlans = ({
|
||||
return loading ? (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 100
|
||||
@@ -275,7 +277,7 @@ export const PricingPlans = ({
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{buying ? (
|
||||
@@ -290,7 +292,7 @@ export const PricingPlans = ({
|
||||
style={{
|
||||
alignSelf: "center"
|
||||
}}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
>
|
||||
{(Platform.OS === "android"
|
||||
? (monthlyPlan?.product as RNIap.SubscriptionAndroid | undefined)
|
||||
@@ -309,9 +311,9 @@ export const PricingPlans = ({
|
||||
type="accent"
|
||||
width={250}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
marginBottom: 15,
|
||||
marginTop: 15,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginBottom: DefaultAppStyles.GAP,
|
||||
marginTop: DefaultAppStyles.GAP,
|
||||
borderRadius: 100
|
||||
}}
|
||||
/>
|
||||
@@ -332,7 +334,7 @@ export const PricingPlans = ({
|
||||
type="secondaryAccented"
|
||||
width={250}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginBottom: 15
|
||||
}}
|
||||
/>
|
||||
@@ -373,7 +375,7 @@ export const PricingPlans = ({
|
||||
<Heading
|
||||
style={{
|
||||
paddingTop: 15,
|
||||
fontSize: SIZE.lg
|
||||
fontSize: AppFontSize.lg
|
||||
}}
|
||||
>
|
||||
Special offer for you
|
||||
@@ -390,7 +392,7 @@ export const PricingPlans = ({
|
||||
alignSelf: "center",
|
||||
textAlign: "center"
|
||||
}}
|
||||
size={SIZE.xxl}
|
||||
size={AppFontSize.xxl}
|
||||
>
|
||||
{Platform.OS === "android"
|
||||
? (product.data as RNIap.SubscriptionAndroid)
|
||||
@@ -411,7 +413,7 @@ export const PricingPlans = ({
|
||||
alignSelf: "center",
|
||||
textAlign: "center"
|
||||
}}
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
>
|
||||
then {getStandardPrice()} {product?.offerType}.
|
||||
</Paragraph>
|
||||
@@ -503,7 +505,7 @@ export const PricingPlans = ({
|
||||
<Button
|
||||
height={35}
|
||||
style={{
|
||||
marginTop: 10
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
onPress={() => {
|
||||
presentDialog({
|
||||
@@ -557,24 +559,24 @@ export const PricingPlans = ({
|
||||
onPress={() => {
|
||||
eSendEvent(eClosePremiumDialog);
|
||||
eSendEvent(eCloseSheet);
|
||||
setTimeout(() => {
|
||||
eSendEvent(eOpenLoginDialog, 1);
|
||||
}, 400);
|
||||
Navigation.navigate("Auth", {
|
||||
mode: AuthMode.login
|
||||
});
|
||||
}}
|
||||
title={"Sign up for free"}
|
||||
type="accent"
|
||||
width={250}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginTop: product?.type === "promo" ? 0 : 30,
|
||||
marginBottom: 10
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
/>
|
||||
{Platform.OS !== "ios" &&
|
||||
promo &&
|
||||
!promo.promoCode.startsWith("com.streetwriters.notesnook") ? (
|
||||
<Paragraph
|
||||
size={SIZE.md}
|
||||
size={AppFontSize.md}
|
||||
textBreakStrategy="balanced"
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
@@ -612,7 +614,7 @@ export const PricingPlans = ({
|
||||
setProduct(undefined);
|
||||
}}
|
||||
style={{
|
||||
marginTop: 5
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
height={30}
|
||||
fontSize={13}
|
||||
@@ -629,18 +631,18 @@ export const PricingPlans = ({
|
||||
{!user || !upgrade ? (
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
textAlign: "center",
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
maxWidth: "80%"
|
||||
}}
|
||||
>
|
||||
{user
|
||||
? 'On clicking "Try free for 14 days", your free trial will be activated.'
|
||||
: "After sign up you will be asked to activate your free trial."}{" "}
|
||||
<Paragraph size={SIZE.xs} style={{ fontWeight: "bold" }}>
|
||||
<Paragraph size={AppFontSize.xs} style={{ fontWeight: "bold" }}>
|
||||
No credit card is required.
|
||||
</Paragraph>
|
||||
</Paragraph>
|
||||
@@ -651,11 +653,11 @@ export const PricingPlans = ({
|
||||
{Platform.OS === "ios" ? (
|
||||
<Paragraph
|
||||
textBreakStrategy="balanced"
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
textAlign: "center"
|
||||
}}
|
||||
>
|
||||
@@ -665,11 +667,11 @@ export const PricingPlans = ({
|
||||
</Paragraph>
|
||||
) : (
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
textAlign: "center"
|
||||
}}
|
||||
>
|
||||
@@ -685,7 +687,7 @@ export const PricingPlans = ({
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
@@ -694,7 +696,7 @@ export const PricingPlans = ({
|
||||
>
|
||||
By subscribing, you agree to our{" "}
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
onPress={() => {
|
||||
openLinkInBrowser("https://notesnook.com/tos")
|
||||
.catch(() => {})
|
||||
@@ -709,7 +711,7 @@ export const PricingPlans = ({
|
||||
</Paragraph>
|
||||
and{" "}
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
onPress={() => {
|
||||
openLinkInBrowser("https://notesnook.com/privacy")
|
||||
.catch(() => {})
|
||||
|
||||
@@ -22,6 +22,7 @@ import { View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -39,7 +40,7 @@ export const ProTag = ({ width, size, background }) => {
|
||||
width: width || 60,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingVertical: 2.5,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -31,12 +31,13 @@ import { useMenuStore } from "../../stores/use-menu-store";
|
||||
import { useRelationStore } from "../../stores/use-relation-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { refreshNotesPage } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import ColorPicker from "../dialogs/color-picker";
|
||||
import { Button } from "../ui/button";
|
||||
import NativeTooltip from "../../utils/tooltip";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const ColorItem = ({ item, note }: { item: Color; note: Note }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -85,7 +86,12 @@ const ColorItem = ({ item, note }: { item: Color; note: Note }) => {
|
||||
}}
|
||||
>
|
||||
{isLinked ? (
|
||||
<Icon testID="icon-check" name="check" color="white" size={SIZE.lg} />
|
||||
<Icon
|
||||
testID="icon-check"
|
||||
name="check"
|
||||
color="white"
|
||||
size={AppFontSize.lg}
|
||||
/>
|
||||
) : null}
|
||||
</Pressable>
|
||||
);
|
||||
@@ -128,37 +134,37 @@ export const ColorTags = ({ item }: { item: Note }) => {
|
||||
flexShrink: 2
|
||||
}}
|
||||
>
|
||||
<FlashList
|
||||
data={colorNotes}
|
||||
estimatedItemSize={30}
|
||||
horizontal
|
||||
extraData={updater}
|
||||
bounces={false}
|
||||
renderItem={renderItem}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
ListFooterComponent={
|
||||
!colorNotes || !colorNotes.length ? (
|
||||
<Button
|
||||
onPress={async () => {
|
||||
useSettingStore.getState().setSheetKeyboardHandler(false);
|
||||
setVisible(true);
|
||||
}}
|
||||
buttonType={{
|
||||
text: colors.primary.accent
|
||||
}}
|
||||
title={strings.addColor()}
|
||||
type="secondary"
|
||||
icon="plus"
|
||||
iconPosition="right"
|
||||
height={30}
|
||||
fontSize={SIZE.xs}
|
||||
style={{
|
||||
marginRight: 5,
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 8
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
{!colorNotes || !colorNotes.length ? (
|
||||
<Button
|
||||
onPress={async () => {
|
||||
useSettingStore.getState().setSheetKeyboardHandler(false);
|
||||
setVisible(true);
|
||||
}}
|
||||
buttonType={{
|
||||
text: colors.primary.accent
|
||||
}}
|
||||
title={strings.addColor()}
|
||||
type="secondary"
|
||||
icon="plus"
|
||||
iconPosition="right"
|
||||
height={30}
|
||||
fontSize={AppFontSize.xs}
|
||||
style={{
|
||||
marginRight: 5,
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<FlashList
|
||||
data={colorNotes}
|
||||
estimatedItemSize={30}
|
||||
horizontal
|
||||
extraData={updater}
|
||||
bounces={false}
|
||||
renderItem={renderItem}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
ListFooterComponent={
|
||||
<Pressable
|
||||
style={{
|
||||
width: 35,
|
||||
@@ -178,12 +184,12 @@ export const ColorTags = ({ item }: { item: Note }) => {
|
||||
testID="icon-plus"
|
||||
name="plus"
|
||||
color={colors.primary.icon}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
/>
|
||||
</Pressable>
|
||||
)
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -20,10 +20,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { getFormattedDate } from "@notesnook/common";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
export const DateMeta = ({ item }) => {
|
||||
const { colors } = useThemeColors();
|
||||
|
||||
@@ -44,13 +45,13 @@ export const DateMeta = ({ item }) => {
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
paddingVertical: 3
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2
|
||||
}}
|
||||
>
|
||||
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
|
||||
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
|
||||
{strings.dateDescFromKey(key)}
|
||||
</Paragraph>
|
||||
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
|
||||
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
|
||||
{getFormattedDate(item[key], "date-time")}
|
||||
</Paragraph>
|
||||
</View>
|
||||
@@ -59,11 +60,10 @@ export const DateMeta = ({ item }) => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingVertical: 5,
|
||||
marginTop: 5,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.primary.border,
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingTop: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
>
|
||||
{getDateMeta().map(renderItem)}
|
||||
|
||||
@@ -16,18 +16,19 @@ GNU General Public License for more details.
|
||||
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 { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { Platform, View } from "react-native";
|
||||
import { View } from "react-native";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
import { db } from "../../common/database";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { eSendEvent, presentSheet } from "../../services/event-manager";
|
||||
import { ColorValues } from "../../utils/colors";
|
||||
import { eOnLoadNote } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { fluidTabsRef } from "../../utils/global-refs";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import SheetProvider from "../sheet-provider";
|
||||
import { useSideBarDraggingStore } from "../side-menu/dragging-store";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import { ReminderTime } from "../ui/reminder-time";
|
||||
@@ -36,10 +37,9 @@ import Paragraph from "../ui/typography/paragraph";
|
||||
import { DateMeta } from "./date-meta";
|
||||
import { Items } from "./items";
|
||||
import Notebooks from "./notebooks";
|
||||
import { Synced } from "./synced";
|
||||
import { TagStrip, Tags } from "./tags";
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
const Line = ({ top = 6, bottom = 6 }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -82,13 +82,14 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
data={[0]}
|
||||
keyExtractor={() => "properties-scroll-item"}
|
||||
renderItem={() => (
|
||||
<View>
|
||||
<View
|
||||
style={{
|
||||
gap: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
marginTop: 5,
|
||||
zIndex: 10,
|
||||
marginBottom: 5
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@@ -101,7 +102,8 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexShrink: 1
|
||||
flexShrink: 1,
|
||||
gap: 5
|
||||
}}
|
||||
>
|
||||
{item.type === "color" ? (
|
||||
@@ -116,16 +118,15 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
marginRight: 10
|
||||
}}
|
||||
/>
|
||||
) : item.type === "tag" ? (
|
||||
<Icon
|
||||
name="pound"
|
||||
size={AppFontSize.lg}
|
||||
color={colors.primary.icon}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<Heading size={SIZE.lg}>
|
||||
{item.type === "tag" && !isColor ? (
|
||||
<Heading size={SIZE.xl} color={colors.primary.accent}>
|
||||
#
|
||||
</Heading>
|
||||
) : null}
|
||||
{item.title}
|
||||
</Heading>
|
||||
<Heading size={AppFontSize.lg}>{item.title}</Heading>
|
||||
</View>
|
||||
|
||||
{item.type === "note" ? (
|
||||
@@ -133,7 +134,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
name="open-in-new"
|
||||
type="plain"
|
||||
color={colors.primary.icon}
|
||||
size={SIZE.lg}
|
||||
size={AppFontSize.lg}
|
||||
style={{
|
||||
alignSelf: "flex-start"
|
||||
}}
|
||||
@@ -144,7 +145,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
newTab: true
|
||||
});
|
||||
if (!DDS.isTab) {
|
||||
tabBarRef.current?.goToPage(1);
|
||||
fluidTabsRef.current?.goToPage("editor");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -165,35 +166,28 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
borderWidth: 0,
|
||||
height: 30,
|
||||
alignSelf: "flex-start",
|
||||
backgroundColor: "transparent",
|
||||
paddingHorizontal: 0
|
||||
paddingHorizontal: 0,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xs}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
<DateMeta item={item} />
|
||||
<Line bottom={0} />
|
||||
<Line bottom={0} top={0} />
|
||||
|
||||
{item.type === "note" ? (
|
||||
<>
|
||||
<Tags close={close} item={item} />
|
||||
<Line bottom={0} />
|
||||
<Line bottom={0} top={0} />
|
||||
</>
|
||||
) : null}
|
||||
{item.type === "note" ? (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
<Notebooks note={item} close={close} />
|
||||
</View>
|
||||
<Notebooks note={item} close={close} />
|
||||
) : null}
|
||||
|
||||
<Items
|
||||
item={item}
|
||||
buttons={buttons}
|
||||
@@ -202,8 +196,6 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
}}
|
||||
/>
|
||||
|
||||
<Synced item={item} close={close} />
|
||||
|
||||
{DDS.isTab ? (
|
||||
<View
|
||||
style={{
|
||||
@@ -218,86 +210,40 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
);
|
||||
};
|
||||
|
||||
Properties.present = async (item, buttons = [], isSheet) => {
|
||||
Properties.present = async (item, isSheet, buttons = []) => {
|
||||
if (!item) return;
|
||||
let type = item?.type;
|
||||
let props = [];
|
||||
let android = [];
|
||||
let dbItem;
|
||||
switch (type) {
|
||||
case "trash":
|
||||
props[0] = item;
|
||||
props.push(["delete", "restore"]);
|
||||
dbItem = item;
|
||||
break;
|
||||
case "note":
|
||||
android = Platform.OS === "android" ? ["pin-to-notifications"] : [];
|
||||
props[0] = await db.notes.note(item.id);
|
||||
props.push([
|
||||
"notebooks",
|
||||
"add-reminder",
|
||||
"share",
|
||||
"export",
|
||||
"copy",
|
||||
"publish",
|
||||
"pin",
|
||||
"favorite",
|
||||
"attachments",
|
||||
"lock-unlock",
|
||||
"trash",
|
||||
"remove-from-notebook",
|
||||
"history",
|
||||
"read-only",
|
||||
"reminders",
|
||||
"local-only",
|
||||
"duplicate",
|
||||
"copy-link",
|
||||
"references",
|
||||
...android,
|
||||
...buttons
|
||||
]);
|
||||
dbItem = await db.notes.note(item.id);
|
||||
break;
|
||||
case "notebook":
|
||||
props[0] = await db.notebooks.notebook(item.id);
|
||||
props.push([
|
||||
"edit-notebook",
|
||||
"pin",
|
||||
"add-shortcut",
|
||||
"trash",
|
||||
"default-notebook",
|
||||
"add-notebook",
|
||||
"move-notes",
|
||||
"move-notebook"
|
||||
]);
|
||||
dbItem = await db.notebooks.notebook(item.id);
|
||||
break;
|
||||
case "tag":
|
||||
props[0] = await db.tags.tag(item.id);
|
||||
props.push(["add-shortcut", "trash", "rename-tag"]);
|
||||
dbItem = await db.tags.tag(item.id);
|
||||
break;
|
||||
case "color":
|
||||
props[0] = await db.colors.color(item.id);
|
||||
|
||||
props.push([
|
||||
"trash",
|
||||
"rename-color",
|
||||
...(useSideBarDraggingStore.getState().dragging ? [] : ["reorder"])
|
||||
]);
|
||||
dbItem = await db.colors.color(item.id);
|
||||
break;
|
||||
case "reminder": {
|
||||
props[0] = await db.reminders.reminder(item.id);
|
||||
props.push(["edit-reminder", "trash", "disable-reminder"]);
|
||||
dbItem = await db.reminders.reminder(item.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!props[0]) return;
|
||||
|
||||
presentSheet({
|
||||
context: isSheet ? "local" : undefined,
|
||||
component: (ref, close) => (
|
||||
<Properties
|
||||
close={() => {
|
||||
close();
|
||||
}}
|
||||
close={close}
|
||||
actionSheetRef={ref}
|
||||
item={props[0]}
|
||||
buttons={props[1]}
|
||||
item={dbItem}
|
||||
buttons={buttons}
|
||||
/>
|
||||
)
|
||||
});
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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 { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { Dimensions, ScrollView, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { useActions } from "../../hooks/use-actions";
|
||||
import { useStoredRef } from "../../hooks/use-stored-ref";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
|
||||
export const Items = ({ item, buttons, close }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const topBarSorting = useStoredRef("topbar-sorting-ref", {});
|
||||
|
||||
const dimensions = useSettingStore((state) => state.dimensions);
|
||||
const actions = useActions({ item, close });
|
||||
const data = actions.filter((i) => buttons.indexOf(i.id) > -1 && !i.hidden);
|
||||
let width = dimensions.width > 600 ? 600 : dimensions.width;
|
||||
const shouldShrink =
|
||||
Dimensions.get("window").fontScale > 1 &&
|
||||
Dimensions.get("window").width < 450;
|
||||
let columnItemsCount = DDS.isLargeTablet() ? 7 : shouldShrink ? 4 : 5;
|
||||
let columnItemWidth = DDS.isTab
|
||||
? (width - 12) / columnItemsCount
|
||||
: (width - 12) / columnItemsCount;
|
||||
|
||||
const _renderRowItem = ({ item }) => (
|
||||
<View
|
||||
key={item.id}
|
||||
testID={"icon-" + item.id}
|
||||
style={{
|
||||
alignItems: "center",
|
||||
width: columnItemWidth,
|
||||
marginBottom: 10
|
||||
}}
|
||||
>
|
||||
<Pressable
|
||||
onPress={item.func}
|
||||
type={item.on ? "shade" : "secondary"}
|
||||
style={{
|
||||
height: columnItemWidth - 12,
|
||||
width: columnItemWidth - 12,
|
||||
borderRadius: 10,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
textAlignVertical: "center",
|
||||
marginBottom: DDS.isTab ? 7 : 3.5
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
allowFontScaling
|
||||
name={item.icon}
|
||||
size={DDS.isTab ? SIZE.xxl : shouldShrink ? SIZE.xxl : SIZE.lg}
|
||||
color={
|
||||
item.on
|
||||
? colors.primary.accent
|
||||
: item.id.match(/(delete|trash)/g)
|
||||
? colors.error.icon
|
||||
: colors.secondary.icon
|
||||
}
|
||||
/>
|
||||
</Pressable>
|
||||
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
textBreakStrategy="simple"
|
||||
style={{ textAlign: "center" }}
|
||||
>
|
||||
{item.title}
|
||||
</Paragraph>
|
||||
</View>
|
||||
);
|
||||
|
||||
const renderColumnItem = (item) => (
|
||||
<Button
|
||||
key={item.name + item.title}
|
||||
buttonType={{
|
||||
text: item.on
|
||||
? colors.primary.accent
|
||||
: item.name === "Delete" || item.name === "PermDelete"
|
||||
? colors.error.paragraph
|
||||
: colors.primary.paragraph
|
||||
}}
|
||||
onPress={item.func}
|
||||
title={item.title}
|
||||
icon={item.icon}
|
||||
type={item.on ? "shade" : "plain"}
|
||||
fontSize={SIZE.sm}
|
||||
style={{
|
||||
borderRadius: 0,
|
||||
justifyContent: "flex-start",
|
||||
alignSelf: "flex-start",
|
||||
width: "100%"
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderTopBarItem = (item, index) => {
|
||||
return (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
item.func();
|
||||
setImmediate(() => {
|
||||
const currentValue = topBarSorting.current[item.id] || 0;
|
||||
topBarSorting.current = {
|
||||
...topBarSorting.current,
|
||||
[item.id]: currentValue + 1
|
||||
};
|
||||
});
|
||||
}}
|
||||
key={item.id}
|
||||
testID={"icon-" + item.id}
|
||||
activeOpacity={1}
|
||||
style={{
|
||||
alignSelf: "flex-start",
|
||||
paddingHorizontal: 0,
|
||||
flex: 1
|
||||
}}
|
||||
>
|
||||
<View
|
||||
onPress={item.func}
|
||||
style={{
|
||||
height: topBarItemWidth,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
textAlignVertical: "center",
|
||||
marginBottom: DDS.isTab ? 7 : 3.5,
|
||||
borderRadius: 100
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name={item.icon}
|
||||
allowFontScaling
|
||||
size={DDS.isTab ? SIZE.xxl : SIZE.md + 4}
|
||||
color={
|
||||
item.on
|
||||
? colors.primary.accent
|
||||
: item.name === "Delete" || item.name === "PermDelete"
|
||||
? colors.error.icon
|
||||
: colors.secondary.icon
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Paragraph
|
||||
textBreakStrategy="simple"
|
||||
size={SIZE.xxs}
|
||||
style={{ textAlign: "center" }}
|
||||
>
|
||||
{item.title}
|
||||
</Paragraph>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
const topBarItemsList = [
|
||||
"pin",
|
||||
"favorite",
|
||||
"copy",
|
||||
"share",
|
||||
"lock-unlock",
|
||||
"publish",
|
||||
"export",
|
||||
"copy-link",
|
||||
"duplicate",
|
||||
"local-only",
|
||||
"read-only"
|
||||
];
|
||||
|
||||
const bottomBarItemsList = [
|
||||
"notebooks",
|
||||
"add-reminder",
|
||||
"pin-to-notifications",
|
||||
"history",
|
||||
"reminders",
|
||||
"attachments",
|
||||
"references",
|
||||
"trash"
|
||||
];
|
||||
|
||||
const topBarItems = data
|
||||
.filter((item) => topBarItemsList.indexOf(item.id) > -1)
|
||||
.sort((a, b) =>
|
||||
topBarItemsList.indexOf(a.id) > topBarItemsList.indexOf(b.id) ? 1 : -1
|
||||
)
|
||||
.sort((a, b) => {
|
||||
return (
|
||||
(topBarSorting.current[b.id] || 0) - (topBarSorting.current[a.id] || 0)
|
||||
);
|
||||
});
|
||||
|
||||
const bottomGridItems = data
|
||||
.filter((item) => bottomBarItemsList.indexOf(item.id) > -1)
|
||||
.sort((a, b) =>
|
||||
bottomBarItemsList.indexOf(a.id) > bottomBarItemsList.indexOf(b.id)
|
||||
? 1
|
||||
: -1
|
||||
);
|
||||
|
||||
let topBarItemWidth =
|
||||
(width - (topBarItems.length * 10 + 14)) / topBarItems.length;
|
||||
topBarItemWidth;
|
||||
|
||||
if (topBarItemWidth < 60) {
|
||||
topBarItemWidth = 60;
|
||||
}
|
||||
|
||||
return item.type === "note" ? (
|
||||
<>
|
||||
<ScrollView
|
||||
horizontal
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
marginTop: 6,
|
||||
marginBottom: 6
|
||||
}}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={{
|
||||
paddingRight: 25,
|
||||
gap: 15
|
||||
}}
|
||||
>
|
||||
{topBarItems.map(renderTopBarItem)}
|
||||
</ScrollView>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
alignContent: "flex-start",
|
||||
marginTop: item.type !== "note" ? 10 : 0,
|
||||
paddingTop: 10,
|
||||
marginLeft: 6
|
||||
}}
|
||||
>
|
||||
{bottomGridItems.map((item) => _renderRowItem({ item }))}
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<View data={data}>{data.map(renderColumnItem)}</View>
|
||||
);
|
||||
};
|
||||
360
apps/mobile/app/components/properties/items.tsx
Normal file
360
apps/mobile/app/components/properties/items.tsx
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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 { Item } from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { Dimensions, View } from "react-native";
|
||||
import SwiperFlatList from "react-native-swiper-flatlist";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { Action, ActionId, useActions } from "../../hooks/use-actions";
|
||||
import { useStoredRef } from "../../hooks/use-stored-ref";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { Button } from "../ui/button";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
|
||||
const TOP_BAR_ITEMS: ActionId[] = [
|
||||
"pin",
|
||||
"favorite",
|
||||
"lock-unlock",
|
||||
"publish",
|
||||
"local-only",
|
||||
"read-only",
|
||||
"pin-to-notifications"
|
||||
];
|
||||
|
||||
const BOTTOM_BAR_ITEMS: ActionId[] = [
|
||||
"notebooks",
|
||||
"add-reminder",
|
||||
"history",
|
||||
"reminders",
|
||||
"attachments",
|
||||
"references",
|
||||
"copy",
|
||||
"share",
|
||||
"export",
|
||||
"copy-link",
|
||||
"duplicate",
|
||||
"trash"
|
||||
];
|
||||
|
||||
const COLUMN_BAR_ITEMS: ActionId[] = [
|
||||
"select",
|
||||
"add-notebook",
|
||||
"edit-notebook",
|
||||
"move-notes",
|
||||
"move-notebook",
|
||||
"pin",
|
||||
"default-notebook",
|
||||
"default-homepage",
|
||||
"add-shortcut",
|
||||
"reorder",
|
||||
"rename-color",
|
||||
"rename-tag",
|
||||
"restore",
|
||||
"trash",
|
||||
"delete"
|
||||
];
|
||||
|
||||
export const Items = ({
|
||||
item,
|
||||
close,
|
||||
buttons
|
||||
}: {
|
||||
item: Item;
|
||||
close: () => void;
|
||||
buttons: Action[];
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const topBarSorting = useStoredRef<{ [name: string]: number }>(
|
||||
"topbar-sorting-ref",
|
||||
{}
|
||||
);
|
||||
const dimensions = useSettingStore((state) => state.dimensions);
|
||||
const actions = useActions({ item, close });
|
||||
const selectedActions = actions.filter((i) => !i.hidden);
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const width = Math.min(dimensions.width, 600);
|
||||
|
||||
const shouldShrink =
|
||||
Dimensions.get("window").fontScale > 1 &&
|
||||
Dimensions.get("window").width < 450;
|
||||
|
||||
const columnItemsCount = deviceMode === "tablet" ? 7 : shouldShrink ? 4 : 5;
|
||||
|
||||
const columnItemWidth =
|
||||
deviceMode !== "mobile"
|
||||
? (width - DefaultAppStyles.GAP) / columnItemsCount
|
||||
: (width - DefaultAppStyles.GAP) / columnItemsCount;
|
||||
|
||||
const topBarItems = selectedActions
|
||||
.filter((item) => TOP_BAR_ITEMS.indexOf(item.id) > -1)
|
||||
.sort((a, b) =>
|
||||
TOP_BAR_ITEMS.indexOf(a.id) > TOP_BAR_ITEMS.indexOf(b.id) ? 1 : -1
|
||||
)
|
||||
.sort((a, b) => {
|
||||
return (
|
||||
(topBarSorting.current[b.id] || 0) - (topBarSorting.current[a.id] || 0)
|
||||
);
|
||||
});
|
||||
|
||||
const bottomGridItems = selectedActions
|
||||
.filter((item) => BOTTOM_BAR_ITEMS.indexOf(item.id) > -1)
|
||||
.sort((a, b) =>
|
||||
BOTTOM_BAR_ITEMS.indexOf(a.id) > BOTTOM_BAR_ITEMS.indexOf(b.id) ? 1 : -1
|
||||
);
|
||||
|
||||
const columnItems = selectedActions
|
||||
.filter((item) => COLUMN_BAR_ITEMS.indexOf(item.id) > -1)
|
||||
.sort((a, b) =>
|
||||
COLUMN_BAR_ITEMS.indexOf(a.id) > COLUMN_BAR_ITEMS.indexOf(b.id) ? 1 : -1
|
||||
);
|
||||
|
||||
const topBarItemHeight = Math.min(
|
||||
(width - (topBarItems.length * 10 + 14)) / topBarItems.length,
|
||||
60
|
||||
);
|
||||
|
||||
const renderRowItem = React.useCallback(
|
||||
({ item }: { item: Action }) => (
|
||||
<View
|
||||
key={item.id}
|
||||
style={{
|
||||
alignItems: "center",
|
||||
width: columnItemWidth - 8
|
||||
}}
|
||||
>
|
||||
<Pressable
|
||||
onPress={item.onPress}
|
||||
type={item.checked ? "shade" : "secondary"}
|
||||
testID={"icon-" + item.id}
|
||||
style={{
|
||||
height: columnItemWidth / 1.5,
|
||||
width: columnItemWidth - 8,
|
||||
borderRadius: 10,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: DDS.isTab ? 7 : 3.5
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
allowFontScaling
|
||||
name={item.icon}
|
||||
size={
|
||||
DDS.isTab
|
||||
? AppFontSize.xxl
|
||||
: shouldShrink
|
||||
? AppFontSize.xxl
|
||||
: AppFontSize.lg
|
||||
}
|
||||
color={
|
||||
item.checked
|
||||
? item.activeColor || colors.primary.accent
|
||||
: item.id.match(/(delete|trash)/g)
|
||||
? colors.error.icon
|
||||
: colors.secondary.icon
|
||||
}
|
||||
/>
|
||||
</Pressable>
|
||||
|
||||
<Paragraph
|
||||
size={AppFontSize.xxs}
|
||||
textBreakStrategy="simple"
|
||||
style={{ textAlign: "center" }}
|
||||
>
|
||||
{item.title}
|
||||
</Paragraph>
|
||||
</View>
|
||||
),
|
||||
[
|
||||
colors.error.icon,
|
||||
colors.primary.accent,
|
||||
colors.secondary.icon,
|
||||
columnItemWidth,
|
||||
shouldShrink
|
||||
]
|
||||
);
|
||||
|
||||
const renderColumnItem = React.useCallback(
|
||||
(item: Action) => (
|
||||
<Button
|
||||
key={item.id}
|
||||
buttonType={{
|
||||
text: item.checked
|
||||
? item.activeColor || colors.primary.accent
|
||||
: item.id === "delete" || item.id === "trash"
|
||||
? colors.error.paragraph
|
||||
: colors.primary.paragraph
|
||||
}}
|
||||
testID={"icon-" + item.id}
|
||||
onPress={item.onPress}
|
||||
title={item.title}
|
||||
icon={item.icon}
|
||||
type={item.checked ? "inverted" : "plain"}
|
||||
fontSize={AppFontSize.sm}
|
||||
style={{
|
||||
borderRadius: 0,
|
||||
justifyContent: "flex-start",
|
||||
alignSelf: "flex-start",
|
||||
width: "100%"
|
||||
}}
|
||||
/>
|
||||
),
|
||||
[colors.error.paragraph, colors.primary.accent, colors.primary.paragraph]
|
||||
);
|
||||
|
||||
const renderTopBarItem = React.useCallback(
|
||||
(item: Action) => {
|
||||
return (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
item.onPress();
|
||||
setImmediate(() => {
|
||||
const currentValue = topBarSorting.current[item.id] || 0;
|
||||
topBarSorting.current = {
|
||||
...topBarSorting.current,
|
||||
[item.id]: currentValue + 1
|
||||
};
|
||||
});
|
||||
}}
|
||||
key={item.id}
|
||||
testID={"icon-" + item.id}
|
||||
style={{
|
||||
width: columnItemWidth - 8
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
height: columnItemWidth / 2,
|
||||
width: columnItemWidth - DefaultAppStyles.GAP_SMALL,
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name={item.icon}
|
||||
allowFontScaling
|
||||
size={DDS.isTab ? AppFontSize.xxl : AppFontSize.md + 4}
|
||||
color={
|
||||
item.checked
|
||||
? item.activeColor || colors.primary.accent
|
||||
: item.id === "delete" || item.id === "trash"
|
||||
? colors.error.icon
|
||||
: colors.secondary.icon
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Paragraph
|
||||
textBreakStrategy="simple"
|
||||
size={AppFontSize.xxs}
|
||||
style={{ textAlign: "center" }}
|
||||
>
|
||||
{item.title}
|
||||
</Paragraph>
|
||||
</Pressable>
|
||||
);
|
||||
},
|
||||
[
|
||||
colors.error.icon,
|
||||
colors.primary.accent,
|
||||
colors.secondary.icon,
|
||||
columnItemWidth,
|
||||
topBarSorting
|
||||
]
|
||||
);
|
||||
|
||||
const getTopBarItemChunksOfFour = () => {
|
||||
const chunks = [];
|
||||
for (let i = 0; i < topBarItems.length; i += 5) {
|
||||
chunks.push(topBarItems.slice(i, i + 5));
|
||||
}
|
||||
return chunks;
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
gap: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{item.type === "note" ? (
|
||||
<>
|
||||
<View>
|
||||
<SwiperFlatList
|
||||
data={getTopBarItemChunksOfFour()}
|
||||
autoplay={false}
|
||||
showPagination
|
||||
paginationStyleItemActive={{
|
||||
borderRadius: 2,
|
||||
backgroundColor: colors.selected.background,
|
||||
height: 6,
|
||||
marginHorizontal: 2
|
||||
}}
|
||||
paginationStyleItemInactive={{
|
||||
borderRadius: 2,
|
||||
backgroundColor: colors.secondary.background,
|
||||
height: 6,
|
||||
marginHorizontal: 2
|
||||
}}
|
||||
paginationStyle={{
|
||||
position: "relative",
|
||||
marginHorizontal: 2,
|
||||
marginBottom: 0,
|
||||
marginTop: DefaultAppStyles.GAP
|
||||
}}
|
||||
renderItem={({ item, index }) => (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
gap: 5,
|
||||
width: width
|
||||
}}
|
||||
>
|
||||
{item.map(renderTopBarItem)}
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
gap: 5,
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{bottomGridItems.map((item) => renderRowItem({ item }))}
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<View>
|
||||
{buttons.map(renderColumnItem)}
|
||||
{columnItems.map(renderColumnItem)}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -25,11 +25,12 @@ import { db } from "../../common/database";
|
||||
import NotebookScreen from "../../screens/notebook";
|
||||
import { eSendEvent, presentSheet } from "../../services/event-manager";
|
||||
import { eClearEditor } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export default function Notebooks({ note, close, full }) {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -59,12 +60,12 @@ export default function Notebooks({ note, close, full }) {
|
||||
type={full ? "transparent" : "secondary"}
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexShrink: 1,
|
||||
flexGrow: 1,
|
||||
padding: 6,
|
||||
padding: DefaultAppStyles.GAP_SMALL,
|
||||
borderRadius: 10,
|
||||
minHeight: 42
|
||||
}}
|
||||
@@ -72,7 +73,7 @@ export default function Notebooks({ note, close, full }) {
|
||||
<Icon
|
||||
name="book-outline"
|
||||
color={colors.primary.accent}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
marginRight: 5
|
||||
}}
|
||||
@@ -82,7 +83,7 @@ export default function Notebooks({ note, close, full }) {
|
||||
style={{
|
||||
maxWidth: "50%"
|
||||
}}
|
||||
size={SIZE.sm}
|
||||
size={AppFontSize.sm}
|
||||
>
|
||||
{item.title}
|
||||
</Heading>
|
||||
@@ -92,40 +93,46 @@ export default function Notebooks({ note, close, full }) {
|
||||
return noteNotebooks.length === 0 ? null : (
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
borderRadius: 10,
|
||||
marginTop: 6
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{full
|
||||
? noteNotebooks.map(renderItem)
|
||||
: noteNotebooks.slice(0, 1).map(renderItem)}
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
borderRadius: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
>
|
||||
{full
|
||||
? noteNotebooks.map(renderItem)
|
||||
: noteNotebooks.slice(0, 1).map(renderItem)}
|
||||
|
||||
{noteNotebooks.length > 1 && !full ? (
|
||||
<Button
|
||||
title={strings.viewAllLinkedNotebooks()}
|
||||
fontSize={SIZE.xs}
|
||||
style={{
|
||||
alignSelf: "flex-end",
|
||||
marginRight: 12,
|
||||
paddingHorizontal: 0,
|
||||
backgroundColor: "transparent"
|
||||
}}
|
||||
type="plain"
|
||||
textStyle={{
|
||||
textDecorationLine: "underline"
|
||||
}}
|
||||
height={20}
|
||||
onPress={() => {
|
||||
presentSheet({
|
||||
context: "properties",
|
||||
component: (ref, close) => (
|
||||
<Notebooks note={note} close={close} full={true} />
|
||||
)
|
||||
});
|
||||
}}
|
||||
/>
|
||||
) : undefined}
|
||||
{noteNotebooks.length > 1 && !full ? (
|
||||
<Button
|
||||
title={strings.viewAllLinkedNotebooks()}
|
||||
fontSize={AppFontSize.xs}
|
||||
style={{
|
||||
alignSelf: "flex-end",
|
||||
marginRight: 12,
|
||||
paddingHorizontal: 0,
|
||||
backgroundColor: "transparent"
|
||||
}}
|
||||
type="plain"
|
||||
textStyle={{
|
||||
textDecorationLine: "underline"
|
||||
}}
|
||||
height={20}
|
||||
onPress={() => {
|
||||
presentSheet({
|
||||
context: "properties",
|
||||
component: (ref, close) => (
|
||||
<Notebooks note={note} close={close} full={true} />
|
||||
)
|
||||
});
|
||||
}}
|
||||
/>
|
||||
) : undefined}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,92 +19,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { View, useWindowDimensions } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { openLinkInBrowser } from "../../utils/functions";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
export const Synced = ({ item, close }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const user = useUserStore((state) => state.user);
|
||||
const lastSynced = useUserStore((state) => state.lastSynced);
|
||||
|
||||
const dimensions = useWindowDimensions();
|
||||
const shouldShrink = dimensions.fontScale > 1 && dimensions.width < 450;
|
||||
return user && lastSynced >= item.dateModified ? (
|
||||
<View
|
||||
<Button
|
||||
style={{
|
||||
paddingVertical: 0,
|
||||
width: "100%",
|
||||
paddingHorizontal: 12,
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
alignSelf: "center",
|
||||
paddingTop: 10,
|
||||
marginTop: 10,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.primary.border
|
||||
alignSelf: "flex-start",
|
||||
height: "auto",
|
||||
padding: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="shield-key-outline"
|
||||
color={colors.primary.accent}
|
||||
size={shouldShrink ? SIZE.xxl : SIZE.xxxl}
|
||||
/>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
marginLeft: 5,
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
color={colors.primary.heading}
|
||||
size={SIZE.xs}
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
>
|
||||
{strings.noteSyncedNoticeHeading()}
|
||||
</Heading>
|
||||
{shouldShrink ? null : (
|
||||
<Paragraph
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
color={colors.primary.paragraph}
|
||||
>
|
||||
{strings.noteSyncedNoticeDesc(item.itemType || item.type)}
|
||||
</Paragraph>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<Button
|
||||
onPress={async () => {
|
||||
try {
|
||||
close();
|
||||
await sleep(300);
|
||||
await openLinkInBrowser(
|
||||
"https://help.notesnook.com/how-is-my-data-encrypted",
|
||||
colors
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}}
|
||||
title={strings.learnMore()}
|
||||
fontSize={SIZE.xs}
|
||||
height={30}
|
||||
type="secondaryAccented"
|
||||
/>
|
||||
</View>
|
||||
fontSize={AppFontSize.xxxs}
|
||||
iconSize={AppFontSize.xs}
|
||||
icon="shield-key-outline"
|
||||
type="shade"
|
||||
title="Encrypted and synced"
|
||||
onPress={async () => {
|
||||
try {
|
||||
close();
|
||||
await sleep(300);
|
||||
await openLinkInBrowser(
|
||||
"https://help.notesnook.com/how-is-my-data-encrypted",
|
||||
colors
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : null;
|
||||
};
|
||||
|
||||
@@ -22,12 +22,13 @@ import { View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import { TaggedNotes } from "../../screens/notes/tagged";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import ManageTagsSheet from "../sheets/manage-tags";
|
||||
import { Button } from "../ui/button";
|
||||
import { ColorTags } from "./color-tags";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
|
||||
export const Tags = ({ item, close }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -35,11 +36,10 @@ export const Tags = ({ item, close }) => {
|
||||
return item.id ? (
|
||||
<View
|
||||
style={{
|
||||
marginTop: 5,
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
alignSelf: "center",
|
||||
justifyContent: "space-between",
|
||||
width: "100%"
|
||||
@@ -56,11 +56,10 @@ export const Tags = ({ item, close }) => {
|
||||
type="secondary"
|
||||
icon="plus"
|
||||
iconPosition="right"
|
||||
height={30}
|
||||
fontSize={SIZE.sm - 1}
|
||||
fontSize={AppFontSize.xs}
|
||||
style={{
|
||||
height: 35,
|
||||
borderRadius: 100
|
||||
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
|
||||
}}
|
||||
/>
|
||||
<ColorTags item={item} />
|
||||
@@ -86,7 +85,7 @@ export const TagStrip = ({ item, close }) => {
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
alignItems: "center",
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
gap: 5
|
||||
}}
|
||||
>
|
||||
@@ -117,7 +116,7 @@ const TagItem = ({ tag, close }) => {
|
||||
title={"#" + tag.title}
|
||||
type="plain"
|
||||
height={20}
|
||||
fontSize={SIZE.xs}
|
||||
fontSize={AppFontSize.xs}
|
||||
style={style}
|
||||
textStyle={{
|
||||
color: colors.secondary.paragraph
|
||||
|
||||
@@ -29,24 +29,23 @@ import {
|
||||
} from "react-native";
|
||||
import { Menu } from "react-native-material-menu";
|
||||
import { db } from "../../common/database";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { ToastManager } from "../../services/event-manager";
|
||||
import Navigation from "../../services/navigation";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { useTrashStore } from "../../stores/use-trash-store";
|
||||
import { deleteItems } from "../../utils/functions";
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
import { fluidTabsRef } from "../../utils/global-refs";
|
||||
import { updateNotebook } from "../../utils/notebooks";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
import MoveNoteSheet from "../sheets/add-to";
|
||||
import ExportNotesSheet from "../sheets/export-notes";
|
||||
import ManageTagsSheet from "../sheets/manage-tags";
|
||||
import { MoveNotebookSheet } from "../sheets/move-notebook";
|
||||
import { Button } from "../ui/button";
|
||||
import { MoveNotebook } from "../../screens/move-notebook";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import NativeTooltip from "../../utils/tooltip";
|
||||
|
||||
export const SelectionHeader = React.memo(
|
||||
({
|
||||
@@ -61,23 +60,20 @@ export const SelectionHeader = React.memo(
|
||||
renderedInRoute?: string;
|
||||
}) => {
|
||||
const menuRef = useRef<Menu>(null);
|
||||
const { colors: contextMenuColors } = useThemeColors("contextMenu");
|
||||
const { colors } = useThemeColors();
|
||||
const selectionMode = useSelectionStore((state) => state.selectionMode);
|
||||
const selectedItemsList = useSelectionStore(
|
||||
(state) => state.selectedItemsList
|
||||
);
|
||||
const clearSelection = useSelectionStore((state) => state.clearSelection);
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const allSelected =
|
||||
items?.placeholders?.length === selectedItemsList.length;
|
||||
const focusedRouteId = useNavigationStore((state) => state.focusedRouteId);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectionMode) {
|
||||
tabBarRef.current?.lock();
|
||||
fluidTabsRef.current?.lock();
|
||||
} else {
|
||||
tabBarRef.current?.unlock();
|
||||
fluidTabsRef.current?.unlock();
|
||||
}
|
||||
}, [selectionMode]);
|
||||
|
||||
@@ -103,8 +99,11 @@ export const SelectionHeader = React.memo(
|
||||
const deleteItem = async () => {
|
||||
if (!type) return;
|
||||
presentDialog({
|
||||
title: strings.doActions.delete.unknown(type, selectedItemsList.length),
|
||||
paragraph: strings.actionConfirmations.delete.unknown(
|
||||
title: strings.doActions.permanentlyDelete.unknown(
|
||||
type,
|
||||
selectedItemsList.length
|
||||
),
|
||||
paragraph: strings.actionConfirmations.permanentlyDelete.unknown(
|
||||
type,
|
||||
selectedItemsList.length
|
||||
),
|
||||
@@ -113,7 +112,7 @@ export const SelectionHeader = React.memo(
|
||||
positivePress: async () => {
|
||||
if (!selectedItemsList.length) return;
|
||||
await db.trash.delete(...selectedItemsList);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useTrashStore.getState().refresh();
|
||||
clearSelection();
|
||||
},
|
||||
positiveType: "errorShade"
|
||||
@@ -139,61 +138,24 @@ export const SelectionHeader = React.memo(
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
height: Platform.OS === "android" ? 50 + insets.top : 50,
|
||||
paddingTop: Platform.OS === "android" ? insets.top : null,
|
||||
backgroundColor: colors.primary.background,
|
||||
justifyContent: "space-between",
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
zIndex: 999,
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
borderTopWidth: 1,
|
||||
borderColor: colors.primary.border,
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
borderRadius: 100
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 40,
|
||||
width: 40,
|
||||
borderRadius: 100,
|
||||
marginRight: 10
|
||||
}}
|
||||
onPress={() => {
|
||||
clearSelection();
|
||||
}}
|
||||
color={colors.primary.icon}
|
||||
name="close"
|
||||
/>
|
||||
|
||||
<View
|
||||
style={{
|
||||
height: 40,
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 16,
|
||||
justifyContent: "center",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Heading size={SIZE.lg} color={colors.primary.paragraph}>
|
||||
{selectedItemsList.length}
|
||||
</Heading>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center"
|
||||
gap: DefaultAppStyles.GAP_SMALL
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
@@ -202,159 +164,155 @@ export const SelectionHeader = React.memo(
|
||||
.getState()
|
||||
.setAll(allSelected ? [] : [...((await items?.ids()) || [])]);
|
||||
}}
|
||||
tooltipText="Select all"
|
||||
tooltipPosition={4}
|
||||
style={{
|
||||
marginLeft: 10
|
||||
}}
|
||||
color={
|
||||
allSelected ? colors.primary.accent : colors.primary.paragraph
|
||||
}
|
||||
size={AppFontSize.lg}
|
||||
color={allSelected ? colors.primary.accent : colors.primary.icon}
|
||||
name="select-all"
|
||||
/>
|
||||
|
||||
{selectedItemsList.length ? (
|
||||
<Menu
|
||||
ref={menuRef}
|
||||
animationDuration={200}
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
backgroundColor: contextMenuColors.primary.background,
|
||||
marginTop: 35
|
||||
}}
|
||||
onRequestClose={() => {
|
||||
//@ts-ignore
|
||||
menuRef.current?.hide();
|
||||
}}
|
||||
anchor={
|
||||
<IconButton
|
||||
onPress={() => {
|
||||
//@ts-ignore
|
||||
menuRef.current?.show();
|
||||
}}
|
||||
name="dots-vertical"
|
||||
color={colors.primary.paragraph}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{[
|
||||
{
|
||||
title: strings.move(),
|
||||
onPress: async () => {
|
||||
const ids = selectedItemsList;
|
||||
const notebooks = await db.notebooks.all.items(ids);
|
||||
MoveNotebookSheet.present(notebooks);
|
||||
},
|
||||
visible: renderedInRoute === "Notebooks",
|
||||
icon: "arrow-right-bold-box-outline"
|
||||
},
|
||||
{
|
||||
title: strings.manageTags(),
|
||||
onPress: async () => {
|
||||
await sleep(100);
|
||||
ManageTagsSheet.present(selectedItemsList);
|
||||
},
|
||||
visible: type === "note",
|
||||
icon: "pound"
|
||||
},
|
||||
{
|
||||
title: strings.export(),
|
||||
onPress: async () => {
|
||||
await sleep(100);
|
||||
ExportNotesSheet.present(selectedItemsList);
|
||||
},
|
||||
visible: type === "note",
|
||||
icon: "export"
|
||||
},
|
||||
{
|
||||
title: strings.linkNotebook(),
|
||||
onPress: async () => {
|
||||
await sleep(100);
|
||||
MoveNoteSheet.present();
|
||||
},
|
||||
visible: type === "note",
|
||||
icon: "plus"
|
||||
},
|
||||
{
|
||||
title: strings.unlinkNotebook(),
|
||||
onPress: async () => {
|
||||
if (!id) return;
|
||||
await db.notes.removeFromNotebook(id, ...selectedItemsList);
|
||||
updateNotebook(id);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
clearSelection();
|
||||
},
|
||||
visible: renderedInRoute === "Notebook",
|
||||
icon: "minus"
|
||||
},
|
||||
{
|
||||
title: strings.unfavorite(),
|
||||
onPress: addToFavorite,
|
||||
visible: focusedRouteId === "Favorites",
|
||||
icon: "star-off"
|
||||
},
|
||||
{
|
||||
title: strings.moveToTrash(),
|
||||
onPress: async () => {
|
||||
const selection = useSelectionStore.getState();
|
||||
if (!selection.selectionMode) return;
|
||||
await deleteItems(
|
||||
selection.selectionMode as ItemType,
|
||||
selection.selectedItemsList
|
||||
);
|
||||
selection.clearSelection();
|
||||
selection.setSelectionMode(undefined);
|
||||
},
|
||||
visible: type === "note" || type === "notebook",
|
||||
icon: "delete"
|
||||
},
|
||||
{
|
||||
title: strings.doActions.delete.unknown(
|
||||
type!,
|
||||
selectedItemsList.length
|
||||
),
|
||||
onPress: async () => {
|
||||
const selection = useSelectionStore.getState();
|
||||
if (!selection.selectionMode) return;
|
||||
await deleteItems(
|
||||
selection.selectionMode as ItemType,
|
||||
selection.selectedItemsList
|
||||
);
|
||||
selection.clearSelection();
|
||||
selection.setSelectionMode(undefined);
|
||||
},
|
||||
visible:
|
||||
type !== "trash" && type !== "note" && type !== "notebook",
|
||||
icon: "delete"
|
||||
},
|
||||
{
|
||||
title: strings.restore(),
|
||||
onPress: restoreItem,
|
||||
visible: type === "trash",
|
||||
icon: "delete-restore"
|
||||
},
|
||||
{
|
||||
title: strings.delete(),
|
||||
onPress: deleteItem,
|
||||
visible: type === "trash",
|
||||
icon: "delete"
|
||||
}
|
||||
].map((item) =>
|
||||
{!selectedItemsList.length
|
||||
? null
|
||||
: (focusedRouteId === "Monographs"
|
||||
? [
|
||||
{
|
||||
title: strings.unpublish(),
|
||||
onPress: () => {
|
||||
presentDialog({
|
||||
title: strings.doActions.unpublish.note(
|
||||
selectedItemsList.length
|
||||
),
|
||||
positiveText: strings.unpublish(),
|
||||
negativeText: strings.cancel(),
|
||||
positivePress: async () => {
|
||||
for (const id of selectedItemsList) {
|
||||
await db.monographs.unpublish(id);
|
||||
}
|
||||
Navigation.queueRoutesForUpdate();
|
||||
clearSelection();
|
||||
},
|
||||
positiveType: "errorShade"
|
||||
});
|
||||
},
|
||||
visible: true,
|
||||
icon: "delete"
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
title: strings.move(),
|
||||
onPress: async () => {
|
||||
const ids = selectedItemsList;
|
||||
const notebooks = await db.notebooks.all.items(ids);
|
||||
MoveNotebook.present(notebooks);
|
||||
},
|
||||
visible: renderedInRoute === "Notebooks",
|
||||
icon: "arrow-right-bold-box-outline"
|
||||
},
|
||||
{
|
||||
title: strings.manageTags(),
|
||||
onPress: async () => {
|
||||
ManageTagsSheet.present(selectedItemsList);
|
||||
},
|
||||
visible: type === "note",
|
||||
icon: "pound"
|
||||
},
|
||||
{
|
||||
title: strings.export(),
|
||||
onPress: async () => {
|
||||
ExportNotesSheet.present(selectedItemsList);
|
||||
},
|
||||
visible: type === "note",
|
||||
icon: "export"
|
||||
},
|
||||
{
|
||||
title: strings.addToNotebook(),
|
||||
onPress: async () => {
|
||||
Navigation.navigate("LinkNotebooks", {
|
||||
noteIds: selectedItemsList
|
||||
});
|
||||
},
|
||||
visible: type === "note",
|
||||
icon: "plus"
|
||||
},
|
||||
{
|
||||
title: strings.unlinkNotebook(),
|
||||
onPress: async () => {
|
||||
if (!id) return;
|
||||
await db.notes.removeFromNotebook(
|
||||
id,
|
||||
...selectedItemsList
|
||||
);
|
||||
updateNotebook(id);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
clearSelection();
|
||||
},
|
||||
visible: renderedInRoute === "Notebook",
|
||||
icon: "minus"
|
||||
},
|
||||
{
|
||||
title: strings.unfavorite(),
|
||||
onPress: addToFavorite,
|
||||
visible: focusedRouteId === "Favorites",
|
||||
icon: "star-off"
|
||||
},
|
||||
{
|
||||
title: strings.moveToTrash(),
|
||||
onPress: async () => {
|
||||
const selection = useSelectionStore.getState();
|
||||
if (!selection.selectionMode) return;
|
||||
await deleteItems(
|
||||
selection.selectionMode as ItemType,
|
||||
selection.selectedItemsList
|
||||
);
|
||||
selection.clearSelection();
|
||||
selection.setSelectionMode(undefined);
|
||||
},
|
||||
visible: type === "note" || type === "notebook",
|
||||
icon: "delete"
|
||||
},
|
||||
{
|
||||
title: strings.doActions.delete.unknown(
|
||||
type!,
|
||||
selectedItemsList.length
|
||||
),
|
||||
onPress: async () => {
|
||||
const selection = useSelectionStore.getState();
|
||||
if (!selection.selectionMode) return;
|
||||
await deleteItems(
|
||||
selection.selectionMode as ItemType,
|
||||
selection.selectedItemsList
|
||||
);
|
||||
selection.clearSelection();
|
||||
selection.setSelectionMode(undefined);
|
||||
},
|
||||
visible:
|
||||
type !== "trash" &&
|
||||
type !== "note" &&
|
||||
type !== "notebook",
|
||||
icon: "delete"
|
||||
},
|
||||
{
|
||||
title: strings.restore(),
|
||||
onPress: restoreItem,
|
||||
visible: type === "trash",
|
||||
icon: "delete-restore"
|
||||
},
|
||||
{
|
||||
title: strings.delete(),
|
||||
onPress: deleteItem,
|
||||
visible: type === "trash",
|
||||
icon: "delete"
|
||||
}
|
||||
]
|
||||
).map((item) =>
|
||||
!item.visible ? null : (
|
||||
<Button
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
borderRadius: 0,
|
||||
alignSelf: "flex-start",
|
||||
width: "100%"
|
||||
}}
|
||||
<IconButton
|
||||
size={AppFontSize.lg}
|
||||
type="plain"
|
||||
buttonType={{
|
||||
text: contextMenuColors.primary.paragraph
|
||||
}}
|
||||
icon={item.icon}
|
||||
tooltipText={item.title}
|
||||
tooltipPosition={NativeTooltip.POSITIONS.TOP}
|
||||
testID={`select-${item.icon}`}
|
||||
name={item.icon}
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
color={colors.primary.icon}
|
||||
onPress={async () => {
|
||||
//@ts-ignore
|
||||
menuRef.current?.hide();
|
||||
@@ -364,9 +322,16 @@ export const SelectionHeader = React.memo(
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Menu>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
<IconButton
|
||||
size={AppFontSize.lg}
|
||||
onPress={() => {
|
||||
clearSelection();
|
||||
}}
|
||||
color={colors.primary.icon}
|
||||
name="close"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,12 +27,13 @@ import {
|
||||
} from "../../services/event-manager";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { eCloseSheet, eOpenSheet } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { Button } from "../ui/button";
|
||||
import SheetWrapper from "../ui/sheet";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
const SheetProvider = ({ context = "global" }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [visible, setVisible] = useState(false);
|
||||
@@ -94,6 +95,8 @@ const SheetProvider = ({ context = "global" }) => {
|
||||
[context]
|
||||
);
|
||||
|
||||
console.log(data?.keyboardHandlerDisabled);
|
||||
|
||||
return !visible || !data ? null : (
|
||||
<SheetWrapper
|
||||
fwdRef={actionSheetRef}
|
||||
@@ -120,13 +123,13 @@ const SheetProvider = ({ context = "global" }) => {
|
||||
!data.progress && !data.icon && !data.title && !data.paragraph
|
||||
? 0
|
||||
: 10,
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{data?.progress ? (
|
||||
<ActivityIndicator
|
||||
style={{
|
||||
marginTop: 15
|
||||
marginTop: DefaultAppStyles.GAP
|
||||
}}
|
||||
size={50}
|
||||
color={colors.primary.accent}
|
||||
@@ -169,7 +172,7 @@ const SheetProvider = ({ context = "global" }) => {
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
marginBottom: data.valueArray ? 12 : 0
|
||||
}}
|
||||
>
|
||||
@@ -180,7 +183,7 @@ const SheetProvider = ({ context = "global" }) => {
|
||||
type="plain"
|
||||
key={v}
|
||||
textStyle={{ fontWeight: "normal" }}
|
||||
fontSize={SIZE.sm}
|
||||
fontSize={AppFontSize.sm}
|
||||
icon="check"
|
||||
width="100%"
|
||||
style={{
|
||||
@@ -193,7 +196,7 @@ const SheetProvider = ({ context = "global" }) => {
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
{data?.action ? (
|
||||
@@ -220,10 +223,10 @@ const SheetProvider = ({ context = "global" }) => {
|
||||
icon={item.icon && item.icon}
|
||||
type={item.type || "accent"}
|
||||
style={{
|
||||
marginBottom: 10
|
||||
marginBottom: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
width="100%"
|
||||
fontSize={SIZE.md}
|
||||
fontSize={AppFontSize.md}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -231,17 +234,17 @@ const SheetProvider = ({ context = "global" }) => {
|
||||
<Paragraph
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
marginTop: 10,
|
||||
marginTop: DefaultAppStyles.GAP_VERTICAL,
|
||||
textDecorationLine: "underline"
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
onPress={data.learnMorePress}
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
<Icon
|
||||
color={colors.primary.icon}
|
||||
name="information-outline"
|
||||
size={SIZE.xs}
|
||||
size={AppFontSize.xs}
|
||||
/>{" "}
|
||||
{data.learnMore}
|
||||
</Paragraph>
|
||||
|
||||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Notebook } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { TextInput, View } from "react-native";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
@@ -30,17 +31,16 @@ import {
|
||||
} from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import { useMenuStore } from "../../../stores/use-menu-store";
|
||||
import { useNotebookStore } from "../../../stores/use-notebook-store";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { eOnNotebookUpdated } from "../../../utils/events";
|
||||
import { getParentNotebookId } from "../../../utils/notebooks";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { Button } from "../../ui/button";
|
||||
import Input from "../../ui/input";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import { MoveNotes } from "../move-notes/movenote";
|
||||
import { eOnNotebookUpdated } from "../../../utils/events";
|
||||
import { getParentNotebookId } from "../../../utils/notebooks";
|
||||
import { useNotebookStore } from "../../../stores/use-notebook-store";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
export const AddNotebookSheet = ({
|
||||
notebook,
|
||||
@@ -97,18 +97,28 @@ export const AddNotebookSheet = ({
|
||||
parentNotebook?.id ||
|
||||
(await getParentNotebookId(notebook?.id || (id as string)));
|
||||
|
||||
eSendEvent(eOnNotebookUpdated, parent);
|
||||
if (notebook) {
|
||||
setImmediate(() => {
|
||||
eSendEvent(eOnNotebookUpdated, notebook.id);
|
||||
});
|
||||
eSendEvent(eOnNotebookUpdated, parent || notebook?.id);
|
||||
|
||||
if (!parent) {
|
||||
useNotebookStore.getState().refresh();
|
||||
}
|
||||
|
||||
if (!notebook && showMoveNotesOnComplete && id) {
|
||||
MoveNotes.present(await db.notebooks.notebook(id));
|
||||
} else {
|
||||
close?.(true);
|
||||
if (showMoveNotesOnComplete && id && !notebook?.id) {
|
||||
ToastManager.show({
|
||||
heading: strings.notebookAdded(),
|
||||
type: "success",
|
||||
context: "global",
|
||||
actionText: strings.addNotes(),
|
||||
duration: 8000,
|
||||
func: async () => {
|
||||
Navigation.navigate("MoveNotes", {
|
||||
notebook: (await db.notebooks.notebook(id)) as Notebook
|
||||
});
|
||||
ToastManager.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
close?.(true);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -116,10 +126,10 @@ export const AddNotebookSheet = ({
|
||||
style={{
|
||||
maxHeight: DDS.isTab ? "90%" : "97%",
|
||||
borderRadius: DDS.isTab ? 5 : 0,
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Heading size={SIZE.lg}>
|
||||
<Heading size={AppFontSize.lg}>
|
||||
{notebook ? strings.editNotebook() : strings.newNotebook()}
|
||||
</Heading>
|
||||
|
||||
@@ -160,10 +170,8 @@ export const AddNotebookSheet = ({
|
||||
<Button
|
||||
title={notebook ? strings.save() : strings.add()}
|
||||
type="accent"
|
||||
height={45}
|
||||
fontSize={SIZE.md}
|
||||
style={{
|
||||
paddingHorizontal: 24,
|
||||
paddingHorizontal: DefaultAppStyles.GAP * 2,
|
||||
width: "100%"
|
||||
}}
|
||||
onPress={onSaveChanges}
|
||||
|
||||
@@ -1,343 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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 { Note } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, {
|
||||
RefObject,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState
|
||||
} from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Keyboard,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from "react-native";
|
||||
import { ActionSheetRef } from "react-native-actions-sheet";
|
||||
import { FlashList } from "react-native-actions-sheet/dist/src/views/FlashList";
|
||||
import { db } from "../../../common/database";
|
||||
import { presentSheet } from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import { ItemSelection } from "../../../stores/item-selection-store";
|
||||
import { useNotebooks } from "../../../stores/use-notebook-store";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
import { updateNotebook } from "../../../utils/notebooks";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { Dialog } from "../../dialog";
|
||||
import DialogHeader from "../../dialog/dialog-header";
|
||||
import SheetProvider from "../../sheet-provider";
|
||||
import { Button } from "../../ui/button";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import Input from "../../ui/input";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { AddNotebookSheet } from "../add-notebook";
|
||||
import { NotebookItem } from "./notebook-item";
|
||||
import { useNotebookItemSelectionStore } from "./store";
|
||||
|
||||
async function updateInitialSelectionState(items: string[]) {
|
||||
const relations = await db.relations
|
||||
.to(
|
||||
{
|
||||
type: "note",
|
||||
ids: items
|
||||
},
|
||||
"notebook"
|
||||
)
|
||||
.get();
|
||||
|
||||
const initialSelectionState: ItemSelection = {};
|
||||
const notebookIds = [
|
||||
...new Set(relations.map((relation) => relation.fromId))
|
||||
];
|
||||
|
||||
for (const id of notebookIds) {
|
||||
const all = items.every((noteId) => {
|
||||
return (
|
||||
relations.findIndex(
|
||||
(relation) => relation.fromId === id && relation.toId === noteId
|
||||
) > -1
|
||||
);
|
||||
});
|
||||
if (all) {
|
||||
initialSelectionState[id] = "selected";
|
||||
} else {
|
||||
initialSelectionState[id] = "intermediate";
|
||||
}
|
||||
}
|
||||
useNotebookItemSelectionStore.setState({
|
||||
initialState: initialSelectionState,
|
||||
selection: { ...initialSelectionState },
|
||||
multiSelect: relations.length > 1
|
||||
});
|
||||
}
|
||||
|
||||
const MoveNoteSheet = ({
|
||||
note,
|
||||
actionSheetRef
|
||||
}: {
|
||||
note: Note | undefined;
|
||||
actionSheetRef: RefObject<ActionSheetRef>;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [rootNotebooks, loading] = useNotebooks();
|
||||
const searchQuery = useRef("");
|
||||
const searchTimer = useRef<NodeJS.Timeout>();
|
||||
const [notebooks, setNotebooks] = useState(rootNotebooks);
|
||||
|
||||
const dimensions = useSettingStore((state) => state.dimensions);
|
||||
const selectedItemsList = useSelectionStore(
|
||||
(state) => state.selectedItemsList
|
||||
);
|
||||
|
||||
const multiSelect = useNotebookItemSelectionStore(
|
||||
(state) => state.multiSelect
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
setNotebooks(rootNotebooks);
|
||||
}
|
||||
}, [loading, rootNotebooks]);
|
||||
|
||||
useEffect(() => {
|
||||
const items = note ? [note.id] : selectedItemsList;
|
||||
updateInitialSelectionState(items);
|
||||
return () => {
|
||||
useNotebookItemSelectionStore.setState({
|
||||
initialState: {},
|
||||
selection: {},
|
||||
multiSelect: false,
|
||||
canEnableMultiSelectMode: true
|
||||
});
|
||||
};
|
||||
}, [note, selectedItemsList]);
|
||||
|
||||
const onSave = async () => {
|
||||
const noteIds = note ? [note.id] : selectedItemsList;
|
||||
|
||||
const changedNotebooks = useNotebookItemSelectionStore.getState().selection;
|
||||
|
||||
for (const id in changedNotebooks) {
|
||||
const item = await db.notebooks.notebook(id);
|
||||
if (!item) continue;
|
||||
if (changedNotebooks[id] === "selected") {
|
||||
for (const id of noteIds) {
|
||||
await db.relations.add(item, { id: id, type: "note" });
|
||||
updateNotebook(item.id);
|
||||
}
|
||||
} else if (changedNotebooks[id] === "deselected") {
|
||||
for (const id of noteIds) {
|
||||
await db.relations.unlink(item, { id: id, type: "note" });
|
||||
updateNotebook(item.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useRelationStore.getState().update();
|
||||
actionSheetRef.current?.hide();
|
||||
};
|
||||
|
||||
const hasSelected = () => {
|
||||
const selection = useNotebookItemSelectionStore.getState().selection;
|
||||
return Object.keys(selection).some((key) => selection[key] === "selected");
|
||||
};
|
||||
|
||||
const renderNotebook = useCallback(
|
||||
({ index }: { item: boolean; index: number }) => (
|
||||
<NotebookItem items={notebooks} id={index} index={index} />
|
||||
),
|
||||
[notebooks]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog context="move_note" />
|
||||
<SheetProvider context="link-notebooks" />
|
||||
<View>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
position: "absolute"
|
||||
}}
|
||||
onPress={() => {
|
||||
Keyboard.dismiss();
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row",
|
||||
alignItems: "flex-start"
|
||||
}}
|
||||
>
|
||||
<DialogHeader
|
||||
style={{
|
||||
minHeight: 10,
|
||||
flexShrink: 1
|
||||
}}
|
||||
title={strings.selectNotebooks()}
|
||||
paragraph={
|
||||
!multiSelect
|
||||
? strings.enableMultiSelect()
|
||||
: strings.selectNotebooksDesc()
|
||||
}
|
||||
/>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
columnGap: 10
|
||||
}}
|
||||
>
|
||||
{hasSelected() ? (
|
||||
<IconButton
|
||||
name="restore"
|
||||
color={colors.primary.icon}
|
||||
onPress={() => {
|
||||
const items = note ? [note.id] : selectedItemsList;
|
||||
updateInitialSelectionState(items);
|
||||
}}
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<Button
|
||||
height={40}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 24,
|
||||
alignSelf: "flex-start"
|
||||
}}
|
||||
title={strings.save()}
|
||||
type={"accent"}
|
||||
onPress={onSave}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 0,
|
||||
maxHeight: dimensions.height * 0.85,
|
||||
height: dimensions.height * 0.85,
|
||||
paddingTop: 6
|
||||
}}
|
||||
>
|
||||
<FlashList
|
||||
data={notebooks?.placeholders}
|
||||
style={{
|
||||
width: "100%"
|
||||
}}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
ListHeaderComponent={
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
width: "100%",
|
||||
paddingTop: 12
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
placeholder={strings.searchNotebooks()}
|
||||
button={{
|
||||
icon: "plus",
|
||||
onPress: () => {
|
||||
AddNotebookSheet.present(
|
||||
undefined,
|
||||
undefined,
|
||||
"link-notebooks",
|
||||
undefined,
|
||||
false,
|
||||
searchQuery.current
|
||||
);
|
||||
},
|
||||
color: colors.primary.icon
|
||||
}}
|
||||
onChangeText={(value) => {
|
||||
searchQuery.current = value;
|
||||
if (!searchQuery.current) {
|
||||
setNotebooks(rootNotebooks);
|
||||
return;
|
||||
}
|
||||
searchTimer.current = setTimeout(() => {
|
||||
db.lookup
|
||||
.notebooks(searchQuery.current)
|
||||
.sorted()
|
||||
.then((result) => {
|
||||
if (searchQuery.current === value) {
|
||||
setNotebooks(result);
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
estimatedItemSize={50}
|
||||
renderItem={renderNotebook}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 200
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator
|
||||
size={SIZE.lg}
|
||||
color={colors.primary.accent}
|
||||
/>
|
||||
) : (
|
||||
<Paragraph color={colors.primary.icon}>
|
||||
{strings.emptyPlaceholders("notebook")}
|
||||
</Paragraph>
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
ListFooterComponent={<View style={{ height: 50 }} />}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
MoveNoteSheet.present = (note?: Note) => {
|
||||
presentSheet({
|
||||
component: (ref) => <MoveNoteSheet actionSheetRef={ref} note={note} />,
|
||||
enableGesturesInScrollView: false,
|
||||
noBottomPadding: true,
|
||||
keyboardHandlerDisabled: true
|
||||
});
|
||||
};
|
||||
export default MoveNoteSheet;
|
||||
@@ -1,263 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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 { Notebook, VirtualizedGrouping } from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useEffect } from "react";
|
||||
import { View, useWindowDimensions } from "react-native";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { useTotalNotes } from "../../../hooks/use-db-item";
|
||||
import { useNotebook } from "../../../hooks/use-notebook";
|
||||
import useNavigationStore from "../../../stores/use-navigation-store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { AddNotebookSheet } from "../add-notebook";
|
||||
import {
|
||||
useNotebookExpandedStore,
|
||||
useNotebookItemSelectionStore
|
||||
} from "./store";
|
||||
|
||||
type NotebookParentProp = {
|
||||
parent?: NotebookParentProp;
|
||||
item?: Notebook;
|
||||
};
|
||||
|
||||
export const NotebookItem = ({
|
||||
id,
|
||||
currentLevel = 0,
|
||||
index,
|
||||
parent,
|
||||
items
|
||||
}: {
|
||||
id: string | number;
|
||||
currentLevel?: number;
|
||||
index: number;
|
||||
parent?: NotebookParentProp;
|
||||
items?: VirtualizedGrouping<Notebook>;
|
||||
}) => {
|
||||
const { nestedNotebooks, notebook: item } = useNotebook(id, items, true);
|
||||
const expanded = useNotebookExpandedStore((state) =>
|
||||
item?.id ? state.expanded[item?.id] : false
|
||||
);
|
||||
const { totalNotes: totalNotes, getTotalNotes } = useTotalNotes("notebook");
|
||||
const focusedRouteId = useNavigationStore((state) => state.focusedRouteId);
|
||||
const { colors } = useThemeColors("sheet");
|
||||
const selection = useNotebookItemSelectionStore((state) =>
|
||||
item?.id ? state.selection[item?.id] : undefined
|
||||
);
|
||||
const isSelected = selection === "selected";
|
||||
const isFocused = focusedRouteId === id;
|
||||
const { fontScale } = useWindowDimensions();
|
||||
|
||||
useEffect(() => {
|
||||
if (item?.id) {
|
||||
getTotalNotes([item?.id]);
|
||||
}
|
||||
}, [getTotalNotes, item?.id]);
|
||||
|
||||
const onPress = () => {
|
||||
if (!item) return;
|
||||
const state = useNotebookItemSelectionStore.getState();
|
||||
|
||||
if (isSelected) {
|
||||
state.markAs(
|
||||
item,
|
||||
!state.initialState[item?.id] ? undefined : "deselected"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.multiSelect) {
|
||||
const keys = Object.keys(state.selection);
|
||||
const nextState: any = {};
|
||||
for (const key in keys) {
|
||||
nextState[key] = !state.initialState[key] ? undefined : "deselected";
|
||||
}
|
||||
|
||||
state.setSelection({
|
||||
[item.id]: "selected",
|
||||
...nextState
|
||||
});
|
||||
} else {
|
||||
state.markAs(item, "selected");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingLeft: currentLevel > 0 && currentLevel < 6 ? 15 : undefined,
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<Pressable
|
||||
type={"transparent"}
|
||||
onLongPress={() => {
|
||||
if (!item) return;
|
||||
useNotebookItemSelectionStore.setState({
|
||||
multiSelect: true
|
||||
});
|
||||
const state = useNotebookItemSelectionStore.getState();
|
||||
useNotebookItemSelectionStore
|
||||
.getState()
|
||||
.markAs(
|
||||
item,
|
||||
!isSelected
|
||||
? "selected"
|
||||
: !state.initialState[item?.id]
|
||||
? undefined
|
||||
: "deselected"
|
||||
);
|
||||
}}
|
||||
testID={`add-to-notebook-item-${currentLevel}-${index}`}
|
||||
onPress={onPress}
|
||||
style={{
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
paddingLeft: 12,
|
||||
paddingRight: 12,
|
||||
borderRadius: 0,
|
||||
height: 45
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{nestedNotebooks?.placeholders.length ? (
|
||||
<IconButton
|
||||
size={SIZE.xl}
|
||||
color={isSelected ? colors.selected.icon : colors.primary.icon}
|
||||
onPress={() => {
|
||||
if (!item?.id) return;
|
||||
useNotebookExpandedStore.getState().setExpanded(item?.id);
|
||||
}}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
right={0}
|
||||
style={{
|
||||
width: 35,
|
||||
height: 35
|
||||
}}
|
||||
name={expanded ? "chevron-down" : "chevron-right"}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<IconButton
|
||||
size={SIZE.xl}
|
||||
color={
|
||||
isSelected
|
||||
? colors.selected.icon
|
||||
: selection === "deselected"
|
||||
? colors.error.accent
|
||||
: colors.primary.icon
|
||||
}
|
||||
onPress={onPress}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
right={0}
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
name={
|
||||
selection === "deselected"
|
||||
? "close-circle-outline"
|
||||
: isSelected
|
||||
? "check-circle-outline"
|
||||
: selection === "intermediate"
|
||||
? "minus-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
/>
|
||||
|
||||
<Paragraph
|
||||
color={
|
||||
isFocused ? colors.selected.paragraph : colors.secondary.paragraph
|
||||
}
|
||||
size={SIZE.sm}
|
||||
>
|
||||
{item?.title}
|
||||
</Paragraph>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
columnGap: 10,
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{item?.id && totalNotes?.(item?.id) ? (
|
||||
<Paragraph size={SIZE.sm} color={colors.secondary.paragraph}>
|
||||
{totalNotes(item?.id)}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
<IconButton
|
||||
name="plus"
|
||||
style={{
|
||||
width: 40 * fontScale,
|
||||
height: 40 * fontScale
|
||||
}}
|
||||
testID={notesnook.ids.notebook.menu}
|
||||
onPress={() => {
|
||||
if (!item) return;
|
||||
AddNotebookSheet.present(
|
||||
undefined,
|
||||
item,
|
||||
"link-notebooks",
|
||||
undefined,
|
||||
false
|
||||
);
|
||||
}}
|
||||
left={0}
|
||||
right={0}
|
||||
bottom={0}
|
||||
top={0}
|
||||
color={colors.primary.icon}
|
||||
size={SIZE.xl}
|
||||
/>
|
||||
</View>
|
||||
</Pressable>
|
||||
|
||||
{!expanded
|
||||
? null
|
||||
: nestedNotebooks?.placeholders.map((id, index) => (
|
||||
<NotebookItem
|
||||
key={item?.id + "_" + index}
|
||||
id={index}
|
||||
index={index}
|
||||
currentLevel={currentLevel + 1}
|
||||
items={nestedNotebooks}
|
||||
parent={{
|
||||
parent: parent,
|
||||
item: item
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user