Add playback fragment
Add a fragment to show songs that are currently being played.
This commit is contained in:
parent
21ff93d5f0
commit
a72cb48c71
18 changed files with 266 additions and 103 deletions
|
@ -17,8 +17,8 @@ TODOs surrounded with !s are things I tried to do, but failed for reasons includ
|
|||
|
||||
/songs/
|
||||
|
||||
- Search when LibraryFragment isnt enabled
|
||||
- ? Sorting ?
|
||||
- ? Search ?
|
||||
- ? Fast Scrolling ?
|
||||
|
||||
/library/
|
||||
|
@ -28,9 +28,14 @@ TODOs surrounded with !s are things I tried to do, but failed for reasons includ
|
|||
- ? Add Nested Nav to Library ViewPager fragment [Hold fire on this until everything else is added, there could be sneaky bugs later on if you add it now] ?
|
||||
- ! Move Adapter functionality to ListAdapter [RecyclerView scrolls to middle/bottom when data is re-sorted] !
|
||||
|
||||
/playback/
|
||||
-
|
||||
|
||||
/other/
|
||||
- Highlight recycler items when they are being played
|
||||
|
||||
/bugs/
|
||||
- Fix issue where fast navigations will cause the app to not display anything
|
||||
|
||||
To be added:
|
||||
/prefs/
|
||||
/playback/
|
|
@ -47,9 +47,9 @@ dependencies {
|
|||
// --- SUPPORT ---
|
||||
|
||||
// General
|
||||
implementation 'androidx.core:core-ktx:1.3.1'
|
||||
implementation 'androidx.activity:activity:1.2.0-alpha08'
|
||||
implementation 'androidx.fragment:fragment:1.3.0-alpha08'
|
||||
implementation 'androidx.core:core-ktx:1.3.2'
|
||||
implementation 'androidx.activity:activity:1.2.0-beta01'
|
||||
implementation 'androidx.fragment:fragment:1.3.0-beta01'
|
||||
|
||||
// Layout
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||
|
@ -71,7 +71,7 @@ dependencies {
|
|||
implementation 'io.coil-kt:coil:0.13.0'
|
||||
|
||||
// Material
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha02'
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
||||
|
||||
// Lint
|
||||
ktlint "com.pinterest:ktlint:0.37.2"
|
||||
|
|
|
@ -41,7 +41,7 @@ class MainFragment : Fragment() {
|
|||
val binding = FragmentMainBinding.inflate(inflater)
|
||||
|
||||
// If musicModel was cleared while the app was closed [Likely due to Auxio being suspended
|
||||
// in the background], then navigate back to loading to reload the music.
|
||||
// in the background], then navigate back to LoadingFragment to reload the music.
|
||||
if (musicModel.response.value == null) {
|
||||
findNavController().navigate(MainFragmentDirections.actionReturnToLoading())
|
||||
|
||||
|
@ -57,7 +57,7 @@ class MainFragment : Fragment() {
|
|||
|
||||
// --- UI SETUP ---
|
||||
|
||||
binding.lifecycleOwner = viewLifecycleOwner
|
||||
binding.lifecycleOwner = this
|
||||
binding.mainViewPager.adapter = PagerAdapter()
|
||||
|
||||
// Link the ViewPager & Tab View
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.oxycblt.auxio.R
|
|||
import org.oxycblt.auxio.databinding.FragmentAlbumDetailBinding
|
||||
import org.oxycblt.auxio.detail.adapters.DetailSongAdapter
|
||||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.recycler.ClickListener
|
||||
import org.oxycblt.auxio.theme.applyDivider
|
||||
import org.oxycblt.auxio.theme.disable
|
||||
|
@ -21,6 +22,7 @@ class AlbumDetailFragment : Fragment() {
|
|||
|
||||
private val args: AlbumDetailFragmentArgs by navArgs()
|
||||
private val detailModel: DetailViewModel by activityViewModels()
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -45,7 +47,7 @@ class AlbumDetailFragment : Fragment() {
|
|||
|
||||
val songAdapter = DetailSongAdapter(
|
||||
ClickListener {
|
||||
Log.d(this::class.simpleName, it.name)
|
||||
playbackModel.updateSong(it)
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -17,13 +17,15 @@ import androidx.transition.TransitionManager
|
|||
import org.oxycblt.auxio.MainFragmentDirections
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentLibraryBinding
|
||||
import org.oxycblt.auxio.library.recycler.LibraryAdapter
|
||||
import org.oxycblt.auxio.library.recycler.SearchAdapter
|
||||
import org.oxycblt.auxio.library.adapters.LibraryAdapter
|
||||
import org.oxycblt.auxio.library.adapters.SearchAdapter
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.BaseModel
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.recycler.ShowMode
|
||||
import org.oxycblt.auxio.theme.applyColor
|
||||
import org.oxycblt.auxio.theme.applyDivider
|
||||
|
@ -36,6 +38,7 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
|
|||
}
|
||||
|
||||
private val libraryModel: LibraryViewModel by activityViewModels()
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -173,6 +176,13 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
|
|||
}
|
||||
|
||||
private fun navToItem(baseModel: BaseModel) {
|
||||
// If the item is a song [That was selected through search], then update the playback
|
||||
// to that song instead of doing any naviagation
|
||||
if (baseModel is Song) {
|
||||
playbackModel.updateSong(baseModel)
|
||||
return
|
||||
}
|
||||
|
||||
if (!libraryModel.isNavigating) {
|
||||
libraryModel.updateNavigationStatus(true)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.oxycblt.auxio.library.recycler
|
||||
package org.oxycblt.auxio.library.adapters
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -13,7 +13,8 @@ import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder
|
|||
import org.oxycblt.auxio.recycler.viewholders.GenreViewHolder
|
||||
|
||||
// A ListAdapter that can contain three different types of ViewHolders depending
|
||||
// the showmode given. It cannot display multiple types of viewholders *at once*.
|
||||
// the ShowMode given.
|
||||
// It cannot display multiple ViewHolders *at once* however. That's what SearchAdapter is for.
|
||||
class LibraryAdapter(
|
||||
private val showMode: ShowMode,
|
||||
private val doOnClick: (BaseModel) -> Unit
|
|
@ -1,4 +1,4 @@
|
|||
package org.oxycblt.auxio.library.recycler
|
||||
package org.oxycblt.auxio.library.adapters
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.ListAdapter
|
|
@ -20,62 +20,44 @@ import org.oxycblt.auxio.music.processing.MusicLoaderResponse
|
|||
|
||||
class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
||||
|
||||
// LoadingFragment is [hopefully] going to be the first one to have to create musicModel,
|
||||
// so pass a factory instance so that the model has access to the application resources.
|
||||
private val musicModel: MusicViewModel by activityViewModels {
|
||||
MusicViewModel.Factory(requireActivity().application)
|
||||
}
|
||||
|
||||
private lateinit var binding: FragmentLoadingBinding
|
||||
private lateinit var permLauncher: ActivityResultLauncher<String>
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = FragmentLoadingBinding.inflate(inflater)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.musicModel = musicModel
|
||||
|
||||
musicModel.response.observe(
|
||||
viewLifecycleOwner,
|
||||
{ response ->
|
||||
onMusicLoadResponse(response)
|
||||
}
|
||||
)
|
||||
|
||||
musicModel.doReload.observe(
|
||||
viewLifecycleOwner,
|
||||
{ retry ->
|
||||
onRetry(retry)
|
||||
}
|
||||
)
|
||||
|
||||
musicModel.doGrant.observe(
|
||||
viewLifecycleOwner,
|
||||
{ grant ->
|
||||
onGrant(grant)
|
||||
}
|
||||
)
|
||||
val binding = FragmentLoadingBinding.inflate(inflater)
|
||||
|
||||
// Set up the permission launcher, as its disallowed outside of onCreate.
|
||||
permLauncher =
|
||||
val permLauncher =
|
||||
registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { granted: Boolean ->
|
||||
// If its actually granted, restart the loading process again.
|
||||
if (granted) {
|
||||
wipeViews()
|
||||
wipeViews(binding)
|
||||
|
||||
musicModel.reload()
|
||||
}
|
||||
}
|
||||
|
||||
// --- UI SETUP ---
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.musicModel = musicModel
|
||||
|
||||
// --- VIEWMODEL SETUP ---
|
||||
|
||||
musicModel.response.observe(viewLifecycleOwner) { onMusicLoadResponse(it, binding) }
|
||||
musicModel.doReload.observe(viewLifecycleOwner) { onRetry(it, binding) }
|
||||
musicModel.doGrant.observe(viewLifecycleOwner) { onGrant(it, permLauncher) }
|
||||
|
||||
// Force an error screen if the permissions are denied or the prompt needs to be shown.
|
||||
if (checkPerms()) {
|
||||
onNoPerms()
|
||||
onNoPerms(binding)
|
||||
} else {
|
||||
musicModel.go()
|
||||
}
|
||||
|
@ -96,13 +78,15 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
|||
) == PackageManager.PERMISSION_DENIED
|
||||
}
|
||||
|
||||
private fun onMusicLoadResponse(response: MusicLoaderResponse?) {
|
||||
private fun onMusicLoadResponse(
|
||||
response: MusicLoaderResponse?,
|
||||
binding: FragmentLoadingBinding
|
||||
) {
|
||||
if (response == MusicLoaderResponse.DONE) {
|
||||
findNavController().navigate(
|
||||
LoadingFragmentDirections.actionToMain()
|
||||
)
|
||||
} else {
|
||||
binding.let { binding ->
|
||||
binding.loadingErrorText.text =
|
||||
if (response == MusicLoaderResponse.NO_MUSIC)
|
||||
getString(R.string.error_no_music)
|
||||
|
@ -112,15 +96,13 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
|||
// If the response wasn't a success, then show the specific error message
|
||||
// depending on which error response was given, along with a retry button
|
||||
binding.loadingBar.visibility = View.GONE
|
||||
|
||||
binding.loadingErrorText.visibility = View.VISIBLE
|
||||
binding.loadingErrorIcon.visibility = View.VISIBLE
|
||||
binding.loadingRetryButton.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onNoPerms() {
|
||||
private fun onNoPerms(binding: FragmentLoadingBinding) {
|
||||
// If there are no perms, switch out the view elements as if an error screen was being
|
||||
// shown, but show the label that Auxio needs to read external storage to function,
|
||||
// along with a GRANT button
|
||||
|
@ -133,15 +115,15 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
|||
binding.loadingErrorText.text = getString(R.string.error_no_perms)
|
||||
}
|
||||
|
||||
private fun onRetry(retry: Boolean) {
|
||||
private fun onRetry(retry: Boolean, binding: FragmentLoadingBinding) {
|
||||
if (retry) {
|
||||
wipeViews()
|
||||
wipeViews(binding)
|
||||
|
||||
musicModel.doneWithReload()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onGrant(grant: Boolean) {
|
||||
private fun onGrant(grant: Boolean, permLauncher: ActivityResultLauncher<String>) {
|
||||
if (grant) {
|
||||
permLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
|
||||
|
@ -150,7 +132,7 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
|||
}
|
||||
|
||||
// Wipe views and switch back to the plain ProgressBar
|
||||
private fun wipeViews() {
|
||||
private fun wipeViews(binding: FragmentLoadingBinding) {
|
||||
binding.loadingBar.visibility = View.VISIBLE
|
||||
binding.loadingErrorText.visibility = View.GONE
|
||||
binding.loadingErrorIcon.visibility = View.GONE
|
||||
|
|
|
@ -13,9 +13,9 @@ sealed class BaseModel {
|
|||
data class Song(
|
||||
override val id: Long = -1,
|
||||
override var name: String,
|
||||
val albumId: Long,
|
||||
val track: Int,
|
||||
val duration: Long,
|
||||
val albumId: Long = -1,
|
||||
val track: Int = -1,
|
||||
val duration: Long = 0,
|
||||
) : BaseModel() {
|
||||
lateinit var album: Album
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package org.oxycblt.auxio.playback
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import org.oxycblt.auxio.databinding.FragmentCompactPlaybackBinding
|
||||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
|
||||
class CompactPlaybackFragment : Fragment() {
|
||||
private val musicModel: MusicViewModel by activityViewModels {
|
||||
MusicViewModel.Factory(requireActivity().application)
|
||||
}
|
||||
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val binding = FragmentCompactPlaybackBinding.inflate(inflater)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
// Put a placeholder song in the binding & hide the playback fragment initially,
|
||||
// as for some reason the attach event doesn't register anymore w/LiveData
|
||||
binding.song = musicModel.songs.value!![0]
|
||||
binding.root.visibility = View.GONE
|
||||
|
||||
playbackModel.currentSong.observe(viewLifecycleOwner) {
|
||||
if (it == null) {
|
||||
Log.d(this::class.simpleName, "Hiding playback bar due to no song being played.")
|
||||
|
||||
binding.root.visibility = View.GONE
|
||||
} else {
|
||||
Log.d(this::class.simpleName, "Updating song display to ${it.name}")
|
||||
|
||||
binding.song = it
|
||||
|
||||
binding.root.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(this::class.simpleName, "Fragment Created")
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.oxycblt.auxio.playback
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.oxycblt.auxio.music.Song
|
||||
|
||||
class PlaybackViewModel : ViewModel() {
|
||||
private val mCurrentSong = MutableLiveData<Song>()
|
||||
val currentSong: LiveData<Song> get() = mCurrentSong
|
||||
|
||||
fun updateSong(song: Song) {
|
||||
mCurrentSong.value = song
|
||||
}
|
||||
}
|
|
@ -9,15 +9,17 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.activityViewModels
|
||||
import org.oxycblt.auxio.databinding.FragmentSongsBinding
|
||||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.recycler.ClickListener
|
||||
import org.oxycblt.auxio.theme.applyDivider
|
||||
|
||||
class SongsFragment : Fragment() {
|
||||
|
||||
private val musicModel: MusicViewModel by activityViewModels {
|
||||
MusicViewModel.Factory(requireActivity().application)
|
||||
}
|
||||
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
@ -31,7 +33,7 @@ class SongsFragment : Fragment() {
|
|||
adapter = SongAdapter(
|
||||
musicModel.songs.value!!,
|
||||
ClickListener { song ->
|
||||
Log.d(this::class.simpleName, song.name)
|
||||
playbackModel.updateSong(song)
|
||||
}
|
||||
)
|
||||
applyDivider()
|
||||
|
|
|
@ -87,7 +87,7 @@ fun resolveAttr(context: Context, @AttrRes attr: Int): Int {
|
|||
}
|
||||
|
||||
// Apply a color to a Menu Item
|
||||
fun MenuItem.applyColor(@ColorRes color: Int) {
|
||||
fun MenuItem.applyColor(@ColorInt color: Int) {
|
||||
SpannableString(title).apply {
|
||||
setSpan(ForegroundColorSpan(color), 0, length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
title = this
|
||||
|
|
78
app/src/main/res/layout/fragment_compact_playback.xml
Normal file
78
app/src/main/res/layout/fragment_compact_playback.xml
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".playback.CompactPlaybackFragment">
|
||||
|
||||
<data>
|
||||
|
||||
<variable
|
||||
name="song"
|
||||
type="org.oxycblt.auxio.music.Song" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:animateLayoutChanges="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/song_progress"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/playback_progress_size"
|
||||
android:clickable="false"
|
||||
android:progressBackgroundTint="?android:attr/colorControlNormal"
|
||||
android:progressTint="?android:attr/colorPrimary"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:progress="70" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/album_cover"
|
||||
android:layout_width="@dimen/cover_size_compact"
|
||||
android:layout_height="@dimen/cover_size_compact"
|
||||
android:contentDescription="@{@string/description_album_cover(song.name)}"
|
||||
android:layout_margin="@dimen/margin_smallish"
|
||||
app:coverArt="@{song}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_progress"
|
||||
tools:src="@drawable/ic_song" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/song_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter_semibold"
|
||||
android:text="@{song.name}"
|
||||
android:layout_marginStart="@dimen/margin_smallish"
|
||||
android:textAppearance="@style/TextAppearance.SmallHeader"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
app:layout_constraintBottom_toTopOf="@+id/song_info"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="Song Name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/song_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/margin_smallish"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
|
||||
android:text="@{@string/format_info(song.album.name, song.album.artist.name)}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/album_cover"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_name"
|
||||
tools:text="Artist / Album" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
|
@ -15,6 +15,13 @@
|
|||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/playback_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:name="org.oxycblt.auxio.playback.CompactPlaybackFragment"
|
||||
android:elevation="@dimen/elevation_normal" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/main_tabs"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -29,7 +36,8 @@
|
|||
app:tabIndicator="@drawable/indicator"
|
||||
app:tabIndicatorColor="?android:attr/colorPrimary"
|
||||
app:tabMode="fixed"
|
||||
app:tabRippleColor="@color/selection_color" />
|
||||
app:tabRippleColor="@color/selection_color"
|
||||
tools:background="@color/control_color" />
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
|
@ -12,10 +12,10 @@
|
|||
<action
|
||||
android:id="@+id/action_to_main"
|
||||
app:destination="@id/main_fragment"
|
||||
app:enterAnim="@anim/fragment_fade_enter"
|
||||
app:exitAnim="@anim/fragment_fade_exit"
|
||||
app:popEnterAnim="@anim/fragment_fade_enter"
|
||||
app:popExitAnim="@anim/fragment_fade_exit"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:popUpTo="@id/loading_fragment"
|
||||
app:popUpToInclusive="true"
|
||||
app:launchSingleTop="true" />
|
||||
|
@ -27,24 +27,24 @@
|
|||
tools:layout="@layout/fragment_main">
|
||||
<action
|
||||
android:id="@+id/action_show_artist"
|
||||
app:enterAnim="@anim/fragment_fade_enter"
|
||||
app:exitAnim="@anim/fragment_fade_exit"
|
||||
app:popEnterAnim="@anim/fragment_fade_enter"
|
||||
app:popExitAnim="@anim/fragment_fade_exit"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:destination="@id/artist_detail_fragment" />
|
||||
<action
|
||||
android:id="@+id/action_show_album"
|
||||
app:enterAnim="@anim/fragment_fade_enter"
|
||||
app:exitAnim="@anim/fragment_fade_exit"
|
||||
app:popEnterAnim="@anim/fragment_fade_enter"
|
||||
app:popExitAnim="@anim/fragment_fade_exit"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:destination="@id/album_detail_fragment" />
|
||||
<action
|
||||
android:id="@+id/action_show_genre"
|
||||
app:enterAnim="@anim/fragment_fade_enter"
|
||||
app:exitAnim="@anim/fragment_fade_exit"
|
||||
app:popEnterAnim="@anim/fragment_fade_enter"
|
||||
app:popExitAnim="@anim/fragment_fade_exit"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:destination="@id/genreDetailFragment" />
|
||||
<action
|
||||
android:id="@+id/action_return_to_loading"
|
||||
|
@ -62,10 +62,10 @@
|
|||
app:argType="long" />
|
||||
<action
|
||||
android:id="@+id/action_show_album"
|
||||
app:enterAnim="@anim/fragment_fade_enter"
|
||||
app:exitAnim="@anim/fragment_fade_exit"
|
||||
app:popEnterAnim="@anim/fragment_fade_enter"
|
||||
app:popExitAnim="@anim/fragment_fade_exit"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:destination="@id/album_detail_fragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
|
@ -81,10 +81,10 @@
|
|||
app:argType="boolean" />
|
||||
<action
|
||||
android:id="@+id/action_show_parent_artist"
|
||||
app:enterAnim="@anim/fragment_fade_enter"
|
||||
app:exitAnim="@anim/fragment_fade_exit"
|
||||
app:popEnterAnim="@anim/fragment_fade_enter"
|
||||
app:popExitAnim="@anim/fragment_fade_exit"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:destination="@id/artist_detail_fragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
|
@ -94,10 +94,10 @@
|
|||
tools:layout="@layout/fragment_genre_detail">
|
||||
<action
|
||||
android:id="@+id/action_show_artist"
|
||||
app:enterAnim="@anim/fragment_fade_enter"
|
||||
app:exitAnim="@anim/fragment_fade_exit"
|
||||
app:popEnterAnim="@anim/fragment_fade_enter"
|
||||
app:popExitAnim="@anim/fragment_fade_exit"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:destination="@id/artist_detail_fragment" />
|
||||
<argument
|
||||
android:name="genreId"
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
<dimen name="padding_medium">16dp</dimen>
|
||||
|
||||
<dimen name="margin_small">8dp</dimen>
|
||||
<dimen name="margin_smallish">10dp</dimen>
|
||||
<dimen name="margin_medium">16dp</dimen>
|
||||
|
||||
<dimen name="status_icon_size">48dp</dimen>
|
||||
|
||||
<dimen name="tab_menu_size">40dp</dimen>
|
||||
|
||||
<dimen name="cover_size_small">36dp</dimen>
|
||||
<dimen name="cover_size_compact">44dp</dimen>
|
||||
<dimen name="cover_size_normal">56dp</dimen>
|
||||
<dimen name="cover_size_large">68dp</dimen>
|
||||
|
@ -26,5 +28,7 @@
|
|||
|
||||
<dimen name="divider_ripple_size">18dp</dimen>
|
||||
|
||||
<dimen name="playback_progress_size">2dp</dimen>
|
||||
|
||||
<dimen name="elevation_normal">4dp</dimen>
|
||||
</resources>
|
|
@ -27,6 +27,10 @@
|
|||
<item name="android:textSize">@dimen/detail_header_size_max</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.SmallHeader" parent="TextAppearance.MaterialComponents.Body2">
|
||||
<item name="android:fontFamily">@font/inter_semibold</item>
|
||||
</style>
|
||||
|
||||
<style name="AppThemeOverlay.Popup" parent="ThemeOverlay.AppCompat.DayNight">
|
||||
<item name="android:colorBackground">@color/background</item>
|
||||
<item name="colorControlHighlight">@color/selection_color</item>
|
||||
|
|
Loading…
Reference in a new issue