Android build v1.1.31

This commit is contained in:
Warren H
2026-07-06 23:49:14 -04:00
parent f48e6130b8
commit a6cca2810c
14 changed files with 219 additions and 96 deletions
+85 -60
View File
@@ -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)
}