@owdproject/core 3.4.0 → 4.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -13
- package/dist/dom/index.d.mts +65 -0
- package/dist/dom/index.d.ts +65 -0
- package/dist/dom/index.mjs +224 -0
- package/dist/events/index.d.mts +70 -0
- package/dist/events/index.d.ts +70 -0
- package/dist/events/index.mjs +3 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.mjs +115 -0
- package/dist/layout/index.d.mts +41 -0
- package/dist/layout/index.d.ts +41 -0
- package/dist/layout/index.mjs +64 -0
- package/dist/machines/index.d.mts +31 -0
- package/dist/machines/index.d.ts +31 -0
- package/dist/machines/index.mjs +2 -0
- package/dist/managers/index.d.mts +118 -0
- package/dist/managers/index.d.ts +118 -0
- package/dist/managers/index.mjs +6 -0
- package/dist/session/index.d.mts +57 -0
- package/dist/session/index.d.ts +57 -0
- package/dist/session/index.mjs +65 -0
- package/dist/shared/core.B1XxB289.mjs +239 -0
- package/dist/shared/core.B3mp7ztE.mjs +237 -0
- package/dist/shared/core.BOvFdEVQ.d.ts +114 -0
- package/dist/shared/core.CsDFgGnX.mjs +40 -0
- package/dist/shared/core.Di1eFcr_.d.mts +114 -0
- package/dist/shared/core.Pd_Ogt4g.mjs +101 -0
- package/dist/shared/core.b3Xldzyu.mjs +29 -0
- package/dist/shared/core.d_A3q1kZ.mjs +869 -0
- package/dist/types/index.d.mts +266 -0
- package/dist/types/index.d.ts +266 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +56 -112
- package/CHANGELOG.md +0 -98
- package/DESKTOP_KERNEL.md +0 -232
- package/MIGRATION_3.3.2.md +0 -23
- package/MIGRATION_3.4.md +0 -126
- package/PLAYGROUND.md +0 -91
- package/dist/module.d.mts +0 -13
- package/dist/module.json +0 -9
- package/dist/module.mjs +0 -254
- package/dist/types.d.mts +0 -7
- package/index.ts +0 -8
- package/kit/authoring.ts +0 -340
- package/kit/defineDesktopApp.ts +0 -56
- package/module.ts +0 -203
- package/runtime/components/Application/DesktopCoreApplicationRender.vue +0 -20
- package/runtime/components/Application/DesktopCoreApplicationWindowsRender.vue +0 -38
- package/runtime/components/background/DesktopCoreBackground.vue +0 -16
- package/runtime/components/core/DesktopCore.vue +0 -43
- package/runtime/components/time/DesktopCoreTime.vue +0 -56
- package/runtime/components/window/DesktopCoreWindow.vue +0 -215
- package/runtime/components/window/DesktopCoreWindowContent.vue +0 -28
- package/runtime/components/window/DesktopCoreWindowNav.vue +0 -66
- package/runtime/components/window/DesktopCoreWindowSnapHintsBase.vue +0 -74
- package/runtime/components/workspace/DesktopCoreWorkspaceEdgeHintsBase.vue +0 -84
- package/runtime/composables/useApplicationEntries.ts +0 -51
- package/runtime/composables/useApplicationManager.ts +0 -285
- package/runtime/composables/useBlockNonInputContextMenu.ts +0 -30
- package/runtime/composables/useDesktopConfig.ts +0 -8
- package/runtime/composables/useDesktopDialogs.ts +0 -16
- package/runtime/composables/useDesktopExtension.ts +0 -8
- package/runtime/composables/useDesktopManager.ts +0 -51
- package/runtime/composables/useDesktopManifest.ts +0 -17
- package/runtime/composables/useDesktopSession.ts +0 -27
- package/runtime/composables/useDesktopShellIdentity.ts +0 -99
- package/runtime/composables/useDesktopShellOptions.ts +0 -36
- package/runtime/composables/useDesktopShellReady.ts +0 -7
- package/runtime/composables/useDesktopWorkArea.ts +0 -93
- package/runtime/composables/useTerminalManager.ts +0 -159
- package/runtime/composables/useToggleWindowMaximize.ts +0 -35
- package/runtime/composables/useWindowDragHandlers.ts +0 -47
- package/runtime/composables/useWindowSnapDrop.ts +0 -112
- package/runtime/composables/useWorkspaceEdgeDrop.ts +0 -176
- package/runtime/composables/useWorkspaceManager.ts +0 -67
- package/runtime/composables/useWorkspaceOverviewCapture.ts +0 -92
- package/runtime/composables/useWorkspaceOverviewLiveScale.ts +0 -151
- package/runtime/constants/desktopShellKeys.ts +0 -12
- package/runtime/constants/shellLayout.ts +0 -5
- package/runtime/dialogs/desktopDialogProvider.ts +0 -73
- package/runtime/internal/controllers/ApplicationController.ts +0 -351
- package/runtime/internal/controllers/WindowController.ts +0 -547
- package/runtime/plugins/01.desktop-shell-init.client.ts +0 -28
- package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +0 -13
- package/runtime/plugins/resize.client.ts +0 -6
- package/runtime/stores/storeApplicationMeta.ts +0 -60
- package/runtime/stores/storeApplicationWindows.ts +0 -21
- package/runtime/stores/storeDesktop.ts +0 -71
- package/runtime/stores/storeDesktopDefaultApps.ts +0 -54
- package/runtime/stores/storeDesktopVolume.ts +0 -19
- package/runtime/stores/storeDesktopWindow.ts +0 -38
- package/runtime/stores/storeDesktopWorkspace.ts +0 -105
- package/runtime/stores/storeIds.ts +0 -35
- package/runtime/types/desktopMenu.ts +0 -10
- package/runtime/utils/initDesktopShell.ts +0 -80
- package/runtime/utils/migratePersistedStoreIds.ts +0 -57
- package/runtime/utils/utilApp.ts +0 -25
- package/runtime/utils/utilCaptureElementToCanvas.ts +0 -21
- package/runtime/utils/utilCommon.ts +0 -26
- package/runtime/utils/utilDebug.ts +0 -30
- package/runtime/utils/utilDetectSnapZone.ts +0 -57
- package/runtime/utils/utilTerminal.ts +0 -6
- package/runtime/utils/utilWindowControllerAdapter.ts +0 -15
- package/runtime/utils/utilWindowLayout.ts +0 -82
- package/runtime/utils/utilWindowMaximizeLayout.ts +0 -44
- package/runtime/utils/utilWorkspaceWindows.ts +0 -33
- package/types/index.d.ts +0 -531
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import type { CSSProperties, Ref } from 'vue'
|
|
2
|
-
import {
|
|
3
|
-
nextTick,
|
|
4
|
-
onScopeDispose,
|
|
5
|
-
readonly,
|
|
6
|
-
shallowRef,
|
|
7
|
-
watch,
|
|
8
|
-
} from 'vue'
|
|
9
|
-
import { useDesktopWorkspaceStore } from '@owdproject/core/runtime/stores/storeDesktopWorkspace'
|
|
10
|
-
|
|
11
|
-
export type WorkspaceStageSize = {
|
|
12
|
-
width: number
|
|
13
|
-
height: number
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export type WorkspaceOverviewLiveScaleOptions = {
|
|
17
|
-
/** Upper bound for scale (default 1). */
|
|
18
|
-
maxScale?: number
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type WorkspaceOverviewInnerStyleOptions =
|
|
22
|
-
WorkspaceOverviewLiveScaleOptions & {
|
|
23
|
-
transformOrigin?: string
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Fit factor to show a 1:1 shell stage inside a panel viewport without clipping.
|
|
28
|
-
*/
|
|
29
|
-
export function computeScaleToFit(
|
|
30
|
-
panelWidth: number,
|
|
31
|
-
panelHeight: number,
|
|
32
|
-
stageWidth: number,
|
|
33
|
-
stageHeight: number,
|
|
34
|
-
options?: WorkspaceOverviewLiveScaleOptions,
|
|
35
|
-
): number {
|
|
36
|
-
if (
|
|
37
|
-
panelWidth <= 0 ||
|
|
38
|
-
panelHeight <= 0 ||
|
|
39
|
-
stageWidth <= 0 ||
|
|
40
|
-
stageHeight <= 0
|
|
41
|
-
) {
|
|
42
|
-
return 1
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const scale = Math.min(panelWidth / stageWidth, panelHeight / stageHeight)
|
|
46
|
-
const maxScale = options?.maxScale ?? 1
|
|
47
|
-
return Math.min(scale, maxScale)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Live DOM workspace overview: measure shell stage, scale desktop roots to fit cards.
|
|
52
|
-
*/
|
|
53
|
-
export function useWorkspaceOverviewLiveScale(
|
|
54
|
-
shellStageRef: Ref<HTMLElement | null | undefined>,
|
|
55
|
-
) {
|
|
56
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
57
|
-
const stageSize = shallowRef<WorkspaceStageSize>({ width: 0, height: 0 })
|
|
58
|
-
|
|
59
|
-
let resizeObserver: ResizeObserver | null = null
|
|
60
|
-
|
|
61
|
-
function readStageSize() {
|
|
62
|
-
const el = shellStageRef.value
|
|
63
|
-
if (!el) {
|
|
64
|
-
stageSize.value = { width: 0, height: 0 }
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
stageSize.value = {
|
|
68
|
-
width: el.clientWidth,
|
|
69
|
-
height: el.clientHeight,
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function stopObserving() {
|
|
74
|
-
resizeObserver?.disconnect()
|
|
75
|
-
resizeObserver = null
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function startObserving() {
|
|
79
|
-
stopObserving()
|
|
80
|
-
const el = shellStageRef.value
|
|
81
|
-
if (!el || typeof ResizeObserver === 'undefined') return
|
|
82
|
-
|
|
83
|
-
readStageSize()
|
|
84
|
-
resizeObserver = new ResizeObserver(() => readStageSize())
|
|
85
|
-
resizeObserver.observe(el)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
watch(
|
|
89
|
-
() => desktopWorkspaceStore.overview,
|
|
90
|
-
(open) => {
|
|
91
|
-
if (open) {
|
|
92
|
-
void nextTick(() => startObserving())
|
|
93
|
-
} else {
|
|
94
|
-
stopObserving()
|
|
95
|
-
stageSize.value = { width: 0, height: 0 }
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
watch(shellStageRef, (el) => {
|
|
101
|
-
if (desktopWorkspaceStore.overview && el) {
|
|
102
|
-
void nextTick(() => startObserving())
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
onScopeDispose(stopObserving)
|
|
107
|
-
|
|
108
|
-
function scaleToFit(
|
|
109
|
-
panelEl: HTMLElement | null | undefined,
|
|
110
|
-
options?: WorkspaceOverviewLiveScaleOptions,
|
|
111
|
-
): number {
|
|
112
|
-
if (!panelEl) return 1
|
|
113
|
-
const { width: stageWidth, height: stageHeight } = stageSize.value
|
|
114
|
-
if (stageWidth <= 0 || stageHeight <= 0) return 1
|
|
115
|
-
|
|
116
|
-
return computeScaleToFit(
|
|
117
|
-
panelEl.clientWidth,
|
|
118
|
-
panelEl.clientHeight,
|
|
119
|
-
stageWidth,
|
|
120
|
-
stageHeight,
|
|
121
|
-
options,
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function innerOverviewStyle(
|
|
126
|
-
panelEl: HTMLElement | null | undefined,
|
|
127
|
-
options?: WorkspaceOverviewInnerStyleOptions,
|
|
128
|
-
): CSSProperties | undefined {
|
|
129
|
-
if (!desktopWorkspaceStore.overview) return undefined
|
|
130
|
-
|
|
131
|
-
const { width: stageWidth, height: stageHeight } = stageSize.value
|
|
132
|
-
if (stageWidth <= 0 || stageHeight <= 0) return undefined
|
|
133
|
-
|
|
134
|
-
const scale = scaleToFit(panelEl, options)
|
|
135
|
-
const transformOrigin = options?.transformOrigin ?? 'top left'
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
width: `${stageWidth}px`,
|
|
139
|
-
height: `${stageHeight}px`,
|
|
140
|
-
transform: `scale(${scale})`,
|
|
141
|
-
transformOrigin,
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
stageSize: readonly(stageSize),
|
|
147
|
-
scaleToFit,
|
|
148
|
-
innerOverviewStyle,
|
|
149
|
-
refreshStageSize: readStageSize,
|
|
150
|
-
}
|
|
151
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { InjectionKey } from 'vue'
|
|
2
|
-
import type { DesktopDialogProvider } from '../dialogs/desktopDialogProvider'
|
|
3
|
-
|
|
4
|
-
export type DesktopToggleWindowMaximizeFn = (
|
|
5
|
-
win: IWindowController | undefined,
|
|
6
|
-
) => boolean
|
|
7
|
-
|
|
8
|
-
export const DESKTOP_DIALOG_PROVIDER_KEY: InjectionKey<DesktopDialogProvider> =
|
|
9
|
-
Symbol('desktop-dialog-provider')
|
|
10
|
-
|
|
11
|
-
export const DESKTOP_TOGGLE_WINDOW_MAXIMIZE_KEY: InjectionKey<DesktopToggleWindowMaximizeFn> =
|
|
12
|
-
Symbol('desktop-toggle-window-maximize')
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/** Options for a yes/no confirmation (theme renders labels and chrome). */
|
|
2
|
-
export interface DesktopConfirmDialogOptions {
|
|
3
|
-
title?: string
|
|
4
|
-
message: string
|
|
5
|
-
danger?: boolean
|
|
6
|
-
acceptLabel?: string
|
|
7
|
-
rejectLabel?: string
|
|
8
|
-
/**
|
|
9
|
-
* Theme-specific payload (e.g. delete dialog passes `toTrash` for slot templates).
|
|
10
|
-
*/
|
|
11
|
-
extras?: Record<string, unknown>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Cross-theme dialog API. Themes implement with PrimeVue, native dialogs, etc.
|
|
16
|
-
* Callers pass user-facing strings (usually from i18n); implementations only render.
|
|
17
|
-
*/
|
|
18
|
-
export interface DesktopDialogProvider {
|
|
19
|
-
confirm(options: DesktopConfirmDialogOptions): Promise<boolean>
|
|
20
|
-
alert(message: string, options?: { title?: string }): Promise<void>
|
|
21
|
-
prompt(message: string, defaultValue?: string): Promise<string | null>
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function browserGlobals(): {
|
|
25
|
-
confirm: (message?: string) => boolean
|
|
26
|
-
alert: (message?: string) => void
|
|
27
|
-
prompt: (message?: string, defaultText?: string) => string | null
|
|
28
|
-
} | null {
|
|
29
|
-
const g = globalThis as typeof globalThis & {
|
|
30
|
-
confirm?: (message?: string) => boolean
|
|
31
|
-
alert?: (message?: string) => void
|
|
32
|
-
prompt?: (message?: string, defaultText?: string) => string | null
|
|
33
|
-
}
|
|
34
|
-
if (typeof g.confirm !== 'function') return null
|
|
35
|
-
return {
|
|
36
|
-
confirm: g.confirm.bind(g),
|
|
37
|
-
alert:
|
|
38
|
-
typeof g.alert === 'function'
|
|
39
|
-
? g.alert.bind(g)
|
|
40
|
-
: (m?: string) => {
|
|
41
|
-
void m
|
|
42
|
-
},
|
|
43
|
-
prompt:
|
|
44
|
-
typeof g.prompt === 'function'
|
|
45
|
-
? g.prompt.bind(g)
|
|
46
|
-
: () => null,
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function createBrowserFallbackDialogProvider(): DesktopDialogProvider {
|
|
51
|
-
return {
|
|
52
|
-
async confirm(opts) {
|
|
53
|
-
if (import.meta.server) return false
|
|
54
|
-
const w = browserGlobals()
|
|
55
|
-
if (!w) return false
|
|
56
|
-
const text = [opts.title, opts.message].filter(Boolean).join('\n\n')
|
|
57
|
-
return w.confirm(text)
|
|
58
|
-
},
|
|
59
|
-
async alert(message, opts) {
|
|
60
|
-
if (import.meta.server) return
|
|
61
|
-
const w = browserGlobals()
|
|
62
|
-
if (!w) return
|
|
63
|
-
w.alert([opts?.title, message].filter(Boolean).join('\n\n'))
|
|
64
|
-
},
|
|
65
|
-
async prompt(message, defaultValue = '') {
|
|
66
|
-
if (import.meta.server) return null
|
|
67
|
-
const w = browserGlobals()
|
|
68
|
-
if (!w) return null
|
|
69
|
-
const v = w.prompt(message, defaultValue)
|
|
70
|
-
return v === null ? null : v
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
import { nanoid } from 'nanoid'
|
|
2
|
-
import { WindowController } from './WindowController'
|
|
3
|
-
import { useApplicationManager } from '../../composables/useApplicationManager'
|
|
4
|
-
import { useApplicationWindowsStore } from '../../stores/storeApplicationWindows'
|
|
5
|
-
import { useApplicationMetaStore } from '../../stores/storeApplicationMeta'
|
|
6
|
-
import { useTerminalManager } from '../../composables/useTerminalManager'
|
|
7
|
-
import { debugLog, debugError } from '../../utils/utilDebug'
|
|
8
|
-
import { useDesktopDefaultAppsStore } from '../../stores/storeDesktopDefaultApps'
|
|
9
|
-
import { useDesktopWorkspaceStore } from '../../stores/storeDesktopWorkspace'
|
|
10
|
-
import { useDesktopWindowStore } from '../../stores/storeDesktopWindow'
|
|
11
|
-
import { shallowRef } from 'vue'
|
|
12
|
-
import { unref } from 'vue'
|
|
13
|
-
|
|
14
|
-
export class ApplicationController implements IApplicationController {
|
|
15
|
-
private readonly applicationManager: IApplicationManager
|
|
16
|
-
private readonly terminalManager: ITerminalManager
|
|
17
|
-
|
|
18
|
-
public readonly id
|
|
19
|
-
public readonly config
|
|
20
|
-
public readonly storeWindows
|
|
21
|
-
|
|
22
|
-
private readonly _windows = shallowRef(new Map<string, IWindowController>())
|
|
23
|
-
|
|
24
|
-
/** Reactive window count for Vue (class getters are not tracked). */
|
|
25
|
-
public readonly openWindowCount = shallowRef(0)
|
|
26
|
-
|
|
27
|
-
get windows(): Map<string, IWindowController> {
|
|
28
|
-
return this._windows.value
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
private replaceWindows(
|
|
32
|
-
mutator: (next: Map<string, IWindowController>) => void,
|
|
33
|
-
) {
|
|
34
|
-
const next = new Map(this._windows.value)
|
|
35
|
-
mutator(next)
|
|
36
|
-
this._windows.value = next
|
|
37
|
-
this.openWindowCount.value = next.size
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
public isRunning = false
|
|
41
|
-
|
|
42
|
-
constructor(id: string, config: ApplicationConfig) {
|
|
43
|
-
this.applicationManager = useApplicationManager()
|
|
44
|
-
this.terminalManager = useTerminalManager()
|
|
45
|
-
|
|
46
|
-
this.id = id
|
|
47
|
-
this.config = config
|
|
48
|
-
this.storeWindows = useApplicationWindowsStore(id)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Lazy meta store — app modules should register state via `useApplicationMetaStore` before `defineDesktopApp`. */
|
|
52
|
-
get storeMeta() {
|
|
53
|
-
return useApplicationMetaStore(this.id)()
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public async initApplication(): Promise<void> {
|
|
57
|
-
const desktopDefaultAppsStore = useDesktopDefaultAppsStore()
|
|
58
|
-
|
|
59
|
-
// provides
|
|
60
|
-
|
|
61
|
-
// set as default app for specific purposes
|
|
62
|
-
// todo improve this and move it in a store
|
|
63
|
-
if (this.config.provides) {
|
|
64
|
-
const existingDefault = desktopDefaultAppsStore.getDefaultApp(
|
|
65
|
-
this.config.provides.name,
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
if (!existingDefault) {
|
|
69
|
-
desktopDefaultAppsStore.setDefaultApp(
|
|
70
|
-
this.config.provides.name,
|
|
71
|
-
this,
|
|
72
|
-
this.config.provides.entry,
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
debugLog(
|
|
76
|
-
`${this.config.title} has been set as predefined app for "${this.config.provides.name}"`,
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// terminal
|
|
82
|
-
|
|
83
|
-
if (this.config.commands) {
|
|
84
|
-
for (const commandKey of Object.keys(this.config.commands)) {
|
|
85
|
-
const meta = this.config.terminal?.[commandKey] ?? {}
|
|
86
|
-
this.terminalManager.addCommand({
|
|
87
|
-
applicationId: this.id,
|
|
88
|
-
name: commandKey,
|
|
89
|
-
...meta,
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// store
|
|
95
|
-
|
|
96
|
-
if (this.storeWindows.$persistedState) {
|
|
97
|
-
await this.storeWindows.$persistedState.isReady()
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (this.storeMeta.$persistedState) {
|
|
101
|
-
await this.storeMeta.$persistedState.isReady()
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// set default meta values
|
|
105
|
-
// this.storeMeta.meta = this.config.meta ?? {}
|
|
106
|
-
|
|
107
|
-
// restore application state
|
|
108
|
-
await this.restoreApplication()
|
|
109
|
-
|
|
110
|
-
// once app is defined, always run "onReady"
|
|
111
|
-
if (typeof this.config.onReady === 'function') {
|
|
112
|
-
// todo transform in hook
|
|
113
|
-
this.config.onReady(this)
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* App always tries to restore previous windows
|
|
119
|
-
* and returns a boolean if it succeeded
|
|
120
|
-
*/
|
|
121
|
-
public async restoreApplication() {
|
|
122
|
-
if (typeof this.config.onRestore === 'function') {
|
|
123
|
-
// todo transform in hook
|
|
124
|
-
await this.config.onRestore(this)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
!this.storeWindows.windows ||
|
|
129
|
-
Object.keys(this.storeWindows.windows).length === 0
|
|
130
|
-
) {
|
|
131
|
-
return false
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
this.restoreWindows()
|
|
135
|
-
|
|
136
|
-
this.setRunning(true)
|
|
137
|
-
|
|
138
|
-
return true
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
private restoreWindows() {
|
|
142
|
-
Object.keys(this.storeWindows.windows).map((windowId) => {
|
|
143
|
-
const windowStore: WindowStoredState | undefined =
|
|
144
|
-
this.storeWindows.windows[windowId]
|
|
145
|
-
|
|
146
|
-
if (windowStore) {
|
|
147
|
-
this.openWindow(windowStore.model, windowStore, {
|
|
148
|
-
isRestoring: true,
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
this.normalizeWindowFocus()
|
|
154
|
-
|
|
155
|
-
debugLog('Windows have been restored', this.windows)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/** Ensure a single focused window after restore or stale persisted state. */
|
|
159
|
-
private normalizeWindowFocus() {
|
|
160
|
-
const allWindows = this.applicationManager?.windowsOpened?.value
|
|
161
|
-
? Array.from(this.applicationManager.windowsOpened.value.values())
|
|
162
|
-
: Array.from(this.windows.values())
|
|
163
|
-
|
|
164
|
-
if (allWindows.length === 0) {
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
let topWindow: IWindowController | undefined
|
|
169
|
-
let topZ = -Infinity
|
|
170
|
-
|
|
171
|
-
for (const window of allWindows) {
|
|
172
|
-
window.setFocus(false)
|
|
173
|
-
const z = window.state.position?.z ?? 0
|
|
174
|
-
if (z >= topZ) {
|
|
175
|
-
topZ = z
|
|
176
|
-
topWindow = window
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
topWindow?.setFocus(true)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
public openWindow(
|
|
184
|
-
model: string,
|
|
185
|
-
windowStoredState: WindowStoredState | undefined,
|
|
186
|
-
meta?: any,
|
|
187
|
-
) {
|
|
188
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
189
|
-
|
|
190
|
-
if (!this.config.windows || !this.config.windows.hasOwnProperty(model)) {
|
|
191
|
-
debugError(`Window model "${model}" not found`)
|
|
192
|
-
return
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (!windowStoredState && this.config.singleton) {
|
|
196
|
-
const existing = this.getFirstWindowByModel(model)
|
|
197
|
-
if (existing) {
|
|
198
|
-
if (meta && typeof meta === 'object') {
|
|
199
|
-
Object.assign(existing.meta, meta)
|
|
200
|
-
}
|
|
201
|
-
if (!meta?.isRestoring) {
|
|
202
|
-
existing.actions.setActive(true)
|
|
203
|
-
existing.actions.bringToFront()
|
|
204
|
-
}
|
|
205
|
-
return existing
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
let windowId: string
|
|
210
|
-
|
|
211
|
-
if (!windowStoredState) {
|
|
212
|
-
windowId = `${model}-${nanoid(6)}`
|
|
213
|
-
|
|
214
|
-
const windowConfig: WindowConfig = this.config.windows[
|
|
215
|
-
model
|
|
216
|
-
] as WindowConfig
|
|
217
|
-
const screenHeight = window.innerHeight
|
|
218
|
-
const configHeight = windowConfig.size?.height
|
|
219
|
-
const layoutHeight =
|
|
220
|
-
typeof configHeight === 'number'
|
|
221
|
-
? configHeight
|
|
222
|
-
: typeof configHeight === 'string' && /^\d+$/.test(configHeight)
|
|
223
|
-
? Number(configHeight)
|
|
224
|
-
: 240
|
|
225
|
-
const centerY = (screenHeight - layoutHeight) / 2
|
|
226
|
-
const positionY =
|
|
227
|
-
windowConfig.position?.y !== undefined
|
|
228
|
-
? window.scrollY + windowConfig.position.y
|
|
229
|
-
: window.scrollY + centerY
|
|
230
|
-
const cascadeStep = 40
|
|
231
|
-
const cascadeOffset = this.getWindowsByModel(model).length * cascadeStep
|
|
232
|
-
const baseX = windowConfig.position?.x ?? 100
|
|
233
|
-
const desktopWindowStore = useDesktopWindowStore()
|
|
234
|
-
const initialZ = desktopWindowStore.incrementPositionZ()
|
|
235
|
-
|
|
236
|
-
const nextWindows = {
|
|
237
|
-
...this.storeWindows.windows,
|
|
238
|
-
[windowId]: {
|
|
239
|
-
model,
|
|
240
|
-
state: {
|
|
241
|
-
id: windowId,
|
|
242
|
-
active: true,
|
|
243
|
-
focused: false,
|
|
244
|
-
position: {
|
|
245
|
-
x: baseX + cascadeOffset,
|
|
246
|
-
y: positionY + cascadeOffset,
|
|
247
|
-
z: initialZ,
|
|
248
|
-
},
|
|
249
|
-
createdAt: +new Date(),
|
|
250
|
-
workspace: desktopWorkspaceStore.resolveActiveWorkspaceId(),
|
|
251
|
-
},
|
|
252
|
-
meta,
|
|
253
|
-
},
|
|
254
|
-
}
|
|
255
|
-
this.storeWindows.windows = nextWindows
|
|
256
|
-
|
|
257
|
-
windowStoredState = this.storeWindows.windows[windowId]
|
|
258
|
-
} else {
|
|
259
|
-
// restore previous id if state is defined
|
|
260
|
-
windowId =
|
|
261
|
-
windowStoredState.state?.id ??
|
|
262
|
-
Object.keys(this.storeWindows.windows).find(
|
|
263
|
-
(key) => this.storeWindows.windows[key] === windowStoredState,
|
|
264
|
-
) ??
|
|
265
|
-
`${model}-restored`
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const windowConfig = this.config.windows[model] as WindowConfig
|
|
269
|
-
|
|
270
|
-
const windowController = new WindowController(
|
|
271
|
-
this,
|
|
272
|
-
model,
|
|
273
|
-
windowConfig,
|
|
274
|
-
windowStoredState!,
|
|
275
|
-
)
|
|
276
|
-
|
|
277
|
-
if (!meta?.isRestoring) {
|
|
278
|
-
windowController.actions.bringToFront()
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
this.replaceWindows((next) => {
|
|
282
|
-
next.set(windowId, windowController)
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
this.setRunning(true)
|
|
286
|
-
|
|
287
|
-
return windowController
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
public closeWindow(windowId: string) {
|
|
291
|
-
if (this.storeWindows.windows[windowId]) {
|
|
292
|
-
const nextWindows = { ...this.storeWindows.windows }
|
|
293
|
-
delete nextWindows[windowId]
|
|
294
|
-
this.storeWindows.windows = nextWindows
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
this.replaceWindows((next) => {
|
|
298
|
-
next.delete(windowId)
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
if (this.openWindowCount.value === 0) {
|
|
302
|
-
this.applicationManager.closeApp(this.id)
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
public closeAllWindows() {
|
|
307
|
-
this.storeWindows.windows = {}
|
|
308
|
-
this._windows.value = new Map()
|
|
309
|
-
this.openWindowCount.value = 0
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
get windowsOpened() {
|
|
313
|
-
return this.windows
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
public getWindowById(id: string): IWindowController[] {
|
|
317
|
-
return this.windows.get(id)
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
public getWindowsByModel(model: string): IWindowController[] {
|
|
321
|
-
return Array.from(this.windows.values()).filter((w) => w.model === model)
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
public getFirstWindowByModel(model: string): IWindowController | undefined {
|
|
325
|
-
return Array.from(this.windows.values()).find((w) => w.model === model)
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
public setRunning(value: boolean): void {
|
|
329
|
-
this.isRunning = value
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// meta
|
|
333
|
-
|
|
334
|
-
get meta() {
|
|
335
|
-
return this.storeMeta.meta
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
getMeta(key: string) {
|
|
339
|
-
return this.meta[key]
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
setMeta(key: string, value: any) {
|
|
343
|
-
this.meta[key] = value
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// commands
|
|
347
|
-
|
|
348
|
-
async execCommand(command: string): Promise<CommandOutput | void> {
|
|
349
|
-
return this.applicationManager.execAppCommand(this.id, command)
|
|
350
|
-
}
|
|
351
|
-
}
|