diff --git a/.vscode/settings.json b/.vscode/settings.json index 20a1472e..e17079b6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -93,5 +93,5 @@ "package.json": "package-lock.json, yarn.lock, pnpm-lock.yaml, pnpm-workspace.yaml, .pnp.cjs, .pnp.loader.mjs", "tsconfig.json": "tsconfig.*.json", "flake.nix": "shell.nix, flake.lock, Cargo.nix" - } + } } diff --git a/desktop/src/bridge/auth.ts b/desktop/src/bridge/auth.ts deleted file mode 100644 index 78bf43da..00000000 --- a/desktop/src/bridge/auth.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { invoke } from '@tauri-apps/api/core'; -import { listen } from '@tauri-apps/api/event'; - -type MicrosoftLoginCallback = (msg: string, stage: number) => never; -export async function loginMicrosoft(cb?: MicrosoftLoginCallback): Promise { - if (cb) { - const unlisten = await listen<[string, number, boolean]>('msa:status', (event) => { - cb(event.payload[0], event.payload[1]); - - if (event.payload[2]) - unlisten(); - }); - } - - return await invoke('plugin:auth|login_msa'); -} - -export async function getUuidHeadSrc(uuid: string): Promise { - // TODO implement some kind of caching + fallback - return `https://crafatar.com/avatars/${uuid}?size=32`; -} diff --git a/desktop/src/bridge/game.ts b/desktop/src/bridge/game.ts deleted file mode 100644 index e79ad4fb..00000000 --- a/desktop/src/bridge/game.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { invoke } from '@tauri-apps/api/core'; -import { type UnlistenFn, listen } from '@tauri-apps/api/event'; - -const _test_cluster = { - cluster: { - id: 'd09575a6-7c17-4399-a7a3-a117fffa5420', - name: 'Placeholder Name', - createdAt: 1715454720, - cover: null, - group: null, - client: { - type: 'Vanilla', - }, - }, - manifest: { - id: '1.0 cluster', - manifest: { - id: '1.8.9', - javaVersion: { - majorVersion: 8, - }, - }, - }, -} as Core.ClusterWithManifest; - -export async function getCluster(uuid: string): Promise { - return _test_cluster; - - return await invoke( - 'plugin:onelauncher|get_cluster', - { uuid }, - ); -} - -export async function getClusterLogs(uuid: string): Promise { - return ['test log']; - try { - return await invoke( - 'plugin:onelauncher|get_cluster_logs', - { uuid }, - ); - } - catch (e) { - console.error(e); - return []; - } -} - -export async function getClusterLog(uuid: string, log: string): Promise { - return 'test log'; - return await invoke( - 'plugin:onelauncher|get_cluster_log', - { uuid, log }, - ); -} - -export async function getClustersGrouped(): Promise[]>> { - const clusters = await getClusters(); - const map = new Map[]>(); - - clusters.forEach((cluster, index) => { - const groupName = cluster.cluster.group || 'Unnamed'; - const value: WithIndex = { - ...cluster, - index, - }; - - if (map.has(groupName)) - map.get(groupName)!.push(value); - else - map.set(groupName, [value]); - }); - - return map; -} - -export async function getClusters(): Promise { - return [_test_cluster]; - return await invoke('plugin:onelauncher|get_clusters'); -} - -export async function createCluster(cluster: Omit & { version: string }): Promise { - return await invoke( - 'plugin:onelauncher|create_cluster', - { - name: cluster.name, - version: cluster.version, - client: cluster.client, - // cover: cluster.cover, - // group: cluster.group, - }, - ); -} - -export async function refreshClientManager(): Promise { - return await invoke('plugin:onelauncher|refresh_client_manager'); -} - -interface LaunchCallbacks { - on_launch: (pid: number) => any; - on_stdout: (line: string) => any; - on_stderr: (line: string) => any; -}; - -export function launchCluster(uuid: string, callbacks?: LaunchCallbacks): Promise { - return; - // eslint-disable-next-line no-async-promise-executor - return new Promise(async (resolve) => { - let unlisten_stdout: UnlistenFn | undefined; - let unlisten_stderr: UnlistenFn | undefined; - let pid: number = -1; - - function guard(passed_pid: number, fn: () => any | undefined) { - if (passed_pid !== pid) - return; - - if (fn) - fn(); - } - - const unlisten_launch = await listen('game:launch', async (e) => { - pid = e.payload; - - if (callbacks) - callbacks.on_launch(pid); - - unlisten_launch!(); - }); - - const unlisten_exit = await listen<[number, number]>(`game:exit`, e => guard(e.payload[0], () => { - if (callbacks) { - unlisten_stdout!(); - unlisten_stderr!(); - } - - unlisten_exit!(); - resolve(e.payload[1]); - })); - - if (callbacks) { - unlisten_stdout = await listen<[number, string]>(`game:stdout`, e => guard( - e.payload[0], - callbacks.on_stdout(e.payload[1]), - )); - - unlisten_stderr = await listen<[number, string]>(`game:stderr`, e => guard( - e.payload[0], - callbacks.on_stderr(e.payload[1]), - )); - } - - await invoke( - 'plugin:onelauncher|launch_cluster', - { uuid }, - ); - }); -} diff --git a/desktop/src/bridge/notifications.ts b/desktop/src/bridge/notifications.ts deleted file mode 100644 index 7abdb93a..00000000 --- a/desktop/src/bridge/notifications.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { invoke } from '@tauri-apps/api/core'; -import type { UnlistenFn } from '@tauri-apps/api/event'; -import { listen } from '@tauri-apps/api/event'; - -// TODO: Refactor notifications -// - getNotifications should return a list of notifications -// - event "update" + "add" + "remove" should emit the event AS WELL AS emitting -// the ID of the notification / the entire notification data -// so that the frontend can easily find the notification reference and update it without losing reactivity - -export enum NotificationType { - Info = 'Info', - Alert = 'Alert', - Success = 'Success', - Download = 'Download', - DownloadSuccess = 'DownloadSuccess', - DownloadError = 'DownloadError', - Refresh = 'Refresh', -} - -let _notifications: Core.Notification[] = []; - -class _Emitter { - private listeners: ((event: string) => unknown)[] = []; - - public emit(event: Core.NotificationEvents) { - this.listeners.forEach(value => value(event)); - } - - public on(callback: (event: string) => unknown) { - this.listeners.push(callback); - } -} - -const emitter = new _Emitter(); - -export async function updateNotification(id: number, notification: Partial): Promise { - const index = _notifications.findIndex(noti => noti.id === id); - if (index < 0) { - console.log('no index'); - return; - } - - const found = _notifications[index]; - if (!found) { - console.log('not found'); - return; - } - - const newNoti = { - ...found, - ...notification, - }; - - _notifications[index] = newNoti; - emitter.emit('modified'); -} - -export async function addNotification(notification: MakeOptional): Promise { - const id = notification.id || _notifications.length + 1; - _notifications.push({ - id, - created_at: Math.floor(Date.now() / 1000), - ...notification, - }); - emitter.emit('added'); - return id; - - // await invoke('plugin:onelauncher|notifications_add', { - // notification: { - // created_at: Math.floor(Date.now() / 1000), - // ...notification, - // }, - // }); -} - -export async function removeNotificationById(id: number): Promise { - const index = _notifications.findIndex(noti => noti.id === id); - if (index > -1) { - _notifications.splice(index, 1); - emitter.emit('removed'); - } -} - -export async function removeNotificationByIndex(index: number): Promise { - _notifications.splice(index, 1); - emitter.emit('removed'); - // await invoke('plugin:onelauncher|notifications_remove_by_index', { index }); -} - -export async function clearNotifications(): Promise { - _notifications = []; - emitter.emit('cleared'); - // await invoke('plugin:onelauncher|notifications_clear'); -} - -export async function getNotifications(): Promise { - return [..._notifications]; // Destructured to mock the way backend <-> frontend works. (new list gets sent) - // return await invoke('plugin:onelauncher|notifications_get'); -} - -export async function getNotificationById(id: number): Promise { - return _notifications.find(noti => noti.id === id); -} - -export async function on< - T extends Core.NotificationEvents, ->( - event: T, - callback: () => void, -): Promise { - emitter.on((e) => { - if (event === e) - callback(); - }); - return () => {}; - // return await listen(`notifications_event`, (e) => { - // if (e.payload.toLowerCase() === event) - // callback(); - // }); -}; diff --git a/desktop/src/index.tsx b/desktop/src/index.tsx index 352c2d0a..5260da85 100644 --- a/desktop/src/index.tsx +++ b/desktop/src/index.tsx @@ -11,6 +11,8 @@ import UpdatesPage from './ui/pages/Updates'; import ClusterRoot from '~ui/pages/cluster/ClusterRoot'; import SettingsRoot from '~ui/pages/settings/SettingsRoot'; +export * as bridge from "./bindings"; + render(() => ( diff --git a/desktop/src/types/auth.d.ts b/desktop/src/types/auth.d.ts deleted file mode 100644 index f8682764..00000000 --- a/desktop/src/types/auth.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -declare namespace Core { - export interface Account { - username: string; - uuid: string; - skins: AccountSkin[]; - } - - export interface AccountSkin { - id: string; - state: 'active' | 'something'; - url: string; - variant: 'CLASSIC' | 'SLIM'; - } -} diff --git a/desktop/src/types/core.d.ts b/desktop/src/types/core.d.ts deleted file mode 100644 index de52f82e..00000000 --- a/desktop/src/types/core.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -declare namespace Core { - export interface Notification { - id: number; - created_at: number; - title: string; - message: string; - notification_type: NotificationType; - progress?: number; - } - - export type NotificationEvents = 'init' | 'modified' | 'added' | 'removed' | 'cleared'; -} \ No newline at end of file diff --git a/desktop/src/types/game.d.ts b/desktop/src/types/game.d.ts deleted file mode 100644 index 37e039d2..00000000 --- a/desktop/src/types/game.d.ts +++ /dev/null @@ -1,35 +0,0 @@ -declare namespace Core { - export type ClusterWithManifest = { - cluster: Cluster, - manifest: Manifest - } - - export interface Manifest { - id: string, - manifest: MinecraftManifest - } - - export interface MinecraftManifest { - id: string, - javaVersion: { - majorVersion: number; - }, - } - - export interface Cluster { - id: string, - createdAt: number, - name: string, - cover: string | null, - group: string | null, - client: ClientType[T], - } - - export interface ClientType { - Vanilla: VanillaProps, - } - - export interface VanillaProps { - type: "Vanilla", - } -} diff --git a/desktop/src/ui/App.tsx b/desktop/src/ui/App.tsx index 4b47e1d5..32a2d73a 100644 --- a/desktop/src/ui/App.tsx +++ b/desktop/src/ui/App.tsx @@ -1,14 +1,14 @@ import type { ParentProps } from 'solid-js'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid'; -import environment from '../utils/environment'; import WindowFrame from './components/WindowFrame'; import Navbar from './components/Navbar'; import ErrorBoundary from './components/ErrorBoundary'; import AnimatedRoutes from './components/AnimatedRoutes'; import NotificationOverlay from './components/overlay/notifications/NotificationOverlay'; +import { bridge } from '~index'; function App(props: ParentProps) { - if (!environment.isDev()) { + if (!bridge.commands.isDev()) { document.addEventListener('contextmenu', (event) => { event.preventDefault(); }); diff --git a/desktop/src/ui/components/game/PlayerHead.tsx b/desktop/src/ui/components/game/PlayerHead.tsx index a9b3eb75..bdd27e76 100644 --- a/desktop/src/ui/components/game/PlayerHead.tsx +++ b/desktop/src/ui/components/game/PlayerHead.tsx @@ -1,12 +1,11 @@ import { createResource } from 'solid-js'; import type { JSX } from 'solid-js'; -import * as auth from '../../../bridge/auth'; import steveSrc from '../../../assets/images/steve.png'; type PlayerHeadProps = JSX.IntrinsicElements['img'] & { uuid: string }; async function fetchHeadSrc(uuid: string) { - return await auth.getUuidHeadSrc(uuid); + return `https://crafatar.com/avatars/${uuid}?size=32`; } function PlayerHead(props: PlayerHeadProps) { diff --git a/desktop/src/ui/components/overlay/notifications/NotificationComponent.tsx b/desktop/src/ui/components/overlay/notifications/NotificationComponent.tsx index 31c22b37..13bbe224 100644 --- a/desktop/src/ui/components/overlay/notifications/NotificationComponent.tsx +++ b/desktop/src/ui/components/overlay/notifications/NotificationComponent.tsx @@ -1,28 +1,29 @@ import { type JSX, Match, Show, Switch, createEffect, createSignal } from 'solid-js'; import { AlertTriangleIcon, CheckCircleIcon, FolderCheckIcon, FolderDownloadIcon, FolderXIcon, InfoCircleIcon, RefreshCcw02Icon } from '@untitled-theme/icons-solid'; import TimeAgo from '../../TimeAgo'; -import { NotificationType } from '../../../../bridge/notifications'; import { PausableTimer } from '~utils/PausableTimer'; type NotificationComponentProps = Core.Notification & { overlay: boolean; }; +type NotificationType = ''; + function IconFromNotificationType(type: NotificationType): (props: JSX.HTMLAttributes) => JSX.Element { switch (type) { - case NotificationType.Alert: - return AlertTriangleIcon as any; - case NotificationType.Download: - return FolderDownloadIcon as any; - case NotificationType.DownloadSuccess: - return FolderCheckIcon as any; - case NotificationType.DownloadError: - return FolderXIcon as any; - case NotificationType.Refresh: - return RefreshCcw02Icon as any; - case NotificationType.Success: - return CheckCircleIcon as any; - case NotificationType.Info: + // case NotificationType.Alert: + // return AlertTriangleIcon as any; + // case NotificationType.Download: + // return FolderDownloadIcon as any; + // case NotificationType.DownloadSuccess: + // return FolderCheckIcon as any; + // case NotificationType.DownloadError: + // return FolderXIcon as any; + // case NotificationType.Refresh: + // return RefreshCcw02Icon as any; + // case NotificationType.Success: + // return CheckCircleIcon as any; + // case NotificationType.Info: default: return InfoCircleIcon as any; } @@ -30,19 +31,19 @@ function IconFromNotificationType(type: NotificationType): (props: JSX.HTMLAttri function ColorFromNotificationType(type: NotificationType): string { switch (type) { - case NotificationType.Info: - case NotificationType.Refresh: - return 'text-brand'; + // case NotificationType.Info: + // case NotificationType.Refresh: + // return 'text-brand'; - case NotificationType.Alert: - case NotificationType.DownloadError: - return 'text-danger'; + // case NotificationType.Alert: + // case NotificationType.DownloadError: + // return 'text-danger'; - case NotificationType.DownloadSuccess: - case NotificationType.Success: - return 'text-success'; + // case NotificationType.DownloadSuccess: + // case NotificationType.Success: + // return 'text-success'; - case NotificationType.Download: + // case NotificationType.Download: default: return 'text-fg-primary'; } diff --git a/desktop/src/ui/components/overlay/notifications/NotificationPopup.tsx b/desktop/src/ui/components/overlay/notifications/NotificationPopup.tsx index 9fc0f4f5..3a98cce8 100644 --- a/desktop/src/ui/components/overlay/notifications/NotificationPopup.tsx +++ b/desktop/src/ui/components/overlay/notifications/NotificationPopup.tsx @@ -3,7 +3,6 @@ import { Settings01Icon, Trash01Icon } from '@untitled-theme/icons-solid'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid'; import Popup from '../Popup'; import Button from '../../base/Button'; -import * as manager from '../../../../bridge/notifications'; import NotificationComponent from './NotificationComponent'; import useNotifications from '~ui/hooks/useNotifications'; @@ -20,39 +19,19 @@ function NotificationPopup(props: Popup.PopupProps) { } } - onMount(() => { - document.addEventListener('keypress', async (e) => { - if (e.key === 'n') { - const progress = Math.random() > 0.0 ? { progress: 0.39 } : {}; - const id = await manager.addNotification({ - title: 'Test Notification', - message: 'This is a test notification', - notification_type: manager.NotificationType.Download, - ...(progress), - }); - - // if (progress.progress) { - setTimeout(() => { - manager.updateNotification(id, { - progress: 0.5, - }); - }, 3500); - - setTimeout(() => { - manager.updateNotification(id, { - progress: 0.75, - }); - }, 8500); - - setTimeout(() => { - manager.updateNotification(id, { - progress: 1, - }); - }, 13500); - // } - } - }); - }); + // onMount(() => { + // document.addEventListener('keypress', async (e) => { + // if (e.key === 'n') { + // const progress = Math.random() > 0.0 ? { progress: 0.39 } : {}; + // const id = await manager.addNotification({ + // title: 'Test Notification', + // message: 'This is a test notification', + // notification_type: manager.NotificationType.Download, + // ...(progress), + // }); + // } + // }); + // }); return ( @@ -82,7 +61,7 @@ function NotificationPopup(props: Popup.PopupProps) {
- diff --git a/desktop/src/ui/hooks/useCluster.ts b/desktop/src/ui/hooks/useCluster.ts index 9d0276c8..b580d098 100644 --- a/desktop/src/ui/hooks/useCluster.ts +++ b/desktop/src/ui/hooks/useCluster.ts @@ -1,6 +1,9 @@ import type { Resource } from 'solid-js'; import { createResource } from 'solid-js'; -import { getCluster } from '../../bridge/game'; + +function getCluster(uuid: string): Core.ClusterWithManifest { + throw new Error('get cluster'); +} function useCluster(uuid: string | undefined | null): Resource | null { if (typeof uuid !== 'string' || uuid.length === 0) diff --git a/desktop/src/ui/hooks/useNotifications.ts b/desktop/src/ui/hooks/useNotifications.ts index 7d24342e..b066ee54 100644 --- a/desktop/src/ui/hooks/useNotifications.ts +++ b/desktop/src/ui/hooks/useNotifications.ts @@ -1,5 +1,4 @@ import { type Signal, createSignal, onMount } from 'solid-js'; -import * as manager from '~bridge/notifications'; type Notifications = Core.Notification[]; type OnUpdateFn = (event: Core.NotificationEvents) => unknown; @@ -8,7 +7,7 @@ function useNotifications(onUpdate?: OnUpdateFn): Signal { const [notifications, setNotifications] = createSignal([]); async function update(event: Core.NotificationEvents) { - const notis = await manager.getNotifications(); + const notis: Notifications = []; // await manager.getNotifications(); setNotifications(notis); if (onUpdate) @@ -18,10 +17,10 @@ function useNotifications(onUpdate?: OnUpdateFn): Signal { onMount(() => { update('init'); - manager.on('added', () => update('added')); - manager.on('removed', () => update('removed')); - manager.on('cleared', () => update('cleared')); - manager.on('modified', () => update('modified')); + // manager.on('added', () => update('added')); + // manager.on('removed', () => update('removed')); + // manager.on('cleared', () => update('cleared')); + // manager.on('modified', () => update('modified')); }); return [notifications, setNotifications]; diff --git a/desktop/src/ui/pages/Home.tsx b/desktop/src/ui/pages/Home.tsx index f0749883..b8a36f4a 100644 --- a/desktop/src/ui/pages/Home.tsx +++ b/desktop/src/ui/pages/Home.tsx @@ -7,11 +7,10 @@ import { SearchMdIcon, } from '@untitled-theme/icons-solid'; import type { Accessor, Setter } from 'solid-js'; -import { For, Show, createResource, createSignal } from 'solid-js'; +import { For, createSignal } from 'solid-js'; import { useNavigate } from '@solidjs/router'; import image from '../../assets/images/header.png'; import ContextMenu from '../components/overlay/ContextMenu'; -import { createCluster, getClustersGrouped, launchCluster } from '../../bridge/game'; import Button from '../components/base/Button'; import Tag from '../components/base/Tag'; import TextField from '../components/base/TextField'; @@ -75,16 +74,6 @@ function ClusterCardContextMenu(props: ClusterCardContextMenuProps) { navigate(`/clusters/?id=${props.id}`); } - async function launch() { - const exit_code = await launchCluster(props.id, { - on_launch: pid => console.log('Launched with PID:', pid), - on_stdout: line => console.log('STDOUT:', line), - on_stderr: line => console.log('STDERR:', line), - }); - - console.log('Exit with code: ', exit_code); - } - return ( } text="Launch" - onClick={() => launch()} + onClick={() => {}} /> ); @@ -192,20 +181,20 @@ function ClusterGroup(props: ClusterGroupProps) { } function HomePage() { - const [clusters, { refetch }] = createResource(getClustersGrouped); + // const [clusters, { refetch }] = createResource(getClustersGrouped); async function newInstance() { - await createCluster({ - name: '1.0 cluster', - version: 'a1.0.11', - client: { - type: 'Vanilla', - }, - cover: null, - group: null, - }); + // await createCluster({ + // name: '1.0 cluster', + // version: 'a1.0.11', + // client: { + // type: 'Vanilla', + // }, + // cover: null, + // group: null, + // }); - await refetch(); + // await refetch(); } return ( @@ -232,13 +221,13 @@ function HomePage() {
- + {/* {([title, clusters]) => ( )} - + */} ); } diff --git a/desktop/src/ui/pages/cluster/cluster/ClusterLogs.tsx b/desktop/src/ui/pages/cluster/cluster/ClusterLogs.tsx index 63004c7b..543b79b8 100644 --- a/desktop/src/ui/pages/cluster/cluster/ClusterLogs.tsx +++ b/desktop/src/ui/pages/cluster/cluster/ClusterLogs.tsx @@ -1,29 +1,30 @@ import { useSearchParams } from '@solidjs/router'; import { For, Show, createEffect, createResource, createSignal } from 'solid-js'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid'; -import { getClusterLog, getClusterLogs } from '../../../../bridge/game'; function ClusterLogs() { const [params] = useSearchParams(); - const [logs] = createResource(params.id, getClusterLogs); + const [logs] = createResource(params.id, async (uuid: string) => { + return [] as string[]; + }); const [activeLogFile, setActiveLogFile] = createSignal(null); const [log, setLog] = createSignal(null); - createEffect(() => { - const log = logs()?.[0]; + // createEffect(() => { + // const log = logs()?.[0]; - // Set default log to the first file - if (log && activeLogFile() === null) - setActiveLogFile(log); + // // Set default log to the first file + // if (log && activeLogFile() === null) + // setActiveLogFile(log); - // Fetch log content - if (activeLogFile() !== null) { - getClusterLog(params.id!, activeLogFile()!).then((log) => { - setLog(log); - }); - } - }); + // // Fetch log content + // if (activeLogFile() !== null) { + // getClusterLog(params.id!, activeLogFile()!).then((log) => { + // setLog(log); + // }); + // } + // }); return (
diff --git a/desktop/src/ui/pages/cluster/cluster/ClusterOverview.tsx b/desktop/src/ui/pages/cluster/cluster/ClusterOverview.tsx index 73e1055b..e88da4aa 100644 --- a/desktop/src/ui/pages/cluster/cluster/ClusterOverview.tsx +++ b/desktop/src/ui/pages/cluster/cluster/ClusterOverview.tsx @@ -5,7 +5,6 @@ import useCluster from '../../../hooks/useCluster'; import ClusterCover from '../../../components/game/ClusterCover'; import LoaderIcon from '../../../components/game/LoaderIcon'; import Button from '../../../components/base/Button'; -import { launchCluster } from '../../../../bridge/game'; import ScrollableContainer from '~ui/components/ScrollableContainer'; import Sidebar from '~ui/components/Sidebar'; @@ -63,7 +62,7 @@ function Banner({ cluster, manifest }: Core.ClusterWithManifest) { iconLeft={} children="Launch" class="!w-auto" - onClick={() => launchCluster(cluster.id)} + onClick={() => {}} />
diff --git a/eslint.config.js b/eslint.config.js index 943b82c0..59263095 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -22,6 +22,7 @@ export default petal({ '*.rs', 'pnpm-lock.yaml', './src-tauri/prisma/migrations/migration_lock.toml', + './desktop/src/bindings.ts', ], }).append([ {