Skip to content

Commit

Permalink
Merge pull request #150 from leoccyao/expose-char-limit
Browse files Browse the repository at this point in the history
Additional status bar format options
  • Loading branch information
mcndt authored Jul 15, 2024
2 parents a76f1b2 + e7dbca2 commit 0cb44a4
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 24 deletions.
4 changes: 4 additions & 0 deletions lib/config/DefaultSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import type { PluginSettings } from "./PluginSettings";
export const DEFAULT_SETTINGS: PluginSettings = {
apiToken: null,
charLimitStatusBar: 40,
statusBarFormat: "m [minute]",
statusBarNoEntryMesssage: "-",
statusBarPrefix: "Timer: ",
statusBarShowProject: false,
updateInRealTime: true,
workspace: { id: "none", name: "None selected" },
};
24 changes: 20 additions & 4 deletions lib/config/PluginSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,31 @@ export interface PluginSettings {
*/
workspace: TogglWorkspace;

/** Has dismissed the update alert for 0.4.0 */
hasDismissedAlert?: boolean;

/** Update the day's total time in real-time in the sidebar */
updateInRealTime?: boolean;

/**
* The max. allowed characters in the title of a timer in
* the status bar.
*/
charLimitStatusBar: number;

/** Has dismissed the update alert for 0.4.0 */
hasDismissedAlert?: boolean;
/**
* The time format for the status bar.
*/
statusBarFormat?: string;

/** Update the day's total time in real-time in the sidebar */
updateInRealTime?: boolean;
/**
* The prefix to show before the time entry in the status bar.
*/
statusBarPrefix?: string;

/** Whether to show the project in the status bar. */
statusBarShowProject?: boolean;

/** Message shown in the status bar when no time entry is running. */
statusBarNoEntryMesssage?: string;
}
5 changes: 5 additions & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
export const ACTIVE_TIMER_POLLING_INTERVAL = 6000;

/**
* The interval in ms at which the status bar is updated
*/
export const STATUS_BAR_UPDATE_INTERVAL = 1000;

/**
* The language string used for report code blocks.
*/
Expand Down
4 changes: 2 additions & 2 deletions lib/stores/dailySummary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ export const DailySummary = derived(
[summaryItems, Projects],
([$summaryItems, $projects]) => {
const summary = {
projects_breakdown: $summaryItems.map(
projects_breakdown: ($summaryItems ?? []).map(
(item): EnrichedWithProject<typeof item> => ({
...item,
$project:
$projects.find((project) => project.id === item.project_id) ?? null,
}),
),
total_seconds: $summaryItems.reduce((a, b) => a + b.tracked_seconds, 0),
total_seconds: ($summaryItems ?? []).reduce((a, b) => a + b.tracked_seconds, 0),
};

return summary;
Expand Down
33 changes: 26 additions & 7 deletions lib/toggl/TogglService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ACTIVE_TIMER_POLLING_INTERVAL } from "lib/constants";
import { ACTIVE_TIMER_POLLING_INTERVAL, STATUS_BAR_UPDATE_INTERVAL } from "lib/constants";
import type {
ClientId,
EnrichedWithClient,
Expand Down Expand Up @@ -30,6 +30,7 @@ import {
import { apiStatusStore, togglService } from "lib/util/stores";
import type MyPlugin from "main";
import moment from "moment";
import "moment-duration-format";
import { Notice } from "obsidian";
import { derived, get } from "svelte/store";

Expand Down Expand Up @@ -71,13 +72,13 @@ export default class TogglService {
private _statusBarItem: HTMLElement;

private _currentTimerInterval: number = null;
private _statusBarInterval: number = null;
private _currentTimeEntry: TimeEntry = null;
private _ApiAvailable = ApiStatus.UNTESTED;

constructor(plugin: MyPlugin) {
this._plugin = plugin;
this._statusBarItem = this._plugin.addStatusBarItem();
this._statusBarItem = this._plugin.addStatusBarItem();
this._statusBarItem.setText("Connecting to Toggl...");

this._plugin.registerDomEvent(this._statusBarItem, "click", () => {
Expand Down Expand Up @@ -106,6 +107,7 @@ export default class TogglService {
}

window.clearInterval(this._currentTimerInterval);
window.clearInterval(this._statusBarInterval);
if (token != null && token != "") {
try {
this._apiManager = new TogglAPI();
Expand All @@ -123,6 +125,7 @@ export default class TogglService {

// Fetch daily summary data and start polling for current timers.
this.startTimerInterval();
this.startStatusBarInterval();
this._apiManager
.getDailySummary()
.then((response) => setDailySummaryItems(response));
Expand Down Expand Up @@ -199,6 +202,17 @@ export default class TogglService {
this._plugin.registerInterval(this._currentTimerInterval);
}

/**
* Start updating the status bar periodically.
*/
private startStatusBarInterval() {
this.updateStatusBarText();
this._statusBarInterval = window.setInterval(() => {
this.updateStatusBarText();
}, STATUS_BAR_UPDATE_INTERVAL);
this._plugin.registerInterval(this._statusBarInterval);
}

private async updateCurrentTimer() {
if (!this.isApiAvailable) {
return;
Expand Down Expand Up @@ -272,7 +286,6 @@ export default class TogglService {
}

this._currentTimeEntry = curr;
this.updateStatusBarText();
}

/**
Expand All @@ -287,7 +300,7 @@ export default class TogglService {

let timer_msg = null;
if (this._currentTimeEntry == null) {
timer_msg = "-";
timer_msg = this._plugin.settings.statusBarNoEntryMesssage;
} else {
let title: string =
this._currentTimeEntry.description || "No description";
Expand All @@ -298,11 +311,17 @@ export default class TogglService {
)}...`;
}
const duration = this.getTimerDuration(this._currentTimeEntry);
const minutes = Math.floor(duration / 60);
const time_string = `${minutes} minute${minutes != 1 ? "s" : ""}`;
const time_string = moment.duration(duration, 'seconds').format(
this._plugin.settings.statusBarFormat,
{ trim: false, trunc: true },
)
if (this._plugin.settings.statusBarShowProject){
const currentEnhanced = enrichObjectWithProject(this._currentTimeEntry)
title += ` - ${currentEnhanced.$project?.name || "No project"}`
}
timer_msg = `${title} (${time_string})`;
}
this._statusBarItem.setText(`Timer: ${timer_msg}`);
this._statusBarItem.setText(`${this._plugin.settings.statusBarPrefix}${timer_msg}`);
}

/**
Expand Down
99 changes: 99 additions & 0 deletions lib/ui/TogglSettingsTab.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DEFAULT_SETTINGS } from "lib/config/DefaultSettings";
import type MyPlugin from "main";
import {
App,
Expand Down Expand Up @@ -32,6 +33,15 @@ export default class TogglSettingsTab extends PluginSettingTab {
this.addTestConnectionSetting(containerEl);
this.addWorkspaceSetting(containerEl);
this.addUpdateRealTimeSetting(containerEl);

containerEl.createEl("h2", {
text: "Status bar display options",
});
this.addCharLimitStatusBarSetting(containerEl);
this.addStatusBarFormatSetting(containerEl);
this.addStatusBarPrefixSetting(containerEl);
this.addStatusBarProjectSetting(containerEl);
this.addStatusBarNoEntrySetting(containerEl);
}

private addApiTokenSetting(containerEl: HTMLElement) {
Expand Down Expand Up @@ -104,6 +114,95 @@ export default class TogglSettingsTab extends PluginSettingTab {
});
}

private addCharLimitStatusBarSetting(containerEl: HTMLElement) {
new Setting(containerEl)
.setName("Status bar character limit")
.setDesc(
"Set a character limit for the time entry " +
"displayed in the status bar."
)
.addText((text) => {
text.setPlaceholder(String(DEFAULT_SETTINGS.charLimitStatusBar))
text.inputEl.type = "number"
text.setValue(String(this.plugin.settings.charLimitStatusBar))
text.onChange(async (value) => {
this.plugin.settings.charLimitStatusBar = (
value !== "" ? Number(value) : DEFAULT_SETTINGS.charLimitStatusBar
);
await this.plugin.saveSettings();
});
});
}

private addStatusBarFormatSetting(containerEl: HTMLElement) {
new Setting(containerEl)
.setName("Status bar time format")
.setDesc(
"Time format for the status bar. " +
"See https://github.com/jsmreese/moment-duration-format for format options.",
)
.addText((text) =>
text
.setPlaceholder(DEFAULT_SETTINGS.statusBarFormat)
.setValue(this.plugin.settings.statusBarFormat || "")
.onChange(async (value) => {
this.plugin.settings.statusBarFormat = value;
await this.plugin.saveSettings();
}),
);
}

private addStatusBarPrefixSetting(containerEl: HTMLElement) {
new Setting(containerEl)
.setName("Status bar prefix")
.setDesc(
"Prefix before the time entry in the status bar. " +
"Leave blank for no prefix.",
)
.addText((text) =>
text
.setPlaceholder(DEFAULT_SETTINGS.statusBarPrefix)
.setValue(this.plugin.settings.statusBarPrefix || "")
.onChange(async (value) => {
this.plugin.settings.statusBarPrefix = value;
await this.plugin.saveSettings();
}),
);
}

private addStatusBarProjectSetting(containerEl: HTMLElement) {
new Setting(containerEl)
.setName("Show project in status bar")
.setDesc(
"Show the project of the time entry displayed in the status bar."
)
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.statusBarShowProject || false)
.onChange(async (value) => {
this.plugin.settings.statusBarShowProject = value;
await this.plugin.saveSettings();
});
});
}

private addStatusBarNoEntrySetting(containerEl: HTMLElement) {
new Setting(containerEl)
.setName("No entry status bar message")
.setDesc(
"Message in the status bar when no time entry is running."
)
.addText((text) =>
text
.setPlaceholder(DEFAULT_SETTINGS.statusBarNoEntryMesssage)
.setValue(this.plugin.settings.statusBarNoEntryMesssage || "")
.onChange(async (value) => {
this.plugin.settings.statusBarNoEntryMesssage = value;
await this.plugin.saveSettings();
}),
);
}

private async fetchWorkspaces() {
// empty the dropdown's list
const selectEl = this.workspaceDropdown.selectEl;
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/components/current_timer/CurrentTimerDisplay.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<span
class="timer-project-name"
style:color={timer.$project?.color ?? "var(--text-muted)"}
>{timer.$project.name}</span
>{timer.$project?.name ?? "No project"}</span
>
<span class="divider-bullet mx-1">•</span>
<span class="timer-duration">{secondsToTimeString(duration)}</span>
Expand Down
21 changes: 11 additions & 10 deletions lib/util/millisecondsToTimeString.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
export default function millisecondsToTimeString(ms: number): string {
const sec = Math.round((ms / 1000) % 60);
const min = Math.floor((ms / 1000 / 60) % 60);
const hr = Math.floor(ms / 1000 / 60 / 60);
import moment from "moment";
import "moment-duration-format";

return `${hr}:${min < 10 ? "0" + min : min}:${sec < 10 ? "0" + sec : sec}`;
export default function millisecondsToTimeString(ms: number): string {
return moment.duration(ms).format(
'h:mm:ss',
{ trim: false, trunc: true },
)
}

export function secondsToTimeString(seconds: number): string {
const sec = Math.round(seconds % 60);
const min = Math.floor((seconds / 60) % 60);
const hr = Math.floor(seconds / 60 / 60);

return `${hr}:${min < 10 ? "0" + min : min}:${sec < 10 ? "0" + sec : sec}`;
return moment.duration(seconds, 'seconds').format(
'h:mm:ss',
{ trim: false, trunc: true },
)
}
Loading

0 comments on commit 0cb44a4

Please sign in to comment.