Compare commits
6 Commits
v0.40.2
...
005efa2ee4
| Author | SHA1 | Date | |
|---|---|---|---|
| 005efa2ee4 | |||
| 1190ed3ce6 | |||
| 2869e1c34e | |||
| 783f01628e | |||
| 94a6feb5db | |||
| 3daaf47689 |
+3
-1
@@ -41,7 +41,9 @@ project follows [Semantic Versioning](https://semver.org/).
|
||||
each column's total depth (face-down cards included) and refills on the
|
||||
cold-start deal, every move, and on resize (incl. the Android safe-area-inset
|
||||
resize and fold/unfold), so a near-square viewport such as an unfolded Galaxy
|
||||
Fold no longer leaves the bottom of the screen empty.
|
||||
Fold no longer leaves the bottom of the screen empty. The fan spread cap was
|
||||
raised so very tall / narrow viewports (e.g. a foldable cover screen) fill
|
||||
further.
|
||||
- **Card-move animation jank.** A move now rebuilds a card's child visuals only
|
||||
when its appearance changes (flip / resize / accessibility) instead of
|
||||
despawning and respawning every card's children each `StateChangedEvent`,
|
||||
|
||||
@@ -99,7 +99,7 @@ const MAX_TABLEAU_CARDS: f32 = 13.0;
|
||||
/// clear overlap (a readable stack) while still filling most of a near-square /
|
||||
/// unfolded-foldable screen. Tunable purely for feel — no effect on correctness
|
||||
/// or hit-testing.
|
||||
pub(crate) const MAX_DYNAMIC_FAN_FRAC: f32 = 0.6;
|
||||
pub(crate) const MAX_DYNAMIC_FAN_FRAC: f32 = 0.9;
|
||||
|
||||
/// Vertical pixel band reserved at the top of the play area for the HUD
|
||||
/// (action buttons, Score / Moves / Timer readouts). The card grid starts
|
||||
@@ -285,13 +285,12 @@ pub fn compute_layout(
|
||||
);
|
||||
}
|
||||
|
||||
// Adaptive tableau fan fraction. On height-limited (desktop) windows the
|
||||
// height-based sizing already ensures a worst-case 13-card column fits at
|
||||
// TABLEAU_FAN_FRAC (0.25), so the formula returns ≈0.25 and the clamp
|
||||
// keeps it there — no change from prior behaviour. On width-limited
|
||||
// (portrait phone) windows card_size is small and lots of vertical space
|
||||
// is unused; we solve for the fraction that exactly fills the available
|
||||
// space to the bottom margin.
|
||||
// Adaptive tableau fan fraction. On height-limited windows the height-based
|
||||
// sizing already ensures a worst-case 13-card column fits at TABLEAU_FAN_FRAC,
|
||||
// so the formula returns the minimum and the clamp keeps it there. On
|
||||
// width-limited (portrait phone) windows card_size is small and lots of
|
||||
// vertical space is unused; solve for the fraction that fills the available
|
||||
// space. `apply_dynamic_tableau_fan` later refines this for the actual deal.
|
||||
//
|
||||
// avail = distance from the top of the first tableau card to the bottom
|
||||
// margin — i.e. the space available for 12 fan steps.
|
||||
@@ -302,20 +301,17 @@ pub fn compute_layout(
|
||||
} else {
|
||||
TABLEAU_FAN_FRAC
|
||||
};
|
||||
// Never go below the desktop minimum — avoids shrinking the fan on
|
||||
// degenerate near-square windows where the formula might undershoot.
|
||||
let tableau_fan_frac = ideal_fan_frac.max(TABLEAU_FAN_FRAC);
|
||||
// Scale the face-down fraction proportionally so rendering and hit-testing
|
||||
// stay in sync (TABLEAU_FACEDOWN_FAN_FRAC / TABLEAU_FAN_FRAC = 0.48 ratio).
|
||||
let facedown_scale = TABLEAU_FACEDOWN_FAN_FRAC / TABLEAU_FAN_FRAC;
|
||||
let tableau_facedown_fan_frac = tableau_fan_frac * facedown_scale;
|
||||
let available_tableau_height = avail;
|
||||
|
||||
Layout {
|
||||
card_size,
|
||||
pile_positions,
|
||||
tableau_fan_frac,
|
||||
tableau_facedown_fan_frac,
|
||||
available_tableau_height: avail,
|
||||
available_tableau_height,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,10 +191,12 @@ fn apply_safe_area_to_modal_scrims(
|
||||
/// whatever `SafeAreaInsets` are current at that moment.
|
||||
///
|
||||
/// On Android the `android::rearm_on_resumed` system runs in the same frame
|
||||
/// and resets both `SafeAreaPollTries` and `SafeAreaInsets` to zero, causing
|
||||
/// `refresh_insets` to re-poll JNI over the next few frames. When it resolves
|
||||
/// the correct values, `on_safe_area_changed` in `table_plugin` emits a second
|
||||
/// synthetic `WindowResized` and the layout converges to the right position.
|
||||
/// and resets `SafeAreaPollTries` (the cached `SafeAreaInsets` keep their
|
||||
/// last-known values), causing `refresh_insets` to re-poll JNI over the next
|
||||
/// few frames. If the insets changed while backgrounded, `on_safe_area_changed`
|
||||
/// in `table_plugin` emits a second synthetic `WindowResized` and the layout
|
||||
/// converges to the right position; if they didn't, nothing is rewritten and
|
||||
/// the layout stays put.
|
||||
///
|
||||
/// On non-Android targets this handler still fires — it ensures that a resume
|
||||
/// event always refreshes the layout (e.g., after a minimise/restore on
|
||||
@@ -232,9 +234,14 @@ mod android {
|
||||
pub(super) struct SafeAreaPollTries(pub u32);
|
||||
|
||||
/// Polls Android for safe-area insets until we get a non-zero
|
||||
/// reading, then stops. `getRootWindowInsets()` returns `null` (or
|
||||
/// all-zero `Insets`) until the decor view has been laid out, which
|
||||
/// is typically frame 1–3 of a fresh launch.
|
||||
/// reading, then settles until [`rearm_on_resumed`] re-arms it on the
|
||||
/// next foreground resume — insets can change while backgrounded
|
||||
/// (rotation, fold/unfold, gesture ↔ 3-button nav). The poll counter
|
||||
/// (not `insets.is_populated()`) gates the loop, so a re-armed cycle
|
||||
/// re-queries JNI even though cached values are already populated.
|
||||
/// `getRootWindowInsets()` returns `null` (or all-zero `Insets`)
|
||||
/// until the decor view has been laid out, which is typically frame
|
||||
/// 1–3 of a fresh launch.
|
||||
pub(super) fn refresh_insets(
|
||||
mut insets: ResMut<SafeAreaInsets>,
|
||||
mut poll: ResMut<SafeAreaPollTries>,
|
||||
@@ -243,18 +250,25 @@ mod android {
|
||||
// devices that genuinely report zero insets.
|
||||
const MAX_TRIES: u32 = 120; // ~2 seconds @ 60 fps
|
||||
|
||||
if poll.0 >= MAX_TRIES || insets.is_populated() {
|
||||
if poll.0 >= MAX_TRIES {
|
||||
return;
|
||||
}
|
||||
poll.0 += 1;
|
||||
|
||||
match query_insets() {
|
||||
Ok(v) if v.is_populated() => {
|
||||
info!(
|
||||
"safe_area: insets resolved top={} bottom={} left={} right={} (after {} frames)",
|
||||
v.top, v.bottom, v.left, v.right, poll.0
|
||||
);
|
||||
*insets = v;
|
||||
if *insets != v {
|
||||
info!(
|
||||
"safe_area: insets resolved top={} bottom={} left={} right={} (after {} frames)",
|
||||
v.top, v.bottom, v.left, v.right, poll.0
|
||||
);
|
||||
*insets = v;
|
||||
}
|
||||
// Settled for this poll cycle; `rearm_on_resumed` re-arms on
|
||||
// the next resume. Writing `insets` only on an actual change
|
||||
// keeps resource change detection (and the relayout it
|
||||
// triggers) quiet on resumes where nothing moved.
|
||||
poll.0 = MAX_TRIES;
|
||||
}
|
||||
Ok(_) => {
|
||||
// Layout not ready yet; try again next frame.
|
||||
|
||||
@@ -1649,62 +1649,62 @@ function __wbg_get_imports() {
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 114855, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 114846, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hea4b5125da4e5ded);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 9841, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 9832, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2a0b90ad2a013a3e);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000003: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Array<any>"), NamedExternref("ResizeObserver")], shim_idx: 9847, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Array<any>"), NamedExternref("ResizeObserver")], shim_idx: 9838, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h0fec466277fb30e8);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000004: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Array<any>")], shim_idx: 9841, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Array<any>")], shim_idx: 9832, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2a0b90ad2a013a3e_3);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000005: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 9841, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 9832, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2a0b90ad2a013a3e_4);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000006: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("FocusEvent")], shim_idx: 9841, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("FocusEvent")], shim_idx: 9832, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2a0b90ad2a013a3e_5);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000007: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("KeyboardEvent")], shim_idx: 9841, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("KeyboardEvent")], shim_idx: 9832, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2a0b90ad2a013a3e_6);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000008: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("PageTransitionEvent")], shim_idx: 9841, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("PageTransitionEvent")], shim_idx: 9832, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2a0b90ad2a013a3e_7);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000009: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("PointerEvent")], shim_idx: 9841, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("PointerEvent")], shim_idx: 9832, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2a0b90ad2a013a3e_8);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_000000000000000a: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("WheelEvent")], shim_idx: 9841, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("WheelEvent")], shim_idx: 9832, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2a0b90ad2a013a3e_9);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_000000000000000b: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Option(NamedExternref("Blob"))], shim_idx: 9843, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Option(NamedExternref("Blob"))], shim_idx: 9834, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hf05069bc44820cc5);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_000000000000000c: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 9839, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 9830, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h5e26b448f43bfba9);
|
||||
return ret;
|
||||
},
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user