Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ android {

dependencies {
implementation 'androidx.core:core-ktx:1.9.0'
// Pinned rather than taken transitively from appcompat: enableEdgeToEdge() (used by both
// activities) landed in 1.8.0 and the edge-to-edge backport was refined for SDK 35 after it.
implementation 'androidx.activity:activity:1.9.3'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.10.0'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/dev/konraditurbe/osmosis/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import androidx.appcompat.app.AppCompatActivity
import android.net.LinkProperties
import android.net.Network
import androidx.activity.OnBackPressedCallback
import androidx.activity.enableEdgeToEdge
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
Expand Down Expand Up @@ -271,6 +272,12 @@ class MainActivity : AppCompatActivity(), OsmoScanner.Listener, GattClient.Liste

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Opt in explicitly instead of inheriting the targetSdk-35 default, so every supported release
// behaves the same way. Without it, API 29-34 keeps opaque system bars while 35+ goes
// edge-to-edge, which is two layouts to reason about and only one of them gets tested on the
// device in front of you. The bar icon polarity auto()-picks off the system dark mode, matching
// what @bool/osmo_light_system_bars does for the pre-35 theme.
enableEdgeToEdge()
setContentView(R.layout.activity_main)
// targetSdk 35+ forces edge-to-edge: android:statusBarColor/navigationBarColor in the theme are
// ignored and the window draws under the bars. Pad the root by the bar + cutout insets so the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import androidx.activity.SystemBarStyle
import androidx.activity.enableEdgeToEdge
import android.os.Bundle
import android.os.Handler
import android.os.Looper
Expand Down Expand Up @@ -99,28 +100,22 @@ class MediaPreviewActivity : AppCompatActivity() {
private lateinit var scrubTime: TextView
private val scrubFrames by lazy { ScrubFrames { Log.i("Osmosis", it) } }

/** Newest status-bar/cutout inset, kept so the floating scrub bubble can clamp against it. */
private var topInsetPx = 0

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Full-screen media viewer: black bars with light icons on every supported release (the app's
// cream theme sets the opposite, which is unreadable over a dark preview). SystemBarStyle.dark
// is what makes this one call cover both platform routes — it paints the scrim on the API 29-34
// devices, where the bars are opaque and used to need window.statusBarColor, and goes fully
// transparent over the layout's black root from 35 on, where those setters are ignored.
enableEdgeToEdge(
statusBarStyle = SystemBarStyle.dark(android.graphics.Color.BLACK),
navigationBarStyle = SystemBarStyle.dark(android.graphics.Color.BLACK),
)
setContentView(R.layout.activity_preview)

// Full-screen media viewer: light bar icons (the app's cream theme sets the opposite), so they
// stay readable over the dark preview.
//
// The bars go black by two different routes depending on the platform, and BOTH are needed
// because minSdk is 29. From targetSdk 35 the window is edge-to-edge, statusBarColor and
// navigationBarColor are ignored, and the bars are transparent over the layout's black root.
// On API 29-34 there is no edge-to-edge: the bars are opaque and painted from these setters,
// so dropping them leaves the theme's cream showing behind white icons.
if (Build.VERSION.SDK_INT < 35) {
@Suppress("DEPRECATION")
window.statusBarColor = android.graphics.Color.BLACK
@Suppress("DEPRECATION")
window.navigationBarColor = android.graphics.Color.BLACK
}
androidx.core.view.WindowCompat.getInsetsController(window, window.decorView).apply {
isAppearanceLightStatusBars = false
isAppearanceLightNavigationBars = false
}
// The media itself is meant to run full-bleed under the bars; only the overlays get inset. The
// insets are ADDED to each overlay's own layout padding, and the base padding is captured once
// so re-dispatches (rotation, IME, bar show/hide) don't accumulate.
Expand All @@ -134,6 +129,7 @@ class MediaPreviewActivity : AppCompatActivity() {
androidx.core.view.WindowInsetsCompat.Type.systemBars() or
androidx.core.view.WindowInsetsCompat.Type.displayCutout()
)
topInsetPx = bars.top
for ((v, base) in basePadding) {
val top = if (v in topOverlays) bars.top else 0
val bottom = if (v in bottomOverlays) bars.bottom else 0
Expand Down Expand Up @@ -648,7 +644,10 @@ class MediaPreviewActivity : AppCompatActivity() {
val margin = 8 * resources.displayMetrics.density
val maxX = (previewRoot.width - w - margin).coerceAtLeast(margin)
scrubPreview.translationX = (thumbX - w / 2f).coerceIn(margin, maxX)
scrubPreview.translationY = (bar[1] - root[1] - h - margin).coerceAtLeast(0f)
// Floor at the status-bar inset, not at 0: the root runs edge-to-edge, so a bubble pushed to
// the top of the window (short screen, tall bubble) would otherwise land under the clock.
scrubPreview.translationY =
(bar[1] - root[1] - h - margin).coerceAtLeast(topInsetPx.toFloat())
}

/** Once the thumb stops moving, pull the keyframe actually under it (debounced from the drag). */
Expand Down
11 changes: 7 additions & 4 deletions app/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
<item name="colorOnSurfaceVariant">@color/osmo_muted</item>
<item name="colorOutline">@color/osmo_track</item>

<!-- Bars follow the (possibly dynamic) window background; icon polarity flips with the theme.
statusBarColor/navigationBarColor are honoured on API 29-34 only: from targetSdk 35 the
window is edge-to-edge and the bars are transparent, so MainActivity pads the root by the
bar insets instead and the window background shows through. -->
<!-- Both activities call enableEdgeToEdge(), which installs its own bar scrims and icon
polarity, so these four items no longer decide what the bars look like on any supported
release — enableEdgeToEdge wins on API 29-34, and from targetSdk 35 the platform ignores
the two colours outright. They stay as the pre-inflation appearance (the window shows the
theme background behind the bars for the frame before the activity runs) and as the
fallback for any window that does not go through those two activities. Content is kept
clear of the bars by inset padding in the activities, never by these. -->
<item name="android:statusBarColor">?android:attr/colorBackground</item>
<item name="android:navigationBarColor">?android:attr/colorBackground</item>
<item name="android:windowLightStatusBar" tools:targetApi="m">@bool/osmo_light_system_bars</item>
Expand Down
Loading