feat(ui): implement edge-to-edge support and improve splash transition

- Enable edge-to-edge display in `MainActivity` and handle window insets in `PlayerFragment`.
- Add a fade-out animation when hiding the loading overlay.
- Sync player state with the controller during setup and reset playing state in preferences on service destruction.
- Simplify splash screen drawable and update background color attributes in layout.
- Remove manual navigation bar color overrides.
This commit is contained in:
2026-03-30 11:06:41 +02:00
parent 89b13e152c
commit dad709f5df
6 changed files with 39 additions and 15 deletions

View File

@@ -6,8 +6,10 @@ import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.isVisible
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.NavigationUI
@@ -28,6 +30,7 @@ class MainActivity : AppCompatActivity() {
/* Overrides onCreate from AppCompatActivity */
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
@@ -49,19 +52,31 @@ class MainActivity : AppCompatActivity() {
NavigationUI.setupWithNavController(toolbar, navController, appBarConfiguration)
supportActionBar?.hide()
// TV-specific loading logic
// TV-specific loading logic: Hide the overlay once the app is ready
if (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
Handler(Looper.getMainLooper()).postDelayed({
findViewById<View>(R.id.loading_layout)?.visibility = View.GONE
}, 1500)
hideLoadingOverlay()
}, 1200)
} else {
findViewById<View>(R.id.loading_layout)?.visibility = View.GONE
hideLoadingOverlay()
}
// register listener for changes in shared preferences
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
}
/* Hides the loading/splash overlay */
private fun hideLoadingOverlay() {
findViewById<View>(R.id.loading_layout)?.let { overlay ->
if (overlay.isVisible) {
overlay.animate()
.alpha(0f)
.setDuration(500)
.withEndAction { overlay.visibility = View.GONE }
}
}
}
/* Overrides onResume from AppCompatActivity */
override fun onResume() {
@@ -75,7 +90,6 @@ class MainActivity : AppCompatActivity() {
/* Overrides onSupportNavigateUp from AppCompatActivity */
override fun onSupportNavigateUp(): Boolean {
// Taken from: https://developer.android.com/guide/navigation/navigation-ui#action_bar
val navHostFragment = supportFragmentManager.findFragmentById(R.id.main_host_container) as NavHostFragment
val navController = navHostFragment.navController
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()

View File

@@ -22,6 +22,9 @@ import androidx.annotation.OptIn
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.media3.common.MediaItem
@@ -167,8 +170,11 @@ class PlayerFragment : Fragment(),
// hide action bar
(activity as AppCompatActivity).supportActionBar?.hide()
// set the same background color of the player sheet for the navigation bar
requireActivity().window.navigationBarColor = ContextCompat.getColor(requireActivity(), R.color.player_sheet_background)
ViewCompat.setOnApplyWindowInsetsListener(layout.rootView) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updatePadding(bottom = systemBars.bottom)
insets
}
// associate the ItemTouchHelper with the RecyclerView
itemTouchHelper = ItemTouchHelper(ItemTouchHelperCallback())
itemTouchHelper?.attachToRecyclerView(layout.recyclerView)
@@ -405,6 +411,13 @@ class PlayerFragment : Fragment(),
private fun setupController() {
val controller: MediaController = this.controller ?: return
controller.addListener(playerListener)
// Sync local playerState with actual controller state
if (playerState.isPlaying != controller.isPlaying) {
playerState.isPlaying = controller.isPlaying
updatePlayerViews()
}
requestMetadataUpdate()
// handle start intent
handleStartIntent()

View File

@@ -81,7 +81,8 @@ class PlayerService : MediaLibraryService() {
/* Overrides onDestroy from Service */
override fun onDestroy() {
// player.removeAnalyticsListener(analyticsListener)
// Reset playing state in preferences
PreferencesHelper.saveIsPlaying(false)
player.removeListener(playerListener)
player.release()
mediaLibrarySession.release()

View File

@@ -21,7 +21,6 @@ import com.michatec.radio.dialogs.ErrorDialog
import com.michatec.radio.dialogs.ThemeSelectionDialog
import com.michatec.radio.dialogs.YesNoDialog
import com.michatec.radio.helpers.*
import com.michatec.radio.helpers.AppThemeHelper.getColor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
@@ -46,7 +45,6 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
(activity as AppCompatActivity).supportActionBar?.show()
(activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)
(activity as AppCompatActivity).supportActionBar?.title = getString(R.string.fragment_settings_title)
requireActivity().window.navigationBarColor = getColor(requireContext(), android.R.attr.colorBackground)
}
/* Overrides onCreatePreferences from PreferenceFragmentCompat */