diff --git a/src-tauri/src/installer/file_ops.rs b/src-tauri/src/installer/file_ops.rs deleted file mode 100644 index be07a7c..0000000 --- a/src-tauri/src/installer/file_ops.rs +++ /dev/null @@ -1,44 +0,0 @@ -// This module contains helper functions for file operations during installation - -use std::fs; -use std::io; -use std::path::Path; - -// Copy a file with backup -#[allow(dead_code)] -pub fn copy_with_backup(src: &Path, dest: &Path) -> io::Result<()> { - // If destination exists, create a backup - if dest.exists() { - let backup = dest.with_extension("bak"); - fs::copy(dest, &backup)?; - } - - fs::copy(src, dest)?; - Ok(()) -} - -// Safely remove a file (doesn't error if it doesn't exist) -#[allow(dead_code)] -pub fn safe_remove(path: &Path) -> io::Result<()> { - if path.exists() { - fs::remove_file(path)?; - } - Ok(()) -} - -// Make a file executable (Unix only) -#[cfg(unix)] -#[allow(dead_code)] -pub fn make_executable(path: &Path) -> io::Result<()> { - use std::os::unix::fs::PermissionsExt; - - let mut perms = fs::metadata(path)?.permissions(); - perms.set_mode(0o755); - fs::set_permissions(path, perms)?; - Ok(()) -} - -#[cfg(not(unix))] -pub fn make_executable(_path: &Path) -> io::Result<()> { - Ok(()) -} \ No newline at end of file diff --git a/src/assets/fonts/WorkSans.ttf b/src/assets/fonts/WorkSans.ttf deleted file mode 100644 index 9a82798..0000000 Binary files a/src/assets/fonts/WorkSans.ttf and /dev/null differ diff --git a/src/components/dialogs/EpicUnlockerSelectionDialog.tsx b/src/components/dialogs/EpicUnlockerSelectionDialog.tsx deleted file mode 100644 index ab7efad..0000000 --- a/src/components/dialogs/EpicUnlockerSelectionDialog.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React from 'react' -import { - Dialog, - DialogHeader, - DialogBody, - DialogFooter, - DialogActions, -} from '@/components/dialogs' -import { Button } from '@/components/buttons' -import { Icon, info } from '@/components/icons' -import { EpicGame } from '@/types/EpicGame' - -export interface EpicUnlockerSelectionDialogProps { - visible: boolean - game: EpicGame | null - onClose: () => void - onSelectScreamAPI: () => void - onSelectKoaloader: () => void -} - -/** - * Unlocker selection dialog for Epic games. - * Recommended: ScreamAPI (direct EOSSDK replacement). - * Alternative: Koaloader + ScreamAPI (proxy DLL injection). - */ -const EpicUnlockerSelectionDialog: React.FC = ({ - visible, - game, - onClose, - onSelectScreamAPI, - onSelectKoaloader, -}) => { - return ( - - -
-

Choose Unlocker

-
-
- - -
-

- Select which unlocker to install for {game?.title}: -

- -
-
-
-

ScreamAPI

- Recommended -
-

- Replaces the EOS SDK DLL directly with ScreamAPI. Works for most Epic games and - requires no additional files. DLC unlocking is automatic. -

- -
- -
-
-

Koaloader + ScreamAPI

- Alternative -
-

- Uses a proxy DLL to inject ScreamAPI without modifying the EOS SDK. Try this if the - recommended method doesn't work for your game. -

- -
-
- -
- - - You can always uninstall and try the other option if one doesn't work properly. - -
-
-
- - - - - - -
- ) -} - -export default EpicUnlockerSelectionDialog \ No newline at end of file diff --git a/src/components/dialogs/ReminderDialog.tsx b/src/components/dialogs/ReminderDialog.tsx deleted file mode 100644 index 728dc79..0000000 --- a/src/components/dialogs/ReminderDialog.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react' -import { - Dialog, - DialogHeader, - DialogBody, - DialogFooter, - DialogActions, -} from '@/components/dialogs' -import { Button } from '@/components/buttons' -import { Icon, info } from '@/components/icons' - -export interface ReminderDialogProps { - visible: boolean - onClose: () => void -} - -/** - * Reminder Dialog component - * Reminds users to remove Steam launch options after removing CreamLinux - */ -const ReminderDialog: React.FC = ({ visible, onClose }) => { - return ( - - -
- -

Reminder

-
-
- - -
-

- If you added a Steam launch option for CreamLinux, remember to remove it in Steam: -

-
    -
  1. Right-click the game in Steam
  2. -
  3. Select "Properties"
  4. -
  5. Go to "Launch Options"
  6. -
  7. Remove the CreamLinux command
  8. -
-
-
- - - - - - -
- ) -} - -export default ReminderDialog \ No newline at end of file diff --git a/src/components/dialogs/ScreamAPISettingsDialog.tsx b/src/components/dialogs/ScreamAPISettingsDialog.tsx deleted file mode 100644 index 8a984ef..0000000 --- a/src/components/dialogs/ScreamAPISettingsDialog.tsx +++ /dev/null @@ -1,209 +0,0 @@ -import { useState, useEffect, useCallback } from 'react' -import { invoke } from '@tauri-apps/api/core' -import { - Dialog, - DialogHeader, - DialogBody, - DialogFooter, - DialogActions, -} from '@/components/dialogs' -import { Button, AnimatedCheckbox } from '@/components/buttons' -import { Dropdown, DropdownOption } from '@/components/common' - -interface ScreamAPIConfig { - $schema: string - $version: number - logging: boolean - log_eos: boolean - block_metrics: boolean - namespace_id: string - default_dlc_status: 'unlocked' | 'locked' | 'original' - override_dlc_status: Record - extra_graphql_endpoints: string[] - extra_entitlements: Record -} - -interface ScreamAPISettingsDialogProps { - visible: boolean - onClose: () => void - gamePath: string - gameTitle: string -} - -const DEFAULT_CONFIG: ScreamAPIConfig = { - $schema: - 'https://raw.githubusercontent.com/acidicoala/ScreamAPI/master/res/ScreamAPI.schema.json', - $version: 3, - logging: false, - log_eos: false, - block_metrics: false, - namespace_id: '', - default_dlc_status: 'unlocked', - override_dlc_status: {}, - extra_graphql_endpoints: [], - extra_entitlements: {}, -} - -const DLC_STATUS_OPTIONS: DropdownOption<'unlocked' | 'locked' | 'original'>[] = [ - { value: 'unlocked', label: 'Unlocked' }, - { value: 'locked', label: 'Locked' }, - { value: 'original', label: 'Original' }, -] - -const ScreamAPISettingsDialog = ({ - visible, - onClose, - gamePath, - gameTitle, -}: ScreamAPISettingsDialogProps) => { - const [enabled, setEnabled] = useState(false) - const [config, setConfig] = useState(DEFAULT_CONFIG) - const [isLoading, setIsLoading] = useState(false) - const [hasChanges, setHasChanges] = useState(false) - - const loadConfig = useCallback(async () => { - setIsLoading(true) - try { - const existingConfig = await invoke('read_screamapi_config', { - gamePath, - }) - if (existingConfig) { - setConfig(existingConfig) - setEnabled(true) - } else { - setConfig(DEFAULT_CONFIG) - setEnabled(false) - } - setHasChanges(false) - } catch (error) { - console.error('Failed to load ScreamAPI config:', error) - setConfig(DEFAULT_CONFIG) - setEnabled(false) - } finally { - setIsLoading(false) - } - }, [gamePath]) - - useEffect(() => { - if (visible && gamePath) { - loadConfig() - } - }, [visible, gamePath, loadConfig]) - - const handleSave = async () => { - setIsLoading(true) - try { - if (enabled) { - await invoke('write_screamapi_config', { gamePath, config }) - } else { - await invoke('delete_screamapi_config', { gamePath }) - } - setHasChanges(false) - onClose() - } catch (error) { - console.error('Failed to save ScreamAPI config:', error) - } finally { - setIsLoading(false) - } - } - - const handleCancel = () => { - setHasChanges(false) - onClose() - } - - const updateConfig = (key: K, value: ScreamAPIConfig[K]) => { - setConfig((prev) => ({ ...prev, [key]: value })) - setHasChanges(true) - } - - return ( - - -
-

ScreamAPI Settings

-
-

{gameTitle}

-
- - -
-
- { - setEnabled(!enabled) - setHasChanges(true) - }} - label="Enable ScreamAPI Configuration" - sublabel="Enable this to customise ScreamAPI settings for this game" - /> -
- -
-
-

General Settings

- - updateConfig('default_dlc_status', value)} - disabled={!enabled} - /> -
- -
-

Logging

- -
- updateConfig('logging', !config.logging)} - label="Enable Logging" - sublabel="Enables logging to ScreamAPI.log.log file" - /> -
- -
- updateConfig('log_eos', !config.log_eos)} - label="Log EOS SDK" - sublabel="Intercept and log EOS SDK calls (requires logging enabled)" - /> -
-
- -
-

Privacy

- -
- updateConfig('block_metrics', !config.block_metrics)} - label="Block Metrics" - sublabel="Block game analytics/usage reporting to Epic Online Services" - /> -
-
-
-
-
- - - - - - - -
- ) -} - -export default ScreamAPISettingsDialog \ No newline at end of file diff --git a/src/components/dialogs/SettingsDialog.tsx b/src/components/dialogs/SettingsDialog.tsx deleted file mode 100644 index 6bf7fe0..0000000 --- a/src/components/dialogs/SettingsDialog.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import React, { useEffect, useState } from 'react' -import { getVersion } from '@tauri-apps/api/app' -import { - Dialog, - DialogHeader, - DialogBody, - DialogFooter, - DialogActions, -} from '@/components/dialogs' -import { Button } from '@/components/buttons' -import { Icon, settings } from '@/components/icons' - -interface SettingsDialogProps { - visible: boolean - onClose: () => void -} - -/** - * Settings Dialog component - * Contains application settings and configuration options - */ -const SettingsDialog: React.FC = ({ visible, onClose }) => { - const [appVersion, setAppVersion] = useState('Loading...') - - useEffect(() => { - // Fetch app version when component mounts - const fetchVersion = async () => { - try { - const version = await getVersion() - setAppVersion(version) - } catch (error) { - console.error('Failed to fetch app version:', error) - setAppVersion('Unknown') - } - } - - fetchVersion() - }, []) - - return ( - - -
- {/**/} -

Settings

-
-
- - -
-
-

General Settings

-

- Configure your CreamLinux preferences and application behavior. -

- -
-
-
-
Settings Coming Soon
-

- Working on adding customizable settings to improve your experience. - Future options may include: -

-
    -
  • Custom Steam library paths
  • -
  • Automatic update settings
  • -
  • Scan frequency options
  • -
  • DLC catalog
  • -
-
-
-
- -
-

About CreamLinux

-
-
- Version: - {appVersion} -
-
- Build: - Beta -
-
- Repository: - - GitHub - -
-
-
-
-
- - - - - - -
- ) -} - -export default SettingsDialog \ No newline at end of file diff --git a/src/components/dialogs/SmokeAPISettingsDialog.tsx b/src/components/dialogs/SmokeAPISettingsDialog.tsx deleted file mode 100644 index 92f3c76..0000000 --- a/src/components/dialogs/SmokeAPISettingsDialog.tsx +++ /dev/null @@ -1,228 +0,0 @@ -import { useState, useEffect, useCallback } from 'react' -import { invoke } from '@tauri-apps/api/core' -import { - Dialog, - DialogHeader, - DialogBody, - DialogFooter, - DialogActions, -} from '@/components/dialogs' -import { Button, AnimatedCheckbox } from '@/components/buttons' -import { Dropdown, DropdownOption } from '@/components/common' -//import { Icon, settings } from '@/components/icons' - -interface SmokeAPIConfig { - $schema: string - $version: number - logging: boolean - log_steam_http: boolean - default_app_status: 'unlocked' | 'locked' | 'original' - override_app_status: Record - override_dlc_status: Record - auto_inject_inventory: boolean - extra_inventory_items: number[] - extra_dlcs: Record -} - -interface SmokeAPISettingsDialogProps { - visible: boolean - onClose: () => void - gamePath: string - gameTitle: string -} - -const DEFAULT_CONFIG: SmokeAPIConfig = { - $schema: - 'https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v4.0.0/res/SmokeAPI.schema.json', - $version: 4, - logging: false, - log_steam_http: false, - default_app_status: 'unlocked', - override_app_status: {}, - override_dlc_status: {}, - auto_inject_inventory: true, - extra_inventory_items: [], - extra_dlcs: {}, -} - -const APP_STATUS_OPTIONS: DropdownOption<'unlocked' | 'locked' | 'original'>[] = [ - { value: 'unlocked', label: 'Unlocked' }, - { value: 'locked', label: 'Locked' }, - { value: 'original', label: 'Original' }, -] - -/** - * SmokeAPI Settings Dialog - * Allows configuration of SmokeAPI for a specific game - */ -const SmokeAPISettingsDialog = ({ - visible, - onClose, - gamePath, - gameTitle, -}: SmokeAPISettingsDialogProps) => { - const [enabled, setEnabled] = useState(false) - const [config, setConfig] = useState(DEFAULT_CONFIG) - const [isLoading, setIsLoading] = useState(false) - const [hasChanges, setHasChanges] = useState(false) - - // Load existing config when dialog opens - const loadConfig = useCallback(async () => { - setIsLoading(true) - try { - const existingConfig = await invoke('read_smokeapi_config', { - gamePath, - }) - - if (existingConfig) { - setConfig(existingConfig) - setEnabled(true) - } else { - setConfig(DEFAULT_CONFIG) - setEnabled(false) - } - setHasChanges(false) - } catch (error) { - console.error('Failed to load SmokeAPI config:', error) - setConfig(DEFAULT_CONFIG) - setEnabled(false) - } finally { - setIsLoading(false) - } - }, [gamePath]) - - useEffect(() => { - if (visible && gamePath) { - loadConfig() - } - }, [visible, gamePath, loadConfig]) - - const handleSave = async () => { - setIsLoading(true) - try { - if (enabled) { - // Save the config - await invoke('write_smokeapi_config', { - gamePath, - config, - }) - } else { - // Delete the config - await invoke('delete_smokeapi_config', { - gamePath, - }) - } - setHasChanges(false) - onClose() - } catch (error) { - console.error('Failed to save SmokeAPI config:', error) - } finally { - setIsLoading(false) - } - } - - const handleCancel = () => { - setHasChanges(false) - onClose() - } - - const updateConfig = (key: K, value: SmokeAPIConfig[K]) => { - setConfig((prev) => ({ ...prev, [key]: value })) - setHasChanges(true) - } - - return ( - - -
- {/**/} -

SmokeAPI Settings

-
-

{gameTitle}

-
- - -
- {/* Enable/Disable Section */} -
- { - setEnabled(!enabled) - setHasChanges(true) - }} - label="Enable SmokeAPI Configuration" - sublabel="Enable this to customize SmokeAPI settings for this game" - /> -
- - {/* Settings Options */} -
-
-

General Settings

- - updateConfig('default_app_status', value)} - disabled={!enabled} - /> -
- -
-

Logging

- -
- updateConfig('logging', !config.logging)} - label="Enable Logging" - sublabel="Enables logging to SmokeAPI.log.log file" - /> -
- -
- updateConfig('log_steam_http', !config.log_steam_http)} - label="Log Steam HTTP" - sublabel="Toggles logging of SteamHTTP traffic" - /> -
-
- -
-

Inventory

- -
- - updateConfig('auto_inject_inventory', !config.auto_inject_inventory) - } - label="Auto Inject Inventory" - sublabel="Automatically inject a list of all registered inventory items when the game queries user inventory" - /> -
-
-
-
-
- - - - - - - -
- ) -} - -export default SmokeAPISettingsDialog \ No newline at end of file diff --git a/src/components/dialogs/UnlockerSelectionDialog.tsx b/src/components/dialogs/UnlockerSelectionDialog.tsx deleted file mode 100644 index 802786c..0000000 --- a/src/components/dialogs/UnlockerSelectionDialog.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import React, { useEffect, useState } from 'react' -import { invoke } from '@tauri-apps/api/core' -import { - Dialog, - DialogHeader, - DialogBody, - DialogFooter, - DialogActions, -} from '@/components/dialogs' -import { Button } from '@/components/buttons' -import { Icon, info } from '@/components/icons' -import VotesDisplay, { GameVotes } from '@/components/common/VotesDisplay' - -export interface UnlockerSelectionDialogProps { - visible: boolean - gameId: string | null - gameTitle: string | null - onClose: () => void - onSelectCreamLinux: () => void - onSelectSmokeAPI: () => void -} - -/** - * Unlocker Selection Dialog component - * Allows users to choose between CreamLinux and SmokeAPI for native Linux games. - * Fetches and displays community vote data per unlocker. - */ -const UnlockerSelectionDialog: React.FC = ({ - visible, - gameId, - gameTitle, - onClose, - onSelectCreamLinux, - onSelectSmokeAPI, -}) => { - const [creamVotes, setCreamVotes] = useState(null) - const [smokeVotes, setSmokeVotes] = useState(null) - - useEffect(() => { - if (!visible || !gameId) { - setCreamVotes(null) - setSmokeVotes(null) - return - } - - invoke('get_game_votes', { gameId }) - .then((results) => { - setCreamVotes(results.find((v) => v.unlocker === 'creamlinux') ?? null) - setSmokeVotes(results.find((v) => v.unlocker === 'smokeapi') ?? null) - }) - .catch(() => { - // Votes are non-critical — silently fall back to "No votes yet" - setCreamVotes(null) - setSmokeVotes(null) - }) - }, [visible, gameId]) - - return ( - - -
-

Choose Unlocker

-
-
- - -
-

- Select which unlocker to install for {gameTitle}: -

- -
-
-
-

CreamLinux

- Recommended -
-

- Native Linux DLC unlocker. Works best with most native Linux games and provides - better compatibility. -

- - -
- -
-
-

SmokeAPI

- Alternative -
-

- Cross-platform DLC unlocker. Try this if CreamLinux doesn't work for your game. - Automatically fetches DLC information. -

- - -
-
- -
- - - You can always uninstall and try the other option if one doesn't work properly. - -
-
-
- - - - - - -
- ) -} - -export default UnlockerSelectionDialog \ No newline at end of file diff --git a/src/components/layout/AnimatedBackground.tsx b/src/components/layout/AnimatedBackground.tsx deleted file mode 100644 index e4203f0..0000000 --- a/src/components/layout/AnimatedBackground.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { useEffect, useRef } from 'react' - -/** - * Animated background component that draws an interactive particle effect - */ -const AnimatedBackground = () => { - const canvasRef = useRef(null) - - useEffect(() => { - const canvas = canvasRef.current - if (!canvas) return - - const ctx = canvas.getContext('2d') - if (!ctx) return - - // Set canvas size to match window - const setCanvasSize = () => { - canvas.width = window.innerWidth - canvas.height = window.innerHeight - } - - setCanvasSize() - window.addEventListener('resize', setCanvasSize) - - // Create particles - const particles: Particle[] = [] - const particleCount = 30 - - interface Particle { - x: number - y: number - size: number - speedX: number - speedY: number - opacity: number - color: string - } - - // Color palette matching theme - const colors = [ - 'rgba(74, 118, 196, 0.5)', // primary blue - 'rgba(155, 125, 255, 0.5)', // purple - 'rgba(251, 177, 60, 0.5)', // gold - ] - - // Create initial particles - for (let i = 0; i < particleCount; i++) { - particles.push({ - x: Math.random() * canvas.width, - y: Math.random() * canvas.height, - size: Math.random() * 3 + 1, - speedX: Math.random() * 0.2 - 0.1, - speedY: Math.random() * 0.2 - 0.1, - opacity: Math.random() * 0.07 + 0.03, - color: colors[Math.floor(Math.random() * colors.length)], - }) - } - - // Animation loop - const animate = () => { - // Clear canvas with transparent black to create fade effect - ctx.fillStyle = 'rgba(15, 15, 15, 0.1)' - ctx.fillRect(0, 0, canvas.width, canvas.height) - - // Update and draw particles - particles.forEach((particle) => { - // Update position - particle.x += particle.speedX - particle.y += particle.speedY - - // Wrap around edges - if (particle.x < 0) particle.x = canvas.width - if (particle.x > canvas.width) particle.x = 0 - if (particle.y < 0) particle.y = canvas.height - if (particle.y > canvas.height) particle.y = 0 - - // Draw particle - ctx.beginPath() - ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2) - ctx.fillStyle = particle.color.replace('0.5', `${particle.opacity}`) - ctx.fill() - - // Connect particles that are close to each other - particles.forEach((otherParticle) => { - const dx = particle.x - otherParticle.x - const dy = particle.y - otherParticle.y - const distance = Math.sqrt(dx * dx + dy * dy) - - if (distance < 100) { - ctx.beginPath() - ctx.strokeStyle = particle.color.replace('0.5', `${particle.opacity * 0.5}`) - ctx.lineWidth = 0.2 - ctx.moveTo(particle.x, particle.y) - ctx.lineTo(otherParticle.x, otherParticle.y) - ctx.stroke() - } - }) - }) - - requestAnimationFrame(animate) - } - - // Start animation - animate() - - // Cleanup - return () => { - window.removeEventListener('resize', setCanvasSize) - } - }, []) - - return