Android build v1.1.31
This commit is contained in:
@@ -1256,7 +1256,7 @@ export function Iwt2RoguelikeUpgradeScreen({
|
||||
setSelectedIndex((current) => moveUpgradeSelection(entries, current, action))
|
||||
return
|
||||
}
|
||||
if (action === 'back' || action === 'pause') return
|
||||
if (action === 'back') onBack()
|
||||
})
|
||||
|
||||
return (
|
||||
@@ -1547,33 +1547,10 @@ export function Iwt2HunterProfileScreen({
|
||||
|
||||
function moveSelection(action: InputAction) {
|
||||
if (!action.startsWith('navigate') || navEntries.length === 0) return
|
||||
setSelectedIndex((current) => {
|
||||
const bounded = Math.min(current, navEntries.length - 1)
|
||||
const active = navEntries[bounded]
|
||||
if (!active) return 0
|
||||
const candidates = navEntries
|
||||
.map((entry, index) => ({ entry, index }))
|
||||
.filter(({ index }) => index !== bounded)
|
||||
.filter(({ entry }) => {
|
||||
if (action === 'navigateLeft') return entry.column < active.column
|
||||
if (action === 'navigateRight') return entry.column > active.column
|
||||
if (action === 'navigateUp') return entry.row < active.row
|
||||
return entry.row > active.row
|
||||
})
|
||||
if (candidates.length === 0) return bounded
|
||||
candidates.sort((a, b) => {
|
||||
const aPrimary = Math.abs(a.entry.row - active.row) + Math.abs(a.entry.column - active.column)
|
||||
const bPrimary = Math.abs(b.entry.row - active.row) + Math.abs(b.entry.column - active.column)
|
||||
const aSecondary = action === 'navigateLeft' || action === 'navigateRight'
|
||||
? Math.abs(a.entry.row - active.row)
|
||||
: Math.abs(a.entry.column - active.column)
|
||||
const bSecondary = action === 'navigateLeft' || action === 'navigateRight'
|
||||
? Math.abs(b.entry.row - active.row)
|
||||
: Math.abs(b.entry.column - active.column)
|
||||
return aPrimary - bPrimary || aSecondary - bSecondary || a.index - b.index
|
||||
})
|
||||
return candidates[0]?.index ?? bounded
|
||||
})
|
||||
const nextIndex = moveHunterProfileSelection(navEntries, selectedIndex, action)
|
||||
const nextEntry = navEntries[nextIndex]
|
||||
setSelectedIndex(nextIndex)
|
||||
if (nextEntry?.kind === 'item') setFocusedItemKey(nextEntry.itemKey)
|
||||
}
|
||||
|
||||
function openEntry(entry: Iwt2HunterProfileNavEntry | undefined) {
|
||||
@@ -1863,6 +1840,7 @@ function Iwt2ProfileNameEditor({
|
||||
<label>
|
||||
<span>Profile Name</span>
|
||||
<input
|
||||
data-controller-nav="skip"
|
||||
maxLength={IWT2_NAME_MAX_LENGTH}
|
||||
onChange={(event) => setDraft(event.target.value.slice(0, IWT2_NAME_MAX_LENGTH))}
|
||||
value={draft}
|
||||
@@ -1901,38 +1879,42 @@ export function Iwt2CloudSaveScreen({
|
||||
const [onlineSave, setOnlineSave] = useState<Iwt2Save | null>(null)
|
||||
const [syncingOnlineSave, setSyncingOnlineSave] = useState(false)
|
||||
const [message, setMessage] = useState('')
|
||||
const statusMessage = message || (!onlineBackupsAvailable ? 'Online save unavailable in offline mode.' : '')
|
||||
|
||||
const checkOnlineSave = useCallback(async (isCancelled: () => boolean) => {
|
||||
setSyncingOnlineSave(true)
|
||||
setMessage('Checking online save...')
|
||||
try {
|
||||
const result = await loadIwt2OnlineSave()
|
||||
if (isCancelled()) return
|
||||
setOnlineSave(result.save)
|
||||
setMessage(result.save ? 'Online save loaded.' : 'No online save yet.')
|
||||
} catch (reason) {
|
||||
if (isCancelled()) return
|
||||
setOnlineSave(null)
|
||||
setMessage(reason instanceof Error ? reason.message : 'Unable to check online save.')
|
||||
} finally {
|
||||
if (!isCancelled()) setSyncingOnlineSave(false)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
if (!onlineBackupsAvailable) {
|
||||
setOnlineSave(null)
|
||||
setMessage('Online save unavailable in offline mode.')
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}
|
||||
setSyncingOnlineSave(true)
|
||||
setMessage('Checking online save...')
|
||||
loadIwt2OnlineSave()
|
||||
.then((result) => {
|
||||
if (cancelled) return
|
||||
setOnlineSave(result.save)
|
||||
setMessage(result.save ? 'Online save loaded.' : 'No online save yet.')
|
||||
})
|
||||
.catch((reason) => {
|
||||
if (cancelled) return
|
||||
setOnlineSave(null)
|
||||
setMessage(reason instanceof Error ? reason.message : 'Unable to check online save.')
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) setSyncingOnlineSave(false)
|
||||
})
|
||||
const timer = window.setTimeout(() => {
|
||||
void checkOnlineSave(() => cancelled)
|
||||
}, 0)
|
||||
return () => {
|
||||
cancelled = true
|
||||
window.clearTimeout(timer)
|
||||
}
|
||||
}, [onlineBackupsAvailable])
|
||||
}, [checkOnlineSave, onlineBackupsAvailable])
|
||||
|
||||
const useLocalSave = useCallback(async () => {
|
||||
const handleUseLocalSave = useCallback(async () => {
|
||||
if (!onlineBackupsAvailable) {
|
||||
setMessage('Using local save. Sign in online to update the server copy.')
|
||||
return
|
||||
@@ -1950,13 +1932,13 @@ export function Iwt2CloudSaveScreen({
|
||||
}
|
||||
}, [onlineBackupsAvailable, save])
|
||||
|
||||
const useOnlineSave = useCallback(() => {
|
||||
if (!onlineSave) return
|
||||
const handleUseOnlineSave = useCallback(() => {
|
||||
if (!onlineBackupsAvailable || !onlineSave) return
|
||||
onSaveUpdated(onlineSave)
|
||||
setMessage('Local save now uses online progress.')
|
||||
}, [onlineSave, onSaveUpdated])
|
||||
}, [onlineBackupsAvailable, onlineSave, onSaveUpdated])
|
||||
|
||||
const useNewSave = useCallback(() => {
|
||||
const handleUseNewSave = useCallback(() => {
|
||||
onSaveUpdated(createDefaultIwt2Save())
|
||||
setMessage('Started a new local IWT2 save.')
|
||||
}, [onSaveUpdated])
|
||||
@@ -1969,7 +1951,7 @@ export function Iwt2CloudSaveScreen({
|
||||
value: onlineBackupsAvailable ? 'Upload' : 'Current',
|
||||
disabled: syncingOnlineSave,
|
||||
onConfirm: () => {
|
||||
void useLocalSave()
|
||||
void handleUseLocalSave()
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1977,30 +1959,30 @@ export function Iwt2CloudSaveScreen({
|
||||
label: 'Use Online Save',
|
||||
detail: syncingOnlineSave ? 'Checking online save...' : formatIwt2SaveSummary(onlineSave),
|
||||
value: onlineSave ? 'Download' : 'Empty',
|
||||
disabled: syncingOnlineSave || !onlineSave,
|
||||
onConfirm: useOnlineSave,
|
||||
disabled: syncingOnlineSave || !onlineBackupsAvailable || !onlineSave,
|
||||
onConfirm: handleUseOnlineSave,
|
||||
},
|
||||
{
|
||||
key: 'new-save',
|
||||
label: 'Use New Save File',
|
||||
detail: 'Start over with a fresh IWT2 character. Online save is not overwritten until you choose local save.',
|
||||
value: 'New',
|
||||
onConfirm: useNewSave,
|
||||
onConfirm: handleUseNewSave,
|
||||
},
|
||||
], onBack), [
|
||||
handleUseLocalSave,
|
||||
handleUseNewSave,
|
||||
handleUseOnlineSave,
|
||||
onlineBackupsAvailable,
|
||||
onlineSave,
|
||||
onBack,
|
||||
save,
|
||||
syncingOnlineSave,
|
||||
useLocalSave,
|
||||
useNewSave,
|
||||
useOnlineSave,
|
||||
])
|
||||
|
||||
return (
|
||||
<Iwt2ScreenShell title="Backup Slot" onBack={onBack}>
|
||||
{message && <p className="iwt2-screen-note">{message}</p>}
|
||||
{statusMessage && <p className="iwt2-screen-note">{statusMessage}</p>}
|
||||
<Iwt2ActionList actions={actions} />
|
||||
</Iwt2ScreenShell>
|
||||
)
|
||||
@@ -2114,6 +2096,16 @@ export function Iwt2GearUpgradeScreen({
|
||||
<section className="content-screen iwt2-screen-shell iwt2-gear-screen" data-game-nav-active="true">
|
||||
<div className="iwt2-gear-layout">
|
||||
<section className="iwt2-gear-column">
|
||||
<button
|
||||
className={`back-button iwt2-gear-back ${activeEntry?.kind === 'back' ? 'game-selected' : ''}`}
|
||||
data-controller-nav="skip"
|
||||
data-game-selected={activeEntry?.kind === 'back' ? 'true' : undefined}
|
||||
onClick={onBack}
|
||||
onPointerDown={() => selectGearEntry(navEntries, setSelectedIndex, 'back')}
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
<div className="iwt2-gear-class-list">
|
||||
{IWT2_PARTY_ORDER.map((classId) => {
|
||||
const metadata = IWT2_CLASS_METADATA[classId]
|
||||
@@ -2372,6 +2364,39 @@ function activeUpgradeEntry(entries: Iwt2UpgradeNavEntry[], index: number) {
|
||||
return entries[Math.min(index, entries.length - 1)]
|
||||
}
|
||||
|
||||
function moveHunterProfileSelection(
|
||||
entries: Iwt2HunterProfileNavEntry[],
|
||||
current: number,
|
||||
action: InputAction,
|
||||
) {
|
||||
if (!action.startsWith('navigate') || entries.length === 0) return current
|
||||
const bounded = Math.min(current, entries.length - 1)
|
||||
const active = entries[bounded]
|
||||
if (!active) return 0
|
||||
const candidates = entries
|
||||
.map((entry, index) => ({ entry, index }))
|
||||
.filter(({ index }) => index !== bounded)
|
||||
.filter(({ entry }) => {
|
||||
if (action === 'navigateLeft') return entry.column < active.column
|
||||
if (action === 'navigateRight') return entry.column > active.column
|
||||
if (action === 'navigateUp') return entry.row < active.row
|
||||
return entry.row > active.row
|
||||
})
|
||||
if (candidates.length === 0) return bounded
|
||||
candidates.sort((a, b) => {
|
||||
const aPrimary = Math.abs(a.entry.row - active.row) + Math.abs(a.entry.column - active.column)
|
||||
const bPrimary = Math.abs(b.entry.row - active.row) + Math.abs(b.entry.column - active.column)
|
||||
const aSecondary = action === 'navigateLeft' || action === 'navigateRight'
|
||||
? Math.abs(a.entry.row - active.row)
|
||||
: Math.abs(a.entry.column - active.column)
|
||||
const bSecondary = action === 'navigateLeft' || action === 'navigateRight'
|
||||
? Math.abs(b.entry.row - active.row)
|
||||
: Math.abs(b.entry.column - active.column)
|
||||
return aPrimary - bPrimary || aSecondary - bSecondary || a.index - b.index
|
||||
})
|
||||
return candidates[0]?.index ?? bounded
|
||||
}
|
||||
|
||||
function upgradeEntryDisabled(entry: Iwt2UpgradeNavEntry) {
|
||||
return entry.kind === 'upgradeContinue' && Boolean(entry.disabled)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user