mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-18 00:46:45 +00:00
refactor(idle): change effect to allow handling multiple track items #1660
This commit is contained in:
parent
e66834246e
commit
af43ed3aef
9 changed files with 128 additions and 104 deletions
|
|
@ -83,7 +83,7 @@
|
|||
<mat-icon *ngIf="!isCreate">track_changes</mat-icon>
|
||||
<mat-icon *ngIf="isCreate">add</mat-icon>
|
||||
<!-- <mat-icon style="margin-left: -4px;">free_breakfast</mat-icon>-->
|
||||
{{T.F.TIME_TRACKING.D_IDLE.TASK_BREAK|translate}}
|
||||
{{T.F.TIME_TRACKING.D_IDLE.TASK_AND_BREAK|translate}}
|
||||
<mat-icon>free_breakfast</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ import { T } from '../../../t.const';
|
|||
import { ipcRenderer } from 'electron';
|
||||
import { IPC } from '../../../../../electron/ipc-events.const';
|
||||
import { SimpleCounterService } from '../../simple-counter/simple-counter.service';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { DialogConfirmComponent } from '../../../ui/dialog-confirm/dialog-confirm.component';
|
||||
import { ElectronService } from '../../../core/electron/electron.service';
|
||||
import { IS_ELECTRON } from '../../../app.constants';
|
||||
import { SimpleCounter } from '../../simple-counter/simple-counter.model';
|
||||
|
|
@ -73,8 +71,6 @@ export class DialogIdleComponent implements OnInit, OnDestroy {
|
|||
isWasEnabledBefore: isOn,
|
||||
} as SimpleCounterIdleBtn),
|
||||
);
|
||||
console.log(this.simpleCounterToggleBtns);
|
||||
|
||||
_matDialogRef.disableClose = true;
|
||||
}
|
||||
|
||||
|
|
@ -109,67 +105,36 @@ export class DialogIdleComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
skipTrack(): void {
|
||||
const activatedItemNr = this.simpleCounterToggleBtns.filter(
|
||||
(btn) => btn.isTrackTo,
|
||||
).length;
|
||||
if (activatedItemNr > 0) {
|
||||
this._matDialog
|
||||
.open(DialogConfirmComponent, {
|
||||
restoreFocus: true,
|
||||
data: {
|
||||
cancelTxt: T.F.TIME_TRACKING.D_IDLE.SIMPLE_CONFIRM_COUNTER_CANCEL,
|
||||
okTxt: T.F.TIME_TRACKING.D_IDLE.SIMPLE_CONFIRM_COUNTER_OK,
|
||||
message: T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_CONFIRM_TXT,
|
||||
translateParams: {
|
||||
nr: activatedItemNr,
|
||||
},
|
||||
},
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((isConfirm: boolean) => {
|
||||
if (isConfirm) {
|
||||
this._updateSimpleCounterValues();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this._matDialogRef.close({
|
||||
task: null,
|
||||
isResetBreakTimer: true,
|
||||
isTrackAsBreak: false,
|
||||
trackItems: [],
|
||||
simpleCounterToggleBtnsWhenNoTrackItems: this.simpleCounterToggleBtns,
|
||||
});
|
||||
}
|
||||
|
||||
trackAsBreak(): void {
|
||||
this._updateSimpleCounterValues();
|
||||
|
||||
this._matDialogRef.close({
|
||||
task: null,
|
||||
isResetBreakTimer: true,
|
||||
isTrackAsBreak: true,
|
||||
trackItems: [
|
||||
{
|
||||
type: 'BREAK',
|
||||
time: 'IDLE_TIME',
|
||||
simpleCounterToggleBtns: this.simpleCounterToggleBtns,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
track(isTrackAsBreak: boolean = false): void {
|
||||
this._updateSimpleCounterValues();
|
||||
|
||||
this._matDialogRef.close({
|
||||
task: this.selectedTask || this.newTaskTitle,
|
||||
isTrackAsBreak,
|
||||
isResetBreakTimer: isTrackAsBreak,
|
||||
});
|
||||
}
|
||||
|
||||
private async _updateSimpleCounterValues(): Promise<void> {
|
||||
const idleTime = await this.idleTime$.pipe(first()).toPromise();
|
||||
|
||||
this.simpleCounterToggleBtns.forEach((tglBtn) => {
|
||||
if (tglBtn.isTrackTo) {
|
||||
this._simpleCounterService.increaseCounterToday(tglBtn.id, idleTime);
|
||||
if (tglBtn.isWasEnabledBefore) {
|
||||
this._simpleCounterService.toggleCounter(tglBtn.id);
|
||||
}
|
||||
}
|
||||
trackItems: [
|
||||
{
|
||||
type: isTrackAsBreak ? 'TASK_AND_BREAK' : 'TASK',
|
||||
time: 'IDLE_TIME',
|
||||
simpleCounterToggleBtns: this.simpleCounterToggleBtns,
|
||||
...(this.isCreate
|
||||
? { title: this.newTaskTitle as string }
|
||||
: { task: this.selectedTask as Task }),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,19 @@ export interface SimpleCounterIdleBtn {
|
|||
}
|
||||
|
||||
export interface DialogIdleReturnData {
|
||||
task: null | Task | string | undefined;
|
||||
isResetBreakTimer: boolean;
|
||||
isTrackAsBreak: boolean;
|
||||
trackItems: IdleTrackItem[];
|
||||
simpleCounterToggleBtnsWhenNoTrackItems?: SimpleCounterIdleBtn[];
|
||||
}
|
||||
|
||||
export interface DialogIdlePassedData {
|
||||
enabledSimpleStopWatchCounters: SimpleCounter[];
|
||||
lastCurrentTaskId: string | null;
|
||||
}
|
||||
|
||||
export interface IdleTrackItem {
|
||||
type: 'BREAK' | 'TASK' | 'TASK_AND_BREAK';
|
||||
time: number | 'IDLE_TIME';
|
||||
simpleCounterToggleBtns: SimpleCounterIdleBtn[];
|
||||
task?: Task;
|
||||
title?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<mat-button-toggle value="BREAK">
|
||||
<mat-icon>free_breakfast</mat-icon>
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle value="TASK_BREAK">
|
||||
<mat-button-toggle value="TASK_AND_BREAK">
|
||||
<mat-icon>free_breakfast</mat-icon>
|
||||
+
|
||||
<mat-icon>track_changes</mat-icon>
|
||||
|
|
|
|||
|
|
@ -12,17 +12,9 @@ import { Store } from '@ngrx/store';
|
|||
import { SimpleCounterService } from '../../../simple-counter/simple-counter.service';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { T } from 'src/app/t.const';
|
||||
import { SimpleCounterIdleBtn } from '../dialog-idle.model';
|
||||
import { SimpleCounterIdleBtn, IdleTrackItem } from '../dialog-idle.model';
|
||||
import { dirtyDeepCopy } from '../../../../util/dirtyDeepCopy';
|
||||
|
||||
interface TrackToItem {
|
||||
type: 'BREAK' | 'TASK' | 'TASK_BREAK';
|
||||
time: number;
|
||||
simpleCounterToggleBtns: SimpleCounterIdleBtn[];
|
||||
task?: Task;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'idle-split-mode',
|
||||
templateUrl: './idle-split-mode.component.html',
|
||||
|
|
@ -36,7 +28,7 @@ export class IdleSplitModeComponent implements OnInit {
|
|||
@Input() prevSelectedTask: Task | null = null;
|
||||
|
||||
idleTime$ = this._store.select(selectIdleTime);
|
||||
trackToItems: TrackToItem[] = [];
|
||||
trackToItems: IdleTrackItem[] = [];
|
||||
|
||||
@Output() cancel = new EventEmitter();
|
||||
@Output() save = new EventEmitter();
|
||||
|
|
@ -78,7 +70,7 @@ export class IdleSplitModeComponent implements OnInit {
|
|||
];
|
||||
}
|
||||
|
||||
onTaskChange(item: TrackToItem, taskOrTaskTitle: Task | string): void {
|
||||
onTaskChange(item: IdleTrackItem, taskOrTaskTitle: Task | string): void {
|
||||
const isCreate = typeof taskOrTaskTitle === 'string';
|
||||
if (isCreate) {
|
||||
item.title = taskOrTaskTitle as string;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { createAction, props } from '@ngrx/store';
|
||||
import { SimpleCounter } from '../../simple-counter/simple-counter.model';
|
||||
import { Task } from '../../tasks/task.model';
|
||||
import { IdleTrackItem, SimpleCounterIdleBtn } from '../dialog-idle/dialog-idle.model';
|
||||
|
||||
export const triggerIdle = createAction(
|
||||
'[Idle] Trigger Idle',
|
||||
|
|
@ -24,10 +24,8 @@ export const setIdleTime = createAction(
|
|||
export const idleDialogResult = createAction(
|
||||
'[Idle] Dialog result',
|
||||
props<{
|
||||
timeSpent: number;
|
||||
selectedTaskOrTitle: Task | string;
|
||||
isResetBreakTimer: boolean;
|
||||
isTrackAsBreak: boolean;
|
||||
trackItems: IdleTrackItem[];
|
||||
simpleCounterToggleBtnsWhenNoTrackItems?: SimpleCounterIdleBtn[];
|
||||
}>(),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,8 +43,12 @@ import { devError } from '../../../util/dev-error';
|
|||
import {
|
||||
DialogIdlePassedData,
|
||||
DialogIdleReturnData,
|
||||
IdleTrackItem,
|
||||
SimpleCounterIdleBtn,
|
||||
} from '../dialog-idle/dialog-idle.model';
|
||||
import { isNotNullOrUndefined } from '../../../util/is-not-null-or-undefined';
|
||||
import { DialogConfirmComponent } from '../../../ui/dialog-confirm/dialog-confirm.component';
|
||||
import { T } from '../../../t.const';
|
||||
|
||||
const DEFAULT_MIN_IDLE_TIME = 60000;
|
||||
const IDLE_POLL_INTERVAL = 1000;
|
||||
|
|
@ -57,7 +61,6 @@ export class IdleEffects {
|
|||
|
||||
private _triggerIdleApis$ = IS_ELECTRON
|
||||
? fromEvent(this._electronService.ipcRenderer as IpcRenderer, IPC.IDLE_TIME).pipe(
|
||||
tap((v) => console.log('IIIIIIIIII', v)),
|
||||
map(([ev, idleTimeInMs]: any) => idleTimeInMs as number),
|
||||
)
|
||||
: this._chromeExtensionInterfaceService.onReady$.pipe(
|
||||
|
|
@ -175,15 +178,7 @@ export class IdleEffects {
|
|||
}
|
||||
}),
|
||||
isNotNullOrUndefined(),
|
||||
withLatestFrom(this._store.select(selectIdleTime)),
|
||||
map(([{ task, isResetBreakTimer, isTrackAsBreak }, idleTimeI]) =>
|
||||
idleDialogResult({
|
||||
timeSpent: idleTimeI,
|
||||
selectedTaskOrTitle: task as any,
|
||||
isResetBreakTimer,
|
||||
isTrackAsBreak,
|
||||
}),
|
||||
),
|
||||
map((dialogRes) => idleDialogResult(dialogRes)),
|
||||
tap(() => (this._isDialogOpen = false)),
|
||||
),
|
||||
);
|
||||
|
|
@ -191,31 +186,84 @@ export class IdleEffects {
|
|||
onIdleDialogResult$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(idleDialogResult),
|
||||
tap(({ timeSpent, selectedTaskOrTitle, isResetBreakTimer, isTrackAsBreak }) => {
|
||||
if (isResetBreakTimer || isTrackAsBreak) {
|
||||
withLatestFrom(this._store.select(selectIdleTime)),
|
||||
tap(([{ trackItems, simpleCounterToggleBtnsWhenNoTrackItems }, idleTime]) => {
|
||||
this._cancelIdlePoll();
|
||||
|
||||
if (trackItems.length === 0 && simpleCounterToggleBtnsWhenNoTrackItems) {
|
||||
const activatedItemNr = simpleCounterToggleBtnsWhenNoTrackItems.filter(
|
||||
(btn) => btn.isTrackTo,
|
||||
).length;
|
||||
|
||||
// TODO maybe move to effect
|
||||
if (activatedItemNr > 0) {
|
||||
this._matDialog
|
||||
.open(DialogConfirmComponent, {
|
||||
restoreFocus: true,
|
||||
data: {
|
||||
cancelTxt: T.F.TIME_TRACKING.D_IDLE.SIMPLE_CONFIRM_COUNTER_CANCEL,
|
||||
okTxt: T.F.TIME_TRACKING.D_IDLE.SIMPLE_CONFIRM_COUNTER_OK,
|
||||
message: T.F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_CONFIRM_TXT,
|
||||
translateParams: {
|
||||
nr: activatedItemNr,
|
||||
},
|
||||
},
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((isConfirm: boolean) => {
|
||||
if (isConfirm) {
|
||||
// TODO maybe move to effect
|
||||
this._updateSimpleCounterValues(
|
||||
simpleCounterToggleBtnsWhenNoTrackItems,
|
||||
idleTime,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const itemsWithMappedIdleTime = trackItems.map((trackItem) => ({
|
||||
...trackItem,
|
||||
time: trackItem.time === 'IDLE_TIME' ? idleTime : trackItem.time,
|
||||
}));
|
||||
|
||||
itemsWithMappedIdleTime.forEach((item) => {
|
||||
this._updateSimpleCounterValues(item.simpleCounterToggleBtns, item.time);
|
||||
});
|
||||
|
||||
const breakItems = itemsWithMappedIdleTime.filter(
|
||||
(item: IdleTrackItem) =>
|
||||
item.type === 'BREAK' || item.type === 'TASK_AND_BREAK',
|
||||
);
|
||||
if (breakItems.length) {
|
||||
this._store.dispatch(triggerResetBreakTimer());
|
||||
breakItems.forEach((item) => {
|
||||
this._workContextService.addToBreakTimeForActiveContext(undefined, item.time);
|
||||
});
|
||||
}
|
||||
|
||||
if (isTrackAsBreak) {
|
||||
this._workContextService.addToBreakTimeForActiveContext(undefined, timeSpent);
|
||||
}
|
||||
|
||||
if (selectedTaskOrTitle) {
|
||||
if (typeof selectedTaskOrTitle === 'string') {
|
||||
const currId = this._taskService.add(selectedTaskOrTitle, false, {
|
||||
timeSpent,
|
||||
const taskItems = itemsWithMappedIdleTime.filter(
|
||||
(item: IdleTrackItem) => item.type === 'TASK' || item.type === 'TASK_AND_BREAK',
|
||||
);
|
||||
let taskItemId: string | undefined;
|
||||
taskItems.forEach((taskItem) => {
|
||||
if (typeof taskItem.title === 'string') {
|
||||
taskItemId = this._taskService.add(taskItem.title, false, {
|
||||
timeSpent: taskItem.time,
|
||||
timeSpentOnDay: {
|
||||
[getWorklogStr()]: timeSpent,
|
||||
[getWorklogStr()]: taskItem.time,
|
||||
},
|
||||
});
|
||||
this._taskService.setCurrentId(currId);
|
||||
} else {
|
||||
this._taskService.addTimeSpent(selectedTaskOrTitle, timeSpent);
|
||||
this._taskService.setCurrentId(selectedTaskOrTitle.id);
|
||||
} else if (taskItem.task) {
|
||||
taskItemId = taskItem.task.id;
|
||||
this._taskService.addTimeSpent(taskItem.task, taskItem.time);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this._cancelIdlePoll();
|
||||
if (taskItems.length === 1 && taskItemId) {
|
||||
this._taskService.setCurrentId(taskItemId);
|
||||
}
|
||||
}),
|
||||
// unset idle at the end
|
||||
mapTo(resetIdle()),
|
||||
|
|
@ -258,4 +306,18 @@ export class IdleEffects {
|
|||
}
|
||||
this._isFrontEndIdlePollRunning = false;
|
||||
}
|
||||
|
||||
private async _updateSimpleCounterValues(
|
||||
simpleCounterToggleBtns: SimpleCounterIdleBtn[],
|
||||
idleTime: number,
|
||||
): Promise<void> {
|
||||
simpleCounterToggleBtns.forEach((tglBtn) => {
|
||||
if (tglBtn.isTrackTo) {
|
||||
this._simpleCounterService.increaseCounterToday(tglBtn.id, idleTime);
|
||||
if (tglBtn.isWasEnabledBefore) {
|
||||
this._simpleCounterService.toggleCounter(tglBtn.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -923,7 +923,7 @@ const T = {
|
|||
'F.TIME_TRACKING.D_IDLE.SIMPLE_COUNTER_TOOLTIP_DISABLE',
|
||||
SKIP: 'F.TIME_TRACKING.D_IDLE.SKIP',
|
||||
TASK: 'F.TIME_TRACKING.D_IDLE.TASK',
|
||||
TASK_BREAK: 'F.TIME_TRACKING.D_IDLE.TASK_BREAK',
|
||||
TASK_AND_BREAK: 'F.TIME_TRACKING.D_IDLE.TASK_BREAK',
|
||||
TRACK_TO: 'F.TIME_TRACKING.D_IDLE.TRACK_TO',
|
||||
},
|
||||
D_TRACKING_REMINDER: {
|
||||
|
|
|
|||
|
|
@ -905,7 +905,7 @@
|
|||
"IDLE_FOR": "You have been idle for:",
|
||||
"SIMPLE_CONFIRM_COUNTER_CANCEL": "Skip",
|
||||
"SIMPLE_CONFIRM_COUNTER_OK": "Track",
|
||||
"SIMPLE_COUNTER_CONFIRM_TXT": "You selected skip, but activated {{nr}1} simple counter button(s). Do you want to track the idle time to them?",
|
||||
"SIMPLE_COUNTER_CONFIRM_TXT": "You selected skip, but activated {{nr}} simple counter button(s). Do you want to track the idle time to them?",
|
||||
"SIMPLE_COUNTER_TOOLTIP": "Click to track to {{title}}",
|
||||
"SIMPLE_COUNTER_TOOLTIP_DISABLE": "Click to NOT track to {{title}}",
|
||||
"SKIP": "Skip",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue