mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
refactor: globalConfigService props to signal
This commit is contained in:
parent
384a9ef62b
commit
4b66f93dfa
21 changed files with 170 additions and 167 deletions
15
package-lock.json
generated
15
package-lock.json
generated
|
|
@ -68,7 +68,6 @@
|
|||
"@schematics/angular": "^20.1.4",
|
||||
"@types/electron-localshortcut": "^3.1.3",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@types/hammerjs": "^2.0.45",
|
||||
"@types/jasmine": "^3.10.2",
|
||||
"@types/jasminewd2": "~2.0.13",
|
||||
"@types/node": "20.12.4",
|
||||
|
|
@ -100,7 +99,6 @@
|
|||
"fflate": "^0.8.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"glob": "^9.3.5",
|
||||
"hammerjs": "^2.0.8",
|
||||
"husky": "^4.2.5",
|
||||
"ical.js": "^2.1.0",
|
||||
"idb": "^8.0.3",
|
||||
|
|
@ -7477,11 +7475,6 @@
|
|||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/hammerjs": {
|
||||
"version": "2.0.46",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/http-cache-semantics": {
|
||||
"version": "4.0.4",
|
||||
"dev": true,
|
||||
|
|
@ -14002,14 +13995,6 @@
|
|||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/hammerjs": {
|
||||
"version": "2.0.8",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/handle-thing": {
|
||||
"version": "2.0.1",
|
||||
"dev": true,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
computed,
|
||||
effect,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
|
|
@ -162,7 +163,14 @@ export class AppComponent implements OnDestroy, AfterViewInit {
|
|||
|
||||
@ViewChild('routeWrapper', { read: ElementRef }) routeWrapper?: ElementRef<HTMLElement>;
|
||||
|
||||
@HostBinding('@.disabled') isDisableAnimations = false;
|
||||
@HostBinding('@.disabled') get isDisableAnimations(): boolean {
|
||||
return this._isDisableAnimations();
|
||||
}
|
||||
|
||||
private _isDisableAnimations = computed(() => {
|
||||
const misc = this._globalConfigService.misc();
|
||||
return misc?.isDisableAnimations ?? false;
|
||||
});
|
||||
|
||||
isRTL: boolean = false;
|
||||
|
||||
|
|
@ -201,11 +209,6 @@ export class AppComponent implements OnDestroy, AfterViewInit {
|
|||
}
|
||||
}),
|
||||
);
|
||||
this._subs.add(
|
||||
this._globalConfigService.misc$.subscribe((misc) => {
|
||||
this.isDisableAnimations = misc.isDisableAnimations;
|
||||
}),
|
||||
);
|
||||
|
||||
// init theme and body class handlers
|
||||
this._globalThemeService.init();
|
||||
|
|
@ -220,7 +223,7 @@ export class AppComponent implements OnDestroy, AfterViewInit {
|
|||
// init offline banner in lack of a better place for it
|
||||
this._initOfflineBanner();
|
||||
|
||||
if (this._globalConfigService.cfg?.misc.isShowTipLonger) {
|
||||
if (this._globalConfigService.misc()?.isShowTipLonger) {
|
||||
this._snackService.open({
|
||||
ico: 'lightbulb',
|
||||
config: {
|
||||
|
|
@ -285,13 +288,13 @@ export class AppComponent implements OnDestroy, AfterViewInit {
|
|||
|
||||
window.ea.on(IPC.TRANSFER_SETTINGS_REQUESTED, () => {
|
||||
window.ea.sendAppSettingsToElectron(
|
||||
this._globalConfigService.cfg as GlobalConfigState,
|
||||
this._globalConfigService.cfg() as GlobalConfigState,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// WEB VERSION
|
||||
window.addEventListener('beforeunload', (e) => {
|
||||
const gCfg = this._globalConfigService.cfg;
|
||||
const gCfg = this._globalConfigService.cfg();
|
||||
if (!gCfg) {
|
||||
throw new Error();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,6 +225,6 @@ export class MainHeaderComponent implements OnDestroy {
|
|||
}
|
||||
|
||||
get kb(): KeyboardConfig {
|
||||
return (this._configService.cfg?.keyboard as KeyboardConfig) || {};
|
||||
return (this._configService.cfg()?.keyboard as KeyboardConfig) || {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ export class MobileSidePanelMenuComponent {
|
|||
{ initialValue: !!this._router.url.match(/tasks$/) },
|
||||
);
|
||||
|
||||
readonly kb: KeyboardConfig = this._globalConfigService.cfg?.keyboard || {};
|
||||
readonly kb: KeyboardConfig = this._globalConfigService.cfg()?.keyboard || {};
|
||||
|
||||
// Plugin-related signals
|
||||
readonly sidePanelButtons = toSignal(this._pluginBridge.sidePanelButtons$, {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export class ShortcutService {
|
|||
}
|
||||
|
||||
async handleKeyDown(ev: KeyboardEvent): Promise<void> {
|
||||
const cfg = this._configService.cfg;
|
||||
const cfg = this._configService.cfg();
|
||||
if (!cfg) {
|
||||
throw new Error();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ export class SideNavComponent implements OnDestroy {
|
|||
private _cachedIssueUrl?: string;
|
||||
|
||||
@HostBinding('class') get cssClass(): string {
|
||||
return this._globalConfigService.cfg?.misc.isUseMinimalNav ? 'minimal-nav' : '';
|
||||
return this._globalConfigService.cfg()?.misc.isUseMinimalNav ? 'minimal-nav' : '';
|
||||
}
|
||||
|
||||
constructor() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { inject, Injectable } from '@angular/core';
|
||||
import { computed, inject, Injectable } from '@angular/core';
|
||||
import { GlobalConfigService } from '../../features/config/global-config.service';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
|
@ -8,53 +7,45 @@ import { map, shareReplay } from 'rxjs/operators';
|
|||
export class DateTimeFormatService {
|
||||
private readonly _globalConfigService = inject(GlobalConfigService);
|
||||
|
||||
// Cache the current locale for synchronous access
|
||||
private _currentLocale: string | undefined = undefined;
|
||||
|
||||
// Observable for the locale to use
|
||||
readonly locale$ = this._globalConfigService.lang$.pipe(
|
||||
map((langConfig) => langConfig.timeLocale || undefined),
|
||||
shareReplay(1),
|
||||
// Signal for the locale to use
|
||||
private readonly _locale = computed(
|
||||
() => this._globalConfigService.lang()?.timeLocale || undefined,
|
||||
);
|
||||
|
||||
// For detecting if current locale uses 24-hour format (used in schedule component)
|
||||
get is24HourFormat(): boolean {
|
||||
readonly is24HourFormat = computed(() => {
|
||||
const testDate = new Date(2000, 0, 1, 13, 0, 0);
|
||||
const formatted = testDate.toLocaleTimeString(this._currentLocale, {
|
||||
const formatted = testDate.toLocaleTimeString(this._locale(), {
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
});
|
||||
return formatted.includes('13');
|
||||
}
|
||||
});
|
||||
|
||||
// Get the current locale being used
|
||||
get currentLocale(): string | undefined {
|
||||
return this._currentLocale;
|
||||
return this._locale();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// Subscribe to keep the cached locale updated
|
||||
this.locale$.subscribe((locale) => {
|
||||
this._currentLocale = locale;
|
||||
|
||||
// Debug logging
|
||||
if (locale) {
|
||||
const testDate = new Date(2000, 0, 1, 13, 0, 0);
|
||||
const formatted = testDate.toLocaleTimeString(locale, {
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
});
|
||||
console.log('[DateTimeFormat] Using locale:', locale);
|
||||
console.log(' - Test time (13:00):', formatted);
|
||||
console.log(' - Format:', formatted.includes('13') ? '24-hour' : '12-hour');
|
||||
} else {
|
||||
console.log('[DateTimeFormat] Using system default locale');
|
||||
}
|
||||
});
|
||||
// Debug logging when locale changes
|
||||
const locale = this._locale();
|
||||
if (locale) {
|
||||
const testDate = new Date(2000, 0, 1, 13, 0, 0);
|
||||
const formatted = testDate.toLocaleTimeString(locale, {
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
});
|
||||
console.log('[DateTimeFormat] Using locale:', locale);
|
||||
console.log(' - Test time (13:00):', formatted);
|
||||
console.log(' - Format:', formatted.includes('13') ? '24-hour' : '12-hour');
|
||||
} else {
|
||||
console.log('[DateTimeFormat] Using system default locale');
|
||||
}
|
||||
}
|
||||
|
||||
formatTime(timestamp: number): string {
|
||||
return new Date(timestamp).toLocaleTimeString(this._currentLocale, {
|
||||
return new Date(timestamp).toLocaleTimeString(this._locale(), {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Injectable, inject } from '@angular/core';
|
||||
import { Injectable, inject, effect } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DateAdapter } from '@angular/material/core';
|
||||
import {
|
||||
|
|
@ -9,7 +9,6 @@ import {
|
|||
} from '../../app.constants';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { GlobalConfigService } from 'src/app/features/config/global-config.service';
|
||||
import { map, startWith } from 'rxjs/operators';
|
||||
import { DEFAULT_GLOBAL_CONFIG } from 'src/app/features/config/default-global-config.const';
|
||||
import { Log } from '../log';
|
||||
|
||||
|
|
@ -55,19 +54,19 @@ export class LanguageService {
|
|||
}
|
||||
|
||||
private _initMonkeyPatchFirstDayOfWeek(): void {
|
||||
let firstDayOfWeek = DEFAULT_GLOBAL_CONFIG.misc.firstDayOfWeek;
|
||||
this._globalConfigService.misc$
|
||||
.pipe(
|
||||
map((cfg) => cfg.firstDayOfWeek),
|
||||
startWith(1),
|
||||
)
|
||||
.subscribe((_firstDayOfWeek: number) => {
|
||||
// default should be monday, if we have an invalid value for some reason
|
||||
firstDayOfWeek =
|
||||
_firstDayOfWeek === 0 || _firstDayOfWeek > 0 ? _firstDayOfWeek : 1;
|
||||
});
|
||||
// overwrites default method to make this configurable
|
||||
this._dateAdapter.getFirstDayOfWeek = () => firstDayOfWeek;
|
||||
// Use effect to reactively update firstDayOfWeek when config changes
|
||||
effect(() => {
|
||||
const miscConfig = this._globalConfigService.misc();
|
||||
const firstDayOfWeek =
|
||||
miscConfig?.firstDayOfWeek ?? DEFAULT_GLOBAL_CONFIG.misc.firstDayOfWeek;
|
||||
|
||||
// default should be monday, if we have an invalid value for some reason
|
||||
const validFirstDayOfWeek =
|
||||
firstDayOfWeek === 0 || firstDayOfWeek > 0 ? firstDayOfWeek : 1;
|
||||
|
||||
// overwrites default method to make this configurable
|
||||
this._dateAdapter.getFirstDayOfWeek = () => validFirstDayOfWeek;
|
||||
});
|
||||
}
|
||||
|
||||
private _setFn(lng: LanguageCode): void {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { inject, Injectable } from '@angular/core';
|
||||
import { effect, inject, Injectable } from '@angular/core';
|
||||
import { BodyClass, IS_ELECTRON } from '../../app.constants';
|
||||
import { IS_MAC } from '../../util/is-mac';
|
||||
import {
|
||||
|
|
@ -89,8 +89,8 @@ export class GlobalThemeService {
|
|||
.pipe(skip(1))
|
||||
.subscribe((darkMode) => localStorage.setItem(LS.DARK_MODE, darkMode));
|
||||
|
||||
// Initialize custom theme
|
||||
this._initCustomTheme();
|
||||
// Set up reactive custom theme updates
|
||||
this._setupCustomThemeEffect();
|
||||
}
|
||||
|
||||
private _setDarkTheme(isDarkTheme: boolean): void {
|
||||
|
|
@ -231,8 +231,10 @@ export class GlobalThemeService {
|
|||
});
|
||||
}
|
||||
|
||||
this._globalConfigService.misc$.subscribe((misc) => {
|
||||
if (misc.isDisableAnimations) {
|
||||
// Use effect to reactively update animation class
|
||||
effect(() => {
|
||||
const misc = this._globalConfigService.misc();
|
||||
if (misc?.isDisableAnimations) {
|
||||
this.document.body.classList.add(BodyClass.isDisableAnimations);
|
||||
} else {
|
||||
this.document.body.classList.remove(BodyClass.isDisableAnimations);
|
||||
|
|
@ -295,26 +297,20 @@ export class GlobalThemeService {
|
|||
this._chartThemeService.setColorschemesOptions(overrides);
|
||||
}
|
||||
|
||||
private _initCustomTheme(): void {
|
||||
// Load initial theme
|
||||
this._globalConfigService.misc$
|
||||
.pipe(
|
||||
take(1),
|
||||
map((misc) => misc.customTheme || 'default'),
|
||||
)
|
||||
.subscribe((themeId) => {
|
||||
this._customThemeService.loadTheme(themeId);
|
||||
});
|
||||
private _setupCustomThemeEffect(): void {
|
||||
// Track previous theme to avoid unnecessary reloads
|
||||
let previousThemeId: string | null = null;
|
||||
|
||||
// Watch for theme changes
|
||||
this._globalConfigService.misc$
|
||||
.pipe(
|
||||
map((misc) => misc.customTheme || 'default'),
|
||||
distinctUntilChanged(),
|
||||
skip(1),
|
||||
)
|
||||
.subscribe((themeId) => {
|
||||
// Set up effect to reactively update custom theme when config changes
|
||||
effect(() => {
|
||||
const misc = this._globalConfigService.misc();
|
||||
const themeId = misc?.customTheme || 'default';
|
||||
|
||||
// Only load theme if it has changed
|
||||
if (themeId !== previousThemeId) {
|
||||
this._customThemeService.loadTheme(themeId);
|
||||
});
|
||||
previousThemeId = themeId;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Injectable, inject } from '@angular/core';
|
||||
import { Injectable, inject, Signal } from '@angular/core';
|
||||
import { select, Store } from '@ngrx/store';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
import { updateGlobalConfigSection } from './store/global-config.actions';
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
|
|
@ -37,7 +38,12 @@ import { distinctUntilChangedObject } from '../../util/distinct-until-changed-ob
|
|||
export class GlobalConfigService {
|
||||
private readonly _store = inject<Store<any>>(Store);
|
||||
|
||||
cfg$: Observable<GlobalConfigState>;
|
||||
// Keep observables for backward compatibility
|
||||
cfg$: Observable<GlobalConfigState> = this._store.pipe(
|
||||
select(selectConfigFeatureState),
|
||||
distinctUntilChanged(distinctUntilChangedObject),
|
||||
shareReplay(1),
|
||||
);
|
||||
|
||||
lang$: Observable<LanguageConfig> = this._store.pipe(
|
||||
select(selectLanguageConfig),
|
||||
|
|
@ -81,16 +87,38 @@ export class GlobalConfigService {
|
|||
select(selectTimelineConfig),
|
||||
);
|
||||
|
||||
cfg?: GlobalConfigState;
|
||||
|
||||
constructor() {
|
||||
this.cfg$ = this._store.pipe(
|
||||
select(selectConfigFeatureState),
|
||||
distinctUntilChanged(distinctUntilChangedObject),
|
||||
shareReplay(1),
|
||||
);
|
||||
this.cfg$.subscribe((cfg) => (this.cfg = cfg));
|
||||
}
|
||||
// Signal versions of the properties
|
||||
readonly cfg: Signal<GlobalConfigState | undefined> = toSignal(this.cfg$, {
|
||||
initialValue: undefined,
|
||||
});
|
||||
readonly lang: Signal<LanguageConfig | undefined> = toSignal(this.lang$, {
|
||||
initialValue: undefined,
|
||||
});
|
||||
readonly misc: Signal<MiscConfig | undefined> = toSignal(this.misc$, {
|
||||
initialValue: undefined,
|
||||
});
|
||||
readonly shortSyntax: Signal<ShortSyntaxConfig | undefined> = toSignal(
|
||||
this.shortSyntax$,
|
||||
{ initialValue: undefined },
|
||||
);
|
||||
readonly sound: Signal<SoundConfig | undefined> = toSignal(this.sound$, {
|
||||
initialValue: undefined,
|
||||
});
|
||||
readonly evaluation: Signal<EvaluationConfig | undefined> = toSignal(this.evaluation$, {
|
||||
initialValue: undefined,
|
||||
});
|
||||
readonly idle: Signal<IdleConfig | undefined> = toSignal(this.idle$, {
|
||||
initialValue: undefined,
|
||||
});
|
||||
readonly sync: Signal<SyncConfig | undefined> = toSignal(this.sync$, {
|
||||
initialValue: undefined,
|
||||
});
|
||||
readonly takeABreak: Signal<TakeABreakConfig | undefined> = toSignal(this.takeABreak$, {
|
||||
initialValue: undefined,
|
||||
});
|
||||
readonly timelineCfg: Signal<ScheduleConfig | undefined> = toSignal(this.timelineCfg$, {
|
||||
initialValue: undefined,
|
||||
});
|
||||
|
||||
updateSection(
|
||||
sectionKey: GlobalConfigSectionKey,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
effect,
|
||||
HostBinding,
|
||||
HostListener,
|
||||
inject,
|
||||
|
|
@ -114,9 +115,13 @@ export class FocusModeMainComponent implements OnDestroy {
|
|||
private _dragEnterTarget?: HTMLElement;
|
||||
|
||||
constructor() {
|
||||
this._globalConfigService.misc$
|
||||
.pipe(takeUntil(this._onDestroy$))
|
||||
.subscribe((misc) => (this.defaultTaskNotes = misc.taskNotesTpl));
|
||||
// Use effect to reactively update defaultTaskNotes
|
||||
effect(() => {
|
||||
const misc = this._globalConfigService.misc();
|
||||
if (misc) {
|
||||
this.defaultTaskNotes = misc.taskNotesTpl;
|
||||
}
|
||||
});
|
||||
this.taskService.currentTask$.pipe(takeUntil(this._onDestroy$)).subscribe((task) => {
|
||||
this.task = task;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { inject, Injectable } from '@angular/core';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import { filter, map, take, tap } from 'rxjs/operators';
|
||||
import { filter, map, tap } from 'rxjs/operators';
|
||||
import {
|
||||
addProject,
|
||||
moveAllProjectBacklogTasksToRegularList,
|
||||
|
|
@ -37,8 +37,8 @@ export class ProjectEffects {
|
|||
this._timeTrackingService.cleanupDataEverywhereForProject(id);
|
||||
|
||||
// we also might need to account for this unlikely but very nasty scenario
|
||||
const cfg = await this._globalConfigService.cfg$.pipe(take(1)).toPromise();
|
||||
if (id === cfg.misc.defaultProjectId) {
|
||||
const cfg = this._globalConfigService.cfg();
|
||||
if (cfg && id === cfg.misc.defaultProjectId) {
|
||||
this._globalConfigService.updateSection('misc', { defaultProjectId: null });
|
||||
}
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ChangeDetectionStrategy, Component, inject, OnDestroy } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogActions,
|
||||
|
|
@ -13,7 +13,6 @@ import { DEFAULT_GLOBAL_CONFIG } from '../../config/default-global-config.const'
|
|||
import { ScheduleConfig } from '../../config/global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
import { GlobalConfigService } from '../../config/global-config.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { LS } from '../../../core/persistence/storage-keys.const';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
|
@ -38,36 +37,46 @@ import { MatButton } from '@angular/material/button';
|
|||
MatButton,
|
||||
],
|
||||
})
|
||||
export class DialogTimelineSetupComponent implements OnDestroy {
|
||||
export class DialogTimelineSetupComponent {
|
||||
private _matDialogRef =
|
||||
inject<MatDialogRef<DialogTimelineSetupComponent>>(MatDialogRef);
|
||||
data = inject<{
|
||||
isInfoShownInitially: boolean;
|
||||
}>(MAT_DIALOG_DATA);
|
||||
private _globalConfigService = inject(GlobalConfigService);
|
||||
readonly globalConfigService = inject(GlobalConfigService);
|
||||
|
||||
T: typeof T = T;
|
||||
timelineCfg: ScheduleConfig;
|
||||
formGroup: UntypedFormGroup = new UntypedFormGroup({});
|
||||
formConfig: FormlyFieldConfig[] = SCHEDULE_FORM_CFG.items as FormlyFieldConfig[];
|
||||
private _subs = new Subscription();
|
||||
|
||||
constructor() {
|
||||
this.timelineCfg = DEFAULT_GLOBAL_CONFIG.schedule;
|
||||
this._subs.add(
|
||||
this._globalConfigService.timelineCfg$.subscribe((v) => (this.timelineCfg = v)),
|
||||
// Local copy for form editing
|
||||
private _localTimelineCfg: ScheduleConfig;
|
||||
|
||||
get timelineCfg(): ScheduleConfig {
|
||||
// Return local copy if it exists, otherwise use the signal value or default
|
||||
return (
|
||||
this._localTimelineCfg ??
|
||||
this.globalConfigService.timelineCfg() ??
|
||||
DEFAULT_GLOBAL_CONFIG.schedule
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this._subs.unsubscribe();
|
||||
set timelineCfg(value: ScheduleConfig) {
|
||||
this._localTimelineCfg = value;
|
||||
}
|
||||
|
||||
formGroup: UntypedFormGroup = new UntypedFormGroup({});
|
||||
formConfig: FormlyFieldConfig[] = SCHEDULE_FORM_CFG.items as FormlyFieldConfig[];
|
||||
|
||||
constructor() {
|
||||
// Initialize local copy with current config value
|
||||
this._localTimelineCfg =
|
||||
this.globalConfigService.timelineCfg() ?? DEFAULT_GLOBAL_CONFIG.schedule;
|
||||
}
|
||||
|
||||
saveAndClose(): void {
|
||||
localStorage.setItem(LS.WAS_SCHEDULE_INITIAL_DIALOG_SHOWN, 'true');
|
||||
this._matDialogRef.close();
|
||||
if (this.timelineCfg) {
|
||||
this._globalConfigService.updateSection('schedule', this.timelineCfg);
|
||||
if (this._localTimelineCfg) {
|
||||
this.globalConfigService.updateSection('schedule', this._localTimelineCfg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ export class ShortSyntaxEffects {
|
|||
mergeMap(([{ task, originalAction }, tags, projects, defaultProjectId]) => {
|
||||
const r = shortSyntax(
|
||||
task,
|
||||
this._globalConfigService?.cfg?.shortSyntax ||
|
||||
this._globalConfigService?.cfg()?.shortSyntax ||
|
||||
DEFAULT_GLOBAL_CONFIG.shortSyntax,
|
||||
tags,
|
||||
projects,
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ export class TaskContextMenuInnerComponent implements AfterViewInit {
|
|||
if (IS_TOUCH_PRIMARY || !this.isAdvancedControls()) {
|
||||
return {} as any;
|
||||
}
|
||||
return (this._globalConfigService.cfg?.keyboard as KeyboardConfig) || {};
|
||||
return (this._globalConfigService.cfg()?.keyboard as KeyboardConfig) || {};
|
||||
}
|
||||
|
||||
quickAccessKeydown(ev: KeyboardEvent): void {
|
||||
|
|
|
|||
|
|
@ -220,12 +220,9 @@ export class TaskDetailPanelComponent implements OnInit, AfterViewInit, OnDestro
|
|||
return [];
|
||||
});
|
||||
|
||||
// Misc config signal
|
||||
private _miscCfg = toSignal(this._globalConfigService.misc$);
|
||||
|
||||
// Default task notes computed signal
|
||||
defaultTaskNotes = computed(() => {
|
||||
const misc = this._miscCfg();
|
||||
const misc = this._globalConfigService.misc();
|
||||
return misc?.taskNotesTpl || '';
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1057,7 +1057,7 @@ export class TaskService {
|
|||
? { projectId: workContextId }
|
||||
: {
|
||||
projectId:
|
||||
this._globalConfigService.cfg?.misc.defaultProjectId || INBOX_PROJECT.id,
|
||||
this._globalConfigService.cfg()?.misc.defaultProjectId || INBOX_PROJECT.id,
|
||||
}),
|
||||
|
||||
tagIds:
|
||||
|
|
|
|||
|
|
@ -915,7 +915,7 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
if (IS_TOUCH_PRIMARY) {
|
||||
return {} as any;
|
||||
}
|
||||
return (this._configService.cfg?.keyboard as KeyboardConfig) || {};
|
||||
return (this._configService.cfg()?.keyboard as KeyboardConfig) || {};
|
||||
}
|
||||
|
||||
private _handleKeyboardShortcuts(ev: KeyboardEvent): void {
|
||||
|
|
@ -924,7 +924,7 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
}
|
||||
|
||||
const t = this.task();
|
||||
const cfg = this._configService.cfg;
|
||||
const cfg = this._configService.cfg();
|
||||
if (!cfg) {
|
||||
throw new Error();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,13 +252,13 @@ export class DailySummaryComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
todayStart.setHours(0, 0, 0, 0);
|
||||
this.isIncludeYesterday = Date.now() - todayStart.getTime() <= MAGIC_YESTERDAY_MARGIN;
|
||||
|
||||
const cfg = this.configService.cfg();
|
||||
if (
|
||||
this.configService.cfg?.dailySummaryNote?.txt &&
|
||||
this.configService.cfg?.dailySummaryNote?.lastUpdateDayStr !==
|
||||
this._dateService.todayStr()
|
||||
cfg?.dailySummaryNote?.txt &&
|
||||
cfg?.dailySummaryNote?.lastUpdateDayStr !== this._dateService.todayStr()
|
||||
) {
|
||||
this.dailySummaryNoteTxt.set(
|
||||
unToggleCheckboxesInMarkdownTxt(this.configService.cfg.dailySummaryNote.txt),
|
||||
unToggleCheckboxesInMarkdownTxt(cfg.dailySummaryNote.txt),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -393,7 +393,8 @@ export class DailySummaryComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
}
|
||||
|
||||
private async _finishDayForGood(cb?: any): Promise<void> {
|
||||
const syncCfg = this.configService.cfg?.sync;
|
||||
const cfg = this.configService.cfg();
|
||||
const syncCfg = cfg?.sync;
|
||||
if (syncCfg?.isEnabled) {
|
||||
await this._syncWrapperService.sync();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
@let isTurnOffMarkdownParsing = isTurnOffMarkdownParsing$ | async;
|
||||
|
||||
<div
|
||||
#wrapperEl
|
||||
[class.isHideOverflow]="isHideOverflow"
|
||||
class="markdown-wrapper"
|
||||
>
|
||||
@if (isShowEdit || isTurnOffMarkdownParsing) {
|
||||
@if (isShowEdit || isTurnOffMarkdownParsing()) {
|
||||
<textarea
|
||||
#textareaEl
|
||||
(blur)="untoggleShowEdit(); setBlur($event)"
|
||||
|
|
@ -21,7 +19,7 @@
|
|||
}
|
||||
|
||||
<!-- (focus)="clickOrFocusPreview($event, true)"-->
|
||||
@if (!isTurnOffMarkdownParsing) {
|
||||
@if (!isTurnOffMarkdownParsing()) {
|
||||
<div
|
||||
#previewEl
|
||||
(click)="clickPreview($event)"
|
||||
|
|
@ -38,7 +36,7 @@
|
|||
<div class="controls">
|
||||
<ng-content> </ng-content>
|
||||
|
||||
@if (isShowChecklistToggle() && !isTurnOffMarkdownParsing) {
|
||||
@if (isShowChecklistToggle() && !isTurnOffMarkdownParsing()) {
|
||||
<!-- -->
|
||||
<button
|
||||
[matTooltip]="'Add checklist item'"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import {
|
|||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
computed,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
inject,
|
||||
|
|
@ -15,8 +16,6 @@ import {
|
|||
import { fadeInAnimation } from '../animations/fade.ani';
|
||||
import { MarkdownComponent } from 'ngx-markdown';
|
||||
import { IS_ELECTRON } from '../../app.constants';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, startWith } from 'rxjs/operators';
|
||||
import { GlobalConfigService } from '../../features/config/global-config.service';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { DialogFullscreenMarkdownComponent } from '../dialog-fullscreen-markdown/dialog-fullscreen-markdown.component';
|
||||
|
|
@ -25,7 +24,6 @@ import { FormsModule } from '@angular/forms';
|
|||
import { MatIconButton } from '@angular/material/button';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
|
||||
const HIDE_OVERFLOW_TIMEOUT_DURATION = 300;
|
||||
|
||||
|
|
@ -35,14 +33,7 @@ const HIDE_OVERFLOW_TIMEOUT_DURATION = 300;
|
|||
styleUrls: ['./inline-markdown.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations: [fadeInAnimation],
|
||||
imports: [
|
||||
FormsModule,
|
||||
MarkdownComponent,
|
||||
MatIconButton,
|
||||
MatTooltip,
|
||||
MatIcon,
|
||||
AsyncPipe,
|
||||
],
|
||||
imports: [FormsModule, MarkdownComponent, MatIconButton, MatTooltip, MatIcon],
|
||||
})
|
||||
export class InlineMarkdownComponent implements OnInit, OnDestroy {
|
||||
private _cd = inject(ChangeDetectorRef);
|
||||
|
|
@ -67,10 +58,10 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
|
|||
isShowEdit: boolean = false;
|
||||
modelCopy: string | undefined;
|
||||
|
||||
isTurnOffMarkdownParsing$: Observable<boolean> = this._globalConfigService.misc$.pipe(
|
||||
map((cfg) => cfg.isTurnOffMarkdown),
|
||||
startWith(false),
|
||||
);
|
||||
isTurnOffMarkdownParsing = computed(() => {
|
||||
const misc = this._globalConfigService.misc();
|
||||
return misc?.isTurnOffMarkdown ?? false;
|
||||
});
|
||||
private _hideOverFlowTimeout: number | undefined;
|
||||
|
||||
constructor() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue