import { ContextMenuItemSchema, DesktopAppBrandingSchema, DesktopEnvironmentBootstrapSchema, DesktopThemeSchema, PickFolderOptionsSchema,} from "@t3tools/contracts";import * as Effect from "effect/Effect";import * as Option from "effect/Option";import * as Schema from "effect/Schema"; import * as DesktopBackendManager from "../../backend/DesktopBackendManager.ts";import * as DesktopEnvironment from "../../app/DesktopEnvironment.ts";import * as ElectronDialog from "../../electron/ElectronDialog.ts";import * as ElectronMenu from "../../electron/ElectronMenu.ts";import * as ElectronShell from "../../electron/ElectronShell.ts";import * as ElectronTheme from "../../electron/ElectronTheme.ts";import * as ElectronWindow from "../../electron/ElectronWindow.ts";import * as IpcChannels from "../channels.ts";import { makeIpcMethod, makeSyncIpcMethod } from "../DesktopIpc.ts"; const ContextMenuPosition = Schema.Struct({ x: Schema.Number, y: Schema.Number,}); const ContextMenuInput = Schema.Struct({ items: Schema.Array(ContextMenuItemSchema), position: Schema.optionalKey(ContextMenuPosition),}); function toWebSocketBaseUrl(httpBaseUrl: URL): string { const url = new URL(httpBaseUrl.href); url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; return url.href;} export const getAppBranding = makeSyncIpcMethod({ channel: IpcChannels.GET_APP_BRANDING_CHANNEL, result: Schema.NullOr(DesktopAppBrandingSchema), handler: Effect.fn("desktop.ipc.window.getAppBranding")(function* () { const environment = yield* DesktopEnvironment.DesktopEnvironment; return environment.branding; }),}); export const getLocalEnvironmentBootstrap = makeSyncIpcMethod({ channel: IpcChannels.GET_LOCAL_ENVIRONMENT_BOOTSTRAP_CHANNEL, result: Schema.NullOr(DesktopEnvironmentBootstrapSchema), handler: Effect.fn("desktop.ipc.window.getLocalEnvironmentBootstrap")(function* () { const backendManager = yield* DesktopBackendManager.DesktopBackendManager; const config = yield* backendManager.currentConfig; return Option.match(config, { onNone: () => null, onSome: ({ bootstrap, httpBaseUrl }) => ({ label: "Local environment", httpBaseUrl: httpBaseUrl.href, wsBaseUrl: toWebSocketBaseUrl(httpBaseUrl), ...(bootstrap.desktopBootstrapToken ? { bootstrapToken: bootstrap.desktopBootstrapToken } : {}), }), }); }),}); export const pickFolder = makeIpcMethod({ channel: IpcChannels.PICK_FOLDER_CHANNEL, payload: Schema.UndefinedOr(PickFolderOptionsSchema), result: Schema.NullOr(Schema.String), handler: Effect.fn("desktop.ipc.window.pickFolder")(function* (options) { const dialog = yield* ElectronDialog.ElectronDialog; const electronWindow = yield* ElectronWindow.ElectronWindow; const environment = yield* DesktopEnvironment.DesktopEnvironment; const selectedPath = yield* dialog.pickFolder({ owner: yield* electronWindow.focusedMainOrFirst, defaultPath: environment.resolvePickFolderDefaultPath(options), }); return Option.getOrNull(selectedPath); }),}); export const confirm = makeIpcMethod({ channel: IpcChannels.CONFIRM_CHANNEL, payload: Schema.String, result: Schema.Boolean, handler: Effect.fn("desktop.ipc.window.confirm")(function* (message) { const dialog = yield* ElectronDialog.ElectronDialog; const electronWindow = yield* ElectronWindow.ElectronWindow; return yield* electronWindow.focusedMainOrFirst.pipe( Effect.flatMap((owner) => dialog.confirm({ owner, message })), ); }),}); export const setTheme = makeIpcMethod({ channel: IpcChannels.SET_THEME_CHANNEL, payload: DesktopThemeSchema, result: Schema.Void, handler: Effect.fn("desktop.ipc.window.setTheme")(function* (theme) { const electronTheme = yield* ElectronTheme.ElectronTheme; yield* electronTheme.setSource(theme); }),}); export const showContextMenu = makeIpcMethod({ channel: IpcChannels.CONTEXT_MENU_CHANNEL, payload: ContextMenuInput, result: Schema.NullOr(Schema.String), handler: Effect.fn("desktop.ipc.window.showContextMenu")(function* (input) { const electronMenu = yield* ElectronMenu.ElectronMenu; const electronWindow = yield* ElectronWindow.ElectronWindow; const window = yield* electronWindow.focusedMainOrFirst; if (Option.isNone(window)) { return null; } const selectedItemId = yield* electronMenu.showContextMenu({ window: window.value, items: input.items, position: Option.fromNullishOr(input.position), }); return Option.getOrNull(selectedItemId); }),}); export const openExternal = makeIpcMethod({ channel: IpcChannels.OPEN_EXTERNAL_CHANNEL, payload: Schema.String, result: Schema.Boolean, handler: Effect.fn("desktop.ipc.window.openExternal")(function* (url) { const shell = yield* ElectronShell.ElectronShell; return yield* shell.openExternal(url); }),});
import {
ContextMenuItemSchema,
DesktopAppBrandingSchema,
DesktopEnvironmentBootstrapSchema,
DesktopThemeSchema,
PickFolderOptionsSchema,
} from "@t3tools/contracts";
import * as Effect from "effect/Effect";
import * as Option from "effect/Option";
import * as Schema from "effect/Schema";
import * as DesktopBackendManager from "../../backend/DesktopBackendManager.ts";
import * as DesktopEnvironment from "../../app/DesktopEnvironment.ts";
import * as ElectronDialog from "../../electron/ElectronDialog.ts";
import * as ElectronMenu from "../../electron/ElectronMenu.ts";
import * as ElectronShell from "../../electron/ElectronShell.ts";
import * as ElectronTheme from "../../electron/ElectronTheme.ts";
import * as ElectronWindow from "../../electron/ElectronWindow.ts";
import * as IpcChannels from "../channels.ts";
import { makeIpcMethod, makeSyncIpcMethod } from "../DesktopIpc.ts";
const ContextMenuPosition = Schema.Struct({
x: Schema.Number,
y: Schema.Number,
});
const ContextMenuInput = Schema.Struct({
items: Schema.Array(ContextMenuItemSchema),
position: Schema.optionalKey(ContextMenuPosition),
});
function toWebSocketBaseUrl(httpBaseUrl: URL): string {
const url = new URL(httpBaseUrl.href);
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
return url.href;
}
export const getAppBranding = makeSyncIpcMethod({
channel: IpcChannels.GET_APP_BRANDING_CHANNEL,
result: Schema.NullOr(DesktopAppBrandingSchema),
handler: Effect.fn("desktop.ipc.window.getAppBranding")(function* () {
const environment = yield* DesktopEnvironment.DesktopEnvironment;
return environment.branding;
}),
});
export const getLocalEnvironmentBootstrap = makeSyncIpcMethod({
channel: IpcChannels.GET_LOCAL_ENVIRONMENT_BOOTSTRAP_CHANNEL,
result: Schema.NullOr(DesktopEnvironmentBootstrapSchema),
handler: Effect.fn("desktop.ipc.window.getLocalEnvironmentBootstrap")(function* () {
const backendManager = yield* DesktopBackendManager.DesktopBackendManager;
const config = yield* backendManager.currentConfig;
return Option.match(config, {
onNone: () => null,
onSome: ({ bootstrap, httpBaseUrl }) => ({
label: "Local environment",
httpBaseUrl: httpBaseUrl.href,
wsBaseUrl: toWebSocketBaseUrl(httpBaseUrl),
...(bootstrap.desktopBootstrapToken
? { bootstrapToken: bootstrap.desktopBootstrapToken }
: {}),
}),
});
}),
});
export const pickFolder = makeIpcMethod({
channel: IpcChannels.PICK_FOLDER_CHANNEL,
payload: Schema.UndefinedOr(PickFolderOptionsSchema),
result: Schema.NullOr(Schema.String),
handler: Effect.fn("desktop.ipc.window.pickFolder")(function* (options) {
const dialog = yield* ElectronDialog.ElectronDialog;
const electronWindow = yield* ElectronWindow.ElectronWindow;
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const selectedPath = yield* dialog.pickFolder({
owner: yield* electronWindow.focusedMainOrFirst,
defaultPath: environment.resolvePickFolderDefaultPath(options),
});
return Option.getOrNull(selectedPath);
}),
});
export const confirm = makeIpcMethod({
channel: IpcChannels.CONFIRM_CHANNEL,
payload: Schema.String,
result: Schema.Boolean,
handler: Effect.fn("desktop.ipc.window.confirm")(function* (message) {
const dialog = yield* ElectronDialog.ElectronDialog;
const electronWindow = yield* ElectronWindow.ElectronWindow;
return yield* electronWindow.focusedMainOrFirst.pipe(
Effect.flatMap((owner) => dialog.confirm({ owner, message })),
);
}),
});
export const setTheme = makeIpcMethod({
channel: IpcChannels.SET_THEME_CHANNEL,
payload: DesktopThemeSchema,
result: Schema.Void,
handler: Effect.fn("desktop.ipc.window.setTheme")(function* (theme) {
const electronTheme = yield* ElectronTheme.ElectronTheme;
yield* electronTheme.setSource(theme);
}),
});
export const showContextMenu = makeIpcMethod({
channel: IpcChannels.CONTEXT_MENU_CHANNEL,
payload: ContextMenuInput,
result: Schema.NullOr(Schema.String),
handler: Effect.fn("desktop.ipc.window.showContextMenu")(function* (input) {
const electronMenu = yield* ElectronMenu.ElectronMenu;
const electronWindow = yield* ElectronWindow.ElectronWindow;
const window = yield* electronWindow.focusedMainOrFirst;
if (Option.isNone(window)) {
return null;
}
const selectedItemId = yield* electronMenu.showContextMenu({
window: window.value,
items: input.items,
position: Option.fromNullishOr(input.position),
});
return Option.getOrNull(selectedItemId);
}),
});
export const openExternal = makeIpcMethod({
channel: IpcChannels.OPEN_EXTERNAL_CHANNEL,
payload: Schema.String,
result: Schema.Boolean,
handler: Effect.fn("desktop.ipc.window.openExternal")(function* (url) {
const shell = yield* ElectronShell.ElectronShell;
return yield* shell.openExternal(url);
}),
});