diff --git a/CHANGELOG.md b/CHANGELOG.md index 18d3fa24b..1dbcec439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,10 @@ #### What's New - Added support for disc subtitles - Added support for ALAC files +- Song properties view now shows tags #### What's Improved -- Auxio will now accept zeroed track/disc numbers in the presence of non-zero total +- Will now accept zeroed track/disc numbers in the presence of non-zero total track/disc fields - Music loading has been made slightly faster - Improved sort menu usability @@ -17,10 +18,18 @@ track/disc fields #### What's Fixed - Fixed non-functioning "repeat all" repeat mode - Fixed visual clipping of shuffle button shadow +- Fixed SeekBar remaining in a "stuck" state if gesture navigation was used +while selecting it. #### Dev/Meta - Started using dependency injection +- Started code obsfucation +- Only bundle audio-related extractors with ExoPlayer +- Switched to Room for database management - Updated to MDC 1.8.0 alpha-01 +- Updated to AGP 7.4.1 +- Updated to Gradle 8.0 +- Updated to ExoPlayer 2.18.3 ## 3.0.2 diff --git a/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt b/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt index bb8d87730..0640a1c64 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt @@ -17,22 +17,28 @@ package org.oxycblt.auxio.detail +import android.content.Context import android.os.Bundle import android.text.format.Formatter import android.view.LayoutInflater import androidx.appcompat.app.AlertDialog -import androidx.core.view.isInvisible import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import dagger.hilt.android.AndroidEntryPoint import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.DialogSongDetailBinding +import org.oxycblt.auxio.detail.recycler.SongPropertyAdapter +import org.oxycblt.auxio.detail.recycler.SongProperty +import org.oxycblt.auxio.list.adapter.BasicListInstructions +import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.metadata.AudioInfo +import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.ui.ViewBindingDialogFragment import org.oxycblt.auxio.util.collectImmediately +import org.oxycblt.auxio.util.concatLocalized /** * A [ViewBindingDialogFragment] that shows information about a Song. @@ -44,6 +50,7 @@ class SongDetailDialog : ViewBindingDialogFragment() { // Information about what song to display is initially within the navigation arguments // as a UID, as that is the only safe way to parcel an song. private val args: SongDetailDialogArgs by navArgs() + private val detailAdapter = SongPropertyAdapter() override fun onCreateBinding(inflater: LayoutInflater) = DialogSongDetailBinding.inflate(inflater) @@ -55,6 +62,7 @@ class SongDetailDialog : ViewBindingDialogFragment() { override fun onBindingCreated(binding: DialogSongDetailBinding, savedInstanceState: Bundle?) { super.onBindingCreated(binding, savedInstanceState) + binding.detailProperties.adapter = detailAdapter // DetailViewModel handles most initialization from the navigation argument. detailModel.setSongUid(args.itemUid) collectImmediately(detailModel.currentSong, detailModel.songAudioInfo, ::updateSong) @@ -67,35 +75,59 @@ class SongDetailDialog : ViewBindingDialogFragment() { return } - val binding = requireBinding() if (info != null) { - // Finished loading song audio info, populate and show the list of Song information. - binding.detailLoading.isInvisible = true - binding.detailContainer.isInvisible = false - val context = requireContext() - binding.detailFileName.setText(song.path.name) - binding.detailRelativeDir.setText(song.path.parent.resolveName(context)) - binding.detailFormat.setText(info.resolvedMimeType.resolveName(context)) - binding.detailSize.setText(Formatter.formatFileSize(context, song.size)) - binding.detailDuration.setText(song.durationMs.formatDurationMs(true)) - - if (info.bitrateKbps != null) { - binding.detailBitrate.setText(getString(R.string.fmt_bitrate, info.bitrateKbps)) - } else { - binding.detailBitrate.setText(R.string.def_bitrate) - } - - if (info.sampleRateHz != null) { - binding.detailSampleRate.setText( - getString(R.string.fmt_sample_rate, info.sampleRateHz)) - } else { - binding.detailSampleRate.setText(R.string.def_sample_rate) - } - } else { - // Loading is still on-going, don't show anything yet. - binding.detailLoading.isInvisible = false - binding.detailContainer.isInvisible = true + detailAdapter.submitList( + buildList { + add(SongProperty(R.string.lbl_name, song.zipName(context))) + add(SongProperty(R.string.lbl_album, song.album.zipName(context))) + add(SongProperty(R.string.lbl_artists, song.artists.zipNames(context))) + add(SongProperty(R.string.lbl_genres, song.genres.resolveNames(context))) + song.date?.let { add(SongProperty(R.string.lbl_date, it.resolveDate(context))) } + song.track?.let { + add(SongProperty(R.string.lbl_track, getString(R.string.fmt_number, it))) + } + song.disc?.let { + val formattedNumber = getString(R.string.fmt_number, it.number) + val zipped = + if (it.name != null) { + getString(R.string.fmt_zipped_names, it.name, formattedNumber) + } else { + formattedNumber + } + add(SongProperty(R.string.lbl_disc, zipped)) + } + add(SongProperty(R.string.lbl_file_name, song.path.name)) + add( + SongProperty( + R.string.lbl_relative_path, song.path.parent.resolveName(context))) + info.resolvedMimeType.resolveName(context)?.let { + SongProperty(R.string.lbl_format, it) + } + add( + SongProperty( + R.string.lbl_size, Formatter.formatFileSize(context, song.size))) + add(SongProperty(R.string.lbl_duration, song.durationMs.formatDurationMs(true))) + info.bitrateKbps?.let { + add(SongProperty(R.string.lbl_bitrate, getString(R.string.fmt_bitrate, it))) + } + info.sampleRateHz?.let { + add( + SongProperty( + R.string.lbl_sample_rate, getString(R.string.fmt_sample_rate, it))) + } + }, + BasicListInstructions.REPLACE) } } + + private fun T.zipName(context: Context) = + if (rawSortName != null) { + getString(R.string.fmt_zipped_names, resolveName(context), rawSortName) + } else { + resolveName(context) + } + + private fun List.zipNames(context: Context) = + concatLocalized(context) { it.zipName(context) } } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt index 4d44384a3..aa573a4e0 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/AlbumDetailAdapter.kt @@ -33,7 +33,9 @@ import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter import org.oxycblt.auxio.list.adapter.SimpleDiffCallback import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.areRawNamesTheSame import org.oxycblt.auxio.music.metadata.Disc +import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.util.context import org.oxycblt.auxio.util.getPlural @@ -136,7 +138,7 @@ private class AlbumDetailViewHolder private constructor(private val binding: Ite // Artist name maps to the subhead text binding.detailSubhead.apply { - text = album.resolveArtistContents(context) + text = album.artists.resolveNames(context) // Add a QoL behavior where navigation to the artist will occur if the artist // name is pressed. @@ -173,7 +175,7 @@ private class AlbumDetailViewHolder private constructor(private val binding: Ite object : SimpleDiffCallback() { override fun areContentsTheSame(oldItem: Album, newItem: Album) = oldItem.rawName == newItem.rawName && - oldItem.areArtistContentsTheSame(newItem) && + oldItem.artists.areRawNamesTheSame(newItem.artists) && oldItem.dates == newItem.dates && oldItem.songs.size == newItem.songs.size && oldItem.durationMs == newItem.durationMs && diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt index e706efc23..655577638 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/ArtistDetailAdapter.kt @@ -30,10 +30,7 @@ import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter import org.oxycblt.auxio.list.adapter.SimpleDiffCallback -import org.oxycblt.auxio.music.Album -import org.oxycblt.auxio.music.Artist -import org.oxycblt.auxio.music.Music -import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.* import org.oxycblt.auxio.util.context import org.oxycblt.auxio.util.getPlural import org.oxycblt.auxio.util.inflater @@ -122,7 +119,7 @@ private class ArtistDetailViewHolder private constructor(private val binding: It // Information about the artist's genre(s) map to the sub-head text binding.detailSubhead.apply { isVisible = true - text = artist.resolveGenreContents(binding.context) + text = artist.genres.resolveNames(context) } // Song and album counts map to the info @@ -168,7 +165,7 @@ private class ArtistDetailViewHolder private constructor(private val binding: It object : SimpleDiffCallback() { override fun areContentsTheSame(oldItem: Artist, newItem: Artist) = oldItem.rawName == newItem.rawName && - oldItem.areGenreContentsTheSame(newItem) && + oldItem.genres.areRawNamesTheSame(newItem.genres) && oldItem.albums.size == newItem.albums.size && oldItem.songs.size == newItem.songs.size } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/SongPropertyAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/SongPropertyAdapter.kt new file mode 100644 index 000000000..863a921e5 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/SongPropertyAdapter.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 Auxio Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.oxycblt.auxio.detail.recycler + +import android.view.View +import android.view.ViewGroup +import androidx.annotation.StringRes +import androidx.recyclerview.widget.RecyclerView +import org.oxycblt.auxio.databinding.ItemSongPropertyBinding +import org.oxycblt.auxio.list.Item +import org.oxycblt.auxio.list.adapter.BasicListInstructions +import org.oxycblt.auxio.list.adapter.DiffAdapter +import org.oxycblt.auxio.list.adapter.ListDiffer +import org.oxycblt.auxio.list.adapter.SimpleDiffCallback +import org.oxycblt.auxio.list.recycler.DialogRecyclerView +import org.oxycblt.auxio.util.context +import org.oxycblt.auxio.util.inflater + +/** + * An adapter for [SongProperty] instances. + * @author Alexander Capehart (OxygenCobalt) + */ +class SongPropertyAdapter : + DiffAdapter( + ListDiffer.Blocking(SongPropertyViewHolder.DIFF_CALLBACK)) { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = + SongPropertyViewHolder.from(parent) + + override fun onBindViewHolder(holder: SongPropertyViewHolder, position: Int) { + holder.bind(getItem(position)) + } +} + +/** + * A property entry for use in [SongPropertyAdapter]. + * @param name The contextual title to use for the property. + * @param value The value of the property. + * @author Alexander Capehart (OxygenCobalt) + */ +data class SongProperty(@StringRes val name: Int, val value: String) : Item + +/** + * A [RecyclerView.ViewHolder] that displays a [SongProperty]. Use [from] to create an instance. + * @author Alexander Capehart (OxygenCobalt) + */ +class SongPropertyViewHolder private constructor(private val binding: ItemSongPropertyBinding) : + DialogRecyclerView.ViewHolder(binding.root) { + fun bind(property: SongProperty) { + val context = binding.context + binding.propertyName.hint = context.getString(property.name) + binding.propertyValue.setText(property.value) + } + + companion object { + /** + * Create a new instance. + * @param parent The parent to inflate this instance from. + * @return A new instance. + */ + fun from(parent: View) = + SongPropertyViewHolder(ItemSongPropertyBinding.inflate(parent.context.inflater)) + + /** A comparator that can be used with DiffUtil. */ + val DIFF_CALLBACK = + object : SimpleDiffCallback() { + override fun areContentsTheSame(oldItem: SongProperty, newItem: SongProperty) = + oldItem.name == newItem.name && oldItem.value == newItem.value + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt b/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt index aaafffc4b..ff09af8b1 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/recycler/ViewHolders.kt @@ -49,7 +49,7 @@ class SongViewHolder private constructor(private val binding: ItemSongBinding) : listener.bind(song, this, menuButton = binding.songMenu) binding.songAlbumCover.bind(song) binding.songName.text = song.resolveName(binding.context) - binding.songInfo.text = song.resolveArtistContents(binding.context) + binding.songInfo.text = song.artists.resolveNames(binding.context) } override fun updatePlayingIndicator(isActive: Boolean, isPlaying: Boolean) { @@ -76,7 +76,8 @@ class SongViewHolder private constructor(private val binding: ItemSongBinding) : val DIFF_CALLBACK = object : SimpleDiffCallback() { override fun areContentsTheSame(oldItem: Song, newItem: Song) = - oldItem.rawName == newItem.rawName && oldItem.areArtistContentsTheSame(newItem) + oldItem.rawName == newItem.rawName && + oldItem.artists.areRawNamesTheSame(newItem.artists) } } } @@ -96,7 +97,7 @@ class AlbumViewHolder private constructor(private val binding: ItemParentBinding listener.bind(album, this, menuButton = binding.parentMenu) binding.parentImage.bind(album) binding.parentName.text = album.resolveName(binding.context) - binding.parentInfo.text = album.resolveArtistContents(binding.context) + binding.parentInfo.text = album.artists.resolveNames(binding.context) } override fun updatePlayingIndicator(isActive: Boolean, isPlaying: Boolean) { @@ -124,7 +125,7 @@ class AlbumViewHolder private constructor(private val binding: ItemParentBinding object : SimpleDiffCallback() { override fun areContentsTheSame(oldItem: Album, newItem: Album) = oldItem.rawName == newItem.rawName && - oldItem.areArtistContentsTheSame(newItem) && + oldItem.artists.areRawNamesTheSame(newItem.artists) && oldItem.releaseType == newItem.releaseType } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/Music.kt b/app/src/main/java/org/oxycblt/auxio/music/Music.kt index 85f1e3044..4cd809b3a 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Music.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Music.kt @@ -23,6 +23,7 @@ import android.os.Parcelable import java.security.MessageDigest import java.text.CollationKey import java.util.UUID +import kotlin.math.max import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize import org.oxycblt.auxio.list.Item @@ -31,6 +32,7 @@ import org.oxycblt.auxio.music.metadata.Disc import org.oxycblt.auxio.music.metadata.ReleaseType import org.oxycblt.auxio.music.storage.MimeType import org.oxycblt.auxio.music.storage.Path +import org.oxycblt.auxio.util.concatLocalized import org.oxycblt.auxio.util.toUuidOrNull /** @@ -269,28 +271,11 @@ interface Song : Music { * this field. */ val artists: List - /** - * Resolves one or more [Artist]s into a single piece of human-readable names. - * @param context [Context] required for [resolveName]. formatter. - */ - fun resolveArtistContents(context: Context): String - /** - * Checks if the [Artist] *display* of this [Song] and another [Song] are equal. This will only - * compare surface-level names, and not [Music.UID]s. - * @param other The [Song] to compare to. - * @return True if the [Artist] displays are equal, false otherwise - */ - fun areArtistContentsTheSame(other: Song): Boolean /** * The parent [Genre]s of this [Song]. Is often one, but there can be multiple if more than one * [Genre] name was specified in the metadata. */ val genres: List - /** - * Resolves one or more [Genre]s into a single piece human-readable names. - * @param context [Context] required for [resolveName]. - */ - fun resolveGenreContents(context: Context): String } /** @@ -321,18 +306,6 @@ interface Album : MusicParent { * are prioritized for this field. */ val artists: List - /** - * Resolves one or more [Artist]s into a single piece of human-readable names. - * @param context [Context] required for [resolveName]. - */ - fun resolveArtistContents(context: Context): String - /** - * Checks if the [Artist] *display* of this [Album] and another [Album] are equal. This will - * only compare surface-level names, and not [Music.UID]s. - * @param other The [Album] to compare to. - * @return True if the [Artist] displays are equal, false otherwise - */ - fun areArtistContentsTheSame(other: Album): Boolean } /** @@ -359,18 +332,6 @@ interface Artist : MusicParent { val isCollaborator: Boolean /** The [Genre]s of this artist. */ val genres: List - /** - * Resolves one or more [Genre]s into a single piece of human-readable names. - * @param context [Context] required for [resolveName]. - */ - fun resolveGenreContents(context: Context): String - /** - * Checks if the [Genre] *display* of this [Artist] and another [Artist] are equal. This will - * only compare surface-level names, and not [Music.UID]s. - * @param other The [Artist] to compare to. - * @return True if the [Genre] displays are equal, false otherwise - */ - fun areGenreContentsTheSame(other: Artist): Boolean } /** @@ -385,3 +346,18 @@ interface Genre : MusicParent { /** The total duration of the songs in this genre, in milliseconds. */ val durationMs: Long } + +fun List.resolveNames(context: Context) = + concatLocalized(context) { it.resolveName(context) } + +fun List.areRawNamesTheSame(other: List): Boolean { + for (i in 0 until max(size, other.size)) { + val a = getOrNull(i) ?: return false + val b = other.getOrNull(i) ?: return false + if (a.rawName != b.rawName) { + return false + } + } + + return true +} diff --git a/app/src/main/java/org/oxycblt/auxio/music/model/MusicImpl.kt b/app/src/main/java/org/oxycblt/auxio/music/model/MusicImpl.kt index e863b8003..a39b474d9 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/model/MusicImpl.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/model/MusicImpl.kt @@ -22,7 +22,6 @@ import androidx.annotation.VisibleForTesting import java.security.MessageDigest import java.text.CollationKey import java.text.Collator -import kotlin.math.max import org.oxycblt.auxio.R import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.music.Album @@ -124,23 +123,10 @@ class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song { private val _artists = mutableListOf() override val artists: List get() = _artists - override fun resolveArtistContents(context: Context) = resolveNames(context, artists) - override fun areArtistContentsTheSame(other: Song): Boolean { - for (i in 0 until max(artists.size, other.artists.size)) { - val a = artists.getOrNull(i) ?: return false - val b = other.artists.getOrNull(i) ?: return false - if (a.rawName != b.rawName) { - return false - } - } - - return true - } private val _genres = mutableListOf() override val genres: List get() = _genres - override fun resolveGenreContents(context: Context) = resolveNames(context, genres) /** * The [RawAlbum] instances collated by the [Song]. This can be used to group [Song]s into an @@ -268,18 +254,7 @@ class AlbumImpl(val rawAlbum: RawAlbum, override val songs: List) : Al private val _artists = mutableListOf() override val artists: List get() = _artists - override fun resolveArtistContents(context: Context) = resolveNames(context, artists) - override fun areArtistContentsTheSame(other: Album): Boolean { - for (i in 0 until max(artists.size, other.artists.size)) { - val a = artists.getOrNull(i) ?: return false - val b = other.artists.getOrNull(i) ?: return false - if (a.rawName != b.rawName) { - return false - } - } - return true - } init { var totalDuration: Long = 0 var earliestDateAdded: Long = Long.MAX_VALUE @@ -361,18 +336,6 @@ class ArtistImpl(private val rawArtist: RawArtist, songAlbums: List) : Ar other is ArtistImpl && uid == other.uid && songs == other.songs override lateinit var genres: List - override fun resolveGenreContents(context: Context) = resolveNames(context, genres) - override fun areGenreContentsTheSame(other: Artist): Boolean { - for (i in 0 until max(genres.size, other.genres.size)) { - val a = genres.getOrNull(i) ?: return false - val b = other.genres.getOrNull(i) ?: return false - if (a.rawName != b.rawName) { - return false - } - } - - return true - } init { val distinctSongs = mutableSetOf() @@ -534,27 +497,6 @@ fun MessageDigest.update(n: Int?) { } } -/** - * Join a list of [Music]'s resolved names into a string in a localized manner, using - * [R.string.fmt_list]. - * @param context [Context] required to obtain localized formatting. - * @param values The list of [Music] to format. - * @return A single string consisting of the values delimited by a localized separator. - */ -private fun resolveNames(context: Context, values: List): String { - if (values.isEmpty()) { - // Nothing to do. - return "" - } - - var joined = values.first().resolveName(context) - for (i in 1..values.lastIndex) { - // Chain all previous values with the next value in the list with another delimiter. - joined = context.getString(R.string.fmt_list, joined, values[i].resolveName(context)) - } - return joined -} - /** Cached collator instance re-used with [makeCollationKey]. */ private val COLLATOR: Collator = Collator.getInstance().apply { strength = Collator.PRIMARY } diff --git a/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt index 73c969633..ca0cdee6c 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt @@ -142,10 +142,9 @@ data class MimeType(val fromExtension: String, val fromFormat: String?) { * Resolve the mime type into a human-readable format name, such as "Ogg Vorbis". * @param context [Context] required to obtain human-readable strings. * @return A human-readable name for this mime type. Will first try [fromFormat], then falling - * back to [fromExtension], then falling back to the extension name, and then finally a - * placeholder "No Format" string. + * back to [fromExtension], and then null if that fails. */ - fun resolveName(context: Context): String { + fun resolveName(context: Context): String? { // We try our best to produce a more readable name for the common audio formats. val formatName = when (fromFormat) { @@ -201,8 +200,6 @@ data class MimeType(val fromExtension: String, val fromFormat: String?) { } else { // Fall back to the extension if we can't find a special name for this format. MimeTypeMap.getSingleton().getExtensionFromMimeType(fromExtension)?.uppercase() - // Fall back to a placeholder if even that fails. - ?: context.getString(R.string.def_codec) } } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt index 2e409844a..5ecf71d21 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt @@ -24,6 +24,7 @@ import dagger.hilt.android.AndroidEntryPoint import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentPlaybackBarBinding import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.ui.MainNavigationAction import org.oxycblt.auxio.ui.NavigationViewModel @@ -122,7 +123,7 @@ class PlaybackBarFragment : ViewBindingFragment() { val binding = requireBinding() binding.playbackCover.bind(song) binding.playbackSong.text = song.resolveName(context) - binding.playbackInfo.text = song.resolveArtistContents(context) + binding.playbackInfo.text = song.artists.resolveNames(context) binding.playbackProgressBar.max = song.durationMs.msToDs().toInt() } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt index 489914391..49f018f85 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt @@ -34,6 +34,7 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.ui.StyledSeekBar import org.oxycblt.auxio.ui.MainNavigationAction @@ -184,7 +185,7 @@ class PlaybackPanelFragment : val context = requireContext() binding.playbackCover.bind(song) binding.playbackSong.text = song.resolveName(context) - binding.playbackArtist.text = song.resolveArtistContents(context) + binding.playbackArtist.text = song.artists.resolveNames(context) binding.playbackAlbum.text = song.album.resolveName(context) binding.playbackSeekBar.durationDs = song.durationMs.msToDs() } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt index 1898af497..2b67c5b3e 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt @@ -33,6 +33,7 @@ import org.oxycblt.auxio.list.adapter.ListDiffer import org.oxycblt.auxio.list.adapter.PlayingIndicatorAdapter import org.oxycblt.auxio.list.recycler.SongViewHolder import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.util.* /** @@ -149,7 +150,7 @@ class QueueSongViewHolder private constructor(private val binding: ItemQueueSong listener.bind(song, this, bodyView, binding.songDragHandle) binding.songAlbumCover.bind(song) binding.songName.text = song.resolveName(binding.context) - binding.songInfo.text = song.resolveArtistContents(binding.context) + binding.songInfo.text = song.artists.resolveNames(binding.context) // Not swiping this ViewHolder if it's being re-bound, ensure that the background is // not visible. See QueueDragCallback for why this is done. binding.background.isInvisible = true diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt index 73ee968e3..c1a099636 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt @@ -35,6 +35,7 @@ import org.oxycblt.auxio.image.BitmapProvider import org.oxycblt.auxio.image.ImageSettings import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.playback.ActionMode import org.oxycblt.auxio.playback.PlaybackSettings import org.oxycblt.auxio.playback.queue.Queue @@ -285,7 +286,7 @@ constructor( // Populate MediaMetadataCompat. For efficiency, cache some fields that are re-used // several times. val title = song.resolveName(context) - val artist = song.resolveArtistContents(context) + val artist = song.artists.resolveNames(context) val builder = MediaMetadataCompat.Builder() .putText(MediaMetadataCompat.METADATA_KEY_TITLE, title) @@ -295,14 +296,14 @@ constructor( .putText(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) .putText( MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, - song.album.resolveArtistContents(context)) + song.album.artists.resolveNames(context)) .putText(MediaMetadataCompat.METADATA_KEY_AUTHOR, artist) .putText(MediaMetadataCompat.METADATA_KEY_COMPOSER, artist) .putText(MediaMetadataCompat.METADATA_KEY_WRITER, artist) .putText( METADATA_KEY_PARENT, parent?.resolveName(context) ?: context.getString(R.string.lbl_all_songs)) - .putText(MediaMetadataCompat.METADATA_KEY_GENRE, song.resolveGenreContents(context)) + .putText(MediaMetadataCompat.METADATA_KEY_GENRE, song.genres.resolveNames(context)) .putText(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, title) .putText(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, artist) .putText( @@ -348,7 +349,7 @@ constructor( // as it's used to request a song to be played from the queue. .setMediaId(song.uid.toString()) .setTitle(song.resolveName(context)) - .setSubtitle(song.resolveArtistContents(context)) + .setSubtitle(song.artists.resolveNames(context)) // Since we usually have to load many songs into the queue, use the // MediaStore URI instead of loading a bitmap. .setIconUri(song.album.coverUri) diff --git a/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt index de624a85d..85aa256da 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/ContextUtil.kt @@ -39,6 +39,7 @@ import androidx.core.content.ContextCompat import kotlin.reflect.KClass import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.MainActivity +import org.oxycblt.auxio.R /** * Get a [LayoutInflater] instance from this [Context]. @@ -57,6 +58,25 @@ val Context.isNight val Context.isLandscape get() = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE +/** + * Concatenate values in a list together in a localized manner. + * @param context [Context] require.d + * @param map Function to map the [T] values to a string value to be concatenated. + */ +inline fun List.concatLocalized(context: Context, map: (T) -> String): String { + if (isEmpty()) { + // Nothing to do. + return "" + } + + var joined = map(first()) + for (i in 1..lastIndex) { + // Chain all previous values with the next value in the list with another delimiter. + joined = context.getString(R.string.fmt_list, joined, map(get(i))) + } + return joined +} + /** * @brief Get a plural resource. * @param pluralRes A plural resource ID. diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt index 813105c7f..d828e8a38 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt @@ -31,6 +31,7 @@ import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.R +import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.system.PlaybackService import org.oxycblt.auxio.ui.UISettings @@ -265,7 +266,7 @@ class WidgetProvider : AppWidgetProvider() { ): RemoteViews { setupCover(context, state) setTextViewText(R.id.widget_song, state.song.resolveName(context)) - setTextViewText(R.id.widget_artist, state.song.resolveArtistContents(context)) + setTextViewText(R.id.widget_artist, state.song.artists.resolveNames(context)) return this } diff --git a/app/src/main/res/layout/dialog_song_detail.xml b/app/src/main/res/layout/dialog_song_detail.xml index 287f692de..1f31d8ce2 100644 --- a/app/src/main/res/layout/dialog_song_detail.xml +++ b/app/src/main/res/layout/dialog_song_detail.xml @@ -1,153 +1,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingStart="@dimen/spacing_small" + android:paddingEnd="@dimen/spacing_small" + tools:listitem="@layout/item_song_property" /> diff --git a/app/src/main/res/layout/item_song_property.xml b/app/src/main/res/layout/item_song_property.xml new file mode 100644 index 000000000..5334756bd --- /dev/null +++ b/app/src/main/res/layout/item_song_property.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/app/src/main/res/menu/menu_album_sort.xml b/app/src/main/res/menu/menu_album_sort.xml index 0b0af5d1d..44f9744aa 100644 --- a/app/src/main/res/menu/menu_album_sort.xml +++ b/app/src/main/res/menu/menu_album_sort.xml @@ -4,10 +4,10 @@ android:id="@+id/sort_modes"> + android:title="@string/lbl_disc" /> + android:title="@string/lbl_track" /> diff --git a/app/src/main/res/menu/menu_artist_sort.xml b/app/src/main/res/menu/menu_artist_sort.xml index c3055096d..50ba847ba 100644 --- a/app/src/main/res/menu/menu_artist_sort.xml +++ b/app/src/main/res/menu/menu_artist_sort.xml @@ -4,16 +4,16 @@ android:id="@+id/sort_modes"> + android:title="@string/lbl_name" /> + android:title="@string/lbl_date" /> + android:title="@string/lbl_duration" /> diff --git a/app/src/main/res/menu/menu_genre_sort.xml b/app/src/main/res/menu/menu_genre_sort.xml index daf303fdf..ad5d920c8 100644 --- a/app/src/main/res/menu/menu_genre_sort.xml +++ b/app/src/main/res/menu/menu_genre_sort.xml @@ -4,7 +4,7 @@ android:id="@+id/sort_modes"> + android:title="@string/lbl_name" /> @@ -13,10 +13,10 @@ android:title="@string/lbl_album" /> + android:title="@string/lbl_date" /> + android:title="@string/lbl_duration" /> diff --git a/app/src/main/res/menu/menu_home.xml b/app/src/main/res/menu/menu_home.xml index f63266c9c..278206a03 100644 --- a/app/src/main/res/menu/menu_home.xml +++ b/app/src/main/res/menu/menu_home.xml @@ -18,7 +18,7 @@ android:id="@+id/sort_modes"> + android:title="@string/lbl_name" /> @@ -27,16 +27,16 @@ android:title="@string/lbl_album" /> + android:title="@string/lbl_date" /> + android:title="@string/lbl_duration" /> + android:title="@string/lbl_song_count" /> + android:title="@string/lbl_date_added" /> diff --git a/app/src/main/res/values-ar-rIQ/strings.xml b/app/src/main/res/values-ar-rIQ/strings.xml index 26b1d9f6a..284a89bab 100644 --- a/app/src/main/res/values-ar-rIQ/strings.xml +++ b/app/src/main/res/values-ar-rIQ/strings.xml @@ -15,10 +15,10 @@ تصفية الكل فرز - اسم + اسم فنان البوم - سنة + سنة تصاعدي يعمل الآن تشغيل diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index 6a4ef9902..75b911111 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -59,16 +59,16 @@ Пошук Фільтр Усе - Назва + Назва Жанры Сартаваць - Дата дабаўлення + Дата дабаўлення Дзяржава адноўлена - Дыск - Дата - Працягласць - Колькасць песень - Кампазіцыя + Дыск + Дата + Працягласць + Колькасць песень + Кампазіцыя Зараз іграе Гуляць Ператасаваць diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 334f834db..418efa547 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -17,14 +17,14 @@ Filtr Vše Řadit - Název + Název Umělec Album - Rok - Trvání - Počet skladeb - Disk - Stopa + Rok + Trvání + Počet skladeb + Disk + Stopa Vzestupně Právě hraje Přehrát @@ -204,7 +204,7 @@ Sledování změn v hudební knihovně… Znovu načíst hudební knihovnu při změně (vyžaduje trvalé oznámení) Načítání hudby - Datum přidání + Datum přidání Singl Singly EP diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index af84a44a6..d00d80311 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -119,7 +119,7 @@ Musikwiedergabe anzeigen und kontrollieren Künstler Album - Jahr + Jahr Schwarzes Farbschema Ein rein schwarzes dunkles Farbschema verwenden Pause bei Wiederholung @@ -131,15 +131,15 @@ Keine Musik wird gespielt Bibliotheks-Registerkarten Sichtbarkeit und Ordnung der Bibliotheksregisterkarten ändern - Name + Name Alle Lieder zufällig Lied in der Warteschlange löschen Tab versetzen Unbekannter Künstler - Dauer - Anzahl der Lieder - Schallplatte - Titel + Dauer + Anzahl der Lieder + Schallplatte + Titel OK Bibliotheksstatistiken Album bevorzugen, wenn eines abgespielt wird @@ -190,7 +190,7 @@ Überwachen der Musikbibliothek Musik wird geladen Musikbibliothek wird auf Änderungen überwacht… - Hinzugefügt am + Hinzugefügt am Musikbibliothek neu laden, sobald es Änderungen gibt (erfordert persistente Benachrichtigung) Automatisch neuladen Zustand wiederhergestellt diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 679e4ae44..1e4d4e407 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -68,13 +68,13 @@ +%.1f dB Φόρτωση της συλλογής μουσικής σας… (%1$d/%2$d) Είδη που φορτώθηκαν: %d - Αριθμός τραγουδιών + Αριθμός τραγουδιών Αυτός ο φάκελος δεν υποστηρίζεται Δίσκος %d Album που φορτώθηκαν: %d Καλλιτέχνες που φορτώθηκαν: %d - Έτος - Δίσκος + Έτος + Δίσκος Δεν βρέθηκε καθόλου μουσική Η φόρτωση μουσικής απέτυχε %d kbps @@ -93,8 +93,8 @@ Είδος -%.1f dB %d Hz - Όνομα - Διάρκεια + Όνομα + Διάρκεια Συνολική διάρκεια: %s Καθόλου φάκελοι Μιά απλή, λογική εφαρμογή αναπαραγωγής μουσικής για Android. @@ -104,7 +104,7 @@ EP EP Καλλιτέχνης - Ημερομηνία πρόσθεσης + Ημερομηνία πρόσθεσης Μορφή Περιεχομένο Tυχαία αναπαραγωγή όλων diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index a55d593b5..b102500aa 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -15,10 +15,10 @@ Filtrar Todo Organizar - Nombre + Nombre Artista Álbum - Año + Año Ascendente En reproducción Reproducir @@ -139,9 +139,9 @@ Tamaño Formato Tasa de bits - Duración - Pista - Disco + Duración + Pista + Disco Ver propiedades Mezclar Mezclar todo @@ -163,7 +163,7 @@ Artistas cargados: %d Géneros cargados: %d Carga de música - Número de canciones + Número de canciones Estado restaurado Recarga automática Recargar la biblioteca musical cada vez que cambie (requiere una notificación persistente) @@ -174,7 +174,7 @@ Monitorizando cambios en tu librería de música… Audio ogg Cuando se reproduce desde los detalles - Fecha de añadido + Fecha de añadido Propiedades de la canción Frecuencia de muestreo Cancelar diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml index 73197dd94..17dfdf605 100644 --- a/app/src/main/res/values-fil/strings.xml +++ b/app/src/main/res/values-fil/strings.xml @@ -19,10 +19,10 @@ Remix single Mga Compilation Ayusin - Pangalan - Taon - Tagal - Bilang ng kanta + Pangalan + Taon + Tagal + Bilang ng kanta Compilation Mga Soundtrack Soundtrack @@ -32,8 +32,8 @@ Mga Artista Salain Lahat - Disko - Petsa ng pagdagdag + Disko + Petsa ng pagdagdag Pataas Tinutugtog Ngayon Tugtugin diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 4507fbea6..43405b0dc 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -95,14 +95,14 @@ Chargement de musique Afficher et contrôler la lecture de la musique Chargement de votre bibliothèque musicale… - Nom + Nom Artiste Album - Année - Durée - Nombre de chansons - Disque - Piste + Année + Durée + Nombre de chansons + Disque + Piste Voir les propriétés Propriétés de la chanson EP live @@ -123,7 +123,7 @@ Mixtapes Mixtape Remix - Date d\'ajout + Date d\'ajout Album live Album de remixes Genre diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 85967d1ee..9949d2df9 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -46,7 +46,7 @@ %d एल्बम %d एल्बम - नाम + नाम शैली अब खेल रहे हैं संकलन @@ -55,5 +55,5 @@ आकार ठीक है कलाकार - तिथि जोड़ी गई + तिथि जोड़ी गई \ No newline at end of file diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index dd0452a9e..4a4bd0301 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -26,13 +26,13 @@ Izvođači Žanrovi Sortiraj - Naziv - Godina - Trajanje - Broj pjesama - Disk - Zvučni zapis - Datum dodavanja + Naziv + Godina + Trajanje + Broj pjesama + Disk + Zvučni zapis + Datum dodavanja Uzlazno Trenutačno svira Reproduciraj diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 5769d3801..c3e211bd5 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -70,15 +70,15 @@ Tingkat sampel Tab Pustaka Memuat pustaka musik Anda… - Nama + Nama Artis Album Pemutar musik yang sederhana dan rasional untuk android. Pemuatan musik Lihat dan kendalikan pemutaran musik - Tanggal - Durasi - Disk + Tanggal + Durasi + Disk Lihat properti Format Dikembangkan oleh Alexander Capehart @@ -179,8 +179,8 @@ Hijau Jingga Genre yang dimuat: %d - Jumlah lagu - Trek + Jumlah lagu + Trek Merah muda ReplayGain Muat ulang otomatis @@ -192,7 +192,7 @@ Aktifkan sudut yang bundar pada elemen UI tambahan (mewajibkan sampul album bersudut bundar) Koma (,) Tambah (+) - Tanggal ditambahkan + Tanggal ditambahkan Kualitas tinggi Titik koma (;) Wiki diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 07b623517..2bdecea75 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -15,10 +15,10 @@ Filtro Tutto Ordine - Nome + Nome Artista Disco - Anno + Anno Ascendente Ora in riproduzione Riproduci @@ -175,10 +175,10 @@ -%.1f dB Caricamento musica Caricamento libreria musicale… - Durata - Numero canzoni - Disco - Traccia + Durata + Numero canzoni + Disco + Traccia OK Frequenza di campionamento Vedi proprietà @@ -196,7 +196,7 @@ Caricamento musica Monitoraggio libreria musicale Stato ripristinato - Data aggiunta + Data aggiunta Ricaricamento automatico Ripristina stato riproduzione Ripristina lo stato di riproduzione precedentemente salvato (se disponibile) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 8da7b51bb..cab205eb7 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -5,7 +5,7 @@ 許可する アーティスト ジャンル - 曲の長さ + 曲の長さ 現在の再生状態を保存 このタブを移動 この再生待ちの曲を移動 @@ -13,8 +13,8 @@ すべての曲 並べ替え - 曲名 - 再生回数 + 曲名 + 再生回数 キャンセル シャフル 自動 @@ -24,7 +24,7 @@ シャフルを記憶 曲の繰り返し時にポーズ 検索クエリを解除 - 日付け + 日付け 高クオリティ ラウンドモード 音楽が見つかりません @@ -46,9 +46,9 @@ リミックスオムニバス DJミックス DJミックス - ディスク + ディスク イコライザ - トラック + トラック 昇順 再生中 カラースキーム @@ -58,7 +58,7 @@ 再生停止 ファイル名 - 追加した日付け + 追加した日付け サンプルレート 降順 再生 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 6f8779b95..24ca35ec2 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -15,14 +15,14 @@ 필터 전체 정렬 - 제목 + 제목 아티스트 앨범 - 연도 - 길이 - 곡 수 - 디스크 - 트랙 + 연도 + 길이 + 곡 수 + 디스크 + 트랙 오름차순 지금 재생 중 재생 @@ -196,7 +196,7 @@ 전송속도 없음 샘플 속도 없음 MPEG-1 오디오 - 추가된 날짜 + 추가된 날짜 상위 경로 맞춤형 재생 동작 버튼 반복 방식 diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 2066d5f6d..e16f4ce22 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -6,12 +6,12 @@ Filtruoti Visos Rūšiuoti - Pavadinimas - Metai - Trukmė - Dainų skaičius - Diskas - Pridėta data + Pavadinimas + Metai + Trukmė + Dainų skaičius + Diskas + Pridėta data Kylantis Groti kitą Pridėti į eilę @@ -29,7 +29,7 @@ Juodoji tema Atlikėjai Albumai - Takelis + Takelis Dabar groja Groti Licencijos diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml index 4b495347c..33bad0d0b 100644 --- a/app/src/main/res/values-ml/strings.xml +++ b/app/src/main/res/values-ml/strings.xml @@ -9,7 +9,7 @@ അജ്ഞാത കലാകാരൻ ചാരനിറം ഒറ്റയായ - തീയതി + തീയതി എല്ലാ പാട്ടുകളും കലാകാരൻ കലാകാരന്മാർ @@ -17,8 +17,8 @@ വിഭാഗം തിരയുക അടുക്കുക - പേര് - ദൈർഘ്യം + പേര് + ദൈർഘ്യം പാട്ടിന്റെ സവിശേഷതകൾ എല്ലാം അടുത്തത് കളിക്കുക @@ -78,8 +78,8 @@ വീണ്ടും ശ്രമിക്കുക അനുവദിക്കുക ഗാനങ്ങൾ - പാട്ടുകളുടെ എണ്ണം - തീയതി ചേർത്തു + പാട്ടുകളുടെ എണ്ണം + തീയതി ചേർത്തു ആരോഹണം ഇപ്പോൾ കളിക്കുന്നു കളിക്കുക diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 888c0fca4..57a41a45c 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -116,11 +116,11 @@ Muziekweergave bekijken en regelen %d Hz Bekijk eigenschappen - Naam + Naam Artiest @android:string/cancel Bibliotheek tabbladen - Jaar + Jaar Ouderpad Lied eigenschappen Bestandsnaam @@ -181,10 +181,10 @@ Genres geladen: %d Muziek aan het laden Album - Looptijd - Aantal Liedjes - Disc - Titel + Looptijd + Aantal Liedjes + Disc + Titel Formaat Grootte Bitsnelheid diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index 4d6dacc1c..ba300f4c6 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -38,12 +38,12 @@ ਫਿਲਟਰ ਸਾਰੇ ਲੜੀਬੱਧ - ਨਾਮ - ਮਿਤੀ - ਮਿਆਦ - ਡਿਸਕ - ਟਰੈਕ - ਮਿਤੀ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ + ਨਾਮ + ਮਿਤੀ + ਮਿਆਦ + ਡਿਸਕ + ਟਰੈਕ + ਮਿਤੀ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ ਵੱਧਦੇ ਹੋਏ ਹੁਣ ਚੱਲ ਰਿਹਾ ਹੈ ਇਕੋਲਾਈਜ਼ਰ @@ -74,7 +74,7 @@ ਲਾਇਬ੍ਰੇਰੀ ਦੇ ਅੰਕੜੇ ਐਂਡਰੌਇਡ ਲਈ ਇੱਕ ਸਰਲ, ਤਰਕਸੰਗਤ ਸੰਗੀਤ ਪਲੇਅਰ। ਖੋਜੋ - ਗੀਤ ਦੀ ਗਿਣਤੀ + ਗੀਤ ਦੀ ਗਿਣਤੀ ਘਟਦੇ ਹੋਏ ਚੁਣਿਆ ਹੋਇਆ ਚਲਾਓ ਕਲਾਕਾਰ \'ਤੇ ਜਾਓ diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 52cfc1e2d..b6baeb34a 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -83,7 +83,7 @@ Nieznana data Nieznana częstotliwość próbkowania MPEG-1 audio - Utwór + Utwór Wyświetl szczegóły Szczegóły utworu Częstotliwość próbkowania @@ -98,7 +98,7 @@ Format Niebieskozielony Płyta %d - Data dodania + Data dodania Okładka albumu %s Ikona Auxio Włącz lub wyłącz odtwarzanie losowe @@ -117,14 +117,14 @@ Czarny motyw Ciemny fiolet -%.1f dB - Nazwa - Rok + Nazwa + Rok Singiel Single - Czas trwania + Czas trwania Składanka - Liczba utworów - Płyta + Liczba utworów + Płyta Wykonawca Zapisz Składanki diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index fbe7475b6..e424de1a5 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -98,11 +98,11 @@ O Auxio precisa de permissão para ler sua biblioteca de músicas Um reprodutor de música simples e racional para android. Carregando sua biblioteca de músicas… - Ano - Duração - Contagem de músicas - Disco - Nome + Ano + Duração + Contagem de músicas + Disco + Nome Artista Álbum Propriedades da música @@ -172,7 +172,7 @@ Prefira o álbum se estiver tocando Recarregamento automático Recarrega a biblioteca de músicas sempre que ela mudar (requer notificação fixa) - Data adicionada + Data adicionada Cancelar Preferir faixa Abrir fila @@ -213,7 +213,7 @@ Compilação Single remix Conteúdo - Faixa + Faixa Ao tocar da biblioteca Ao tocar a partir dos detalhes do item Mixtapes diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index bef6734f7..85da07c0a 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -78,15 +78,15 @@ Artistas carregados: %d Duração total: %s Falha no carregamento da música - Nome + Nome Prefira o álbum se estiver tocando Nenhuma aplicação encontrada que possa lidar com esta tarefa Ciano - Contagem de músicas + Contagem de músicas Formato Estatísticas da biblioteca Capa do álbum - Ano + Ano Rápido Qualidade alta Ação da barra de reprodução personalizada @@ -100,8 +100,8 @@ Remover pasta Compilações de remix Compilação ao vivo - Disco - Faixa + Disco + Faixa Taxa de bits Pular para o próximo Aviso: Alterar o pré-amplificador para um valor positivo alto pode resultar em picos em algumas faixas de áudio. @@ -109,7 +109,7 @@ Barra (/) Mais (+) Áudio Ogg - Data adicionada + Data adicionada Taxa de amostragem Gravar Separadores multi-valor @@ -136,7 +136,7 @@ Compilações Compilação Ao vivo - Duração + Duração Cancelar A carregar a sua biblioteca de músicas… Gira de onde a música deve ser carregada diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index acf5d2c6d..4170d35de 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -92,17 +92,17 @@ Amestecă-le pe toate Bine Anulează - Disc + Disc Vezi proprietăți - Data + Data Mix Mixuri - Piesă - Durată - Număr de melodii + Piesă + Durată + Număr de melodii Egalizator Bit rate - Data adăugării + Data adăugării Calea principală Format Proprietățile cântecului @@ -124,7 +124,7 @@ Artist Coloane sonore Coloană sonoră - Nume + Nume Personalizați controalele și comportamentul UI Tema neagră Schimbați tema și culorile aplicației diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 549ae6d7a..0720673e3 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -15,10 +15,10 @@ Фильтр Все Сортировать - Название + Название Исполнитель Альбом - Год + Год По возрастанию Сейчас играет Играть @@ -148,10 +148,10 @@ ОК При воспроизведении из сведений Воспроизведение с показанного элемента - Номер песни + Номер песни Битрейт - Диск - Трек + Диск + Трек Состояние восстановлено Отмена Внимание: Изменение предусилителя на большое положительное значение может привести к появлению искажений на некоторых звуковых дорожках. @@ -164,12 +164,12 @@ Предусилитель применяется к существующей настройке во время воспроизведения Статистика библиотеки Восстановить состояние воспроизведения - Продолжительность + Продолжительность Имя файла Мини-альбом Мини-альбомы Сингл - Дата добавления + Дата добавления Синглы Предусилитель ReplayGain Исключить diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 35db24609..d97f5aae4 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -64,9 +64,9 @@ Ekle Kaydet Toplam süre: %s - Şarkı sayısı - Disk - Parça + Şarkı sayısı + Disk + Parça Boyut Bit hızı Örnek hızı @@ -74,11 +74,11 @@ Android için basit, rasyonel bir müzik çalar. Müzik yükleniyor Müzik kitaplığınız yükleniyor… - Ad + Ad Sanatçı Albüm - Yıl - Süre + Yıl + Süre Durum kaydedildi Alexander Capehart tarafından geliştirildi Siyah tema @@ -192,7 +192,7 @@ Müzik kitaplığı değişiklikler için denetleniyor… Otomatik yeniden yükleme Müzik kitaplığı her değiştiğinde yeniden yükleyin (kalıcı bildirim gerektirir) - Eklendiği tarih + Eklendiği tarih Remix albüm Canlı albüm Bu şarkıyı kuyruktan kaldır diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 47fb22a76..bc731c721 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -82,7 +82,7 @@ Концертний альбом Шлях до каталогу Екран - Дата + Дата Відтворити вибране Обкладинки альбомів Приховати співавторів @@ -94,7 +94,7 @@ Загальна тривалість: %s Мікстейпи Виконавець - Тривалість + Тривалість Мікси Мікс Заокруглені обкладинки @@ -102,7 +102,7 @@ Властивості пісні Додати Ставити на паузу при повторенні пісні - Дата додавання + Дата додавання Частота дискретизації Висока якість Оновити музику @@ -115,9 +115,9 @@ Запам\'ятати перемішування Пауза при повторенні Жанр - Диск + Диск За зростанням - Назва + Назва Переглянути властивості Ігнорувати аудіо файли які не являються музикою, наприклад, подкасти Виключити інші звукові файли @@ -126,7 +126,7 @@ Концертна збірка Мініальбом Мініальбоми - Номер пісні + Номер пісні Завжди починати відтворення при підключенні гарнітури (може працювати не на всіх пристроях) Мініальбом реміксів Концертний сингл @@ -181,7 +181,7 @@ Зберегти стан відтворення Очистити стан відтворення Відновити стан відтворення - Пісня + Пісня Стан відтворення відновлено Перегляд і керування відтворенням музики Перемотайте на початок пісні перед відтворенням попередньої diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index bf26d917b..6f8174ce8 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -15,10 +15,10 @@ 过滤器 全部 排序方式 - 名称 + 名称 艺术家 专辑 - 年份 + 年份 首字符(正序) 正在播放 播放 @@ -173,10 +173,10 @@ 没有采样率信息 音乐加载中 正在加载您的音乐库…… - 碟片 - 时长 - 歌曲计数 - 音轨 + 碟片 + 时长 + 歌曲计数 + 音轨 查看属性 曲目属性 文件名 @@ -210,7 +210,7 @@ 混音带 混音带 混音 - 添加日期 + 添加日期 混音专辑 现场 EP 现场专辑 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 0734c59d5..345d98a3e 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -55,7 +55,7 @@ 檢測音樂庫 格式 黑色主題 - 時長 + 時長 大小 位元率 取樣頻率 diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 2535c992e..03936b846 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -7,6 +7,7 @@ %1$s • %2$s %1$s • %2$s • %3$s %d + %1$s (%2$s) %s - %s %1$s/%2$s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6ae4291c5..a8e92346e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -83,14 +83,15 @@ All + Name + Date + Duration + Song count + Disc + Track + Date added + Sort - Name - Date - Duration - Song count - Disc - Track - Date added Ascending Descending @@ -311,11 +312,8 @@ Unknown artist Unknown genre No date - No track number + No track No music playing - Unknown format - No bitrate - No sample rate