music: show months in UI

If a song/album date has a month value, show it in the UI.

This hopefully improves the date experience for more well-tagged
libraries. Due to date limitations however, it is limited to
Android O onwards for now.
This commit is contained in:
Alexander Capehart 2022-10-20 18:03:59 -06:00
parent f4d25f81cc
commit daf1cf8590
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
28 changed files with 77 additions and 37 deletions

View file

@ -22,6 +22,7 @@
- Reshuffling the queue will no longer drop any songs you have added/removed - Reshuffling the queue will no longer drop any songs you have added/removed
- Allowed light/dark theme to be customized on Android 12+ - Allowed light/dark theme to be customized on Android 12+
- All information now scrolls in the playback view - All information now scrolls in the playback view
- A month is now shown for song/album dates when available (Android O+ only)
#### What's Fixed #### What's Fixed
- Fixed issue where the scroll popup would not display correctly in landscape mode [#230] - Fixed issue where the scroll popup would not display correctly in landscape mode [#230]

View file

@ -120,7 +120,7 @@ private class AlbumDetailViewHolder private constructor(private val binding: Ite
binding.detailInfo.apply { binding.detailInfo.apply {
val date = val date =
item.date?.resolveYear(context) item.date?.resolveDate(context)
?: context.getString(R.string.def_date) ?: context.getString(R.string.def_date)
val songCount = context.getPlural(R.plurals.fmt_song_count, item.songs.size) val songCount = context.getPlural(R.plurals.fmt_song_count, item.songs.size)

View file

@ -159,7 +159,7 @@ private class ArtistAlbumViewHolder private constructor(private val binding: Ite
binding.parentImage.bind(item) binding.parentImage.bind(item)
binding.parentName.text = item.resolveName(binding.context) binding.parentName.text = item.resolveName(binding.context)
binding.parentInfo.text = binding.parentInfo.text =
item.date?.resolveYear(binding.context) item.date?.resolveDate(binding.context)
?: binding.context.getString(R.string.def_date) ?: binding.context.getString(R.string.def_date)
// binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) } // binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) }

View file

@ -70,7 +70,7 @@ class AlbumListFragment : HomeListFragment<Album>() {
is Sort.Mode.ByArtist -> album.artists[0].collationKey?.run { sourceString.first().uppercase() } is Sort.Mode.ByArtist -> album.artists[0].collationKey?.run { sourceString.first().uppercase() }
// Year -> Use Full Year // Year -> Use Full Year
is Sort.Mode.ByDate -> album.date?.resolveYear(requireContext()) is Sort.Mode.ByDate -> album.date?.resolveDate(requireContext())
// Duration -> Use formatted duration // Duration -> Use formatted duration
is Sort.Mode.ByDuration -> album.durationMs.formatDurationMs(false) is Sort.Mode.ByDuration -> album.durationMs.formatDurationMs(false)

View file

@ -86,7 +86,7 @@ class SongListFragment : HomeListFragment<Song>() {
is Sort.Mode.ByAlbum -> song.album.collationKey?.run { sourceString.first().uppercase() } is Sort.Mode.ByAlbum -> song.album.collationKey?.run { sourceString.first().uppercase() }
// Year -> Use Full Year // Year -> Use Full Year
is Sort.Mode.ByDate -> song.album.date?.resolveYear(requireContext()) is Sort.Mode.ByDate -> song.album.date?.resolveDate(requireContext())
// Duration -> Use formatted duration // Duration -> Use formatted duration
is Sort.Mode.ByDuration -> song.durationMs.formatDurationMs(false) is Sort.Mode.ByDuration -> song.durationMs.formatDurationMs(false)

View file

@ -18,10 +18,21 @@
package org.oxycblt.auxio.music package org.oxycblt.auxio.music
import android.content.Context import android.content.Context
import android.os.Build
import android.text.format.DateUtils
import androidx.annotation.RequiresApi
import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.playback.secsToMs
import org.oxycblt.auxio.util.inRangeOrNull import org.oxycblt.auxio.util.inRangeOrNull
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE
import org.oxycblt.auxio.util.nonZeroOrNull import org.oxycblt.auxio.util.nonZeroOrNull
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalQueries
import java.util.Formatter
import java.util.Locale
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -60,10 +71,7 @@ class Date private constructor(private val tokens: List<Int>) : Comparable<Date>
} }
} }
val year = tokens[0] private val year = tokens[0]
/** Resolve the year field in a way suitable for the UI. */
fun resolveYear(context: Context) = context.getString(R.string.fmt_number, year)
private val month = tokens.getOrNull(1) private val month = tokens.getOrNull(1)
@ -75,6 +83,37 @@ class Date private constructor(private val tokens: List<Int>) : Comparable<Date>
private val second = tokens.getOrNull(5) private val second = tokens.getOrNull(5)
fun resolveDate(context: Context): String {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return try {
resolveFullDate(context).also { logD(it) }
} catch (e: Exception) {
logE("Failed to format a full date")
logE(e.stackTraceToString())
return resolveYear(context)
}
} else {
return resolveYear(context)
}
}
@RequiresApi(Build.VERSION_CODES.O)
private fun resolveFullDate(context: Context) =
if( month != null ) {
val temporal = DateTimeFormatter.ISO_DATE.parse(
"$year-$month-${day ?: 1}",
TemporalQueries.localDate()
)
temporal.atStartOfDay(ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("MMM yyyy", Locale.getDefault()))
} else {
resolveYear(context)
}
/** Resolve the year field in a way suitable for the UI. */
private fun resolveYear(context: Context) = context.getString(R.string.fmt_number, year)
override fun hashCode() = tokens.hashCode() override fun hashCode() = tokens.hashCode()
override fun equals(other: Any?) = other is Date && tokens == other.tokens override fun equals(other: Any?) = other is Date && tokens == other.tokens
@ -103,20 +142,20 @@ class Date private constructor(private val tokens: List<Int>) : Comparable<Date>
private fun StringBuilder.appendDate(): StringBuilder { private fun StringBuilder.appendDate(): StringBuilder {
append(year.toFixedString(4)) append(year.toFixedString(4))
append("-${(month ?: return this).toFixedString(2)}") append("-${(month ?: 1).toFixedString(2)}")
append("-${(day ?: return this).toFixedString(2)}") append("-${(day ?: 1).toFixedString(2)}")
append("T${(hour ?: return this).toFixedString(2)}") append("T${(hour ?: 0).toFixedString(2)}")
append(":${(minute ?: return this.append('Z')).toFixedString(2)}") append(":${(minute ?: 0).toFixedString(2)}")
append(":${(second ?: return this.append('Z')).toFixedString(2)}") append(":${(second ?: 0).toFixedString(2)}")
return this.append('Z') return this.append('Z')
} }
private fun Int.toFixedString(len: Int) = toString().padStart(len, '0') private fun Int.toFixedString(len: Int) = toString().padStart(len, '0').substring(0 until len)
companion object { companion object {
private val ISO8601_REGEX = private val ISO8601_REGEX =
Regex( Regex(
"""^(\d{4,})([-.](\d{2})([-.](\d{2})([T ](\d{2})([:.](\d{2})([:.](\d{2}))?)?)?)?)?$""" """^(\d{4,})([-.](\d{2})([-.](\d{2})([T ](\d{2})([:.](\d{2})([:.](\d{2})(Z)?)?)?)?)?)?$"""
) )
fun from(year: Int) = fromTokens(listOf(year)) fun from(year: Int) = fromTokens(listOf(year))

View file

@ -9,7 +9,7 @@
android:title="@string/lbl_album" /> android:title="@string/lbl_album" />
<item <item
android:id="@+id/option_sort_year" android:id="@+id/option_sort_year"
android:title="@string/lbl_sort_year" /> android:title="@string/lbl_sort_date" />
<item <item
android:id="@+id/option_sort_duration" android:id="@+id/option_sort_duration"
android:title="@string/lbl_sort_duration" /> android:title="@string/lbl_sort_duration" />

View file

@ -12,7 +12,7 @@
android:title="@string/lbl_album" /> android:title="@string/lbl_album" />
<item <item
android:id="@+id/option_sort_year" android:id="@+id/option_sort_year"
android:title="@string/lbl_sort_year" /> android:title="@string/lbl_sort_date" />
<item <item
android:id="@+id/option_sort_duration" android:id="@+id/option_sort_duration"
android:title="@string/lbl_sort_duration" /> android:title="@string/lbl_sort_duration" />

View file

@ -26,7 +26,7 @@
android:title="@string/lbl_album" /> android:title="@string/lbl_album" />
<item <item
android:id="@+id/option_sort_year" android:id="@+id/option_sort_year"
android:title="@string/lbl_sort_year" /> android:title="@string/lbl_sort_date" />
<item <item
android:id="@+id/option_sort_duration" android:id="@+id/option_sort_duration"
android:title="@string/lbl_sort_duration" /> android:title="@string/lbl_sort_duration" />

View file

@ -18,7 +18,7 @@
<string name="lbl_sort_name">اسم</string> <string name="lbl_sort_name">اسم</string>
<string name="lbl_artist">فنان</string> <string name="lbl_artist">فنان</string>
<string name="lbl_album">البوم</string> <string name="lbl_album">البوم</string>
<string name="lbl_sort_year">سنة</string> <string name="lbl_sort_date">سنة</string>
<string name="lbl_sort_asc">تصاعدي</string> <string name="lbl_sort_asc">تصاعدي</string>
<string name="lbl_playback">يعمل الآن</string> <string name="lbl_playback">يعمل الآن</string>
<string name="lbl_play">تشغيل</string> <string name="lbl_play">تشغيل</string>

View file

@ -20,7 +20,7 @@
<string name="lbl_sort_name">Název</string> <string name="lbl_sort_name">Název</string>
<string name="lbl_artist">Umělec</string> <string name="lbl_artist">Umělec</string>
<string name="lbl_album">Album</string> <string name="lbl_album">Album</string>
<string name="lbl_sort_year">Rok</string> <string name="lbl_sort_date">Rok</string>
<string name="lbl_sort_duration">Trvání</string> <string name="lbl_sort_duration">Trvání</string>
<string name="lbl_sort_count">Počet skladeb</string> <string name="lbl_sort_count">Počet skladeb</string>
<string name="lbl_sort_disc">Disk</string> <string name="lbl_sort_disc">Disk</string>

View file

@ -120,7 +120,7 @@
<string name="lng_playback">Musikwiedergabe anzeigen und kontrollieren</string> <string name="lng_playback">Musikwiedergabe anzeigen und kontrollieren</string>
<string name="lbl_artist">Künstler</string> <string name="lbl_artist">Künstler</string>
<string name="lbl_album">Album</string> <string name="lbl_album">Album</string>
<string name="lbl_sort_year">Jahr</string> <string name="lbl_sort_date">Jahr</string>
<string name="set_black_mode">Schwarzes Farbschema</string> <string name="set_black_mode">Schwarzes Farbschema</string>
<string name="set_black_mode_desc">Ein rein schwarzes dunkles Farbschema verwenden</string> <string name="set_black_mode_desc">Ein rein schwarzes dunkles Farbschema verwenden</string>
<string name="set_repeat_pause">Pause bei Wiederholung</string> <string name="set_repeat_pause">Pause bei Wiederholung</string>

View file

@ -74,7 +74,7 @@
<string name="fmt_disc_no">Δίσκος %d</string> <string name="fmt_disc_no">Δίσκος %d</string>
<string name="fmt_lib_album_count">Album που φορτώθηκαν: %d</string> <string name="fmt_lib_album_count">Album που φορτώθηκαν: %d</string>
<string name="fmt_lib_artist_count">Καλλιτέχνες που φορτώθηκαν: %d</string> <string name="fmt_lib_artist_count">Καλλιτέχνες που φορτώθηκαν: %d</string>
<string name="lbl_sort_year">Έτος</string> <string name="lbl_sort_date">Έτος</string>
<string name="lbl_sort_disc">Δίσκος</string> <string name="lbl_sort_disc">Δίσκος</string>
<string name="err_no_music">Δεν βρέθηκε καθόλου μουσική</string> <string name="err_no_music">Δεν βρέθηκε καθόλου μουσική</string>
<string name="err_index_failed">Η φόρτωση μουσικής απέτυχε</string> <string name="err_index_failed">Η φόρτωση μουσικής απέτυχε</string>

View file

@ -18,7 +18,7 @@
<string name="lbl_sort_name">Nombre</string> <string name="lbl_sort_name">Nombre</string>
<string name="lbl_artist">Artista</string> <string name="lbl_artist">Artista</string>
<string name="lbl_album">Álbum</string> <string name="lbl_album">Álbum</string>
<string name="lbl_sort_year">Año</string> <string name="lbl_sort_date">Año</string>
<string name="lbl_sort_asc">Ascendente</string> <string name="lbl_sort_asc">Ascendente</string>
<string name="lbl_playback">En reproducción</string> <string name="lbl_playback">En reproducción</string>
<string name="lbl_play">Reproducir</string> <string name="lbl_play">Reproducir</string>

View file

@ -20,7 +20,7 @@
<string name="lbl_compilations">Mga Compilation</string> <string name="lbl_compilations">Mga Compilation</string>
<string name="lbl_sort">Ayusin</string> <string name="lbl_sort">Ayusin</string>
<string name="lbl_sort_name">Pangalan</string> <string name="lbl_sort_name">Pangalan</string>
<string name="lbl_sort_year">Taon</string> <string name="lbl_sort_date">Taon</string>
<string name="lbl_sort_duration">Tagal</string> <string name="lbl_sort_duration">Tagal</string>
<string name="lbl_sort_count">Bilang ng kanta</string> <string name="lbl_sort_count">Bilang ng kanta</string>
<string name="lbl_compilation">Compilation</string> <string name="lbl_compilation">Compilation</string>

View file

@ -99,7 +99,7 @@
<string name="lbl_sort_name">Nom</string> <string name="lbl_sort_name">Nom</string>
<string name="lbl_artist">Artiste</string> <string name="lbl_artist">Artiste</string>
<string name="lbl_album">Album</string> <string name="lbl_album">Album</string>
<string name="lbl_sort_year">Année</string> <string name="lbl_sort_date">Année</string>
<string name="lbl_sort_duration">Durée</string> <string name="lbl_sort_duration">Durée</string>
<string name="lbl_sort_count">Nombre de chansons</string> <string name="lbl_sort_count">Nombre de chansons</string>
<string name="lbl_sort_disc">Disque</string> <string name="lbl_sort_disc">Disque</string>

View file

@ -27,7 +27,7 @@
<string name="lbl_genres">Žanrovi</string> <string name="lbl_genres">Žanrovi</string>
<string name="lbl_sort">Sortiraj</string> <string name="lbl_sort">Sortiraj</string>
<string name="lbl_sort_name">Naziv</string> <string name="lbl_sort_name">Naziv</string>
<string name="lbl_sort_year">Godina</string> <string name="lbl_sort_date">Godina</string>
<string name="lbl_sort_duration">Trajanje</string> <string name="lbl_sort_duration">Trajanje</string>
<string name="lbl_sort_count">Broj pjesama</string> <string name="lbl_sort_count">Broj pjesama</string>
<string name="lbl_sort_disc">Disk</string> <string name="lbl_sort_disc">Disk</string>

View file

@ -77,7 +77,7 @@
<string name="info_app_desc">Pemutar musik yang simpel dan rasional untuk android.</string> <string name="info_app_desc">Pemutar musik yang simpel dan rasional untuk android.</string>
<string name="lbl_indexer">Pemuatan Musik</string> <string name="lbl_indexer">Pemuatan Musik</string>
<string name="lng_playback">Lihat dan kontrol pemutaran musik</string> <string name="lng_playback">Lihat dan kontrol pemutaran musik</string>
<string name="lbl_sort_year">Tahun</string> <string name="lbl_sort_date">Tahun</string>
<string name="lbl_sort_duration">Durasi</string> <string name="lbl_sort_duration">Durasi</string>
<string name="lbl_sort_disc">Disk</string> <string name="lbl_sort_disc">Disk</string>
<string name="lbl_song_detail">Lihat properti</string> <string name="lbl_song_detail">Lihat properti</string>

View file

@ -18,7 +18,7 @@
<string name="lbl_sort_name">Nome</string> <string name="lbl_sort_name">Nome</string>
<string name="lbl_artist">Artista</string> <string name="lbl_artist">Artista</string>
<string name="lbl_album">Disco</string> <string name="lbl_album">Disco</string>
<string name="lbl_sort_year">Anno</string> <string name="lbl_sort_date">Anno</string>
<string name="lbl_sort_asc">Ascendente</string> <string name="lbl_sort_asc">Ascendente</string>
<string name="lbl_playback">Ora in riproduzione</string> <string name="lbl_playback">Ora in riproduzione</string>
<string name="lbl_play">Riproduci</string> <string name="lbl_play">Riproduci</string>

View file

@ -18,7 +18,7 @@
<string name="lbl_sort_name">제목</string> <string name="lbl_sort_name">제목</string>
<string name="lbl_artist">아티스트</string> <string name="lbl_artist">아티스트</string>
<string name="lbl_album">앨범</string> <string name="lbl_album">앨범</string>
<string name="lbl_sort_year">연도</string> <string name="lbl_sort_date">연도</string>
<string name="lbl_sort_duration">길이</string> <string name="lbl_sort_duration">길이</string>
<string name="lbl_sort_count">곡 수</string> <string name="lbl_sort_count">곡 수</string>
<string name="lbl_sort_disc">디스크</string> <string name="lbl_sort_disc">디스크</string>

View file

@ -7,7 +7,7 @@
<string name="lbl_filter_all">Visos</string> <string name="lbl_filter_all">Visos</string>
<string name="lbl_sort">Rūšiuoti</string> <string name="lbl_sort">Rūšiuoti</string>
<string name="lbl_sort_name">Pavadinimas</string> <string name="lbl_sort_name">Pavadinimas</string>
<string name="lbl_sort_year">Metai</string> <string name="lbl_sort_date">Metai</string>
<string name="lbl_sort_duration">Trukmė</string> <string name="lbl_sort_duration">Trukmė</string>
<string name="lbl_sort_count">Dainų skaičius</string> <string name="lbl_sort_count">Dainų skaičius</string>
<string name="lbl_sort_disc">Diskas</string> <string name="lbl_sort_disc">Diskas</string>

View file

@ -121,7 +121,7 @@
<string name="lbl_artist">Artiest</string> <string name="lbl_artist">Artiest</string>
<string name="lbl_cancel">@android:string/cancel</string> <string name="lbl_cancel">@android:string/cancel</string>
<string name="set_lib_tabs">Bibliotheek tabbladen</string> <string name="set_lib_tabs">Bibliotheek tabbladen</string>
<string name="lbl_sort_year">Jaar</string> <string name="lbl_sort_date">Jaar</string>
<string name="lbl_relative_path">Ouderpad</string> <string name="lbl_relative_path">Ouderpad</string>
<string name="lbl_props">Lied eigenschappen</string> <string name="lbl_props">Lied eigenschappen</string>
<string name="lbl_file_name">Bestandsnaam</string> <string name="lbl_file_name">Bestandsnaam</string>

View file

@ -119,7 +119,7 @@
<string name="clr_deep_purple">Ciemny fiolet</string> <string name="clr_deep_purple">Ciemny fiolet</string>
<string name="fmt_db_neg">-%.1f dB</string> <string name="fmt_db_neg">-%.1f dB</string>
<string name="lbl_sort_name">Nazwa</string> <string name="lbl_sort_name">Nazwa</string>
<string name="lbl_sort_year">Rok</string> <string name="lbl_sort_date">Rok</string>
<string name="lbl_single">Singiel</string> <string name="lbl_single">Singiel</string>
<string name="lbl_singles">Single</string> <string name="lbl_singles">Single</string>
<string name="lbl_sort_duration">Czas trwania</string> <string name="lbl_sort_duration">Czas trwania</string>

View file

@ -97,7 +97,7 @@
<string name="err_no_perms">O Auxio precisa de permissão para ler sua biblioteca de músicas</string> <string name="err_no_perms">O Auxio precisa de permissão para ler sua biblioteca de músicas</string>
<string name="info_app_desc">Um leitor de música simples e racional para android.</string> <string name="info_app_desc">Um leitor de música simples e racional para android.</string>
<string name="lng_indexing">Carregando sua biblioteca de músicas…</string> <string name="lng_indexing">Carregando sua biblioteca de músicas…</string>
<string name="lbl_sort_year">Ano</string> <string name="lbl_sort_date">Ano</string>
<string name="lbl_sort_duration">Duração</string> <string name="lbl_sort_duration">Duração</string>
<string name="lbl_sort_count">Contagem de músicas</string> <string name="lbl_sort_count">Contagem de músicas</string>
<string name="lbl_sort_disc">Disco</string> <string name="lbl_sort_disc">Disco</string>

View file

@ -18,7 +18,7 @@
<string name="lbl_sort_name">Название</string> <string name="lbl_sort_name">Название</string>
<string name="lbl_artist">Исполнитель</string> <string name="lbl_artist">Исполнитель</string>
<string name="lbl_album">Альбом</string> <string name="lbl_album">Альбом</string>
<string name="lbl_sort_year">Год</string> <string name="lbl_sort_date">Год</string>
<string name="lbl_sort_asc">По возрастанию</string> <string name="lbl_sort_asc">По возрастанию</string>
<string name="lbl_playback">Сейчас играет</string> <string name="lbl_playback">Сейчас играет</string>
<string name="lbl_play">Играть</string> <string name="lbl_play">Играть</string>

View file

@ -78,7 +78,7 @@
<string name="lbl_sort_name">İsim</string> <string name="lbl_sort_name">İsim</string>
<string name="lbl_artist">Sanatçı</string> <string name="lbl_artist">Sanatçı</string>
<string name="lbl_album">Albüm</string> <string name="lbl_album">Albüm</string>
<string name="lbl_sort_year">Yıl</string> <string name="lbl_sort_date">Yıl</string>
<string name="lbl_sort_duration">Süre</string> <string name="lbl_sort_duration">Süre</string>
<string name="lbl_state_saved">Durum kaydedildi</string> <string name="lbl_state_saved">Durum kaydedildi</string>
<string name="lng_author">OxygenCobalt tarafından geliştirildi</string> <string name="lng_author">OxygenCobalt tarafından geliştirildi</string>

View file

@ -18,7 +18,7 @@
<string name="lbl_sort_name">名称</string> <string name="lbl_sort_name">名称</string>
<string name="lbl_artist">艺术家</string> <string name="lbl_artist">艺术家</string>
<string name="lbl_album">专辑</string> <string name="lbl_album">专辑</string>
<string name="lbl_sort_year">年份</string> <string name="lbl_sort_date">年份</string>
<string name="lbl_sort_asc">首字符(正序)</string> <string name="lbl_sort_asc">首字符(正序)</string>
<string name="lbl_playback">正在播放</string> <string name="lbl_playback">正在播放</string>
<string name="lbl_play">播放</string> <string name="lbl_play">播放</string>

View file

@ -85,7 +85,7 @@
<string name="lbl_sort">Sort</string> <string name="lbl_sort">Sort</string>
<string name="lbl_sort_name">Name</string> <string name="lbl_sort_name">Name</string>
<string name="lbl_sort_year">Year</string> <string name="lbl_sort_date">Date</string>
<string name="lbl_sort_duration">Duration</string> <string name="lbl_sort_duration">Duration</string>
<string name="lbl_sort_count">Song count</string> <string name="lbl_sort_count">Song count</string>
<string name="lbl_sort_disc">Disc</string> <string name="lbl_sort_disc">Disc</string>