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

View File

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

View File

@@ -81,7 +81,8 @@ class PlayerService : MediaLibraryService() {
/* Overrides onDestroy from Service */ /* Overrides onDestroy from Service */
override fun onDestroy() { override fun onDestroy() {
// player.removeAnalyticsListener(analyticsListener) // Reset playing state in preferences
PreferencesHelper.saveIsPlaying(false)
player.removeListener(playerListener) player.removeListener(playerListener)
player.release() player.release()
mediaLibrarySession.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.ThemeSelectionDialog
import com.michatec.radio.dialogs.YesNoDialog import com.michatec.radio.dialogs.YesNoDialog
import com.michatec.radio.helpers.* import com.michatec.radio.helpers.*
import com.michatec.radio.helpers.AppThemeHelper.getColor
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -46,7 +45,6 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
(activity as AppCompatActivity).supportActionBar?.show() (activity as AppCompatActivity).supportActionBar?.show()
(activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true) (activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)
(activity as AppCompatActivity).supportActionBar?.title = getString(R.string.fragment_settings_title) (activity as AppCompatActivity).supportActionBar?.title = getString(R.string.fragment_settings_title)
requireActivity().window.navigationBarColor = getColor(requireContext(), android.R.attr.colorBackground)
} }
/* Overrides onCreatePreferences from PreferenceFragmentCompat */ /* Overrides onCreatePreferences from PreferenceFragmentCompat */

View File

@@ -4,9 +4,6 @@
<item <item
android:width="160dp" android:width="160dp"
android:height="160dp" android:height="160dp"
android:gravity="center">
<bitmap
android:gravity="center" android:gravity="center"
android:src="@mipmap/ic_launcher" /> android:drawable="@mipmap/ic_launcher" />
</item>
</layer-list> </layer-list>

View File

@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?android:attr/colorBackground"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context=".MainActivity"> tools:context=".MainActivity">