Compare commits

..

44 Commits

Author SHA1 Message Date
Abdullah Atta
c2710aa560 web: fix tests 2025-03-28 12:26:08 +05:00
Abdullah Atta
96611e6857 web: bump version to 3.1.0-beta.4 2025-03-27 16:07:32 +05:00
Abdullah Atta
e253fa2b19 web: close expanded nav pane on navigation 2025-03-27 16:06:39 +05:00
Abdullah Atta
a165dda9d8 web: force list pane to be visible when reveal item in list is called 2025-03-27 16:06:39 +05:00
Abdullah Atta
76c2baa9f6 web: improve item flash animation when revealing item in list
this also fixes a potential memory leak due to event listener not unsubscribing
2025-03-27 16:06:39 +05:00
Abdullah Atta
dcba3ebdd7 Revert "web: fix list pane not expanding (#7758)"
This reverts commit fd9db3605d.
2025-03-27 16:06:39 +05:00
Abdullah Atta
df1c1595c7 web: fix active tab background 2025-03-27 16:06:39 +05:00
Abdullah Atta
341e8b867f web: fix Service worker did not respond. error 2025-03-27 16:06:39 +05:00
Abdullah Atta
750724ee27 web: fix app not starting up on firefox 2025-03-27 16:06:39 +05:00
01zulfi
3304660864 web: don't remove properties pane when editor is refocused (#7780)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-03-27 16:06:39 +05:00
Abdullah Atta
74f76f0f83 intl: update strings 2025-03-27 16:06:39 +05:00
Abdullah Atta
1b63b2dccf web: replace shared worker with service worker for sqlite 2025-03-27 16:06:39 +05:00
01zulfi
800a875a8f web: collapse hovered navbar when item is clicked (#7771)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-03-27 16:06:39 +05:00
Abdullah Atta
43d7d52fa6 web: release v3.1.0-beta.3 2025-03-27 16:06:39 +05:00
Ammar Ahmed
929e6f7227 web: cleanup 2025-03-27 16:06:39 +05:00
01zulfi
ce1b03cbbc web: fix list pane not expanding (#7758)
* web: fix list pane not expanding
* when a nav item was clicked, list pane was removed entirely which made it difficult to re-open it, now when nav item is clicked we manually collapse, expand, or reset the list pane
* open list pane if 'reveal in list' is called
* open list pane if navigated to a different nav item

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* web: clicking on nav item should not collapse list pane
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* web: collapse hovered nav pane when notebook/tag item clicked
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

---------

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-03-27 16:06:39 +05:00
01zulfi
577e053816 web: restore notebook crumbs (#7765)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-03-27 16:06:39 +05:00
Ammar Ahmed
2637bb0507 web: bump version to 3.1.0-beta.2 for desktop and web 2025-03-27 16:06:39 +05:00
Abdullah Atta
d5f9a11565 web: make editor note properties work like toc 2025-03-27 16:06:39 +05:00
Abdullah Atta
c44d667ffc web: slightly improve add note button ui 2025-03-27 16:06:39 +05:00
Abdullah Atta
b3a2a5c2a1 web: bump version to 3.1.0-beta.1 2025-03-27 16:06:39 +05:00
Abdullah Atta
d9898d8fcb desktop: set publish channel to beta for beta builds 2025-03-27 16:06:39 +05:00
Abdullah Atta
ea8092d8c8 web: minor ui fixes 2025-03-27 16:06:39 +05:00
Abdullah Atta
b9696a91ef theme: fix button hover colors 2025-03-27 16:06:39 +05:00
Abdullah Atta
ac7e84ba3b web: make notesnook branding a bit smaller 2025-03-27 16:06:39 +05:00
Abdullah Atta
4b5cab0d34 web: minor ui changes and fixes 2025-03-27 16:06:39 +05:00
Abdullah Atta
5cfe42acde web: fix theme not persisting 2025-03-27 16:06:39 +05:00
Abdullah Atta
df83180322 web: collapse sidebar on navigate if sidebar is temporarily expanded 2025-03-27 16:06:39 +05:00
Abdullah Atta
f65a36331c desktop: explicitly deny geolocation permission to electron process 2025-03-27 16:06:39 +05:00
Abdullah Atta
597a09b06d web: fix scrollbar styling in sidebar 2025-03-27 16:06:39 +05:00
Abdullah Atta
337e5f8f7a web: reset search on navigate 2025-03-27 16:06:39 +05:00
Abdullah Atta
b48232bb62 web: fix expand sidebar button not working 2025-03-27 16:06:39 +05:00
Abdullah Atta
ba7154d58c web: always show "X" button if there is query in search input 2025-03-27 16:06:38 +05:00
Abdullah Atta
de7b382a02 web: bump version to 3.1.0-beta.0 2025-03-27 16:06:38 +05:00
Abdullah Atta
26dda2a481 web: use virtualized tree for rendering toc 2025-03-27 16:06:38 +05:00
Abdullah Atta
773214a353 editor: fix toc level mapping 2025-03-27 16:06:38 +05:00
Abdullah Atta
04cac3e542 web: add support for pre-expanding tree nodes on creation 2025-03-27 16:06:38 +05:00
Abdullah Atta
732ebf24c8 web: do not collapse child nodes when collapsing parent 2025-03-27 16:06:38 +05:00
Abdullah Atta
0dcdc99175 web: fix all tests 2025-03-27 16:06:38 +05:00
Abdullah Atta
6ecad2314c global: update ui 2025-03-27 16:06:38 +05:00
01zulfi
fe364b7932 web: fix faulty useEffect
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-03-27 16:06:38 +05:00
01zulfi
3c2fe37693 web: refactor props for Tags component
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-03-27 16:06:38 +05:00
01zulfi
81f7af0b28 web: separate component for tab items in sidebar
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-03-27 16:06:38 +05:00
01zulfi
46dfe9df7c web: new sidebar ui
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-03-27 16:06:38 +05:00
416 changed files with 23751 additions and 34383 deletions

View File

@@ -4,7 +4,7 @@ on: workflow_dispatch
jobs:
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
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: "17"
java-version: "11"
architecture: "x64"
- name: Install node modules
@@ -58,7 +58,7 @@ jobs:
ccache -p
- name: Cache gradle
uses: actions/cache@v3
uses: actions/cache@v2
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: beta
track: alpha
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}}
name: Notesnook Android v${{ steps.package-version.outputs.current-version}} Beta
repository: streetwriters/notesnook
token: ${{ secrets.GITHUB_TOKEN }}
files: |
@@ -146,7 +146,6 @@ 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

View File

@@ -58,7 +58,7 @@ jobs:
ccache -p
- name: Cache gradle
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: |
~/.gradle/caches

View File

@@ -4,7 +4,7 @@ on: workflow_dispatch
jobs:
build:
runs-on: macos-14
runs-on: macos-latest
timeout-minutes: 60
steps:
@@ -14,11 +14,6 @@ jobs:
- name: Setup Node
uses: ./.github/actions/setup-node-with-cache
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "16.1"
- name: Install node modules
run: |
npm ci --ignore-scripts --prefer-offline --no-audit

View File

@@ -58,10 +58,10 @@ This will compile and run the app in production mode but it won't generate any p
npm run release -- --rebuild
# For macOS
npx electron-builder --config=electron-builder.config.js --mac dmg --arm64 --x64 --publish never
npx electron-builder --config=electron-builder.config.js --mac dmg --arm64 --x64 -publish never
# For Linux (AppImage)
npx electron-builder --config=electron-builder.config.js --linux AppImage:x64 AppImage:arm64 --publish never
npx electron-builder --config=electron-builder.config.js --linux AppImage:x64 AppImage:arm64 -publish never
# For Windows
npx electron-builder --config=electron-builder.config.js --win --publish never

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "@notesnook/desktop",
"productName": "Notesnook",
"description": "Your private note taking space",
"version": "3.1.1",
"version": "3.1.0-beta.4",
"appAppleId": "1544027013",
"private": true,
"main": "./dist/cjs/index.js",

View File

@@ -19,30 +19,26 @@ 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 { Appearance, I18nManager, StatusBar } from "react-native";
import { I18nManager, View } from "react-native";
import "react-native-gesture-handler";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { SafeAreaProvider } from "react-native-safe-area-context";
import DialogProvider from "./components/dialog-provider";
import AppLockedOverlay from "./components/app-lock-overlay";
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 { changeSystemBarColors, useThemeStore } from "./stores/use-theme-store";
import { 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);
@@ -52,13 +48,11 @@ 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();
@@ -70,27 +64,42 @@ const App = (props: { configureMode: "note-preview" }) => {
}, []);
return (
<SafeAreaProvider>
<StatusBar translucent={true} backgroundColor="transparent" />
<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>
<GestureHandlerRootView
style={{
height: "100%",
width: "100%"
}}
>
<GlobalSafeAreaProvider />
{props.configureMode === "note-preview" ? (
<NotePreviewConfigure />
) : (
<RootNavigation />
<ApplicationHolder />
)}
<ScopedThemeProvider value="dialog">
<Toast />
</ScopedThemeProvider>
<DialogProvider />
<AppLocked />
</GestureHandlerRootView>
</SafeAreaProvider>
<AppLockedOverlay />
</View>
);
};
@@ -129,27 +138,16 @@ 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
}, []);
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]);
const nextTheme = colorScheme === "dark" ? darkTheme : lightTheme;
if (JSON.stringify(nextTheme) !== JSON.stringify(currTheme)) {
useThemeEngineStore
.getState()
.setTheme(colorScheme === "dark" ? darkTheme : lightTheme);
currTheme = nextTheme;
}
return (
<I18nProvider i18n={i18n}>

File diff suppressed because one or more lines are too long

View File

@@ -149,9 +149,7 @@ export async function downloadFile(
});
}
await RNFetchBlob.fs.mv(tempFilePath, originalFilePath).catch(() => {
/* empty */
});
await RNFetchBlob.fs.mv(tempFilePath, originalFilePath);
if (!(await exists(filename))) {
throw new Error("File size mismatch");

View File

@@ -24,7 +24,6 @@ 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();
@@ -37,8 +36,9 @@ export const Announcement = ({ color }) => {
style={{
backgroundColor: colors.primary.background,
width: "100%",
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingHorizontal: 12,
paddingTop: 12,
paddingBottom: 12
}}
>
<View
@@ -54,7 +54,7 @@ export const Announcement = ({ color }) => {
<View
style={{
width: "100%",
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 12
}}
>
{announcement?.body

View File

@@ -20,13 +20,12 @@ 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: DefaultAppStyles.GAP,
paddingHorizontal: 12,
...getStyle(style)
}}
>

View File

@@ -23,13 +23,12 @@ import { Linking, View } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import { eSendEvent, presentSheet } from "../../services/event-manager";
import { eCloseAnnouncementDialog } from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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();
@@ -62,7 +61,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
return (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
...getStyle(style),
flexDirection: inline ? "row" : "column"
}}
@@ -76,7 +75,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
<Button
key={item.title}
title={item.title}
fontSize={AppFontSize.sm}
fontSize={SIZE.sm}
type="transparent"
textStyle={{
textDecorationLine: "underline"
@@ -84,7 +83,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
onPress={() => onPress(item)}
bold
style={{
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
height: 30,
alignSelf: "flex-start",
paddingHorizontal: 0
}}
@@ -96,7 +95,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
<Button
key={item.title}
title={item.title}
fontSize={AppFontSize.sm}
fontSize={SIZE.sm}
type="plain"
onPress={() => onPress(item)}
width={null}
@@ -119,7 +118,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
<Button
key={item.title}
title={item.title}
fontSize={AppFontSize.md}
fontSize={SIZE.md}
buttonType={{
color: color ? color : colors.primary.accent,
text: color
@@ -131,7 +130,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
onPress={() => onPress(item)}
width={250}
style={{
marginBottom: DefaultAppStyles.GAP_VERTICAL,
marginBottom: 5,
borderRadius: 100
}}
/>
@@ -142,14 +141,14 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
<Button
key={item.title}
title={item.title}
fontSize={AppFontSize.xs}
fontSize={SIZE.xs}
type="plain"
onPress={() => onPress(item)}
width={null}
height={30}
style={{
minWidth: "50%",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
marginTop: 5
}}
textStyle={{
textDecorationLine: "underline"

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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 ? AppFontSize.sm : AppFontSize.md}
size={inline ? SIZE.sm : SIZE.md}
>
{text}
</Paragraph>

View File

@@ -28,7 +28,6 @@ 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;
@@ -54,7 +53,7 @@ const Features = () => {
return (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
alignItems: "center",
width: "100%"
}}

View File

@@ -22,13 +22,12 @@ 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: DefaultAppStyles.GAP,
paddingHorizontal: 12,
paddingLeft: listType === "ordered" ? 25 : 25,
...getStyle(style)
}}
@@ -37,7 +36,7 @@ export const List = ({ items, listType, style = {} }) => {
<View
key={item.text}
style={{
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
paddingVertical: 6,
flexDirection: "row"
}}
>

View File

@@ -18,18 +18,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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={AppFontSize.md + 2}
size={SIZE.md + 2}
style={{
marginHorizontal: DefaultAppStyles.GAP,
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginHorizontal: 12,
marginTop: 12,
...getStyle(style)
}}
>

View File

@@ -20,11 +20,10 @@ 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 { AppFontSize } from "../../utils/size";
import { SIZE } 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);
@@ -37,19 +36,19 @@ export const Title = ({ text, style = {}, inline }) => {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: inline ? DefaultAppStyles.GAP_VERTICAL_SMALL : 0
marginBottom: inline ? 5 : 0
}}
>
<Heading
style={{
marginHorizontal: DefaultAppStyles.GAP,
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginHorizontal: 12,
marginTop: 12,
...getStyle(style),
textAlign: inline ? "left" : style?.textAlign,
flexShrink: 1
}}
numberOfLines={1}
size={inline ? AppFontSize.md : AppFontSize.xl}
size={inline ? SIZE.md : SIZE.xl}
>
{inline ? text?.toUpperCase() : text}
</Heading>
@@ -68,7 +67,7 @@ export const Title = ({ text, style = {}, inline }) => {
right: 0
}}
iconSize={24}
fontSize={AppFontSize.xs}
fontSize={SIZE.xs}
style={{
borderRadius: 100,
paddingVertical: 0,
@@ -81,9 +80,9 @@ export const Title = ({ text, style = {}, inline }) => {
) : (
<Heading
style={{
marginHorizontal: DefaultAppStyles.GAP,
marginHorizontal: 12,
...getStyle(style),
marginTop: style?.marginTop || DefaultAppStyles.GAP_VERTICAL
marginTop: style?.marginTop || 12
}}
>
{text}

View File

@@ -44,6 +44,7 @@ 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";
@@ -53,9 +54,6 @@ 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");
@@ -84,7 +82,7 @@ const verifyUserPassword = async (password: string) => {
}
};
const AppLocked = () => {
const AppLockedOverlay = () => {
const initialLaunchBiometricRequest = useRef(true);
const { colors } = useThemeColors();
const user = getUser();
@@ -111,9 +109,6 @@ const AppLocked = () => {
);
const onUnlockAppRequested = useCallback(async () => {
editorController.current?.commands.blur(useTabStore.getState().currentTab);
editorController.current?.commands.blurPassInput();
if (
!biometricsAuthEnabled ||
!(await BiometricService.isBiometryAvailable())
@@ -187,13 +182,7 @@ const AppLocked = () => {
(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 (
@@ -294,16 +283,6 @@ const AppLocked = () => {
keyboardType={
appLockHasPasswordSecurity ? keyboardType : "default"
}
onLayout={async () => {
if (
!biometricsAuthEnabled ||
!(await BiometricService.isBiometryAvailable())
) {
setTimeout(() => {
passwordInputRef.current?.focus();
}, 32);
}
}}
placeholder={
appLockHasPasswordSecurity
? keyboardType === "numeric"
@@ -336,7 +315,7 @@ const AppLocked = () => {
borderRadius: 150,
marginBottom: 10
}}
fontSize={AppFontSize.md}
fontSize={SIZE.md}
/>
</>
) : null}
@@ -357,4 +336,4 @@ const AppLocked = () => {
) : null;
};
export default AppLocked;
export default AppLockedOverlay;

View File

@@ -45,7 +45,7 @@ import {
eDBItemUpdate,
eOnLoadNote
} from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import { Dialog } from "../dialog";
import { presentDialog } from "../dialog/functions";
@@ -58,7 +58,6 @@ 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,
@@ -227,15 +226,14 @@ const Actions = ({
style={{
borderBottomWidth: 1,
borderBottomColor: colors.primary.border,
marginBottom:
notes && notes.length > 0 ? 0 : DefaultAppStyles.GAP_VERTICAL
marginBottom: notes && notes.length > 0 ? 0 : 12
}}
>
<Heading
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
size={AppFontSize.lg}
size={SIZE.lg}
>
{filename}
</Heading>
@@ -243,21 +241,21 @@ const Actions = ({
<View
style={{
flexDirection: "row",
marginBottom: DefaultAppStyles.GAP_VERTICAL,
paddingHorizontal: DefaultAppStyles.GAP,
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
marginBottom: 10,
paddingHorizontal: 12,
marginTop: 6,
gap: 10
}}
>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
{attachment.mimeType}
</Paragraph>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
{formatBytes(attachment.size)}
</Paragraph>
{notes.length ? (
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
{strings.notes(notes.length)}
</Paragraph>
) : null}
@@ -270,7 +268,7 @@ const Actions = ({
context: "local"
});
}}
size={AppFontSize.xs}
size={SIZE.xs}
color={colors.secondary.paragraph}
>
{attachment.hash}
@@ -285,16 +283,16 @@ const Actions = ({
style={{
borderBottomWidth: 1,
borderBottomColor: colors.primary.border,
marginBottom: DefaultAppStyles.GAP_VERTICAL,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
marginBottom: 12,
paddingVertical: 12
}}
>
<>
<Heading
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
size={AppFontSize.sm}
size={SIZE.sm}
>
{strings.listOf()} {strings.dataTypesPlural.note()}:
</Heading>
@@ -309,14 +307,14 @@ const Actions = ({
openNote(item, (item as any).type === "trash");
}}
style={{
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
paddingVertical: 12,
alignItems: "flex-start",
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
key={item.id}
>
<Paragraph size={AppFontSize.xs}>{item.title}</Paragraph>
<Paragraph size={SIZE.xs}>{item.title}</Paragraph>
</Pressable>
))}
</>
@@ -337,7 +335,7 @@ const Actions = ({
icon={item.icon}
loading={loading?.name === item.name}
type="plain"
fontSize={AppFontSize.sm}
fontSize={SIZE.sm}
style={{
borderRadius: 0,
justifyContent: "flex-start",
@@ -349,7 +347,7 @@ const Actions = ({
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
{failed ? (

View File

@@ -25,14 +25,13 @@ 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 { defaultBorderRadius, AppFontSize } from "../../utils/size";
import { SIZE } 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);
@@ -77,8 +76,8 @@ export const AttachmentItem = ({
flexDirection: "row",
marginVertical: 5,
justifyContent: "space-between",
padding: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
padding: 12,
paddingVertical: 6,
minHeight: 45
}}
>
@@ -102,7 +101,7 @@ export const AttachmentItem = ({
paddingHorizontal: 2,
width: 30,
height: 30,
borderRadius: defaultBorderRadius
borderRadius: 5
}}
>
<Paragraph
@@ -125,7 +124,7 @@ export const AttachmentItem = ({
}}
>
<Paragraph
size={AppFontSize.sm}
size={SIZE.sm}
style={{
flexWrap: "wrap"
}}
@@ -137,10 +136,7 @@ export const AttachmentItem = ({
</Paragraph>
{!hideWhenNotDownloading ? (
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.xxs}
>
<Paragraph color={colors.secondary.paragraph} size={SIZE.xxs}>
{strings.fileSize()}: {formatBytes(attachment.size)}
</Paragraph>
) : null}
@@ -163,7 +159,7 @@ export const AttachmentItem = ({
}}
>
<ProgressCircleComponent
size={AppFontSize.xxl}
size={SIZE.xxl}
progress={
currentProgress?.value ? currentProgress?.value / 100 : 0
}

View File

@@ -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 { AppFontSize } from "../../utils/size";
import { SIZE } from "../../utils/size";
import { Dialog } from "../dialog";
import { presentDialog } from "../dialog/functions";
import { Header } from "../header";
@@ -50,7 +50,6 @@ 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",
@@ -326,31 +325,30 @@ export const AttachmentDialog = ({
title={strings.manageAttachments()}
renderedInRoute="SettingsGroup"
canGoBack
// 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()
// }
// ]}
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
@@ -358,7 +356,7 @@ export const AttachmentDialog = ({
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
<Heading>{strings.dataTypesPluralCamelCase.attachment()}</Heading>
@@ -371,15 +369,21 @@ export const AttachmentDialog = ({
<IconButton
name="check-all"
style={{
height: 40,
width: 40,
marginRight: 10
}}
color={colors.primary.paragraph}
size={AppFontSize.lg}
size={SIZE.lg}
onPress={onCheck}
/>
<IconButton
name="download"
style={{
height: 40,
width: 40
}}
color={colors.primary.paragraph}
onPress={() => {
if (!attachments) return;
@@ -394,7 +398,7 @@ export const AttachmentDialog = ({
negativeText: strings.cancel()
});
}}
size={AppFontSize.lg}
size={SIZE.lg}
/>
</View>
</View>
@@ -404,7 +408,7 @@ export const AttachmentDialog = ({
style={{
width: "100%",
alignSelf: "center",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
height: "100%"
}}
>
@@ -424,7 +428,7 @@ export const AttachmentDialog = ({
alignItems: "center",
width: "100%",
borderRadius: 10,
padding: DefaultAppStyles.GAP_SMALL,
padding: 10,
borderWidth: 1,
borderColor: colors.primary.border,
gap: 12,
@@ -469,7 +473,7 @@ export const AttachmentDialog = ({
<IconButton
type={rechecker.isWorking ? "errorShade" : "plain"}
name={rechecker.isWorking ? "close" : "check"}
size={AppFontSize.lg}
size={SIZE.lg}
color={
rechecker.isWorking ? colors.error.icon : colors.primary.accent
}
@@ -490,7 +494,7 @@ export const AttachmentDialog = ({
backgroundColor: colors.primary.background,
flexWrap: "wrap",
flexDirection: "row",
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingVertical: 12
}}
contentContainerStyle={{
alignItems: "center"
@@ -507,10 +511,10 @@ export const AttachmentDialog = ({
}
key={item.title}
title={item.title}
fontSize={AppFontSize.sm}
fontSize={SIZE.sm}
style={{
borderRadius: 100,
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
height: 40,
minWidth: 80
}}

View File

@@ -37,7 +37,6 @@ 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,
@@ -134,7 +133,7 @@ const AuthModal = () => {
style={{
flexDirection: "row",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
width: "100%",
height: 50,
justifyContent:
@@ -168,7 +167,7 @@ const AuthModal = () => {
marginTop: 2
}}
style={{
paddingHorizontal: DefaultAppStyles.GAP_SMALL
paddingHorizontal: 6
}}
/>
)}

View File

@@ -36,7 +36,6 @@ 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();
@@ -104,7 +103,7 @@ export const ChangePassword = () => {
<View
style={{
width: "100%",
padding: DefaultAppStyles.GAP
padding: 12
}}
>
<Dialog context="change-password-dialog" />
@@ -149,7 +148,7 @@ export const ChangePassword = () => {
<Button
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
width: "100%"
}}
loading={loading}

View File

@@ -20,20 +20,23 @@ 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 === AuthMode.welcomeSignup) {
Navigation.replace("FluidPanelsView");
} else {
Navigation.goBack();
}
// if (initialAuthMode.current === 2) {
// Navigation.replace(
// {
// name: 'Notes'
// },
// {
// menu: true
// }
// );
// } else {
// Navigation.goBack();
// }
// tabBarRef.current?.unlock();
}

View File

@@ -33,7 +33,6 @@ 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");
@@ -108,7 +107,7 @@ export const ForgotPassword = () => {
{sent ? (
<View
style={{
padding: DefaultAppStyles.GAP,
padding: 12,
justifyContent: "center",
alignItems: "center",
paddingBottom: 50
@@ -139,7 +138,7 @@ export const ForgotPassword = () => {
backgroundColor: colors.primary.background,
zIndex: 10,
width: "100%",
padding: DefaultAppStyles.GAP
padding: 12
}}
>
<DialogHeader title={strings.accountRecovery()} />
@@ -165,7 +164,7 @@ export const ForgotPassword = () => {
<Button
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
width: "100%"
}}
loading={loading}

View File

@@ -17,98 +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 { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React, { useState } from "react";
import { View } from "react-native";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import Navigation from "../../services/navigation";
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
import { Toast } from "../toast";
import { Button } from "../ui/button";
import { IconButton } from "../ui/icon-button";
import { AuthMode, initialAuthMode } from "./common";
import { initialAuthMode } from "./common";
import { Login } from "./login";
import { Signup } from "./signup";
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
import { DefaultAppStyles } from "../../utils/styles";
import { useSettingStore } from "../../stores/use-setting-store";
export const AuthMode = {
login: 0,
signup: 1,
welcomeSignup: 2,
trialSignup: 3
};
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, {});
useNavigationFocus(navigation, {
onFocus: () => {
//tabBarRef?.current.lock();
initialAuthMode.current = route?.params.mode || AuthMode.login;
}
});
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)}

View File

@@ -17,7 +17,6 @@ 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";
@@ -25,9 +24,10 @@ 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 { AppFontSize } from "../../utils/size";
import { SIZE } 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 { DefaultAppStyles } from "../../utils/styles";
import { strings } from "@notesnook/intl";
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,24 +96,23 @@ export const Login = ({ changeMode }) => {
backgroundColor: colors.primary.background,
zIndex: 10,
width: "100%",
height: "100%",
alignSelf: "center"
}}
>
<View
style={{
justifyContent: "flex-end",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 20,
backgroundColor: colors.secondary.background,
borderBottomWidth: 0.8,
marginBottom: DefaultAppStyles.GAP_VERTICAL,
marginBottom: 12,
borderBottomColor: colors.primary.border,
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%",
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%",
minHeight: height * 0.4
}}
>
@@ -144,10 +143,10 @@ export const Login = ({ changeMode }) => {
<Heading
style={{
marginBottom: 25,
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
extraBold
size={AppFontSize.xxl}
size={SIZE.xxl}
>
{strings.loginToYourAccount()}
</Heading>
@@ -164,7 +163,7 @@ export const Login = ({ changeMode }) => {
: "99.9%",
backgroundColor: colors.primary.background,
alignSelf: "center",
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 20
}}
>
<Input
@@ -217,7 +216,7 @@ export const Login = ({ changeMode }) => {
title={strings.forgotPassword()}
style={{
alignSelf: "flex-end",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
height: 30,
paddingHorizontal: 0
}}
onPress={() => {
@@ -227,7 +226,7 @@ export const Login = ({ changeMode }) => {
textStyle={{
textDecorationLine: "underline"
}}
fontSize={AppFontSize.xs}
fontSize={SIZE.xs}
type="plain"
/>
</>
@@ -245,8 +244,11 @@ export const Login = ({ changeMode }) => {
login();
}}
style={{
width: 250
width: 250,
borderRadius: 100
}}
height={50}
fontSize={SIZE.md}
type="accent"
title={!loading ? strings.continue() : null}
/>
@@ -256,16 +258,19 @@ export const Login = ({ changeMode }) => {
title={strings.cancelLogin()}
style={{
alignSelf: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
width: 250
height: 30,
marginTop: 10
}}
onPress={() => {
if (loading) return;
setStep(LoginSteps.emailAuth);
setLoading(false);
}}
fontSize={AppFontSize.xs}
type="secondaryAccented"
textStyle={{
textDecorationLine: "underline"
}}
fontSize={SIZE.xs}
type="errorShade"
/>
)}
@@ -278,17 +283,17 @@ export const Login = ({ changeMode }) => {
activeOpacity={0.8}
style={{
alignSelf: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
marginTop: 12,
paddingVertical: 12
}}
>
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs + 1}
color={colors.secondary.paragraph}
>
{strings.dontHaveAccount()}{" "}
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs + 1}
style={{ color: colors.primary.accent }}
>
{strings.signUp()}

View File

@@ -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 { AppFontSize } from "../../utils/size";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import { Dialog } from "../dialog";
import BaseDialog from "../dialog/base-dialog";
@@ -48,8 +48,18 @@ import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { LoginSteps, useLogin } from "./use-login";
import { strings } from "@notesnook/intl";
import { getObfuscatedEmail } from "../../utils/functions";
import { DefaultAppStyles } from "../../utils/styles";
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;
});
}
export const SessionExpired = () => {
const { colors } = useThemeColors();
@@ -158,7 +168,7 @@ export const SessionExpired = () => {
<View
style={{
width: focused ? "100%" : "99.9%",
padding: DefaultAppStyles.GAP,
padding: 12,
justifyContent: "center",
flex: 1,
backgroundColor: colors.primary.background
@@ -183,7 +193,7 @@ export const SessionExpired = () => {
color={colors.error.icon}
size={50}
/>
<Heading size={AppFontSize.xxxl} color={colors.primary.heading}>
<Heading size={SIZE.xxxl} color={colors.primary.heading}>
{strings.sessionExpired()}
</Heading>
<Paragraph
@@ -214,7 +224,7 @@ export const SessionExpired = () => {
<Button
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
width: 250,
borderRadius: 100
}}
@@ -226,7 +236,7 @@ export const SessionExpired = () => {
<Button
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
width: "100%"
}}
onPress={() => {

View File

@@ -17,8 +17,6 @@ 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";
@@ -26,17 +24,19 @@ import { DDS } from "../../services/device-detection";
import { ToastManager } from "../../services/event-manager";
import { clearMessage, setEmailVerifyMessage } from "../../services/message";
import PremiumService from "../../services/premium";
import SettingsService from "../../services/settings";
import { useThemeColors } from "@notesnook/theme";
import { useUserStore } from "../../stores/use-user-store";
import { openLinkInBrowser } from "../../utils/functions";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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 { DefaultAppStyles } from "../../utils/styles";
import { useSettingStore } from "../../stores/use-setting-store";
import SettingsService from "../../services/settings";
import { strings } from "@notesnook/intl";
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,24 +105,23 @@ export const Signup = ({ changeMode, trial }) => {
backgroundColor: colors.primary.background,
zIndex: 10,
width: "100%",
height: "100%",
alignSelf: "center"
}}
>
<View
style={{
justifyContent: "flex-end",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 20,
backgroundColor: colors.secondary.background,
marginBottom: 20,
borderBottomWidth: 0.8,
marginBottom: DefaultAppStyles.GAP_VERTICAL,
borderBottomColor: colors.primary.border,
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%",
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%",
minHeight: height * 0.4
}}
>
@@ -154,9 +153,9 @@ export const Signup = ({ changeMode, trial }) => {
extraBold
style={{
marginBottom: 25,
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
size={AppFontSize.xxl}
size={SIZE.xxl}
>
{strings.createYourAccount()}
</Heading>
@@ -165,7 +164,7 @@ export const Signup = ({ changeMode, trial }) => {
<View
style={{
width: DDS.isTab ? "50%" : "100%",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 20,
backgroundColor: colors.primary.background,
alignSelf: "center"
}}
@@ -234,12 +233,12 @@ export const Signup = ({ changeMode, trial }) => {
style={{
marginBottom: 25
}}
size={AppFontSize.xxs}
size={SIZE.xs}
color={colors.secondary.paragraph}
>
{strings.signupAgreement[0]()}
<Paragraph
size={AppFontSize.xxs}
size={SIZE.xs}
onPress={() => {
openLinkInBrowser("https://notesnook.com/tos", colors);
}}
@@ -248,12 +247,11 @@ export const Signup = ({ changeMode, trial }) => {
}}
color={colors.primary.accent}
>
{" "}
{strings.signupAgreement[1]()}
</Paragraph>{" "}
</Paragraph>
{strings.signupAgreement[2]()}
<Paragraph
size={AppFontSize.xxs}
size={SIZE.xs}
onPress={() => {
openLinkInBrowser("https://notesnook.com/privacy", colors);
}}
@@ -262,9 +260,8 @@ export const Signup = ({ changeMode, trial }) => {
}}
color={colors.primary.accent}
>
{" "}
{strings.signupAgreement[3]()}
</Paragraph>{" "}
</Paragraph>
{strings.signupAgreement[4]()}
</Paragraph>
@@ -273,8 +270,11 @@ export const Signup = ({ changeMode, trial }) => {
type="accent"
loading={loading}
onPress={signup}
fontSize={SIZE.md}
style={{
width: 250
marginRight: 12,
width: 250,
borderRadius: 100
}}
/>
@@ -286,14 +286,14 @@ export const Signup = ({ changeMode, trial }) => {
activeOpacity={0.8}
style={{
alignSelf: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
marginTop: 12,
paddingVertical: 12
}}
>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
<Paragraph size={SIZE.xs + 1} color={colors.secondary.paragraph}>
{strings.alreadyHaveAccount()}{" "}
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs + 1}
style={{ color: colors.primary.accent }}
>
{strings.login()}

View File

@@ -30,14 +30,13 @@ import {
ToastManager
} from "../../services/event-manager";
import { eCloseSheet } from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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();
@@ -205,9 +204,9 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
}}
onSubmitEditing={onNext}
caretHidden
height={60}
inputStyle={{
fontSize: AppFontSize.lg,
fontSize: SIZE.lg,
height: 60,
textAlign: "center",
letterSpacing: 10,
width: 250
@@ -217,13 +216,11 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
}
enablesReturnKeyAutomatically
containerStyle={{
height: 60,
borderWidth: 0,
width: undefined,
minWidth: "50%"
}}
wrapperStyle={{
height: 60
}}
/>
<Button
@@ -232,12 +229,9 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
width={250}
loading={loading}
onPress={onNext}
/>
<Button
title={strings.cancel()}
type="secondaryAccented"
onPress={onCancel}
width={250}
style={{
borderRadius: 100
}}
/>
<Button
@@ -248,6 +242,13 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
onPress={onRequestSecondaryMethod}
height={30}
/>
<Button
title={strings.cancel()}
type="plain"
onPress={onCancel}
height={30}
/>
</>
) : (
<>
@@ -261,8 +262,8 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
});
}}
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
paddingHorizontal: 12,
paddingVertical: 12,
marginTop: 0,
flexDirection: "row",
borderRadius: 0,
@@ -274,6 +275,8 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
<IconButton
type="secondaryAccented"
style={{
width: 40,
height: 40,
marginRight: 10
}}
size={15}
@@ -285,7 +288,7 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo, onCancel }) => {
flexShrink: 1
}}
>
<Paragraph size={AppFontSize.md}>{item.title}</Paragraph>
<Paragraph size={SIZE.md}>{item.title}</Paragraph>
</View>
</Pressable>
))}

View File

@@ -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, TouchableOpacity, View, ViewStyle } from "react-native";
import { Keyboard, View } from "react-native";
import Animated, {
Easing,
useAnimatedStyle,
@@ -33,31 +33,20 @@ 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 { AppFontSize, normalize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { hexToRGBA, RGB_Linear_Shade } from "../../utils/colors";
import { SIZE, normalize } from "../../utils/size";
import { Pressable } from "../ui/pressable";
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,
icon,
testID,
position = "right",
size = "large",
style
alwaysVisible = false
}: FloatingButtonProps) => {
const { colors } = useThemeColors();
const deviceMode = useSettingStore((state) => state.deviceMode);
@@ -119,26 +108,20 @@ const FloatingButton = ({
style={[
{
position: "absolute",
right: position === "right" ? DefaultAppStyles.GAP : undefined,
left: position === "left" ? DefaultAppStyles.GAP : undefined,
right: 12,
bottom: 20,
zIndex: 10,
...style
zIndex: 10
},
animatedStyle
]}
>
<TouchableOpacity
testID={testID || notesnook.buttons.add}
activeOpacity={0.95}
<Pressable
testID={notesnook.buttons.add}
type="accent"
accentColor={color}
style={{
...getElevationStyle(5),
borderRadius: size === "small" ? 15 : 20,
borderTopWidth: 0,
borderBottomWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 0,
backgroundColor: colors.primary.background
borderRadius: 100
}}
onPress={onPress}
>
@@ -146,29 +129,23 @@ const FloatingButton = ({
style={{
alignItems: "center",
justifyContent: "center",
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
height: normalize(60),
width: normalize(60)
}}
>
<Icon
name={
icon
? icon
: route.name === "Notebooks"
route.name === "Notebooks"
? "notebook-plus"
: route.name === "Trash"
? "delete"
: "plus"
}
color={color || colors.primary.accent}
size={size === "small" ? AppFontSize.xl : AppFontSize.xxxl}
color={colors.primary.accentForeground}
size={SIZE.xxl}
/>
</View>
</TouchableOpacity>
</Pressable>
</Animated.View>
);
};

View File

@@ -23,8 +23,6 @@ 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();
@@ -42,7 +40,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
<View
style={{
width: "100%",
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
{hasAnnoucements ? (
@@ -53,7 +51,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
borderRadius: 10,
marginBottom: 20,
backgroundColor: colors.secondary.background,
padding: DefaultAppStyles.GAP
padding: 12
}}
>
<View
@@ -61,7 +59,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
width: 150,
height: 20,
backgroundColor: colors.primary.hover,
borderRadius: defaultBorderRadius,
borderRadius: 5,
marginBottom: 10
}}
/>
@@ -70,7 +68,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
width: 250,
height: 14,
backgroundColor: colors.primary.hover,
borderRadius: defaultBorderRadius
borderRadius: 5
}}
/>
@@ -80,7 +78,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
height: 15,
backgroundColor: shadeColor,
borderRadius: 3,
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
/>
</View>
@@ -95,7 +93,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
marginBottom: 20,
flexDirection: "row",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 20
}}
>
<View
@@ -113,7 +111,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
width: 150,
height: 12,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius,
borderRadius: 5,
marginBottom: 10
}}
/>
@@ -122,7 +120,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
width: 250,
height: 16,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius
borderRadius: 5
}}
/>
</View>
@@ -136,7 +134,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
backgroundColor: colors.secondary.background,
borderRadius: 10,
marginBottom: 20,
padding: DefaultAppStyles.GAP_SMALL,
padding: 5,
justifyContent: "space-between",
flexDirection: "row",
alignItems: "center"
@@ -181,7 +179,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
width: 200,
height: 16,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius
borderRadius: 5
}}
/>
<View
@@ -189,15 +187,15 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
width: "85%",
height: 13,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius,
marginTop: DefaultAppStyles.GAP_VERTICAL
borderRadius: 5,
marginTop: 10
}}
/>
<View
style={{
flexDirection: "row",
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
>
<View
@@ -205,7 +203,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
width: 50,
height: 10,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius
borderRadius: 5
}}
/>
<View
@@ -213,7 +211,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
width: 60,
height: 10,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius,
borderRadius: 5,
marginLeft: 10
}}
/>

View File

@@ -17,10 +17,11 @@ 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 { View, ViewProps } from "react-native";
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 { DefaultPlaceholder } from "./default-placeholder";
import { SettingsPlaceholder } from "./settings-placeholder";
@@ -48,7 +49,8 @@ export default function DelayLayout({
const Placeholder = placeholder[props.type || "default"];
return loading || props.wait ? (
<View
<Animated.View
exiting={animated ? FadeOutUp : undefined}
style={{
backgroundColor: colors.primary.background,
flex: 1,
@@ -56,7 +58,7 @@ export default function DelayLayout({
}}
>
<Placeholder color={props.color || colors.primary.accent} />
</View>
</Animated.View>
) : (
<>{props.children}</>
);

View File

@@ -20,8 +20,6 @@ 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();
@@ -33,7 +31,7 @@ export const SettingsPlaceholder = () => {
width: 100,
height: 12,
backgroundColor: colors.primary.shade,
borderRadius: defaultBorderRadius,
borderRadius: 5,
marginLeft: 12,
marginBottom: 12
}}
@@ -46,7 +44,7 @@ export const SettingsPlaceholder = () => {
marginBottom: 20,
flexDirection: "row",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 16
}}
>
<View
@@ -64,7 +62,7 @@ export const SettingsPlaceholder = () => {
width: 150,
height: 12,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius,
borderRadius: 5,
marginBottom: 10
}}
/>
@@ -73,7 +71,7 @@ export const SettingsPlaceholder = () => {
width: 250,
height: 16,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius
borderRadius: 5
}}
/>
</View>
@@ -87,7 +85,7 @@ export const SettingsPlaceholder = () => {
marginBottom: 20,
flexDirection: "row",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 16,
justifyContent: "space-between"
}}
>
@@ -106,7 +104,7 @@ export const SettingsPlaceholder = () => {
width: 150,
height: 12,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius,
borderRadius: 5,
marginBottom: 10
}}
/>
@@ -115,7 +113,7 @@ export const SettingsPlaceholder = () => {
width: 250,
height: 16,
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius
borderRadius: 5
}}
/>
</View>

View File

@@ -17,7 +17,6 @@ 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,
@@ -31,8 +30,11 @@ import {
} from "react-native";
import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard";
import { useSettingStore } from "../../stores/use-setting-store";
import { useUserStore } from "../../stores/use-user-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";
export interface BaseDialogProps extends PropsWithChildren {
animation?: "fade" | "none" | "slide" | undefined;

View File

@@ -17,17 +17,16 @@ 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 { StyleSheet, View } from "react-native";
import { ActivityIndicator, StyleSheet, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { notesnook } from "../../../e2e/test.ids";
import { getColorLinearShade } from "../../utils/colors";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { useThemeColors } from "@notesnook/theme";
import { SIZE } from "../../utils/size";
import { Button } from "../ui/button";
import Paragraph from "../ui/typography/paragraph";
import { getColorLinearShade } from "../../utils/colors";
import { strings } from "@notesnook/intl";
const DialogButtons = ({
onPressPositive,
@@ -47,7 +46,9 @@ const DialogButtons = ({
{
backgroundColor: colors.secondary.background,
height: 60,
paddingHorizontal: DefaultAppStyles.GAP,
borderBottomRightRadius: 5,
borderBottomLeftRadius: 5,
paddingHorizontal: 12,
borderTopWidth: 0.7,
borderTopColor: getColorLinearShade(
colors.secondary.background,
@@ -57,7 +58,9 @@ const DialogButtons = ({
}
]}
>
{doneText ? (
{loading ? (
<ActivityIndicator color={colors.primary.accent} size={SIZE.lg} />
) : doneText ? (
<View
style={{
flexDirection: "row",
@@ -67,7 +70,7 @@ const DialogButtons = ({
<Icon
color={colors.primary.accent}
name="check-circle-outline"
size={AppFontSize.md}
size={SIZE.md}
/>
<Paragraph color={colors.primary.accent}>{" " + doneText}</Paragraph>
</View>
@@ -83,7 +86,7 @@ const DialogButtons = ({
>
<Button
onPress={onPressNegative}
fontSize={AppFontSize.sm}
fontSize={SIZE.md}
testID={notesnook.ids.default.dialog.no}
type="plain"
bold
@@ -92,12 +95,11 @@ const DialogButtons = ({
{onPressPositive ? (
<Button
onPress={onPressPositive}
fontSize={AppFontSize.sm}
fontSize={SIZE.md}
testID={notesnook.ids.default.dialog.yes}
style={{
marginLeft: 10
}}
loading={loading}
bold
type={positiveType || "transparent"}
title={positiveTitle}
@@ -115,6 +117,6 @@ const styles = StyleSheet.create({
justifyContent: "space-between",
alignItems: "center",
flexDirection: "row",
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}
});

View File

@@ -20,12 +20,11 @@ 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 { AppFontSize } from "../../utils/size";
import { SIZE } 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;
@@ -83,7 +82,7 @@ const DialogHeader = ({
>
<Heading
style={{ textAlign: centered ? "center" : "left" }}
size={AppFontSize.lg}
size={SIZE.lg}
>
{title}{" "}
{titlePart ? (
@@ -98,7 +97,7 @@ const DialogHeader = ({
onPress={button.onPress}
style={{
borderRadius: 100,
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
loading={button.loading}
fontSize={13}

View File

@@ -17,35 +17,33 @@ 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, useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import { View } from "react-native";
import { DDS } from "../../services/device-detection";
import {
eSubscribeEvent,
eUnSubscribeEvent
} from "../../services/event-manager";
import { getContainerBorder } from "../../utils/colors";
import { useThemeColors } from "@notesnook/theme";
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
});
@@ -74,23 +72,14 @@ export const Dialog = ({ context = "global" }) => {
const onPressPositive = async () => {
if (dialogInfo.positivePress) {
inputRef.current?.blur();
setLoading(true);
let result;
try {
result = await dialogInfo.positivePress(
values.current.inputValue || dialogInfo.defaultValue,
checked
);
} catch (e) {
/** Empty */
}
setLoading(false);
let result = await dialogInfo.positivePress(
values.current.inputValue || dialogInfo.defaultValue,
checked
);
if (result === false) {
return;
}
}
setChecked(false);
values.current.inputValue = undefined;
setVisible(false);
@@ -136,11 +125,10 @@ export const Dialog = ({ context = "global" }) => {
...getElevationStyle(5),
width: DDS.isTab ? 400 : "85%",
maxHeight: 450,
borderRadius: defaultBorderRadius,
borderRadius: 5,
backgroundColor: colors.primary.background,
paddingTop: 12,
...getContainerBorder(colors.primary.border, 0.5),
overflow: "hidden"
...getContainerBorder(colors.primary.border, 0.5)
};
return visible ? (
@@ -176,7 +164,7 @@ export const Dialog = ({ context = "global" }) => {
{dialogInfo.input ? (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
<Input
@@ -200,7 +188,7 @@ export const Dialog = ({ context = "global" }) => {
{dialogInfo?.notice ? (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
<Notice
@@ -221,7 +209,6 @@ export const Dialog = ({ context = "global" }) => {
? "check-circle-outline"
: "checkbox-blank-circle-outline"
}
iconColor={checked ? colors.secondary.icon : colors.primary.icon}
style={{
justifyContent: "flex-start"
}}
@@ -237,7 +224,6 @@ export const Dialog = ({ context = "global" }) => {
<DialogButtons
onPressNegative={onNegativePress}
onPressPositive={dialogInfo.positivePress && onPressPositive}
loading={loading}
positiveTitle={dialogInfo.positiveText}
negativeTitle={dialogInfo.negativeText}
positiveType={dialogInfo.positiveType}

View File

@@ -39,7 +39,7 @@ import {
eCloseAppLocKPasswordDailog,
eOpenAppLockPasswordDialog
} from "../../../utils/events";
import { AppFontSize } from "../../../utils/size";
import { SIZE } from "../../../utils/size";
import { sleep } from "../../../utils/time";
import BaseDialog from "../../dialog/base-dialog";
import DialogButtons from "../../dialog/dialog-buttons";
@@ -50,7 +50,6 @@ 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();
@@ -129,7 +128,7 @@ export const AppLockPassword = () => {
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
{mode === "change" ? (
@@ -193,7 +192,7 @@ export const AppLockPassword = () => {
height: 25,
marginRight: 5
}}
size={AppFontSize.lg}
size={SIZE.lg}
/>
)
}
@@ -249,7 +248,7 @@ export const AppLockPassword = () => {
setSecureTextEntry(true);
});
}}
iconSize={AppFontSize.lg}
iconSize={SIZE.lg}
type="plain"
iconColor={
accountPass ? colors.primary.accent : colors.primary.icon
@@ -260,7 +259,7 @@ export const AppLockPassword = () => {
alignSelf: "flex-start",
justifyContent: "flex-start",
paddingHorizontal: 0,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
height: 30
}}
/>
</>

View File

@@ -27,13 +27,12 @@ import {
import { Image as ImageType } from "react-native-image-crop-picker";
import { useThemeColors } from "@notesnook/theme";
import { presentSheet } from "../../../services/event-manager";
import { defaultBorderRadius, AppFontSize } from "../../../utils/size";
import { SIZE } 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,
@@ -51,26 +50,21 @@ export default function AttachImage({
<View
style={{
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
<View
style={{
backgroundColor: colors.secondary.background,
marginBottom: DefaultAppStyles.GAP_VERTICAL,
marginBottom: 12,
height: 140,
width: "100%",
borderRadius: 10,
padding: DefaultAppStyles.GAP_SMALL,
paddingHorizontal: DefaultAppStyles.GAP_SMALL
padding: 5,
paddingHorizontal: 12
}}
>
<Paragraph
style={{
color: colors.primary.paragraph,
marginBottom: DefaultAppStyles.GAP_VERTICAL_SMALL
}}
>
<Paragraph style={{ color: colors.primary.paragraph, marginBottom: 6 }}>
{strings.attachImageHeading(response?.length || 1)}
</Paragraph>
<ScrollView horizontal>
@@ -86,7 +80,7 @@ export default function AttachImage({
style={{
width: 100,
height: 100,
borderRadius: defaultBorderRadius,
borderRadius: 5,
backgroundColor: "black",
marginRight: 6
}}
@@ -102,7 +96,7 @@ export default function AttachImage({
style={{
flexDirection: "row",
alignSelf: "center",
marginBottom: DefaultAppStyles.GAP_VERTICAL,
marginBottom: 12,
alignItems: "center",
width: "100%"
}}
@@ -111,7 +105,7 @@ export default function AttachImage({
}}
>
<IconButton
size={AppFontSize.lg}
size={SIZE.lg}
name={compress ? "checkbox-marked" : "checkbox-blank-outline"}
color={compress ? colors.primary.accent : colors.primary.icon}
style={{
@@ -128,7 +122,7 @@ export default function AttachImage({
flexShrink: 1,
marginLeft: 3
}}
size={AppFontSize.sm}
size={SIZE.sm}
>
{strings.compress()} ({strings.recommended().toLowerCase()})
</Paragraph>
@@ -141,7 +135,7 @@ export default function AttachImage({
size="small"
style={{
width: "100%",
marginBottom: DefaultAppStyles.GAP_VERTICAL
marginBottom: 12
}}
/>
) : (
@@ -151,7 +145,7 @@ export default function AttachImage({
size="small"
style={{
width: "100%",
marginBottom: DefaultAppStyles.GAP_VERTICAL
marginBottom: 12
}}
/>
)}

View File

@@ -34,7 +34,6 @@ 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})$/;
@@ -106,16 +105,16 @@ const ColorPicker = ({
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
<View
style={{
flexDirection: "row",
alignItems: "center",
paddingTop: DefaultAppStyles.GAP_VERTICAL,
columnGap: DefaultAppStyles.GAP_VERTICAL,
marginBottom: DefaultAppStyles.GAP_VERTICAL
paddingTop: 10,
columnGap: 10,
marginBottom: 10
}}
>
<Input
@@ -156,7 +155,7 @@ const ColorPicker = ({
<Button
title={strings.addColor()}
style={{
marginBottom: DefaultAppStyles.GAP_VERTICAL
marginBottom: 10
}}
onPress={async () => {
if (!selectedColor)

View File

@@ -39,11 +39,10 @@ import {
eOpenJumpToDialog,
eScrollEvent
} from "../../../utils/events";
import { AppFontSize } from "../../../utils/size";
import { SIZE } 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>>();
@@ -153,13 +152,13 @@ const JumpToSectionDialog = () => {
maxHeight: "65%",
borderRadius: 10,
alignSelf: "center",
padding: DefaultAppStyles.GAP_SMALL,
padding: 10,
paddingTop: 30
}}
>
{loading ? (
<ActivityIndicator
size={AppFontSize.lg}
size={SIZE.lg}
color={colors.primary.accent}
style={{
marginBottom: 20
@@ -189,15 +188,15 @@ const JumpToSectionDialog = () => {
style={{
minWidth: "20%",
width: null,
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
margin: 5,
borderRadius: 100,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
height: 30,
marginVertical: 10
}}
>
<Paragraph
size={AppFontSize.sm}
size={SIZE.sm}
color={
currentIndex === index
? colors.static.white

View File

@@ -28,7 +28,6 @@ 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();
@@ -68,7 +67,7 @@ export const LoadingDialog = () => {
style={{
flexDirection: "row",
width: 100,
marginTop: DefaultAppStyles.GAP
marginTop: 15
}}
>
<ProgressBarComponent

View File

@@ -19,7 +19,10 @@ 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 Orientation from "react-native-orientation-locker";
import {
addOrientationListener,
removeOrientationListener
} from "react-native-orientation";
import Pdf from "react-native-pdf";
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
import downloadAttachment from "../../../common/filesystem/download-attachment";
@@ -31,7 +34,7 @@ import {
eUnSubscribeEvent
} from "../../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { AppFontSize } from "../../../utils/size";
import { SIZE } from "../../../utils/size";
import { Dialog } from "../../dialog";
import BaseDialog from "../../dialog/base-dialog";
import { presentDialog } from "../../dialog/functions";
@@ -43,7 +46,6 @@ 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;
@@ -96,9 +98,9 @@ const PDFPreview = () => {
};
useEffect(() => {
Orientation.addDeviceOrientationListener(onOrientationChange);
addOrientationListener(onOrientationChange);
return () => {
Orientation.removeDeviceOrientationListener(onOrientationChange);
removeOrientationListener(onOrientationChange);
};
}, []);
@@ -182,7 +184,7 @@ const PDFPreview = () => {
/>
<Paragraph
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
color={colors.static.white}
>
@@ -198,7 +200,7 @@ const PDFPreview = () => {
marginTop: insets.top,
flexDirection: "row",
justifyContent: "space-between",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
paddingLeft: 6
}}
>
@@ -214,7 +216,7 @@ const PDFPreview = () => {
style={{
marginRight: 12
}}
size={AppFontSize.xxl}
size={SIZE.xxl}
/>
</View>

View File

@@ -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 { AppFontSize } from "../../../utils/size";
import { SIZE } from "../../../utils/size";
import { Dialog } from "../../dialog";
import BaseDialog from "../../dialog/base-dialog";
import DialogContainer from "../../dialog/dialog-container";
@@ -29,7 +29,6 @@ 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;
@@ -112,7 +111,7 @@ export default function Progress() {
>
<DialogContainer
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
paddingBottom: 10
}}
noBorder={data?.fillBackground ? true : false}
@@ -122,7 +121,7 @@ export default function Progress() {
style={{
justifyContent: "center",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
gap: 10,
paddingBottom: 20
}}
@@ -132,7 +131,7 @@ export default function Progress() {
textAlign: "center"
}}
color={colors.primary.paragraph}
size={AppFontSize.lg}
size={SIZE.lg}
>
{data?.title}
</Heading>
@@ -149,7 +148,7 @@ export default function Progress() {
style={{
flexDirection: "row",
width: 100,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingVertical: 12
}}
>
<ProgressBarComponent

View File

@@ -27,14 +27,13 @@ import {
import { useThemeColors } from "@notesnook/theme";
import { getElevationStyle } from "../../../utils/elevation";
import { eCloseResultDialog, eOpenResultDialog } from "../../../utils/events";
import { AppFontSize } from "../../../utils/size";
import { SIZE } 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();
@@ -79,15 +78,15 @@ const ResultDialog = () => {
}}
>
<Heading
size={AppFontSize.lg}
size={SIZE.lg}
textBreakStrategy="balanced"
style={{
alignSelf: "center",
textAlign: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
maxWidth: "100%",
marginBottom: DefaultAppStyles.GAP_VERTICAL,
paddingHorizontal: DefaultAppStyles.GAP
marginBottom: 10,
paddingHorizontal: 12
}}
>
{dialogData.title}
@@ -95,12 +94,12 @@ const ResultDialog = () => {
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.md}
size={SIZE.md}
style={{
alignSelf: "center",
textAlign: "center",
maxWidth: "80%",
lineHeight: AppFontSize.sm + 5
lineHeight: SIZE.sm + 5
}}
>
{dialogData.paragraph}
@@ -110,7 +109,7 @@ const ResultDialog = () => {
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
alignItems: "center",
width: "100%"
}}
@@ -125,17 +124,17 @@ const ResultDialog = () => {
width: "100%",
borderBottomRightRadius: 10,
borderBottomLeftRadius: 10,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingVertical: 10
}}
>
<Button
title={dialogData.button}
width={null}
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
onPress={close}
fontSize={AppFontSize.md + 2}
fontSize={SIZE.md + 2}
/>
</View>
</View>

View File

@@ -27,10 +27,9 @@ import {
eCloseResultDialog,
eOpenPremiumDialog
} from "../../../utils/events";
import { defaultBorderRadius, AppFontSize } from "../../../utils/size";
import { SIZE } 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();
@@ -68,17 +67,13 @@ export const ProFeatures = ({ count = 6 }) => {
width: "100%",
height: 40,
paddingHorizontal: 0,
marginBottom: DefaultAppStyles.GAP_VERTICAL,
marginBottom: 10,
alignItems: "center",
borderRadius: defaultBorderRadius,
borderRadius: 5,
justifyContent: "flex-start"
}}
>
<Icon
size={AppFontSize.lg}
color={colors.primary.accent}
name="check"
/>
<Icon size={SIZE.lg} color={colors.primary.accent} name="check" />
<Paragraph style={{ marginLeft: 5, flexShrink: 1 }}>
{item.content}
</Paragraph>
@@ -91,7 +86,7 @@ export const ProFeatures = ({ count = 6 }) => {
await sleep(300);
eSendEvent(eOpenPremiumDialog);
}}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
textDecorationLine: "underline",
color: colors.secondary.paragraph

View File

@@ -41,7 +41,7 @@ import {
eUpdateNoteInEditor
} from "../../../utils/events";
import { deleteItems } from "../../../utils/functions";
import { fluidTabsRef } from "../../../utils/global-refs";
import { tabBarRef } from "../../../utils/global-refs";
import { convertNoteToText } from "../../../utils/note-to-text";
import { sleep } from "../../../utils/time";
import BaseDialog from "../../dialog/base-dialog";
@@ -53,7 +53,6 @@ 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) {
@@ -554,7 +553,7 @@ export class VaultDialog extends Component {
item: note
});
if (!DDS.isTab) {
fluidTabsRef.current?.goToPage("editor");
tabBarRef.current?.goToPage(1);
}
});
}
@@ -678,7 +677,7 @@ export class VaultDialog extends Component {
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
{(novault ||
@@ -751,7 +750,7 @@ export class VaultDialog extends Component {
: "checkbox-blank-circle-outline"
}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
width="100%"
title={strings.deleteAllNotes()}
@@ -848,7 +847,7 @@ export class VaultDialog extends Component {
});
}}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
icon="fingerprint"
width="100%"

View File

@@ -17,52 +17,60 @@ 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 { View } from "react-native";
import { Platform, StyleSheet, View } from "react-native";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import {
eSubscribeEvent,
eUnSubscribeEvent
} from "../../services/event-manager";
import { RouteName } from "../../stores/use-navigation-store";
import useNavigationStore, {
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,
rightButton
onSearch
}: {
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 [selectedItemsList, selectionMode] = useSelectionStore((state) => [
state.selectedItemsList,
state.selectionMode
]);
const selectionMode = useSelectionStore((state) => state.selectionMode);
const isFocused = useNavigationStore((state) => state.focusedRouteId === id);
const onScroll = useCallback(
(data: { x: number; y: number; id?: string; route: string }) => {
@@ -85,48 +93,88 @@ export const Header = ({
};
}, [borderHidden, onScroll]);
const HeaderWrapper = hasSearch ? Pressable : 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?.();
}}
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"
}
]}
>
<LeftMenus
canGoBack={canGoBack}
onLeftButtonPress={onLeftMenuButtonPress}
/>
<>
<View style={styles.leftBtnContainer}>
<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>
<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>
</>
);
};
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
}
});

View File

@@ -20,9 +20,10 @@ 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 { fluidTabsRef } from "../../utils/global-refs";
import { tabBarRef } from "../../utils/global-refs";
import { IconButton } from "../ui/icon-button";
export const LeftMenus = ({
@@ -40,7 +41,7 @@ export const LeftMenus = ({
if (onLeftButtonPress) return onLeftButtonPress();
if (!canGoBack) {
if (fluidTabsRef.current?.isDrawerOpen()) {
if (tabBarRef.current?.isDrawerOpen()) {
Navigation.closeDrawer();
} else {
Navigation.openDrawer();
@@ -53,14 +54,23 @@ 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.icon}
color={colors.primary.paragraph}
/>
);
};

View File

@@ -17,30 +17,127 @@ 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 React from "react";
import { StyleSheet, View } from "react-native";
import { IconButton, IconButtonProps } from "../ui/icon-button";
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";
export const RightMenus = ({
rightButton
headerRightButtons,
renderedInRoute,
id,
onPressDefaultRightButton,
search,
onSearch
}: {
rightButton?: IconButtonProps;
headerRightButtons?: HeaderRightButton[];
renderedInRoute?: RouteName;
id?: string;
onPressDefaultRightButton?: () => void;
search?: boolean;
onSearch?: () => void;
}) => {
const { colors } = useThemeColors();
const { colors: contextMenuColors } = useThemeColors("contextMenu");
const deviceMode = useSettingStore((state) => state.deviceMode);
const menuRef = useRef<Menu>(null);
return (
<View style={styles.rightBtnContainer}>
{rightButton ? (
<IconButton {...rightButton} color={colors.primary.icon} />
) : (
<View
{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
}}
style={{
width: 40,
height: 40
marginLeft: 10,
width: 32,
height: 32,
borderRadius: 100,
paddingHorizontal: 0,
borderWidth: 1,
borderColor: colors.primary.accent
}}
/>
)}
) : 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>
);
};
@@ -52,6 +149,10 @@ const styles = StyleSheet.create({
},
rightBtn: {
justifyContent: "center",
alignItems: "center"
alignItems: "center",
height: 40,
width: 40,
marginLeft: 10,
paddingRight: 0
}
});

View File

@@ -25,7 +25,7 @@ import {
eUnSubscribeEvent
} from "../../services/event-manager";
import { eScrollEvent } from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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={AppFontSize.lg}
size={SIZE.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={AppFontSize.xl} color={colors.primary.accent}>
<Heading size={SIZE.xl} color={colors.primary.accent}>
#
</Heading>
) : null}

View File

@@ -38,7 +38,6 @@ 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");
@@ -125,7 +124,7 @@ const ImagePreview = () => {
justifyContent: "flex-end",
alignItems: "center",
height: 50,
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
gap: 10
}}
>

View File

@@ -23,28 +23,31 @@ 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 { AppFontSize } from "../../utils/size";
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 { 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 = () => {
const Intro = ({ navigation }) => {
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: (typeof strings.introData)[0] }) => (
({ item }) => (
<View
style={{
justifyContent: "center",
width: isTablet ? width / 2 : width,
paddingHorizontal: isTablet ? (width / 2) * 0.05 : width * 0.05
width: deviceMode !== "mobile" ? width / 2 : width,
paddingHorizontal:
deviceMode !== "mobile" ? (width / 2) * 0.05 : width * 0.05
}}
>
<View
@@ -73,7 +76,7 @@ const Intro = () => {
</View>
<View
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
maxWidth: "90%",
width: "100%"
}}
@@ -85,21 +88,21 @@ const Intro = () => {
marginBottom: 5
}}
extraBold
size={AppFontSize.xxl}
size={SIZE.xxl}
>
{heading()}
</Heading>
))}
{item.body ? (
<Paragraph size={AppFontSize.sm}>{item.body()}</Paragraph>
<Paragraph size={SIZE.sm}>{item.body()}</Paragraph>
) : null}
{item.tesimonial ? (
<Paragraph
style={{
fontStyle: "italic",
fontSize: AppFontSize.lg
fontSize: SIZE.lg
}}
onPress={() => {
Linking.openURL(item.link);
@@ -111,37 +114,31 @@ const Intro = () => {
</View>
</View>
),
[colors.primary.accent, colors.secondary.background, isTablet, width]
[colors.primary.accent, colors.secondary.background, deviceMode, width]
);
return (
<ScrollView
testID="notesnook.splashscreen"
style={{
width: "100%",
backgroundColor: colors.primary.background
width: "100%"
}}
>
<View
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
}
]}
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)
}}
>
<SwiperFlatList
autoplay
@@ -173,12 +170,23 @@ const Intro = () => {
<Button
width={250}
onPress={async () => {
SettingsService.set({ introCompleted: true });
Navigation.push("Auth", {
mode: AuthMode.welcomeSignup
});
eSendEvent(eOpenLoginDialog, AuthMode.welcomeSignup);
setTimeout(() => {
SettingsService.set({
introCompleted: true
});
Navigation.replace("Notes", {
canGoBack: false
});
}, 1000);
}}
fontSize={AppFontSize.md}
style={{
paddingHorizontal: 24,
alignSelf: "center",
...getElevationStyle(5),
borderRadius: 100
}}
fontSize={SIZE.md}
type="accent"
title={strings.getStarted()}
/>

File diff suppressed because one or more lines are too long

View File

@@ -24,13 +24,12 @@ 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?: keyof RouteParams;
screen?: string;
shouldShow?: boolean;
};
@@ -51,11 +50,19 @@ 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}
</>
);

View File

@@ -17,115 +17,140 @@ 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 from "react";
import React, { useState } from "react";
import { View } from "react-native";
import { AppFontSize } from "../../../utils/size";
import { DefaultAppStyles } from "../../../utils/styles";
import AppIcon from "../../ui/AppIcon";
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 Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import { IconButton } from "../../ui/icon-button";
import { Pressable } from "../../ui/pressable";
import NotebookScreen from "../../../screens/notebook";
import { db } from "../../../common/database";
import { getFormattedDate } from "@notesnook/common";
import { strings } from "@notesnook/intl";
export const NotebookHeader = ({
notebook,
totalNotes = 0,
breadcrumbs
onEditNotebook,
totalNotes = 0
}: {
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={{
paddingHorizontal: DefaultAppStyles.GAP,
marginTop: DefaultAppStyles.GAP,
backgroundColor: colors.secondary.background
marginBottom: 5,
padding: 0,
width: "100%",
paddingVertical: 15,
paddingHorizontal: 12,
alignSelf: "center",
borderRadius: 10,
paddingTop: 25
}}
>
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
{getFormattedDate(notebook.dateModified, "date-time")}
</Paragraph>
<View
style={{
width: "100%",
gap: DefaultAppStyles.GAP_VERTICAL,
paddingVertical: DefaultAppStyles.GAP
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
}}
>
{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>
<Heading
style={{
flexShrink: 1
}}
size={SIZE.lg}
>
{notebook.title}
</Heading>
<View
style={{
flexDirection: "row",
gap: DefaultAppStyles.GAP_SMALL
flexDirection: "row"
}}
>
<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>
<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
}}
/>
</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>
);
};

View File

@@ -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 { View } from "react-native";
import { TouchableOpacity, View, useWindowDimensions } 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 { AppFontSize } from "../../../utils/size";
import { DefaultAppStyles } from "../../../utils/styles";
import { getContainerBorder } from "../../../utils/colors";
import { SIZE } from "../../../utils/size";
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,6 +56,8 @@ 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"
);
@@ -63,126 +65,104 @@ export const SectionHeader = React.memo<
return (
<View
style={{
width: "100%",
paddingHorizontal: DefaultAppStyles.GAP,
marginBottom: DefaultAppStyles.GAP_VERTICAL
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)
}}
>
<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",
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
alignItems: "center"
}}
>
<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>
{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"
/>
<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>
<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>
</View>
);

View File

@@ -29,32 +29,24 @@ import { EntityLevel, decode } from "entities";
import React from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
import useNavigationStore, {
RouteParams
} from "../../../stores/use-navigation-store";
import { useRelationStore } from "../../../stores/use-relation-store";
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 { 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 { useRelationStore } from "../../../stores/use-relation-store";
import { SIZE } from "../../../utils/size";
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { DefaultAppStyles } from "../../../utils/styles";
import { NotebooksWithDateEdited, TagsWithDateEdited } from "@notesnook/common";
import { Properties } from "../../properties";
import AppIcon from "../../ui/AppIcon";
import { Button } from "../../ui/button";
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 dayjs from "dayjs";
import { strings } from "@notesnook/intl";
type NoteItemProps = {
item: Note | BaseTrashItem<Note>;
@@ -68,7 +60,6 @@ type NoteItemProps = {
isTrash?: boolean;
noOpen?: boolean;
locked?: boolean;
renderedInRoute?: keyof RouteParams;
};
const NoteItem = ({
@@ -81,8 +72,7 @@ const NoteItem = ({
tags,
attachmentsCount,
locked,
noOpen = false,
renderedInRoute
noOpen = false
}: NoteItemProps) => {
const isEditingNote = useTabStore(
(state) =>
@@ -95,8 +85,7 @@ 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
@@ -105,27 +94,69 @@ const NoteItem = ({
flexShrink: 1
}}
>
{compactMode ? null : (
<Paragraph
{!compactMode ? (
<View
style={{
fontSize: AppFontSize.xxxs,
color: colors.secondary.paragraph
flexDirection: "row",
alignItems: "center",
zIndex: 10,
elevation: 10,
marginBottom: 2.5,
flexWrap: "wrap"
}}
>
{getFormattedDate(
date,
dayjs(date).isBefore(dayjs().subtract(1, "day").hour(23))
? "date"
: "time"
)}
</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}
{compactMode ? (
<Paragraph
numberOfLines={1}
color={color?.colorCode || primaryColors.heading}
size={AppFontSize.sm}
size={SIZE.sm}
style={{
paddingRight: 10
}}
@@ -136,7 +167,7 @@ const NoteItem = ({
<Heading
numberOfLines={1}
color={color?.colorCode || primaryColors.heading}
size={AppFontSize.sm}
size={SIZE.md}
style={{
paddingRight: 10
}}
@@ -166,10 +197,8 @@ const NoteItem = ({
justifyContent: "flex-start",
alignItems: "center",
width: "100%",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
columnGap: 8,
rowGap: 4,
flexWrap: "wrap"
marginTop: 5,
height: SIZE.md + 2
}}
>
{!isTrash ? (
@@ -177,7 +206,10 @@ const NoteItem = ({
{item.conflicted ? (
<Icon
name="alert-circle"
size={AppFontSize.sm}
style={{
marginRight: 6
}}
size={SIZE.sm}
color={colors.error.accent}
/>
) : null}
@@ -186,7 +218,10 @@ const NoteItem = ({
<Icon
testID="sync-off"
name="sync-off"
size={AppFontSize.sm}
size={SIZE.sm}
style={{
marginRight: 6
}}
color={primaryColors.icon}
/>
) : null}
@@ -195,27 +230,41 @@ const NoteItem = ({
<Icon
testID="pencil-lock"
name="pencil-lock"
size={AppFontSize.sm}
size={SIZE.sm}
style={{
marginRight: 6
}}
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={AppFontSize.sm}
size={SIZE.sm}
color={primaryColors.icon}
/>
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.xxs}
size={SIZE.xs}
>
{attachmentsCount}
</Paragraph>
@@ -226,7 +275,10 @@ const NoteItem = ({
<Icon
testID="icon-pinned"
name="pin-outline"
size={AppFontSize.sm}
size={SIZE.sm}
style={{
marginRight: 6
}}
color={color?.colorCode || primaryColors.accent}
/>
) : null}
@@ -235,7 +287,10 @@ const NoteItem = ({
<Icon
name="lock"
testID="note-locked-icon"
size={AppFontSize.sm}
size={SIZE.sm}
style={{
marginRight: 6
}}
color={primaryColors.icon}
/>
) : null}
@@ -244,83 +299,37 @@ const NoteItem = ({
<Icon
testID="icon-star"
name="star-outline"
size={AppFontSize.sm}
size={SIZE.sm}
style={{
marginRight: 6
}}
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 ? (
<View
<Button
title={"#" + item.title}
key={item.id}
style={{
borderRadius: 4,
backgroundColor: colors.secondary.background,
paddingHorizontal: DefaultAppStyles.GAP_SMALL / 2,
borderWidth: 0.5,
borderColor:
color?.colorCode || primaryColors.border,
paddingVertical: 1
height={23}
type="plain"
textStyle={{
textDecorationLine: "underline",
color: colors.secondary.paragraph
}}
>
<Paragraph
size={AppFontSize.xxxs}
color={colors.secondary.paragraph}
>
#{item.title}
</Paragraph>
</View>
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
}}
onPress={() => TaggedNotes.navigate(item, true)}
/>
) : null
)
: null}
@@ -329,7 +338,7 @@ const NoteItem = ({
<>
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.xxs}
size={SIZE.xs}
style={{
marginRight: 6
}}
@@ -343,7 +352,7 @@ const NoteItem = ({
<Paragraph
color={primaryColors.accent}
size={AppFontSize.xxs}
size={SIZE.xs}
style={{
marginRight: 6
}}
@@ -369,7 +378,7 @@ const NoteItem = ({
style={{
marginRight: 6
}}
size={AppFontSize.sm}
size={SIZE.sm}
color={colors.error.accent}
/>
) : null}
@@ -378,11 +387,11 @@ const NoteItem = ({
<Icon
name="lock"
testID="note-locked-icon"
size={AppFontSize.sm}
size={SIZE.sm}
style={{
marginRight: 6
}}
color={primaryColors.icon}
color={colors.secondary.background}
/>
) : null}
@@ -390,17 +399,17 @@ const NoteItem = ({
<Icon
testID="icon-star"
name="star-outline"
size={AppFontSize.sm}
size={SIZE.sm}
style={{
marginRight: 6
}}
color={colors.static.orange}
color="orange"
/>
) : null}
<TimeSince
style={{
fontSize: AppFontSize.xxs,
fontSize: SIZE.xs,
color: colors.secondary.paragraph,
marginRight: 6
}}
@@ -410,39 +419,20 @@ const NoteItem = ({
</>
) : null}
{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"
}}
/>
)}
<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"
}}
/>
</View>
</>
);

View File

@@ -29,12 +29,11 @@ import {
presentSheet
} from "../../../services/event-manager";
import { eOnLoadNote, eShowMergeDialog } from "../../../utils/events";
import { fluidTabsRef } from "../../../utils/global-refs";
import { tabBarRef } 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,
@@ -67,7 +66,7 @@ export const openNote = async (
item: note
});
if (!DDS.isTab) {
fluidTabsRef.current?.goToPage("editor");
tabBarRef.current?.goToPage(1);
}
}
};
@@ -83,7 +82,6 @@ type NoteWrapperProps = {
date: number;
isRenderedInActionSheet: boolean;
locked?: boolean;
renderedInRoute?: keyof RouteParams;
};
export const NoteWrapper = React.memo<
@@ -103,7 +101,6 @@ 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} />

View File

@@ -19,22 +19,18 @@ 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 useIsSelected from "../../../hooks/use-selected";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { AppFontSize } from "../../../utils/size";
import { SIZE } 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 { DefaultAppStyles } from "../../../utils/styles";
import { strings } from "@notesnook/intl";
type NotebookItemProps = {
item: Notebook | BaseTrashItem<Notebook>;
@@ -54,8 +50,6 @@ export const NotebookItem = ({
const compactMode = useIsCompactModeEnabled(
(item as TrashItem).itemType || item.type
);
const selectionMode = useSelectionStore((state) => state.selectionMode);
const [selected] = useIsSelected(item);
return (
<>
@@ -67,7 +61,7 @@ export const NotebookItem = ({
>
{compactMode ? (
<Paragraph
size={AppFontSize.sm}
size={SIZE.sm}
numberOfLines={1}
style={{
flexWrap: "wrap"
@@ -77,7 +71,7 @@ export const NotebookItem = ({
</Paragraph>
) : (
<Heading
size={AppFontSize.md}
size={SIZE.md}
numberOfLines={1}
style={{
flexWrap: "wrap"
@@ -89,7 +83,7 @@ export const NotebookItem = ({
{!item.description || compactMode ? null : (
<Paragraph
size={AppFontSize.sm}
size={SIZE.sm}
numberOfLines={2}
style={{
flexWrap: "wrap"
@@ -105,15 +99,15 @@ export const NotebookItem = ({
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
height: AppFontSize.md + 2
marginTop: 5,
height: SIZE.md + 2
}}
>
{isTrash ? (
<>
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
textAlignVertical: "center",
marginRight: 6
@@ -127,7 +121,7 @@ export const NotebookItem = ({
</Paragraph>
<Paragraph
color={colors.primary.accent}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
textAlignVertical: "center",
marginRight: 6
@@ -140,7 +134,7 @@ export const NotebookItem = ({
) : (
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
marginRight: 6
}}
@@ -150,7 +144,7 @@ export const NotebookItem = ({
)}
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
marginRight: 6
}}
@@ -161,7 +155,7 @@ export const NotebookItem = ({
{item.pinned ? (
<Icon
name="pin-outline"
size={AppFontSize.sm}
size={SIZE.sm}
style={{
marginRight: 10,
marginTop: 2
@@ -182,7 +176,7 @@ export const NotebookItem = ({
<>
<Paragraph
color={colors.primary.icon}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
marginRight: 6
}}
@@ -191,39 +185,21 @@ export const NotebookItem = ({
</Paragraph>
</>
) : null}
{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"
}}
/>
)}
<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"
}}
/>
</View>
</>
);

View File

@@ -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 { defaultBorderRadius, AppFontSize } from "../../../utils/size";
import { SIZE } from "../../../utils/size";
import { Properties } from "../../properties";
import ReminderSheet from "../../sheets/reminder";
import { IconButton } from "../../ui/icon-button";
@@ -31,10 +31,6 @@ 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(
({
@@ -52,8 +48,6 @@ 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
@@ -68,7 +62,7 @@ const ReminderItem = React.memo(
style={{
flexWrap: "wrap"
}}
size={AppFontSize.md}
size={SIZE.md}
>
{item.title}
</Heading>
@@ -88,18 +82,18 @@ const ReminderItem = React.memo(
style={{
flexDirection: "row",
flexWrap: "wrap",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
marginTop: 5
}}
>
{item.disabled ? (
<View
style={{
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius,
borderRadius: 5,
flexDirection: "row",
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
paddingHorizontal: 6,
alignItems: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
marginTop: 5,
justifyContent: "flex-start",
alignSelf: "flex-start",
marginRight: 10,
@@ -108,11 +102,11 @@ const ReminderItem = React.memo(
>
<Icon
name="bell-off-outline"
size={AppFontSize.md}
size={SIZE.md}
color={colors.error.icon}
/>
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs}
color={colors.secondary.paragraph}
style={{ marginLeft: 5 }}
>
@@ -124,24 +118,24 @@ const ReminderItem = React.memo(
<View
style={{
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius,
borderRadius: 5,
flexDirection: "row",
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
paddingHorizontal: 6,
alignItems: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
marginTop: 5,
justifyContent: "flex-start",
alignSelf: "flex-start",
marginRight: DefaultAppStyles.GAP_SMALL,
marginRight: 10,
height: 30
}}
>
<Icon
name="reload"
size={AppFontSize.md}
size={SIZE.md}
color={colors.primary.accent}
/>
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs}
color={colors.secondary.paragraph}
style={{ marginLeft: 5 }}
>
@@ -153,49 +147,29 @@ const ReminderItem = React.memo(
<ReminderTime
reminder={item}
checkIsActive={false}
fontSize={AppFontSize.xxs}
fontSize={SIZE.xs}
style={{
justifyContent: "flex-start",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
height: 25,
alignSelf: "flex-start"
}}
/>
</View>
</View>
{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"
}}
/>
)}
<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"
}}
/>
</SelectionWrapper>
);
},

View File

@@ -39,15 +39,16 @@ export const Filler = ({ item, color }: { item: Item; color?: string }) => {
style={{
position: "absolute",
width: "110%",
height: "100%",
backgroundColor: colors.selected.accent
// borderLeftWidth: 5,
// borderLeftColor: isEditingNote
// ? color
// ? color
// : colors.selected.accent
// : "transparent"
height: "150%",
backgroundColor: colors.selected.background,
borderLeftWidth: 5,
borderLeftColor: isEditingNote
? color
? color
: colors.selected.accent
: "transparent"
}}
collapsable={false}
/>
) : null;
};

View File

@@ -17,15 +17,14 @@ 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 { View } from "react-native";
import { Filler } from "./back-fill";
import { SelectionIcon } from "./selection";
import { Item, TrashItem } from "@notesnook/core";
export function selectItem(item: Item) {
if (useSelectionStore.getState().selectionMode === item.type) {
@@ -50,7 +49,6 @@ type SelectionWrapperProps = PropsWithChildren<{
testID?: string;
isSheet?: boolean;
color?: string;
index?: number;
}>;
const SelectionWrapper = ({
@@ -59,16 +57,10 @@ const SelectionWrapper = ({
testID,
isSheet,
children,
color,
index = 0
color
}: 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
);
@@ -87,13 +79,7 @@ const SelectionWrapper = ({
return (
<Pressable
customColor={
isEditingNote
? colors.selected.background
: isSheet
? colors.primary.hover
: "transparent"
}
customColor={isSheet ? colors.secondary.background : "transparent"}
testID={testID}
onLongPress={onLongPress}
onPress={onPress}
@@ -105,26 +91,15 @@ const SelectionWrapper = ({
justifyContent: "space-between",
alignItems: "center",
width: "100%",
alignSelf: "center",
overflow: "hidden",
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: compactMode ? 4 : DefaultAppStyles.GAP_VERTICAL,
paddingHorizontal: 12,
paddingVertical: compactMode ? 4 : 12,
borderRadius: isSheet ? 10 : 0,
marginBottom: isSheet ? DefaultAppStyles.GAP_VERTICAL : undefined
marginBottom: isSheet ? 12 : undefined
}}
>
{isEditingNote ? (
<View
style={{
backgroundColor: color || colors.selected.accent,
position: "absolute",
bottom: 0,
top: 0,
left: 0,
width: 5
}}
/>
) : null}
{item.type === "note" ? <Filler item={item} color={color} /> : null}
<SelectionIcon item={item} />
{children}
</Pressable>
);

View File

@@ -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 { AppFontSize } from "../../../utils/size";
import { SIZE } 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 ? AppFontSize.xl - 2 : AppFontSize.xl}
size={compactMode ? SIZE.xl - 2 : SIZE.xl}
color={selected ? colors.selected.accent : colors.primary.icon}
name={"check"}
/>

View File

@@ -23,14 +23,13 @@ import React from "react";
import { View } from "react-native";
import { notesnook } from "../../../../e2e/test.ids";
import { TaggedNotes } from "../../../screens/notes/tagged";
import { AppFontSize } from "../../../utils/size";
import { SIZE } 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(
({
@@ -61,9 +60,9 @@ const TagItem = React.memo(
flexShrink: 1
}}
>
<Heading size={AppFontSize.md}>
<Heading size={SIZE.md}>
<Heading
size={AppFontSize.md}
size={SIZE.md}
style={{
color: colors.primary.accent
}}
@@ -74,9 +73,9 @@ const TagItem = React.memo(
</Heading>
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
marginTop: 5
}}
>
{strings.notes(totalNotes)}
@@ -86,7 +85,7 @@ const TagItem = React.memo(
<IconButton
color={colors.primary.heading}
name="dots-horizontal"
size={AppFontSize.xl}
size={SIZE.xl}
onPress={() => {
Properties.present(item);
}}

View File

@@ -17,28 +17,20 @@ 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 { Message, useMessageStore } from "../../stores/use-message-store";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { useMessageStore } from "../../stores/use-message-store";
import { useThemeColors } from "@notesnook/theme";
import { getContainerBorder, hexToRGBA } from "../../utils/colors";
import { SIZE } from "../../utils/size";
import { Pressable } from "../ui/pressable";
import Paragraph from "../ui/typography/paragraph";
export const Card = ({
color,
customMessage
}: {
color?: string;
customMessage?: Omit<Message, "data">;
}) => {
export const Card = ({ color }: { color?: string }) => {
const { colors } = useThemeColors();
color = color ? color : colors.primary.accent;
const messageBoardState = useMessageStore(
(state) => customMessage || state.message
);
const messageBoardState = useMessageStore((state) => state.message);
const announcements = useMessageStore((state) => state.announcements);
const fontScale = Dimensions.get("window").fontScale;
@@ -46,19 +38,18 @@ export const Card = ({
(announcements && announcements.length) ? null : (
<View
style={{
width: "100%",
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
width: "95%"
}}
>
<Pressable
onPress={messageBoardState.onPress}
type="plain"
style={{
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
paddingVertical: 12,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingHorizontal: 0,
width: "100%"
}}
>
@@ -66,20 +57,30 @@ export const Card = ({
style={{
flexDirection: "row",
alignItems: "center",
width: "100%"
flexShrink: 1
}}
>
<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"
justifyContent: "center",
...getContainerBorder(
messageBoardState.type === "error"
? colors.error.accent
: color || colors.primary.accent,
0.4
)
}}
>
<Icon
size={AppFontSize.xxxl}
size={SIZE.lg}
color={
messageBoardState.type === "error" ? colors.error.icon : color
}
@@ -94,21 +95,39 @@ export const Card = ({
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>
);

View File

@@ -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, View } from "react-native";
import { ActivityIndicator, useWindowDimensions, 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 { AppFontSize } from "../../utils/size";
import { SIZE } 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?: keyof RouteParams;
screen?: string;
};
export const Empty = React.memo(function Empty({
@@ -58,6 +58,8 @@ 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
);
@@ -72,7 +74,7 @@ export const Empty = React.memo(function Empty({
<View
style={[
{
flex: 1,
height: height - (140 + insets.top),
width: "80%",
justifyContent: "center",
alignSelf: "center"
@@ -96,13 +98,18 @@ export const Empty = React.memo(function Empty({
{placeholder?.button && (
<Button
testID={notesnook.buttons.add}
type="secondaryAccented"
type="accent"
title={placeholder?.button}
iconPosition="right"
icon="arrow-right"
onPress={placeholder?.action}
buttonType={{
text: "white"
}}
style={{
alignSelf: "flex-start"
alignSelf: "flex-start",
borderRadius: 5,
height: 40
}}
/>
)}
@@ -117,12 +124,12 @@ export const Empty = React.memo(function Empty({
}}
>
<Heading>{placeholder?.title}</Heading>
<Paragraph size={AppFontSize.sm} textBreakStrategy="balanced">
<Paragraph size={SIZE.sm} textBreakStrategy="balanced">
{placeholder?.loading}
</Paragraph>
<Seperator />
<ActivityIndicator
size={AppFontSize.lg}
size={SIZE.lg}
color={color || colors.primary.accent}
/>
</View>

View File

@@ -24,9 +24,9 @@ import React, { useEffect, useRef } from "react";
import {
NativeScrollEvent,
NativeSyntheticEvent,
RefreshControl,
View
RefreshControl
} 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,7 +34,8 @@ 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 { fluidTabsRef } from "../../utils/global-refs";
import { tabBarRef } from "../../utils/global-refs";
import { Footer } from "../list-items/footer";
import { Header } from "../list-items/headers/header";
import { Empty, PlaceholderData } from "./empty";
import { ListItemWrapper } from "./list-item.wrapper";
@@ -42,7 +43,6 @@ import { ListItemWrapper } from "./list-item.wrapper";
type ListProps = {
data: VirtualizedGrouping<Item> | undefined;
dataType: Item["type"];
mode?: "drawer" | "sheet";
onRefresh?: () => void;
loading?: boolean;
headerTitle?: string;
@@ -73,7 +73,7 @@ export default function List(props: ListProps) {
? "home"
: props.renderedInRoute === "Favorites"
? "favorites"
: props.renderedInRoute === "Trash" || props.dataType === "trash"
: props.renderedInRoute === "Trash"
? "trash"
: `${props.dataType}s`;
@@ -145,80 +145,70 @@ export default function List(props: ListProps) {
return (
<>
<View
<Animated.View
style={{
flex: 1
}}
entering={props.renderedInRoute === "Search" ? undefined : FadeInDown}
>
{props.data?.placeholders?.length === 0 ? (
<>
{props.CustomLisHeader ? (
props.CustomLisHeader
) : !props.headerTitle ? null : (
<Header
<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}
color={props.customAccentColor}
placeholder={props.placeholder}
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}
) : null
}
ListFooterComponent={
<Footer height={props.renderedInRoute === "Notebook" ? 300 : 150} />
}
ListHeaderComponent={
<>
{props.CustomLisHeader ? (
props.CustomLisHeader
) : !props.headerTitle ? null : (
<Header
color={props.customAccentColor}
screen={props.renderedInRoute}
/>
)
}
ListHeaderComponent={
<>
{props.CustomLisHeader ? (
props.CustomLisHeader
) : !props.headerTitle ? null : (
<Header
color={props.customAccentColor}
screen={props.renderedInRoute}
/>
)}
</>
}
/>
)}
</View>
)}
</>
}
/>
</Animated.View>
</>
);
}

View File

@@ -200,7 +200,6 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
isRenderedInActionSheet={isSheet}
index={index}
locked={locked.current}
renderedInRoute={props.renderedInRoute}
/>
</>
);

View File

@@ -26,8 +26,8 @@ import {
DraxListRenderItemContent
} from "react-native-drax";
import { fluidTabsRef } from "../../utils/global-refs";
import { AppFontSize } from "../../utils/size";
import { tabBarRef } from "../../utils/global-refs";
import { SIZE } 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) {
fluidTabsRef.current?.lock();
tabBarRef.current?.lock();
} else {
fluidTabsRef.current?.unlock();
tabBarRef.current?.unlock();
}
useEffect(() => {
@@ -79,14 +79,13 @@ function ReorderableList<T extends { id: string }>({
<View
style={{
flexDirection: "row",
width: "100%"
paddingHorizontal: 12
}}
>
<View
style={{
opacity: isHidden ? 0.4 : 1,
flexGrow: 1,
flexShrink: 1
opacity: isHidden ? 0.4 : 1
}}
>
{renderDraggableItem(info, props)}
@@ -95,12 +94,13 @@ function ReorderableList<T extends { id: string }>({
<IconButton
name={!isHidden ? "minus" : "plus"}
color={colors.primary.icon}
size={AppFontSize.lg}
size={SIZE.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 {

View File

@@ -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 { AppFontSize } from "../../utils/size";
import { SIZE } from "../../utils/size";
import BaseDialog from "../dialog/base-dialog";
import DialogButtons from "../dialog/dialog-buttons";
import DialogContainer from "../dialog/dialog-container";
@@ -49,7 +49,6 @@ 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();
@@ -143,7 +142,7 @@ const MergeConflicts = () => {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
paddingLeft: 6
}}
>
@@ -165,7 +164,7 @@ const MergeConflicts = () => {
<Paragraph
style={{ flexWrap: "wrap" }}
color={colors.secondary.paragraph}
size={AppFontSize.xs}
size={SIZE.xs}
>
<Text
style={{
@@ -202,9 +201,9 @@ const MergeConflicts = () => {
height={30}
style={{
borderRadius: 100,
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
fontSize={AppFontSize.xs}
fontSize={SIZE.xs}
/>
) : null}
<View style={{ width: 10 }} />
@@ -219,9 +218,9 @@ const MergeConflicts = () => {
height={30}
style={{
borderRadius: 100,
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
fontSize={AppFontSize.xs}
fontSize={SIZE.xs}
color={colors.error.paragraph}
onPress={() => {
setDialogVisible(true);
@@ -234,12 +233,12 @@ const MergeConflicts = () => {
height={30}
style={{
borderRadius: 100,
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
minWidth: 60,
marginLeft: 10
}}
type="accent"
fontSize={AppFontSize.xs}
fontSize={SIZE.xs}
title={
keeping && !isDiscarded ? strings.undo() : strings.keep()
}

View File

@@ -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 { AppFontSize } from "../../utils/size";
import { SIZE } from "../../utils/size";
import DialogHeader from "../dialog/dialog-header";
import SheetProvider from "../sheet-provider";
import { Pressable } from "../ui/pressable";
@@ -38,7 +38,6 @@ 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,
@@ -89,16 +88,16 @@ const HistoryItem = ({
style={{
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
height: 45,
marginBottom: DefaultAppStyles.GAP_VERTICAL,
marginBottom: 10,
flexDirection: "row"
}}
>
{!item ? null : (
<>
<Paragraph>{getDate(item.dateCreated, item.dateModified)}</Paragraph>
<Paragraph color={colors.secondary.paragraph} size={AppFontSize.xs}>
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
{getTimeAgo(item.dateModified)}
</Paragraph>
</>
@@ -149,7 +148,7 @@ export default function NoteHistory({
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
height: !history?.placeholders.length
? 300
: (history.placeholders.length + 1) * 55,
@@ -171,7 +170,7 @@ export default function NoteHistory({
>
{_loading ? (
<ActivityIndicator
size={AppFontSize.xl}
size={SIZE.xl}
color={colors.primary.accent}
/>
) : (
@@ -188,7 +187,7 @@ export default function NoteHistory({
/>
</View>
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs}
color={colors.secondary.paragraph}
style={{
alignSelf: "center"

View File

@@ -36,7 +36,6 @@ 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";
/**
*
@@ -159,7 +158,7 @@ export default function NotePreview({ session, content, note }) {
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
<Button
@@ -174,7 +173,7 @@ export default function NotePreview({ session, content, note }) {
type="error"
width="100%"
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 12
}}
/>
</View>

View File

@@ -20,7 +20,6 @@ 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,
@@ -85,7 +84,7 @@ export const CompactFeatures = ({
style={{
width: "100%",
maxHeight: maxHeight,
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
{data.map((item) => (

View File

@@ -17,7 +17,6 @@ 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";
@@ -25,13 +24,17 @@ 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 Navigation from "../../services/navigation";
import { useThemeColors } from "@notesnook/theme";
import { useUserStore } from "../../stores/use-user-store";
import { getElevationStyle } from "../../utils/elevation";
import { eClosePremiumDialog, eCloseSheet } from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import {
eClosePremiumDialog,
eCloseSheet,
eOpenLoginDialog
} from "../../utils/events";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import { AuthMode } from "../auth/common";
import { AuthMode } from "../auth";
import SheetProvider from "../sheet-provider";
import { Toast } from "../toast";
import { Button } from "../ui/button";
@@ -44,7 +47,6 @@ 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();
@@ -64,9 +66,9 @@ export const Component = ({ close, promo }) => {
});
} else {
close();
Navigation.navigate("Auth", {
mode: AuthMode.trialSignup
});
setTimeout(() => {
eSendEvent(eOpenLoginDialog, AuthMode.trialSignup);
}, 400);
}
};
@@ -135,14 +137,14 @@ export const Component = ({ close, promo }) => {
<Heading
key="heading"
size={AppFontSize.lg}
size={SIZE.lg}
style={{
alignSelf: "center",
paddingTop: 20
}}
>
Notesnook{" "}
<Heading size={AppFontSize.lg} color={colors.primary.accent}>
<Heading size={SIZE.lg} color={colors.primary.accent}>
Pro
</Heading>
</Heading>
@@ -152,7 +154,7 @@ export const Component = ({ close, promo }) => {
style={{
marginBottom: 20
}}
size={AppFontSize.md}
size={SIZE.md}
color={colors.primary.accent}
/>
) : (
@@ -161,7 +163,7 @@ export const Component = ({ close, promo }) => {
alignSelf: "center",
marginBottom: 20
}}
size={AppFontSize.md}
size={SIZE.md}
>
(
{Platform.OS === "android"
@@ -174,9 +176,9 @@ export const Component = ({ close, promo }) => {
<Paragraph
key="description"
size={AppFontSize.md}
size={SIZE.md}
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
textAlign: "center",
alignSelf: "center",
paddingBottom: 20,
@@ -204,7 +206,7 @@ export const Component = ({ close, promo }) => {
type="accent"
width={250}
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
marginBottom: 15,
borderRadius: 100
}}
@@ -220,7 +222,7 @@ export const Component = ({ close, promo }) => {
type={userCanRequestTrial ? "secondaryAccented" : "accent"}
width={250}
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
marginBottom: 15,
borderRadius: 100
}}
@@ -229,18 +231,18 @@ export const Component = ({ close, promo }) => {
{!user || userCanRequestTrial ? (
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
alignSelf: "center",
textAlign: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
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={AppFontSize.xs} style={{ fontWeight: "bold" }}>
<Paragraph size={SIZE.xs} style={{ fontWeight: "bold" }}>
No credit card is required.
</Paragraph>
</Paragraph>
@@ -255,7 +257,7 @@ export const Component = ({ close, promo }) => {
<View
key="plans"
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
<PricingPlans showTrialOption={false} promo={promo} />
@@ -270,7 +272,7 @@ export const Component = ({ close, promo }) => {
}
type="accent"
style={{
paddingHorizontal: DefaultAppStyles.GAP * 2,
paddingHorizontal: 24,
position: "absolute",
borderRadius: 100,
bottom: 30,

View File

@@ -32,7 +32,7 @@ import {
eOpenResultDialog,
eOpenTrialEndingDialog
} from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import BaseDialog from "../dialog/base-dialog";
import DialogContainer from "../dialog/dialog-container";
@@ -42,7 +42,6 @@ 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();
@@ -95,7 +94,7 @@ export const Expiring = () => {
>
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
width: "100%"
}}
>
@@ -128,7 +127,7 @@ export const Expiring = () => {
paddingTop: 0,
paddingBottom: 20
}}
size={AppFontSize.md + 2}
size={SIZE.md + 2}
>
Upgrade now to continue using all the pro features after
your trial ends
@@ -144,11 +143,11 @@ export const Expiring = () => {
await sleep(300);
eSendEvent(eOpenPremiumDialog, promo);
}}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
textDecorationLine: "underline",
color: colors.secondary.paragraph,
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
>
{"See what's included in Basic & Pro plans"}
@@ -177,11 +176,11 @@ export const Expiring = () => {
promo?.discount > 30 ? null : promo
);
}}
fontSize={AppFontSize.md + 2}
fontSize={SIZE.md + 2}
style={{
marginBottom: status.extend ? 0 : 10,
marginTop: DefaultAppStyles.GAP_VERTICAL,
paddingHorizontal: DefaultAppStyles.GAP * 2
marginTop: 10,
paddingHorizontal: 24
}}
/>
@@ -202,10 +201,10 @@ export const Expiring = () => {
button: "Continue"
});
}}
fontSize={AppFontSize.xs}
fontSize={SIZE.xs}
height={30}
style={{
marginBottom: DefaultAppStyles.GAP_VERTICAL
marginBottom: 10
}}
/>
)}

View File

@@ -21,10 +21,9 @@ import React from "react";
import { Text, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useThemeColors } from "@notesnook/theme";
import { defaultBorderRadius, AppFontSize } from "../../utils/size";
import { SIZE } from "../../utils/size";
import Paragraph from "../ui/typography/paragraph";
import { ProTag } from "./pro-tag";
import { DefaultAppStyles } from "../../utils/styles";
export const FeatureBlock = ({
vertical,
@@ -41,11 +40,11 @@ export const FeatureBlock = ({
style={{
flexDirection: "row",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
marginBottom: DefaultAppStyles.GAP_VERTICAL,
paddingHorizontal: 12,
marginBottom: 10,
backgroundColor: colors.secondary.background,
borderRadius: 10,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingVertical: 12
}}
>
<Paragraph
@@ -54,7 +53,7 @@ export const FeatureBlock = ({
marginLeft: 5,
flexShrink: 1
}}
size={AppFontSize.sm}
size={SIZE.sm}
>
{content}
</Paragraph>
@@ -64,14 +63,14 @@ export const FeatureBlock = ({
style={{
height: 100,
justifyContent: "center",
padding: DefaultAppStyles.GAP_SMALL,
padding: 10,
marginRight: 10,
borderRadius: defaultBorderRadius,
borderRadius: 5,
minWidth: 100
}}
>
<Icon color={colors.primary.icon} name={icon} size={AppFontSize.xl} />
<Paragraph size={AppFontSize.md}>
<Icon color={colors.primary.icon} name={icon} size={SIZE.xl} />
<Paragraph size={SIZE.md}>
<Text style={{ color: colors.primary.accent }}>{highlight}</Text>
{content ? "\n" + content : null}
</Paragraph>
@@ -79,14 +78,14 @@ export const FeatureBlock = ({
{pro ? (
<>
<View style={{ height: 5 }} />
<ProTag width={50} size={AppFontSize.xs} background={proTagBg} />
<ProTag width={50} size={SIZE.xs} background={proTagBg} />
</>
) : (
<View
style={{
width: 30,
height: 3,
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
borderRadius: 100,
backgroundColor: colors.primary.accent
}}

View File

@@ -20,12 +20,11 @@ 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 { AppFontSize } from "../../utils/size";
import { SIZE } 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();
@@ -33,31 +32,24 @@ export const Group = ({ item, index }) => {
return (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
backgroundColor:
index % 2 !== 0
? colors.primary.background
: colors.secondary.background,
paddingHorizontal: 12,
backgroundColor: index % 2 !== 0 ? colors.primary.background : colors.secondary.background,
paddingVertical: 40
}}
>
{item?.pro ? (
<ProTag
size={AppFontSize.sm}
background={
index % 2 === 0
? colors.primary.background
: colors.secondary.background
}
size={SIZE.sm}
background={index % 2 === 0 ? colors.primary.background : colors.secondary.background}
/>
) : null}
<Heading>{item.title}</Heading>
<Paragraph size={AppFontSize.md}>{item.detail}</Paragraph>
<Paragraph size={SIZE.md}>{item.detail}</Paragraph>
{item.features && (
<ScrollView
style={{
marginTop: DefaultAppStyles.GAP
marginTop: 20
}}
horizontal
showsHorizontalScrollIndicator={false}
@@ -68,11 +60,7 @@ 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>
@@ -80,9 +68,9 @@ export const Group = ({ item, index }) => {
{item.info ? (
<Paragraph
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
size={AppFontSize.xs}
size={SIZE.xs}
color={colors.secondary.paragraph}
>
{item.info}

View File

@@ -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 { AppFontSize } from "../../utils/size";
import { SIZE } from "../../utils/size";
import Paragraph from "../ui/typography/paragraph";
export const Offer = ({
@@ -36,7 +36,7 @@ export const Offer = ({
textAlign: "center",
paddingVertical: padding
}}
size={AppFontSize.xxxl}
size={SIZE.xxxl}
>
GET {off}
<Text style={{ color: colors.primary.accent }}>%</Text> OFF!{"\n"}

View File

@@ -35,12 +35,11 @@ import {
eOpenPremiumDialog,
eShowGetPremium
} from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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();
@@ -96,7 +95,7 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
backgroundColor: colors.secondary.background,
zIndex: 999,
...getElevationStyle(20),
padding: DefaultAppStyles.GAP,
padding: 12,
borderRadius: 10,
flexDirection: "row",
alignSelf: "center",
@@ -121,7 +120,7 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
flexWrap: "wrap"
}}
color={colors.primary.accent}
size={AppFontSize.md}
size={SIZE.md}
>
{msg.title}
</Heading>
@@ -130,7 +129,7 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
style={{
flexWrap: "wrap"
}}
size={AppFontSize.sm}
size={SIZE.sm}
color={colors.primary.paragraph}
>
{msg.desc}

View File

@@ -19,12 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { Platform, View } from "react-native";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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,
@@ -50,7 +49,7 @@ export const PricingItem = ({
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
paddingVertical: compact ? 15 : 10,
width: compact ? null : "100%",
minWidth: 150,
@@ -60,13 +59,13 @@ export const PricingItem = ({
>
{!compact && (
<View>
<Heading size={AppFontSize.lg - 2}>
<Heading size={SIZE.lg - 2}>
{product?.type === "yearly" || product?.offerType === "yearly"
? "Yearly"
: "Monthly"}
</Heading>
{product?.info && (
<Paragraph size={AppFontSize.xs}>{product.info}</Paragraph>
<Paragraph size={SIZE.xs}>{product.info}</Paragraph>
)}
</View>
)}
@@ -76,13 +75,13 @@ export const PricingItem = ({
style={{
textDecorationLine: strikethrough ? "line-through" : undefined
}}
size={AppFontSize.sm}
size={SIZE.sm}
>
<Heading
style={{
textDecorationLine: strikethrough ? "line-through" : undefined
}}
size={AppFontSize.lg - 2}
size={SIZE.lg - 2}
>
{Platform.OS === "android"
? (product.data as RNIap.SubscriptionAndroid | undefined)

View File

@@ -17,8 +17,6 @@ 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";
@@ -29,19 +27,18 @@ import {
presentSheet,
ToastManager
} from "../../services/event-manager";
import Navigation from "../../services/navigation";
import PremiumService from "../../services/premium";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeColors } from "@notesnook/theme";
import { useUserStore } from "../../stores/use-user-store";
import {
eClosePremiumDialog,
eCloseSheet,
eCloseSimpleDialog
eCloseSimpleDialog,
eOpenLoginDialog
} from "../../utils/events";
import { openLinkInBrowser } from "../../utils/functions";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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";
@@ -50,7 +47,8 @@ import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { Walkthrough } from "../walkthroughs";
import { PricingItem } from "./pricing-item";
import { DefaultAppStyles } from "../../utils/styles";
import { useSettingStore } from "../../stores/use-setting-store";
import { strings } from "@notesnook/intl";
const UUID_PREFIX = "0bdaea";
const UUID_VERSION = "4";
@@ -266,7 +264,7 @@ export const PricingPlans = ({
return loading ? (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
justifyContent: "center",
alignItems: "center",
height: 100
@@ -277,7 +275,7 @@ export const PricingPlans = ({
) : (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
{buying ? (
@@ -292,7 +290,7 @@ export const PricingPlans = ({
style={{
alignSelf: "center"
}}
size={AppFontSize.lg}
size={SIZE.lg}
>
{(Platform.OS === "android"
? (monthlyPlan?.product as RNIap.SubscriptionAndroid | undefined)
@@ -311,9 +309,9 @@ export const PricingPlans = ({
type="accent"
width={250}
style={{
paddingHorizontal: DefaultAppStyles.GAP,
marginBottom: DefaultAppStyles.GAP,
marginTop: DefaultAppStyles.GAP,
paddingHorizontal: 12,
marginBottom: 15,
marginTop: 15,
borderRadius: 100
}}
/>
@@ -334,7 +332,7 @@ export const PricingPlans = ({
type="secondaryAccented"
width={250}
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
marginBottom: 15
}}
/>
@@ -375,7 +373,7 @@ export const PricingPlans = ({
<Heading
style={{
paddingTop: 15,
fontSize: AppFontSize.lg
fontSize: SIZE.lg
}}
>
Special offer for you
@@ -392,7 +390,7 @@ export const PricingPlans = ({
alignSelf: "center",
textAlign: "center"
}}
size={AppFontSize.xxl}
size={SIZE.xxl}
>
{Platform.OS === "android"
? (product.data as RNIap.SubscriptionAndroid)
@@ -413,7 +411,7 @@ export const PricingPlans = ({
alignSelf: "center",
textAlign: "center"
}}
size={AppFontSize.md}
size={SIZE.md}
>
then {getStandardPrice()} {product?.offerType}.
</Paragraph>
@@ -505,7 +503,7 @@ export const PricingPlans = ({
<Button
height={35}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 10
}}
onPress={() => {
presentDialog({
@@ -559,24 +557,24 @@ export const PricingPlans = ({
onPress={() => {
eSendEvent(eClosePremiumDialog);
eSendEvent(eCloseSheet);
Navigation.navigate("Auth", {
mode: AuthMode.login
});
setTimeout(() => {
eSendEvent(eOpenLoginDialog, 1);
}, 400);
}}
title={"Sign up for free"}
type="accent"
width={250}
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
marginTop: product?.type === "promo" ? 0 : 30,
marginBottom: DefaultAppStyles.GAP_VERTICAL
marginBottom: 10
}}
/>
{Platform.OS !== "ios" &&
promo &&
!promo.promoCode.startsWith("com.streetwriters.notesnook") ? (
<Paragraph
size={AppFontSize.md}
size={SIZE.md}
textBreakStrategy="balanced"
style={{
alignSelf: "center",
@@ -614,7 +612,7 @@ export const PricingPlans = ({
setProduct(undefined);
}}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
marginTop: 5
}}
height={30}
fontSize={13}
@@ -631,18 +629,18 @@ export const PricingPlans = ({
{!user || !upgrade ? (
<Paragraph
color={colors.secondary.paragraph}
size={AppFontSize.xs}
size={SIZE.xs}
style={{
alignSelf: "center",
textAlign: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
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={AppFontSize.xs} style={{ fontWeight: "bold" }}>
<Paragraph size={SIZE.xs} style={{ fontWeight: "bold" }}>
No credit card is required.
</Paragraph>
</Paragraph>
@@ -653,11 +651,11 @@ export const PricingPlans = ({
{Platform.OS === "ios" ? (
<Paragraph
textBreakStrategy="balanced"
size={AppFontSize.xs}
size={SIZE.xs}
color={colors.secondary.paragraph}
style={{
alignSelf: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
textAlign: "center"
}}
>
@@ -667,11 +665,11 @@ export const PricingPlans = ({
</Paragraph>
) : (
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs}
color={colors.secondary.paragraph}
style={{
alignSelf: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
textAlign: "center"
}}
>
@@ -687,7 +685,7 @@ export const PricingPlans = ({
}}
>
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs}
color={colors.secondary.paragraph}
style={{
maxWidth: "100%",
@@ -696,7 +694,7 @@ export const PricingPlans = ({
>
By subscribing, you agree to our{" "}
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs}
onPress={() => {
openLinkInBrowser("https://notesnook.com/tos")
.catch(() => {})
@@ -711,7 +709,7 @@ export const PricingPlans = ({
</Paragraph>
and{" "}
<Paragraph
size={AppFontSize.xs}
size={SIZE.xs}
onPress={() => {
openLinkInBrowser("https://notesnook.com/privacy")
.catch(() => {})

View File

@@ -22,7 +22,6 @@ 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";
/**
*
@@ -40,7 +39,7 @@ export const ProTag = ({ width, size, background }) => {
width: width || 60,
justifyContent: "center",
alignItems: "center",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
paddingVertical: 2.5,
flexDirection: "row"
}}
>

View File

@@ -31,13 +31,12 @@ 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 { AppFontSize } from "../../utils/size";
import { SIZE } 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();
@@ -86,12 +85,7 @@ const ColorItem = ({ item, note }: { item: Color; note: Note }) => {
}}
>
{isLinked ? (
<Icon
testID="icon-check"
name="check"
color="white"
size={AppFontSize.lg}
/>
<Icon testID="icon-check" name="check" color="white" size={SIZE.lg} />
) : null}
</Pressable>
);
@@ -134,37 +128,37 @@ export const ColorTags = ({ item }: { item: Note }) => {
flexShrink: 2
}}
>
{!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={
<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
}}
/>
) : (
<Pressable
style={{
width: 35,
@@ -184,12 +178,12 @@ export const ColorTags = ({ item }: { item: Note }) => {
testID="icon-plus"
name="plus"
color={colors.primary.icon}
size={AppFontSize.lg}
size={SIZE.lg}
/>
</Pressable>
}
/>
)}
)
}
/>
</View>
</>
);

View File

@@ -20,11 +20,10 @@ 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 { AppFontSize } from "../../utils/size";
import { SIZE } 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();
@@ -45,13 +44,13 @@ export const DateMeta = ({ item }) => {
style={{
flexDirection: "row",
justifyContent: "space-between",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2
paddingVertical: 3
}}
>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
{strings.dateDescFromKey(key)}
</Paragraph>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
<Paragraph size={SIZE.xs} color={colors.secondary.paragraph}>
{getFormattedDate(item[key], "date-time")}
</Paragraph>
</View>
@@ -60,10 +59,11 @@ export const DateMeta = ({ item }) => {
return (
<View
style={{
paddingVertical: 5,
marginTop: 5,
borderTopWidth: 1,
borderTopColor: colors.primary.border,
paddingHorizontal: DefaultAppStyles.GAP,
paddingTop: DefaultAppStyles.GAP_VERTICAL_SMALL
paddingHorizontal: 12
}}
>
{getDateMeta().map(renderItem)}

View File

@@ -16,19 +16,18 @@ 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 { View } from "react-native";
import { Platform, 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 { fluidTabsRef } from "../../utils/global-refs";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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";
@@ -37,9 +36,10 @@ 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 Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { DefaultAppStyles } from "../../utils/styles";
import { tabBarRef } from "../../utils/global-refs";
import { strings } from "@notesnook/intl";
const Line = ({ top = 6, bottom = 6 }) => {
const { colors } = useThemeColors();
@@ -58,6 +58,7 @@ const Line = ({ top = 6, bottom = 6 }) => {
export const Properties = ({ close = () => {}, item, buttons = [] }) => {
const { colors } = useThemeColors();
const isColor = !!ColorValues[item.title];
if (!item || !item.id) {
return (
<Paragraph style={{ marginVertical: 10, alignSelf: "center" }}>
@@ -81,14 +82,13 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
data={[0]}
keyExtractor={() => "properties-scroll-item"}
renderItem={() => (
<View
style={{
gap: DefaultAppStyles.GAP_VERTICAL
}}
>
<View>
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12,
marginTop: 5,
zIndex: 10,
marginBottom: 5
}}
>
<View
@@ -101,8 +101,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
style={{
flexDirection: "row",
alignItems: "center",
flexShrink: 1,
gap: 5
flexShrink: 1
}}
>
{item.type === "color" ? (
@@ -117,15 +116,16 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
marginRight: 10
}}
/>
) : item.type === "tag" ? (
<Icon
name="pound"
size={AppFontSize.lg}
color={colors.primary.icon}
/>
) : null}
<Heading size={AppFontSize.lg}>{item.title}</Heading>
<Heading size={SIZE.lg}>
{item.type === "tag" && !isColor ? (
<Heading size={SIZE.xl} color={colors.primary.accent}>
#
</Heading>
) : null}
{item.title}
</Heading>
</View>
{item.type === "note" ? (
@@ -133,7 +133,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
name="open-in-new"
type="plain"
color={colors.primary.icon}
size={AppFontSize.lg}
size={SIZE.lg}
style={{
alignSelf: "flex-start"
}}
@@ -144,7 +144,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
newTab: true
});
if (!DDS.isTab) {
fluidTabsRef.current?.goToPage("editor");
tabBarRef.current?.goToPage(1);
}
}}
/>
@@ -165,28 +165,35 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
style={{
justifyContent: "flex-start",
borderWidth: 0,
height: 30,
alignSelf: "flex-start",
backgroundColor: "transparent",
paddingHorizontal: 0,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
paddingHorizontal: 0
}}
fontSize={AppFontSize.xs}
fontSize={SIZE.xs}
/>
) : null}
</View>
<DateMeta item={item} />
<Line bottom={0} top={0} />
<Line bottom={0} />
{item.type === "note" ? (
<>
<Tags close={close} item={item} />
<Line bottom={0} top={0} />
<Line bottom={0} />
</>
) : null}
{item.type === "note" ? (
<Notebooks note={item} close={close} />
<View
style={{
paddingHorizontal: 12
}}
>
<Notebooks note={item} close={close} />
</View>
) : null}
<Items
item={item}
buttons={buttons}
@@ -195,6 +202,8 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
}}
/>
<Synced item={item} close={close} />
{DDS.isTab ? (
<View
style={{
@@ -209,40 +218,86 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
);
};
Properties.present = async (item, isSheet, buttons = []) => {
Properties.present = async (item, buttons = [], isSheet) => {
if (!item) return;
let type = item?.type;
let dbItem;
let props = [];
let android = [];
switch (type) {
case "trash":
dbItem = item;
props[0] = item;
props.push(["delete", "restore"]);
break;
case "note":
dbItem = await db.notes.note(item.id);
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
]);
break;
case "notebook":
dbItem = await db.notebooks.notebook(item.id);
props[0] = await db.notebooks.notebook(item.id);
props.push([
"edit-notebook",
"pin",
"add-shortcut",
"trash",
"default-notebook",
"add-notebook",
"move-notes",
"move-notebook"
]);
break;
case "tag":
dbItem = await db.tags.tag(item.id);
props[0] = await db.tags.tag(item.id);
props.push(["add-shortcut", "trash", "rename-tag"]);
break;
case "color":
dbItem = await db.colors.color(item.id);
props[0] = await db.colors.color(item.id);
props.push([
"trash",
"rename-color",
...(useSideBarDraggingStore.getState().dragging ? [] : ["reorder"])
]);
break;
case "reminder": {
dbItem = await db.reminders.reminder(item.id);
props[0] = await db.reminders.reminder(item.id);
props.push(["edit-reminder", "trash", "disable-reminder"]);
break;
}
}
if (!props[0]) return;
presentSheet({
context: isSheet ? "local" : undefined,
component: (ref, close) => (
<Properties
close={close}
close={() => {
close();
}}
actionSheetRef={ref}
item={dbItem}
buttons={buttons}
item={props[0]}
buttons={props[1]}
/>
)
});

View File

@@ -0,0 +1,266 @@
/*
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>
);
};

View File

@@ -1,360 +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 { 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>
);
};

View File

@@ -25,12 +25,11 @@ import { db } from "../../common/database";
import NotebookScreen from "../../screens/notebook";
import { eSendEvent, presentSheet } from "../../services/event-manager";
import { eClearEditor } from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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();
@@ -60,12 +59,12 @@ export default function Notebooks({ note, close, full }) {
type={full ? "transparent" : "secondary"}
style={{
justifyContent: "flex-start",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
flexDirection: "row",
alignItems: "center",
flexShrink: 1,
flexGrow: 1,
padding: DefaultAppStyles.GAP_SMALL,
padding: 6,
borderRadius: 10,
minHeight: 42
}}
@@ -73,7 +72,7 @@ export default function Notebooks({ note, close, full }) {
<Icon
name="book-outline"
color={colors.primary.accent}
size={AppFontSize.sm}
size={SIZE.sm}
style={{
marginRight: 5
}}
@@ -83,7 +82,7 @@ export default function Notebooks({ note, close, full }) {
style={{
maxWidth: "50%"
}}
size={AppFontSize.sm}
size={SIZE.sm}
>
{item.title}
</Heading>
@@ -93,46 +92,40 @@ export default function Notebooks({ note, close, full }) {
return noteNotebooks.length === 0 ? null : (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
width: "100%",
borderRadius: 10,
marginTop: 6
}}
>
<View
style={{
width: "100%",
borderRadius: 10,
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
}}
>
{full
? noteNotebooks.map(renderItem)
: noteNotebooks.slice(0, 1).map(renderItem)}
{full
? noteNotebooks.map(renderItem)
: noteNotebooks.slice(0, 1).map(renderItem)}
{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>
{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}
</View>
);
}

View File

@@ -19,44 +19,92 @@ 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 { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { SIZE } 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 { 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 ? (
<Button
<View
style={{
paddingVertical: 0,
width: "100%",
paddingHorizontal: 12,
alignItems: "center",
flexDirection: "row",
justifyContent: "flex-start",
alignSelf: "flex-start",
height: "auto",
padding: DefaultAppStyles.GAP_VERTICAL_SMALL,
paddingHorizontal: DefaultAppStyles.GAP_SMALL
alignSelf: "center",
paddingTop: 10,
marginTop: 10,
borderTopWidth: 1,
borderTopColor: colors.primary.border
}}
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);
}
}}
/>
>
<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>
) : null;
};

View File

@@ -22,13 +22,12 @@ import { View } from "react-native";
import { db } from "../../common/database";
import { TaggedNotes } from "../../screens/notes/tagged";
import { useThemeColors } from "@notesnook/theme";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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();
@@ -36,10 +35,11 @@ export const Tags = ({ item, close }) => {
return item.id ? (
<View
style={{
marginTop: 5,
flexDirection: "row",
flexWrap: "wrap",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
alignSelf: "center",
justifyContent: "space-between",
width: "100%"
@@ -56,10 +56,11 @@ export const Tags = ({ item, close }) => {
type="secondary"
icon="plus"
iconPosition="right"
fontSize={AppFontSize.xs}
height={30}
fontSize={SIZE.sm - 1}
style={{
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
height: 35,
borderRadius: 100
}}
/>
<ColorTags item={item} />
@@ -85,7 +86,7 @@ export const TagStrip = ({ item, close }) => {
flexDirection: "row",
flexWrap: "wrap",
alignItems: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
gap: 5
}}
>
@@ -116,7 +117,7 @@ const TagItem = ({ tag, close }) => {
title={"#" + tag.title}
type="plain"
height={20}
fontSize={AppFontSize.xs}
fontSize={SIZE.xs}
style={style}
textStyle={{
color: colors.secondary.paragraph

View File

@@ -29,23 +29,24 @@ 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 { fluidTabsRef } from "../../utils/global-refs";
import { tabBarRef } from "../../utils/global-refs";
import { updateNotebook } from "../../utils/notebooks";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { SIZE } from "../../utils/size";
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 { MoveNotebook } from "../../screens/move-notebook";
import { MoveNotebookSheet } from "../sheets/move-notebook";
import { Button } from "../ui/button";
import { IconButton } from "../ui/icon-button";
import NativeTooltip from "../../utils/tooltip";
import Heading from "../ui/typography/heading";
export const SelectionHeader = React.memo(
({
@@ -60,20 +61,23 @@ 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) {
fluidTabsRef.current?.lock();
tabBarRef.current?.lock();
} else {
fluidTabsRef.current?.unlock();
tabBarRef.current?.unlock();
}
}, [selectionMode]);
@@ -99,11 +103,8 @@ export const SelectionHeader = React.memo(
const deleteItem = async () => {
if (!type) return;
presentDialog({
title: strings.doActions.permanentlyDelete.unknown(
type,
selectedItemsList.length
),
paragraph: strings.actionConfirmations.permanentlyDelete.unknown(
title: strings.doActions.delete.unknown(type, selectedItemsList.length),
paragraph: strings.actionConfirmations.delete.unknown(
type,
selectedItemsList.length
),
@@ -112,7 +113,7 @@ export const SelectionHeader = React.memo(
positivePress: async () => {
if (!selectedItemsList.length) return;
await db.trash.delete(...selectedItemsList);
useTrashStore.getState().refresh();
Navigation.queueRoutesForUpdate();
clearSelection();
},
positiveType: "errorShade"
@@ -138,24 +139,61 @@ 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,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
justifyContent: "space-between",
alignItems: "center",
flexDirection: "row",
zIndex: 999,
paddingHorizontal: DefaultAppStyles.GAP,
position: "absolute",
bottom: 0,
borderTopWidth: 1,
borderColor: colors.primary.border,
justifyContent: "space-between"
paddingHorizontal: 12
}}
>
<View
style={{
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "center",
gap: DefaultAppStyles.GAP_SMALL
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"
}}
>
<IconButton
@@ -164,155 +202,159 @@ export const SelectionHeader = React.memo(
.getState()
.setAll(allSelected ? [] : [...((await items?.ids()) || [])]);
}}
size={AppFontSize.lg}
color={allSelected ? colors.primary.accent : colors.primary.icon}
tooltipText="Select all"
tooltipPosition={4}
style={{
marginLeft: 10
}}
color={
allSelected ? colors.primary.accent : colors.primary.paragraph
}
name="select-all"
/>
{!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) =>
{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) =>
!item.visible ? null : (
<IconButton
size={AppFontSize.lg}
<Button
style={{
justifyContent: "flex-start",
borderRadius: 0,
alignSelf: "flex-start",
width: "100%"
}}
type="plain"
tooltipText={item.title}
tooltipPosition={NativeTooltip.POSITIONS.TOP}
testID={`select-${item.icon}`}
name={item.icon}
buttonType={{
text: contextMenuColors.primary.paragraph
}}
icon={item.icon}
key={item.title}
color={colors.primary.icon}
title={item.title}
onPress={async () => {
//@ts-ignore
menuRef.current?.hide();
@@ -322,16 +364,9 @@ export const SelectionHeader = React.memo(
/>
)
)}
</Menu>
) : null}
</View>
<IconButton
size={AppFontSize.lg}
onPress={() => {
clearSelection();
}}
color={colors.primary.icon}
name="close"
/>
</View>
);
}

View File

@@ -27,13 +27,12 @@ import {
} from "../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { eCloseSheet, eOpenSheet } from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import { SIZE } 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);
@@ -95,8 +94,6 @@ const SheetProvider = ({ context = "global" }) => {
[context]
);
console.log(data?.keyboardHandlerDisabled);
return !visible || !data ? null : (
<SheetWrapper
fwdRef={actionSheetRef}
@@ -123,13 +120,13 @@ const SheetProvider = ({ context = "global" }) => {
!data.progress && !data.icon && !data.title && !data.paragraph
? 0
: 10,
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
{data?.progress ? (
<ActivityIndicator
style={{
marginTop: DefaultAppStyles.GAP
marginTop: 15
}}
size={50}
color={colors.primary.accent}
@@ -172,7 +169,7 @@ const SheetProvider = ({ context = "global" }) => {
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
marginBottom: data.valueArray ? 12 : 0
}}
>
@@ -183,7 +180,7 @@ const SheetProvider = ({ context = "global" }) => {
type="plain"
key={v}
textStyle={{ fontWeight: "normal" }}
fontSize={AppFontSize.sm}
fontSize={SIZE.sm}
icon="check"
width="100%"
style={{
@@ -196,7 +193,7 @@ const SheetProvider = ({ context = "global" }) => {
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
{data?.action ? (
@@ -223,10 +220,10 @@ const SheetProvider = ({ context = "global" }) => {
icon={item.icon && item.icon}
type={item.type || "accent"}
style={{
marginBottom: DefaultAppStyles.GAP_VERTICAL
marginBottom: 10
}}
width="100%"
fontSize={AppFontSize.md}
fontSize={SIZE.md}
/>
))}
@@ -234,17 +231,17 @@ const SheetProvider = ({ context = "global" }) => {
<Paragraph
style={{
alignSelf: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL,
marginTop: 10,
textDecorationLine: "underline"
}}
size={AppFontSize.xs}
size={SIZE.xs}
onPress={data.learnMorePress}
color={colors.secondary.paragraph}
>
<Icon
color={colors.primary.icon}
name="information-outline"
size={AppFontSize.xs}
size={SIZE.xs}
/>{" "}
{data.learnMore}
</Paragraph>

View File

@@ -18,7 +18,6 @@ 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";
@@ -31,16 +30,17 @@ 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 { eOnNotebookUpdated } from "../../../utils/events";
import { getParentNotebookId } from "../../../utils/notebooks";
import { AppFontSize } from "../../../utils/size";
import { SIZE } 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 { DefaultAppStyles } from "../../../utils/styles";
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";
export const AddNotebookSheet = ({
notebook,
@@ -97,28 +97,18 @@ export const AddNotebookSheet = ({
parentNotebook?.id ||
(await getParentNotebookId(notebook?.id || (id as string)));
eSendEvent(eOnNotebookUpdated, parent || notebook?.id);
if (!parent) {
useNotebookStore.getState().refresh();
}
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();
}
eSendEvent(eOnNotebookUpdated, parent);
if (notebook) {
setImmediate(() => {
eSendEvent(eOnNotebookUpdated, notebook.id);
});
}
close?.(true);
if (!notebook && showMoveNotesOnComplete && id) {
MoveNotes.present(await db.notebooks.notebook(id));
} else {
close?.(true);
}
};
return (
@@ -126,10 +116,10 @@ export const AddNotebookSheet = ({
style={{
maxHeight: DDS.isTab ? "90%" : "97%",
borderRadius: DDS.isTab ? 5 : 0,
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: 12
}}
>
<Heading size={AppFontSize.lg}>
<Heading size={SIZE.lg}>
{notebook ? strings.editNotebook() : strings.newNotebook()}
</Heading>
@@ -170,8 +160,10 @@ export const AddNotebookSheet = ({
<Button
title={notebook ? strings.save() : strings.add()}
type="accent"
height={45}
fontSize={SIZE.md}
style={{
paddingHorizontal: DefaultAppStyles.GAP * 2,
paddingHorizontal: 24,
width: "100%"
}}
onPress={onSaveChanges}

View File

@@ -0,0 +1,343 @@
/*
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;

View File

@@ -0,0 +1,263 @@
/*
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>
);
};

View File

@@ -16,17 +16,24 @@ 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 create from "zustand";
import { createItemSelectionStore } from "../../../stores/item-selection-store";
import { createNotebookTreeStores } from "../../stores/create-notebook-tree-stores";
import { createItemSelectionStore } from "../../stores/item-selection-store";
export const useNotebookExpandedStore = create<{
expanded: {
[id: string]: boolean;
};
setExpanded: (id: string) => void;
}>((set, get) => ({
expanded: {},
setExpanded(id: string) {
set({
expanded: {
...get().expanded,
[id]: !get().expanded[id]
}
});
}
}));
export const {
useNotebookExpandedStore: useSideMenuNotebookExpandedStore,
useNotebookSelectionStore: useSideMenuNotebookSelectionStore,
useNotebookTreeStore: useSideMenuNotebookTreeStore
} = createNotebookTreeStores(true, false);
export const useSideMenuTagsSelectionStore = createItemSelectionStore(
true,
false
);
export const useNotebookItemSelectionStore = createItemSelectionStore(true);

View File

@@ -31,7 +31,6 @@ import { Button } from "../../ui/button";
import Input from "../../ui/input";
import { eUserLoggedIn } from "../../../utils/events";
import { strings } from "@notesnook/intl";
import { DefaultAppStyles } from "../../../utils/styles";
type ChangeEmailProps = {
actionSheetRef: RefObject<ActionSheetRef>;
@@ -102,14 +101,14 @@ export const ChangeEmail = ({ close }: ChangeEmailProps) => {
};
return (
<View style={{ paddingHorizontal: DefaultAppStyles.GAP }}>
<View style={{ paddingHorizontal: 12 }}>
<DialogHeader
title={strings.changeEmail()}
paragraph={strings.changeEmailDesc()}
/>
<View
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: 12
}}
>
{step === EmailChangeSteps.verify ? (

View File

@@ -32,12 +32,11 @@ import {
import { editorController } from "../../../screens/editor/tiptap/utils";
import { eSendEvent, presentSheet } from "../../../services/event-manager";
import { eUnlockNote } from "../../../utils/events";
import { AppFontSize } from "../../../utils/size";
import { SIZE } from "../../../utils/size";
import { IconButton } from "../../ui/icon-button";
import { Pressable } from "../../ui/pressable";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import { DefaultAppStyles } from "../../../utils/styles";
const TabItemComponent = (props: {
tab: TabItem;
@@ -102,15 +101,15 @@ const TabItemComponent = (props: {
{props.tab.session?.noteLocked ? (
<>
{props.tab.session?.locked ? (
<Icon size={AppFontSize.md} name="lock" />
<Icon size={SIZE.md} name="lock" />
) : (
<Icon size={AppFontSize.md} name="lock-open-outline" />
<Icon size={SIZE.md} name="lock-open-outline" />
)}
</>
) : null}
{props.tab.session?.readonly ? (
<Icon size={AppFontSize.md} name="pencil-lock" />
<Icon size={SIZE.md} name="pencil-lock" />
) : null}
<Paragraph
@@ -120,7 +119,7 @@ const TabItemComponent = (props: {
: colors.primary.paragraph
}
numberOfLines={1}
size={AppFontSize.md}
size={SIZE.md}
>
{props.tab.session?.noteId
? item?.title || strings.untitledNote()
@@ -137,7 +136,7 @@ const TabItemComponent = (props: {
>
<IconButton
name="pin"
size={AppFontSize.lg}
size={SIZE.lg}
color={props.tab.pinned ? colors.primary.accent : colors.primary.icon}
onPress={() => {
useTabStore.getState().updateTab(props.tab.id, {
@@ -153,7 +152,7 @@ const TabItemComponent = (props: {
{!props.tab?.pinned ? (
<IconButton
name="close"
size={AppFontSize.lg}
size={SIZE.lg}
color={colors.primary.icon}
onPress={() => {
const isLastTab = useTabStore.getState().tabs.length === 1;
@@ -203,7 +202,7 @@ export default function EditorTabs({
return (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
gap: 12,
maxHeight: "100%"
}}
@@ -216,7 +215,7 @@ export default function EditorTabs({
alignItems: "center"
}}
>
<Heading size={AppFontSize.lg}>{strings.tabs()}</Heading>
<Heading size={SIZE.lg}>{strings.tabs()}</Heading>
<IconButton
onPress={() => {
useTabStore.getState().newTab();

Some files were not shown because too many files have changed in this diff Show More