detail: fix song deletion issue
Fix an issue where the song dialog would not properly close when the song it corresponded to was deleted.
This commit is contained in:
parent
35f05ed902
commit
201f132686
3 changed files with 48 additions and 24 deletions
|
@ -26,7 +26,6 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.detail.recycler.DiscHeader
|
import org.oxycblt.auxio.detail.recycler.DiscHeader
|
||||||
import org.oxycblt.auxio.detail.recycler.SortHeader
|
import org.oxycblt.auxio.detail.recycler.SortHeader
|
||||||
|
@ -54,8 +53,9 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
*/
|
*/
|
||||||
class DetailViewModel(application: Application) :
|
class DetailViewModel(application: Application) :
|
||||||
AndroidViewModel(application), MusicStore.Callback {
|
AndroidViewModel(application), MusicStore.Callback {
|
||||||
data class DetailSong(
|
data class DetailSong(val song: Song, val info: SongInfo?)
|
||||||
val song: Song,
|
|
||||||
|
data class SongInfo(
|
||||||
val bitrateKbps: Int?,
|
val bitrateKbps: Int?,
|
||||||
val sampleRate: Int?,
|
val sampleRate: Int?,
|
||||||
val resolvedMimeType: MimeType
|
val resolvedMimeType: MimeType
|
||||||
|
@ -156,12 +156,20 @@ class DetailViewModel(application: Application) :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateDetailSong(song: Song) {
|
private fun generateDetailSong(song: Song) {
|
||||||
viewModelScope.launch {
|
_currentSong.value = DetailSong(song, null)
|
||||||
_currentSong.value = withContext(Dispatchers.IO) { generateDetailSongImpl(song) }
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val info = generateDetailSongInfo(song)
|
||||||
|
|
||||||
|
// Theoretically, the song could have been changed again while we were
|
||||||
|
// extracting song information, so make sure that we can update the song
|
||||||
|
// in the first place.
|
||||||
|
if (_currentSong.value?.run { this.song.id } == song.id) {
|
||||||
|
_currentSong.value = DetailSong(song, info)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateDetailSongImpl(song: Song): DetailSong {
|
private fun generateDetailSongInfo(song: Song): SongInfo {
|
||||||
val extractor = MediaExtractor()
|
val extractor = MediaExtractor()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -169,7 +177,7 @@ class DetailViewModel(application: Application) :
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logW("Unable to extract song attributes.")
|
logW("Unable to extract song attributes.")
|
||||||
logW(e.stackTraceToString())
|
logW(e.stackTraceToString())
|
||||||
return DetailSong(song, null, null, song.mimeType)
|
return SongInfo(null, null, song.mimeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
val format = extractor.getTrackFormat(0)
|
val format = extractor.getTrackFormat(0)
|
||||||
|
@ -203,7 +211,7 @@ class DetailViewModel(application: Application) :
|
||||||
MimeType(song.mimeType.fromExtension, formatMimeType)
|
MimeType(song.mimeType.fromExtension, formatMimeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
return DetailSong(song, bitrate, sampleRate, resolvedMimeType)
|
return SongInfo(bitrate, sampleRate, resolvedMimeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshAlbumData(album: Album) {
|
private fun refreshAlbumData(album: Album) {
|
||||||
|
@ -258,6 +266,8 @@ class DetailViewModel(application: Application) :
|
||||||
val newSong = library.sanitize(song.song)
|
val newSong = library.sanitize(song.song)
|
||||||
if (newSong != null) {
|
if (newSong != null) {
|
||||||
generateDetailSong(newSong)
|
generateDetailSong(newSong)
|
||||||
|
} else {
|
||||||
|
_currentSong.value = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import android.text.format.Formatter
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.DialogSongDetailBinding
|
import org.oxycblt.auxio.databinding.DialogSongDetailBinding
|
||||||
|
@ -29,6 +30,7 @@ import org.oxycblt.auxio.ui.fragment.ViewBindingDialogFragment
|
||||||
import org.oxycblt.auxio.util.androidActivityViewModels
|
import org.oxycblt.auxio.util.androidActivityViewModels
|
||||||
import org.oxycblt.auxio.util.collectImmediately
|
import org.oxycblt.auxio.util.collectImmediately
|
||||||
import org.oxycblt.auxio.util.formatDuration
|
import org.oxycblt.auxio.util.formatDuration
|
||||||
|
import org.oxycblt.auxio.util.logD
|
||||||
|
|
||||||
class SongDetailDialog : ViewBindingDialogFragment<DialogSongDetailBinding>() {
|
class SongDetailDialog : ViewBindingDialogFragment<DialogSongDetailBinding>() {
|
||||||
private val detailModel: DetailViewModel by androidActivityViewModels()
|
private val detailModel: DetailViewModel by androidActivityViewModels()
|
||||||
|
@ -56,28 +58,38 @@ class SongDetailDialog : ViewBindingDialogFragment<DialogSongDetailBinding>() {
|
||||||
private fun updateSong(song: DetailViewModel.DetailSong?) {
|
private fun updateSong(song: DetailViewModel.DetailSong?) {
|
||||||
val binding = requireBinding()
|
val binding = requireBinding()
|
||||||
|
|
||||||
|
logD("$song")
|
||||||
|
|
||||||
if (song != null) {
|
if (song != null) {
|
||||||
|
if (song.info != null) {
|
||||||
binding.detailContainer.isGone = false
|
binding.detailContainer.isGone = false
|
||||||
binding.detailFileName.setText(song.song.path.name)
|
binding.detailFileName.setText(song.song.path.name)
|
||||||
binding.detailRelativeDir.setText(song.song.path.parent.resolveName(requireContext()))
|
binding.detailRelativeDir.setText(
|
||||||
binding.detailFormat.setText(song.resolvedMimeType.resolveName(requireContext()))
|
song.song.path.parent.resolveName(requireContext()))
|
||||||
binding.detailSize.setText(Formatter.formatFileSize(requireContext(), song.song.size))
|
binding.detailFormat.setText(
|
||||||
|
song.info.resolvedMimeType.resolveName(requireContext()))
|
||||||
|
binding.detailSize.setText(
|
||||||
|
Formatter.formatFileSize(requireContext(), song.song.size))
|
||||||
binding.detailDuration.setText(song.song.durationSecs.formatDuration(true))
|
binding.detailDuration.setText(song.song.durationSecs.formatDuration(true))
|
||||||
|
|
||||||
if (song.bitrateKbps != null) {
|
if (song.info.bitrateKbps != null) {
|
||||||
binding.detailBitrate.setText(getString(R.string.fmt_bitrate, song.bitrateKbps))
|
binding.detailBitrate.setText(
|
||||||
|
getString(R.string.fmt_bitrate, song.info.bitrateKbps))
|
||||||
} else {
|
} else {
|
||||||
binding.detailBitrate.setText(R.string.def_bitrate)
|
binding.detailBitrate.setText(R.string.def_bitrate)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (song.sampleRate != null) {
|
if (song.info.sampleRate != null) {
|
||||||
binding.detailSampleRate.setText(
|
binding.detailSampleRate.setText(
|
||||||
getString(R.string.fmt_sample_rate, song.sampleRate))
|
getString(R.string.fmt_sample_rate, song.info.sampleRate))
|
||||||
} else {
|
} else {
|
||||||
binding.detailSampleRate.setText(R.string.def_sample_rate)
|
binding.detailSampleRate.setText(R.string.def_sample_rate)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
binding.detailContainer.isGone = true
|
binding.detailContainer.isGone = true
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
findNavController().navigateUp()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,8 @@ import org.oxycblt.auxio.util.logD
|
||||||
* boilerplate you skip is not worth the insanity of androidx.
|
* boilerplate you skip is not worth the insanity of androidx.
|
||||||
*
|
*
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
|
*
|
||||||
|
* TODO: Add abstractions for services. notifications, and generations
|
||||||
*/
|
*/
|
||||||
class IndexerService : Service(), Indexer.Controller, Settings.Callback {
|
class IndexerService : Service(), Indexer.Controller, Settings.Callback {
|
||||||
private val indexer = Indexer.getInstance()
|
private val indexer = Indexer.getInstance()
|
||||||
|
|
Loading…
Reference in a new issue