Minor fixes
Fix some bugs/problems here and there.
This commit is contained in:
parent
e7e683c3a9
commit
1980dafcff
14 changed files with 67 additions and 76 deletions
|
|
@ -90,7 +90,6 @@ dependencies {
|
||||||
|
|
||||||
// Fast-Scroll [Too lazy to make it myself]
|
// Fast-Scroll [Too lazy to make it myself]
|
||||||
implementation 'com.reddit:indicator-fast-scroll:1.3.0'
|
implementation 'com.reddit:indicator-fast-scroll:1.3.0'
|
||||||
|
|
||||||
// --- DEV ---
|
// --- DEV ---
|
||||||
|
|
||||||
// Lint
|
// Lint
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackMode
|
import org.oxycblt.auxio.playback.state.PlaybackMode
|
||||||
|
import org.oxycblt.auxio.ui.createToast
|
||||||
import org.oxycblt.auxio.ui.disable
|
import org.oxycblt.auxio.ui.disable
|
||||||
import org.oxycblt.auxio.ui.setupAlbumSongActions
|
import org.oxycblt.auxio.ui.setupAlbumSongActions
|
||||||
|
|
||||||
|
|
@ -80,9 +81,12 @@ class AlbumDetailFragment : DetailFragment() {
|
||||||
detailModel.currentAlbum.value!!, false
|
detailModel.currentAlbum.value!!, false
|
||||||
)
|
)
|
||||||
|
|
||||||
R.id.action_queue_add -> playbackModel.addToUserQueue(
|
R.id.action_queue_add -> {
|
||||||
detailModel.currentAlbum.value!!.songs
|
playbackModel.addToUserQueue(
|
||||||
)
|
detailModel.currentAlbum.value!!.songs
|
||||||
|
)
|
||||||
|
context.getString(R.string.label_queue_added).createToast(requireContext())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
@ -139,11 +143,9 @@ class AlbumDetailFragment : DetailFragment() {
|
||||||
binding.albumSongRecycler.post {
|
binding.albumSongRecycler.post {
|
||||||
lastHolder?.removePlaying()
|
lastHolder?.removePlaying()
|
||||||
|
|
||||||
lastHolder = (
|
lastHolder = binding.albumSongRecycler.getChildViewHolder(
|
||||||
binding.albumSongRecycler.getChildViewHolder(
|
binding.albumSongRecycler.getChildAt(pos)
|
||||||
binding.albumSongRecycler.getChildAt(pos)
|
) as AlbumSongAdapter.ViewHolder
|
||||||
) as AlbumSongAdapter.ViewHolder
|
|
||||||
)
|
|
||||||
|
|
||||||
lastHolder?.setPlaying(requireContext())
|
lastHolder?.setPlaying(requireContext())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ class GenreDetailFragment : DetailFragment() {
|
||||||
},
|
},
|
||||||
doOnLongClick = { data, view ->
|
doOnLongClick = { data, view ->
|
||||||
PopupMenu(requireContext(), view).setupArtistActions(
|
PopupMenu(requireContext(), view).setupArtistActions(
|
||||||
data, requireContext(), playbackModel
|
data, playbackModel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -186,8 +186,8 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
|
||||||
when (data) {
|
when (data) {
|
||||||
is Song -> menu.setupSongActions(data, requireContext(), playbackModel)
|
is Song -> menu.setupSongActions(data, requireContext(), playbackModel)
|
||||||
is Album -> menu.setupAlbumActions(data, requireContext(), playbackModel)
|
is Album -> menu.setupAlbumActions(data, requireContext(), playbackModel)
|
||||||
is Artist -> menu.setupArtistActions(data, requireContext(), playbackModel)
|
is Artist -> menu.setupArtistActions(data, playbackModel)
|
||||||
is Genre -> menu.setupGenreActions(data, requireContext(), playbackModel)
|
is Genre -> menu.setupGenreActions(data, playbackModel)
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.music.processing.MusicLoaderResponse
|
import org.oxycblt.auxio.music.processing.MusicLoaderResponse
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The intermediary [Fragment] that asks for the READ_EXTERNAL_STORAGE permission and runs
|
* An intermediary [Fragment] that asks for the READ_EXTERNAL_STORAGE permission and runs
|
||||||
* the music loading process in the background.
|
* the music loading process in the background.
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*/
|
*/
|
||||||
|
|
@ -93,6 +93,7 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
||||||
loadingModel.doGrant.observe(viewLifecycleOwner) {
|
loadingModel.doGrant.observe(viewLifecycleOwner) {
|
||||||
if (it) {
|
if (it) {
|
||||||
permLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
permLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
returnToLoading(binding)
|
||||||
loadingModel.doneWithGrant()
|
loadingModel.doneWithGrant()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,7 @@ class LoadingViewModel(private val app: Application) : ViewModel() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val musicStore = MusicStore.getInstance()
|
val musicStore = MusicStore.getInstance()
|
||||||
|
|
||||||
val response = withContext(Dispatchers.IO) {
|
val response = musicStore.load(app)
|
||||||
return@withContext musicStore.load(app)
|
|
||||||
}
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
mResponse.value = response
|
mResponse.value = response
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package org.oxycblt.auxio.music
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.music.processing.MusicLoader
|
import org.oxycblt.auxio.music.processing.MusicLoader
|
||||||
import org.oxycblt.auxio.music.processing.MusicLoaderResponse
|
import org.oxycblt.auxio.music.processing.MusicLoaderResponse
|
||||||
|
|
@ -36,56 +38,61 @@ class MusicStore private constructor() {
|
||||||
var loaded = false
|
var loaded = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
// Load/Sort the entire library.
|
/**
|
||||||
// ONLY CALL THIS FROM AN IO THREAD.
|
* Load/Sort the entire music library.
|
||||||
fun load(app: Application): MusicLoaderResponse {
|
* ***THIS SHOULD ONLY BE RAN FROM AN IO THREAD.***
|
||||||
Log.i(this::class.simpleName, "Starting initial music load...")
|
* @param app [Application] required to load the music.
|
||||||
|
*/
|
||||||
|
suspend fun load(app: Application): MusicLoaderResponse {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
Log.i(this::class.simpleName, "Starting initial music load...")
|
||||||
|
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
|
|
||||||
// Get the placeholder strings, which are used by MusicLoader & MusicSorter for
|
// Get the placeholder strings, which are used by MusicLoader & MusicSorter for
|
||||||
// any music that doesn't have metadata.
|
// any music that doesn't have metadata.
|
||||||
val genrePlaceholder = app.getString(R.string.placeholder_genre)
|
val genrePlaceholder = app.getString(R.string.placeholder_genre)
|
||||||
val artistPlaceholder = app.getString(R.string.placeholder_artist)
|
val artistPlaceholder = app.getString(R.string.placeholder_artist)
|
||||||
val albumPlaceholder = app.getString(R.string.placeholder_album)
|
val albumPlaceholder = app.getString(R.string.placeholder_album)
|
||||||
|
|
||||||
val loader = MusicLoader(
|
val loader = MusicLoader(
|
||||||
app.contentResolver,
|
app.contentResolver,
|
||||||
|
|
||||||
genrePlaceholder,
|
|
||||||
artistPlaceholder,
|
|
||||||
albumPlaceholder
|
|
||||||
)
|
|
||||||
|
|
||||||
if (loader.response == MusicLoaderResponse.DONE) {
|
|
||||||
// If the loading succeeds, then sort the songs and update the value
|
|
||||||
val sorter = MusicSorter(
|
|
||||||
loader.genres,
|
|
||||||
loader.artists,
|
|
||||||
loader.albums,
|
|
||||||
loader.songs,
|
|
||||||
|
|
||||||
genrePlaceholder,
|
genrePlaceholder,
|
||||||
artistPlaceholder,
|
artistPlaceholder,
|
||||||
albumPlaceholder
|
albumPlaceholder
|
||||||
)
|
)
|
||||||
|
|
||||||
mSongs = sorter.songs.toList()
|
if (loader.response == MusicLoaderResponse.DONE) {
|
||||||
mAlbums = sorter.albums.toList()
|
// If the loading succeeds, then sort the songs and update the value
|
||||||
mArtists = sorter.artists.toList()
|
val sorter = MusicSorter(
|
||||||
mGenres = sorter.genres.toList()
|
loader.genres,
|
||||||
|
loader.artists,
|
||||||
|
loader.albums,
|
||||||
|
loader.songs,
|
||||||
|
|
||||||
val elapsed = System.currentTimeMillis() - start
|
genrePlaceholder,
|
||||||
|
artistPlaceholder,
|
||||||
|
albumPlaceholder
|
||||||
|
)
|
||||||
|
|
||||||
Log.i(
|
mSongs = sorter.songs.toList()
|
||||||
this::class.simpleName,
|
mAlbums = sorter.albums.toList()
|
||||||
"Music load completed successfully in ${elapsed}ms."
|
mArtists = sorter.artists.toList()
|
||||||
)
|
mGenres = sorter.genres.toList()
|
||||||
|
|
||||||
loaded = true
|
val elapsed = System.currentTimeMillis() - start
|
||||||
|
|
||||||
|
Log.i(
|
||||||
|
this::class.simpleName,
|
||||||
|
"Music load completed successfully in ${elapsed}ms."
|
||||||
|
)
|
||||||
|
|
||||||
|
loaded = true
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.response
|
||||||
}
|
}
|
||||||
|
|
||||||
return loader.response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getListForShowMode(showMode: ShowMode): List<BaseModel> {
|
fun getListForShowMode(showMode: ShowMode): List<BaseModel> {
|
||||||
|
|
|
||||||
|
|
@ -118,8 +118,9 @@ class QueueAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clearUserQueue() {
|
private fun clearUserQueue() {
|
||||||
val nextQueueHeaderIndex = data.indexOfLast { it is Header }
|
val nextQueueHeaderIndex = data.indexOfLast { it is Header && !it.isAction }
|
||||||
val slice = data.slice(0 until nextQueueHeaderIndex)
|
Log.d(this::class.simpleName, nextQueueHeaderIndex.toString())
|
||||||
|
val slice = data.slice(0..nextQueueHeaderIndex.dec())
|
||||||
|
|
||||||
data.removeAll(slice)
|
data.removeAll(slice)
|
||||||
notifyItemRangeRemoved(0, slice.size)
|
notifyItemRangeRemoved(0, slice.size)
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,6 @@ class AlbumViewHolder private constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add indicators to song recycler items when they're being played?
|
|
||||||
|
|
||||||
class SongViewHolder private constructor(
|
class SongViewHolder private constructor(
|
||||||
private val binding: ItemSongBinding,
|
private val binding: ItemSongBinding,
|
||||||
doOnClick: (data: Song) -> Unit,
|
doOnClick: (data: Song) -> Unit,
|
||||||
|
|
|
||||||
|
|
@ -153,18 +153,10 @@ fun PopupMenu.setupAlbumActions(
|
||||||
*/
|
*/
|
||||||
fun PopupMenu.setupArtistActions(
|
fun PopupMenu.setupArtistActions(
|
||||||
artist: Artist,
|
artist: Artist,
|
||||||
context: Context,
|
|
||||||
playbackModel: PlaybackViewModel
|
playbackModel: PlaybackViewModel
|
||||||
) {
|
) {
|
||||||
setOnMenuItemClickListener {
|
setOnMenuItemClickListener {
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.action_queue_add -> {
|
|
||||||
playbackModel.addToUserQueue(artist.songs)
|
|
||||||
context.getString(R.string.label_queue_added).createToast(context)
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.action_play -> {
|
R.id.action_play -> {
|
||||||
playbackModel.playArtist(artist, false)
|
playbackModel.playArtist(artist, false)
|
||||||
true
|
true
|
||||||
|
|
@ -186,18 +178,10 @@ fun PopupMenu.setupArtistActions(
|
||||||
*/
|
*/
|
||||||
fun PopupMenu.setupGenreActions(
|
fun PopupMenu.setupGenreActions(
|
||||||
genre: Genre,
|
genre: Genre,
|
||||||
context: Context,
|
|
||||||
playbackModel: PlaybackViewModel
|
playbackModel: PlaybackViewModel
|
||||||
) {
|
) {
|
||||||
setOnMenuItemClickListener {
|
setOnMenuItemClickListener {
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.action_queue_add -> {
|
|
||||||
playbackModel.addToUserQueue(genre.songs)
|
|
||||||
context.getString(R.string.label_queue_added).createToast(context)
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.action_play -> {
|
R.id.action_play -> {
|
||||||
playbackModel.playGenre(genre, false)
|
playbackModel.playGenre(genre, false)
|
||||||
true
|
true
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:duration="@android:integer/config_mediumAnimTime"
|
android:duration="@integer/config_navAnimTime"
|
||||||
android:fromYDelta="0%"
|
android:fromYDelta="0%"
|
||||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
|
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
|
||||||
android:toYDelta="100%" />
|
android:toYDelta="100%" />
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:duration="@android:integer/config_mediumAnimTime"
|
android:duration="@integer/config_navAnimTime"
|
||||||
android:fromYDelta="100%"
|
android:fromYDelta="100%"
|
||||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
|
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
|
||||||
android:toYDelta="0%" />
|
android:toYDelta="0%" />
|
||||||
|
|
@ -4,7 +4,7 @@ https://stackoverflow.com/a/64314693/14143986
|
||||||
-->
|
-->
|
||||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<translate
|
<translate
|
||||||
android:duration="@android:integer/config_mediumAnimTime"
|
android:duration="@integer/config_navAnimTime"
|
||||||
android:fromYDelta="0.0%p"
|
android:fromYDelta="0.0%p"
|
||||||
android:toYDelta="0.0%p" />
|
android:toYDelta="0.0%p" />
|
||||||
</set>
|
</set>
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
maven { url "https://jitpack.io" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue