Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee224bf4f2 | ||
|
|
f1bd0b1ce6 | ||
|
|
300ed213af | ||
|
|
4be67ce491 | ||
|
|
98107ba4ea |
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "remotely-save",
|
||||
"name": "Remotely Save",
|
||||
"version": "0.4.12",
|
||||
"version": "0.4.13",
|
||||
"minAppVersion": "0.13.21",
|
||||
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
|
||||
"author": "fyears",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "remotely-save",
|
||||
"name": "Remotely Save",
|
||||
"version": "0.4.12",
|
||||
"version": "0.4.13",
|
||||
"minAppVersion": "0.13.21",
|
||||
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
|
||||
"author": "fyears",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "remotely-save",
|
||||
"version": "0.4.12",
|
||||
"version": "0.4.13",
|
||||
"description": "This is yet another sync plugin for Obsidian app.",
|
||||
"scripts": {
|
||||
"dev2": "node esbuild.config.mjs --watch",
|
||||
|
||||
+2
-2
@@ -272,9 +272,9 @@ export const DEFAULT_LOG_HISTORY_FILE_PREFIX = "log_hist_exported_on_";
|
||||
|
||||
export type SyncTriggerSourceType =
|
||||
| "manual"
|
||||
| "auto"
|
||||
| "dry"
|
||||
| "autoOnceInit"
|
||||
| "auto"
|
||||
| "auto_once_init"
|
||||
| "auto_sync_on_save";
|
||||
|
||||
export const REMOTELY_SAVE_VERSION_2022 = "0.3.25";
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"goback": "Go Back",
|
||||
"submit": "Submit",
|
||||
"sometext": "Here are some texts.",
|
||||
"syncrun_alreadyrunning": "{{pluginName}} already running in stage {{syncStatus}}!",
|
||||
"syncrun_alreadyrunning": "New command {{newTriggerSource}} stops because {{pluginName}} is already running in stage {{syncStatus}}!",
|
||||
"syncrun_syncingribbon": "{{pluginName}}: syncing from {{triggerSource}}",
|
||||
"syncrun_step0": "0/8 Remotely Save is running in dry mode, thus not actual file changes would happen.",
|
||||
"syncrun_step1": "1/8 Remotely Save is preparing ({{serviceType}})",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"goback": "返回",
|
||||
"submit": "提交",
|
||||
"sometext": "这里有一段文字。",
|
||||
"syncrun_alreadyrunning": "{{pluginName}} 正处于此阶段:{{syncStatus}}!",
|
||||
"syncrun_alreadyrunning": "{{pluginName}} 正处于此阶段:{{syncStatus}}!中断触发 {{newTriggerSource}}。",
|
||||
"syncrun_syncingribbon": "{{pluginName}}:正在由 {{triggerSource}} 触发运行",
|
||||
"syncrun_step0": "0/8 Remotely Save 在空跑(dry run)模式,不会发生实际的文件交换。",
|
||||
"syncrun_step1": "1/8 Remotely Save 准备同步({{serviceType}})",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"goback": "返回",
|
||||
"submit": "提交",
|
||||
"sometext": "這裡有一段文字。",
|
||||
"syncrun_alreadyrunning": "{{pluginName}} 正處於此階段:{{syncStatus}}!",
|
||||
"syncrun_alreadyrunning": "{{pluginName}} 正處於此階段:{{syncStatus}}! 中斷觸發 {{newTriggerSource}}。",
|
||||
"syncrun_syncingribbon": "{{pluginName}}:正在由 {{triggerSource}} 觸發執行",
|
||||
"syncrun_step0": "0/8 Remotely Save 在空跑(dry run)模式,不會發生實際的檔案交換。",
|
||||
"syncrun_step1": "1/8 Remotely Save 準備同步({{serviceType}})",
|
||||
|
||||
+54
-28
@@ -9,6 +9,7 @@ import {
|
||||
Platform,
|
||||
requestUrl,
|
||||
requireApiVersion,
|
||||
Events,
|
||||
} from "obsidian";
|
||||
import cloneDeep from "lodash/cloneDeep";
|
||||
import { createElement, RotateCcw, RefreshCcw, FileText } from "lucide";
|
||||
@@ -149,6 +150,8 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
i18n!: I18n;
|
||||
vaultRandomID!: string;
|
||||
debugServerTemp?: string;
|
||||
syncEvent?: Events;
|
||||
appContainerObserver?: MutationObserver;
|
||||
|
||||
async syncRun(triggerSource: SyncTriggerSourceType = "manual") {
|
||||
const t = (x: TransItemType, vars?: any) => {
|
||||
@@ -165,15 +168,17 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
}
|
||||
};
|
||||
if (this.syncStatus !== "idle") {
|
||||
// here the notice is shown regardless of triggerSource
|
||||
new Notice(
|
||||
// really, users don't want to see this in auto mode
|
||||
// so we use getNotice to avoid unnecessary show up
|
||||
getNotice(
|
||||
t("syncrun_alreadyrunning", {
|
||||
pluginName: this.manifest.name,
|
||||
syncStatus: this.syncStatus,
|
||||
newTriggerSource: triggerSource,
|
||||
})
|
||||
);
|
||||
if (this.currSyncMsg !== undefined && this.currSyncMsg !== "") {
|
||||
new Notice(this.currSyncMsg);
|
||||
getNotice(this.currSyncMsg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -376,7 +381,8 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
realCounter,
|
||||
realTotalCount,
|
||||
pathName,
|
||||
decision
|
||||
decision,
|
||||
triggerSource
|
||||
),
|
||||
this.db
|
||||
);
|
||||
@@ -416,6 +422,7 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
this.updateLastSuccessSyncMsg(lastSuccessSyncMillis);
|
||||
}
|
||||
|
||||
this.syncEvent?.trigger("SYNC_DONE");
|
||||
console.info(
|
||||
`${
|
||||
this.manifest.id
|
||||
@@ -465,6 +472,8 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
|
||||
this.currSyncMsg = "";
|
||||
|
||||
this.syncEvent = new Events();
|
||||
|
||||
await this.loadSettings();
|
||||
|
||||
// MUST after loadSettings and before prepareDB
|
||||
@@ -812,6 +821,10 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
async onunload() {
|
||||
console.info(`unloading plugin ${this.manifest.id}`);
|
||||
this.syncRibbon = undefined;
|
||||
if (this.appContainerObserver !== undefined) {
|
||||
this.appContainerObserver.disconnect();
|
||||
this.appContainerObserver = undefined;
|
||||
}
|
||||
if (this.oauth2Info !== undefined) {
|
||||
this.oauth2Info.helperModal = undefined;
|
||||
this.oauth2Info = {
|
||||
@@ -1100,7 +1113,7 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
) {
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
window.setTimeout(() => {
|
||||
this.syncRun("autoOnceInit");
|
||||
this.syncRun("auto_once_init");
|
||||
}, this.settings.initRunAfterMilliseconds);
|
||||
});
|
||||
}
|
||||
@@ -1126,52 +1139,64 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
}, scheduleTimeFromNow);
|
||||
};
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
const intervalID = window.setInterval(() => {
|
||||
const checkCurrFileModified = async (caller: "SYNC" | "FILE_CHANGES") => {
|
||||
const currentFile = this.app.workspace.getActiveFile();
|
||||
|
||||
if (currentFile) {
|
||||
// get the last modified time of the current file
|
||||
// if it has been modified within the last syncOnSaveAfterMilliseconds
|
||||
// if it has modified after lastSuccessSync
|
||||
// then schedule a run for syncOnSaveAfterMilliseconds after it was modified
|
||||
const lastModified = currentFile.stat.mtime;
|
||||
const currentTime = Date.now();
|
||||
const lastSuccessSyncMillis = await getLastSuccessSyncTimeByVault(
|
||||
this.db,
|
||||
this.vaultRandomID
|
||||
);
|
||||
if (
|
||||
currentTime - lastModified <
|
||||
this.settings!.syncOnSaveAfterMilliseconds!
|
||||
this.syncStatus === "idle" &&
|
||||
lastModified > lastSuccessSyncMillis &&
|
||||
!runScheduled
|
||||
) {
|
||||
if (
|
||||
!needToRunAgain &&
|
||||
!runScheduled &&
|
||||
this.syncStatus === "idle"
|
||||
) {
|
||||
const scheduleTimeFromNow =
|
||||
this.settings!.syncOnSaveAfterMilliseconds! -
|
||||
(currentTime - lastModified);
|
||||
scheduleSyncOnSave(scheduleTimeFromNow);
|
||||
scheduleSyncOnSave(this.settings!.syncOnSaveAfterMilliseconds!);
|
||||
} else if (
|
||||
this.syncStatus === "idle" &&
|
||||
needToRunAgain &&
|
||||
!runScheduled &&
|
||||
this.syncStatus === "idle"
|
||||
!runScheduled
|
||||
) {
|
||||
scheduleSyncOnSave(this.settings!.syncOnSaveAfterMilliseconds!);
|
||||
needToRunAgain = false;
|
||||
} else {
|
||||
if (caller === "FILE_CHANGES") {
|
||||
needToRunAgain = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, this.settings.syncOnSaveAfterMilliseconds);
|
||||
this.syncOnSaveIntervalID = intervalID;
|
||||
this.registerInterval(intervalID);
|
||||
};
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
// listen to sync done
|
||||
this.registerEvent(
|
||||
this.syncEvent?.on("SYNC_DONE", () => {
|
||||
checkCurrFileModified("SYNC");
|
||||
})!
|
||||
);
|
||||
|
||||
// listen to current file save changes
|
||||
this.registerEvent(
|
||||
this.app.vault.on("modify", (x) => {
|
||||
// console.debug(`event=modify! file=${x}`);
|
||||
checkCurrFileModified("FILE_CHANGES");
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enableMobileStatusBarIfSet() {
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
if (Platform.isMobile && this.settings.enableMobileStatusBar) {
|
||||
changeMobileStatusBar("enable");
|
||||
this.appContainerObserver = changeMobileStatusBar("enable");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async saveAgreeToUseNewSyncAlgorithm() {
|
||||
@@ -1183,9 +1208,10 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
i: number,
|
||||
totalCount: number,
|
||||
pathName: string,
|
||||
decision: string
|
||||
decision: string,
|
||||
triggerSource: SyncTriggerSourceType
|
||||
) {
|
||||
const msg = `syncing progress=${i}/${totalCount},decision=${decision},path=${pathName}`;
|
||||
const msg = `syncing progress=${i}/${totalCount},decision=${decision},path=${pathName},source=${triggerSource}`;
|
||||
this.currSyncMsg = msg;
|
||||
}
|
||||
|
||||
|
||||
+67
-7
@@ -517,21 +517,81 @@ export const stringToFragment = (string: string) => {
|
||||
* https://forum.obsidian.md/t/css-to-show-status-bar-on-mobile-devices/77185
|
||||
* @param op
|
||||
*/
|
||||
export const changeMobileStatusBar = (op: "enable" | "disable") => {
|
||||
const bar = document.querySelector(
|
||||
export const changeMobileStatusBar = (
|
||||
op: "enable" | "disable",
|
||||
oldAppContainerObserver?: MutationObserver
|
||||
) => {
|
||||
const appContainer = document.getElementsByClassName("app-container")[0] as
|
||||
| HTMLElement
|
||||
| undefined;
|
||||
|
||||
const statusbar = document.querySelector(
|
||||
".is-mobile .app-container .status-bar"
|
||||
) as HTMLElement;
|
||||
) as HTMLElement | undefined;
|
||||
|
||||
if (appContainer === undefined || statusbar === undefined) {
|
||||
// give up, exit
|
||||
console.warn(`give up watching appContainer for statusbar`);
|
||||
console.warn(`appContainer=${appContainer}, statusbar=${statusbar}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (op === "enable") {
|
||||
bar.style.setProperty("display", "flex");
|
||||
const callback = async (
|
||||
mutationList: MutationRecord[],
|
||||
observer: MutationObserver
|
||||
) => {
|
||||
for (const mutation of mutationList) {
|
||||
// console.debug(mutation);
|
||||
if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
|
||||
const k = mutation.addedNodes[0] as Element;
|
||||
if (
|
||||
k.className.contains("mobile-navbar") ||
|
||||
k.className.contains("mobile-toolbar")
|
||||
) {
|
||||
// have to wait, otherwise the height is not correct??
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
const height = window
|
||||
.getComputedStyle(k as Element)
|
||||
.getPropertyValue("height");
|
||||
|
||||
statusbar.style.setProperty("display", "flex");
|
||||
statusbar.style.setProperty("margin-bottom", height);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const observer = new MutationObserver(callback);
|
||||
observer.observe(appContainer, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
characterData: false,
|
||||
subtree: false,
|
||||
});
|
||||
|
||||
try {
|
||||
// init, manual call
|
||||
const navBar = document.getElementsByClassName(
|
||||
"mobile-navbar"
|
||||
)[0] as HTMLElement;
|
||||
// thanks to community's solution
|
||||
const height = window.getComputedStyle(navBar).getPropertyValue("height");
|
||||
bar.style.setProperty("margin-bottom", height);
|
||||
statusbar.style.setProperty("display", "flex");
|
||||
statusbar.style.setProperty("margin-bottom", height);
|
||||
} catch (e) {
|
||||
// skip
|
||||
}
|
||||
|
||||
return observer;
|
||||
} else {
|
||||
bar.style.removeProperty("display");
|
||||
bar.style.removeProperty("margin-bottom");
|
||||
if (oldAppContainerObserver !== undefined) {
|
||||
console.debug(`disconnect oldAppContainerObserver`);
|
||||
oldAppContainerObserver.disconnect();
|
||||
oldAppContainerObserver = undefined;
|
||||
}
|
||||
statusbar.style.removeProperty("display");
|
||||
statusbar.style.removeProperty("margin-bottom");
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+7
-1
@@ -2098,10 +2098,16 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
||||
.onChange(async (val) => {
|
||||
if (val === "enable") {
|
||||
this.plugin.settings.enableMobileStatusBar = true;
|
||||
this.plugin.appContainerObserver =
|
||||
changeMobileStatusBar("enable");
|
||||
} else {
|
||||
this.plugin.settings.enableMobileStatusBar = false;
|
||||
changeMobileStatusBar("disable");
|
||||
changeMobileStatusBar(
|
||||
"disable",
|
||||
this.plugin.appContainerObserver
|
||||
);
|
||||
this.plugin.appContainerObserver?.disconnect();
|
||||
this.plugin.appContainerObserver = undefined;
|
||||
}
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user