Android build v1.1.8
This commit is contained in:
Binary file not shown.
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.warren.iwanttoheal"
|
applicationId "com.warren.iwanttoheal"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 86
|
versionCode 87
|
||||||
versionName "1.1.7"
|
versionName "1.1.8"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||||
|
|||||||
+210
@@ -6977,6 +6977,95 @@ h2 {
|
|||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auth-shell {
|
||||||
|
height: 100dvh;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-panel {
|
||||||
|
gap: 12px;
|
||||||
|
max-height: calc(100dvh - 20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-brand,
|
||||||
|
.auth-card {
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-brand {
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-brand h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
line-height: 1.15;
|
||||||
|
margin: 6px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-brand > p:last-child {
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 1.15;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-tabs {
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-tabs button {
|
||||||
|
min-height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card form {
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card label {
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card input {
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 7px 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card .primary-button {
|
||||||
|
min-height: 34px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-message {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.1;
|
||||||
|
margin-top: 8px;
|
||||||
|
min-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline-divider {
|
||||||
|
gap: 8px;
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline-entry {
|
||||||
|
gap: 7px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline-entry p:not(.eyebrow) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline-entry h2 {
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline-resume-button,
|
||||||
|
.offline-new-button {
|
||||||
|
min-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
.screen-heading {
|
.screen-heading {
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
@@ -7340,6 +7429,127 @@ h2 {
|
|||||||
.ability-library {
|
.ability-library {
|
||||||
max-height: 190px;
|
max-height: 190px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.enemy-card {
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 8px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-portrait {
|
||||||
|
flex-basis: 48px;
|
||||||
|
font-size: 17px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enemy-info p {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1;
|
||||||
|
margin-top: 4px;
|
||||||
|
max-height: 28px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-label {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combat-layout {
|
||||||
|
gap: 8px;
|
||||||
|
grid-template-columns: minmax(0, 1.6fr) minmax(248px, 0.85fr);
|
||||||
|
margin-top: 8px;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.party-panel,
|
||||||
|
.combat-log {
|
||||||
|
min-height: 0;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.party-panel-top {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.party-grid {
|
||||||
|
gap: 7px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.party-member {
|
||||||
|
min-height: 72px;
|
||||||
|
padding: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-header {
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-header small {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-health {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-effects {
|
||||||
|
gap: 3px;
|
||||||
|
margin-top: 4px;
|
||||||
|
min-height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-effects span {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combat-side-rail .panel-heading .eyebrow {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combat-side-rail .panel-heading h2 {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-spell-bar,
|
||||||
|
.vertical-spell-bar.six-slots {
|
||||||
|
gap: 6px;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
margin-top: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-spell-bar .spell {
|
||||||
|
min-height: 54px;
|
||||||
|
padding: 5px 5px 5px 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-spell-bar .spell-icon {
|
||||||
|
font-size: 10px;
|
||||||
|
height: 22px;
|
||||||
|
left: 6px;
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-spell-bar .spell strong {
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-spell-bar .spell small {
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-spell-bar .spell kbd {
|
||||||
|
font-size: 8px;
|
||||||
|
min-height: 16px;
|
||||||
|
padding: 1px 4px;
|
||||||
|
right: 3px;
|
||||||
|
top: 3px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
|
|||||||
+12
-3
@@ -150,6 +150,16 @@ function formatDualTime(seconds: number) {
|
|||||||
return `${Math.floor(total / 60)}:${String(total % 60).padStart(2, '0')}`
|
return `${Math.floor(total / 60)}:${String(total % 60).padStart(2, '0')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldRelayBottomAction(
|
||||||
|
action: InputAction,
|
||||||
|
state: DualScreenCombatState | null,
|
||||||
|
) {
|
||||||
|
if (!state) return false
|
||||||
|
if (action === 'confirm' || action === 'toggleTouchLock') return false
|
||||||
|
if (state.status === 'playing') return true
|
||||||
|
return action === 'pause' || action === 'back'
|
||||||
|
}
|
||||||
|
|
||||||
export function DualScreenProvider({ children }: { children: ReactNode }) {
|
export function DualScreenProvider({ children }: { children: ReactNode }) {
|
||||||
const [enabled, setEnabledState] = useState(
|
const [enabled, setEnabledState] = useState(
|
||||||
() => localStorage.getItem(STORAGE_KEY) === 'true',
|
() => localStorage.getItem(STORAGE_KEY) === 'true',
|
||||||
@@ -404,8 +414,7 @@ export function DualScreenBottomDisplay() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useGameAction((action) => {
|
useGameAction((action) => {
|
||||||
if (!state || state.opponentParty) return
|
if (!shouldRelayBottomAction(action, state)) return
|
||||||
if (action === 'confirm' || action === 'back' || action === 'toggleTouchLock') return
|
|
||||||
sendAction(action)
|
sendAction(action)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -458,7 +467,7 @@ export function DualScreenBottomDisplay() {
|
|||||||
return (
|
return (
|
||||||
<main
|
<main
|
||||||
className={`dual-bottom-display ${state.opponentParty ? 'pvp-opponent-bottom-display' : ''}`}
|
className={`dual-bottom-display ${state.opponentParty ? 'pvp-opponent-bottom-display' : ''}`}
|
||||||
data-combat-active={!state.opponentParty && state.status === 'playing' && !state.paused ? 'true' : 'false'}
|
data-combat-active={state.status === 'playing' && !state.paused ? 'true' : 'false'}
|
||||||
>
|
>
|
||||||
<header className="dual-controls-header">
|
<header className="dual-controls-header">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
+2
-1
@@ -131,7 +131,7 @@ const PREFERENCES_STORAGE_KEY = 'ashen-halls-input-preferences-v1'
|
|||||||
const GAME_ACTION_EVENT = 'ashen-halls-game-action'
|
const GAME_ACTION_EVENT = 'ashen-halls-game-action'
|
||||||
const NATIVE_CONTROLLER_EVENT = 'ashen-halls-native-controller'
|
const NATIVE_CONTROLLER_EVENT = 'ashen-halls-native-controller'
|
||||||
const FOCUSABLE_SELECTOR = 'button:not(:disabled):not([data-controller-nav="skip"]), input:not(:disabled):not([data-controller-nav="skip"]), select:not(:disabled):not([data-controller-nav="skip"]), textarea:not(:disabled):not([data-controller-nav="skip"]), [tabindex]:not([tabindex="-1"]):not([data-controller-nav="skip"])'
|
const FOCUSABLE_SELECTOR = 'button:not(:disabled):not([data-controller-nav="skip"]), input:not(:disabled):not([data-controller-nav="skip"]), select:not(:disabled):not([data-controller-nav="skip"]), textarea:not(:disabled):not([data-controller-nav="skip"]), [tabindex]:not([tabindex="-1"]):not([data-controller-nav="skip"])'
|
||||||
const MAIN_CONTENT_SELECTOR = '.menu-screen, .content-screen, .dungeon-run-screen'
|
const MAIN_CONTENT_SELECTOR = '.auth-shell, .menu-screen, .content-screen, .dungeon-run-screen, .dual-bottom-display'
|
||||||
const HEADER_CONTENT_SELECTOR = '.app-header'
|
const HEADER_CONTENT_SELECTOR = '.app-header'
|
||||||
const GAMEPAD_COMBAT_POLL_MS = 1000 / 60
|
const GAMEPAD_COMBAT_POLL_MS = 1000 / 60
|
||||||
const GAMEPAD_MENU_POLL_MS = 1000 / 30
|
const GAMEPAD_MENU_POLL_MS = 1000 / 30
|
||||||
@@ -309,6 +309,7 @@ function rememberFocusableControl(element: HTMLElement) {
|
|||||||
function focusControl(element: HTMLElement) {
|
function focusControl(element: HTMLElement) {
|
||||||
rememberFocusableControl(element)
|
rememberFocusableControl(element)
|
||||||
element.focus({ preventScroll: true })
|
element.focus({ preventScroll: true })
|
||||||
|
element.scrollIntoView({ block: 'nearest', inline: 'nearest' })
|
||||||
}
|
}
|
||||||
|
|
||||||
function currentFocusableControl(candidates = focusableElements()) {
|
function currentFocusableControl(candidates = focusableElements()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user