diff --git a/src/i18n/localization/locales/en/translation.json b/src/i18n/localization/locales/en/translation.json
index bd31aae..2646d5e 100644
--- a/src/i18n/localization/locales/en/translation.json
+++ b/src/i18n/localization/locales/en/translation.json
@@ -520,7 +520,9 @@
"TidGiMobileShare": "Shared from TidGi Mobile",
"ImportSuccess": "Import Success",
"TagForSharedContent": "Tag for shared content",
- "Clipped": "Clipped"
+ "Clipped": "Clipped",
+ "FastImport": "Fast Import",
+ "FastImportDescription": "Import to default workspace without opening the wiki, but no popup box to confirm. You can manually open the wiki and view the imported results in “Recent”."
},
"Description": "Description",
"Tags": "Tags",
diff --git a/src/i18n/localization/locales/zh_CN/translation.json b/src/i18n/localization/locales/zh_CN/translation.json
index 8a784ae..6caddd9 100644
--- a/src/i18n/localization/locales/zh_CN/translation.json
+++ b/src/i18n/localization/locales/zh_CN/translation.json
@@ -506,7 +506,9 @@
"ImportSuccess": "导入成功",
"TagForSharedContent": "分享内容标签",
"TagForSharedContentDescription": "分享给太记移动端的内容,会自动加上这个标签。留空时表示不加任何标签。",
- "Clipped": "剪藏"
+ "Clipped": "剪藏",
+ "FastImport": "快速导入",
+ "FastImportDescription": "无需打开Wiki即可导入内容到默认工作区,但不会有弹框确认。可以手动打开Wiki后到「最近」里查看导入的结果。"
},
"Import": {
"ImportWiki": "导入Wiki"
diff --git a/src/pages/Config/Shared.tsx b/src/pages/Config/Shared.tsx
index 2d3267b..9a30e43 100644
--- a/src/pages/Config/Shared.tsx
+++ b/src/pages/Config/Shared.tsx
@@ -3,7 +3,8 @@ import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { styled } from 'styled-components/native';
-import { TextInput, Text } from 'react-native-paper';
+import { Switch, Text, TextInput } from 'react-native-paper';
+import { FlexibleText, SwitchContainer } from '../../components/PreferenceWidgets';
import { useConfigStore } from '../../store/config';
const StyledTextInput = styled(TextInput)`
@@ -13,7 +14,7 @@ const StyledTextInput = styled(TextInput)`
export function Shared(): JSX.Element {
const { t } = useTranslation();
- const [initialTagForSharedContent] = useConfigStore(state => [state.tagForSharedContent]);
+ const [initialTagForSharedContent, fastImport] = useConfigStore(state => [state.tagForSharedContent, state.fastImport]);
const [tagForSharedContent, tagForSharedContentSetter] = useState(initialTagForSharedContent);
const setConfig = useConfigStore(state => state.set);
@@ -21,6 +22,10 @@ export function Shared(): JSX.Element {
setConfig({ tagForSharedContent: newText });
}, []);
+ const fastImportOnChange = (value: boolean) => {
+ setConfig({ fastImport: value });
+ };
+
return (
<>
{t('Share.TagForSharedContentDescription')}
+ {t('Share.FastImport')}
+
+ {t('Share.FastImportDescription')}
+
+
>
);
}
diff --git a/src/services/NativeService/hooks.tsx b/src/services/NativeService/hooks.tsx
index 1c8a8ec..24a5700 100644
--- a/src/services/NativeService/hooks.tsx
+++ b/src/services/NativeService/hooks.tsx
@@ -1,18 +1,11 @@
/* eslint-disable security-node/detect-crlf */
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
-import { format } from 'date-fns';
-import * as fs from 'expo-file-system';
import type { useShareIntent as IUseShareIntent } from 'expo-share-intent';
-import { compact } from 'lodash';
-import { useEffect, useMemo, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Snackbar } from 'react-native-paper';
import { useRegisterProxy } from 'react-native-postmessage-cat';
-import { ITiddlerFieldsParam } from 'tiddlywiki';
import i18n from '../../i18n';
-import { useConfigStore } from '../../store/config';
-import { IWikiWorkspace, useWorkspaceStore } from '../../store/workspace';
-import { WikiStorageService } from '../WikiStorageService';
import { nativeService } from '.';
import { NativeServiceIPCDescriptor } from './descriptor';
@@ -42,8 +35,6 @@ export function useRegisterReceivingShareIntent() {
{i18n.t('Share.ImportSuccess')}
);
- const [tagForSharedContent] = useConfigStore(state => [state.tagForSharedContent]);
- const newTagForSharedContent = useMemo(() => tagForSharedContent ?? i18n.t('Share.Clipped'), [tagForSharedContent]);
/** If you get error on development:
* ```
@@ -75,44 +66,8 @@ export function useRegisterReceivingShareIntent() {
void (async () => {
try {
if (!hasShareIntent) return;
- const defaultWiki = compact(useWorkspaceStore.getState().workspaces).find((w): w is IWikiWorkspace => w.type === 'wiki');
- if (defaultWiki === undefined) return;
await nativeService.receivingShareIntent(shareIntent);
resetShareIntent();
- // put into default workspace's database, with random title
- const storageOfDefaultWorkspace = new WikiStorageService(defaultWiki);
- const randomTitle = `${i18n.t('Share.SharedContent')}-${Date.now()}`;
- const created = format(new Date(), 'yyyyMMddHHmmssSSS');
- let fields: ITiddlerFieldsParam = {
- created,
- modified: created,
- creator: i18n.t('Share.TidGiMobileShare'),
- tags: newTagForSharedContent,
- };
- if (shareIntent.webUrl) fields = { ...fields, url: shareIntent.webUrl };
- switch (shareIntent.type) {
- case 'text':
- case 'weburl': {
- if (shareIntent.text) fields = { ...fields, text: shareIntent.text };
- await storageOfDefaultWorkspace.saveTiddler(shareIntent.meta?.title ?? randomTitle, fields);
- break;
- }
- case 'media':
- case 'file': {
- if (shareIntent.files) {
- for (const file of shareIntent.files) {
- const fileContent = await fs.readAsStringAsync(file.path, { encoding: fs.EncodingType.Base64 });
- const fileFields = {
- ...fields,
- type: file.mimeType,
- text: fileContent,
- };
- await storageOfDefaultWorkspace.saveTiddler(file.fileName || randomTitle, fileFields);
- }
- }
- break;
- }
- }
setImportSuccessSnackBarVisible(true);
} catch (error) {
console.log(
@@ -122,7 +77,7 @@ export function useRegisterReceivingShareIntent() {
);
}
})();
- }, [hasShareIntent, shareIntent, resetShareIntent, error, newTagForSharedContent]);
+ }, [hasShareIntent, shareIntent, resetShareIntent, error]);
return { importSuccessSnackBar };
}
diff --git a/src/services/NativeService/index.ts b/src/services/NativeService/index.ts
index 91a6aca..ceff71e 100644
--- a/src/services/NativeService/index.ts
+++ b/src/services/NativeService/index.ts
@@ -1,11 +1,18 @@
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
+import { format } from 'date-fns';
import { Camera, PermissionStatus } from 'expo-camera';
import * as fs from 'expo-file-system';
-import { ShareIntent } from 'expo-share-intent';
+import type { ShareIntent } from 'expo-share-intent';
+import { compact } from 'lodash';
+
+import type { ITiddlerFieldsParam } from 'tiddlywiki';
import { openDefaultWikiIfNotAlreadyThere } from '../../hooks/useAutoOpenDefaultWiki';
+import i18n from '../../i18n';
import { useConfigStore } from '../../store/config';
+import { IWikiWorkspace, useWorkspaceStore } from '../../store/workspace';
import type { WikiHookService } from '../WikiHookService';
+import { WikiStorageService } from '../WikiStorageService';
import { importBinaryTiddlers, importTextTiddlers } from './wikiOperations';
/**
@@ -73,34 +80,40 @@ export class NativeService {
}
}
+ async receivingShareIntent(shareIntent: ShareIntent) {
+ const configs = useConfigStore.getState();
+ if (configs.fastImport) {
+ await this.storeSharedContentToStorage(shareIntent);
+ } else {
+ await this.importSharedContentToWiki(shareIntent);
+ }
+ }
+
/**
* If wiki has not started, android will store files in a queue, wait for getReceivedFiles to be called.
* Even wiki previously loaded, but after go background for a while, it may be unloaded too. We need to wait not only webview loaded, need wiki core loaded, then call this.
*/
- async receivingShareIntent(shareIntent: ShareIntent) {
- // wait for wiki start, and use injectJavascript to add tiddler, for user to edit.
- // To get All Recived Urls
-
- // files returns as JSON Array example
- // [{ filePath: null, text: null, weblink: null, mimeType: null, contentUri: null, fileName: null, extension: null }]
+ async importSharedContentToWiki(shareIntent: ShareIntent) {
const { text, files } = shareIntent;
let script = '';
- if (files !== null) {
- console.log(text, files);
- if (text) {
- script = importTextTiddlers([text]);
- } else {
- if (files.length === 0) return;
- const filesWithFileLoadedToText = await Promise.all(files.map(async (file) => {
- if (file.path === null) return file;
- /**
- * based on tiddlywiki file type parsers `$tw.utils.registerFileType("image/jpeg","base64",[".jpg",".jpeg"],{flags:["image"]});`
- * we need to use base64 encoding to load file
- */
- const text = await fs.readAsStringAsync(file.path.startsWith('file://') ? file.path : `file://${file.path}`, { encoding: 'base64' });
- return { ...file, text };
- }));
- script = importBinaryTiddlers(filesWithFileLoadedToText);
+ switch (shareIntent.type) {
+ case 'text':
+ case 'weburl': {
+ if (text) {
+ script = importTextTiddlers([text]);
+ }
+ break;
+ }
+ case 'media':
+ case 'file': {
+ if (files && files.length > 0) {
+ const filesWithFileLoadedToText = await Promise.all(files.map(async (file) => {
+ const text = await fs.readAsStringAsync(file.path.startsWith('file://') ? file.path : `file://${file.path}`, { encoding: 'base64' });
+ return { ...file, text, type: file.mimeType };
+ }));
+ script = importBinaryTiddlers(filesWithFileLoadedToText);
+ }
+ break;
}
}
if (!script) return;
@@ -109,6 +122,51 @@ export class NativeService {
await wikiHookService.executeAfterTwReady(script);
}
+ /**
+ * Directly store shared content to default workspace's sqlite, very fast, don't need to wait for wiki to load.
+ */
+ async storeSharedContentToStorage(shareIntent: ShareIntent) {
+ const defaultWiki = compact(useWorkspaceStore.getState().workspaces).find((w): w is IWikiWorkspace => w.type === 'wiki');
+ if (defaultWiki === undefined) return;
+ const storageOfDefaultWorkspace = new WikiStorageService(defaultWiki);
+ const configs = useConfigStore.getState();
+ const tagForSharedContent = configs.tagForSharedContent;
+ const newTagForSharedContent = tagForSharedContent ?? i18n.t('Share.Clipped');
+ // put into default workspace's database, with random title
+ const randomTitle = `${i18n.t('Share.SharedContent')}-${Date.now()}`;
+ const created = format(new Date(), 'yyyyMMddHHmmssSSS');
+ let fields: ITiddlerFieldsParam = {
+ created,
+ modified: created,
+ creator: i18n.t('Share.TidGiMobileShare'),
+ tags: newTagForSharedContent,
+ };
+ if (shareIntent.webUrl) fields = { ...fields, url: shareIntent.webUrl };
+ switch (shareIntent.type) {
+ case 'text':
+ case 'weburl': {
+ if (shareIntent.text) fields = { ...fields, text: shareIntent.text };
+ await storageOfDefaultWorkspace.saveTiddler(shareIntent.meta?.title ?? randomTitle, fields);
+ break;
+ }
+ case 'media':
+ case 'file': {
+ if (shareIntent.files) {
+ for (const file of shareIntent.files) {
+ const fileContent = await fs.readAsStringAsync(file.path.startsWith('file://') ? file.path : `file://${file.path}`, { encoding: fs.EncodingType.Base64 });
+ const fileFields = {
+ ...fields,
+ type: file.mimeType,
+ text: fileContent,
+ };
+ await storageOfDefaultWorkspace.saveTiddler(file.fileName || randomTitle, fileFields);
+ }
+ }
+ break;
+ }
+ }
+ }
+
async saveFileToFs(filename: string, text: string, mimeType?: string): Promise {
const configs = useConfigStore.getState();
const result = await fs.StorageAccessFramework.requestDirectoryPermissionsAsync(configs.defaultDownloadLocation);
diff --git a/src/store/config.ts b/src/store/config.ts
index 6fa2af7..83fef3e 100644
--- a/src/store/config.ts
+++ b/src/store/config.ts
@@ -8,6 +8,7 @@ export interface ConfigState {
/** the initial value should be undefined, so an initial true value won't immediately trigger autoOpen */
autoOpenDefaultWiki?: boolean;
defaultDownloadLocation?: string;
+ fastImport: boolean;
hideStatusBar?: boolean;
keepAliveInBackground: boolean;
preferredLanguage?: string;
@@ -23,6 +24,7 @@ export interface ConfigState {
}
const defaultConfig: ConfigState = {
autoOpenDefaultWiki: undefined,
+ fastImport: true,
hideStatusBar: false,
keepAliveInBackground: true,
preferredLanguage: undefined,
@@ -30,9 +32,9 @@ const defaultConfig: ConfigState = {
syncInBackground: true,
syncInterval: 60 * 1000,
syncIntervalBackground: 60 * 30 * 1000,
+ tagForSharedContent: undefined,
theme: 'default',
translucentStatusBar: true,
- tagForSharedContent: undefined,
userName: '',
};
interface ConfigActions {