OneLauncher-Cracked/apps/oneclient/frontend/src/components/LaunchButton.tsx
2025-12-27 02:21:15 +09:00

128 lines
4.3 KiB
TypeScript

import type { ClusterModel } from '@/bindings.gen';
import type { ButtonProps } from '@onelauncher/common/components';
import { KillMinecraft, NoAccountPopup, Overlay } from '@/components';
import { useIsRunning } from '@/hooks/useClusters';
import { useLaunchCluster } from '@/hooks/useLaunchCluster';
import { bindings } from '@/main';
import { useCommandSuspense } from '@onelauncher/common';
import { Button } from '@onelauncher/common/components';
import { useNavigate } from '@tanstack/react-router';
import { useState } from 'react';
import { tv } from 'tailwind-variants';
export type LaunchButtonProps = Omit<ButtonProps, 'children' | 'onClick'> & {
cluster: ClusterModel;
};
const launchButtonVariants = tv({
variants: {
isRunning: {
true: 'bg-success hover:bg-success-hover pressed:bg-success-pressed disabled:bg-success-disabled pending:bg-success-disabled',
},
},
});
function PromptForOnboarding({ launch, setSkipPackagesCheck, cluster }: { launch: () => void; setSkipPackagesCheck: React.Dispatch<React.SetStateAction<boolean>>; cluster: ClusterModel }) {
const navigate = useNavigate();
const onClickYes = () => {
localStorage.setItem('selectedClusters', JSON.stringify([{ mc_version: cluster.mc_version, mc_loader: cluster.mc_loader }]));
navigate({ to: `/onboarding/preferences/versionCategory` });
};
const onClickLaunch = () => {
setSkipPackagesCheck(true);
launch();
};
return (
<Overlay.Dialog>
<Overlay.Title>Not Setup</Overlay.Title>
<div className="flex flex-col items-center">
<p className="max-w-sm text-fg-secondary">It seems like you haven't setup this version</p>
<p className="max-w-sm text-fg-secondary">Do you want to setup this version?</p>
</div>
<Overlay.Buttons
buttons={[
{ color: 'primary', key: 'Yes', children: 'Yes', size: 'normal', onClick: onClickYes },
{
color: 'secondary',
key: 'anyways',
children: 'Launch Anyways',
size: 'normal',
onClick: onClickLaunch,
},
]}
/>
</Overlay.Dialog>
);
}
export function LaunchButton({
cluster,
isDisabled,
className,
...rest
}: LaunchButtonProps) {
const { data: currentAccount } = useCommandSuspense(['getDefaultUser'], () => bindings.core.getDefaultUser(true));
const { data: installedPackages } = useCommandSuspense(['getLinkedPackages', cluster.id], () => bindings.core.getLinkedPackages(cluster.id));
const { launch: launchCluster, showDownloadWarning, setShowDownloadWarning, forceLaunch } = useLaunchCluster(cluster.id);
const isRunning = useIsRunning(cluster.id);
const [reason, setReason] = useState<'account' | 'packages' | 'kill' | null>(null);
const [skipPackagesCheck, setSkipPackagesCheck] = useState(false);
const launch = () => {
if (isRunning)
return setReason('kill');
if (!currentAccount)
return setReason('account');
if (installedPackages.length === 0 && !skipPackagesCheck)
return setReason('packages');
launchCluster();
setSkipPackagesCheck(false);
setReason(null);
};
return (
<>
<Overlay.Trigger isOpen={reason !== null} onOpenChange={open => !open && setReason(null)}>
<Button
className={launchButtonVariants({ isRunning, className })}
isDisabled={isDisabled}
onPress={launch}
{...rest}
>
{isRunning ? 'Running' : 'Launch'}
</Button>
<Overlay>
{reason === 'kill' && <KillMinecraft setOpen={() => setReason(null)} />}
{reason === 'packages' && <PromptForOnboarding cluster={cluster} launch={launch} setSkipPackagesCheck={setSkipPackagesCheck} />}
{reason === 'account' && <NoAccountPopup />}
</Overlay>
</Overlay.Trigger>
<Overlay isOpen={showDownloadWarning} onOpenChange={setShowDownloadWarning}>
<Overlay.Dialog>
<Overlay.Title>Cluster is downloading</Overlay.Title>
<div className="flex flex-col items-center">
<p className="max-w-sm text-fg-secondary">The cluster is currently downloading. Launching it now might cause issues or corruption. Are you sure you want to proceed?</p>
</div>
<Overlay.Buttons
buttons={[
{ color: 'secondary', key: 'Cancel', children: 'Cancel', size: 'normal', onClick: () => setShowDownloadWarning(false) },
{
color: 'primary',
key: 'Proceed',
children: 'Proceed Anyways',
size: 'normal',
onClick: forceLaunch,
},
]}
/>
</Overlay.Dialog>
</Overlay>
</>
);
}