import { useEffect, useState } from 'react' import { ACTION_LABELS, INPUT_ACTIONS, useInput, type InputDevice, } from '../input' import { ControllerBindingLabel, ControllerStylePreview, } from './ControllerIcons' const CONTROLLER_STYLE_LABELS = { xbox: 'Xbox', playstation: 'PlayStation', nintendo: 'Nintendo', } as const import { useDualScreen } from '../dualScreen' import { getNativeDisplays, hasNativeDualScreenBridge, type AndroidDisplay, } from '../nativeDualScreen' export function SettingsScreen({ onBack }: { onBack: () => void }) { const [device, setDevice] = useState('controller') const [settingsTab, setSettingsTab] = useState<'display' | 'input' | 'bindings'>('display') const [displayMessage, setDisplayMessage] = useState('') const [androidDisplays, setAndroidDisplays] = useState([]) const { bindings, capture, controllerIconStyle, directPartyTargeting, beginCapture, cancelCapture, resetBindings, setControllerIconStyle, setDirectPartyTargeting, } = useInput() const { enabled: dualScreenEnabled, connected: topDisplayConnected, setEnabled: setDualScreenEnabled, openTopDisplay, } = useDualScreen() const nativeDualScreen = hasNativeDualScreenBridge() const directTargetActions = new Set([ 'targetParty1', 'targetParty2', 'targetParty3', 'targetParty4', 'targetParty5', 'targetParty6', 'toggleTargetGroup', ]) const visibleActions = INPUT_ACTIONS.filter((action) => ( directPartyTargeting ? action !== 'previousTarget' && action !== 'nextTarget' : !directTargetActions.has(action) )) async function refreshNativeDisplays() { if (!nativeDualScreen) return try { const result = await getNativeDisplays() setAndroidDisplays(result.displays) } catch { setAndroidDisplays([]) } } useEffect(() => { if (!nativeDualScreen) return getNativeDisplays() .then((result) => setAndroidDisplays(result.displays)) .catch(() => setAndroidDisplays([])) }, [nativeDualScreen]) async function launchTopDisplay() { const opened = await openTopDisplay() setDisplayMessage(opened ? nativeDualScreen ? 'Android placed the game on the larger display and controls on the smaller display.' : 'Companion display opened. Move it to the Thor screen you want and select Fullscreen.' : 'No usable second display was found. Check the Thor display mode and try again.') await refreshNativeDisplays() } return (

Game Options

Settings

{settingsTab === 'display' && (

Display

AYN Thor Dual-Screen Mode

The upper display shows enemy and party health. The lower display keeps targeting, resources, skills, and cooldowns.

{displayMessage || ( topDisplayConnected ? 'The companion display is connected and receiving live combat data.' : 'Open the companion display before starting combat.' )} {nativeDualScreen && androidDisplays.length > 0 && (
{androidDisplays.map((display) => ( {display.isCurrent ? 'Current' : 'Secondary'} #{display.id} {display.width}x{display.height} at {Math.round(display.refreshRate)} Hz {display.isPresentation ? ' - Presentation' : ''} ))}
)}
)} {settingsTab === 'input' && (

Targeting

Direct Party Keybinds

Assign party slots directly. In raids, use the group-switch binding to alternate between members 1-6, 7-12, and 13-18.

Controller Icons {(['xbox', 'playstation', 'nintendo'] as const).map((style) => ( ))}
)} {settingsTab === 'bindings' && (

Input

Keybindings

Select an action, then press the new key or controller control.

{visibleActions.map((action) => ( ))}
Bindings are saved automatically on this device.
)} {capture && (

Remapping

{ACTION_LABELS[capture.action]}

Press any {capture.device === 'pc' ? 'keyboard key' : 'controller button or move a stick'}.

)}
) }