diff --git a/src/baseTypes.ts b/src/baseTypes.ts index 318f750..ba656ba 100644 --- a/src/baseTypes.ts +++ b/src/baseTypes.ts @@ -87,6 +87,8 @@ export interface RemotelySavePluginSettings { logToDB?: boolean; skipSizeLargerThan?: number; ignorePaths?: string[]; + enableStatusBarInfo?: boolean; + lastSuccessSync?: number; /** * @deprecated diff --git a/src/langs b/src/langs index c75336a..a8f6e1d 160000 --- a/src/langs +++ b/src/langs @@ -1 +1 @@ -Subproject commit c75336a2a52fcf00147eea01ca767872dff2d0b4 +Subproject commit a8f6e1d05def00387ee5a50a829fd91e60ae6351 diff --git a/src/main.ts b/src/main.ts index b8ec457..6b70493 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,6 +6,7 @@ import { addIcon, setIcon, FileSystemAdapter, + Platform, } from "obsidian"; import cloneDeep from "lodash/cloneDeep"; import { createElement, RotateCcw, RefreshCcw, FileText } from "lucide"; @@ -86,6 +87,8 @@ const DEFAULT_SETTINGS: RemotelySavePluginSettings = { logToDB: false, skipSizeLargerThan: -1, ignorePaths: [], + enableStatusBarInfo: true, + lastSuccessSync: -1, }; interface OAuth2Info { @@ -126,6 +129,7 @@ export default class RemotelySavePlugin extends Plugin { settings: RemotelySavePluginSettings; db: InternalDBs; syncStatus: SyncStatusType; + statusBarElement: HTMLSpanElement; oauth2Info: OAuth2Info; currLogLevel: string; currSyncMsg?: string; @@ -357,11 +361,17 @@ export default class RemotelySavePlugin extends Plugin { this.syncStatus = "finish"; this.syncStatus = "idle"; + this.settings.lastSuccessSync = Date.now(); + if (this.syncRibbon !== undefined) { setIcon(this.syncRibbon, iconNameSyncWait); this.syncRibbon.setAttribute("aria-label", originLabel); } + if (this.statusBarElement !== undefined) { + this.updateLastSuccessSyncMsg(this.settings.lastSuccessSync); + } + log.info( `${ this.manifest.id @@ -673,6 +683,21 @@ export default class RemotelySavePlugin extends Plugin { async () => this.syncRun("manual") ); + // Create Status Bar Item (not supported on mobile) + if (!Platform.isMobileApp && this.settings.enableStatusBarInfo === true) { + const statusBarItem = this.addStatusBarItem(); + this.statusBarElement = statusBarItem.createEl("span"); + this.statusBarElement.setAttribute("aria-label-position", "top"); + + this.updateLastSuccessSyncMsg(this.settings.lastSuccessSync); + // update statusbar text every 30 seconds + this.registerInterval( + window.setInterval(() => { + this.updateLastSuccessSyncMsg(this.settings.lastSuccessSync); + }, 1000 * 30) + ); + } + this.addCommand({ id: "start-sync", name: t("command_startsync"), @@ -970,6 +995,62 @@ export default class RemotelySavePlugin extends Plugin { this.currSyncMsg = msg; } + updateLastSuccessSyncMsg(lastSuccessSyncMillis?: number) { + if (this.statusBarElement === undefined) return; + + const t = (x: TransItemType, vars?: any) => { + return this.i18n.t(x, vars); + }; + + let lastSyncMsg = t("statusbar_lastsync_never"); + let lastSyncLabelMsg = t("statusbar_lastsync_never_label"); + + if (lastSuccessSyncMillis !== undefined && lastSuccessSyncMillis > 0) { + const deltaTime = Date.now() - lastSuccessSyncMillis; + + // create human readable time + const years = Math.floor(deltaTime / 31556952000); + const months = Math.floor(deltaTime / 2629746000); + const weeks = Math.floor(deltaTime / 604800000); + const days = Math.floor(deltaTime / 86400000); + const hours = Math.floor(deltaTime / 3600000); + const minutes = Math.floor(deltaTime / 60000); + let timeText = ""; + + if (years > 0) { + timeText = t("statusbar_time_years", { time: years }); + } else if (months > 0) { + timeText = t("statusbar_time_months", { time: months }); + } else if (weeks > 0) { + timeText = t("statusbar_time_weeks", { time: weeks }); + } else if (days > 0) { + timeText = t("statusbar_time_days", { time: days }); + } else if (hours > 0) { + timeText = t("statusbar_time_hours", { time: hours }); + } else if (minutes > 0) { + timeText = t("statusbar_time_minutes", { time: minutes }); + } else { + timeText = t("statusbar_time_lessminute"); + } + + let dateText = new Date(lastSuccessSyncMillis).toLocaleTimeString( + navigator.language, + { + weekday: "long", + year: "numeric", + month: "long", + day: "numeric", + } + ); + + lastSyncMsg = t("statusbar_lastsync", { time: timeText }); + lastSyncLabelMsg = t("statusbar_lastsync_label", { date: dateText }); + } + + this.statusBarElement.setText(lastSyncMsg); + this.statusBarElement.setAttribute("aria-label", lastSyncLabelMsg); + } + /** * Because data.json contains sensitive information, * We usually want to ignore it in the version control. diff --git a/src/settings.ts b/src/settings.ts index d8e51ff..5d49697 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -197,6 +197,8 @@ class ChangeRemoteBaseDirModal extends Modal { button.onClick(async () => { this.plugin.settings[this.service].remoteBaseDir = this.newRemoteBaseDir; + // reset last sync time + this.plugin.settings.lastSuccessSync = -1; await this.plugin.saveSettings(); new Notice(t("modal_remotebasedir_notice")); this.close(); @@ -1596,6 +1598,22 @@ export class RemotelySaveSettingTab extends PluginSettingTab { }); }); + // custom status bar items is not supported on mobile + if (!Platform.isMobileApp) { + new Setting(basicDiv) + .setName(t("settings_enablestatusbar_info")) + .setDesc(t("settings_enablestatusbar_info_desc")) + .addToggle((toggle) => { + toggle + .setValue(this.plugin.settings.enableStatusBarInfo) + .onChange(async (val) => { + this.plugin.settings.enableStatusBarInfo = val; + await this.plugin.saveSettings(); + new Notice(t("settings_enablestatusbar_reloadrequired_notice")); + }); + }); + } + new Setting(basicDiv) .setName(t("settings_ignorepaths")) .setDesc(t("settings_ignorepaths_desc")) diff --git a/tests/configPersist.test.ts b/tests/configPersist.test.ts index cde0a7c..b5dabc5 100644 --- a/tests/configPersist.test.ts +++ b/tests/configPersist.test.ts @@ -23,6 +23,8 @@ const DEFAULT_SETTINGS: RemotelySavePluginSettings = { password: "password", serviceType: "s3", currLogLevel: "info", + ignorePaths: ["somefoldertoignore"], + enableStatusBarInfo: true, }; describe("Config Persist tests", () => {