Compare commits

..

2 Commits

Author SHA1 Message Date
Abdullah Atta
5962f059ce editor: remove table view 2025-11-27 12:03:43 +05:00
01zulfi
4991bdf689 editor: readonly table fixes
* fix tables not hiding under collapsed headings in readonly view
* allow column resizing in readonly view
* fix scrollbar not showing in readonly view

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-11-27 11:56:52 +05:00
128 changed files with 1038 additions and 66105 deletions

View File

@@ -55,13 +55,13 @@ jobs:
- name: Detox build
run: |
yarn build:android
ls apps/mobile/android/app/build/outputs/apk
ls apps/mobile/android/app/build/outputs/apk/release
ls apps/mobile/native/android/app/build/outputs/apk
ls apps/mobile/native/android/app/build/outputs/apk/release
- name: Get device name
id: device
run: |
AVD_NAME=$(node -p "require('./apps/mobile/.detoxrc.js').devices.emulator.device.avdName")
AVD_NAME=$(node -p "require('./apps/mobile/native/.detoxrc.js').devices.emulator.device.avdName")
echo "AVD_NAME=$AVD_NAME" >> $GITHUB_OUTPUT
- name: AVD cache

View File

@@ -24,22 +24,6 @@ jobs:
java-version: "17"
architecture: "x64"
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
# this might remove tools that are actually needed,
# if set to "true" but frees about 6 GB
tool-cache: false
# all of these default to true, but feel free to set to
# "false" if necessary for your workflow
android: false
dotnet: true
haskell: true
large-packages: true
docker-images: true
swap-storage: true
- name: Install node modules
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
@@ -140,7 +124,7 @@ jobs:
- name: Get app version
id: package-version
uses: saionaro/extract-package-version@master
uses: martinbeentjes/npm-get-version-action@master
with:
path: apps/mobile
@@ -159,8 +143,8 @@ jobs:
uses: softprops/action-gh-release@v1
with:
draft: true
tag_name: ${{ steps.package-version.outputs.version}}-android
name: Notesnook Android v${{ steps.package-version.outputs.version}}
tag_name: ${{ steps.package-version.outputs.current-version}}-android
name: Notesnook Android v${{ steps.package-version.outputs.current-version}}
repository: streetwriters/notesnook
token: ${{ secrets.GITHUB_TOKEN }}
files: |

View File

@@ -45,7 +45,7 @@ jobs:
test-macos-x64:
name: Test macOS x64
needs: build
runs-on: macos-15-intel
runs-on: macos-13
steps:
- name: Check out Git repository

View File

@@ -4,7 +4,7 @@ on: workflow_dispatch
jobs:
build:
runs-on: macos-26
runs-on: macos-14
timeout-minutes: 60
steps:
@@ -17,7 +17,7 @@ jobs:
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "26.1.1"
xcode-version: "16.1"
- name: Install node modules
run: |
@@ -30,7 +30,7 @@ jobs:
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ runner.os }}-ccache-${{ hashFiles(format('apps/mobile/ios/Podfile.lock')) }}
key: ${{ runner.os }}-ccache-${{ hashFiles(format('apps/mobile/native/ios/Podfile.lock')) }}
max-size: 1500M
restore-keys: |
${{ runner.os }}-ccache-
@@ -55,13 +55,14 @@ jobs:
uses: actions/cache@v3
id: pods-cache
with:
path: apps/mobile/ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('apps/mobile/ios/Podfile.lock') }}
path: apps/mobile/native/ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('apps/mobile/native/ios/Podfile.lock') }}
- name: Install Pods
run: |
cd apps/mobile/ios
pod install
cd apps/mobile/native/ios
bundle install
RCT_NEW_ARCH_ENABLED=0 bundle exec pod install
- name: Check for typescript errors
run: |
@@ -78,9 +79,9 @@ jobs:
bundle-identifier: org.streetwriters.notesnook
scheme: Notesnook
configuration: "Release"
export-options: apps/mobile/ios/ExportOptions.plist
project-path: apps/mobile/ios/Notesnook.xcodeproj
workspace-path: apps/mobile/ios/Notesnook.xcworkspace
export-options: apps/mobile/native/ios/ExportOptions.plist
project-path: apps/mobile/native/ios/Notesnook.xcodeproj
workspace-path: apps/mobile/native/ios/Notesnook.xcworkspace
update-targets: |
Notesnook
Make Note
@@ -116,5 +117,5 @@ jobs:
name: Notesnook.zip
path: |
Notesnook.ipa
apps/mobile/ios/**/*.map
apps/mobile/native/ios/**/*.map
packages/editor-mobile/sourcemaps/*.map

View File

@@ -11,5 +11,5 @@
"cache": true,
"cacheStrategy": "content"
},
"git.rebaseWhenSync": false
"git.rebaseWhenSync": true
}

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.3.7",
"version": "3.3.6-beta.0",
"appAppleId": "1544027013",
"private": true,
"main": "./dist/cjs/index.js",
@@ -36,8 +36,8 @@
"electron-trpc": "0.7.1",
"electron-updater": "^6.6.2",
"icojs": "^0.19.5",
"sqlite-better-trigram": "0.0.5",
"sqlite3-fts5-html": "^0.0.6",
"sqlite-better-trigram": "0.0.3",
"sqlite3-fts5-html": "^0.0.4",
"typed-emitter": "^2.1.0",
"yargs": "^17.7.2",
"zod": "3.24.3"

View File

@@ -47,7 +47,7 @@ module.exports = {
simulator: {
type: "ios.simulator",
device: {
type: "iPhone 17 Pro Max"
type: "iPhone 12"
}
},
attached: {
@@ -59,7 +59,7 @@ module.exports = {
emulator: {
type: "android.emulator",
device: {
avdName: "Pixel_5_API_36"
avdName: "Pixel_5_API_34"
}
}
},

View File

@@ -1,7 +1,6 @@
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
apply plugin: 'kotlin-parcelize'
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
@@ -125,7 +124,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled true
versionCode 3087
versionCode 3079
versionName getNpmVersion()
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'

View File

@@ -63,7 +63,4 @@
-keepattributes Signature
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
-keep class com.streetwriters.notesnook.datatypes.* { *; }
-keep class net.gotev.uploadservice.* { *; }
-keep class kotlinx.parcelize.* { *; }
-keep class com.streetwriters.notesnook.datatypes.* { *; }

View File

@@ -20,7 +20,7 @@ import com.zoontek.rnbootsplash.RNBootSplash;
public class MainActivity extends ReactActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
protected void onCreate(Bundle savedInstanceState) {
RNBootSplash.init(this, R.style.BootTheme);
super.onCreate(null);
@@ -32,6 +32,19 @@ public class MainActivity extends ReactActivity {
startService(new Intent(getBaseContext(), OnClearFromRecentService.class));
} catch (Exception ignored) {}
if (Build.VERSION.SDK_INT >= 35) {
final View rootView = findViewById(android.R.id.content);
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, insets) -> {
Insets innerPadding = insets.getInsets(WindowInsetsCompat.Type.ime());
rootView.setPadding(
innerPadding.left,
innerPadding.top,
innerPadding.right,
innerPadding.bottom
);
return insets;
});
}
}
/**
@@ -47,20 +60,20 @@ public class MainActivity extends ReactActivity {
DefaultNewArchitectureEntryPoint.getFabricEnabled());
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getReactHost().onConfigurationChanged(this);
Intent intent = new Intent("onConfigurationChanged");
intent.putExtra("newConfig", newConfig);
this.sendBroadcast(intent);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getReactInstanceManager().onConfigurationChanged(this, newConfig);
Intent intent = new Intent("onConfigurationChanged");
intent.putExtra("newConfig", newConfig);
this.sendBroadcast(intent);
}
@Override
protected String getMainComponentName() {

View File

@@ -6,7 +6,7 @@ import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
import org.wonday.orientation.OrientationActivityLifecycle;
class MainApplication : Application(), ReactApplication {
override val reactHost: ReactHost by lazy {
getDefaultReactHost(
@@ -22,7 +22,6 @@ class MainApplication : Application(), ReactApplication {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(OrientationActivityLifecycle.getInstance());
loadReactNative(this)
}
}

View File

@@ -17,7 +17,7 @@
</style>
<!-- BootTheme should inherit from Theme.SplashScreen -->
<style name="BootTheme" parent="Theme.BootSplash.EdgeToEdge">
<style name="BootTheme" parent="Theme.SplashScreen">
<item name="bootSplashBackground">@color/bootsplash_background</item>
<item name="bootSplashLogo">@mipmap/bootsplash_logo_dark</item>
<item name="android:navigationBarColor">@color/bootsplash_background</item>

0
apps/mobile/android/gradlew vendored Executable file → Normal file
View File

View File

@@ -1,6 +1,3 @@
- Get an overview of your year with Notesnook with Wrapped 2025
- Cell selection and column resizing in tables
- Added support for uploading large files in background
- Bug fixes and minor improvements
Thank you for using Notesnook!
Thank you for using Notesnook!

View File

@@ -51,9 +51,8 @@ const { appLockEnabled, appLockMode } = SettingsService.get();
if (appLockEnabled || appLockMode !== "none") {
useUserStore.getState().lockApp(true);
}
RNBootSplash.hide({
fade: true
});
RNBootSplash.hide();
const App = (props: { configureMode: "note-preview" }) => {
useAppEvents();
//@ts-ignore
@@ -64,7 +63,7 @@ const App = (props: { configureMode: "note-preview" }) => {
setTimeout(async () => {
await Notifications.get();
if (SettingsService.get().notifNotes) {
Notifications.pinQuickNote();
Notifications.pinQuickNote(true);
}
TipManager.init();
}, 100);

View File

@@ -70,7 +70,7 @@ export async function downloadFile(
throw new Error(error);
}
const totalChunks = Math.ceil(size / (chunkSize + ABYTES));
const totalChunks = Math.ceil(size / chunkSize);
const decryptedLength = size - totalChunks * ABYTES;
if (attachment && attachment.size !== decryptedLength) {

View File

@@ -222,21 +222,15 @@ export async function deleteCacheFileByName(name: string) {
}
export async function deleteDCacheFiles() {
try {
await createCacheDir();
const files = await RNFetchBlob.fs.ls(cacheDir);
for (const file of files) {
if (
file.includes("_dcache") ||
file.startsWith("NN_") ||
file.endsWith(".pdf")
) {
await RNFetchBlob.fs.unlink(file).catch(() => {
/* empty */
});
}
await createCacheDir();
const files = await RNFetchBlob.fs.ls(cacheDir);
for (const file of files) {
if (file.includes("_dcache") || file.startsWith("NN_")) {
await RNFetchBlob.fs.unlink(file).catch(() => {
/* empty */
});
}
} catch (e) {}
}
}
export async function getCachePathForFile(filename: string) {

View File

@@ -17,8 +17,8 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { isImage, RequestOptions } from "@notesnook/core";
import { PermissionsAndroid, Platform } from "react-native";
import { RequestOptions } from "@notesnook/core";
import { Platform } from "react-native";
import RNFetchBlob from "react-native-blob-util";
import { ToastManager } from "../../services/event-manager";
import { useAttachmentStore } from "../../stores/use-attachment-store";
@@ -31,7 +31,6 @@ import {
FileSizeResult,
getUploadedFileSize
} from "./utils";
import Upload from "@ammarahmed/react-native-upload";
export async function uploadFile(
filename: string,
@@ -65,87 +64,47 @@ export async function uploadFile(
);
}
const fileInfo = await RNFetchBlob.fs.stat(filePath);
const fileSize = (await RNFetchBlob.fs.stat(filePath)).size;
const remoteFileSize = await getUploadedFileSize(filename);
if (remoteFileSize === FileSizeResult.Error) return false;
if (
remoteFileSize > FileSizeResult.Empty &&
remoteFileSize === fileInfo.size
) {
if (remoteFileSize > FileSizeResult.Empty && remoteFileSize === fileSize) {
DatabaseLogger.log(`File ${filename} is already uploaded.`);
return true;
}
let attachmentInfo = await db.attachments.attachment(filename);
DatabaseLogger.info(`Starting upload: ${filename}`);
DatabaseLogger.info(
`Starting upload of ${filename} at path: ${fileInfo.path} ${fileInfo.size}`
);
const uploadRequest = RNFetchBlob.config({
//@ts-ignore
IOSBackgroundTask: !globalThis["IS_SHARE_EXTENSION"]
})
.fetch(
"PUT",
url,
{
...headers,
"content-type": ""
},
RNFetchBlob.wrap(filePath)
)
.uploadProgress((sent, total) => {
useAttachmentStore
.getState()
.setProgress(sent, total, filename, 0, "upload");
DatabaseLogger.info(
`File upload progress: ${filename}, ${sent}/${total}`
);
});
if (Platform.OS === "android") {
const status = await PermissionsAndroid.request(
"android.permission.POST_NOTIFICATIONS"
);
if (status !== "granted") {
ToastManager.show({
message: `The permission to show file upload notification was disallowed by the user.`,
type: "info"
});
}
}
const upload = Upload.create({
customUploadId: filename,
path: Platform.OS === "ios" ? "file://" + fileInfo.path : fileInfo.path,
url: url,
method: "PUT",
headers: {
...headers,
"content-type": "application/octet-stream"
},
appGroup: IOS_APPGROUPID,
notification: {
filename:
attachmentInfo && isImage(attachmentInfo?.mimeType)
? "image"
: attachmentInfo?.filename || "file",
enabled: true,
enableRingTone: true,
autoClear: true
}
}).onChange((event) => {
switch (event.status) {
case "running":
case "pending":
useAttachmentStore
.getState()
.setProgress(
event.uploadedBytes || 0,
event.totalBytes || fileInfo.size,
filename,
0,
"upload"
);
DatabaseLogger.info(
`File upload progress: ${filename}, ${event.uploadedBytes}/${
event.totalBytes || fileInfo.size
}`
);
break;
case "completed":
console.log("Upload completed");
break;
}
});
const result = await upload.start();
cancelToken.cancel = async () => {
useAttachmentStore.getState().remove(filename);
upload.cancel();
uploadRequest.cancel();
};
const status = result.responseCode || 0;
const uploadResponse = await uploadRequest;
const status = uploadResponse.info().status;
const uploaded = status >= 200 && status < 300;
useAttachmentStore.getState().remove(filename);
@@ -155,12 +114,12 @@ export async function uploadFile(
throw new Error(
`${status}, name: ${fileInfo.filename}, length: ${
fileInfo.size
}, info: ${JSON.stringify(result.error)}`
}, info: ${JSON.stringify(uploadResponse.info())}`
);
}
attachmentInfo = await db.attachments.attachment(filename);
if (!attachmentInfo) return false;
await checkUpload(filename, requestOptions.chunkSize, attachmentInfo.size);
const attachment = await db.attachments.attachment(filename);
if (!attachment) return false;
await checkUpload(filename, requestOptions.chunkSize, attachment.size);
DatabaseLogger.info(`File upload status: ${filename}, ${status}`);
return uploaded;
} catch (e) {

View File

@@ -155,16 +155,16 @@ export async function checkUpload(
expectedSize: number
) {
const size = await getUploadedFileSize(filename);
const totalChunks = Math.ceil(size / (chunkSize + ABYTES));
const totalChunks = Math.ceil(size / chunkSize);
const decryptedLength = size - totalChunks * ABYTES;
const error =
size === 0
? `File size is 0.`
: size === -1
? `File verification check failed.`
: expectedSize !== decryptedLength
? `File size mismatch. Expected ${size} bytes but got ${decryptedLength} bytes.`
: undefined;
? `File verification check failed.`
: expectedSize !== decryptedLength
? `File size mismatch. Expected ${size} bytes but got ${decryptedLength} bytes.`
: undefined;
if (error) throw new Error(error);
}
@@ -189,7 +189,3 @@ export async function checkAndCreateDir(path: string) {
}
return dir;
}
export const santizeUri = (uri: string) => {
return Platform.OS === "ios" ? decodeURI(uri).replace("file:///", "/") : uri;
};

View File

@@ -324,9 +324,7 @@ export const Signup = ({
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
width: DDS.isTab ? "50%" : "100%",
alignSelf: "center"
paddingHorizontal: DefaultAppStyles.GAP
}}
>
<Paragraph

View File

@@ -42,7 +42,9 @@ export default function DelayLayout({
...props
}: IDelayLayoutProps) {
const { colors } = useThemeColors();
const loading = useDelayLayout(props.delay === undefined ? 200 : props.delay);
const loading = useDelayLayout(
!props.delay || props.delay < 300 ? 0 : props.delay
);
const Placeholder = placeholder[props.type || "default"];
return loading || props.wait ? (

View File

@@ -136,12 +136,12 @@ const BaseDialog = ({
backgroundColor: background
? background
: transparent
? "transparent"
: "rgba(0,0,0,0.3)"
? "transparent"
: "rgba(0,0,0,0.3)"
}}
>
<KeyboardAvoidingView
enabled={!floating && !avoidKeyboardResize}
enabled={!floating && Platform.OS === "ios" && !avoidKeyboardResize}
behavior="padding"
>
<BouncingView
@@ -155,8 +155,8 @@ const BaseDialog = ({
justifyContent: centered
? "center"
: bottom
? "flex-end"
: "flex-start"
? "flex-end"
: "flex-start"
}
]}
>

View File

@@ -23,7 +23,6 @@ import React, { useCallback, useEffect, useRef, useState } from "react";
import { Dimensions, TextInput, View } from "react-native";
import Orientation from "react-native-orientation-locker";
import Pdf from "react-native-pdf";
import FileViewer from "react-native-file-viewer";
import { MMKV } from "../../../common/database/mmkv";
import downloadAttachment from "../../../common/filesystem/download-attachment";
import { deleteCacheFileByPath, exists } from "../../../common/filesystem/io";
@@ -44,7 +43,6 @@ import SheetProvider from "../../sheet-provider";
import { IconButton } from "../../ui/icon-button";
import { ProgressBarComponent } from "../../ui/svg/lazy";
import Paragraph from "../../ui/typography/paragraph";
import ReactNativeBlobUtil from "react-native-blob-util";
const WIN_WIDTH = Dimensions.get("window").width;
const WIN_HEIGHT = Dimensions.get("window").height;
@@ -119,11 +117,8 @@ const PDFPreview = () => {
setVisible(false);
return;
}
let path = `${cacheDir}/${attachment.filename}`;
const path = `${cacheDir}/${uri}`;
snapshotValue.current = snapshot.current;
await ReactNativeBlobUtil.fs
.mv(`${cacheDir}/${uri}`, path)
.catch(console.log);
setPDFSource("file://" + path);
setLoading(false);
}, 100);
@@ -132,7 +127,7 @@ const PDFPreview = () => {
);
const close = () => {
deleteCacheFileByPath(pdfSource.replace("file://", ""));
deleteCacheFileByPath(pdfSource);
setPDFSource(null);
setVisible(false);
setPassword("");
@@ -162,12 +157,7 @@ const PDFPreview = () => {
return (
visible && (
<BaseDialog
animation="fade"
visible={true}
onRequestClose={close}
useSafeArea={false}
>
<BaseDialog animation="fade" visible={true} onRequestClose={close}>
<SheetProvider context={attachment?.hash} />
<Dialog context={attachment?.hash} />
@@ -233,48 +223,45 @@ const PDFPreview = () => {
<View
style={{
flexDirection: "row",
gap: DefaultAppStyles.GAP_SMALL
alignItems: "center",
marginRight: 12
}}
>
<View
<TextInput
ref={inputRef}
defaultValue={currentPage + ""}
style={{
flexDirection: "row",
alignItems: "center"
color: colors.primary.paragraph,
padding: 0,
paddingTop: 0,
paddingBottom: 0,
marginTop: 0,
marginBottom: 0,
paddingVertical: 0,
height: 25,
backgroundColor: colors.secondary.background,
width: 40,
textAlign: "center",
marginRight: 4,
borderRadius: 3,
fontFamily: "Inter-Regular"
}}
>
<TextInput
ref={inputRef}
defaultValue={currentPage + ""}
style={{
color: colors.primary.paragraph,
padding: 0,
paddingTop: 0,
paddingBottom: 0,
marginTop: 0,
marginBottom: 0,
paddingVertical: 0,
height: 25,
backgroundColor: colors.secondary.background,
width: 40,
textAlign: "center",
marginRight: 4,
borderRadius: 3,
fontFamily: "Inter-Regular"
}}
selectTextOnFocus
keyboardType="decimal-pad"
onSubmitEditing={(event) => {
setCurrentPage(event.nativeEvent.text);
pdfRef.current?.setPage(
parseInt(event.nativeEvent.text)
);
}}
blurOnSubmit
/>
<Paragraph color={colors.static.white}>
/{numPages}
</Paragraph>
</View>
selectTextOnFocus
keyboardType="decimal-pad"
onSubmitEditing={(event) => {
setCurrentPage(event.nativeEvent.text);
pdfRef.current?.setPage(parseInt(event.nativeEvent.text));
}}
blurOnSubmit
/>
<Paragraph color={colors.static.white}>/{numPages}</Paragraph>
</View>
<View
style={{
flexDirection: "row"
}}
>
<IconButton
color={colors.static.white}
name="download"
@@ -282,16 +269,6 @@ const PDFPreview = () => {
downloadAttachment(attachment.hash, false);
}}
/>
<IconButton
color={colors.static.white}
name="open-in-new"
onPress={() => {
FileViewer.open(pdfSource, {
showOpenWithDialog: true,
showAppsSuggestions: true
});
}}
/>
</View>
</View>
{pdfSource ? (

View File

@@ -96,22 +96,22 @@ export class VaultDialog extends Component {
this.title = !this.state.novault
? strings.createVault()
: this.state.fingerprintAccess
? strings.vaultFingerprintUnlock()
: this.state.revokeFingerprintAccess
? strings.revokeVaultFingerprintUnlock()
: this.state.changePassword
? strings.changeVaultPassword()
: this.state.noteLocked
? this.state.deleteNote
? strings.deleteNote()
: this.state.share
? strings.shareNote()
: this.state.copyNote
? strings.copyNote()
: this.state.goToEditor
? strings.goToEditor()
: strings.goToEditor()
: strings.lockNote();
? strings.vaultFingerprintUnlock()
: this.state.revokeFingerprintAccess
? strings.revokeVaultFingerprintUnlock()
: this.state.changePassword
? strings.changeVaultPassword()
: this.state.noteLocked
? this.state.deleteNote
? strings.deleteNote()
: this.state.share
? strings.shareNote()
: this.state.copyNote
? strings.copyNote()
: this.state.goToEditor
? strings.goToEditor()
: strings.goToEditor()
: strings.lockNote();
}
componentDidMount() {
@@ -337,13 +337,12 @@ export class VaultDialog extends Component {
);
});
}
eSendEvent("vaultUpdated");
this.setState({
loading: false
});
setTimeout(() => {
this.close();
}, 100);
this.close();
} else {
ToastManager.show({
heading: strings.passwordIncorrect(),
@@ -354,6 +353,9 @@ export class VaultDialog extends Component {
} catch (e) {
console.error(e);
}
this.setState({
loading: false
});
};
clearVault = async () => {
@@ -872,24 +874,24 @@ export class VaultDialog extends Component {
deleteVault
? strings.delete()
: clearVault
? strings.clear()
: fingerprintAccess
? strings.enable()
: this.state.revokeFingerprintAccess
? strings.revoke()
: changePassword
? strings.change()
: this.state.noteLocked
? deleteNote
? strings.delete()
: share
? strings.share()
: goToEditor
? strings.open()
: strings.unlock()
: !note.id
? strings.create()
: strings.lock()
? strings.clear()
: fingerprintAccess
? strings.enable()
: this.state.revokeFingerprintAccess
? strings.revoke()
: changePassword
? strings.change()
: this.state.noteLocked
? deleteNote
? strings.delete()
: share
? strings.share()
: goToEditor
? strings.open()
: strings.unlock()
: !note.id
? strings.create()
: strings.lock()
}
/>
</View>

View File

@@ -31,7 +31,6 @@ import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
runOnJS,
SharedValue,
SnappySpringConfig,
useAnimatedReaction,
useAnimatedStyle,
useSharedValue,
@@ -111,6 +110,7 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
const containerWidth = widths
? widths.sidebar + widths.list + widths.editor
: dimensions.width;
const drawerPosition = 0;
const homePosition = widths.sidebar;
const editorPosition = widths.sidebar + widths.list;
@@ -354,10 +354,13 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
const finalValue = isSwipeLeft
? translateX.value - velocityX / 40.0
: translateX.value + velocityX / 40.0;
const velocity = velocityX / 5000;
const animationConfig: WithSpringConfig = {
velocity: velocity,
...SnappySpringConfig
velocity: velocityX,
mass: 0.5,
overshootClamping: true,
damping: 800,
stiffness: 800
};
if (finalValue < homePosition) {
@@ -440,7 +443,15 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
width: containerWidth,
flexDirection: "row"
},
animatedStyles
deviceMode === "tablet"
? {
transform: [
{
translateX: 0
}
]
}
: animatedStyles
]}
>
{children}

View File

@@ -994,7 +994,7 @@ const PricingPlanCard = ({
PremiumService.get() &&
(pricingPlans?.user?.subscription?.productId ===
(product as RNIap.Subscription)?.productId ||
pricingPlans?.user?.subscription?.productId?.startsWith(
pricingPlans?.user?.subscription?.productId.startsWith(
(product as RNIap.Subscription)?.productId
));
pricingPlans?.selectPlan(

View File

@@ -352,7 +352,7 @@ const ProductItem = (props: {
props.pricingPlans.isSubscribed() &&
(props.pricingPlans.user?.subscription?.productId ===
(product as RNIap.Subscription)?.productId ||
props.pricingPlans.user?.subscription?.productId?.startsWith(
props.pricingPlans.user?.subscription?.productId.startsWith(
(product as RNIap.Subscription)?.productId
) ||
props.pricingPlans.user?.subscription?.productId ===

View File

@@ -103,7 +103,7 @@ export function PlanLimits() {
if (
user?.subscription.plan !== SubscriptionPlan.FREE &&
user?.subscription.productId?.includes("5year")
user?.subscription.productId.includes("5year")
) {
ToastManager.show({
message:

View File

@@ -58,7 +58,6 @@ import { Button } from "../ui/button";
import SettingsService from "../../services/settings";
import { isFeatureAvailable } from "@notesnook/common";
import PaywallSheet from "../sheets/paywall";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
const renderScene = SceneMap({
home: SideMenuHome,
notebooks: SideMenuNotebooks,
@@ -69,7 +68,6 @@ const renderScene = SceneMap({
export const SideMenu = React.memo(
function SideMenu() {
const { colors } = useThemeColors();
const insets = useGlobalSafeAreaInsets();
const [index, setIndex] = React.useState(
SettingsService.getProperty("defaultSidebarTab")
);
@@ -89,13 +87,10 @@ export const SideMenu = React.memo(
]);
return (
<View
<SafeAreaView
style={{
flex: 1,
backgroundColor: colors.primary.background,
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left
backgroundColor: colors.primary.background
}}
>
<TabView
@@ -108,7 +103,7 @@ export const SideMenu = React.memo(
animationEnabled={false}
lazy
/>
</View>
</SafeAreaView>
);
},
() => true
@@ -356,8 +351,9 @@ const TabBar = (
color={colors.primary.icon}
onPress={async () => {
if (props.navigationState.index === 1) {
const notebooksFeature =
await isFeatureAvailable("notebooks");
const notebooksFeature = await isFeatureAvailable(
"notebooks"
);
if (!notebooksFeature.isAllowed) {
PaywallSheet.present(notebooksFeature);
return;

View File

@@ -104,12 +104,15 @@ function _MenuItem({
const _onPress = () => {
if (useSideBarDraggingStore.getState().dragging) return;
if (item.onPress) return item.onPress(item);
Navigation.closeDrawer();
if (useNavigationStore.getState().currentRoute !== item.id) {
Navigation.navigate(item.id as keyof RouteParams, {
canGoBack: false
});
}
setImmediate(() => {
Navigation.closeDrawer();
});
};
return (
@@ -151,8 +154,8 @@ function _MenuItem({
item.icon === "crown"
? colors.static.yellow
: isFocused
? colors.selected.icon
: colors.secondary.icon
? colors.selected.icon
: colors.secondary.icon
}
size={AppFontSize.md}
/>

View File

@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { SubscriptionPlan } from "@notesnook/core";
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import dayjs from "dayjs";
import React from "react";
import { FlatList, View } from "react-native";
import { DraxProvider, DraxScrollView } from "react-native-drax";
@@ -141,35 +140,19 @@ export function SideMenuHome() {
paddingVertical: DefaultAppStyles.GAP_VERTICAL
}}
>
{dayjs().month() !== 11 ? (
<>
{(subscriptionType === SubscriptionPlan.FREE ||
!subscriptionType ||
!user) &&
!SettingsService.getProperty("serverUrls") ? (
<Button
title={pro.title}
style={{
width: "100%"
}}
type="accent"
onPress={pro.onPress}
/>
) : null}
</>
) : (
{(subscriptionType === SubscriptionPlan.FREE ||
!subscriptionType ||
!user) &&
!SettingsService.getProperty("serverUrls") ? (
<Button
title={`Wrapped ${dayjs().year()} 🎉`}
title={pro.title}
style={{
width: "100%"
}}
bold
type="secondaryAccented"
onPress={() => {
Navigation.navigate("Wrapped");
}}
type="accent"
onPress={pro.onPress}
/>
)}
) : null}
</View>
</View>
);

View File

@@ -42,7 +42,7 @@ const SheetWrapper = ({
closeOnTouchBackdrop = true,
onHasReachedTop,
overlay,
overlayOpacity = 0.7,
overlayOpacity = 0.3,
enableGesturesInScrollView = false,
bottomPadding = true,
keyboardHandlerDisabled

View File

@@ -107,7 +107,6 @@ import { fluidTabsRef } from "../utils/global-refs";
import { NotesnookModule } from "../utils/notesnook-module";
import { sleep } from "../utils/time";
import useFeatureManager from "./use-feature-manager";
import { deleteDCacheFiles } from "../common/filesystem/io";
const onCheckSyncStatus = async (type: SyncStatusEvent) => {
const { disableSync, disableAutoSync } = SettingsService.get();
@@ -177,7 +176,6 @@ const onAppOpenedFromURL = async (event: { url: string }) => {
if (id) {
const note = await db.notes.note(id);
if (note) {
editorState().initialLoadCalled = true;
eSendEvent(eOnLoadNote, {
item: note
});
@@ -456,9 +454,11 @@ const initializeDatabase = async (password?: string) => {
await setAppMessage();
useSettingStore.getState().setAppLoading(false);
Notifications.setupReminders(true);
if (SettingsService.get().notifNotes) {
Notifications.pinQuickNote(false);
}
DatabaseLogger.info("Database initialized");
Notifications.restorePinnedNotes();
deleteDCacheFiles();
}
Walkthrough.init();
};

View File

@@ -660,25 +660,9 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
}
}
function isSubscribedToPlan(planId: string) {
if (!PremiumService.get()) return false;
return user?.subscription?.productId?.includes(planId);
}
function isSubscribedToProduct(productId: string) {
if (!PremiumService.get()) return false;
return (
user?.subscription?.productId &&
(user?.subscription?.productId === productId ||
user?.subscription?.productId?.startsWith(productId))
);
}
return {
currentPlan: pricingPlans.find((p) => p.id === currentPlan),
pricingPlans: plans,
isSubscribedToPlan,
isSubscribedToProduct,
getStandardPrice: getLocalizedPrice,
loadingPlans,
loading,

View File

@@ -29,7 +29,7 @@ import React, {
useRef,
useState
} from "react";
import { LayoutChangeEvent, View } from "react-native";
import { Dimensions, LayoutChangeEvent, Platform, View } from "react-native";
import Orientation, {
OrientationType,
useDeviceOrientationChange
@@ -39,6 +39,7 @@ import Animated, {
useSharedValue,
withTiming
} from "react-native-reanimated";
import { SafeAreaView } from "react-native-safe-area-context";
import { notesnook } from "../../e2e/test.ids";
import { db } from "../common/database";
import { FluidPanels } from "../components/fluid-panels";
@@ -68,13 +69,15 @@ import {
eOpenFullscreenEditor,
eUnlockNote
} from "../utils/events";
import { valueLimiter } from "../utils/functions";
import { fluidTabsRef } from "../utils/global-refs";
import { editorRef, fluidTabsRef } from "../utils/global-refs";
import { AppNavigationStack } from "./navigation-stack";
import type { PaneWidths } from "../screens/editor/wrapper";
const MOBILE_SIDEBAR_SIZE = 0.85;
const valueLimiter = (value: number, min: number, max: number) => {
return value < min ? min : value > max ? max : value;
};
let SideMenu: any = null;
let EditorWrapper: any = null;
@@ -90,6 +93,7 @@ export const FluidPanelsView = React.memo(
const insets = useGlobalSafeAreaInsets();
const animatedOpacity = useSharedValue(0);
const animatedTranslateY = useSharedValue(-9999);
const overlayRef = useRef<Animated.View>(null);
const [orientation, setOrientation] = useState<OrientationType>(
Orientation.getInitialOrientation()
@@ -98,21 +102,16 @@ export const FluidPanelsView = React.memo(
const [isLoading, setIsLoading] = useState(false);
useDeviceOrientationChange((o) => {
if (
o !== OrientationType.UNKNOWN &&
o !== OrientationType["FACE-UP"] &&
o !== OrientationType["FACE-DOWN"] &&
o !== OrientationType["PORTRAIT-UPSIDEDOWN"]
) {
setOrientation(o);
}
setOrientation(o);
});
const isLandscape = orientation.includes("LANDSCAPE");
useEffect(() => {
if (!appLoading) {
setTimeout(() => {
setIsLoading(false);
}, 200);
}, 500);
}
}, [appLoading]);
@@ -148,6 +147,16 @@ export const FluidPanelsView = React.memo(
if (deviceMode === "smallTablet") {
fluidTabsRef.current?.openDrawer(false);
}
editorRef.current?.setNativeProps({
style: {
width: dimensions.width,
zIndex: 999,
paddingHorizontal:
deviceMode === "smallTablet"
? dimensions.width * 0
: dimensions.width * 0.15
}
});
}, [deviceMode, dimensions.width, setFullscreen]);
const closeFullScreenEditor = useCallback(
@@ -160,6 +169,17 @@ export const FluidPanelsView = React.memo(
editorController.current?.commands.updateSettings({
fullscreen: false
});
editorRef.current?.setNativeProps({
style: {
width:
_deviceMode === "smallTablet"
? dimensions.width -
valueLimiter(dimensions.width * 0.4, 300, 450)
: dimensions.width * 0.48,
zIndex: null,
paddingHorizontal: 0
}
});
if (_deviceMode === "smallTablet") {
fluidTabsRef.current?.goToIndex(1, false);
}
@@ -201,8 +221,38 @@ export const FluidPanelsView = React.memo(
(current: string | null, size: { width: number; height: number }) => {
setDeviceModeState(current);
if (fullscreen && current === "mobile") {
eSendEvent(eCloseFullscreenEditor, current);
const needsLayout = current !== deviceMode;
if (fullscreen && current !== "mobile") {
// Runs after size is set via state.
setTimeout(() => {
editorRef.current?.setNativeProps({
style: {
width: size.width,
zIndex: 999,
paddingHorizontal:
current === "smallTablet" ? size.width * 0 : size.width * 0.15
}
});
}, 1);
} else {
if (fullscreen) eSendEvent(eCloseFullscreenEditor, current);
editorRef.current?.setNativeProps({
style: {
position: "relative",
width:
current === "tablet"
? size.width * 0.48
: current === "smallTablet"
? size.width - valueLimiter(size.width * 0.4, 300, 450)
: size.width,
zIndex: null,
paddingHorizontal: 0
}
});
}
if (!needsLayout) {
return;
}
const state = getAppState();
@@ -214,6 +264,8 @@ export const FluidPanelsView = React.memo(
case "smallTablet":
if (!fullscreen) {
fluidTabsRef.current?.closeDrawer(false);
} else {
fluidTabsRef.current?.openDrawer(false);
}
break;
case "mobile":
@@ -222,52 +274,46 @@ export const FluidPanelsView = React.memo(
editorState().movedAway === false &&
useTabStore.getState().getCurrentNoteId()
) {
fluidTabsRef.current?.goToPage("editor", false);
fluidTabsRef.current?.goToIndex(2, false);
} else {
fluidTabsRef.current?.goToPage(
fluidTabsRef.current?.page(),
false
);
fluidTabsRef.current?.goToIndex(1, false);
}
break;
}
}, 0);
}, 32);
},
[deviceMode, fullscreen, setDeviceModeState]
);
const checkDeviceType = React.useCallback(
(size: { width: number; height: number }) => {
if (DDS.width === size.width && orientation === DDS.orientation) return;
setDimensions({
width: size.width,
height: size.height
});
DDS.setSize(size, orientation);
const nextDeviceMode = DDS.isLargeTablet()
? "tablet"
: DDS.isSmallTab
? "smallTablet"
: "mobile";
setDeviceMode(nextDeviceMode, size);
},
[orientation, setDeviceMode, setDimensions]
);
useEffect(() => {
if (orientation !== "UNKNOWN") {
checkDeviceType(dimensions);
}
}, [orientation, dimensions]);
const _onLayout = React.useCallback(
(event: LayoutChangeEvent) => {
const size = event?.nativeEvent?.layout;
setDimensions({
width: size.width,
height: size.height
});
if (size.width > size.height) {
setOrientation(OrientationType["LANDSCAPE-RIGHT"]);
} else {
setOrientation(OrientationType["PORTRAIT"]);
if (!size || (size.width === dimensions.width && deviceMode !== null)) {
DDS.setSize(size, orientation);
setDeviceMode(deviceMode, size);
checkDeviceType(size);
return;
}
checkDeviceType(size);
},
[
checkDeviceType,
@@ -278,6 +324,11 @@ export const FluidPanelsView = React.memo(
]
);
if (!deviceMode) {
const size = Dimensions.get("window");
checkDeviceType(size);
}
const PANE_OFFSET = useMemo(
() => ({
mobile: {
@@ -305,7 +356,7 @@ export const FluidPanelsView = React.memo(
[dimensions.width, fullscreen]
);
const PANE_WIDTHS: PaneWidths = useMemo(
const PANE_WIDTHS = useMemo(
() => ({
mobile: {
sidebar: dimensions.width * MOBILE_SIDEBAR_SIZE,
@@ -331,7 +382,6 @@ export const FluidPanelsView = React.memo(
(scrollOffset: number) => {
if (!deviceMode) return;
hideAllTooltips();
if (
scrollOffset >
PANE_OFFSET[deviceMode as keyof typeof PANE_OFFSET].sidebar - 10
@@ -359,7 +409,7 @@ export const FluidPanelsView = React.memo(
};
}, []);
if (!isLoading && !SideMenu && !EditorWrapper) {
if (!isLoading) {
SideMenu = require("../components/side-menu").SideMenu;
EditorWrapper = require("../screens/editor/wrapper").EditorWrapper;
}
@@ -371,7 +421,15 @@ export const FluidPanelsView = React.memo(
style={{
height: "100%",
width: "100%",
backgroundColor: colors.primary.background
backgroundColor: colors.primary.background,
marginRight:
orientation === "LANDSCAPE-RIGHT" && Platform.OS === "ios"
? insets.right
: 0,
marginLeft:
orientation === "LANDSCAPE-LEFT" && Platform.OS === "ios"
? insets.left
: 0
}}
>
{deviceMode && PANE_WIDTHS[deviceMode as keyof typeof PANE_WIDTHS] ? (
@@ -445,7 +503,9 @@ export const FluidPanelsView = React.memo(
style={{
flex: 1,
paddingTop: insets.top,
paddingBottom: insets.bottom
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right
}}
>
<AppNavigationStack />

View File

@@ -273,7 +273,6 @@ let Settings: any = null;
let ManageTags: any = null;
let AddReminder: any = null;
let PayWall: any = null;
let Wrapped: any = null;
export const RootNavigation = () => {
const introCompleted = useSettingStore(
(state) => state.settings.introCompleted
@@ -385,14 +384,6 @@ export const RootNavigation = () => {
return PayWall;
}}
/>
<RootStack.Screen
name="Wrapped"
getComponent={() => {
Wrapped = Wrapped || require("../screens/wrapped").default;
return Wrapped;
}}
/>
</RootStack.Navigator>
</NavigationContainer>
);

View File

@@ -62,7 +62,6 @@ import { fluidTabsRef } from "../../utils/global-refs";
import { strings } from "@notesnook/intl";
import { i18n } from "@lingui/core";
import { useVaultStatus } from "../../hooks/use-vault-status";
import { useSettingStore } from "../../stores/use-setting-store";
const style: ViewStyle = {
height: "100%",
@@ -232,6 +231,7 @@ const useLockedNoteHandler = () => {
const unlockWithBiometrics = async () => {
try {
if (!tabRef.current?.session?.noteLocked || !tabRef.current) return;
console.log("Trying to unlock with biometrics...");
const credentials = await BiometricService.getCredentials(
"Unlock note",
"Unlock note to open it in editor."
@@ -320,16 +320,12 @@ const useLockedNoteHandler = () => {
}
};
const unlock = (forced?: boolean) => {
const isMovedAway =
useSettingStore.getState().deviceMode !== "mobile"
? false
: editorState().movedAway;
const unlock = () => {
if (
tabRef.current?.session?.locked &&
(tabRef.current?.session?.locked,
useTabStore.getState().biometryAvailable &&
useTabStore.getState().biometryEnrolled &&
(!isMovedAway || forced)
useTabStore.getState().biometryEnrolled &&
!editorState().movedAway)
) {
setTimeout(() => {
unlockWithBiometrics();
@@ -348,15 +344,13 @@ const useLockedNoteHandler = () => {
const subs = [
eSubscribeEvent(eUnlockNote, unlock),
eSubscribeEvent(eUnlockWithBiometrics, () => {
unlock(true);
unlock();
}),
eSubscribeEvent(eUnlockWithPassword, onSubmit)
];
if (
tabRef.current?.session?.locked &&
(fluidTabsRef.current?.page() === "editor" ||
useSettingStore.getState().deviceMode !== "mobile")
fluidTabsRef.current?.page() === "editor"
) {
unlock();
}

View File

@@ -22,10 +22,10 @@ import { isFeatureAvailable } from "@notesnook/common";
import { isImage } from "@notesnook/core";
import { strings } from "@notesnook/intl";
import {
pick as pickFile,
DocumentPickerOptions,
keepLocalCopy,
KeepLocalCopyResponse,
pick as pickFile
DocumentPickerResponse,
keepLocalCopy
} from "@react-native-documents/picker";
import { basename } from "pathe";
import { Platform } from "react-native";
@@ -35,13 +35,31 @@ import { DatabaseLogger, db } from "../../../common/database";
import filesystem from "../../../common/filesystem";
import { compressToFile } from "../../../common/filesystem/compress";
import AttachImage from "../../../components/dialogs/attach-image-dialog";
import { ToastManager } from "../../../services/event-manager";
import {
ToastManager,
eSendEvent,
presentSheet
} from "../../../services/event-manager";
import PremiumService from "../../../services/premium";
import { useSettingStore } from "../../../stores/use-setting-store";
import { useUserStore } from "../../../stores/use-user-store";
import { eCloseSheet } from "../../../utils/events";
import { useTabStore } from "./use-tab-store";
import { editorController, editorState } from "./utils";
import { santizeUri } from "../../../common/filesystem/utils";
const showEncryptionSheet = (file: DocumentPickerResponse) => {
presentSheet({
title: strings.encryptingAttachment(),
paragraph: strings.encryptingAttachmentDesc(file.name || ""),
icon: "attachment"
});
};
const santizeUri = (uri: string) => {
uri = decodeURI(uri);
uri = Platform.OS === "ios" ? uri.replace("file:///", "/") : uri;
return uri;
};
type PickerOptions = {
noteId?: string;
@@ -62,7 +80,7 @@ const file = async (fileOptions: PickerOptions) => {
await db.attachments.generateKey();
let file;
let fileCopyUri: KeepLocalCopyResponse[0];
let fileCopyUri;
let fileName;
try {
useSettingStore.getState().setAppDidEnterBackgroundForAction(true);
@@ -79,10 +97,12 @@ const file = async (fileOptions: PickerOptions) => {
});
fileCopyUri = result[0];
} catch (e) {
DatabaseLogger.error(e as Error, "Error picking file");
return;
}
let uri =
Platform.OS === "ios" ? fileCopyUri.sourceUri || file.uri : file.uri;
const featureResult = await isFeatureAvailable("fileSize", file.size || 0);
if (!featureResult.isAllowed) {
ToastManager.show({
@@ -102,7 +122,8 @@ const file = async (fileOptions: PickerOptions) => {
return;
}
let uri = santizeUri(fileCopyUri.localUri);
uri = Platform.OS === "ios" ? santizeUri(uri) : uri;
showEncryptionSheet(file);
const hash = await Sodium.hashFile({
uri: uri,
type: "url"
@@ -118,8 +139,7 @@ const file = async (fileOptions: PickerOptions) => {
) {
throw new Error("Failed to attach file");
}
await RNFetchBlob.fs.unlink(uri);
if (Platform.OS === "ios") await RNFetchBlob.fs.unlink(uri);
if (
fileOptions.tabId !== undefined &&
@@ -153,7 +173,10 @@ const file = async (fileOptions: PickerOptions) => {
} else {
throw new Error("Failed to attach file, no tabId is set");
}
eSendEvent(eCloseSheet);
} catch (e) {
eSendEvent(eCloseSheet);
ToastManager.show({
heading: (e as Error).message,
type: "error",
@@ -182,9 +205,7 @@ const camera = async (options: PickerOptions) => {
options
);
})
.catch((e) => {
console.log(e);
});
.catch((e) => {});
} catch (e) {
ToastManager.show({
heading: (e as Error).message,

View File

@@ -664,8 +664,7 @@ export const useEditorEvents = (
if (note) {
eSendEvent(eOnLoadNote, {
item: note,
tabId: editorMessage.tabId,
loadedFromEditor: true
tabId: editorMessage.tabId
});
}
} else {
@@ -676,8 +675,7 @@ export const useEditorEvents = (
if (note) {
eSendEvent(eOnLoadNote, {
item: note,
tabId: editorMessage.tabId,
loadedFromEditor: true
tabId: editorMessage.tabId
});
}
}

View File

@@ -508,17 +508,9 @@ export const useEditor = (
newTab?: boolean;
refresh?: boolean;
searchResultIndex?: number;
loadedFromEditor?: boolean;
}) => {
loadNoteMutex.runExclusive(async () => {
if (
!event ||
(event.loadedFromEditor &&
event.item &&
event.item?.id !== useTabStore.getState().getCurrentNoteId())
) {
return;
}
if (!event) return;
if (event.blockId) {
blockIdRef.current = event.blockId;
}
@@ -677,7 +669,7 @@ export const useEditor = (
state.current.currentlyEditing = true;
if (!tabLocked) {
await loadContent(item);
} else if (fluidTabsRef.current?.page() === "editor") {
} else {
commands.focus(tabId!);
}
@@ -727,7 +719,6 @@ export const useEditor = (
}, 300);
}
postMessage(NativeEvents.theme, theme);
console.log("load finished", event.item?.id);
});
},
[

View File

@@ -23,36 +23,21 @@ import {
AppState,
AppStateStatus,
KeyboardAvoidingView,
Platform,
TextInput,
View
} from "react-native";
import Editor from ".";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard";
import useKeyboard from "../../hooks/use-keyboard";
import { DDS } from "../../services/device-detection";
import { useSettingStore } from "../../stores/use-setting-store";
import { editorRef } from "../../utils/global-refs";
import { editorController, textInput } from "./tiptap/utils";
import deviceInfo from "react-native-device-info";
export type PaneWidths = {
mobile: {
sidebar: number;
list: number;
editor: number;
};
smallTablet: {
sidebar: number;
list: number;
editor: number;
};
tablet: {
sidebar: number;
list: number;
editor: number;
};
};
export const EditorWrapper = ({ widths }: { widths: PaneWidths }) => {
export const EditorWrapper = ({ widths }: { widths: any }) => {
const { colors } = useThemeColors();
const { colors: toolBarColors } = useThemeColors("editorToolbar");
const deviceMode = useSettingStore((state) => state.deviceMode);
@@ -62,9 +47,8 @@ export const EditorWrapper = ({ widths }: { widths: PaneWidths }) => {
const introCompleted = useSettingStore(
(state) => state.settings.introCompleted
);
const keyboard = useKeyboard();
const prevState = useRef<AppStateStatus>(undefined);
const isFullscreen = useSettingStore((state) => state.fullscreen);
const dimensions = useSettingStore((state) => state.dimensions);
const onAppStateChanged = async (state: AppStateStatus) => {
if (!prevState.current) {
@@ -88,40 +72,37 @@ export const EditorWrapper = ({ widths }: { widths: PaneWidths }) => {
};
}, [loading]);
const getMarginBottom = () => {
const bottomInsets =
Platform.OS === "android" ? 12 : insets.bottom + 16 || 14;
if (!keyboard.keyboardShown) return bottomInsets / 1.5;
if (deviceInfo.isTablet() && Platform.OS === "ios" && !floating)
return bottomInsets;
if (Platform.OS === "ios") return bottomInsets / 1.5;
return 0;
};
const KeyboardAvoidingViewIOS =
Platform.OS === "ios" ? KeyboardAvoidingView : View;
return (
<View
testID="editor-wrapper"
ref={editorRef}
style={[
{
width: isFullscreen
? dimensions.width
: widths[
!introCompleted ? "mobile" : (deviceMode as keyof PaneWidths)
]?.editor,
height: "100%",
minHeight: "100%",
backgroundColor: toolBarColors.primary.background,
paddingLeft: isFullscreen
? deviceMode === "smallTablet"
? 0
: dimensions.width * 0.15
: null,
paddingRight: isFullscreen
? deviceMode === "smallTablet"
? 0
: dimensions.width * 0.15
: insets.right,
borderLeftWidth: DDS.isTab ? 1 : 0,
borderLeftColor: DDS.isTab
? colors.secondary.background
: "transparent",
paddingBottom: insets.bottom
}
]}
style={{
width: widths[!introCompleted ? "mobile" : (deviceMode as any)]?.editor,
height: "100%",
minHeight: "100%",
backgroundColor: toolBarColors.primary.background,
borderLeftWidth: DDS.isTab ? 1 : 0,
borderLeftColor: DDS.isTab
? colors.secondary.background
: "transparent",
paddingBottom: insets.bottom
}}
>
{loading || !introCompleted ? null : (
<KeyboardAvoidingView
<KeyboardAvoidingViewIOS
behavior="padding"
style={{
backgroundColor: colors.primary.background,
@@ -137,7 +118,7 @@ export const EditorWrapper = ({ widths }: { widths: PaneWidths }) => {
blurOnSubmit={false}
/>
<Editor key="editor" withController={true} />
</KeyboardAvoidingView>
</KeyboardAvoidingViewIOS>
)}
</View>
);

View File

@@ -217,12 +217,12 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
position: "absolute",
bottom: 20,
right: 20,
gap: DefaultAppStyles.GAP_VERTICAL,
alignItems: "center"
}}
>
<FloatingButton
icon="file-tree"
testID="notebookTreeSheet"
size="small"
onPress={() => {
Notebooks.present(params.current.item);
@@ -230,8 +230,7 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
style={{
position: "relative",
right: 0,
bottom: 0,
paddingBottom: 10
bottom: 5
}}
/>
<FloatingButton
@@ -239,7 +238,6 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
alwaysVisible
style={{
position: "relative",
paddingTop: 10,
right: 0,
bottom: 0
}}

View File

@@ -23,6 +23,7 @@ import React, { useRef, useState } from "react";
import { View } from "react-native";
import { TextInput } from "react-native-gesture-handler";
import { IconButton } from "../../components/ui/icon-button";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import Navigation from "../../services/navigation";
import useNavigationStore from "../../stores/use-navigation-store";
import { useSelectionStore } from "../../stores/use-selection-store";
@@ -40,6 +41,7 @@ export const SearchBar = ({
const isFocused = useNavigationStore(
(state) => state.focusedRouteId === "Search"
);
const insets = useGlobalSafeAreaInsets();
const { colors } = useThemeColors();
const inputRef = useRef<TextInput>(null);
const _onChangeText = (value: string) => {
@@ -56,6 +58,7 @@ export const SearchBar = ({
>
<View
style={{
marginTop: DefaultAppStyles.GAP_SMALL,
flexDirection: "row",
alignItems: "center",
width: "100%",

View File

@@ -59,7 +59,7 @@ const Group = ({
id="Settings"
/>
)}
<DelayLayout type="settings">
<DelayLayout type="settings" delay={0}>
<View
style={{
flex: 1

View File

@@ -59,7 +59,7 @@ const Home = ({
hasSearch={false}
id="Settings"
/>
<DelayLayout type="settings">
<DelayLayout delay={0} type="settings">
<LegendList
data={settingsGroups}
keyExtractor={keyExtractor}

View File

@@ -17,29 +17,23 @@ 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, useThemeColors } from "@notesnook/theme";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import React from "react";
import { View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import useNavigationStore from "../../stores/use-navigation-store";
import { ScopedThemeProvider, useThemeColors } from "@notesnook/theme";
import Group from "./group";
import Home from "./home";
import { RouteParams } from "./types";
import { SafeAreaView } from "react-native-safe-area-context";
const SettingsStack = createNativeStackNavigator<RouteParams>();
export const Settings = () => {
const { colors } = useThemeColors();
const insets = useSafeAreaInsets();
return (
<View
<SafeAreaView
style={{
flex: 1,
backgroundColor: colors.primary.background,
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right
backgroundColor: colors.primary.background
}}
>
<ScopedThemeProvider value="list">
@@ -64,7 +58,7 @@ export const Settings = () => {
<SettingsStack.Screen name="SettingsGroup" component={Group} />
</SettingsStack.Navigator>
</ScopedThemeProvider>
</View>
</SafeAreaView>
);
};

View File

@@ -367,6 +367,7 @@ export const RestoreBackup = () => {
disableAppLockRequests: true
});
const file = await pick();
const fileCopy = await keepLocalCopy({
destination: "cachesDirectory",
files: [
@@ -389,7 +390,10 @@ export const RestoreBackup = () => {
}, 1000);
restoreBackup({
uri: fileCopy[0].localUri,
uri:
Platform.OS === "android"
? (("file://" + fileCopy[0].sourceUri) as string)
: (fileCopy[0].sourceUri as string),
deleteFile: true
});
},

View File

@@ -118,8 +118,7 @@ export const settingsGroups: SettingSection[] = [
if (
(user.subscription?.provider === SubscriptionProvider.GOOGLE ||
user.subscription?.provider === SubscriptionProvider.APPLE) &&
isCurrentPlatform &&
user?.subscription?.productId
isCurrentPlatform
) {
RNIap.deepLinkToSubscriptions({
sku: user?.subscription.productId
@@ -143,18 +142,13 @@ export const settingsGroups: SettingSection[] = [
"dddd, MMMM D, YYYY h:mm A"
);
if (
user.subscription?.plan !== SubscriptionPlan.FREE &&
user.subscription?.productId
) {
if (user.subscription?.plan !== SubscriptionPlan.FREE) {
const status = user.subscription?.status;
return status === SubscriptionStatus.TRIAL
? strings.trialEndsOn(
dayjs(user?.subscription?.start)
.add(
user?.subscription?.productId?.includes("monthly")
? 7
: 14
user?.subscription?.productId.includes("monthly") ? 7 : 14
)
.format("dddd, MMMM D, YYYY h:mm A")
)
@@ -1329,7 +1323,7 @@ export const settingsGroups: SettingSection[] = [
if (settings.notifNotes) {
Notifications.unpinQuickNote();
} else {
Notifications.pinQuickNote();
Notifications.pinQuickNote(false);
}
SettingsService.set({
notifNotes: !settings.notifNotes

View File

@@ -16,8 +16,6 @@ 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 { LegendList } from "@legendapp/list";
import { strings } from "@notesnook/intl";
import {
THEME_COMPATIBILITY_VERSION,
ThemeDefinition,
@@ -30,7 +28,8 @@ import type {
ThemeMetadata,
ThemesRouter
} from "@notesnook/themes-server";
import { keepLocalCopy, pick } from "@react-native-documents/picker";
import { pick } from "@react-native-documents/picker";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
import { createTRPCReact } from "@trpc/react-query";
@@ -41,24 +40,23 @@ import {
TouchableOpacity,
View
} from "react-native";
import ReactNativeBlobUtil from "react-native-blob-util";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { DatabaseLogger, db } from "../../common/database";
import { santizeUri } from "../../common/filesystem/utils";
import SheetProvider from "../../components/sheet-provider";
import { Button } from "../../components/ui/button";
import { IconButton } from "../../components/ui/icon-button";
import Input from "../../components/ui/input";
import { Pressable } from "../../components/ui/pressable";
import Heading from "../../components/ui/typography/heading";
import Paragraph from "../../components/ui/typography/paragraph";
import { ToastManager, presentSheet } from "../../services/event-manager";
import { useThemeStore } from "../../stores/use-theme-store";
import { getColorLinearShade } from "../../utils/colors";
import { defaultBorderRadius, AppFontSize } from "../../utils/size";
import { getElevationStyle } from "../../utils/elevation";
import { MenuItemsList } from "../../utils/menu-items";
import { AppFontSize, defaultBorderRadius } from "../../utils/size";
import { IconButton } from "../../components/ui/icon-button";
import { Pressable } from "../../components/ui/pressable";
import { getColorLinearShade } from "../../utils/colors";
import { strings } from "@notesnook/intl";
import { DefaultAppStyles } from "../../utils/styles";
import { LegendList } from "@legendapp/list";
const THEME_SERVER_URL = "https://themes-api.notesnook.com";
//@ts-ignore
@@ -414,43 +412,20 @@ function ThemeSelector() {
type={"secondaryAccented"}
icon="folder"
fontSize={AppFontSize.xs}
onPress={async () => {
try {
const pickResponse = await pick({
allowMultiSelection: false
onPress={() => {
pick({
allowMultiSelection: false
}).then((r) => {
fetch(r[0].uri).then(async (response) => {
const json = await response.json();
const result = validateTheme(json);
if (result.error) {
ToastManager.error(new Error(result.error));
return;
}
select(json, true);
});
const copiedFile = await keepLocalCopy({
destination: "cachesDirectory",
files: [
{
uri: pickResponse[0].uri,
fileName: pickResponse[0].name || "theme.json"
}
]
});
if (copiedFile[0].status !== "success") return;
const themeJsonCopiedPath = santizeUri(
copiedFile[0].localUri
);
const themeJson = await ReactNativeBlobUtil.fs.readFile(
themeJsonCopiedPath,
"utf8"
);
ReactNativeBlobUtil.fs
.unlink(themeJsonCopiedPath)
.catch(() => {});
const json = JSON.parse(themeJson);
const result = validateTheme(json);
if (result.error) {
ToastManager.error(new Error(result.error));
return;
}
select(json, true);
} catch (e) {
ToastManager.error(e as Error);
}
});
}}
/>
</View>

File diff suppressed because it is too large Load Diff

View File

@@ -114,7 +114,7 @@ async function onBackgroundSyncStarted() {
}
await Notifications.setupReminders();
if (SettingsService.get().notifNotes) {
Notifications.pinQuickNote();
Notifications.pinQuickNote(false);
}
Notifications.restorePinnedNotes();
NotePreviewWidget.updateNotes();
@@ -142,7 +142,7 @@ const onBoot = async () => {
await Notifications.setupReminders();
if (SettingsService.get().notifNotes) {
Notifications.pinQuickNote();
Notifications.pinQuickNote(false);
}
Notifications.restorePinnedNotes();
NotePreviewWidget.updateNotes();

View File

@@ -76,11 +76,11 @@ async function getCredentials(title?: string, description?: string) {
const options = Platform.select({
ios: {
fallbackEnabled: false,
description: description || title || "Unlock"
description: description
},
android: {
title: title,
description: description || "Unlock",
description: description,
deviceCredentialAllowed: false
}
});
@@ -132,11 +132,11 @@ async function validateUser(title: string, description?: string) {
Platform.select({
ios: {
fallbackEnabled: false,
description: title || "Unlock"
description: title
},
android: {
title: title,
description: description || "Unlock",
description: description,
deviceCredentialAllowed: false
}
}) as AuthenticateIOS

View File

@@ -50,7 +50,6 @@ export class DeviceDetectionService {
windowSize = size || windowSize;
this.width = windowSize.width;
this.height = windowSize.height;
this.orientation = orientation;
this.adjustedWidth = this.width * this.pixelDensity;
this.adjustedHeight = this.height * this.pixelDensity;
screenSize = Dimensions.get("screen");

View File

@@ -71,8 +71,7 @@ const routeNames = {
Archive: "Archive",
ManageTags: "ManageTags",
AddReminder: "AddReminder",
PayWall: "PayWall",
Wrapped: "Wrapped"
PayWall: "PayWall"
};
export type NavigationProps<T extends RouteName> = NativeStackScreenProps<

View File

@@ -109,15 +109,6 @@ async function initDatabase() {
const onEvent = async ({ type, detail }: Event) => {
await initDatabase();
const { notification, pressAction, input } = detail;
if (
type === EventType.DISMISSED &&
Platform.OS === "android" &&
notification?.id === "notesnook_note_input" &&
SettingsService.getProperty("notifNotes")
) {
pinQuickNote();
}
if (type === EventType.DELIVERED && Platform.OS === "android") {
if (notification?.id) {
const reminder = await db.reminders?.reminder(
@@ -447,7 +438,6 @@ async function scheduleNotification(
async function loadNote(id: string, jump: boolean) {
if (!id || id === "notesnook_note_input") return;
editorState().initialLoadCalled = true;
const note = await db.notes.note(id);
if (!note) return;
if (!DDS.isTab && jump) {
@@ -512,8 +502,7 @@ async function displayNotification({
ongoing,
reply_placeholder_text,
reply_button_text,
id,
channelId = "default"
id
}: {
title?: string;
message: string;
@@ -524,7 +513,6 @@ async function displayNotification({
reply_placeholder_text?: string;
reply_button_text?: string;
id?: string;
channelId?: "silent" | "vibrate" | "urgent" | "default";
}) {
useUserStore.setState({
disableAppLockRequests: true
@@ -549,7 +537,7 @@ async function displayNotification({
ongoing: ongoing,
smallIcon: "ic_stat_name",
localOnly: true,
channelId: await getChannelId(channelId),
channelId: await getChannelId("default"),
autoCancel: false,
pressAction: {
id: "default",
@@ -896,7 +884,7 @@ function init() {
notifee.onForegroundEvent(onEvent);
}
async function pinQuickNote() {
async function pinQuickNote(launch: boolean) {
useUserStore.setState({
disableAppLockRequests: true
});
@@ -908,13 +896,14 @@ async function pinQuickNote() {
return;
}
get().then((items) => {
const notification = items.find((n) => n.id === "notesnook_note_input");
if (notification) return;
const notification = items.filter((n) => n.id === "notesnook_note_input");
if (notification && launch) {
return;
}
displayNotification({
title: strings.quickNoteTitle(),
message: strings.quickNoteContent(),
ongoing: true,
channelId: "silent",
actions: ["ReplyInput", strings.hide()],
reply_button_text: strings.takeNote(),
reply_placeholder_text: strings.quickNotePlaceholder(),
@@ -1041,7 +1030,6 @@ async function pinNote(id: string) {
subtitle: "",
bigText: html,
ongoing: true,
channelId: "silent",
actions: [strings.unpin()],
id: note.id
});
@@ -1052,13 +1040,9 @@ async function pinNote(id: string) {
async function restorePinnedNotes() {
const pinnedNotes = PinnedNotesStorage.get();
Notifications.get().then(() => {
for (const id of pinnedNotes) {
if (!isNotePinned(id)) {
pinNote(id);
}
}
});
for (const id of pinnedNotes) {
pinNote(id);
}
}
async function clearPinnedNotes() {

View File

@@ -251,7 +251,6 @@ const ShareView = () => {
setRawData(item);
if (isURL(item.value)) {
note = await showLinkPreview(note, item.value);
noteTitle.current = note.title;
} else {
note.content.data = makeHtmlFromPlainText(item.value);
}
@@ -262,6 +261,9 @@ const ShareView = () => {
if (key.includes("TITLE") || key.includes("SUBJECT")) {
note.title = item[key];
noteTitle.current = note.title;
inputRef.current?.setNativeProps?.({
text: noteTitle.current
});
}
if (key.includes("TEXT") && !note.content.data) {
note.content.data = item[key];
@@ -292,10 +294,6 @@ const ShareView = () => {
}
}
}
inputRef.current?.setNativeProps?.({
text: noteTitle.current
});
onLoad();
setNote({ ...note });
} catch (e) {
@@ -310,6 +308,7 @@ const ShareView = () => {
try {
await initDatabase();
setLoadingExtension(false);
loadData(false);
useShareStore.getState().restore();
} catch (e) {
DatabaseLogger.error(e);

View File

@@ -112,7 +112,6 @@ export interface RouteParams extends ParamListBase {
context: "signup" | "logged-in" | "logged-out" | "subscribed";
state?: BillingState;
};
Wrapped: GenericRouteParam;
}
export type RouteName = keyof RouteParams;

View File

@@ -35,10 +35,6 @@ import { useTagStore } from "../stores/use-tag-store";
import { eUpdateNoteInEditor } from "./events";
import { unlockVault } from "./unlock-vault";
export const valueLimiter = (value: number, min: number, max: number) => {
return value < min ? min : value > max ? max : value;
};
export function getObfuscatedEmail(email: string) {
if (!email) return "";
const [username, provider] = email.split("@");

View File

@@ -23,7 +23,7 @@ module.exports = function (api, opts) {
});
}
env.plugins.push("react-native-worklets/plugin");
env.plugins.push("react-native-reanimated/plugin");
api.cache(true);
return env;

View File

@@ -134,7 +134,7 @@ describe("NOTE TESTS", () => {
.run();
});
it.only("Assign colors to a note", async () => {
it("Assign colors to a note", async () => {
await TestBuilder.create()
.prepare()
.createNote()

View File

@@ -121,7 +121,7 @@ describe("NOTEBOOKS", () => {
.run();
});
it("Remove note from notebook", async () => {
it.only("Remove note from notebook", async () => {
await TestBuilder.create()
.prepare()
.openSideMenu()
@@ -138,8 +138,7 @@ describe("NOTEBOOKS", () => {
.longPressByText(note.body)
.wait(500)
.waitAndTapById("select-minus")
.wait(500)
.isNotVisibleByText(note.body)
.isNotVisibleById(note.title)
.run();
})
.run();
@@ -200,7 +199,6 @@ describe("NOTEBOOKS", () => {
.longPressByText("Notebook 1")
.wait(500)
.waitAndTapByText("Move to trash")
.wait(500)
.waitAndTapByText("Delete")
.waitAndTapById("tab-home")
.waitAndTapByText("Trash")

View File

@@ -34,7 +34,7 @@ describe("Sort & filter", () => {
.element(by.web.className("ProseMirror"))
.typeText("Edited ", true);
})
.pressBack(2)
.pressBack()
.waitAndTapById("icon-sort")
.wait(500)
.waitAndTapByText("Date created")

View File

@@ -32,10 +32,7 @@ const testvars = {
class Element {
element: Detox.NativeElement;
constructor(
public type: "id" | "text",
public value: string
) {
constructor(public type: "id" | "text", public value: string) {
if (type == "id") {
this.element = element(by.id(value)).atIndex(0);
} else {
@@ -138,7 +135,6 @@ const Tests = {
);
await titleInput.isVisible();
await titleInput.element.typeText(title);
await Tests.sleep(1000);
if (description) {
await Tests.fromId(
notesnook.ids.dialogs.notebook.inputs.description

View File

@@ -84,7 +84,7 @@ describe("VAULT", () => {
.run();
});
it("Change vault password", async () => {
it.only("Change vault password", async () => {
await TestBuilder.create()
.prepare()
.createNote()
@@ -94,7 +94,7 @@ describe("VAULT", () => {
.typeTextById(notesnook.ids.dialogs.vault.pwd, "1234")
.typeTextById(notesnook.ids.dialogs.vault.changePwd, "2362")
.waitAndTapByText("Change")
.pressBack(4)
.pressBack(3)
.addStep(async () => await openLockedNote("2362"))
.run();
});

View File

@@ -1029,7 +1029,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2167;
CURRENT_PROJECT_VERSION = 2158;
DEVELOPMENT_TEAM = 53CWBG3QUC;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1104,7 +1104,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.3.11;
MARKETING_VERSION = 3.3.10;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1135,7 +1135,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2167;
CURRENT_PROJECT_VERSION = 2158;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1210,7 +1210,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.3.11;
MARKETING_VERSION = 3.3.10;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"$(inherited)",
@@ -1367,7 +1367,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2167;
CURRENT_PROJECT_VERSION = 2158;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1379,7 +1379,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 3.3.11;
MARKETING_VERSION = 3.3.10;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
@@ -1410,7 +1410,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2167;
CURRENT_PROJECT_VERSION = 2158;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1423,7 +1423,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 3.3.11;
MARKETING_VERSION = 3.3.10;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1453,7 +1453,7 @@
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2167;
CURRENT_PROJECT_VERSION = 2158;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1534,7 +1534,7 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
MARKETING_VERSION = 3.3.11;
MARKETING_VERSION = 3.3.10;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
@@ -1565,7 +1565,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2167;
CURRENT_PROJECT_VERSION = 2158;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1647,7 +1647,7 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
MARKETING_VERSION = 3.3.11;
MARKETING_VERSION = 3.3.10;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -4,7 +4,6 @@
#import "RNShortcuts.h"
#import "RNBootSplash.h"
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
#import "RNFileUploader.h"
@interface ReactNativeDelegate : RCTDefaultReactNativeFactoryDelegate
@end
@@ -80,8 +79,4 @@
[RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; // ⬅️ initialize the splash screen
}
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
[RNFileUploader setCompletionHandlerWithIdentifier:identifier completionHandler:completionHandler];
}
@end

View File

@@ -10,6 +10,8 @@
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
<string>3B52.1</string>
<string>C617.1</string>
</array>
</dict>
<dict>

View File

@@ -1887,7 +1887,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-document-picker (11.0.3):
- react-native-document-picker (10.1.7):
- boost
- DoubleConversion
- fast_float
@@ -1969,14 +1969,14 @@ PODS:
- React-Core
- React-RCTFabric
- ReactCommon/turbomodule/core
- react-native-mmkv-storage (12.0.1):
- react-native-mmkv-storage (0.11.2):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- MMKV (~> 1.3.14)
- MMKV (~> 1.3.9)
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
@@ -2004,7 +2004,7 @@ PODS:
- React
- react-native-orientation-locker (1.7.0):
- React-Core
- react-native-pager-view (8.0.0):
- react-native-pager-view (6.9.1):
- boost
- DoubleConversion
- fast_float
@@ -2031,9 +2031,8 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- SwiftUIIntrospect (~> 1.0)
- Yoga
- react-native-pdf (7.0.3):
- react-native-pdf (6.7.7):
- boost
- DoubleConversion
- fast_float
@@ -2245,36 +2244,6 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-upload (6.29.0):
- React
- react-native-view-shot (4.0.3):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-webview (13.16.0):
- boost
- DoubleConversion
@@ -3062,14 +3031,14 @@ PODS:
- Yoga
- RNKeychain (4.0.5):
- React
- RNNotifee (7.4.10):
- RNNotifee (7.4.9):
- React-Core
- RNNotifee/NotifeeCore (= 7.4.10)
- RNNotifee/NotifeeCore (7.4.10):
- RNNotifee/NotifeeCore (= 7.4.9)
- RNNotifee/NotifeeCore (7.4.9):
- React-Core
- RNPrivacySnapshot (1.0.0):
- React-Core
- RNReanimated (4.2.0):
- RNReanimated (4.1.3):
- boost
- DoubleConversion
- fast_float
@@ -3096,11 +3065,11 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- RNReanimated/reanimated (= 4.2.0)
- RNReanimated/reanimated (= 4.1.3)
- RNWorklets
- SocketRocket
- Yoga
- RNReanimated/reanimated (4.2.0):
- RNReanimated/reanimated (4.1.3):
- boost
- DoubleConversion
- fast_float
@@ -3127,11 +3096,11 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- RNReanimated/reanimated/apple (= 4.2.0)
- RNReanimated/reanimated/apple (= 4.1.3)
- RNWorklets
- SocketRocket
- Yoga
- RNReanimated/reanimated/apple (4.2.0):
- RNReanimated/reanimated/apple (4.1.3):
- boost
- DoubleConversion
- fast_float
@@ -3311,7 +3280,7 @@ PODS:
- pop (~> 1.0)
- React
- SexyTooltip
- RNWorklets (0.7.1):
- RNWorklets (0.6.1):
- boost
- DoubleConversion
- fast_float
@@ -3338,10 +3307,10 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- RNWorklets/worklets (= 0.7.1)
- RNWorklets/worklets (= 0.6.1)
- SocketRocket
- Yoga
- RNWorklets/worklets (0.7.1):
- RNWorklets/worklets (0.6.1):
- boost
- DoubleConversion
- fast_float
@@ -3368,10 +3337,10 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- RNWorklets/worklets/apple (= 0.7.1)
- RNWorklets/worklets/apple (= 0.6.1)
- SocketRocket
- Yoga
- RNWorklets/worklets/apple (0.7.1):
- RNWorklets/worklets/apple (0.6.1):
- boost
- DoubleConversion
- fast_float
@@ -3414,7 +3383,6 @@ PODS:
- pop (~> 1.0)
- SocketRocket (0.7.1)
- SSZipArchive (2.4.3)
- SwiftUIIntrospect (1.3.0)
- SwiftyRSA (1.7.0):
- SwiftyRSA/ObjC (= 1.7.0)
- SwiftyRSA/ObjC (1.7.0)
@@ -3494,8 +3462,6 @@ DEPENDENCIES:
- "react-native-share-extension (from `../node_modules/@ammarahmed/react-native-share-extension`)"
- "react-native-sodium (from `../node_modules/@ammarahmed/react-native-sodium`)"
- react-native-theme-switch-animation (from `../node_modules/react-native-theme-switch-animation`)
- "react-native-upload (from `../node_modules/@ammarahmed/react-native-upload`)"
- react-native-view-shot (from `../node_modules/react-native-view-shot`)
- react-native-webview (from `../node_modules/react-native-webview`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`)
@@ -3570,7 +3536,6 @@ SPEC REPOS:
- SDWebImage
- SocketRocket
- SSZipArchive
- SwiftUIIntrospect
- SwiftyRSA
- TOCropViewController
@@ -3710,10 +3675,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/@ammarahmed/react-native-sodium"
react-native-theme-switch-animation:
:path: "../node_modules/react-native-theme-switch-animation"
react-native-upload:
:path: "../node_modules/@ammarahmed/react-native-upload"
react-native-view-shot:
:path: "../node_modules/react-native-view-shot"
react-native-webview:
:path: "../node_modules/react-native-webview"
React-NativeModulesApple:
@@ -3894,7 +3855,7 @@ SPEC CHECKSUMS:
react-native-blob-util: 7946b7e13acf0da5e849dc2f73fcfebe1d981699
react-native-config: 963b5efabc864cf69412e54b5de49b6a23e4af03
react-native-date-picker: 4f4f40f6e65798038bb4b1bff47890c2be69c2e6
react-native-document-picker: d624d3d9bd9311da87f6f7b64aa44f69927d8543
react-native-document-picker: 1734eb0aa3dbd1cd7bf1b105936f9b55031ae616
react-native-fingerprint-scanner: d5e143a361f3f01858e9c45141ddcabc4fd57055
react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba
react-native-gzip: 794e0e964a0d9e1dfd1773fee938adb4d4310e26
@@ -3902,20 +3863,18 @@ SPEC CHECKSUMS:
react-native-image-resizer: 290b045c34c69db7574e4d08aadfc4abe1ff5a99
react-native-in-app-review: 1516ba69d60d58053b7eb3aaaf8d2a5a74af8b57
react-native-keep-awake: a351e6f67006b47f316ae2b17ee8ee69386167f4
react-native-mmkv-storage: e84980084e371a9c2230bbde071536a7e1539406
react-native-mmkv-storage: b7ce5a5eb3d3bfddcf2df127671abba6ef3d76ae
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
react-native-notification-sounds: ce106d58df0dd384bccbd2e84fb53accab7cc068
react-native-orientation-locker: cc6f357b289a2e0dd2210fea0c52cb8e0727fdaa
react-native-pager-view: d7d2aa47f54343bf55fdcee3973503dd27c2bd37
react-native-pdf: edc236298f13f1609e42d41e45b8b6ea88ed10f9
react-native-pager-view: a0516effb17ca5120ac2113bfd21b91130ad5748
react-native-pdf: c586da0d19c14e6d859e62bf957851687fba0f25
react-native-quick-sqlite: 1ed8d3db1e22a8604d006be69f06053382e93bb0
react-native-safe-area-context: c6e2edd1c1da07bdce287fa9d9e60c5f7b514616
react-native-screenguard: 9fc3b4ad5b97783fc0832638fae0dce51272c661
react-native-share-extension: fdc6aaab51591a2d445df239c446aaa3a99658ec
react-native-sodium: 066f76e46c9be13e9260521e3fa994937c4cdab4
react-native-theme-switch-animation: 449d6db7a760f55740505e7403ae8061debc9a7e
react-native-upload: 1459a4be625dda39e4364d9e7d859477a3000f2a
react-native-view-shot: 6c008e58f4720de58370848201c5d4a082c6d4ca
react-native-webview: 654f794a7686b47491cf43aa67f7f428bea00eed
React-NativeModulesApple: 46690a0fe94ec28fc6fc686ec797b911d251ded0
React-oscompat: 95875e81f5d4b3c7b2c888d5bd2c9d83450d8bdb
@@ -3962,21 +3921,20 @@ SPEC CHECKSUMS:
RNIap: 61f183ac917792fae42b0326b1bef33598c1adf6
RNImageCropPicker: 5fd4ceaead64d8c53c787e4e559004f97bc76df7
RNKeychain: ffd0513e676445c637410b47249460cbf56bc9cb
RNNotifee: 3840cc81add9954a5dec040f96442498f3f95d7b
RNNotifee: dabf3cdd7bfd9340bb84358cc78f635af4bc80e2
RNPrivacySnapshot: ccad3a548338c2f526bb7b1789af3fb0618b7d1d
RNReanimated: f1868b36f4b2b52a0ed00062cfda69506f75eaee
RNReanimated: 732e7d1662f8cc0e533fa32791800de5b5934726
RNScreens: d821082c6dd1cb397cc0c98b026eeafaa68be479
RNSecureRandom: b64d263529492a6897e236a22a2c4249aa1b53dc
RNShare: 5d39a36f2d3d9a6c9344bfb3232c8ed607924a35
RNSVG: 8c0bbfa480a24b24468f1c76bd852a4aac3178e6
RNTooltips: 50ff94bd2bff84ef74279c9532d008f5fdcddb95
RNWorklets: d9c050940f140af5d8b611d937eab1cbfce5e9a5
RNWorklets: ab618bf7d1c7fd2cb793b9f0f39c3e29274b3ebf
RNZipArchive: 71befbdc20e7fbd4b64552a0b324ad0e8d0efefb
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SexyTooltip: 5c9b4dec52bfb317938cb0488efd9da3717bb6fd
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
SwiftUIIntrospect: fee9aa07293ee280373a591e1824e8ddc869ba5d
SwiftyRSA: 8c6dd1ea7db1b8dc4fb517a202f88bb1354bc2c6
TOCropViewController: 797deaf39c90e6e9ddd848d88817f6b9a8a09888
toolbar-android: c426ed5bd3dcccfed20fd79533efc0d1ae0ef018

File diff suppressed because one or more lines are too long

View File

@@ -1,22 +1,21 @@
{
"name": "@notesnook/mobile",
"version": "3.3.11",
"version": "3.3.10-beta.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "3.3.11",
"version": "3.3.10-beta.0",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@ammarahmed/notifee-react-native": "^7.4.10",
"@ammarahmed/notifee-react-native": "7.4.9",
"@ammarahmed/react-native-background-fetch": "^4.2.2",
"@ammarahmed/react-native-eventsource": "1.1.0",
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.1",
"@ammarahmed/react-native-share-extension": "^2.9.5",
"@ammarahmed/react-native-sodium": "^1.6.8",
"@ammarahmed/react-native-upload": "^6.29.0",
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bam.tech/react-native-image-resizer": "3.0.11",
"@callstack/repack": "~5.2.1",
@@ -42,7 +41,7 @@
"@react-native-community/datetimepicker": "^8.4.5",
"@react-native-community/netinfo": "^11.4.1",
"@react-native-community/toolbar-android": "^0.2.1",
"@react-native-documents/picker": "^11.0.3",
"@react-native-documents/picker": "^10.1.7",
"@react-native-masked-view/masked-view": "^0.3.2",
"@react-navigation/elements": "^1.3.3",
"@react-navigation/native": "^6.0.10",
@@ -72,7 +71,7 @@
"react": "19.1.1",
"react-async-hook": "^4.0.0",
"react-native": "0.82.1",
"react-native-actions-sheet": "^10.1.0",
"react-native-actions-sheet": "10.0.0-alpha.8",
"react-native-actions-shortcuts": "^1.0.1",
"react-native-background-actions": "^2.6.6",
"react-native-begin-background-task": "github:blockfirm/react-native-begin-background-task",
@@ -97,18 +96,18 @@
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-keychain": "4.0.5",
"react-native-material-menu": "^2.0.0",
"react-native-mmkv-storage": "^12.0.1",
"react-native-mmkv-storage": "^12.0.0",
"react-native-modal-datetime-picker": "14.0.0",
"react-native-navigation-bar-color": "2.0.2",
"react-native-notification-sounds": "0.5.5",
"react-native-orientation-locker": "^1.7.0",
"react-native-pager-view": "^8.0.0",
"react-native-pdf": "^7.0.3",
"react-native-pager-view": "^6.5.1",
"react-native-pdf": "6.7.7",
"react-native-privacy-snapshot": "github:standardnotes/react-native-privacy-snapshot",
"react-native-progress": "5.0.0",
"react-native-qrcode-svg": "^6.0.6",
"react-native-quick-sqlite": "^8.2.7",
"react-native-reanimated": "^4.2.0",
"react-native-reanimated": "^4.1.3",
"react-native-reanimated-progress-bar": "1.0.1",
"react-native-safe-area-context": "^5.6.1",
"react-native-scoped-storage": "^1.9.5",
@@ -118,15 +117,14 @@
"react-native-share": "^12.0.3",
"react-native-svg": "^15.12.0",
"react-native-swiper-flatlist": "3.2.2",
"react-native-tab-view": "^4.2.2",
"react-native-tab-view": "^4.1.3",
"react-native-theme-switch-animation": "^0.6.0",
"react-native-tooltips": "^1.0.3",
"react-native-url-polyfill": "^2.0.0",
"react-native-vector-icons": "10.3.0",
"react-native-view-shot": "^4.0.3",
"react-native-webview": "^13.13.5",
"react-native-wheel-color-picker": "^1.3.1",
"react-native-worklets": "^0.7.1",
"react-native-worklets": "^0.6.1",
"react-native-zip-archive": "6.0.9",
"timeago.js": "4.0.2",
"toggle-switch-react-native": "3.2.0",
@@ -229,7 +227,6 @@
"@streetwriters/kysely": "^0.27.4",
"@streetwriters/showdown": "^3.0.9-alpha",
"@types/mime-db": "^1.43.5",
"alfaaz": "^1.1.0",
"async-mutex": "0.5.0",
"dayjs": "1.11.13",
"dom-serializer": "^2.0.0",
@@ -485,9 +482,9 @@
}
},
"node_modules/@ammarahmed/notifee-react-native": {
"version": "7.4.10",
"resolved": "https://registry.npmjs.org/@ammarahmed/notifee-react-native/-/notifee-react-native-7.4.10.tgz",
"integrity": "sha512-19t1vhIddFneOI7JVmXghunEt5mEmDBY/G1YVMuRNNT/HFQ1EcArJWuAaFAJrhrl/2CBS7xoPGLusKbkbT/JjA==",
"version": "7.4.9",
"resolved": "https://registry.npmjs.org/@ammarahmed/notifee-react-native/-/notifee-react-native-7.4.9.tgz",
"integrity": "sha512-DK4ogXPBnoM8UsDQQLK6AQZUbP9TqOcL3YDEKtXmsWug1hzvcP/AfJ42KUCni/XR5NMI1VWW7a7tEwdbdzmS8g==",
"license": "Apache-2.0",
"peerDependencies": {
"react-native": "*"
@@ -532,16 +529,6 @@
"integrity": "sha512-FbX9fMfqJ3ysd+zkSS5di459tPv5iB0fhmK3dx/xo+l07sf7f1gzJu17mghSGkOKkbjXaoLPcq3XLMwWGpvapQ==",
"license": "ISC"
},
"node_modules/@ammarahmed/react-native-upload": {
"version": "6.29.0",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-upload/-/react-native-upload-6.29.0.tgz",
"integrity": "sha512-k2FJAVR4Nohx4VhfgHuXzLXQpgEnco/PAv9R080X7oY3O12DTgY0ruDvOFwvQGFW0PDIHlXfLfUiMq2kZc/k1A==",
"license": "BSD-3-Clause",
"peerDependencies": {
"react": "*",
"react-native": ">=0.47.0"
}
},
"node_modules/@azure/core-asynciterator-polyfill": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.2.tgz",
@@ -2003,7 +1990,6 @@
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz",
"integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
@@ -2486,16 +2472,16 @@
}
},
"node_modules/@babel/preset-typescript": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz",
"integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==",
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz",
"integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==",
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-validator-option": "^7.27.1",
"@babel/plugin-syntax-jsx": "^7.27.1",
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
"@babel/plugin-transform-typescript": "^7.27.1"
"@babel/plugin-transform-typescript": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
@@ -4853,13 +4839,13 @@
}
},
"node_modules/@react-native-documents/picker": {
"version": "11.0.3",
"resolved": "https://registry.npmjs.org/@react-native-documents/picker/-/picker-11.0.3.tgz",
"integrity": "sha512-q+vQNT1NtZcFGwsDpTwMKNNcgOEq6foFDGlPQVt8H7KaEjCjC+wTGdXuVSe8JJr2uO9xZR6kJ7aRHReZ4XDRBw==",
"version": "10.1.7",
"resolved": "https://registry.npmjs.org/@react-native-documents/picker/-/picker-10.1.7.tgz",
"integrity": "sha512-Tb8SPU+pHxrSJmDHBozSUStIPeyFHTHLrU3MW0N3sUAioLd5z+nmUdypfg5fs+Yzp7KTxVW06APe2HLB1ysLww==",
"license": "MIT",
"peerDependencies": {
"react": "*",
"react-native": ">=0.79.0"
"react-native": "*"
}
},
"node_modules/@react-native-masked-view/masked-view": {
@@ -7500,15 +7486,6 @@
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
"integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -8565,15 +8542,6 @@
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
"license": "MIT"
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/css-select": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
@@ -11654,19 +11622,6 @@
"entities": "^4.4.0"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"license": "MIT",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/htmlparser2": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
@@ -17164,9 +17119,9 @@
}
},
"node_modules/react-native-actions-sheet": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-10.1.0.tgz",
"integrity": "sha512-pfbfWs2YqdF3Vo7Cx6LUsDQ/uS3iw8H64iFxZvtLXhZ3cVHWundJ903sZtadzJC+TpQIRV7NQsdnhErhf+wBlg==",
"version": "10.0.0-alpha.8",
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-10.0.0-alpha.8.tgz",
"integrity": "sha512-olKqucpGaxP/kiO2/nw0uPXn69ZdWWhcHFzu2tcv5RBMl+PhRv870HuODbE21X4jXY/fWTG6FwPJqRqWpKkY8A==",
"license": "MIT",
"peerDependencies": {
"react-native": "*",
@@ -17689,10 +17644,13 @@
}
},
"node_modules/react-native-mmkv-storage": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-native-mmkv-storage/-/react-native-mmkv-storage-12.0.1.tgz",
"integrity": "sha512-4I4NzjStuCqkeXGfJ7pcACNQ2FlZKlAQqeRvI80iZL7mQcaO5NMO26ILUk2f4LPEvxaT2ns+NcqPMZSj7L83ng==",
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/react-native-mmkv-storage/-/react-native-mmkv-storage-12.0.0.tgz",
"integrity": "sha512-sssZInILQBquytDDfjosjEdvevwMPk3fqQQjdjfnH362IcsBsApvtT8yJS406Mz9aJ6VhqVsZw/awltsUuPSYg==",
"license": "MIT",
"bin": {
"mmkv-link": "autolink/postlink/run.js"
},
"peerDependencies": {
"react-native": "*"
}
@@ -17743,9 +17701,9 @@
}
},
"node_modules/react-native-pager-view": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-8.0.0.tgz",
"integrity": "sha512-oAwlWT1lhTkIs9HhODnjNNl/owxzn9DP1MbP+az6OTUdgbmzA16Up83sBH8NRKwrH8rNm7iuWnX1qMqiiWOLhg==",
"version": "6.9.1",
"resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.9.1.tgz",
"integrity": "sha512-uUT0MMMbNtoSbxe9pRvdJJKEi9snjuJ3fXlZhG8F2vVMOBJVt/AFtqMPUHu9yMflmqOr08PewKzj9EPl/Yj+Gw==",
"license": "MIT",
"peerDependencies": {
"react": "*",
@@ -17753,9 +17711,9 @@
}
},
"node_modules/react-native-pdf": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-7.0.3.tgz",
"integrity": "sha512-zDtF6CGXPAfGptQZqX7LQK3CVQrIGsD+rYuBnMK0sVmd8mrq7ciwmWXINT+d92emMtZ7+PLnx1IQZIdsh0fphA==",
"version": "6.7.7",
"resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.7.tgz",
"integrity": "sha512-D0ga/eyPsVWSPEBm622sGVZLl3gibxPmfm2cxsLcUrZ4WDSGR5HyGmvvWaR/m9wXEyIbD4J6q9qzuG6yObcSXw==",
"license": "MIT",
"dependencies": {
"crypto-js": "4.2.0",
@@ -17830,18 +17788,19 @@
}
},
"node_modules/react-native-reanimated": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.2.0.tgz",
"integrity": "sha512-frhu5b8/m/VvaMWz48V8RxcsXnE3hrlErQ5chr21MzAeDCpY4X14sQjvm+jvu3aOI+7Cz2atdRpyhhIuqxVaXg==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.3.tgz",
"integrity": "sha512-GP8wsi1u3nqvC1fMab/m8gfFwFyldawElCcUSBJQgfrXeLmsPPUOpDw44lbLeCpcwUuLa05WTVePdTEwCLTUZg==",
"license": "MIT",
"dependencies": {
"react-native-is-edge-to-edge": "1.2.1",
"semver": "7.7.3"
"react-native-is-edge-to-edge": "^1.2.1",
"semver": "7.7.2"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0",
"react": "*",
"react-native": "*",
"react-native-worklets": ">=0.7.0"
"react-native-worklets": ">=0.5.0"
}
},
"node_modules/react-native-reanimated-progress-bar": {
@@ -17856,9 +17815,9 @@
}
},
"node_modules/react-native-reanimated/node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -17959,9 +17918,9 @@
}
},
"node_modules/react-native-tab-view": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-4.2.2.tgz",
"integrity": "sha512-NXtrG6OchvbGjsvbySJGVocXxo4Y2vA17ph4rAaWtA2jh+AasD8OyikKBRg2SmllEfeQ+GEhcKe8kulHv8BhTg==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-4.2.0.tgz",
"integrity": "sha512-TUbh7Yr0tE/99t1pJQLbQ+4/Px67xkT7/r3AhfV+93Q3WoUira0Lx7yuKUP2C118doqxub8NCLERwcqsHr29nQ==",
"license": "MIT",
"dependencies": {
"use-latest-callback": "^0.2.4"
@@ -18099,19 +18058,6 @@
"node": ">=10"
}
},
"node_modules/react-native-view-shot": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/react-native-view-shot/-/react-native-view-shot-4.0.3.tgz",
"integrity": "sha512-USNjYmED7C0me02c1DxKA0074Hw+y/nxo+xJKlffMvfUWWzL5ELh/TJA/pTnVqFurIrzthZDPtDM7aBFJuhrHQ==",
"license": "MIT",
"dependencies": {
"html2canvas": "^1.4.1"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-webview": {
"version": "13.16.0",
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.16.0.tgz",
@@ -18136,49 +18082,33 @@
}
},
"node_modules/react-native-worklets": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.7.1.tgz",
"integrity": "sha512-KNsvR48ULg73QhTlmwPbdJLPsWcyBotrGPsrDRDswb5FYpQaJEThUKc2ncXE4UM5dn/ewLoQHjSjLaKUVPxPhA==",
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.6.1.tgz",
"integrity": "sha512-URca8l7c7Uog7gv4mcg9KILdJlnbvwdS5yfXQYf5TDkD2W1VY1sduEKrD+sA3lUPXH/TG1vmXAvNxCNwPMYgGg==",
"license": "MIT",
"dependencies": {
"@babel/plugin-transform-arrow-functions": "7.27.1",
"@babel/plugin-transform-class-properties": "7.27.1",
"@babel/plugin-transform-classes": "7.28.4",
"@babel/plugin-transform-nullish-coalescing-operator": "7.27.1",
"@babel/plugin-transform-optional-chaining": "7.27.1",
"@babel/plugin-transform-shorthand-properties": "7.27.1",
"@babel/plugin-transform-template-literals": "7.27.1",
"@babel/plugin-transform-unicode-regex": "7.27.1",
"@babel/preset-typescript": "7.27.1",
"convert-source-map": "2.0.0",
"semver": "7.7.3"
"@babel/plugin-transform-arrow-functions": "^7.0.0-0",
"@babel/plugin-transform-class-properties": "^7.0.0-0",
"@babel/plugin-transform-classes": "^7.0.0-0",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0",
"@babel/plugin-transform-optional-chaining": "^7.0.0-0",
"@babel/plugin-transform-shorthand-properties": "^7.0.0-0",
"@babel/plugin-transform-template-literals": "^7.0.0-0",
"@babel/plugin-transform-unicode-regex": "^7.0.0-0",
"@babel/preset-typescript": "^7.16.7",
"convert-source-map": "^2.0.0",
"semver": "7.7.2"
},
"peerDependencies": {
"@babel/core": "*",
"@babel/core": "^7.0.0-0",
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-worklets/node_modules/@babel/plugin-transform-optional-chaining": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz",
"integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==",
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/react-native-worklets/node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -20325,15 +20255,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/thingies": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz",
@@ -21145,15 +21066,6 @@
"node": ">= 0.4.0"
}
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"license": "MIT",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/uuid": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "@notesnook/mobile",
"version": "3.3.11",
"version": "3.3.10-beta.0",
"private": true,
"license": "GPL-3.0-or-later",
"scripts": {
@@ -26,13 +26,12 @@
"react": "19.1.1"
},
"dependencies": {
"@ammarahmed/notifee-react-native": "^7.4.10",
"@ammarahmed/notifee-react-native": "7.4.9",
"@ammarahmed/react-native-background-fetch": "^4.2.2",
"@ammarahmed/react-native-eventsource": "1.1.0",
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.1",
"@ammarahmed/react-native-share-extension": "^2.9.5",
"@ammarahmed/react-native-sodium": "^1.6.8",
"@ammarahmed/react-native-upload": "^6.29.0",
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bam.tech/react-native-image-resizer": "3.0.11",
"@callstack/repack": "~5.2.1",
@@ -58,7 +57,7 @@
"@react-native-community/datetimepicker": "^8.4.5",
"@react-native-community/netinfo": "^11.4.1",
"@react-native-community/toolbar-android": "^0.2.1",
"@react-native-documents/picker": "^11.0.3",
"@react-native-documents/picker": "^10.1.7",
"@react-native-masked-view/masked-view": "^0.3.2",
"@react-navigation/elements": "^1.3.3",
"@react-navigation/native": "^6.0.10",
@@ -88,7 +87,7 @@
"react": "19.1.1",
"react-async-hook": "^4.0.0",
"react-native": "0.82.1",
"react-native-actions-sheet": "^10.1.0",
"react-native-actions-sheet": "10.0.0-alpha.8",
"react-native-actions-shortcuts": "^1.0.1",
"react-native-background-actions": "^2.6.6",
"react-native-begin-background-task": "github:blockfirm/react-native-begin-background-task",
@@ -113,18 +112,18 @@
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-keychain": "4.0.5",
"react-native-material-menu": "^2.0.0",
"react-native-mmkv-storage": "^12.0.1",
"react-native-mmkv-storage": "^12.0.0",
"react-native-modal-datetime-picker": "14.0.0",
"react-native-navigation-bar-color": "2.0.2",
"react-native-notification-sounds": "0.5.5",
"react-native-orientation-locker": "^1.7.0",
"react-native-pager-view": "^8.0.0",
"react-native-pdf": "^7.0.3",
"react-native-pager-view": "^6.5.1",
"react-native-pdf": "6.7.7",
"react-native-privacy-snapshot": "github:standardnotes/react-native-privacy-snapshot",
"react-native-progress": "5.0.0",
"react-native-qrcode-svg": "^6.0.6",
"react-native-quick-sqlite": "^8.2.7",
"react-native-reanimated": "^4.2.0",
"react-native-reanimated": "^4.1.3",
"react-native-reanimated-progress-bar": "1.0.1",
"react-native-safe-area-context": "^5.6.1",
"react-native-scoped-storage": "^1.9.5",
@@ -134,15 +133,14 @@
"react-native-share": "^12.0.3",
"react-native-svg": "^15.12.0",
"react-native-swiper-flatlist": "3.2.2",
"react-native-tab-view": "^4.2.2",
"react-native-tab-view": "^4.1.3",
"react-native-theme-switch-animation": "^0.6.0",
"react-native-tooltips": "^1.0.3",
"react-native-url-polyfill": "^2.0.0",
"react-native-vector-icons": "10.3.0",
"react-native-view-shot": "^4.0.3",
"react-native-webview": "^13.13.5",
"react-native-wheel-color-picker": "^1.3.1",
"react-native-worklets": "^0.7.1",
"react-native-worklets": "^0.6.1",
"react-native-zip-archive": "6.0.9",
"timeago.js": "4.0.2",
"toggle-switch-react-native": "3.2.0",

View File

@@ -1,13 +0,0 @@
diff --git a/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js
index 6eca156..5a42107 100644
--- a/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js
+++ b/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js
@@ -208,7 +208,7 @@ class KeyboardAvoidingView extends React.Component<
];
} else {
this._subscriptions = [
- Keyboard.addListener('keyboardDidHide', this._onKeyboardChange),
+ Keyboard.addListener('keyboardDidHide', this._onKeyboardHide),
Keyboard.addListener('keyboardDidShow', this._onKeyboardChange),
];
}

View File

@@ -1,22 +1,3 @@
diff --git a/node_modules/react-native-actions-shortcuts/android/.settings/org.eclipse.buildship.core.prefs b/node_modules/react-native-actions-shortcuts/android/.settings/org.eclipse.buildship.core.prefs
deleted file mode 100644
index 8c253d6..0000000
--- a/node_modules/react-native-actions-shortcuts/android/.settings/org.eclipse.buildship.core.prefs
+++ /dev/null
@@ -1,13 +0,0 @@
-arguments=
-auto.sync=false
-build.scans.enabled=false
-connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.0))
-connection.project.dir=
-eclipse.preferences.version=1
-gradle.user.home=
-java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
-jvm.arguments=
-offline.mode=false
-override.workspace.settings=true
-show.console.view=true
-show.executions.view=true
diff --git a/node_modules/react-native-actions-shortcuts/android/build.gradle b/node_modules/react-native-actions-shortcuts/android/build.gradle
index 19bd311..642ddbc 100644
--- a/node_modules/react-native-actions-shortcuts/android/build.gradle
@@ -3807,7 +3788,7 @@ index b438823..ba03915 100644
}
diff --git a/node_modules/react-native-actions-shortcuts/android/src/main/java/com/reactnativeshortcuts/ShortcutsModule.kt b/node_modules/react-native-actions-shortcuts/android/src/main/java/com/reactnativeshortcuts/ShortcutsModule.kt
index ec847cc..f101793 100644
index ec847cc..a4686a0 100644
--- a/node_modules/react-native-actions-shortcuts/android/src/main/java/com/reactnativeshortcuts/ShortcutsModule.kt
+++ b/node_modules/react-native-actions-shortcuts/android/src/main/java/com/reactnativeshortcuts/ShortcutsModule.kt
@@ -28,18 +28,18 @@ class ShortcutsModule(reactContext: ReactApplicationContext) :
@@ -3872,7 +3853,7 @@ index ec847cc..f101793 100644
shortcutManager?.removeAllDynamicShortcuts()
}
@@ -145,6 +145,17 @@ class ShortcutsModule(reactContext: ReactApplicationContext) :
@@ -145,6 +145,19 @@ class ShortcutsModule(reactContext: ReactApplicationContext) :
fun isSupported(): Boolean {
return Build.VERSION.SDK_INT >= 25
}
@@ -3882,7 +3863,9 @@ index ec847cc..f101793 100644
+ requestCode: Int,
+ resultCode: Int,
+ data: Intent?
+ ) {}
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun onNewIntent(intent: Intent) {
+ emitEvent(intent)

View File

@@ -1,12 +0,0 @@
diff --git a/node_modules/react-native-gesture-handler/android/build.gradle b/node_modules/react-native-gesture-handler/android/build.gradle
index ac149a0..37f620c 100644
--- a/node_modules/react-native-gesture-handler/android/build.gradle
+++ b/node_modules/react-native-gesture-handler/android/build.gradle
@@ -187,6 +187,7 @@ android {
exclude "**/libreactnative.so"
exclude "**/libjsi.so"
exclude "**/libc++_shared.so"
+ exclude "**/libfbjni.so"
}
sourceSets.main {

View File

@@ -155,8 +155,39 @@ module.exports = (env) => {
type: "javascript/auto"
},
...Repack.getAssetTransformRules({
inline: false
})
inline: true
}),
/**
* This loader handles all static assets (images, video, audio and others), so that you can
* use (reference) them inside your application.
*
* If you wan to handle specific asset type manually, filter out the extension
* from `ASSET_EXTENSIONS`, for example:
* ```
* Repack.ASSET_EXTENSIONS.filter((ext) => ext !== 'svg')
* ```
*/
{
test: Repack.getAssetExtensionsRegExp(
Repack.ASSET_EXTENSIONS.filter((ext) => ext !== "svg")
),
use: {
loader: "@callstack/repack/assets-loader"
}
},
{
test: /\.svg$/,
use: [
{
loader: "@svgr/webpack",
options: {
native: true,
dimensions: false
}
}
]
}
]
},
plugins: [

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "@notesnook/web",
"description": "Your private note taking space",
"version": "3.3.7",
"version": "3.3.6-beta.0",
"private": true,
"main": "./src/app.js",
"homepage": "https://notesnook.com/",
@@ -86,7 +86,7 @@
"devDependencies": {
"@babel/core": "7.22.5",
"@cloudflare/workers-types": "^4.20250224.0",
"@playwright/test": "1.57.0",
"@playwright/test": "1.48.2",
"@swc/plugin-react-remove-properties": "^6.0.2",
"@trpc/server": "10.45.2",
"@types/babel__core": "^7.20.1",

View File

@@ -48,7 +48,6 @@ import { getFontSizes } from "@notesnook/theme/theme/font/fontsize.js";
import { useWindowControls } from "./hooks/use-window-controls";
import { STATUS_BAR_HEIGHT } from "./common/constants";
import { NavigationEvents } from "./navigation";
import { db } from "./common/db";
new WebExtensionRelay();
@@ -144,10 +143,6 @@ function DesktopAppContents() {
const isTablet = useTablet();
const navPane = useRef<SplitPaneImperativeHandle>(null);
useEffect(() => {
(async () => {})();
}, []);
useEffect(() => {
if (isTablet) navPane.current?.collapse(0);
else if (navPane.current?.isCollapsed(0)) navPane.current?.expand(0);

View File

@@ -25,7 +25,6 @@ import {
isFeatureSupported
} from "./utils/feature-check";
import { initializeLogger } from "./utils/logger";
import { shouldShowWrapped } from "./utils/should-show-wrapped";
type Route<TProps = null> = {
component: () => Promise<{
@@ -56,9 +55,6 @@ const routes = {
"/plans": {
component: () => import("./views/plans")
},
"/wrapped": {
component: () => import("./views/wrapped")
},
"/checkout": {
component: () => import("./views/checkout")
},
@@ -126,12 +122,6 @@ function getRoute(): RouteWithPath<AuthProps> | RouteWithPath {
routes[path] ? { route: routes[path], path } : null
) as RouteWithPath<AuthProps> | null;
if (route?.path === "/wrapped" && !shouldShowWrapped())
return {
route: routes.default,
path: "default"
};
return signup || sessionExpired || route || fallback;
}

View File

@@ -226,13 +226,11 @@ export default function TabsView() {
<TableOfContents sessionId={activeSession.id} />
</Pane>
) : null}
{arePropertiesVisible &&
activeSession &&
activeSession.type !== "new" && (
<Pane id="properties-pane" initialSize={250} minSize={250}>
<Properties sessionId={activeSession.id} />
</Pane>
)}
{arePropertiesVisible && activeSession && (
<Pane id="properties-pane" initialSize={250} minSize={250}>
<Properties sessionId={activeSession.id} />
</Pane>
)}
</SplitPane>
<DropZone overlayRef={overlayRef} />
</ScopedThemeProvider>
@@ -850,27 +848,17 @@ function useDragOverlay() {
e.preventDefault();
}
function handleKeyDown(e: KeyboardEvent) {
if (e.key === "Escape") {
hideOverlay();
}
}
dropElement.addEventListener("dragenter", showOverlay);
overlay.addEventListener("drop", hideOverlay);
overlay.addEventListener("dragenter", allowDrag);
overlay.addEventListener("dragover", allowDrag);
overlay.addEventListener("dragleave", hideOverlay);
overlay.addEventListener("click", hideOverlay);
document.addEventListener("keydown", handleKeyDown);
return () => {
dropElement.removeEventListener("dragenter", showOverlay);
overlay.removeEventListener("drop", hideOverlay);
overlay.removeEventListener("dragenter", allowDrag);
overlay.removeEventListener("dragover", allowDrag);
overlay.removeEventListener("dragleave", hideOverlay);
overlay.removeEventListener("click", hideOverlay);
document.removeEventListener("keydown", handleKeyDown);
};
}, []);

View File

@@ -202,7 +202,7 @@ function ListItem<TItem extends Item, TContext>(
data-test-id={`title`}
variant={"body"}
sx={{
whiteSpace: "pre",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
fontWeight: isCompact ? "body" : "medium",

View File

@@ -1,143 +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 { Box, Flex, Text } from "@theme-ui/components";
import { SxProp } from "@theme-ui/core";
type MonthlyActivityHeatmapProps = {
monthlyStats: Record<string, number>;
year?: number;
} & SxProp;
const MONTHS = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];
const MONTHS_SHORT = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
export function MonthlyActivityHeatmap({
monthlyStats
}: MonthlyActivityHeatmapProps) {
// Find max count for bar height calculation
const maxCount = Math.max(...Object.values(monthlyStats), 1);
// Create month data with counts
const monthData = MONTHS.map((month) => ({
month,
count: monthlyStats[month] || 0
}));
return (
<>
{/* Bar chart */}
<Flex
sx={{
alignItems: "flex-end",
justifyContent: "space-between",
gap: 2,
height: "100%",
width: "100%",
position: "relative",
pb: 2
}}
>
{monthData.map((data, index) => {
const barHeight = maxCount > 0 ? (data.count / maxCount) * 100 : 0;
return (
<Flex
key={data.month}
sx={{
flexDirection: "column",
alignItems: "center",
justifyContent: "flex-end",
flex: 1,
gap: 2,
cursor: "pointer",
"&:hover .tooltip": { opacity: 1 },
"&:hover .bar": { bg: "accent" },
height: "100%"
}}
>
<Flex
className="tooltip"
sx={{ opacity: 0, bg: "background", zIndex: 1000 }}
>
<Text variant="body" sx={{ fontWeight: "bold" }}>
{data.count}
</Text>
</Flex>
<Box
className="bar"
sx={{
width: "100%",
height: `${barHeight}%`,
minHeight: data.count > 0 ? "10px" : "5px",
bg: maxCount === data.count ? "accent" : "paragraph",
borderRadius: "4px 4px 0 0",
transition: "all 0.3s ease",
position: "relative",
"&:hover": {
transform: "scaleY(1.05)",
transformOrigin: "bottom"
}
}}
></Box>
<Text
sx={{
fontSize: "11px",
color: "paragraph-secondary",
fontWeight: "normal",
transition: "all 0.3s ease"
}}
>
{MONTHS_SHORT[index]}
</Text>
</Flex>
);
})}
</Flex>
</>
);
}

View File

@@ -97,6 +97,7 @@ import { strings } from "@notesnook/intl";
import Tags from "../../views/tags";
import { Notebooks } from "../../views/notebooks";
import { UserProfile } from "../../dialogs/settings/components/user-profile";
import { SUBSCRIPTION_STATUS } from "../../common/constants";
import {
checkFeature,
createSetDefaultHomepageMenuItem,
@@ -104,6 +105,7 @@ import {
withFeatureCheck
} from "../../common";
import { TabItem } from "./tab-item";
import Notice from "../notice";
import { Freeze } from "react-freeze";
import { CREATE_BUTTON_MAP } from "../../common";
import { useStore as useNotebookStore } from "../../stores/notebook-store";
@@ -116,7 +118,6 @@ import {
useIsFeatureAvailable
} from "@notesnook/common";
import { isUserSubscribed } from "../../hooks/use-is-user-premium";
import { shouldShowWrapped } from "../../utils/should-show-wrapped";
type Route = {
id: "notes" | "favorites" | "reminders" | "monographs" | "trash" | "archive";
@@ -448,17 +449,7 @@ function NavigationMenu({ onExpand }: { onExpand?: () => void }) {
</FlexScrollContainer>
</Freeze>
</Flex>
{currentTab.id === "home" && !isCollapsed && shouldShowWrapped() ? (
<Button
variant="accent"
sx={{ m: 2 }}
onClick={() => {
hardNavigate("/wrapped");
}}
>
🎉 Wrapped {new Date().getFullYear()}
</Button>
) : null}
{currentTab.id === "home" && !isCollapsed ? <Notice /> : null}
</ScopedThemeProvider>
);
}

View File

@@ -153,7 +153,7 @@ export function Notebook(props: NotebookProps) {
variant={"body"}
color={isOpened ? "paragraph-selected" : "paragraph"}
sx={{
whiteSpace: "pre",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
fontWeight: "body",

View File

@@ -67,7 +67,7 @@ function Tag(props: TagProps) {
variant={"body"}
color={isSelected ? "paragraph-selected" : "paragraph"}
sx={{
whiteSpace: "pre",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
fontWeight: "body",

View File

@@ -147,7 +147,7 @@ export const BuyDialog = DialogManager.register(function BuyDialog(
</Text>
</Flex>
<PlansList
selectedPlan={user?.subscription?.productId}
selectedPlan={user?.subscription.productId}
recommendedPlan={SubscriptionPlan.PRO}
onPlanSelected={(plan) => selectPlan(plan)}
/>

View File

@@ -42,7 +42,7 @@ import { useStore as useUserStore } from "../../stores/user-store";
import { getCurrencySymbol } from "../../common/currencies";
type PlansListProps = {
selectedPlan?: string | null;
selectedPlan?: string;
loadAllPlans?: boolean;
ignoreTrial?: boolean;
recommendedPlan?: SubscriptionPlan;

View File

@@ -91,27 +91,7 @@ const features: Record<FeatureKeys, Feature> = {
)
}
]
: [
{
title: "Wrapped 2025",
subtitle:
"Notesnook Wrapped 2025 is your personal recap of the year you spent with Notesnook. Available throughout December and accessible from the sidebar, it highlights your activity, stats and how you used Notesnook this year."
},
{
title: "Monograph analytics",
subtitle:
"Pro users can now see view count analytics for monographs."
},
{
title: "Twitter/X embed support",
subtitle: "Simply paste the post URL in the Insert Embed dialog."
},
{
title: "New keyboard shortcuts",
subtitle:
"Use Ctrl/Cmd + Alt/Option + F to open search/replace in the editor. We have also added Ctrl/Cmd + Alt/Option + C for toggling text color."
}
],
: [],
cta: {
title: strings.gotIt(),
icon: Checkmark,

View File

@@ -454,7 +454,7 @@ export async function checkUpload(
expectedSize: number
) {
const size = await getUploadedFileSize(filename);
const totalChunks = Math.ceil(size / (chunkSize + ABYTES));
const totalChunks = Math.ceil(size / chunkSize);
const decryptedLength = size - totalChunks * ABYTES;
const error =
size === 0
@@ -520,7 +520,7 @@ async function downloadFile(
throw new Error(error);
}
const totalChunks = Math.ceil(size / (chunkSize + ABYTES));
const totalChunks = Math.ceil(size / chunkSize);
const decryptedLength = size - totalChunks * ABYTES;
if (attachment && attachment.size !== decryptedLength) {
const error = `File length mismatch. Expected ${attachment.size} but got ${decryptedLength} bytes. Please upload this file again from the attachment manager. (File hash: ${filename})`;

View File

@@ -20,12 +20,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { INNCrypto } from "@notesnook/crypto";
import CryptoWorker from "./nncrypto.worker?worker";
import { wrap } from "comlink";
import { NNCrypto as NNCryptoSync } from "@notesnook/crypto";
import { isTransferableStreamsSupported } from "../utils/feature-check";
export const NNCrypto = isTransferableStreamsSupported()
? (wrap<INNCrypto>(new CryptoWorker()) as INNCrypto)
: new NNCryptoSync();
export const NNCrypto = wrap<INNCrypto>(new CryptoWorker()) as INNCrypto;
// TODO: disable until we fix the `pull failed` errors for good.
// IS_DESKTOP_APP && window.NativeNNCrypto
// ? new window.NativeNNCrypto()

View File

@@ -22,28 +22,9 @@ const FEATURE_CHECKS = {
cache: false,
indexedDB: false,
clonableCryptoKey: false,
applePaySupported: false,
transferableStreams: false
applePaySupported: false
};
export function isTransferableStreamsSupported() {
try {
const readable = new ReadableStream({
pull(controller) {
controller.enqueue(new Uint8Array([1, 2, 3]));
controller.close();
}
});
window.postMessage(readable, [readable]);
FEATURE_CHECKS.transferableStreams = true;
return true;
} catch {
console.log("Transferable streams not supported");
FEATURE_CHECKS.transferableStreams = false;
return false;
}
}
async function isApplePaySupported() {
try {
FEATURE_CHECKS.applePaySupported =
@@ -118,7 +99,6 @@ async function isCryptoKeyClonable() {
export async function initializeFeatureChecks() {
await Promise.allSettled([
isTransferableStreamsSupported(),
isOPFSSupported(),
isCacheSupported(),
isIndexedDBSupported(),

View File

@@ -1,23 +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/>.
*/
export const shouldShowWrapped = () => {
const now = new Date();
return now.getMonth() === 11;
};

View File

@@ -1,776 +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 { Button, Flex, Text, Box, FlexProps } from "@theme-ui/components";
import { db } from "../common/db";
import { useState, useEffect, useRef } from "react";
import { NoteStats, WrappedStats } from "@notesnook/core";
import { formatBytes } from "@notesnook/common";
import { ArrowDown, ArrowLeft, Loading } from "../components/icons";
import { hardNavigate } from "../navigation";
import { MonthlyActivityHeatmap } from "../components/monthly-activity-heatmap";
function formatNumber(num: number) {
return num.toLocaleString();
}
function formatCount(num: number) {
return num > 1000 ? `${(num / 1000).toFixed(0)}k` : num.toString();
}
interface SlideProps {
children: React.ReactNode;
pattern?: "dots" | "grid" | "diagonal" | "none";
}
function Slide({
children,
pattern = "none",
sx,
...flexProps
}: SlideProps & FlexProps) {
const slideRef = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
}
},
{ threshold: 0.5 }
);
if (slideRef.current) {
observer.observe(slideRef.current);
}
return () => {
if (slideRef.current) {
observer.unobserve(slideRef.current);
}
};
}, []);
const getBackgroundPattern = () => {
switch (pattern) {
case "dots":
return "radial-gradient(circle, var(--border) 1px, transparent 1px)";
case "grid":
return "linear-gradient(var(--border) 1px, transparent 1px), linear-gradient(90deg, var(--border) 1px, transparent 1px)";
case "diagonal":
return "repeating-linear-gradient(-45deg, transparent, transparent 20px, var(--border) 20px, var(--border) 21px)";
default:
return "none";
}
};
const getBackgroundSize = () => {
switch (pattern) {
case "dots":
return "20px 20px";
case "grid":
return "30px 30px";
case "diagonal":
default:
return "auto";
}
};
return (
<Flex
ref={slideRef}
sx={{
minHeight: "100vh",
minWidth: "100%",
scrollSnapAlign: "start",
scrollSnapStop: "always",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
p: 4,
position: "relative",
backgroundImage: getBackgroundPattern(),
backgroundSize: getBackgroundSize(),
backgroundPosition: "center"
}}
>
<Flex
{...flexProps}
sx={{
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
opacity: isVisible ? 1 : 0,
transform: isVisible ? "translateY(0)" : "translateY(50px)",
transition: "opacity 0.8s ease-out, transform 0.8s ease-out",
...sx
}}
>
{children}
</Flex>
</Flex>
);
}
function WelcomeSlide({ loading }: { loading: boolean }) {
return (
<Slide pattern="dots">
<Text
sx={{
fontSize: "6rem",
fontWeight: "bold",
mb: 3,
textAlign: "center",
background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
animation: "slideUp 1s ease-out"
}}
>
🎉
</Text>
<Text
variant="heading"
sx={{
fontSize: ["2rem", "3rem", "4rem"],
fontWeight: "bold",
mb: 2,
textAlign: "center",
animation: "slideUp 1s ease-out 0.2s both"
}}
>
Your {new Date().getFullYear()} Wrapped
</Text>
{loading ? (
<Loading
sx={{
animation: "fadeIn 1s ease-out 0.4s both"
}}
size={30}
/>
) : (
<>
<Text
sx={{
fontSize: ["1rem", "1.2rem"],
textAlign: "center",
animation: "fadeIn 1s ease-out 0.4s both"
}}
>
Let&apos;s look back at your year in Notesnook
</Text>
<Text
variant="body"
sx={{
mt: 4,
fontSize: "title",
color: "paragraph-secondary",
textAlign: "center",
animation: "fadeIn 1s ease-out 0.4s both"
}}
>
Scroll down to explore
</Text>
<ArrowDown sx={{ mt: 2 }} color="paragraph-secondary" />
</>
)}
</Slide>
);
}
function TotalNotesSlide({ count }: { count: number }) {
return (
<Slide pattern="dots">
<Flex>
<Flex sx={{ flexDirection: "column" }}>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
textAlign: "center",
animation: "fadeIn 0.8s ease-out"
}}
>
You created
</Text>
<Text
variant="heading"
sx={{
fontSize: ["5rem", "7rem", "8rem"],
textAlign: "center",
color: "accent",
animation: "scaleIn 0.8s ease-out 0.2s both"
}}
>
{formatNumber(count)}
</Text>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
textAlign: "center",
animation: "fadeIn 0.8s ease-out 0.4s both"
}}
>
notes this year
</Text>
</Flex>
<Flex
sx={{
flexDirection: "column",
ml: [0, 5],
mt: [4, 0],
borderLeft: ["none", "1px solid var(--border)"],
pl: [0, 5],
borderTop: ["1px solid var(--border)", "none"]
}}
>
<Text
variant="body"
color="paragraph-secondary"
sx={{
fontSize: ["1.2rem", "1.2rem"],
animation: "fadeIn 0.8s ease-out",
lineHeight: 1.8
}}
>
That&apos;s <strong>{formatNumber(count)}</strong>
<br />
ideas
<br />
thoughts
<br />
memories.
<br />
100% encrypted.
<br />
100% yours.
</Text>
</Flex>
</Flex>
</Slide>
);
}
const TOTAL_WORDS_TAGLINES = {
1000: "That's longer than the average blog post on Medium!",
10000: "That's real commitment to your mindspace.",
25000: "That's almost the length of a short novel!",
50000:
"That's the length of The Great Gatsby if you were F. Scott Fitzgerald.",
100000: "You wrote more than many published authors this year.",
250000: "Woah! Your notes could fill a small library.",
500000: "Your vault is becoming a chronicle.",
1000000: "That's longer than the entire Harry Potter series!"
};
function TotalWordsSlide({ count }: { count: number }) {
const tagline = Object.entries(TOTAL_WORDS_TAGLINES)
.sort((a, b) => Number(b[0]) - Number(a[0]))
.find(([threshold]) => count >= Number(threshold))?.[1];
return (
<Slide pattern="dots">
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
textAlign: "center",
animation: "fadeIn 0.8s ease-out"
}}
>
You wrote a total of
</Text>
<Text
variant="heading"
sx={{
fontSize: ["5rem", "7rem"],
textAlign: "center",
color: "accent",
animation: "scaleIn 0.8s ease-out 0.2s both"
}}
>
{formatNumber(count)}
</Text>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
textAlign: "center",
animation: "fadeIn 0.8s ease-out 0.4s both"
}}
>
words this year
</Text>
{tagline ? (
<Text
variant="body"
color="paragraph-secondary"
sx={{
fontSize: ["1.2rem", "1.2rem"],
animation: "fadeIn 0.8s ease-out",
borderTop: "1px solid var(--border)",
mt: 3,
pt: 3
}}
>
{tagline}
</Text>
) : null}
</Slide>
);
}
type ActivityStatsSlideProps = {
mostNotesCreatedInMonth: NoteStats["mostNotesCreatedInMonth"];
mostNotesCreatedInDay: NoteStats["mostNotesCreatedInDay"];
};
function ActivityStatsSlide({
mostNotesCreatedInMonth,
mostNotesCreatedInDay
}: ActivityStatsSlideProps) {
if (!mostNotesCreatedInMonth && !mostNotesCreatedInDay) return null;
return (
<Slide pattern="diagonal" sx={{ alignItems: "start" }}>
{mostNotesCreatedInMonth && (
<>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"]
}}
>
Your most productive month was
</Text>
<Flex
sx={{
alignItems: "center",
justifyContent: "space-between",
width: "100%"
}}
>
<Text
variant="heading"
sx={{
fontSize: ["5rem", "7rem", "3rem"]
}}
>
{mostNotesCreatedInMonth.month}
</Text>
<Text
variant="body"
sx={{ fontSize: "1rem" }}
color="paragraph-secondary"
>
{formatNumber(mostNotesCreatedInMonth.count)} notes
</Text>
</Flex>
</>
)}
{mostNotesCreatedInDay && (
<>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
mt: 5
}}
>
Your favorite day to write was
</Text>
<Flex
sx={{
alignItems: "center",
justifyContent: "space-between",
width: "100%"
}}
>
<Text
variant="heading"
sx={{
fontSize: ["5rem", "7rem", "3rem"]
}}
>
{mostNotesCreatedInDay.day}
</Text>
<Text
variant="body"
sx={{ fontSize: "1rem" }}
color="paragraph-secondary"
>
{formatNumber(mostNotesCreatedInDay.count)} notes
</Text>
</Flex>
</>
)}
</Slide>
);
}
function SummarySlide({ stats }: { stats: WrappedStats }) {
return (
<Slide
pattern="dots"
sx={{
bg: "background-secondary",
border: "1px solid var(--accent)",
borderRadius: "dialog",
boxShadow: "-15px 15px 0px 0px var(--accent)",
p: 5
}}
>
<svg
style={{
height: 20,
width: 20,
position: "absolute",
bottom: "20px",
right: "20px"
}}
>
<use href="#themed-logo" />
</svg>
<Text
variant="heading"
sx={{
fontSize: "1.2rem",
fontWeight: 800,
textAlign: "center",
transform: "skew(-10deg) scaleX(1.5)",
letterSpacing: "-1px",
mb: "25px",
textDecorationLine: "underline",
textDecorationColor: "border"
}}
>
NOTESNOOK WRAPPED {new Date().getFullYear()}
</Text>
<Flex
sx={{
flexDirection: ["column", "row"],
gap: "30px",
justifyContent: "center",
alignItems: "center"
}}
>
<Flex
sx={{
flexDirection: "column",
flex: 1
}}
>
<Box
sx={{
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gridTemplateRows: "1fr 1fr",
gap: 4,
height: "100%"
}}
>
{[
{
icon: "📝",
count: stats.totalNotes,
label: "Notes"
},
{
icon: "🎨",
count: stats.totalColors,
label: "Colors"
},
{
icon: "📚",
count: stats.totalNotebooks,
label: "Notebooks"
},
{
icon: "🏷️",
count: stats.totalTags,
label: "Tags"
},
{
icon: "📂",
count: stats.totalAttachments,
label: "Files"
},
{
icon: "☁️",
count: stats.totalMonographs,
label: "Monographs"
}
].map(({ icon, count, label }) => (
<Flex
key={label}
sx={{
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
gap: 1
}}
>
<Text sx={{ fontSize: "1.5rem" }}>{icon}</Text>
<Text
sx={{
fontSize: "2rem",
fontWeight: "bold"
}}
>
{formatCount(count)}
</Text>
<Text sx={{ fontSize: "0.85rem", color: "fontTertiary" }}>
{label}
</Text>
</Flex>
))}
</Box>
<Flex
sx={{
flexDirection: "column",
gap: 2,
borderTop: "1px solid var(--border)",
mt: 6,
pt: 3,
"& strong": {
color: "accent"
}
}}
>
<Text sx={{ fontSize: "1rem", fontWeight: "bold" }}>
Fun facts of the year
</Text>
{stats.mostNotesCreatedInMonth && (
<Text sx={{ fontSize: "0.9rem", color: "fontTertiary" }}>
📅 Your most productive month was{" "}
<Text as="strong">{stats.mostNotesCreatedInMonth.month}</Text>
</Text>
)}
{stats.mostNotesCreatedInDay && (
<Text sx={{ fontSize: "0.9rem", color: "fontTertiary" }}>
🗓 Your favorite day to write was{" "}
<Text as="strong">{stats.mostNotesCreatedInDay.day}</Text>
</Text>
)}
{stats.largestNote && (
<Text
sx={{
fontSize: "0.9rem",
color: "fontTertiary",
maxWidth: 340
}}
>
📝 Your longest note was{" "}
<Text as="strong">
{formatNumber(stats.largestNote.length)}
{" words"}
</Text>
</Text>
)}
{stats.largestAttachment && (
<Text
sx={{
fontSize: "0.9rem",
color: "fontTertiary",
maxWidth: 340
}}
>
🔗 Your largest attachment was{" "}
<strong>{formatBytes(stats.largestAttachment.size)}</strong>
</Text>
)}
</Flex>
</Flex>
<Flex
sx={{
flexDirection: "column",
justifyContent: "stretch",
height: "100%",
flex: 1
}}
>
<Flex
sx={{
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
}}
>
<Text sx={{ fontSize: "2.5rem" }}></Text>
<Text
sx={{
fontSize: "3rem",
fontWeight: "bold",
color: "accent"
}}
>
{formatNumber(stats.totalWords)}
</Text>
<Text sx={{ fontSize: "1rem", color: "fontTertiary" }}>
Words Written
</Text>
</Flex>
<Flex
sx={{
flexDirection: "column",
borderTop: "1px solid var(--border)",
mt: 6,
pt: 2,
flex: 1
}}
>
<MonthlyActivityHeatmap monthlyStats={stats.monthlyStats} />
<Text
sx={{
fontSize: "1rem",
color: "fontTertiary",
textAlign: "center"
}}
>
Notes per month
</Text>
</Flex>
</Flex>
</Flex>
<Text
variant="body"
color="paragraph-secondary"
sx={{ mt: 2, borderTop: "1px solid var(--border)", pt: 2 }}
>
Generated 100% locally on your device.
</Text>
</Slide>
);
}
export default function Wrapped() {
const [loading, setLoading] = useState(false);
const [stats, setStats] = useState<WrappedStats>();
useEffect(() => {
async function loadWrapped() {
setLoading(true);
try {
console.time("wrapped - getting from core");
const wrapped = await db.wrapped.get();
console.timeEnd("wrapped - getting from core");
setStats(wrapped);
} finally {
setLoading(false);
}
}
loadWrapped();
}, []);
return (
<>
<style>
{`
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
`}
</style>
<Flex
sx={{
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
flexDirection: "column",
overflowY: "scroll",
overflowX: "hidden",
scrollSnapType: "y mandatory",
scrollBehavior: "smooth",
"&::-webkit-scrollbar": {
display: "none"
},
msOverflowStyle: "none",
scrollbarWidth: "none"
}}
>
<WelcomeSlide loading={loading} />
{stats ? (
<>
<TotalNotesSlide count={stats.totalNotes} />
{stats.totalWords > 0 && (
<TotalWordsSlide count={stats.totalWords} />
)}
{(stats.mostNotesCreatedInMonth || stats.mostNotesCreatedInDay) && (
<ActivityStatsSlide
mostNotesCreatedInMonth={stats.mostNotesCreatedInMonth}
mostNotesCreatedInDay={stats.mostNotesCreatedInDay}
/>
)}
<SummarySlide stats={stats} />
</>
) : null}
</Flex>
<Button
onClick={() => hardNavigate("/")}
variant="secondary"
sx={{
position: "fixed",
top: 3,
left: 3,
zIndex: 1000
}}
>
<Flex sx={{ alignItems: "center", gap: 1, justifyContent: "center" }}>
<ArrowLeft size={16} />
<Text variant="body">Go back to app</Text>
</Flex>
</Button>
</>
);
}

View File

@@ -9,73 +9,71 @@ The following keyboard shortcuts will help you navigate Notesnook faster.
### General
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Search in notes list view if editor is not focused | Ctrl F | Ctrl F | ⌘ F |
| Settings | Ctrl , | Ctrl , | ⌘ , |
| Keyboard shortcuts | Ctrl / | Ctrl / | ⌘ / |
| New note | - | Ctrl N | ⌘ N |
| Description | Web | Windows/Linux | Mac |
| -------------------------------------------------- | ------ | ------------- | --- |
| Search in notes list view if editor is not focused | Ctrl F | Ctrl F | ⌘ F |
| Settings | Ctrl , | Ctrl , | ⌘ , |
| Keyboard shortcuts | Ctrl / | Ctrl / | ⌘ / |
| New note | - | Ctrl N | ⌘ N |
### Navigation
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Next tab | Ctrl Alt → / Ctrl Alt ⇧ → | Ctrl tab | ⌘ tab |
| Previous tab | Ctrl Alt ← / Ctrl Alt ⇧ ← | Ctrl ⇧ tab | ⌘ ⇧ tab |
| Command palette | Ctrl ⇧ P / Ctrl ⇧ : | Ctrl ⇧ P | ⌘ ⇧ P |
| Quick open | Ctrl P | Ctrl P | ⌘ P |
| New tab | - | Ctrl T | ⌘ T |
| Close active tab | - | Ctrl W | ⌘ W |
| Close all tabs | - | Ctrl ⇧ W | ⌘ ⇧ W |
| Description | Web | Windows/Linux | Mac |
| ---------------- | ------------------------- | ------------- | ------- |
| Next tab | Ctrl Alt → / Ctrl Alt ⇧ → | Ctrl tab | ⌘ tab |
| Previous tab | Ctrl Alt ← / Ctrl Alt ⇧ ← | Ctrl ⇧ tab | ⌘ ⇧ tab |
| Command palette | Ctrl ⇧ P | Ctrl ⇧ P | ⌘ ⇧ P |
| Quick open | Ctrl P | Ctrl P | ⌘ P |
| New tab | - | Ctrl T | ⌘ T |
| Close active tab | - | Ctrl W | ⌘ W |
| Close all tabs | - | Ctrl ⇧ W | ⌘ ⇧ W |
### Editor
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Add attachment | Ctrl ⇧ A | Ctrl ⇧ A | ⌘ ⇧ A |
| Insert blockquote | Ctrl ⇧ B | Ctrl ⇧ B | ⌘ ⇧ B |
| Toggle bold | Ctrl B | Ctrl B | ⌘ B |
| Toggle bullet list | Ctrl ⇧ 8 | Ctrl ⇧ 8 | ⌘ ⇧ 8 |
| Toggle check list | Ctrl ⇧ 9 | Ctrl ⇧ 9 | ⌘ ⇧ 9 |
| Split list item | ↵ | ↵ | ↵ |
| Lift list item | ⇧ Tab | ⇧ Tab | ⇧ Tab |
| Sink list item | Ctrl ⇧ Down | Ctrl ⇧ Down | ⌘ ⇧ Down |
| Toggle code | Ctrl E | Ctrl E | ⌘ E |
| Toggle code block | Ctrl ⇧ C | Ctrl ⇧ C | ⌘ ⇧ C |
| Insert date | Alt D | Alt D | ⌥ D |
| Insert time | Alt T | Alt T | ⌥ T |
| Insert date and time | Ctrl Alt D | Ctrl Alt D | ⌘ ⌥ D |
| Insert date and time with timezone | Ctrl Alt Z | Ctrl Alt Z | ⌘ ⌥ Z |
| Increase font size | Ctrl [ | Ctrl [ | ⌘ [ |
| Decrease font size | Ctrl ] | Ctrl ] | ⌘ ] |
| Insert paragraph | Ctrl Alt 0 | Ctrl Alt 0 | ⌘ 0 |
| Insert heading 1 | Ctrl Alt 1 | Ctrl Alt 1 | ⌘ ⌥ 1 |
| Insert heading 2 | Ctrl Alt 2 | Ctrl Alt 2 | ⌘ ⌥ 2 |
| Insert heading 3 | Ctrl Alt 3 | Ctrl Alt 3 | ⌘ ⌥ 3 |
| Insert heading 4 | Ctrl Alt 4 | Ctrl Alt 4 | ⌘ ⌥ 4 |
| Insert heading 5 | Ctrl Alt 5 | Ctrl Alt 5 | ⌘ ⌥ 5 |
| Insert heading 6 | Ctrl Alt 6 | Ctrl Alt 6 | ⌘ ⌥ 6 |
| Undo | Ctrl Z | Ctrl Z | ⌘ Z |
| Redo | Ctrl ⇧ Z / Ctrl Y | Ctrl ⇧ Z / Ctrl Y | ⌘ ⇧ Z / ⌘ Y |
| Add image | Ctrl ⇧ I | Ctrl ⇧ I | ⌘ ⇧ I |
| Toggle italic | Ctrl I | Ctrl I | ⌘ I |
| Remove formatting in selection | Ctrl \ | Ctrl \ | ⌘ \ |
| Insert internal link | Ctrl ⇧ K | Ctrl ⇧ K | ⌘ ⇧ K |
| Insert link | Ctrl K | Ctrl K | ⌘ K |
| Insert math block | Ctrl ⇧ M | Ctrl ⇧ M | ⌘ ⇧ M |
| Toggle ordered list | Ctrl ⇧ 7 | Ctrl ⇧ 7 | ⌘ ⇧ 7 |
| Toggle outline list | Ctrl ⇧ O | Ctrl ⇧ O | ⌘ ⇧ O |
| Toggle outline list expand | Ctrl Space | Ctrl Space | ⌘ Space |
| Open search | Ctrl F | Ctrl F | ⌘ F |
| Open search and replace | Ctrl Alt F | Ctrl Alt F | ⌘ ⌥ F |
| Toggle strike | Ctrl ⇧ S | Ctrl ⇧ S | ⌘ ⇧ S |
| Toggle subscript | Ctrl , | Ctrl , | ⌘ , |
| Toggle superscript | Ctrl . | Ctrl . | ⌘ . |
| Toggle task list | Ctrl ⇧ T | Ctrl ⇧ T | ⌘ ⇧ T |
| Text align center | Ctrl ⇧ E | Ctrl ⇧ E | ⌘ ⇧ E |
| Text align justify | Ctrl ⇧ J | Ctrl ⇧ J | ⌘ ⇧ J |
| Text align left | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L |
| Text align right | Ctrl ⇧ R | Ctrl ⇧ R | ⌘ ⇧ R |
| Underline | Ctrl U | Ctrl U | ⌘ U |
| Toggle highlight | Ctrl Alt H | Ctrl Alt H | ⌘ ⌥ H |
| Toggle text color | Ctrl Alt C | Ctrl Alt C | ⌘ ⌥ C |
| Description | Web | Windows/Linux | Mac |
| ---------------------------------- | ----------------- | ----------------- | ----------- |
| Add attachment | Ctrl ⇧ A | Ctrl ⇧ A | ⌘ ⇧ A |
| Insert blockquote | Ctrl ⇧ B | Ctrl ⇧ B | ⌘ ⇧ B |
| Toggle bold | Ctrl B | Ctrl B | ⌘ B |
| Toggle bullet list | Ctrl ⇧ 8 | Ctrl ⇧ 8 | ⌘ ⇧ 8 |
| Toggle check list | Ctrl ⇧ 9 | Ctrl ⇧ 9 | ⌘ ⇧ 9 |
| Split list item | ↵ | ↵ | ↵ |
| Lift list item | ⇧ Tab | ⇧ Tab | ⇧ Tab |
| Sink list item | Ctrl ⇧ Down | Ctrl ⇧ Down | ⌘ ⇧ Down |
| Toggle code | Ctrl E | Ctrl E | ⌘ E |
| Toggle code block | Ctrl ⇧ C | Ctrl ⇧ C | ⌘ ⇧ C |
| Insert date | Alt D | Alt D | ⌥ D |
| Insert time | Alt T | Alt T | ⌥ T |
| Insert date and time | Ctrl Alt D | Ctrl Alt D | ⌘ ⌥ D |
| Insert date and time with timezone | Ctrl Alt Z | Ctrl Alt Z | ⌘ ⌥ Z |
| Increase font size | Ctrl [ | Ctrl [ | ⌘ [ |
| Decrease font size | Ctrl ] | Ctrl ] | ⌘ ] |
| Insert paragraph | Ctrl ⇧ 0 | Ctrl ⇧ 0 | ⌘ 0 |
| Insert heading 1 | Ctrl Alt 1 | Ctrl Alt 1 | ⌘ ⌥ 1 |
| Insert heading 2 | Ctrl Alt 2 | Ctrl Alt 2 | ⌘ ⌥ 2 |
| Insert heading 3 | Ctrl Alt 3 | Ctrl Alt 3 | ⌘ ⌥ 3 |
| Insert heading 4 | Ctrl Alt 4 | Ctrl Alt 4 | ⌘ ⌥ 4 |
| Insert heading 5 | Ctrl Alt 5 | Ctrl Alt 5 | ⌘ ⌥ 5 |
| Insert heading 6 | Ctrl Alt 6 | Ctrl Alt 6 | ⌘ ⌥ 6 |
| Undo | Ctrl Z | Ctrl Z | ⌘ Z |
| Redo | Ctrl ⇧ Z / Ctrl Y | Ctrl ⇧ Z / Ctrl Y | ⌘ ⇧ Z / ⌘ Y |
| Add image | Ctrl ⇧ I | Ctrl ⇧ I | ⌘ ⇧ I |
| Toggle italic | Ctrl I | Ctrl I | ⌘ I |
| Remove formatting in selection | Ctrl \ | Ctrl \ | ⌘ \ |
| Insert internal link | Ctrl ⇧ K | Ctrl ⇧ K | ⌘ ⇧ K |
| Insert link | Ctrl K | Ctrl K | ⌘ K |
| Insert math block | Ctrl ⇧ M | Ctrl ⇧ M | ⌘ ⇧ M |
| Toggle ordered list | Ctrl ⇧ 7 | Ctrl ⇧ 7 | ⌘ ⇧ 7 |
| Toggle outline list | Ctrl ⇧ O | Ctrl ⇧ O | ⌘ ⇧ O |
| Toggle outline list expand | Ctrl Space | Ctrl Space | ⌘ Space |
| Open search | Ctrl F | Ctrl F | ⌘ F |
| Toggle strike | Ctrl ⇧ S | Ctrl ⇧ S | ⌘ ⇧ S |
| Toggle subscript | Ctrl , | Ctrl , | ⌘ , |
| Toggle superscript | Ctrl . | Ctrl . | ⌘ . |
| Toggle task list | Ctrl ⇧ T | Ctrl ⇧ T | ⌘ ⇧ T |
| Text align center | Ctrl ⇧ E | Ctrl ⇧ E | ⌘ ⇧ E |
| Text align justify | Ctrl ⇧ J | Ctrl ⇧ J | ⌘ ⇧ J |
| Text align left | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L |
| Text align right | Ctrl ⇧ R | Ctrl ⇧ R | ⌘ ⇧ R |
| Underline | Ctrl U | Ctrl U | ⌘ U |
| Toggle highlight | Ctrl Alt H | Ctrl Alt H | ⌘ ⌥ H |

View File

@@ -1,5 +0,0 @@
- Get an overview of your year with Notesnook with Wrapped 2025
- Cell selection and column resizing in tables
- Bug fixes and minor improvements
Thank you for using Notesnook!

View File

@@ -1,5 +0,0 @@
- Get an overview of your year with Notesnook with Wrapped 2025
- Cell selection and column resizing in tables
- Bug fixes and minor improvements
Thank you for using Notesnook!

View File

@@ -34,7 +34,10 @@ export default defineConfig({
js: "clipper.bundle.js"
},
distPath: {
root: path.resolve(__dirname, "../../apps/mobile/ios/extension.bundle")
root: path.resolve(
__dirname,
"../../apps/mobile/native/ios/extension.bundle"
)
}
}
});

View File

@@ -26,13 +26,9 @@ type CloneNodeOptions = {
export function cloneNode(node: HTMLElement, options: CloneNodeOptions) {
node = node.cloneNode(true) as HTMLElement;
const images = node.querySelectorAll("img");
if (!options.images) {
const images = node.getElementsByTagName("img");
for (const image of images) image.remove();
} else {
for (const image of images) {
image.src = image.currentSrc;
}
}
if (!options.styles) {

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