feat: improve finish day for electron variant

This commit is contained in:
Johannes Millan 2021-11-03 16:56:08 +01:00
parent 765ee1da28
commit e85cfe2937
11 changed files with 176 additions and 31 deletions

View File

@ -2,11 +2,9 @@ import * as windowStateKeeper from 'electron-window-state';
import {
App,
BrowserWindow,
dialog,
ipcMain,
Menu,
MenuItemConstructorOptions,
MessageBoxReturnValue,
shell,
} from 'electron';
import { errorHandlerWithFrontendInform } from './error-handler-with-frontend-inform';
@ -237,25 +235,7 @@ const appCloseHandler = (app: App): void => {
log('Actions to wait for ', ids);
mainWin.webContents.send(IPC.NOTIFY_ON_CLOSE, ids);
} else {
if (appCfg && appCfg.misc.isConfirmBeforeExit && !(app as any).isQuiting) {
dialog
.showMessageBox(mainWin, {
type: 'question',
buttons: ['Yes', 'No'],
title: 'Confirm',
message: 'Are you sure you want to quit?',
})
.then((choice: MessageBoxReturnValue) => {
if (choice.response === 1) {
return;
} else if (choice.response === 0) {
_quitApp();
return;
}
});
} else {
_quitApp();
}
_quitApp();
}
});
}

View File

@ -45,6 +45,7 @@ import { SyncModule } from './imex/sync/sync.module';
import { SearchBarModule } from './features/search-bar/search-bar.module';
import { IdleModule } from './features/idle/idle.module';
import { TrackingReminderModule } from './features/tracking-reminder/tracking-reminder.module';
import { FinishDayBeforeCloseModule } from './features/finish-day-before-close/finish-day-before-close.module';
// NOTE: export required for aot to work
export const createTranslateLoader = (http: HttpClient): TranslateHttpLoader =>
@ -76,6 +77,7 @@ export const createTranslateLoader = (http: HttpClient): TranslateHttpLoader =>
SyncModule,
MaterialCssVarsModule.forRoot(),
SearchBarModule,
FinishDayBeforeCloseModule,
// External
BrowserModule,

View File

@ -16,6 +16,7 @@ export const DEFAULT_GLOBAL_CONFIG: GlobalConfigState = {
misc: {
isDarkMode: IS_USE_DARK_THEME_AS_DEFAULT,
isConfirmBeforeExit: false,
isConfirmBeforeExitWithoutFinishDay: true,
isNotifyWhenTimeEstimateExceeded: true,
isAutMarkParentAsDone: false,
isAutoStartNextTask: true,

View File

@ -1,6 +1,11 @@
/* eslint-disable max-len */
import { ConfigFormSection, MiscConfig } from '../global-config.model';
import {
ConfigFormSection,
LimitedFormlyFieldConfig,
MiscConfig,
} from '../global-config.model';
import { T } from '../../../t.const';
import { IS_ELECTRON } from '../../../app.constants';
export const MISC_SETTINGS_FORM_CFG: ConfigFormSection<MiscConfig> = {
title: T.GCF.MISC.TITLE,
@ -14,13 +19,25 @@ export const MISC_SETTINGS_FORM_CFG: ConfigFormSection<MiscConfig> = {
// label: T.GCF.MISC.IS_DARK_MODE,
// },
// },
{
key: 'isConfirmBeforeExit',
type: 'checkbox',
templateOptions: {
label: T.GCF.MISC.IS_CONFIRM_BEFORE_EXIT,
},
},
...((IS_ELECTRON
? [
{
key: 'isConfirmBeforeExitWithoutFinishDay',
type: 'checkbox',
templateOptions: {
label: T.GCF.MISC.IS_CONFIRM_BEFORE_EXIT_WITHOUT_FINISH_DAY,
},
},
]
: [
{
key: 'isConfirmBeforeExit',
type: 'checkbox',
templateOptions: {
label: T.GCF.MISC.IS_CONFIRM_BEFORE_EXIT,
},
},
]) as LimitedFormlyFieldConfig<MiscConfig>[]),
{
key: 'isNotifyWhenTimeEstimateExceeded',
type: 'checkbox',

View File

@ -9,6 +9,7 @@ export type MiscConfig = Readonly<{
isAutMarkParentAsDone: boolean;
isAutoStartNextTask: boolean;
isConfirmBeforeExit: boolean;
isConfirmBeforeExitWithoutFinishDay: boolean;
isNotifyWhenTimeEstimateExceeded: boolean;
isTurnOffMarkdown: boolean;
isAutoAddWorkedOnToToday: boolean;

View File

@ -9,7 +9,7 @@ import { MODEL_VERSION_KEY } from '../../app.constants';
import { isMigrateModel } from '../../util/model-version';
import { SyncProvider } from '../../imex/sync/sync-provider.model';
const MODEL_VERSION = 2.2005;
const MODEL_VERSION = 2.2006;
export const migrateGlobalConfigState = (
globalConfigState: GlobalConfigState,

View File

@ -0,0 +1,25 @@
// import { TestBed } from '@angular/core/testing';
// import { provideMockActions } from '@ngrx/effects/testing';
// import { Observable } from 'rxjs';
//
// import { FinishDayBeforeCloseEffects } from './finish-day-before-close.effects';
//
// describe('FinishDayBeforeCloseEffects', () => {
// let actions$: Observable<any>;
// let effects: FinishDayBeforeCloseEffects;
//
// beforeEach(() => {
// TestBed.configureTestingModule({
// providers: [
// FinishDayBeforeCloseEffects,
// provideMockActions(() => actions$)
// ]
// });
//
// effects = TestBed.inject(FinishDayBeforeCloseEffects);
// });
//
// it('should be created', () => {
// expect(effects).toBeTruthy();
// });
// });

View File

@ -0,0 +1,97 @@
import { Injectable } from '@angular/core';
import { Actions, createEffect } from '@ngrx/effects';
import { ExecBeforeCloseService } from '../../core/electron/exec-before-close.service';
import { GlobalConfigService } from '../config/global-config.service';
import {
concatMap,
distinctUntilChanged,
first,
map,
switchMap,
tap,
} from 'rxjs/operators';
import { DataInitService } from '../../core/data-init/data-init.service';
import { IS_ELECTRON } from '../../app.constants';
import { EMPTY, Observable } from 'rxjs';
import { WorkContextService } from '../work-context/work-context.service';
import { TaskService } from '../tasks/task.service';
import { Router } from '@angular/router';
import { TODAY_TAG } from '../tag/tag.const';
import { TranslateService } from '@ngx-translate/core';
import { T } from '../../t.const';
const EXEC_BEFORE_CLOSE_ID = 'FINISH_DAY_BEFORE_CLOSE_EFFECT';
@Injectable()
export class FinishDayBeforeCloseEffects {
isEnabled$: Observable<boolean> = this._dataInitService.isAllDataLoadedInitially$.pipe(
concatMap(() => this._globalConfigService.misc$),
map((misc) => misc.isConfirmBeforeExitWithoutFinishDay),
distinctUntilChanged(),
);
scheduleUnscheduleFinishDayBeforeClose$ =
IS_ELECTRON &&
createEffect(
() =>
this.isEnabled$.pipe(
tap((isEnabled) =>
isEnabled
? this._execBeforeCloseService.schedule(EXEC_BEFORE_CLOSE_ID)
: this._execBeforeCloseService.unschedule(EXEC_BEFORE_CLOSE_ID),
),
),
{ dispatch: false },
);
warnToFinishDayBeforeClose$ =
IS_ELECTRON &&
createEffect(
() =>
this.isEnabled$.pipe(
switchMap((isEnabled) =>
isEnabled ? this._execBeforeCloseService.onBeforeClose$ : EMPTY,
),
switchMap(() =>
this._workContextService.mainWorkContext$.pipe(
switchMap((workContext) =>
this._taskService.getByIdsLive$(workContext.taskIds).pipe(first()),
),
),
),
tap((todayMainTasks) => {
const doneTasks = todayMainTasks.filter((t) => t.isDone);
if (doneTasks.length) {
if (
confirm(
this._translateService.instant(
T.F.FINISH_DAY_BEFORE_EXIT.C.FINISH_DAY_BEFORE_EXIT,
{
nr: doneTasks.length,
},
),
)
) {
this._execBeforeCloseService.setDone(EXEC_BEFORE_CLOSE_ID);
} else {
this._router.navigate([`tag/${TODAY_TAG.id}/daily-summary`]);
}
} else {
this._execBeforeCloseService.setDone(EXEC_BEFORE_CLOSE_ID);
}
}),
),
{ dispatch: false },
);
constructor(
private actions$: Actions,
private _execBeforeCloseService: ExecBeforeCloseService,
private _globalConfigService: GlobalConfigService,
private _dataInitService: DataInitService,
private _taskService: TaskService,
private _workContextService: WorkContextService,
private _router: Router,
private _translateService: TranslateService,
) {}
}

View File

@ -0,0 +1,10 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { EffectsModule } from '@ngrx/effects';
import { FinishDayBeforeCloseEffects } from './finish-day-before-close.effects';
@NgModule({
declarations: [],
imports: [CommonModule, EffectsModule.forFeature([FinishDayBeforeCloseEffects])],
})
export class FinishDayBeforeCloseModule {}

View File

@ -124,6 +124,11 @@ const T = {
SYNC_ERROR: 'F.DROPBOX.S.SYNC_ERROR',
},
},
FINISH_DAY_BEFORE_EXIT: {
C: {
FINISH_DAY_BEFORE_EXIT: 'F.FINISH_DAY_BEFORE_EXIT.C.FINISH_DAY_BEFORE_EXIT',
},
},
GITHUB: {
DIALOG_INITIAL: {
TITLE: 'F.GITHUB.DIALOG_INITIAL.TITLE',
@ -1113,6 +1118,8 @@ const T = {
IS_AUTO_MARK_PARENT_AS_DONE: 'GCF.MISC.IS_AUTO_MARK_PARENT_AS_DONE',
IS_AUTO_START_NEXT_TASK: 'GCF.MISC.IS_AUTO_START_NEXT_TASK',
IS_CONFIRM_BEFORE_EXIT: 'GCF.MISC.IS_CONFIRM_BEFORE_EXIT',
IS_CONFIRM_BEFORE_EXIT_WITHOUT_FINISH_DAY:
'GCF.MISC.IS_CONFIRM_BEFORE_EXIT_WITHOUT_FINISH_DAY',
IS_DARK_MODE: 'GCF.MISC.IS_DARK_MODE',
IS_HIDE_NAV: 'GCF.MISC.IS_HIDE_NAV',
IS_MINIMIZE_TO_TRAY: 'GCF.MISC.IS_MINIMIZE_TO_TRAY',
@ -1267,7 +1274,6 @@ const T = {
PP: {
ARCHIVED_PROJECTS: 'PP.ARCHIVED_PROJECTS',
ARCHIVE_PROJECT: 'PP.ARCHIVE_PROJECT',
CREATE_NEW: 'PP.CREATE_NEW',
DELETE_PROJECT: 'PP.DELETE_PROJECT',
D_CONFIRM_ARCHIVE: {
MSG: 'PP.D_CONFIRM_ARCHIVE.MSG',

View File

@ -124,6 +124,11 @@
"SYNC_ERROR": "Dropbox: Error while syncing"
}
},
"FINISH_DAY_BEFORE_EXIT": {
"C": {
"FINISH_DAY_BEFORE_EXIT": "There are {{nr}} done tasks in your today list not yet moved to the archive. Do you really want to quit without finishing your day?"
}
},
"GITHUB": {
"DIALOG_INITIAL": {
"TITLE": "Setup GitHub for Project"
@ -1099,6 +1104,7 @@
"IS_AUTO_MARK_PARENT_AS_DONE": "Mark parent task as done, when all sub tasks are done",
"IS_AUTO_START_NEXT_TASK": "Start tracking next task when marking current as done",
"IS_CONFIRM_BEFORE_EXIT": "Confirm before exiting the app",
"IS_CONFIRM_BEFORE_EXIT_WITHOUT_FINISH_DAY": "Confirm before exiting the app without finishing day first",
"IS_DARK_MODE": "Dark Mode",
"IS_HIDE_NAV": "Hide navigation until main header is hovered (desktop only)",
"IS_MINIMIZE_TO_TRAY": "Minimize to tray (desktop only)",