Releases: jeiel85/flux-hourglass-android
Release list
v1.9.1
Flux Hourglass v1.9.1 Release Notes
Flux Hourglass v1.9.1 is a bug-fix release that hardens the Setup Screen layout so the time picker and START button can never be pushed off-screen and lost.
The Bug
The Setup Screen content was laid out in a fixed Column(Modifier.fillMaxSize()) with verticalArrangement = Arrangement.SpaceBetween and no scroll fallback. When the total content height exceeded the viewport — short/small screens, split-screen, a large accessibility font scale, tall system-bar insets, or any future growth of the object filmstrip — SpaceBetween placed the lower children (Quick Presets, the HR/MIN/SEC picker, and the START button) below the bottom edge with no way to scroll to them. The controls silently disappeared, leaving only the header and the object selector visible.
The Fix
- Min-height scroll container. The content is now wrapped in a
BoxWithConstraintswhoseColumnusesModifier.heightIn(min = viewportHeight).verticalScroll(rememberScrollState()).- When the content fits (the common case), the column is exactly the viewport height, so
Arrangement.SpaceBetweenspreads the children exactly as before — the layout is pixel-identical and never scrolls. - When the content overflows, the column grows past the viewport and becomes scrollable, so every control stays reachable instead of being clipped away.
- When the content fits (the common case), the column is exactly the viewport height, so
- No visual change on screens where the content already fit.
Technical Notes
- Added imports:
androidx.compose.foundation.verticalScroll,androidx.compose.foundation.rememberScrollState,androidx.compose.foundation.layout.heightIn. statusBarsPadding()/navigationBarsPadding()/background(PureBlack)moved to the outerBoxWithConstraints, somaxHeightreflects the true content area used as the column's minimum height.- All
testTags (mode_column,mode_scroller,preset_row,start_button, themode_*object tags, picker tags) are unchanged. - No data-model, schema, or persistence changes; saved durations and object preferences carry over.
- Verification. The golden
setup.pngRoborazzi test still passes in compare mode (verifyRoborazziDebug), proving no visual regression when content fits. A separate overflow-forcing render (tiny viewport + 1.8× font) confirmsSTARTcan be scrolled into view (performScrollTo().assertIsDisplayed()), which was impossible before the fix. - versionCode 10 → 11, versionName 1.9.0 → 1.9.1.
v1.9.0
Flux Hourglass v1.9.0 Release Notes
Flux Hourglass v1.9.0 reworks the object selector on the Setup Screen from a fixed three-row grid into a single horizontally scrollable filmstrip, reclaiming the vertical space the time picker and START button need.
What's New
Object Selector — Single Swipe-Through Row
The 15 objects previously occupied three stacked rows of five, a fixed block that crowded the time picker and start control and grew taller with every new object added (v1.6 → v1.7 → v1.8).
- One row instead of three. Objects now live in a single
LazyRowyou swipe left/right. The footprint is fixed regardless of how many objects exist, so future additions no longer push the picker down. - Auto-centering selection. Tapping (or restoring) an object glides it to the horizontal center via
animateScrollBy, computed from the livelayoutInfoviewport. Off-screen selections jump close first, then center. - Edge-fade affordance. Pure-black horizontal gradients on both ends signal that the strip continues. The overlays carry no pointer modifiers, so the partially-faded edge items stay tappable.
- Concept-preserving. Keeps the hairline-underline / letter-spaced
ModeTabstyling untouched — only the container changed. No new chrome, no expand/collapse state.
Technical Notes
DisplayModeenum and per-objectmode_*test tags are unchanged; the order is now driven by a singleModeOptionslist (ModeOption(mode, label, tag)), the single place to append new objects.- Removed the
mode_row_1/2/3containers; the wrappingBoxkeeps themode_columntest tag and the newLazyRowcarriesmode_scroller. - No data-model, schema, or persistence changes —
DisplayModeserialization is identical, so saved object preferences carry over. - versionCode 9 → 10, versionName 1.8.0 → 1.9.0.
v1.8.0
Flux Hourglass v1.8.0 Release Notes
We are thrilled to present Flux Hourglass v1.8.0, introducing a sandbox physics settings panel, live procedural soundscapes, and interactive gesture-drawn collision barriers.
What's New
1. Sandbox Physics Settings
Customize the core simulation engine using three adjustable parameters in the Setup Screen (S E T T button):
-
Gravity Sensitivity (
$0.3\times$ to$2.5\times$ ): Tweak how aggressively particles slump and react to accelerometer tilting. -
Particle Size (
$0.6\times$ to$2.2\times$ ): Modify grain size, splash radius, and droplet scale. -
Particle Density (
$0.5\times$ to$2.0\times$ ): Control the spawn rate/amount of simultaneous simulation elements.
2. Procedural Soundscapes
Listen to math-modeled, real-time PCM audio synthesis dynamically generated using mathematical noise models:
- Rain Mode: Immersive low-pass filtered white noise rumbling.
- Fire Mode: Organic crackling logs using random sparse amplitude pops over a low rumble.
- Water Mode: Rolling amplitude-modulated wave rumble mimicking ocean waves.
- Uses zero resource files, keeping the APK lightweight! Toggle sound with the middle overlay button.
3. Interactive Obstacle Drawing
Draw transient, fading lines on the screen using drag gestures. Grains (Sand), splashes (Water), and droplets (Rain) will deflect off your barriers in real time using elastic 2D collision vector calculations.
v1.7.0
Flux Hourglass 1.7.0
A major feature release introducing 5 premium interactive, accelerometer-driven particle-physics and fluid simulation modes: MAGNETIC, AURORA, RAIN, BLACKHOLE, and ELECTRIC. This release elevates the minimalist timer experience with satisfying physics and multi-touch gestures.
Highlights
- Magnetic Ferrofluid Mode (MAGNETIC).
- Features spiky black ferrofluid fluid dynamics that accumulate and stretch towards a virtual magnet.
- Spikes bristle and wiggle organically with time-based sine wave micro-vibrations.
- Interactive dragging moves the virtual magnet attraction center on touch.
- Aurora Flow Field Mode (AURORA).
- Sweeps glowing teal, green, and purple particles through a dynamic trigonometry flow field.
- Particles drift with device tilt and slowly settle into a calm, glowing sediment layer at the bottom.
- Touching the screen creates a powerful swirling vortex that redirects the particle winds.
- Rain & Ripples Mode (RAIN).
- Simulates rain condensation sliding down a glass pane, merging with other drops upon collision.
- Drops slide at an angle determined by the device accelerometer (gravity vector).
- Touching the screen sweeps drops away like a finger wiping the condensation.
- Accretion black hole Mode (BLACKHOLE).
- Features star particles orbiting a growing gravitational singularity.
- Star orbits are perturbed by device tilt and experience friction, spiraling inward until they cross the event horizon.
- Touching the screen spawns a secondary mini-singularity, splitting orbital streams.
- Tesla Plasma Globe Mode (ELECTRIC).
- Generates electric discharge arcs using recursive midpoint displacement fractal algorithms.
- Arcs bend upward to simulate hot gas rising against the accelerometer's gravity vector.
- Touching the screen focuses all main plasma arcs directly to the finger coordinate with rapid haptic micro-pulses.
Implementation Notes
- Interactivity is managed through a unified
pointerInputsystem using Compose's customawaitPointerEventScopeto cleanly capture tap, hold, drag, and release events in one thread-safe pass. - Accelerometer low-pass filtering feeds into all physics loops, adjusting drag directions, gravitational pull, and convective heat rise in real-time.
v1.6.0
Flux Hourglass 1.6.0
A premium release introducing a beautiful, progressive Campfire-to-Embers (불멍) motion alongside critical build environment stability upgrades. The fire simulation transitions dynamically from roaring bonfire flames to crackling embers and breathing glowing charcoal.
Highlights
- Campfire-to-Embers Mode (FIRE). Tap "FIRE" on the setup screen to toggle this premium bonfire simulation:
- Dynamic Progressive States: The fire starts with high intensity, roaring yellow/orange/white flames. As time runs out, the flames gradually die down.
- Campfire Logs: The background features beautifully rendered crossed firewood logs at the bottom center of the screen.
- Breathing Charcoal Glow: In the final phase (progress > 80%), the logs transition to a burning coal state, breathing with an organic pulsing red-orange glow using double sine/cosine waves.
- Crackling Ember Sparks: Tiny, high-velocity golden spark particles crackle and float upwards from the coal bed during the embers phase, drifting sideways under device tilt.
- Interactive Tilt Physics: The fire flames and floating sparks react dynamically to the device accelerometer, leaning realistically when the phone is tilted.
- Gradle 9.5.1 Upgrade. Upgraded the project build system and Gradle wrapper to version 9.5.1 to resolve script compilation regressions on Windows environments.
Implementation Notes
- Inside
MainActivity.kt, the progressive state usesrememberUpdatedState(progress)inside the continuousLaunchedEffectsimulation loop to correctly track real-time progression without resetting particle states. - The logs are rendered using Compose Canvas
drawLinewith a thick stroke andStrokeCap.Round. The glowing charcoal core is drawn as pulsing inner stroke layers:
$$\text{glowColor} = \text{Color}(0xFFFF3D00).copy(\text{alpha} = \text{emberGlowAlpha} \cdot (0.85f + \sin(\text{tick} \cdot 0.05f) \cdot 0.15f))$$ - Particle system caps max particles and adjusts spawn rates to decline linearly as the timer progress increases, transitioning flame spawning off at 80% progress and replacing them with a low-density spark emitter.
v1.5.0
Flux Hourglass 1.5.0
A premium release introducing a gorgeous Water Mode alongside complete Full-Screen Immersive Mode support. The liquid rendering utilizes accelerometer-driven fluid dynamics with beautiful wobbly bubbles and splash particles.
Highlights
- Dynamic Water Mode. Tap "WATER" on the setup screen to toggle this premium liquid simulation. It features:
- Double-Layer Waves: Undulating translucent waves (Cyan & Blue paths) flowing continuously in real-time.
- Spring-Damper Tilt Physics: Highly-responsive fluid tilting that realistically sloshes back and forth when you tilt your device, settling naturally into equilibrium.
- Ambient Gaseous Bubbles: Gentle bubbles spawning at the bottom pool, rising with a side-to-side wobble phase, and popping cleanly on the surface waves.
- Gravity-Accelerated Splashes: Splashing water droplets erupting upwards under gravity from the exact point of the vertical stream's impact.
- Full-Screen Immersive Mode. No more status or navigation bars breaking the minimalism. The entire display is dedicated to the visual timer experience, with bar visibility toggled via a transient swipe-to-reveal gesture.
- Enhanced Physics & Aesthetics. Highly refined gravity formulas and scaled splash properties align the physical tilting response of the fluid perfectly with the device's actual angle, matching the premium look of the Sand simulation.
Implementation Notes
- Inside
MainActivity.onCreate, standardWindowInsetsControllerCompathandles the immersive configuration:val controller = WindowInsetsControllerCompat(window, window.decorView) controller.hide(WindowInsetsCompat.Type.systemBars()) controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
- Accelerometer values are continuously filtered using low-pass and spring-damper equations to prevent micro-jitter and achieve realistic fluid inertia:
$$\text{acceleration} = (\text{targetSlosh} - \text{sloshAngle}) \cdot 35f - \text{sloshVelocity} \cdot 6f$$ - Splash droplet horizontal velocity components scale linearly with
tiltX * 36fto perfectly align the impact point with the falling water column on tilted screens.
v1.4.0
Flux Hourglass 1.4.0
A small but very physical release. Rotate the phone and the sand and
LEDs now actually obey gravity, and the bottom controls finally stay
readable when they sit on top of a white pile.
Highlights
- Gravity-aware orientation. The accelerometer is sampled every
frame and snapped to one of four 90° orientations (portrait,
upside-down, landscape-left, landscape-right). The running screen
rotates its content so the sand always falls from the physical
12 o'clock toward the physical 6 o'clock, and the pile always lives
on the gravity-down edge of the device. Hold the phone sideways and
the sand falls sideways — the way you would expect. - LED grid follows gravity too. The 16 × 32 LED grid fills from
the physical bottom regardless of how you hold the device, matching
the sand mode's behaviour. - Readable PAUSE / RESET pills. The bottom controls now sit on a
semi-transparent black rounded pill so they stay legible when the
white sand pile (or a fully lit LED grid) reaches them. The label
alpha also went up from 0.65 to 0.95 — they read clearly without
having to stand out against the background alone.
Implementation notes
- A
GravityOrientenum classifies device-frame gravity into the
four 90° orientations with hysteresis: the dominant axis has to
beat the other by 1.5× and exceed 5 m/s² before we snap, so a
phone held near the diagonal does not flip-flop every frame. - The running screen wraps its Canvas + overlay in a
BoxWithConstraintsthat picks logical dimensions (swapped for
landscape) and appliesgraphicsLayer(rotationZ = …)to the
inner box. The physics never sees device coordinates — it always
runs in a logical frame where+yis gravity-down. Tilt input
is projected throughGravityOrient.logicalGravitybefore being
passed toParticleSystem.update. ParticleSystem.initDimensionsnow rescalesheights[]
proportionally when the logical height changes, so an in-flight
pile keeps the same fill ratio across a rotation instead of
appearing empty or overflowing.- Tap detection lives on the unrotated outer container, so taps
resolve in device coordinates regardless of rotation while the
visual content rotates underneath.
v1.3.0
Flux Hourglass 1.3.0
A focused upgrade to the visual core of the timer — the sand pile now
behaves like sand instead of plateauing two-thirds of the way, the
display reacts to physical gravity, and a brand-new LED grid mode
sits alongside the original hourglass.
Highlights
- Pile fills the full screen. Previously the heap topped out at
roughly two thirds of the height regardless of duration. The pile
now tracks elapsed time 1:1, so when the timer ends the screen is
fully covered. A baseline catch-up keeps the pile honest even on
long durations where per-grain deposition would otherwise lag. - Softer, finer texture. Grains shrank from 3.0 dp to 1.4 dp and
the column count nearly doubled (50 → 90), giving the pile a much
smoother silhouette and a more powdery surface. - Real gyro response. The accelerometer is no longer cosmetic. The
falling stream bends with the gravity vector, and the heap on the
floor immediately slumps toward the lower side when you tilt the
device — strong tilts trigger an extra pour pass for a more decisive
reaction. - New LED mode. A "전광판" alternative renders the screen as a
16 × 32 grid of LED-style cells that light up bottom-to-top in
proportion to elapsed time. When every cell is lit, time is up.
Toggle betweenS A N DandL E Dfrom a new tab row at the top
of the setup screen; the choice is persisted alongside the last
duration. - Bolder typography. Secondary labels were close to invisible at
the old 0.25–0.4 alpha range. They have been lifted to 0.55–0.8 and
bumped fromThin/ExtraLighttoLight(withMediumon the
selected mode tab), so the chrome reads clearly without losing the
minimalist character.
Implementation notes
ParticleSystemnow owns a baseline lift step that adds the deficit
between the target average height(1 - remainingFraction) * hand
the current average back into every column. The lift is capped at
h * 0.004per frame so it never produces a visible jolt.pvxis no longer reset to zero each frame; particles integrate
horizontal gravity and despawn when they leave the canvas. Spawn
positions get mild jitter plus a small directional bias so the
stream visibly leans when the device is tilted.- Slumping uses an asymmetric threshold
(1.0 ± biasX)with four
passes per frame, escalating to six passes when|gravityX| > 2.0. - LED mode reuses the same touch-reveal + pause/reset overlay as the
sand mode through a sharedRunningOverlaycomposable; the renderer
itself is a singleCanvasthat lights cells in row-major order
from the bottom. TimerPreferencesgained amodefield backed by a string
preference (SAND/LED), defaulting toSANDfor first runs and
upgrading users.
v1.2.0
Flux Hourglass 1.2.0
Two ergonomic improvements that make the timer feel less like a one-shot
demo and more like a tool you reach for repeatedly.
Highlights
- Completion chime. When the timer finishes, a soft three-note chime
plays on the notification audio stream alongside the existing vibration
pulse. Volume is intentionally subdued so it does not intrude on
meditation or focus sessions; if the device is silent, only the
vibration fires. - Remembers your last duration. A small DataStore Preferences file
persists the most recent H R / M I N / S E C the user pressed
S T A R Twith. The next time the app launches, the pickers are
pre-seeded with that value — no extra preset tap needed.
Implementation notes
TimerPreferencesis a thin wrapper over aPreferencesDataStore
namedtimer_prefs. Reads are clamped to the same ranges as the picker
(0..99hours,0..59minutes/seconds) so corrupt or out-of-range
storage cannot crash the UI.- The chime uses
ToneGenerator(STREAM_NOTIFICATION, 70)so it respects
the user's silent/DnD profile and does not require any new permission. - Seed reads happen with
runBlocking { observe(context).first() }
during composition. The first launch hits the disk once; everything
after that is in the Compose state.
v1.1.0
Flux Hourglass 1.1.0
The first meaningful upgrade after the initial 1.0.0 release. Focuses on the
real-world ergonomics of using the hourglass as an everyday timer without
breaking the minimalist surface.
Highlights
- Quick presets. A row of
1m / 3m / 5m / 10m / 25m / 1htext chips sits
just under the title on the setup screen and populates the H R / M I N / S E C
pickers in one tap. They are deliberately rendered as thin labels — not
buttons — so they read as suggestions, not chrome. - Pause / Resume. The running screen now exposes a faint
P A U S E
control opposite the existingR E S E Tlabel. Pausing freezes the timer
exactly where it is; the new Paused screen shows the remainingHH : MM : SS
plus the percent of the duration still ahead, with a centeredR E S U M E
affordance that re-anchors the countdown from the moment you tap. - Screen stays on. While the timer is in the Running state the activity
setsFLAG_KEEP_SCREEN_ONso the display does not dim mid-run; the flag is
cleared the moment the timer reaches the Paused, Finished, or Setup state.
Implementation notes
TimerState.Paused(remainingMillis, totalMillis)is a new state. The view
model snapshots the remaining time on pause and re-anchorsendTimeto
System.currentTimeMillis() + remainingMillison resume, so the existing
monotonic-clock tick loop continues to be the single source of truth.- The
KeepScreenOn()composable is scoped to the running screen only and
cleans up viaDisposableEffect, so it does not leak when the timer
finishes, is reset, or the activity is torn down.