util: fix number issues
Fix issues where invalid durations and years would not be aliased to readable values.
This commit is contained in:
parent
e099d1c38c
commit
13730c303c
8 changed files with 55 additions and 20 deletions
|
@ -31,6 +31,7 @@ import org.oxycblt.auxio.music.ActionHeader
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.BaseModel
|
import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
|
import org.oxycblt.auxio.music.toDate
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.ActionHeaderViewHolder
|
import org.oxycblt.auxio.ui.ActionHeaderViewHolder
|
||||||
import org.oxycblt.auxio.ui.BaseViewHolder
|
import org.oxycblt.auxio.ui.BaseViewHolder
|
||||||
|
@ -154,7 +155,7 @@ class AlbumDetailAdapter(
|
||||||
|
|
||||||
binding.detailInfo.text = binding.detailInfo.context.getString(
|
binding.detailInfo.text = binding.detailInfo.context.getString(
|
||||||
R.string.fmt_three,
|
R.string.fmt_three,
|
||||||
data.year.toString(),
|
data.year.toDate(binding.detailInfo.context),
|
||||||
binding.detailInfo.context.getPlural(
|
binding.detailInfo.context.getPlural(
|
||||||
R.plurals.fmt_song_count,
|
R.plurals.fmt_song_count,
|
||||||
data.songs.size
|
data.songs.size
|
||||||
|
|
|
@ -26,6 +26,7 @@ import androidx.navigation.fragment.findNavController
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.home.HomeFragmentDirections
|
import org.oxycblt.auxio.home.HomeFragmentDirections
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
|
import org.oxycblt.auxio.music.toDate
|
||||||
import org.oxycblt.auxio.ui.AlbumViewHolder
|
import org.oxycblt.auxio.ui.AlbumViewHolder
|
||||||
import org.oxycblt.auxio.ui.DisplayMode
|
import org.oxycblt.auxio.ui.DisplayMode
|
||||||
import org.oxycblt.auxio.ui.Sort
|
import org.oxycblt.auxio.ui.Sort
|
||||||
|
@ -73,7 +74,7 @@ class AlbumListFragment : HomeListFragment() {
|
||||||
.first().uppercase()
|
.first().uppercase()
|
||||||
|
|
||||||
// Year -> Use Full Year
|
// Year -> Use Full Year
|
||||||
is Sort.ByYear -> album.year.toString()
|
is Sort.ByYear -> album.year.toDate(requireContext())
|
||||||
|
|
||||||
// Unsupported sort, error gracefully
|
// Unsupported sort, error gracefully
|
||||||
else -> ""
|
else -> ""
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
|
import org.oxycblt.auxio.music.toDate
|
||||||
import org.oxycblt.auxio.ui.DisplayMode
|
import org.oxycblt.auxio.ui.DisplayMode
|
||||||
import org.oxycblt.auxio.ui.SongViewHolder
|
import org.oxycblt.auxio.ui.SongViewHolder
|
||||||
import org.oxycblt.auxio.ui.Sort
|
import org.oxycblt.auxio.ui.Sort
|
||||||
|
@ -74,7 +75,7 @@ class SongListFragment : HomeListFragment() {
|
||||||
.first().uppercase()
|
.first().uppercase()
|
||||||
|
|
||||||
// Year -> Use Full Year
|
// Year -> Use Full Year
|
||||||
is Sort.ByYear -> song.album.year.toString()
|
is Sort.ByYear -> song.album.year.toDate(requireContext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ data class Song(
|
||||||
val album: Album get() = requireNotNull(mAlbum)
|
val album: Album get() = requireNotNull(mAlbum)
|
||||||
|
|
||||||
val seconds: Long get() = duration / 1000
|
val seconds: Long get() = duration / 1000
|
||||||
val formattedDuration: String get() = (duration / 1000).toDuration()
|
val formattedDuration: String get() = (duration / 1000).toDuration(false)
|
||||||
|
|
||||||
override val hash: Long get() {
|
override val hash: Long get() {
|
||||||
var result = name.hashCode().toLong()
|
var result = name.hashCode().toLong()
|
||||||
|
@ -129,7 +129,7 @@ data class Album(
|
||||||
val artist: Artist get() = requireNotNull(mArtist)
|
val artist: Artist get() = requireNotNull(mArtist)
|
||||||
|
|
||||||
val totalDuration: String get() =
|
val totalDuration: String get() =
|
||||||
songs.sumOf { it.seconds }.toDuration()
|
songs.sumOf { it.seconds }.toDuration(false)
|
||||||
|
|
||||||
fun linkArtist(artist: Artist) {
|
fun linkArtist(artist: Artist) {
|
||||||
mArtist = artist
|
mArtist = artist
|
||||||
|
@ -190,7 +190,7 @@ data class Genre(
|
||||||
val songs: List<Song> get() = mSongs
|
val songs: List<Song> get() = mSongs
|
||||||
|
|
||||||
val totalDuration: String get() =
|
val totalDuration: String get() =
|
||||||
songs.sumOf { it.seconds }.toDuration()
|
songs.sumOf { it.seconds }.toDuration(false)
|
||||||
|
|
||||||
fun linkSong(song: Song) {
|
fun linkSong(song: Song) {
|
||||||
mSongs.add(song)
|
mSongs.add(song)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.oxycblt.auxio.music
|
package org.oxycblt.auxio.music
|
||||||
|
|
||||||
import android.content.ContentUris
|
import android.content.ContentUris
|
||||||
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
|
@ -109,8 +110,14 @@ fun Long.toAlbumArtURI(): Uri {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a [Long] of seconds into a string duration.
|
* Convert a [Long] of seconds into a string duration.
|
||||||
|
* @param isElapsed Whether this duration is represents elapsed time. If this is false, then
|
||||||
|
* --:-- will be returned if the second value is 0.
|
||||||
*/
|
*/
|
||||||
fun Long.toDuration(): String {
|
fun Long.toDuration(isElapsed: Boolean): String {
|
||||||
|
if (!isElapsed && this == 0L) {
|
||||||
|
return "--:--"
|
||||||
|
}
|
||||||
|
|
||||||
var durationString = DateUtils.formatElapsedTime(this)
|
var durationString = DateUtils.formatElapsedTime(this)
|
||||||
|
|
||||||
// If the duration begins with a excess zero [e.g 01:42], then cut it off.
|
// If the duration begins with a excess zero [e.g 01:42], then cut it off.
|
||||||
|
@ -121,6 +128,14 @@ fun Long.toDuration(): String {
|
||||||
return durationString
|
return durationString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Int.toDate(context: Context): String {
|
||||||
|
return if (this == 0) {
|
||||||
|
context.getString(R.string.def_date)
|
||||||
|
} else {
|
||||||
|
toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- BINDING ADAPTERS ---
|
// --- BINDING ADAPTERS ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.oxycblt.auxio.databinding.ViewSeekBarBinding
|
||||||
import org.oxycblt.auxio.music.toDuration
|
import org.oxycblt.auxio.music.toDuration
|
||||||
import org.oxycblt.auxio.util.inflater
|
import org.oxycblt.auxio.util.inflater
|
||||||
import org.oxycblt.auxio.util.resolveAttr
|
import org.oxycblt.auxio.util.resolveAttr
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom view that bundles together a seekbar with a current duration and a total duration.
|
* A custom view that bundles together a seekbar with a current duration and a total duration.
|
||||||
|
@ -63,13 +62,29 @@ class PlaybackSeekBar @JvmOverloads constructor(
|
||||||
// Don't update the progress while we are seeking, that will make the SeekBar jump around.
|
// Don't update the progress while we are seeking, that will make the SeekBar jump around.
|
||||||
if (!isSeeking) {
|
if (!isSeeking) {
|
||||||
binding.seekBar.value = seconds.toFloat()
|
binding.seekBar.value = seconds.toFloat()
|
||||||
binding.playbackDurationCurrent.text = seconds.toDuration()
|
binding.playbackDurationCurrent.text = seconds.toDuration(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setDuration(seconds: Long) {
|
fun setDuration(seconds: Long) {
|
||||||
binding.seekBar.valueTo = max(seconds.toFloat(), 1f)
|
if (seconds == 0L) {
|
||||||
binding.playbackSongDuration.text = seconds.toDuration()
|
// One of two things occured:
|
||||||
|
// - Android couldn't get the total duration of the song
|
||||||
|
// - The duration of the song was so low as to be rounded to zero when converted
|
||||||
|
// to seconds.
|
||||||
|
// In either of these cases, the seekbar is more or less useless. Disable it.
|
||||||
|
binding.seekBar.apply {
|
||||||
|
valueTo = 1f
|
||||||
|
isEnabled = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.seekBar.apply {
|
||||||
|
valueTo = seconds.toFloat()
|
||||||
|
isEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.playbackSongDuration.text = seconds.toDuration(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartTrackingTouch(slider: Slider) {
|
override fun onStartTrackingTouch(slider: Slider) {
|
||||||
|
@ -85,7 +100,7 @@ class PlaybackSeekBar @JvmOverloads constructor(
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
// Don't actually seek yet when the user moves the progress bar, as to make our
|
// Don't actually seek yet when the user moves the progress bar, as to make our
|
||||||
// player seek during every movement is both inefficient and weird.
|
// player seek during every movement is both inefficient and weird.
|
||||||
binding.playbackDurationCurrent.text = value.toLong().toDuration()
|
binding.playbackDurationCurrent.text = value.toLong().toDuration(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -333,14 +333,14 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
|
||||||
private fun restorePlaybackState() {
|
private fun restorePlaybackState() {
|
||||||
logD("Attempting to restore playback state.")
|
logD("Attempting to restore playback state.")
|
||||||
|
|
||||||
mSong.value = playbackManager.song
|
onSongUpdate(playbackManager.song)
|
||||||
mPosition.value = playbackManager.position / 1000
|
onPositionUpdate(playbackManager.position)
|
||||||
mParent.value = playbackManager.parent
|
onParentUpdate(playbackManager.parent)
|
||||||
mNextUp.value = playbackManager.queue
|
onQueueUpdate(playbackManager.queue, playbackManager.index)
|
||||||
mMode.value = playbackManager.playbackMode
|
onModeUpdate(playbackManager.playbackMode)
|
||||||
mIsPlaying.value = playbackManager.isPlaying
|
onPlayingUpdate(playbackManager.isPlaying)
|
||||||
mIsShuffling.value = playbackManager.isShuffling
|
onShuffleUpdate(playbackManager.isShuffling)
|
||||||
mLoopMode.value = playbackManager.loopMode
|
onLoopUpdate(playbackManager.loopMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- OVERRIDES ---
|
// --- OVERRIDES ---
|
||||||
|
|
|
@ -99,6 +99,8 @@ class PlaybackStateManager private constructor() {
|
||||||
val position: Long get() = mPosition
|
val position: Long get() = mPosition
|
||||||
/** The current queue determined by [parent] and [playbackMode] */
|
/** The current queue determined by [parent] and [playbackMode] */
|
||||||
val queue: List<Song> get() = mQueue
|
val queue: List<Song> get() = mQueue
|
||||||
|
/** The current position in the queue */
|
||||||
|
val index: Int get() = mIndex
|
||||||
/** The current [PlaybackMode] */
|
/** The current [PlaybackMode] */
|
||||||
val playbackMode: PlaybackMode get() = mPlaybackMode
|
val playbackMode: PlaybackMode get() = mPlaybackMode
|
||||||
/** Whether playback is paused or not */
|
/** Whether playback is paused or not */
|
||||||
|
|
Loading…
Reference in a new issue