mirror of
https://github.com/Michatec/Radio.git
synced 2026-03-31 23:46:28 +02:00
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:
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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">
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user