From 4429ed4057326ed72d052ce9a30010a7f4354254 Mon Sep 17 00:00:00 2001 From: Michatec Date: Sun, 31 May 2026 23:06:57 +0200 Subject: [PATCH] refactor(ui): use anchor view for Snackbars above bottom sheet Replace manual bottom margin adjustments with `setAnchorView` for Snackbars to ensure they are positioned correctly above the bottom sheet on mobile devices. - In `LayoutHolder`, make `bottomSheet` public to allow access from other components. - In `PlayerFragment` and `MainActivity`, replace `FrameLayout.LayoutParams` modifications with `setAnchorView(bottomSheet)`. - Maintain standard Snackbar behavior for Android TV where the bottom sheet is not present. --- .../java/com/michatec/radio/MainActivity.kt | 5 +--- .../java/com/michatec/radio/PlayerFragment.kt | 27 ++++++++++++------- .../com/michatec/radio/ui/LayoutHolder.kt | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/michatec/radio/MainActivity.kt b/app/src/main/java/com/michatec/radio/MainActivity.kt index 33e71c4..b108974 100644 --- a/app/src/main/java/com/michatec/radio/MainActivity.kt +++ b/app/src/main/java/com/michatec/radio/MainActivity.kt @@ -13,7 +13,6 @@ import android.os.Handler import android.os.Looper import android.provider.Settings import android.view.View -import android.widget.FrameLayout import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity @@ -55,8 +54,6 @@ class MainActivity : AppCompatActivity() { R.string.snackbar_failed_permission_notification, Snackbar.LENGTH_LONG ) - val params = snackbar.view.layoutParams as FrameLayout.LayoutParams - params.bottomMargin = 300 // If the user permanently denied the permission, show a link to settings if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.POST_NOTIFICATIONS)) { snackbar.setAction(R.string.fragment_settings_title) { @@ -66,7 +63,7 @@ class MainActivity : AppCompatActivity() { startActivity(intent) } } - snackbar.view.layoutParams = params + snackbar.setAnchorView(findViewById(R.id.bottom_sheet)) snackbar.show() } } diff --git a/app/src/main/java/com/michatec/radio/PlayerFragment.kt b/app/src/main/java/com/michatec/radio/PlayerFragment.kt index 9352f49..2d44236 100644 --- a/app/src/main/java/com/michatec/radio/PlayerFragment.kt +++ b/app/src/main/java/com/michatec/radio/PlayerFragment.kt @@ -14,7 +14,6 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.FrameLayout import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.activity.result.ActivityResultLauncher @@ -150,7 +149,11 @@ class PlayerFragment : Fragment(), pickSingleMediaLauncher = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { imageUri -> if (imageUri == null) { - Snackbar.make(requireView(), R.string.toastalert_failed_picking_media, Snackbar.LENGTH_LONG).show() + val snackbar = Snackbar.make(requireView(), R.string.toastalert_failed_picking_media, Snackbar.LENGTH_LONG) + if (!isAndroidTV) { + snackbar.setAnchorView(layout.bottomSheet) + } + snackbar.show() } else { collection = CollectionHelper.setStationImageWithStationUuid( activity as Context, @@ -501,11 +504,17 @@ class PlayerFragment : Fragment(), // display the TimePicker dialog timePicker.show(requireActivity().supportFragmentManager, "tag") } - else -> Snackbar.make( - requireView(), - R.string.toastmessage_sleep_timer_unable_to_start, - Snackbar.LENGTH_SHORT - ).show() + else -> { + val snackbar = Snackbar.make( + requireView(), + R.string.toastmessage_sleep_timer_unable_to_start, + Snackbar.LENGTH_SHORT + ) + if (!isAndroidTV) { + snackbar.setAnchorView(layout.bottomSheet) + } + snackbar.show() + } } } @@ -860,9 +869,7 @@ class PlayerFragment : Fragment(), R.color.default_neutral_white)) if (!isAndroidTV) { - val params = snackbar.view.layoutParams as FrameLayout.LayoutParams - params.bottomMargin = 300 - snackbar.view.layoutParams = params + snackbar.setAnchorView(layout.bottomSheet) } snackbar.show() } diff --git a/app/src/main/java/com/michatec/radio/ui/LayoutHolder.kt b/app/src/main/java/com/michatec/radio/ui/LayoutHolder.kt index bf80363..dfdd369 100644 --- a/app/src/main/java/com/michatec/radio/ui/LayoutHolder.kt +++ b/app/src/main/java/com/michatec/radio/ui/LayoutHolder.kt @@ -42,7 +42,7 @@ data class LayoutHolder(var rootView: View) { /* Main class variables */ var recyclerView: RecyclerView = rootView.findViewById(R.id.station_list) val layoutManager: LinearLayoutManager - private var bottomSheet: ConstraintLayout? = rootView.findViewById(R.id.bottom_sheet) + var bottomSheet: ConstraintLayout? = rootView.findViewById(R.id.bottom_sheet) //private var sheetMetadataViews: Group private var sleepTimerRunningViews: Group? = rootView.findViewById(R.id.sleep_timer_running_views)