diff --git a/apps/mobile/src/screens/settings/debug.tsx b/apps/mobile/src/screens/settings/debug.tsx
index 4c0812cf2..dca9cde0f 100644
--- a/apps/mobile/src/screens/settings/debug.tsx
+++ b/apps/mobile/src/screens/settings/debug.tsx
@@ -1,5 +1,6 @@
import Clipboard from '@react-native-clipboard/clipboard';
-import React, { useState } from 'react';
+import { format, LogLevel, logManager } from '@streetwriters/notesnook-core/logger';
+import React, { useEffect, useState } from 'react';
import { FlatList, Platform, TouchableOpacity, View } from 'react-native';
import * as ScopedStorage from 'react-native-scoped-storage';
import RNFetchBlob from 'rn-fetch-blob';
@@ -11,28 +12,25 @@ import { ToastEvent } from '../../services/event-manager';
import { useThemeStore } from '../../stores/use-theme-store';
import { hexToRGBA } from '../../utils/color-scheme/utils';
import Storage from '../../utils/database/storage';
-import { sanitizeFilename } from '../../utils/sanitizer';
-import { DatabaseLogger } from '../../utils/database/index';
-import { useEffect } from 'react';
import useTimer from '../../utils/hooks/use-timer';
-import { LogLevel } from '@streetwriters/notesnook-core/logger';
+import { sanitizeFilename } from '../../utils/sanitizer';
-function getLevelString(level: number) {
- switch (level) {
- case LogLevel.Debug:
- return 'DEBUG';
- case LogLevel.Info:
- return 'INFO';
- case LogLevel.Log:
- return 'LOG';
- case LogLevel.Error:
- return 'ERROR';
- case LogLevel.Warn:
- return 'WARN';
- case LogLevel.Fatal:
- return 'FATAL';
- }
-}
+// function getLevelString(level: number) {
+// switch (level) {
+// case LogLevel.Debug:
+// return 'DEBUG';
+// case LogLevel.Info:
+// return 'INFO';
+// case LogLevel.Log:
+// return 'LOG';
+// case LogLevel.Error:
+// return 'ERROR';
+// case LogLevel.Warn:
+// return 'WARN';
+// case LogLevel.Fatal:
+// return 'FATAL';
+// }
+// }
export default function DebugLogs() {
const colors = useThemeStore(state => state.colors);
@@ -52,7 +50,8 @@ export default function DebugLogs() {
(async () => {
if (seconds === 0) {
start(5, 'debug_logs_timer');
- let logs = await DatabaseLogger.get();
+ let logs = await logManager?.get();
+ if (!logs) return;
if (logs.length > 0 && !currentLog) {
setCurrentLog(logs[0]);
} else {
@@ -63,7 +62,7 @@ export default function DebugLogs() {
})();
}, [seconds]);
- const renderItem = ({ item, index }) => {
+ const renderItem = ({ item, index }: { item: any; index: number }) => {
const background =
item.level === LogLevel.Error || item.level === LogLevel.Fatal
? hexToRGBA(colors.red, 0.2)
@@ -78,11 +77,11 @@ export default function DebugLogs() {
? colors.orange
: colors.pri;
- return (
+ return !item ? null : (
{
- Clipboard.setString(item.error);
+ Clipboard.setString(format(item));
ToastEvent.show({
heading: 'Debug log copied!',
context: 'global',
@@ -107,11 +106,87 @@ export default function DebugLogs() {
size={12}
color={color}
>
- [{getLevelString(item.level)}] {item.message}
+ {format(item)}
);
};
+
+ const downloadLogs = async () => {
+ try {
+ let path = null;
+ const fileName = sanitizeFilename(`notesnook_logs_${Date.now()}`);
+ const data = currentLog?.logs
+ .map(log => {
+ return !log ? '' : format(log);
+ })
+ .join(`\n`);
+ if (!data) return;
+ if (Platform.OS === 'android') {
+ let file = await ScopedStorage.createDocument(
+ fileName + '.txt',
+ 'text/plain',
+ data,
+ 'utf8'
+ );
+ if (!file) return;
+ path = file.uri;
+ } else {
+ path = await Storage.checkAndCreateDir('/');
+ await RNFetchBlob.fs.writeFile(path + fileName + '.txt', data, 'utf8');
+ path = path + fileName;
+ }
+
+ if (path) {
+ ToastEvent.show({
+ heading: 'Debug logs downloaded',
+ context: 'global',
+ type: 'success'
+ });
+ }
+ } catch (e) {
+ console.log(e);
+ }
+ };
+
+ const copyLogs = () => {
+ const data = currentLog?.logs
+ .map(log => {
+ return !log ? '' : format(log);
+ })
+ .join(`\n`);
+ if (!data) return;
+ Clipboard.setString(data);
+ ToastEvent.show({
+ heading: 'Debug log copied!',
+ context: 'global',
+ type: 'success'
+ });
+ };
+
+ const clearLogs = () => {
+ if (!currentLog) return;
+ presentDialog({
+ title: 'Clear logs',
+ paragraph: `Are you sure you want to delete all logs from ${currentLog.key}?`,
+ negativeText: 'Cancel',
+ positiveText: 'Clear',
+ positivePress: () => {
+ let index = logs.findIndex(l => (l.key = currentLog.key));
+ logManager?.delete(currentLog.key);
+ if (logs.length > 1) {
+ if (logs.length - 1 === index) {
+ setCurrentLog(logs[index - 1]);
+ } else {
+ setCurrentLog(logs[index + 1]);
+ }
+ } else {
+ setCurrentLog(undefined);
+ }
+ }
+ });
+ };
+
return (
@@ -188,14 +263,7 @@ export default function DebugLogs() {
}}
>
{
- Clipboard.setString('All logs copied');
- ToastEvent.show({
- heading: 'Debug log copied!',
- context: 'global',
- type: 'success'
- });
- }}
+ onPress={copyLogs}
size={20}
customStyle={{
width: 30,
@@ -206,47 +274,7 @@ export default function DebugLogs() {
color={colors.gray}
/>
{
- try {
- let path = null;
- const fileName = sanitizeFilename(`notesnook_logs_${Date.now()}`);
- const data = currentLog?.logs
- .map(
- log =>
- `${new Date(log.timestamp).toUTCString()}: [${getLevelString(
- log.level
- )}] ${log.message || log.error?.message}${
- log.error?.stack ? '\n' + log.error?.stack : ''
- }`
- )
- .join(`\n`);
- if (!data) return;
- if (Platform.OS === 'android') {
- let file = await ScopedStorage.createDocument(
- fileName + '.txt',
- 'text/plain',
- data,
- 'utf8'
- );
- if (!file) return;
- path = file.uri;
- } else {
- path = await Storage.checkAndCreateDir('/');
- await RNFetchBlob.fs.writeFile(path + fileName + '.txt', data, 'utf8');
- path = path + fileName;
- }
-
- if (path) {
- ToastEvent.show({
- heading: 'Debug logs downloaded',
- context: 'global',
- type: 'success'
- });
- }
- } catch (e) {
- console.log(e);
- }
- }}
+ onPress={downloadLogs}
customStyle={{
width: 30,
height: 30,
@@ -256,6 +284,18 @@ export default function DebugLogs() {
name="download"
color={colors.gray}
/>
+
+
}
diff --git a/apps/mobile/src/screens/settings/settingsdata.tsx b/apps/mobile/src/screens/settings/settingsdata.tsx
index 34fab3af7..018570236 100644
--- a/apps/mobile/src/screens/settings/settingsdata.tsx
+++ b/apps/mobile/src/screens/settings/settingsdata.tsx
@@ -340,9 +340,19 @@ export const settingsGroups: SettingSection[] = [
description: 'Try force sync to resolve issues with syncing',
icon: 'sync-alert',
modifer: async () => {
- Progress.present();
- await Sync.run('global', true);
- eSendEvent(eCloseProgressDialog);
+ presentDialog({
+ title: 'Force sync',
+ paragraph: `If your data on two devices is out of sync even after trying to sync normally. You can try running force sync to solve such problems. Usually you should never need to run this otherwise. Force sync means that all your data on the device is reuploaded to the server.`,
+ negativeText: 'Cancel',
+ positiveText: 'Start',
+ positivePress: async () => {
+ eSendEvent(eCloseProgressDialog);
+ await sleep(300);
+ Progress.present();
+ await Sync.run('global', true);
+ eSendEvent(eCloseProgressDialog);
+ }
+ });
}
}
]
@@ -744,18 +754,27 @@ export const settingsGroups: SettingSection[] = [
icon: 'file-document'
},
{
- id: 'debug-mode',
- type: 'switch',
- name: 'Debug mode',
- description: 'Show debug options on items',
- property: 'devMode'
- },
- {
- id: 'debug-logs',
+ id: 'debugging',
+ name: 'Debugging',
+ description: 'Get helpful debug info about the app to help us find bugs.',
type: 'screen',
- name: 'Debug logs',
- description: 'View debug logs from the app',
- component: 'debug-logs'
+ icon: 'bug',
+ sections: [
+ {
+ id: 'debug-mode',
+ type: 'switch',
+ name: 'Debug mode',
+ description: 'Show debug options on items',
+ property: 'devMode'
+ },
+ {
+ id: 'debug-logs',
+ type: 'screen',
+ name: 'Debug logs',
+ description: 'View debug logs from the app',
+ component: 'debug-logs'
+ }
+ ]
}
]
},