windows/stores/apps.ts

230 lines
5.9 KiB
TypeScript
Raw Permalink Normal View History

2025-09-25 05:38:59 +00:00
import { ref, computed } from 'vue';
import { defineStore } from 'pinia';
export interface AppInfo {
id: string;
name: string;
icon: string;
component: string;
description: string;
category: string;
}
export interface AppInstance {
id: string;
appId: string;
title: string;
x: number;
y: number;
width: number;
height: number;
zIndex: number;
isMinimized: boolean;
isMaximized: boolean;
isFocused: boolean;
2025-09-25 06:38:14 +00:00
maxWidth?: number;
maxHeight?: number;
minWidth?: number;
minHeight?: number;
2025-09-25 05:38:59 +00:00
}
let appInstanceIdCounter = 0;
export const useAppsStore = defineStore('apps', () => {
// Available apps registry
const availableApps = ref<AppInfo[]>([
{
2025-09-25 09:21:54 +00:00
id: 'livestream-hub',
name: 'livestream-hub', // Use translation key instead of hardcoded name
2025-09-25 17:20:06 +00:00
icon: '📰',
component: 'NewsHub',
2025-09-25 09:21:54 +00:00
description: 'Discover and watch live streams from popular streamers',
category: 'Entertainment'
2025-09-25 05:38:59 +00:00
},
// More apps can be added here in the future
]);
// Running app instances
const appInstances = ref<AppInstance[]>([]);
const nextZIndex = ref(100);
// Getters
const getAppById = computed(() => {
return (id: string) => availableApps.value.find(app => app.id === id);
});
const getAppInstanceById = computed(() => {
return (id: string) => appInstances.value.find(instance => instance.id === id);
});
const orderedAppInstances = computed(() => {
return [...appInstances.value].sort((a, b) => a.zIndex - b.zIndex);
});
const focusedAppInstance = computed(() => {
return appInstances.value.find(instance => instance.isFocused);
});
2025-09-25 06:38:14 +00:00
// Get default size and constraints for specific app
function getAppSizeConstraints(appId: string) {
const appConstraints: Record<string, {
width: number;
height: number;
maxWidth?: number;
maxHeight?: number;
minWidth?: number;
minHeight?: number;
}> = {
2025-09-25 09:21:54 +00:00
'livestream-hub': {
width: 800,
height: 600,
maxWidth: 1200, // Allow wider view for better content display
maxHeight: 800, // Allow taller view for more streamers
minWidth: 600, // Minimum usable width
minHeight: 500 // Minimum usable height
2025-09-25 06:38:14 +00:00
},
'text-editor': {
width: 600,
height: 400,
maxWidth: 1200,
maxHeight: 800,
minWidth: 400,
minHeight: 300
},
'file-manager': {
width: 800,
height: 500,
maxWidth: 1400,
maxHeight: 900,
minWidth: 600,
minHeight: 400
},
'web-browser': {
width: 1000,
height: 600,
maxWidth: 1600,
maxHeight: 1000,
minWidth: 800,
minHeight: 500
},
};
return appConstraints[appId] || {
width: 400,
height: 300,
maxWidth: 800,
maxHeight: 600,
minWidth: 300,
minHeight: 200
};
}
2025-09-25 05:38:59 +00:00
// Actions
function launchApp(appId: string) {
const app = getAppById.value(appId);
if (!app) {
console.error(`App with id "${appId}" not found`);
return null;
}
2025-09-25 06:38:14 +00:00
const constraints = getAppSizeConstraints(appId);
2025-09-25 05:38:59 +00:00
const newInstanceId = appInstanceIdCounter++;
const newInstance: AppInstance = {
id: `app-${appId}-${newInstanceId}`,
appId: appId,
title: `${app.name} #${newInstanceId + 1}`,
x: Math.random() * 200 + 50,
y: Math.random() * 100 + 50 + 48, // Below taskbar
2025-09-25 06:38:14 +00:00
width: constraints.width,
height: constraints.height,
2025-09-25 05:38:59 +00:00
zIndex: nextZIndex.value++,
isMinimized: false,
isMaximized: false,
isFocused: true,
2025-09-25 06:38:14 +00:00
maxWidth: constraints.maxWidth,
maxHeight: constraints.maxHeight,
minWidth: constraints.minWidth,
minHeight: constraints.minHeight,
2025-09-25 05:38:59 +00:00
};
// Unfocus all other instances
appInstances.value.forEach(instance => instance.isFocused = false);
appInstances.value.push(newInstance);
return newInstance;
}
function focusAppInstance(instanceId: string) {
const instance = appInstances.value.find(i => i.id === instanceId);
if (!instance || instance.isFocused) return;
// Unfocus all other instances
appInstances.value.forEach(i => i.isFocused = false);
instance.zIndex = nextZIndex.value++;
instance.isFocused = true;
if (instance.isMinimized) {
instance.isMinimized = false;
}
}
function closeAppInstance(instanceId: string) {
appInstances.value = appInstances.value.filter(i => i.id !== instanceId);
}
function minimizeAppInstance(instanceId: string) {
const instance = appInstances.value.find(i => i.id === instanceId);
if (instance) {
instance.isMinimized = true;
instance.isFocused = false;
}
}
function toggleMaximizeAppInstance(instanceId: string) {
const instance = appInstances.value.find(i => i.id === instanceId);
if (instance) {
instance.isMaximized = !instance.isMaximized;
focusAppInstance(instanceId);
}
}
function updateAppInstancePosition({ id, x, y }: { id: string; x: number; y: number }) {
const instance = appInstances.value.find(i => i.id === id);
if (instance && !instance.isMaximized) {
instance.x = x;
instance.y = y;
}
}
function updateAppInstanceSize({ id, width, height }: { id: string; width: number; height: number }) {
const instance = appInstances.value.find(i => i.id === id);
if (instance && !instance.isMaximized) {
instance.width = width;
instance.height = height;
}
}
function closeAllAppInstances() {
appInstances.value = [];
}
return {
availableApps,
appInstances,
nextZIndex,
getAppById,
getAppInstanceById,
orderedAppInstances,
focusedAppInstance,
launchApp,
focusAppInstance,
closeAppInstance,
minimizeAppInstance,
toggleMaximizeAppInstance,
updateAppInstancePosition,
updateAppInstanceSize,
closeAllAppInstances,
};
});