music: replace loading with indexing

Replace all in-code instances of music loading with music indexing,
primarily for clarity.
This commit is contained in:
OxygenCobalt 2022-06-05 19:30:45 -06:00
parent fb3c32b14c
commit 0a18883a6a
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
26 changed files with 152 additions and 147 deletions

View file

@ -53,6 +53,7 @@ import org.oxycblt.auxio.ui.DisplayMode
import org.oxycblt.auxio.ui.MainNavigationAction
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.getColorStateListSafe
import org.oxycblt.auxio.util.launch
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE
@ -92,11 +93,16 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
updateTabConfiguration()
binding.homeLoadingContainer.setOnApplyWindowInsetsListener { view, insets ->
binding.homeIndexingContainer.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(bottom = insets.systemBarInsetsCompat.bottom)
insets
}
// Load the track color in manually as it's unclear whether the track actually supports
// using a ColorStateList in the resources
binding.homeIndexingProgress.trackColor =
requireContext().getColorStateListSafe(R.color.sel_track).defaultColor
binding.homePager.apply {
adapter = HomePagerAdapter()
@ -262,41 +268,41 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
val binding = requireBinding()
when (state) {
is Indexer.State.Complete -> handleLoaderResponse(binding, state.response)
is Indexer.State.Loading -> handleLoadingState(binding, state.loading)
is Indexer.State.Complete -> handleIndexerResponse(binding, state.response)
is Indexer.State.Indexing -> handleIndexingState(binding, state.indexing)
null -> {
logW("Loading is in indeterminate state, doing nothing")
logW("Indexer is in indeterminate state, doing nothing")
}
}
}
private fun handleLoaderResponse(binding: FragmentHomeBinding, response: Indexer.Response) {
private fun handleIndexerResponse(binding: FragmentHomeBinding, response: Indexer.Response) {
if (response is Indexer.Response.Ok) {
binding.homeFab.show()
binding.homeLoadingContainer.visibility = View.INVISIBLE
binding.homeIndexingContainer.visibility = View.INVISIBLE
binding.homePager.visibility = View.VISIBLE
} else {
binding.homeFab.hide()
binding.homePager.visibility = View.INVISIBLE
binding.homeLoadingContainer.visibility = View.VISIBLE
binding.homeIndexingContainer.visibility = View.VISIBLE
logD("Received non-ok response $response")
when (response) {
is Indexer.Response.Ok -> error("Unreachable")
is Indexer.Response.Err -> {
binding.homeLoadingProgress.visibility = View.INVISIBLE
binding.homeLoadingStatus.textSafe = getString(R.string.err_load_failed)
binding.homeLoadingAction.apply {
binding.homeIndexingProgress.visibility = View.INVISIBLE
binding.homeIndexingStatus.textSafe = getString(R.string.err_index_failed)
binding.homeIndexingAction.apply {
visibility = View.VISIBLE
text = getString(R.string.lbl_retry)
setOnClickListener { indexerModel.reindex() }
}
}
is Indexer.Response.NoMusic -> {
binding.homeLoadingProgress.visibility = View.INVISIBLE
binding.homeLoadingStatus.textSafe = getString(R.string.err_no_music)
binding.homeLoadingAction.apply {
binding.homeIndexingProgress.visibility = View.INVISIBLE
binding.homeIndexingStatus.textSafe = getString(R.string.err_no_music)
binding.homeIndexingAction.apply {
visibility = View.VISIBLE
text = getString(R.string.lbl_retry)
setOnClickListener { indexerModel.reindex() }
@ -308,9 +314,9 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
"Cannot access permission launcher while detached"
}
binding.homeLoadingProgress.visibility = View.INVISIBLE
binding.homeLoadingStatus.textSafe = getString(R.string.err_no_perms)
binding.homeLoadingAction.apply {
binding.homeIndexingProgress.visibility = View.INVISIBLE
binding.homeIndexingStatus.textSafe = getString(R.string.err_no_perms)
binding.homeIndexingAction.apply {
visibility = View.VISIBLE
text = getString(R.string.lbl_grant)
setOnClickListener {
@ -322,25 +328,25 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
}
}
private fun handleLoadingState(binding: FragmentHomeBinding, loading: Indexer.Loading) {
private fun handleIndexingState(binding: FragmentHomeBinding, indexing: Indexer.Indexing) {
binding.homeFab.hide()
binding.homePager.visibility = View.INVISIBLE
binding.homeLoadingContainer.visibility = View.VISIBLE
binding.homeLoadingProgress.visibility = View.VISIBLE
binding.homeLoadingAction.visibility = View.INVISIBLE
binding.homeIndexingContainer.visibility = View.VISIBLE
binding.homeIndexingProgress.visibility = View.VISIBLE
binding.homeIndexingAction.visibility = View.INVISIBLE
when (loading) {
is Indexer.Loading.Indeterminate -> {
binding.homeLoadingStatus.textSafe = getString(R.string.lbl_loading)
binding.homeLoadingProgress.isIndeterminate = true
when (indexing) {
is Indexer.Indexing.Indeterminate -> {
binding.homeIndexingStatus.textSafe = getString(R.string.lbl_indexing)
binding.homeIndexingProgress.isIndeterminate = true
}
is Indexer.Loading.Songs -> {
binding.homeLoadingStatus.textSafe =
getString(R.string.fmt_indexing, loading.current, loading.total)
binding.homeLoadingProgress.apply {
is Indexer.Indexing.Songs -> {
binding.homeIndexingStatus.textSafe =
getString(R.string.fmt_indexing, indexing.current, indexing.total)
binding.homeIndexingProgress.apply {
isIndeterminate = false
max = loading.total
progress = loading.current
max = indexing.total
progress = indexing.current
}
}
}

View file

@ -56,7 +56,7 @@ import org.oxycblt.auxio.util.logE
*/
class Indexer {
private var lastResponse: Response? = null
private var loadingState: Loading? = null
private var indexingState: Indexing? = null
private var currentGeneration = 0L
private val callbacks = mutableListOf<Callback>()
@ -66,11 +66,11 @@ class Indexer {
* loaded, yet no loading is going on.
*/
val isIndeterminate: Boolean
get() = lastResponse == null && loadingState == null
get() = lastResponse == null && indexingState == null
fun addCallback(callback: Callback) {
val currentState =
loadingState?.let { State.Loading(it) } ?: lastResponse?.let { State.Complete(it) }
indexingState?.let { State.Indexing(it) } ?: lastResponse?.let { State.Complete(it) }
callback.onIndexerStateChanged(currentState)
callbacks.add(callback)
@ -98,7 +98,7 @@ class Indexer {
val library = withContext(Dispatchers.IO) { indexImpl(context, generation) }
if (library != null) {
logD(
"Music load completed successfully in " +
"Music indexing completed successfully in " +
"${System.currentTimeMillis() - start}ms")
Response.Ok(library)
} else {
@ -106,7 +106,7 @@ class Indexer {
Response.NoMusic
}
} catch (e: Exception) {
logE("Music loading failed.")
logE("Music indexing failed.")
logE(e.stackTraceToString())
Response.Err(e)
}
@ -133,22 +133,22 @@ class Indexer {
fun cancelLast() {
synchronized(this) {
currentGeneration++
emitLoading(null, currentGeneration)
emitIndexing(null, currentGeneration)
}
}
private fun emitLoading(loading: Loading?, generation: Long) {
private fun emitIndexing(indexing: Indexing?, generation: Long) {
synchronized(this) {
if (currentGeneration != generation) {
return
}
loadingState = loading
indexingState = indexing
// If we have canceled the loading process, we want to revert to a previous completion
// whenever possible to prevent state inconsistency.
val state =
loadingState?.let { State.Loading(it) } ?: lastResponse?.let { State.Complete(it) }
indexingState?.let { State.Indexing(it) } ?: lastResponse?.let { State.Complete(it) }
for (callback in callbacks) {
callback.onIndexerStateChanged(state)
@ -163,7 +163,7 @@ class Indexer {
}
lastResponse = response
loadingState = null
indexingState = null
val state = State.Complete(response)
for (callback in callbacks) {
@ -177,11 +177,10 @@ class Indexer {
* calling this function.
*/
private fun indexImpl(context: Context, generation: Long): MusicStore.Library? {
emitLoading(Loading.Indeterminate, generation)
emitIndexing(Indexing.Indeterminate, generation)
// Establish the backend to use when initially loading songs.
val mediaStoreBackend =
when {
val mediaStoreBackend = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> Api30MediaStoreBackend()
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> Api29MediaStoreBackend()
else -> Api21MediaStoreBackend()
@ -230,7 +229,7 @@ class Indexer {
"Successfully queried media database " +
"in ${System.currentTimeMillis() - start}ms")
backend.loadSongs(context, cursor) { loading -> emitLoading(loading, generation) }
backend.buildSongs(context, cursor) { indexing -> emitIndexing(indexing, generation) }
}
// Deduplicate songs to prevent (most) deformed music clones
@ -251,7 +250,7 @@ class Indexer {
// Ensure that sorting order is consistent so that grouping is also consistent.
Sort.ByName(true).songsInPlace(songs)
logD("Successfully loaded ${songs.size} songs in ${System.currentTimeMillis() - start}ms")
logD("Successfully built ${songs.size} songs in ${System.currentTimeMillis() - start}ms")
return songs
}
@ -344,13 +343,13 @@ class Indexer {
/** Represents the current indexer state. */
sealed class State {
data class Loading(val loading: Indexer.Loading) : State()
data class Indexing(val indexing: Indexer.Indexing) : State()
data class Complete(val response: Response) : State()
}
sealed class Loading {
object Indeterminate : Loading()
class Songs(val current: Int, val total: Int) : Loading()
sealed class Indexing {
object Indeterminate : Indexing()
class Songs(val current: Int, val total: Int) : Indexing()
}
/** Represents the possible outcomes of a loading process. */
@ -385,10 +384,10 @@ class Indexer {
fun query(context: Context): Cursor
/** Create a list of songs from the [Cursor] queried in [query]. */
fun loadSongs(
fun buildSongs(
context: Context,
cursor: Cursor,
emitLoading: (Loading) -> Unit
emitIndexing: (Indexing) -> Unit
): Collection<Song>
}

View file

@ -28,7 +28,6 @@ import androidx.core.app.NotificationCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.IntegerTable
@ -64,7 +63,7 @@ class IndexerService : Service(), Indexer.Callback {
indexer.addCallback(this)
if (musicStore.library == null && indexer.isIndeterminate) {
logD("No library present and no previous response, loading music now")
logD("No library present and no previous response, indexing music now")
onRequestReindex()
}
@ -105,12 +104,12 @@ class IndexerService : Service(), Indexer.Callback {
// database.
stopForegroundSession()
}
is Indexer.State.Loading -> {
is Indexer.State.Indexing -> {
// When loading, we want to enter the foreground state so that android does
// not shut off the loading process. Note that while we will always post the
// notification when initially starting, we will not update the notification
// unless it indicates that we have changed it.
val changed = notification.updateLoadingState(state.loading)
val changed = notification.updateIndexingState(state.indexing)
if (!isForeground) {
logD("Starting foreground session")
startForeground(IntegerTable.INDEXER_NOTIFICATION_CODE, notification.build())
@ -163,7 +162,7 @@ private class IndexerNotification(private val context: Context) :
setContentIntent(context.newMainPendingIntent())
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
setContentTitle(context.getString(R.string.info_indexer_channel_name))
setContentText(context.getString(R.string.lbl_loading))
setContentText(context.getString(R.string.lbl_indexing))
setProgress(0, 0, true)
}
@ -171,19 +170,19 @@ private class IndexerNotification(private val context: Context) :
notificationManager.notify(IntegerTable.INDEXER_NOTIFICATION_CODE, build())
}
fun updateLoadingState(loading: Indexer.Loading): Boolean {
when (loading) {
is Indexer.Loading.Indeterminate -> {
setContentText(context.getString(R.string.lbl_loading))
fun updateIndexingState(indexing: Indexer.Indexing): Boolean {
when (indexing) {
is Indexer.Indexing.Indeterminate -> {
setContentText(context.getString(R.string.lbl_indexing))
setProgress(0, 0, true)
return true
}
is Indexer.Loading.Songs -> {
is Indexer.Indexing.Songs -> {
// Only update the notification every 50 songs to prevent excessive updates.
if (loading.current % 50 == 0) {
if (indexing.current % 50 == 0) {
setContentText(
context.getString(R.string.fmt_indexing, loading.current, loading.total))
setProgress(loading.total, loading.current, false)
context.getString(R.string.fmt_indexing, indexing.current, indexing.total))
setProgress(indexing.total, indexing.current, false)
return true
}
}

View file

@ -59,10 +59,10 @@ class ExoPlayerBackend(private val inner: MediaStoreBackend) : Indexer.Backend {
// MediaStore.
override fun query(context: Context) = inner.query(context)
override fun loadSongs(
override fun buildSongs(
context: Context,
cursor: Cursor,
emitLoading: (Indexer.Loading) -> Unit
emitIndexing: (Indexer.Indexing) -> Unit
): Collection<Song> {
// Metadata retrieval with ExoPlayer is asynchronous, so a callback may at any point
// add a completed song to the list. To prevent a crash in that case, we use the
@ -91,7 +91,7 @@ class ExoPlayerBackend(private val inner: MediaStoreBackend) : Indexer.Backend {
AudioCallback(audio) {
runningTasks[index] = null
songs.add(it)
emitLoading(Indexer.Loading.Songs(songs.size, total))
emitIndexing(Indexer.Indexing.Songs(songs.size, total))
},
// Normal JVM dispatcher will suffice here, as there is no IO work
// going on (and there is no cost from switching contexts with executors)

View file

@ -125,10 +125,10 @@ abstract class MediaStoreBackend : Indexer.Backend {
selector.args.toTypedArray())) { "Content resolver failure: No Cursor returned" }
}
override fun loadSongs(
override fun buildSongs(
context: Context,
cursor: Cursor,
emitLoading: (Indexer.Loading) -> Unit
emitIndexing: (Indexer.Indexing) -> Unit
): Collection<Song> {
// Note: We do not actually update the callback with a current/total value, this is because
// loading music from MediaStore tends to be quite fast, with the only bottlenecks being
@ -210,8 +210,9 @@ abstract class MediaStoreBackend : Indexer.Backend {
// Try to use the DISPLAY_NAME field to obtain a (probably sane) file name
// from the android system. Once again though, OEM issues get in our way and
// this field isn't available on some platforms. In that case, see if we can
// grok a file name from the DATA field.
// this field isn't available on some platforms. In that case, version-specific
// implementation will fall back to the equivalent of the path field if it
// cannot be obtained here.
audio.displayName = cursor.getStringOrNull(displayNameIndex)
audio.duration = cursor.getLong(durationIndex)

View file

@ -74,7 +74,7 @@ class AboutFragment : ViewBindingFragment<FragmentAboutBinding>() {
private fun updateSongCount(songs: List<Song>) {
val binding = requireBinding()
binding.aboutSongCount.textSafe = getString(R.string.fmt_songs_loaded, songs.size)
binding.aboutSongCount.textSafe = getString(R.string.fmt_song_count, songs.size)
binding.aboutTotalDuration.textSafe =
getString(
R.string.fmt_total_duration, songs.sumOf { it.durationSecs }.formatDuration(false))
@ -82,17 +82,17 @@ class AboutFragment : ViewBindingFragment<FragmentAboutBinding>() {
private fun updateAlbumCount(albums: List<Album>) {
requireBinding().aboutAlbumCount.textSafe =
getString(R.string.fmt_albums_loaded, albums.size)
getString(R.string.fmt_album_count, albums.size)
}
private fun updateArtistCount(artists: List<Artist>) {
requireBinding().aboutArtistCount.textSafe =
getString(R.string.fmt_artists_loaded, artists.size)
getString(R.string.fmt_artist_count, artists.size)
}
private fun updateGenreCount(genres: List<Genre>) {
requireBinding().aboutGenreCount.textSafe =
getString(R.string.fmt_genres_loaded, genres.size)
getString(R.string.fmt_genre_count, genres.size)
}
/** Go through the process of opening a [link] in a browser. */

View file

@ -183,7 +183,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
true
}
}
SettingsManager.KEY_RELOAD -> {
SettingsManager.KEY_REINDEX -> {
onPreferenceClickListener =
Preference.OnPreferenceClickListener {
playbackModel.savePlaybackState(requireContext()) {

View file

@ -323,7 +323,7 @@ class SettingsManager private constructor(context: Context) :
const val KEY_PAUSE_ON_REPEAT = "KEY_LOOP_PAUSE"
const val KEY_SAVE_STATE = "auxio_save_state"
const val KEY_RELOAD = "auxio_reload"
const val KEY_REINDEX = "auxio_reindex"
const val KEY_EXCLUDED = "auxio_excluded_dirs"
const val KEY_SEARCH_FILTER_MODE = "KEY_SEARCH_FILTER"

View file

@ -34,7 +34,7 @@
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/home_loading_container"
android:id="@+id/home_indexing_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
@ -42,35 +42,35 @@
android:paddingEnd="@dimen/spacing_medium">
<TextView
android:id="@+id/home_loading_status"
android:id="@+id/home_indexing_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginBottom="@dimen/spacing_medium"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
app:layout_constraintBottom_toTopOf="@+id/home_loading_action"
app:layout_constraintBottom_toTopOf="@+id/home_indexing_action"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Status" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/home_loading_progress"
android:id="@+id/home_indexing_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
app:indeterminateAnimationType="disjoint"
app:layout_constraintBottom_toBottomOf="@+id/home_loading_action"
app:layout_constraintTop_toTopOf="@+id/home_loading_action"
app:layout_constraintBottom_toBottomOf="@+id/home_indexing_action"
app:layout_constraintTop_toTopOf="@+id/home_indexing_action"
app:trackColor="@color/sel_track" />
<Button
android:id="@+id/home_loading_action"
android:id="@+id/home_indexing_action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/lbl_retry"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/home_loading_status" />
app:layout_constraintTop_toBottomOf="@+id/home_indexing_status" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -104,7 +104,7 @@
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">لم يتم ايجاد موسيقى</string>
<string name="err_load_failed">فشل تحميل الموسيقى</string>
<string name="err_index_failed">فشل تحميل الموسيقى</string>
<string name="err_no_perms">اوكسيو يحتاج إلى صلاحيات لقراءة للاطلاع على مكتبتك للموسيقى</string>
<string name="err_no_app">لا يوجد تطبيق لفتح هذا الرابط</string>
<string name="err_bad_dir">هذا المجلد غير مدعوم</string>
@ -161,7 +161,7 @@
<string name="clr_grey">رمادي</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">الاغنية المُحملة: %d</string>
<string name="fmt_song_count">الاغنية المُحملة: %d</string>
<plurals name="fmt_song_count">
<item quantity="zero">%d اغاني</item>

View file

@ -7,7 +7,7 @@
<string name="info_widget_desc">Zobrazení a ovládání přehrávání hudby</string>
<!-- Label Namespace | Static Labels -->
<string name="lbl_loading">Načítání vaší hudební knihovny…</string>
<string name="lbl_indexing">Načítání vaší hudební knihovny…</string>
<string name="lbl_retry">Zkusit znovu</string>
<string name="lbl_grant">Udělit</string>
@ -115,14 +115,14 @@
<string name="set_content">Obsah</string>
<string name="set_save">Uložit stav přehrávání</string>
<string name="set_save_desc">Uložit aktuální stav přehrávání</string>
<string name="set_reload">Znovu načíst hudbu</string>
<string name="set_reload_desc">Aplikace bude restartována</string>
<string name="set_reindex">Znovu načíst hudbu</string>
<string name="set_reindex_desc">Aplikace bude restartována</string>
<string name="set_excluded">Vyloučené složky</string>
<string name="set_excluded_desc">Obsah vyloučených složek je skrytý z vaší knihovny</string>
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">Nenalezena žádná hudba</string>
<string name="err_load_failed">Načítání hudby selhalo</string>
<string name="err_index_failed">Načítání hudby selhalo</string>
<string name="err_no_perms">Auxio potřebuje oprávnění ke čtení vaší hudební knihovny</string>
<string name="err_no_app">Žádná aplikace nedokáže otevřít tento odkaz</string>
<string name="err_no_dirs">Žádné složky</string>
@ -190,10 +190,10 @@
<string name="fmt_indexing">Načítání hudební knihovny… (%1$d/%2$d)</string>
<string name="fmt_songs_loaded">Načtených skladeb: %d</string>
<string name="fmt_albums_loaded">Načtených alb: %d</string>
<string name="fmt_artists_loaded">Načtených umělců: %d</string>
<string name="fmt_genres_loaded">Načtených žánrů: %d</string>
<string name="fmt_song_count">Načtených skladeb: %d</string>
<string name="fmt_album_count">Načtených alb: %d</string>
<string name="fmt_artist_count">Načtených umělců: %d</string>
<string name="fmt_genre_count">Načtených žánrů: %d</string>
<string name="fmt_total_duration">Celková doba trvání: %s</string>
<plurals name="fmt_song_count">

View file

@ -93,14 +93,14 @@
<string name="set_content">Inhalt</string>
<string name="set_save">Wiedergabezustand speichern</string>
<string name="set_save_desc">Den aktuellen Wiedergabezustand speichern</string>
<string name="set_reload">Musik neu laden</string>
<string name="set_reload_desc">Startet die App neu</string>
<string name="set_reindex">Musik neu laden</string>
<string name="set_reindex_desc">Startet die App neu</string>
<string name="set_excluded">Ausgeschlossene Ordner</string>
<string name="set_excluded_desc">Die Inhalte der ausgeschlossenen Ordner werden nicht deiner Musikbibliothek angezeigt</string>
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">Keine Musik gefunden</string>
<string name="err_load_failed">Laden der Musik fehlgeschlagen</string>
<string name="err_index_failed">Laden der Musik fehlgeschlagen</string>
<string name="err_no_perms">Auxio benötigt die Berechtigung, um deine Musikbibliothek zu lesen</string>
<string name="err_no_app">Link konnte nicht geöffnet werden</string>
<string name="err_bad_dir">Das Verzeichnis wird nicht unterstützt</string>
@ -146,7 +146,7 @@
<string name="clr_grey">Grau</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Geladene Lieder: %d</string>
<string name="fmt_song_count">Geladene Lieder: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d Lied</item>
@ -191,8 +191,8 @@
<string name="fmt_disc_no">Schallplatte %d</string>
<string name="fmt_db_pos">+%.1f dB</string>
<string name="fmt_db_neg">-%.1f dB</string>
<string name="fmt_albums_loaded">Geladene Alben: %d</string>
<string name="fmt_artists_loaded">Geladene Künstler: %d</string>
<string name="fmt_genres_loaded">Geladene Genres: %d</string>
<string name="fmt_album_count">Geladene Alben: %d</string>
<string name="fmt_artist_count">Geladene Künstler: %d</string>
<string name="fmt_genre_count">Geladene Genres: %d</string>
<string name="fmt_total_duration">Gesamtdauer: %s</string>
</resources>

View file

@ -74,7 +74,7 @@
<string name="clr_grey">Γκρί</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Τραγούδια φορτώθηκε: %d</string>
<string name="fmt_song_count">Τραγούδια φορτώθηκε: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d Τραγούδι</item>

View file

@ -99,14 +99,14 @@
<string name="set_content">Contenido</string>
<string name="set_save">Guardar estado de reproducción</string>
<string name="set_save_desc">Guardar el estado de reproduccion ahora</string>
<string name="set_reload">Recargar música</string>
<string name="set_reload_desc">Se reiniciará la aplicación</string>
<string name="set_reindex">Recargar música</string>
<string name="set_reindex_desc">Se reiniciará la aplicación</string>
<string name="set_excluded">Directorios excluidos</string>
<string name="set_excluded_desc">El contenido de los directorios excluidos no se mostrará</string>
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">Sin música</string>
<string name="err_load_failed">Falló la carga de música</string>
<string name="err_index_failed">Falló la carga de música</string>
<string name="err_no_perms">Auxio necesita permiso para leer su biblioteca de música</string>
<string name="err_no_app">Sin aplicación para abrir este enlace</string>
<string name="err_bad_dir">Directorio no soportado</string>
@ -165,7 +165,7 @@
<string name="clr_grey">Gris</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Canciones cargadas: %d</string>
<string name="fmt_song_count">Canciones cargadas: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d Canción</item>

View file

@ -80,7 +80,7 @@
<string name="clr_grey">Gris</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Titres chargés: %d</string>
<string name="fmt_song_count">Titres chargés: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%s Titre</item>

View file

@ -100,8 +100,8 @@
<string name="set_content">Contenuti</string>
<string name="set_save">Salva stato riproduzione</string>
<string name="set_save_desc">Salva lo stato di riproduzione corrente</string>
<string name="set_reload">Ricarica musica</string>
<string name="set_reload_desc">L\'applicazione sarà riavviata</string>
<string name="set_reindex">Ricarica musica</string>
<string name="set_reindex_desc">L\'applicazione sarà riavviata</string>
<string name="set_excluded">Cartelle escluse</string>
<string name="set_excluded_desc">Il contenuto delle cartelle escluse sarà nascosto dalla tua libreria</string>
@ -109,7 +109,7 @@
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">Musica non trovata</string>
<string name="err_load_failed">Caricamento musica fallito</string>
<string name="err_index_failed">Caricamento musica fallito</string>
<string name="err_no_perms">Auxio ha bisogno del permesso per leggere la tua libreria musicale</string>
<string name="err_no_app">Nessuna app può aprire il link</string>
<string name="err_bad_dir">Questa cartella non è supportata</string>
@ -168,10 +168,10 @@
<string name="clr_grey">Grigio</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Canzoni trovate: %d</string>
<string name="fmt_albums_loaded">Dischi trovati: %d</string>
<string name="fmt_artists_loaded">Artisti trovati: %d</string>
<string name="fmt_genres_loaded">Generi trovati: %d</string>
<string name="fmt_song_count">Canzoni trovate: %d</string>
<string name="fmt_album_count">Dischi trovati: %d</string>
<string name="fmt_artist_count">Artisti trovati: %d</string>
<string name="fmt_genre_count">Generi trovati: %d</string>
<string name="fmt_total_duration">Durata totale: %s</string>
<plurals name="fmt_song_count">

View file

@ -113,14 +113,14 @@
<string name="set_content">내용</string>
<string name="set_save">재생 상태 저장</string>
<string name="set_save_desc">현재 재생 상태를 지금 저장</string>
<string name="set_reload">음악 다시 불러오기</string>
<string name="set_reload_desc">앱이 다시 시작됩니다.</string>
<string name="set_reindex">음악 다시 불러오기</string>
<string name="set_reindex_desc">앱이 다시 시작됩니다.</string>
<string name="set_excluded">폴더 제외</string>
<string name="set_excluded_desc">제외한 폴더는 라이브러리에서 숨겨집니다.</string>
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">음악 없음</string>
<string name="err_load_failed">음악 불러오기 실패</string>
<string name="err_index_failed">음악 불러오기 실패</string>
<string name="err_no_perms">앱에서 음악 라이브러리를 읽기 위해 권한이 필요합니다.</string>
<string name="err_no_app">이 링크를 열 수 있는 앱 없음</string>
<string name="err_no_dirs">폴더 없음</string>
@ -186,10 +186,10 @@
<string name="fmt_db_pos">+%.1f dB</string>
<string name="fmt_db_neg">-%.1f dB</string>
<string name="fmt_songs_loaded">불러온 음악: %d</string>
<string name="fmt_albums_loaded">불러온 앨범: %d</string>
<string name="fmt_artists_loaded">불러온 아티스트: %d</string>
<string name="fmt_genres_loaded">불러온 장르: %d</string>
<string name="fmt_song_count">불러온 음악: %d</string>
<string name="fmt_album_count">불러온 앨범: %d</string>
<string name="fmt_artist_count">불러온 아티스트: %d</string>
<string name="fmt_genre_count">불러온 장르: %d</string>
<string name="fmt_total_duration">총 길이: %s</string>
<plurals name="fmt_song_count">

View file

@ -86,7 +86,7 @@
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">Geen muziek aangetroffen</string>
<string name="err_load_failed">Laden van muziek mislukt</string>
<string name="err_index_failed">Laden van muziek mislukt</string>
<string name="err_no_perms">Auxio heeft toestemming nodig om uw muziekbibliotheek te lezen</string>
<string name="err_no_app">Geen app kan deze link openen</string>
<string name="err_bad_dir">Deze map wordt niet ondersteund</string>
@ -133,7 +133,7 @@
<string name="clr_grey">Grijis</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Nummers geladen: %d</string>
<string name="fmt_song_count">Nummers geladen: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d Nummer</item>

View file

@ -78,7 +78,7 @@
<string name="clr_grey">Szary</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Utwory uruchamia się: %d</string>
<string name="fmt_song_count">Utwory uruchamia się: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d Utwór</item>

View file

@ -79,7 +79,7 @@
<string name="clr_grey">Grisalho</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Músicas carregado: %d</string>
<string name="fmt_song_count">Músicas carregado: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d Música</item>

View file

@ -80,7 +80,7 @@
<string name="clr_grey">Grisalho</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Músicas carregado: %d</string>
<string name="fmt_song_count">Músicas carregado: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d Música</item>

View file

@ -101,14 +101,14 @@
<string name="set_content">Библиотека</string>
<string name="set_save">Запоминать позицию</string>
<string name="set_save_desc">Запоминать позицию в треке</string>
<string name="set_reload">Перезагрузить музыку</string>
<string name="set_reload_desc">Это перезапустит приложение</string>
<string name="set_reindex">Перезагрузить музыку</string>
<string name="set_reindex_desc">Это перезапустит приложение</string>
<string name="set_excluded">Исключённые папки</string>
<string name="set_excluded_desc">Содержимое исключённых папок будет скрыто из библиотеки</string>
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">Треков нет</string>
<string name="err_load_failed">Ошибка чтения библиотеки</string>
<string name="err_index_failed">Ошибка чтения библиотеки</string>
<string name="err_no_perms">Auxio требуется разрешение на чтение музыкальной библиотеки</string>
<string name="err_no_app">Нет приложений для открытия данной ссылки</string>
<string name="err_bad_dir">Эта папка не поддерживается</string>
@ -166,7 +166,7 @@
<string name="clr_grey">Серый</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Всего треков: %d</string>
<string name="fmt_song_count">Всего треков: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d трек</item>

View file

@ -60,7 +60,7 @@
<string name="desc_play_pause">Відтворити/Зупинити</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">Пісні завантажено: %d</string>
<string name="fmt_song_count">Пісні завантажено: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d Пісня</item>

View file

@ -99,8 +99,8 @@
<string name="set_content">内容</string>
<string name="set_save">保存播放状态</string>
<string name="set_save_desc">立即保存当前播放状态</string>
<string name="set_reload">重新加载音乐</string>
<string name="set_reload_desc">将会重启应用</string>
<string name="set_reindex">重新加载音乐</string>
<string name="set_reindex_desc">将会重启应用</string>
<string name="set_excluded">排除文件夹</string>
<string name="set_excluded_desc">被排除文件夹的内容将从媒体库中隐藏</string>
@ -108,7 +108,7 @@
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">没有找到音乐</string>
<string name="err_load_failed">加载音乐失败</string>
<string name="err_index_failed">加载音乐失败</string>
<string name="err_no_perms">Auxio 需要权限来读取音乐库</string>
<string name="err_no_app">没有可以打开该链接的应用</string>
<string name="err_bad_dir">该目录不受支持</string>
@ -167,7 +167,7 @@
<string name="clr_grey">灰色</string>
<!-- Format Namespace | Value formatting/plurals -->
<string name="fmt_songs_loaded">已加载 %d 首曲目</string>
<string name="fmt_song_count">已加载 %d 首曲目</string>
<plurals name="fmt_song_count">
<item quantity="other">"%d 首歌曲"</item>

View file

@ -7,7 +7,7 @@
<string name="info_widget_desc">View and control music playback</string>
<!-- Label Namespace | Static Labels -->
<string name="lbl_loading">Loading your music library…</string>
<string name="lbl_indexing">Loading your music library…</string>
<string name="lbl_retry">Retry</string>
<string name="lbl_grant">Grant</string>
@ -115,14 +115,14 @@
<string name="set_content">Content</string>
<string name="set_save">Save playback state</string>
<string name="set_save_desc">Save the current playback state now</string>
<string name="set_reload">Reload music</string>
<string name="set_reload_desc">Will restart app</string>
<string name="set_reindex">Reload music</string>
<string name="set_reindex_desc">Will restart app</string>
<string name="set_excluded">Excluded folders</string>
<string name="set_excluded_desc">The content of excluded folders is hidden from your library</string>
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">No music found</string>
<string name="err_load_failed">Music loading failed</string>
<string name="err_index_failed">Music loading failed</string>
<string name="err_no_perms">Auxio needs permission to read your music library</string>
<string name="err_no_app">No app can open this link</string>
<string name="err_no_dirs">No Folders</string>
@ -190,10 +190,10 @@
<string name="fmt_indexing">Loading your music library… (%1$d/%2$d)</string>
<string name="fmt_songs_loaded">Songs loaded: %d</string>
<string name="fmt_albums_loaded">Albums loaded: %d</string>
<string name="fmt_artists_loaded">Artists loaded: %d</string>
<string name="fmt_genres_loaded">Genres loaded: %d</string>
<string name="fmt_song_count">Songs loaded: %d</string>
<string name="fmt_album_count">Albums loaded: %d</string>
<string name="fmt_artist_count">Artists loaded: %d</string>
<string name="fmt_genre_count">Genres loaded: %d</string>
<string name="fmt_total_duration">Total duration: %s</string>
<plurals name="fmt_song_count">

View file

@ -153,9 +153,9 @@
<Preference
app:iconSpaceReserved="false"
app:key="auxio_reload"
app:summary="@string/set_reload_desc"
app:title="@string/set_reload" />
app:key="auxio_reindex"
app:summary="@string/set_reindex_desc"
app:title="@string/set_reindex" />
<Preference
app:iconSpaceReserved="false"