import React, { useEffect, useState, useRef } from 'react';
import { createPortal } from 'react-dom';
import { open } from '@tauri-apps/plugin-shell';
import { listen } from '@tauri-apps/api/event';
import { dirname } from '@tauri-apps/api/path';
import { invoke } from '@tauri-apps/api/core';
import { ArrowUpCircle, CheckCircle2, ChevronDown, Download, FolderOpen, RefreshCw, ShieldCheck, X } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { version as currentVersion } from '../../package.json';
import { IS_LINUX, IS_MACOS, IS_WINDOWS } from '../utils/platform';
const SKIP_KEY = 'psysonic_skipped_update_version';
// Semver comparison: returns true if `a` is newer than `b`
function isNewer(a: string, b: string): boolean {
const pa = a.replace(/^[^0-9]*/, '').split('.').map(Number);
const pb = b.replace(/^[^0-9]*/, '').split('.').map(Number);
for (let i = 0; i < 3; i++) {
if ((pa[i] ?? 0) > (pb[i] ?? 0)) return true;
if ((pa[i] ?? 0) < (pb[i] ?? 0)) return false;
}
return false;
}
function fmtBytes(n: number): string {
if (n < 1024 * 1024) return `${(n / 1024).toFixed(0)} KB`;
return `${(n / 1024 / 1024).toFixed(1)} MB`;
}
// Minimal inline-markdown renderer (bold, italic, code)
// IMPORTANT: regex must have NO nested capture groups — split() includes captured
// groups in the result, and nested groups produce undefined entries that crash on .startsWith()
function renderInline(text: string): React.ReactNode[] {
const parts = text.split(/(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`)/g);
return parts.map((part, i) => {
if (!part) return null;
if (part.startsWith('**') && part.endsWith('**'))
return {part.slice(2, -2)};
if (part.startsWith('*') && part.endsWith('*'))
return {part.slice(1, -1)};
if (part.startsWith('`') && part.endsWith('`'))
return {part.slice(1, -1)};
return part;
});
}
function renderChangelog(body: string) {
return body.split('\n').map((line, i) => {
if (line.startsWith('### '))
return
yay -S psysonic-bin
sudo pacman -Syu psysonic-bin