From 17e49ff49e2e5f5e9be94849b6880b076f9eba45 Mon Sep 17 00:00:00 2001 From: Nite Date: Mon, 20 Dec 2021 13:15:45 +0100 Subject: [PATCH 01/24] Updated custom cache location handling to remove isUri Fixed DownloadFileCache contained DownloadFiles with old cache path --- .../ultrasonic/fragment/SettingsFragment.kt | 87 ++++++++++--------- .../moire/ultrasonic/service/Downloader.kt | 6 ++ .../service/MediaPlayerController.kt | 5 ++ .../org/moire/ultrasonic/util/Settings.kt | 5 +- .../org/moire/ultrasonic/util/Storage.kt | 15 ++-- 5 files changed, 65 insertions(+), 53 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt index b551fd29..ed65a05e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt @@ -50,7 +50,6 @@ import org.moire.ultrasonic.util.Storage import org.moire.ultrasonic.util.TimeSpanPreference import org.moire.ultrasonic.util.TimeSpanPreferenceDialogFragmentCompat import org.moire.ultrasonic.util.Util.toast -import org.moire.ultrasonic.util.isUri import timber.log.Timber /** @@ -171,31 +170,36 @@ class SettingsFragment : */ override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { if ( - requestCode != SELECT_CACHE_ACTIVITY || - resultCode != Activity.RESULT_OK || - resultData == null - ) return + requestCode == SELECT_CACHE_ACTIVITY && + resultCode == Activity.RESULT_OK && + resultData != null + ) { + val read = (resultData.flags and Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0 + val write = (resultData.flags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0 + val persist = (resultData.flags and Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0 - val read = (resultData.flags and Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0 - val write = (resultData.flags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0 - val persist = (resultData.flags and Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0 + if (read && write && persist) { + if (resultData.data != null) { + // The result data contains a URI for the document or directory that + // the user selected. + val uri = resultData.data!! + val contentResolver = UApp.applicationContext().contentResolver - if (!read || !write || !persist) { + contentResolver.takePersistableUriPermission(uri, RW_FLAG) + setCacheLocation(uri.toString()) + setupCacheLocationPreference() + return + } + } ErrorDialog.Builder(context) .setMessage(R.string.settings_cache_location_error) .show() - return } - // The result data contains a URI for the document or directory that - // the user selected. - resultData.data?.also { uri -> - // Perform operations on the document using its URI. - val contentResolver = UApp.applicationContext().contentResolver - - contentResolver.takePersistableUriPermission(uri, RW_FLAG) - - setCacheLocation(uri.toString()) + if (Settings.cacheLocationUri == "") { + Settings.customCacheLocation = false + customCacheLocation?.isChecked = false + setupCacheLocationPreference() } } @@ -234,7 +238,12 @@ class SettingsFragment : RxBus.themeChangedEventPublisher.onNext(Unit) } Constants.PREFERENCES_KEY_CUSTOM_CACHE_LOCATION -> { - setupCacheLocationPreference() + if (Settings.customCacheLocation) { + selectCacheLocation() + } else { + if (Settings.cacheLocationUri != "") setCacheLocation("") + setupCacheLocationPreference() + } } } } @@ -259,34 +268,32 @@ class SettingsFragment : } private fun setupCacheLocationPreference() { - val isDefault = Settings.cacheLocation == defaultMusicDirectory.path - if (!Settings.customCacheLocation) { cacheLocation?.isVisible = false - if (!isDefault) setCacheLocation(defaultMusicDirectory.path) return } cacheLocation?.isVisible = true - val uri = Uri.parse(Settings.cacheLocation) + val uri = Uri.parse(Settings.cacheLocationUri) cacheLocation!!.summary = uri.path - cacheLocation!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { + cacheLocation!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + selectCacheLocation() + true + } + } - // Choose a directory using the system's file picker. - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + private fun selectCacheLocation() { + // Choose a directory using the system's file picker. + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - if (!isDefault && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, defaultMusicDirectory.path) - } + if (Settings.cacheLocationUri != "" && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, defaultMusicDirectory.path) + } - intent.addFlags(RW_FLAG) - intent.addFlags(PERSISTABLE_FLAG) + intent.addFlags(RW_FLAG) + intent.addFlags(PERSISTABLE_FLAG) - startActivityForResult(intent, SELECT_CACHE_ACTIVITY) - - true - } + startActivityForResult(intent, SELECT_CACHE_ACTIVITY) } private fun setupBluetoothDevicePreferences() { @@ -393,7 +400,6 @@ class SettingsFragment : sharingDefaultExpiration!!.summary = sharingDefaultExpiration!!.text sharingDefaultDescription!!.summary = sharingDefaultDescription!!.text sharingDefaultGreeting!!.summary = sharingDefaultGreeting!!.text - cacheLocation!!.summary = Settings.cacheLocation if (!mediaButtonsEnabled!!.isChecked) { lockScreenEnabled!!.isChecked = false lockScreenEnabled!!.isEnabled = false @@ -438,15 +444,16 @@ class SettingsFragment : } private fun setCacheLocation(path: String) { - if (path.isUri()) { + if (path != "") { val uri = Uri.parse(path) cacheLocation!!.summary = uri.path ?: "" } - Settings.cacheLocation = path + Settings.cacheLocationUri = path // Clear download queue. mediaPlayerControllerLazy.value.clear() + mediaPlayerControllerLazy.value.clearCaches() Storage.reset() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/Downloader.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/Downloader.kt index d2c0ea22..7aa00bbb 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/Downloader.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/Downloader.kt @@ -44,6 +44,7 @@ class Downloader( private val jukeboxMediaPlayer: JukeboxMediaPlayer by inject() + // TODO is this cache necessary? private val downloadFileCache = LRUCache(100) private var executorService: ScheduledExecutorService? = null @@ -281,6 +282,11 @@ class Downloader( @Synchronized fun getPlaylist(): List = playlist + @Synchronized + fun clearDownloadFileCache() { + downloadFileCache.clear() + } + @Synchronized fun clearPlaylist() { playlist.clear() diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt index 55cf2796..54f76a4c 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt @@ -280,6 +280,11 @@ class MediaPlayerController( jukeboxMediaPlayer.updatePlaylist() } + @Synchronized + fun clearCaches() { + downloader.clearDownloadFileCache() + } + @Synchronized fun clearIncomplete() { reset() diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt index e5240e33..d025563e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt @@ -112,9 +112,8 @@ object Settings { ) @JvmStatic - var cacheLocation by StringSetting( - Constants.PREFERENCES_KEY_CACHE_LOCATION, - FileUtil.defaultMusicDirectory.path + var cacheLocationUri by StringSetting( + Constants.PREFERENCES_KEY_CACHE_LOCATION, "" ) @JvmStatic diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Storage.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Storage.kt index 3ab71bd3..3af8f6fa 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Storage.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Storage.kt @@ -31,7 +31,8 @@ object Storage { Timber.i("StorageFile caches were reset") val root = getRoot() if (root == null) { - Settings.cacheLocation = FileUtil.defaultMusicDirectory.path + Settings.customCacheLocation = false + Settings.cacheLocationUri = "" Util.toast(UApp.applicationContext(), R.string.settings_cache_location_error) } } @@ -70,22 +71,16 @@ object Storage { } private fun getRoot(): AbstractFile? { - return if (Settings.cacheLocation.isUri()) { + return if (Settings.customCacheLocation) { val documentFile = DocumentFile.fromTreeUri( UApp.applicationContext(), - Uri.parse(Settings.cacheLocation) + Uri.parse(Settings.cacheLocationUri) ) ?: return null if (!documentFile.exists()) return null StorageFile(null, documentFile.uri, documentFile.name!!, documentFile.isDirectory) } else { - val file = File(Settings.cacheLocation) - if (!file.exists()) return null + val file = File(FileUtil.defaultMusicDirectory.path) JavaFile(null, file) } } } - -fun String.isUri(): Boolean { - // TODO is there a better way to tell apart a path and an URI? - return this.contains(':') -} From fa434342d91793c7d5f26565d6cb5a110518c674 Mon Sep 17 00:00:00 2001 From: tzugen Date: Tue, 16 Nov 2021 19:41:12 +0100 Subject: [PATCH 02/24] Covert LRUCache to Kotlin --- .../org/moire/ultrasonic/util/LRUCache.java | 117 ------------------ .../org/moire/ultrasonic/util/LRUCache.kt | 79 ++++++++++++ 2 files changed, 79 insertions(+), 117 deletions(-) delete mode 100644 ultrasonic/src/main/java/org/moire/ultrasonic/util/LRUCache.java create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/LRUCache.kt diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/LRUCache.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/LRUCache.java deleted file mode 100644 index 2adc7cea..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/LRUCache.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.util; - -import java.lang.ref.SoftReference; -import java.util.HashMap; -import java.util.Map; - -/** - * @author Sindre Mehus - */ -public class LRUCache -{ - - private final int capacity; - private final Map map; - - public LRUCache(int capacity) - { - map = new HashMap(capacity); - this.capacity = capacity; - } - - public synchronized V get(K key) - { - TimestampedValue value = map.get(key); - - V result = null; - if (value != null) - { - value.updateTimestamp(); - result = value.getValue(); - } - - return result; - } - - public synchronized void put(K key, V value) - { - if (map.size() >= capacity) - { - removeOldest(); - } - map.put(key, new TimestampedValue(value)); - } - - public void clear() - { - map.clear(); - } - - private void removeOldest() - { - K oldestKey = null; - long oldestTimestamp = Long.MAX_VALUE; - - for (Map.Entry entry : map.entrySet()) - { - K key = entry.getKey(); - TimestampedValue value = entry.getValue(); - if (value.getTimestamp() < oldestTimestamp) - { - oldestTimestamp = value.getTimestamp(); - oldestKey = key; - } - } - - if (oldestKey != null) - { - map.remove(oldestKey); - } - } - - private final class TimestampedValue - { - - private final SoftReference value; - private long timestamp; - - public TimestampedValue(V value) - { - this.value = new SoftReference(value); - updateTimestamp(); - } - - public V getValue() - { - return value.get(); - } - - public long getTimestamp() - { - return timestamp; - } - - public void updateTimestamp() - { - timestamp = System.currentTimeMillis(); - } - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/LRUCache.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/LRUCache.kt new file mode 100644 index 00000000..22ab7f60 --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/LRUCache.kt @@ -0,0 +1,79 @@ +/* + * LRUCache.kt + * Copyright (C) 2009-2021 Ultrasonic developers + * + * Distributed under terms of the GNU GPLv3 license. + */ +package org.moire.ultrasonic.util + +import java.lang.ref.SoftReference +import java.util.HashMap + +/** + * A cache that deletes the least-recently-used items. + */ +class LRUCache(capacity: Int) { + private val capacity: Int + private val map: MutableMap + + @Synchronized + operator fun get(key: K): V? { + val value = map[key] + var result: V? = null + if (value != null) { + value.updateTimestamp() + result = value.getValue() + } + return result + } + + @Synchronized + fun put(key: K, value: V) { + if (map.size >= capacity) { + removeOldest() + } + map[key] = TimestampedValue(value) + } + + fun clear() { + map.clear() + } + + private fun removeOldest() { + var oldestKey: K? = null + var oldestTimestamp = Long.MAX_VALUE + for ((key, value) in map) { + if (value.timestamp < oldestTimestamp) { + oldestTimestamp = value.timestamp + oldestKey = key + } + } + if (oldestKey != null) { + map.remove(oldestKey) + } + } + + private inner class TimestampedValue(value: V) { + private val value: SoftReference = SoftReference(value) + + var timestamp: Long = 0 + private set + + fun getValue(): V? { + return value.get() + } + + fun updateTimestamp() { + timestamp = System.currentTimeMillis() + } + + init { + updateTimestamp() + } + } + + init { + map = HashMap(capacity) + this.capacity = capacity + } +} From 34e232a43a12e9c9b32e13635a03162aaf268189 Mon Sep 17 00:00:00 2001 From: Nite Date: Mon, 20 Dec 2021 19:39:44 +0100 Subject: [PATCH 03/24] Fixed default for cache directory selector --- .../kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt | 3 +-- .../src/main/kotlin/org/moire/ultrasonic/service/Downloader.kt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt index ed65a05e..6cbc219a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt @@ -38,7 +38,6 @@ import org.moire.ultrasonic.service.MediaPlayerController import org.moire.ultrasonic.service.RxBus import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.ErrorDialog -import org.moire.ultrasonic.util.FileUtil.defaultMusicDirectory import org.moire.ultrasonic.util.FileUtil.ultrasonicDirectory import org.moire.ultrasonic.util.InfoDialog import org.moire.ultrasonic.util.MediaSessionHandler @@ -287,7 +286,7 @@ class SettingsFragment : val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) if (Settings.cacheLocationUri != "" && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, defaultMusicDirectory.path) + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Settings.cacheLocationUri) } intent.addFlags(RW_FLAG) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/Downloader.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/Downloader.kt index 7aa00bbb..601e5817 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/Downloader.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/Downloader.kt @@ -44,7 +44,7 @@ class Downloader( private val jukeboxMediaPlayer: JukeboxMediaPlayer by inject() - // TODO is this cache necessary? + // This cache helps us to avoid creating duplicate DownloadFile instances when showing Entries private val downloadFileCache = LRUCache(100) private var executorService: ScheduledExecutorService? = null From 2153650d8b942b4a4d89b6b98a149872891ebb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Tue, 21 Dec 2021 09:26:42 +0100 Subject: [PATCH 04/24] Update translations --- ultrasonic/src/main/res/values-cs/strings.xml | 44 +------------ ultrasonic/src/main/res/values-de/strings.xml | 62 +++++++++++-------- ultrasonic/src/main/res/values-es/strings.xml | 44 +++++++------ ultrasonic/src/main/res/values-fr/strings.xml | 50 +++++---------- ultrasonic/src/main/res/values-hu/strings.xml | 38 +----------- ultrasonic/src/main/res/values-it/strings.xml | 4 -- ultrasonic/src/main/res/values-nl/strings.xml | 48 ++++++++------ ultrasonic/src/main/res/values-pl/strings.xml | 45 +------------- .../src/main/res/values-pt-rBR/strings.xml | 46 +++----------- ultrasonic/src/main/res/values-pt/strings.xml | 35 +---------- ultrasonic/src/main/res/values-ru/strings.xml | 47 +------------- .../src/main/res/values-zh-rCN/strings.xml | 24 +++++-- 12 files changed, 141 insertions(+), 346 deletions(-) diff --git a/ultrasonic/src/main/res/values-cs/strings.xml b/ultrasonic/src/main/res/values-cs/strings.xml index 034a12f0..11dd16e9 100644 --- a/ultrasonic/src/main/res/values-cs/strings.xml +++ b/ultrasonic/src/main/res/values-cs/strings.xml @@ -43,7 +43,6 @@ Opravdu smazat %1$s Záložka odstraněna. Záložka vytvořena na %s. - Playlist je prázdný Vzdálené ovládání není povoleno. Povolte jukebox mód v Uživatelském > Nastavení na Subsonic serveru. Vzdálené ovládání vypnuto. Hudba je přehrávána na telefonu. Vzdálené ovládání není dostupné v offline módu. @@ -129,7 +128,6 @@ Skladby Hledat Média nenalezena - %d skladeb označeno. Varování: Připojení nedostupné. Chyba: SD karta nedostupná. Přehrát vše @@ -194,9 +192,7 @@ 1 hodina Řadit skladby podle čísla CD Řadit seznam skladeb dle čísla CD a čísla skladby - Zobrazovat bitrate a příponu souboru Připojovat jméno umělce, bitrate a příponu souboru - Zobrazit stahování při přehrávání Při spuštění přehrávání přepnout na aktivitu stahování Přehrávání bez pauz Zapnout přehrávání bez pauz @@ -303,8 +299,6 @@ Obrázek umělce v seznamu umělců Zobrazí obrázek umělce v náhledu umělců pokud je dostupný Video - Streamovat media pouze přes Wi-Fi připojení - Streamovat pouze přes Wi-Fi %1$s%2$s %d kbps 0 B @@ -358,7 +352,6 @@ Všechny bluetooth přístroje Pouze audio (A2DP) přístroje Vypnuto - Jedno tlačítko přehráváná/pauza na bluetooth přístroji Povolení tohoto nastavení může pomoci zlepšit funkci spuštění/pozastavení přehrávání na starších bluetooth přístrojích Možnosti ladění aplikace Zapisovat logy ladění do souboru @@ -367,7 +360,6 @@ Zachovat soubory Smazat soubory Smazat soubory logů. - Nakonfigurované servery Opravdu chcete odebrat server? Úprava serveru @@ -383,36 +375,13 @@ %d skladba %d skladby + %d skladeb %d skladeb - - %d skladba vybrána pro připnutí. - %d skladby vybrány pro připnutí. - %d skladeb vybráno pro připnutí. - - - %d skladba vybrána pro stažení. - %d skladby vybrány pro stažení. - %d skladeb vybráno pro stažení. - - - %d skladba vybrána pro odepnutí. - %d skladby vybrány pro odepnutí. - %d skladeb vybráno pro odepnutí. - - - %d skladba přidána na konec fronty přehrávání. - %d skladyb přidány na konec fronty přehrávání. - %d skladeb přidáno na konec fronty přehrávání. - - - %d skladba přidána za aktuální skladbu. - %d skladby přidány za aktuální skladbu. - %d skladeb přidáno za aktuální skladbu. - Zbývá %d den zkušební doby Zbývají %d dny zkušební doby + Zbývá %d dní zkušební doby Zbývá %d dní zkušební doby @@ -428,11 +397,4 @@ Nekompatibilní verze. Aktualizujte prosím Ultrasonic Android aplikaci. Nekompatibilní verze. Aktualizujte prosím Subsonic server. - - Příznaky funkcí - Používat pět hvězdiček pro hodnocení skladeb - Používat pět hvězdiček pro hodnocení skladeb - namísto jednoduchého jednohvězdičkového hodnocení. - - - + diff --git a/ultrasonic/src/main/res/values-de/strings.xml b/ultrasonic/src/main/res/values-de/strings.xml index 32fedc2a..ab621dd9 100644 --- a/ultrasonic/src/main/res/values-de/strings.xml +++ b/ultrasonic/src/main/res/values-de/strings.xml @@ -14,13 +14,22 @@ Chat Ultrasonic Hauptseite Aktuelle Wiedergabe + Abspielen + Pause + Wiederholen + Zufall + Stop + Nächstes + Vorheriges Podcast Keine Podcast Kanäle registriert Podcast Wiedergabeliste Suche Nachricht senden + Album Ultrasonic + Künstler*in Abbrechen Kommentar Bestätigen @@ -31,18 +40,22 @@ Name OK Anheften + Pause + Abspielen Zuletzt spielen Als nächstes spielen + Vorheriges abspielen + Jetzt spielen Zufällig spielen Öffentlich Speichern + Titel Lösen - Verschiedene Künstler + Verschiedene Künstler*innen Möchtest du %1$s löschen Lesezeichen entfernt Lesezeichen gesetzt als %s. - Wiedergabeliste ist leer Fernbedienung ist nicht erlaubt. Bitte Jukebox Modus auf dem Subsonic Server in Benutzer > Einstellungen aktivieren. Fernbedienung ausgeschaltet. Musik wird auf dem Telefon wiedergegeben. Fernbedienungs-Modus is Offline nicht verfügbar. @@ -81,7 +94,7 @@ file:///android_asset/html/de/index.html Jukebox als Standard Keine Liedtexte gefunden - Nach Künstler + Nach Künstler*innen Nach Namen Am häufigsten gespielt Am besten bewertet @@ -90,7 +103,7 @@ Kürzlich gespielt Mit Stern Alben - Künstler + Künstler*in Genres Musik Offline @@ -104,6 +117,7 @@ Allgemein Wiedergabeliste %s gelöscht Löschen der Wiedergabeliste %s ist fehlgeschlagen + Downloads Ende Navigation Einstellungen @@ -111,7 +125,7 @@ Medienbibliothek Offline Medien Netzwerkfehler. Neuer Versuch %1$d von %2$d. - Habe %d Künstler. + %d Künstler*in gefunden Lese vom Server. Lese vom Server. Fertig! Wiedergabelisten @@ -120,7 +134,7 @@ Aktualisierung der Wiedergabeliste %s ist fehlgeschlagen Bitte warten… Alben - Künstler + Künstler*in Suche Zeige mehr Keine Treffer, bitte erneut versuchen @@ -128,7 +142,6 @@ Titel Suche Keine Medien gefunden - %d Titel ausgewählt Warnung: kein Netz. Fehler: Keine SD Karte verfügbar. Alles wiedergeben @@ -183,7 +196,7 @@ Standard Alben Standard Künstler Standard Titel - Verzeichnis Chache-Zeit + Cache-Zeit für Verzeichnisse Deaktiviert 1 Minute 10 Minuten @@ -193,9 +206,8 @@ 1 hour Sortiere Titel nach CD Sortierung der Titelliste nach CD-Nummer und Titelnummer - Bitrate und Dateiendung zeigen - Bitrate und Dateityp hinter dem Künstler anzeigen - Herunterladen bei Wiedergabe + Bitrate und Dateiendung anzeigen + Bitrate und Dateityp hinter der Künstler*in anzeigen Herunterladen zusammen mit der Wiedergabe starten. Lückenlose Wiedergabe Lückenlose Wiedergabe aktivieren @@ -206,7 +218,7 @@ Bitte eine gültige URL angeben. Bitte einen gültigen Benutzernamen eingeben (ohne führende Leerzeichen). Maximale Alben - Maximale Künstler + Maximale Künstler*innen 112 Kbps 128 Kbps 160 Kbps @@ -298,8 +310,6 @@ Durchsuchen von ID3-Tags Nutze ID3 Tag Methode anstatt Dateisystem-Methode Film - Nur bei WLAN verbindung streamen - Nur über WLAN streamen %1$s%2$s %d kbps 0 B @@ -339,19 +349,28 @@ Ablaufzeit %s wurde von der Wiedergabeliste entfernt Wiedergabeliste teilen + Aktuelles Lied teilen Standard Begrüßung beim Teilen Hör dir mal die Musik an, die ich mit dir über %s geteilt habe. Titel teilen über Freigabe - Alle Titel nach Künstler sortieren + Alle Titel nach Künstler*innen sortieren Einen neuen Eintrag in der Künstleransicht hinzufügen, um auf alle Lieder eines Künstlers zuzugreifen - Künstler zeigen + Künstler*in zeigen Mehrere Jahre + Wiedergabe fortsetzen, wenn ein Bluetooth Gerät verbunden wurde + Wiedergabe pausieren, wenn ein Bluetooth Gerät getrennt wurde + Alle Bluetooth Geräte + Nur Audio (A2DP) Geräte + Deaktiviert + Dateien behalten + Dateien löschen + Logeinträge gelöscht Server hinzufügen Allgemeiner API Fehler: %1$s Keine Nachricht vom Server erhalten - Autorisirung mit Token ist für LDAP Benutzer nicht möglich. + Autorisierung mit Token ist für LDAP Benutzer nicht möglich. Falscher Benutzername oder Kennwort. Nicht autorisiert. Bitte die Rechte auf dem Subsonic Server überprüfen. Erforderlicher Parameter fehlt. @@ -360,11 +379,4 @@ Inkompatible Versionen. Bitte die Ultrasonic App aktualisieren. Inkompatible Versionen. Bitte den subsonic Server aktualisieren. - - Funktionseinstellungem - Verwenden Sie Fünf-Sterne-Bewertung für Songs - Verwenden Sie Fünf-Sterne-Bewertungssystem für Songs -         anstatt einfach Elemente zu markieren / zu entfernen. - - - + diff --git a/ultrasonic/src/main/res/values-es/strings.xml b/ultrasonic/src/main/res/values-es/strings.xml index c3010b41..1b6b9f68 100644 --- a/ultrasonic/src/main/res/values-es/strings.xml +++ b/ultrasonic/src/main/res/values-es/strings.xml @@ -50,12 +50,14 @@ Reproducción aleatoria Public Guardar + Seleccionar todo Título Desanclar Varios artistas Quieres eliminar %1$s Marcador eliminado. Marcador añadido a %s. + Nada se esta descargando La lista de reproducción esta vacía El control remoto no esta habilitado. Por favor habilita el modo jukebox en Configuración > Usuarios en tu servidor de Subsonic. Control remoto apagado. La música se reproduce en tu dispositivo. @@ -108,6 +110,7 @@ Géneros Música Sin conexión + %s - Configurar servidor Reproducción aleatoria Aleatorio Me gusta @@ -120,6 +123,7 @@ Común Eliminada lista de reproducción %s Fallo al eliminar la lista de reproducción %s + Descargas Salir Navegación Configuración @@ -167,6 +171,7 @@ 5 segundos 1 minuto 8 segundos + Usar ubicación de caché personalizada Ubicación de la Caché Ubicación de la caché no válida. Usando la localización predeterminada. Tamaño de la caché @@ -209,8 +214,8 @@ 1 hora Ordenar canciones por disco Ordena las canciones por el número de disco y el número de pista - Mostrar bitrate y extensión - Añadir al nombre del artista el bitrate la extensión del fichero + Mostrar tasa de bits y la extensión del archivo + Añadir el nombre del artista con la tasa de bits y la extensión del archivo Mostrar descargas en reproducción Mostrar la actividad de descarga cuando comienza la reproducción Reproducción sin pausas @@ -294,6 +299,7 @@ Escalado de caratulas en el servidor Sin usar Nombre de usuario + Color del servidor Mostrar controles en la pantalla de bloqueo Mostrar controles de reproducción en la pantalla de bloqueo Mostrar notificación @@ -322,8 +328,8 @@ Mostrar la imagen del artista en la lista de artistas Muestra la imagen del artista en la lista de artistas si está disponible Vídeo - Solo trasmitir medios si esta conectado a la Wi-Fi - Trasmitir solo por Wi-Fi + Solo descargar medios en conexiones sin medir + Descargar solo por Wi-Fi %1$s%2$s %d kbps 0 B @@ -381,7 +387,7 @@ Todos los dispositivos Bluetooth Solo dispositivos de audio (A2DP) Deshabilitado - Reproducir / Pausar con un solo botón en el dispositivo Bluetooth + Dispositivo Bluetooth con solo un único botón Reproducir / Pausa Habilitar esto puede ayudar con los dispositivos Bluetooth más antiguos cuando la reproducción / pausa no funciona correctamente Opciones de depuración Escribir registro de depuración en un archivo @@ -392,8 +398,6 @@ Archivos de registro eliminados. Descargando medios en segundo plano… - - Servidores configurados ¿Seguro que deseas borrar el servidor? Editando servidor @@ -414,23 +418,27 @@ %d canciones - %d canción seleccionada para ser anclada. - %d canciones seleccionadas para ser ancladas. + %d canción seleccionada para ser anclada + %d canciones seleccionadas para ser ancladas - %d canción seleccionada para ser descargada. - %d canciones seleccionadas para ser descargadas. + %d canción seleccionada para ser descargada + %d canciones seleccionadas para ser descargadas - %d canción seleccionada para ser desanclada. - %d canciones seleccionadas para ser desancladas. + %d canción desanclada + %d canciones desancladas + + + %d canción eliminada + %d canciones eliminadas - %d canción añadida al final de la cola de reproducción. - %d canciones añadidas al final de la cola de reproducción. + %d canción añadida al final de la cola de reproducción + %d canciones añadidas al final de la cola de reproducción - %d canción insertada después de la canción actual. + %d canción insertada después de la canción actual %d canciones insertadas después de la canción actual. @@ -451,10 +459,10 @@ Versiones incompatibles. Por favor actualiza el servidor de Subsonic. - Funciones experimentales + Características Use cinco estrellas para las canciones Utilice el sistema de calificación de cinco estrellas para canciones - en lugar de simplemente destacar / desestimar elementos. + en lugar de simplemente marcar / desmarcar elementos. diff --git a/ultrasonic/src/main/res/values-fr/strings.xml b/ultrasonic/src/main/res/values-fr/strings.xml index c538e37a..fb150c3d 100644 --- a/ultrasonic/src/main/res/values-fr/strings.xml +++ b/ultrasonic/src/main/res/values-fr/strings.xml @@ -28,7 +28,9 @@ Playlists Recherche Envoyer un message + Album Ultrasonic + Artiste Annuler Commenter Confirmer @@ -48,12 +50,12 @@ Jouer aléatoirement Public Enregistrer + Titre Détacher Artistes divers Voulez-vous supprimer %1$s Signet supprimé. Signet ajouté à %s. - La playlist est vide La télécommande n\'est pas autorisée. Veuillez activer le mode jukebox dans Utilisateurs > Paramètres à partir de votre serveur Subsonic. Mode jukebox désactivé. La musique est jouée sur l\'appareil. Le mode jukebox n\'est pas disponible en mode déconnecté. @@ -117,6 +119,7 @@ Général Playlist %s supprimée Échec de suppression de la playlist %s + Téléchargements Quitter Navigation Paramètres @@ -141,7 +144,6 @@ Titres Recherche Aucun titre trouvé - %d pistes sélectionnées. Avertissement : Aucun réseau disponible. Erreur : Aucune carte SD disponible. Tout jouer @@ -206,7 +208,7 @@ 1 hour Trier les titres par disque Trier la liste des titres par numéro de disques/pistes - Afficher bitrate et suffixe du fichier + Afficher le Bitrate et l’extension de fichier Ajouter le nom d\'artiste, bitrate et suffixe du fichier Afficher le téléchargement lors de la lecture Aller vers les téléchargements lorsque qu\'un titre est écouté @@ -278,6 +280,8 @@ Paramètres de recherche Envoyer la pochette de l\'album via Bluetooth (peut causer l\'échec des notifications Bluetooth) Pochette de l\'album via Bluetooth + La liste de lecture ne sera pas envoyée aux appareils connectés. Cela peut restaurer la compatibilité avec les appareils AVRCP 1.3 lorsque l’affichage de la piste actuelle n’est pas mise à jour. + Désactiver l’envoi de la liste de lecture Envoyer des notifications de lecture via Bluetooth Envoyer une notification Bluetooth Gérer les serveurs @@ -289,6 +293,7 @@ Mise à l\'échelle des pochettes d\'album sur le serveur Inutilisé Nom d\'utilisateur + Couleur du serveur Boutons de contrôle sur l\'écran de verrouillage Afficher les contrôles de lecture sur l\'écran de verrouillage Notifications @@ -317,8 +322,6 @@ Afficher l’image de l’artiste dans la liste Affiche l’image de l’artiste dans la liste des artistes si celle-ci est disponible Vidéo - Lire en streaming seulement si connecté en Wi-Fi - Streaming en Wi-Fi uniquement %1$s%2$s %d Kb/s 0 o @@ -332,10 +335,13 @@ Aucune carte SD Description par défaut de la collection partagée Répartition + Toujours demander une description et une date d’expiration lors de la création d’un partage sur le serveur Toujours demander pour plus de détails Temps d\'expiration par défaut Ne montre pas de dialogue à nouveau Définir les options de partage + Créer un partage sur le serveur + Partager créera un partage sur le serveur et donnera son URL. Si désactivé, seuls les détails de la piste seront partagées. Aucune date d\'expiration Changer de vue playlist Mettre en signet @@ -358,6 +364,7 @@ Temps d\'expiration \"%s\" retiré de la playlist Partager playlist + Partager la piste actuelle Texte par défaut lors d\'un partage Regardez cette musique que j\'ai partagée depuis %s Partager des titres via @@ -372,7 +379,7 @@ Tous les appareils Bluetooth Seulement les appareils audio (A2DP) Désactivé - Bouton unique Lecture/Pause en Bluetooth + Appareil Bluetooth avec un seul bouton Lecture/Pause Activer cela peut aider sur les anciens appareils Bluetooth lorsque Lecture/Pause ne fonctionne pas correctement Paramètres de debug Enregistrer les logs de debug dans des fichiers @@ -381,7 +388,7 @@ Conserver les fichiers Supprimer les fichiers Fichiers de log supprimés - + Téléchargement des fichiers en arrière-plan… Serveurs configurés Êtes-vous sûr de vouloir supprimer ce serveur ? @@ -402,26 +409,6 @@ %d titre %d titres - - %d titre sélectionné pour être épinglé. - %d titres sélectionnés pour être épinglés. - - - %d titre sélectionné pour être téléchargé. - %d titres sélectionnés pour être téléchargés. - - - %d titre sélectionné pour être désépinglé. - %d titres sélectionnés pour être désépinglés. - - - %d titre ajouté à la fin de la file d\'attente de lecture. - %d titres ajoutés à la fin de la file d\'attente de lecture. - - - %d titre inséré après le titre actuel. - %d titres insérés après le titre actuel. - %d jour restant à la période d\'essai %d jours restant à la période d\'essai @@ -439,11 +426,4 @@ Versions incompatibles. Veuillez mette à jour l\'application Android Ultrasonic. Versions incompatibles. Veuillez mette à jour le serveur Subsonic. - - Drapeaux des fonctionnalités - Utiliser les étoiles pour noter les morceaux - Utiliser un système de notation à base d\'étoiles pour les morceaux - au lieu de simplement mettre en avant les morceaux. - - - + diff --git a/ultrasonic/src/main/res/values-hu/strings.xml b/ultrasonic/src/main/res/values-hu/strings.xml index efa3dcd0..c2ad6e60 100644 --- a/ultrasonic/src/main/res/values-hu/strings.xml +++ b/ultrasonic/src/main/res/values-hu/strings.xml @@ -53,7 +53,6 @@ Biztos, hogy törölni akarja? %1$s Könyvjelző eltávolítva. Könyvjelző beállítva %s. - A várólista üres! A távvezérlés nem áll rendelkezésre. Kérjük, engedélyezze a Jukebox módot a Felhasználók > Beállítások menüpontban, az Ön Subsonic kiszolgálóján! Távvezérlés kikapcsolása. A zenelejátszás a telefonon történik. A távvezérlés nem lehetséges kapcsolat nélküli módban! @@ -139,7 +138,6 @@ Dalok Keresés Nem található média! - %d dal kijelölve. Figyelem: Hálózat nem áll rendelkezésre! Hiba: SD kártya nem áll rendelkezésre! Összes lejátszása @@ -204,9 +202,7 @@ 1 óra Dalok rendezése albumok szerint Dalok rendezése albumsorszám és dalsorszám szerint. - Bitráta és fájlkiterjesztés megjelenítése Bitráta és fájlkiterjesztés megjelenítése az előadónév mellett. - Letöltés megjelenítése Letöltési aktivitás megjelenítése a lejátszás indításakor. Egybefüggő lejátszás Kihagyás (dalszünet) nélküli egybefüggő lejátszás (Gapless). @@ -315,8 +311,6 @@ Előadó képének megjelenítése Az előadó listában megjeleníti a képeket, amennyiben elérhetőek Videó - Streaming csak Wi-Fi hálózaton keresztül. - Streaming csak Wi-Fivel %1$s%2$s %d kbps 0 B @@ -370,7 +364,6 @@ Minden Bluetooth eszköz Csak audio (A2DP) eszközök Kikapcsolva - Egy gombos Lejátszás/Szünet a Bluetooth eszközökön Régebbi Bluetooth eszközök esetén segíthet, ha a Lejátszás/Szünet nem működik megfelelően Hibakeresési lehetőségek Hibakeresési napló írása fájlba @@ -379,8 +372,6 @@ Fájlok megtartása Fájlok törlése Naplófájlok törölve. - - Beállított szerverek Biztosan törölni szeretnéd a szervert? Szerver szerkesztése @@ -397,26 +388,6 @@ %d dal %d dal - - %d dal kijelölve tárolásra. - %d dal kijelölve tárolásra. - - - %d dal kijelölve letöltésre. - %d dal kijelölve letöltésre. - - - %d dal tárolása visszavonva. - %d dal tárolása visszavonva. - - - %d dal hozzáadva a várólistához utolsóként. - %d dal hozzáadva a várólistához utolsóként. - - - %d dal hozzáadva a várólistához következőként. - %d dal hozzáadva a várólistához következőként. - %d nap van hátra a próba időszakból. %d nap van hátra a próba időszakból. @@ -434,11 +405,4 @@ Nem kompatibilis verzió. Kérjük, frissítse az Ultrasonic Android alkalmazást! Nem kompatibilis verzió. Kérjük, frissítse a Subsonic kiszolgálót! - - Jellemzők Zászlók - Öt csillagos értékelés használata a dalokhoz - Öt csillag használata az értékeléshez az egyszerű - csillaggal jelölés helyett. - - - + diff --git a/ultrasonic/src/main/res/values-it/strings.xml b/ultrasonic/src/main/res/values-it/strings.xml index 200c0ac2..58b33cde 100644 --- a/ultrasonic/src/main/res/values-it/strings.xml +++ b/ultrasonic/src/main/res/values-it/strings.xml @@ -40,7 +40,6 @@ Vuoi eliminare %1$s Segnalibro rimosso. Segnalibro impostato su %s. - Playlist vuota Il controllo remoto non è consentito. Per favore abilita la modalità jukebox nelle Impostazioni > Utente nel server Airsonic. Controllo remoto disattivato. La musica verrà riprodotta sullo smartphone. Il controllo remoto non è disponibile nella modalità offline. @@ -125,7 +124,6 @@ Canzoni Cerca Nessun media trovato - %dtracce selezionate. Attenzione: nessuna rete disponibile. Errore: Nessuna memoria SD disponibile. Riproduci tutto @@ -190,9 +188,7 @@ 1 ora Ordina Canzoni secondo Disco Ordina lista canzoni secondo il numero disco e traccia - Visualizza Bitrate Ed Estensione File Aggiungi nome artista con bitrare ed estensione file - Visualizza Download Durante Riproduzione Passa al download quando inizia riproduzione Riproduzione Ininterrotta Abilita riproduzione ininterrotta diff --git a/ultrasonic/src/main/res/values-nl/strings.xml b/ultrasonic/src/main/res/values-nl/strings.xml index 194afb24..be74a57a 100644 --- a/ultrasonic/src/main/res/values-nl/strings.xml +++ b/ultrasonic/src/main/res/values-nl/strings.xml @@ -50,12 +50,14 @@ Willekeurig afspelen Openbaar Opslaan + Alles selecteren Titel Losmaken Verschillende artiesten Wil je %1$s verwijderen? Bladwijzer verwijderd. Bladwijzer ingesteld op %s. + Er wordt niks gedownload Lege afspeellijst Afstandsbediening wordt niet ondersteund. Schakel jukebox-modus in op je Subsonic-server via Gebruikers > Instellingen. Afstandsbediening uitgeschakeld; muziek wordt afgespeeld op de telefoon. @@ -108,6 +110,7 @@ Genres Muziek Offline + %s - Server instellen Willekeurig afspelen Willekeurig Favorieten @@ -120,6 +123,7 @@ Algemeen Afspeellijst %s verwijderd Afspeellijst %s kan niet worden verwijderd + Downloads Afsluiten Navigatie Instellingen @@ -144,7 +148,7 @@ Nummers Zoeken Geen media gevonden - %d nummers geselecteerd. + %d nummers geselecteerd Waarschuwing: geen internetverbinding. Fout: geen SD-kaart beschikbaar. Alles afspelen @@ -167,6 +171,7 @@ 5 seconden 1 minuut 8 seconden + Aangepaste cachelocatie gebruiken Cachelocatie Ongeldige cachelocatie; de standaardlocatie wordt gebruikt. Cachegrootte @@ -294,6 +299,7 @@ Verkleinde afbeeldingen ophalen van server Ongebruikt Gebruikersnaam + Serverkleur Vergrendelschermbediening tonen Toont afspeelbediening op het vergrendelscherm Melding tonen @@ -322,8 +328,8 @@ Artiestfoto tonen op artiestenlijst Toont de artiestfoto op de artiestenlijst (indien beschikbaar) Video - Alleen streamen via wifi-verbindingen - Alleen streamen via wifi + Haal media alleen op bij gebruik van onbeperkte dataverbindingen + Alleen ophalen via wifi %1$s%2$s %d kbps 0 B @@ -381,7 +387,7 @@ Alle bluetoothapparaten Alleen audio-apparaten (AD2P) Uitgeschakeld - Eén afspeel-/pauzeerknop op bluetoothapparaat + Bluetoothapparaat met één afspeel- en pauzeknop Schakel dit in bij gebruik van oudere bluetoothapparaten om de afspeel- en pauzeerknop goed te laten werken Foutopsporingsopties Foutopsporingslogboek bijhouden @@ -392,8 +398,6 @@ De logboeken zijn verwijderd. Bezig met downloaden van media op de achtergrond… - - Ingestelde servers: Weet je zeker dat je deze server wilt verwijderen? Server bewerken @@ -414,24 +418,28 @@ %d nummers - %d vast te maken nummer geselecteerd. - %d vast te maken nummers geselecteerd. + %d vast te maken nummer geselecteerd + %d vast te maken nummers geselecteerd - %d te downloaden nummer geselecteerd. - %d te downloaden nummers geselecteerd. + %d te downloaden nummer geselecteerd + %d te downloaden nummers geselecteerd - %d los te maken nummer geselecteerd. - %d los te maken nummers geselecteerd. + %d nummer losgemaakt + %d nummers losgemaakt + + + %d nummer verwijderd + %d nummers verwijderd - %d nummer toegevoegd aan het einde van afspeelwachtrij. - %d nummers toegevoegd aan het einde van afspeelwachtrij. + %d nummer toegevoegd aan het einde van afspeelwachtrij + %d nummers toegevoegd aan het einde van afspeelwachtrij - %d nummer ingevoegd na het huidige nummer. - %d nummers ingevoegd na het huidige nummer. + %d nummer ingevoegd na het huidige nummer + %d nummers ingevoegd na het huidige nummer Nog %d dag over van de proefperiode @@ -451,10 +459,10 @@ Incompatibele versies. Werk je Subsonic-server bij. - Experimentele functies - Gebruik vijf sterren voor nummers - Gebruik vijf sterren ratingsysteem voor liedjes - in plaats van items simpelweg in de hoofdrol te zetten / niet te verwijderen. + Functies + Vijf sterren gebruiken voor nummers + Toon vijf sterren om nummers te beoordelen + in plaats van items toe te voegen aan of te verwijderen uit de favorieten. diff --git a/ultrasonic/src/main/res/values-pl/strings.xml b/ultrasonic/src/main/res/values-pl/strings.xml index 8832e780..953fb967 100644 --- a/ultrasonic/src/main/res/values-pl/strings.xml +++ b/ultrasonic/src/main/res/values-pl/strings.xml @@ -42,7 +42,6 @@ Czy chcesz usunąć %1$s? Zakładka usunięta. Zakładka ustawiona na %s. - Playlista jest pusta Kontrola pilotem jest niedostępna. Proszę uruchomić tryb jukebox w Użytkownicy > Ustawienia na serwerze Subsonic. Tryb pilota jest wyłączony. Muzyka jest odtwarzana w telefonie. Pilot jest niedostępny w trybie offline. @@ -127,7 +126,6 @@ Utwory Wyszukiwanie Brak mediów - Zaznaczono %d utworów. Uwaga: sieć niedostępna. Błąd: Niedostępna karta SD. Odtwórz wszystkie @@ -192,9 +190,7 @@ 1 godzina Sortuj utwory wg dysku Sortuje listę utworów wg numeru dysku i numeru utworu - Wyświetlaj bitrate i typ pliku Dołącza bitrate i typ pliku do nazwy artysty - Wyświetlaj postęp pobierania Wyświetla postęp pobierania podczas odtwarzania Odtwarzanie bez przerw Włącz odtwarzanie bez przerw między utworami @@ -298,8 +294,6 @@ ponieważ api Subsonic nie wspiera nowego sposobu autoryzacji dla użytkowników Przeglądaj używając tagów ID3 Używa metod z tagów ID3 zamiast metod opartych na systemie plików Wideo - Przesyłanie mediów tylko gdy Wi-fi jest włączone - Przesyłanie tylko przez Wi-fi %1$s%2$s %d kbps 0 B @@ -355,36 +349,6 @@ ponieważ api Subsonic nie wspiera nowego sposobu autoryzacji dla użytkowników %d utworów %d utworów - - %d utwór zaznaczony do przypięcia. - %d utwory zaznaczone do przypięcia. - %d utworów zaznaczonych do przypięcia. - %d utworów zaznaczonych do przypięcia. - - - %d utwór zaznaczony do pobrania. - %d utwory zaznaczone do pobrania. - %d utworów zaznaczonych do pobrania. - %d utworów zaznaczonych do pobrania. - - - %d utwór zaznaczony do odpięcia. - %d utwory zaznaczone do odpięcia. - %d utworów zaznaczonych do odpięcia. - %d utworów zaznaczonych do odpięcia. - - - %d utwór dodany na koniec kolejki odtwarzania. - %d utwory dodane na koniec kolejki odtwarzania. - %d utworów dodanych na koniec kolejki odtwarzania. - %d utworów dodanych na koniec kolejki odtwarzania. - - - %d utwór wstawiony po bieżącym utworze. - %d utwory wstawione po bieżącym utworze. - %d utworów wstawionych po bieżącym utworze. - %d utworów wstawionych po bieżącym utworze. - %d dzień pozostał do zakończenia okresu próbnego %d dni pozostały do zakończenia okresu próbnego @@ -404,11 +368,4 @@ ponieważ api Subsonic nie wspiera nowego sposobu autoryzacji dla użytkowników Brak zgodności wersji. Uaktualnij aplikację Ultrasonic na Androida. Brak zgodności wersji. Uaktualnij serwer Subsonic. - - Flagi funkcji - Użyj pięciu gwiazdek dla utworów - W przypadku utworów użyj systemu pięciu gwiazdek - zamiast po prostu grać gwiazdkami / bez gwiazd. - - - + diff --git a/ultrasonic/src/main/res/values-pt-rBR/strings.xml b/ultrasonic/src/main/res/values-pt-rBR/strings.xml index 5fd380a2..4fbec20d 100644 --- a/ultrasonic/src/main/res/values-pt-rBR/strings.xml +++ b/ultrasonic/src/main/res/values-pt-rBR/strings.xml @@ -28,7 +28,9 @@ Playlists Pesquisa Enviar uma mensagem + Álbum Ultrasonic + Artista Cancelar Comentar Confirmar @@ -48,12 +50,12 @@ Tocar Aleatoriamente Público Salvar + Título Desafixar Vários Artistas Você quer excluir %1$s Favorito removido. Favorito marcado em %s. - Playlist está vazia Controle remoto não está permitido. Habilite o modo jukebox em Usuário > Configurações no seu servidor Subsonic. Controle remoto desligado. Música tocada no celular. Controle remoto não está disponível no modo offline. @@ -117,6 +119,7 @@ Comum Playlist excluída %s Falha ao excluir a playlist %s + Downloads Sair Navegação Configurações @@ -141,7 +144,6 @@ Músicas Pesquisar Nenhuma mídia encontrada - %d faixas selecionadas. Aviso: Nenhuma rede disponível. Erro: Nenhum cartão SD disponível. Tocar Tudo @@ -206,7 +208,7 @@ 1 hora Classificar Músicas por Álbum Classificar músicas pelo número do álbum e faixas - Mostrar Taxa de Bits e Sufixo de Arquivo + Mostrar Bitrate se Sufixo do Arquivo Adicionar o nome do artista com a taxa de bits e sufixo do arquivo Mostrar Downloads na Reprodução Transição para atividade de download quando iniciar reprodução @@ -319,8 +321,6 @@ Mostrar Foto do Artista na Lista Mostrar a imagem do artista na lista de artistas, se disponível Vídeo - Somente fazer stream de mídia se conectado por Wi-Fi - Streaming Somente por Wi-Fi %1$s%2$s %d kbps 0 B @@ -334,10 +334,13 @@ Sem cartão SD Descrição Padrão do Compartilhamento Compartilhamento + Sempre pedir descrição e expiração ao criar um compartilhamento no servidor Sempre Perguntar por Detalhes Tempo Padrão para Expirar Não mostrar este diálogo novamente Configurações de Compartilhamento + Criar Compartilhamento no Servidor + Compartilhar cria o compartilhamento no servidor e compartilha sua URL. Se desativado, somente os detalhes da música são compartilhados Não Expira Alternar Playlist Definir como Favorito @@ -360,6 +363,7 @@ Tempo até expirar \"%s\" foi removido da playlist Compartilhar Playlist + Compartilhar a Música Atual Saudação Padrão do Compartilhamento Confira esta música que compartilhei do %s Compartilhar músicas via @@ -374,7 +378,6 @@ Todos os dispositivos Bluetooth Somente dispositivos de áudio (A2DP) Desativado - Botão Único para Reproduzir/Pausar Ativar isso pode ajudar com dispositivos Bluetooth mais antigos quando Reproduzir/Pausar não funciona corretamente Opções de Depuração Log de Depuração em Arquivo @@ -385,8 +388,6 @@ Arquivos de log excluídos. Baixado mídia em segundo plano… - - Servidores Configurados Quer realmente excluir o servidor? Gerenciar Servidor @@ -406,26 +407,6 @@ %d música %d músicas - - %d música selecionada para ser fixada. - %d músicas selecionadas para serem fixadas. - - - %d música selecionada para ser baixada. - %d músicas selecionadas para serem baixadas. - - - %d música selecionada para ser desfixada. - %d músicas selecionadas para serem desfixadas. - - - %d música adicionada ao final da playlist. - %d músicas adicionadas ao final da playlist. - - - %d música adicionada após a atual. - %d músicas adicionadas após a atual. - %d dia restante do período de teste %d dias restantes do período de teste @@ -443,11 +424,4 @@ Versões incompativeis. Atualize o aplicativo Ultrasonic para Android. Versões incompativeis. Atualize o servidor Ultrasonic. - - Sinalização de Recursos - Usar Classif. 5 Estrelas para Músicas - Usar o sistema de classificação de 5 estrelas para músicas - em vez de simplesmente estrelar/não estrelar itens - - - + diff --git a/ultrasonic/src/main/res/values-pt/strings.xml b/ultrasonic/src/main/res/values-pt/strings.xml index 1a277b2d..cf4a202e 100644 --- a/ultrasonic/src/main/res/values-pt/strings.xml +++ b/ultrasonic/src/main/res/values-pt/strings.xml @@ -42,7 +42,6 @@ Você quer apagar %1$s Favorito removido. Favorito marcado em %s. - Playlist está vazia Controle remoto não está permitido. Habilite o modo jukebox em Usuário > Configurações no seu servidor Subsonic. Controle remoto desligado. Música tocada no celular. Controle remoto não está disponível no modo offline. @@ -127,7 +126,6 @@ Músicas Pesquisar Nenhuma mídia encontrada - %d faixas selecionadas. Aviso: Nenhuma rede disponível. Erro: Nenhum cartão SD disponível. Tocar Tudo @@ -192,9 +190,7 @@ 1 hora Classificar Músicas por Álbum Classificar músicas pelo número do álbum e faixas. - Taxa de Bits e Sufixo Adiciona o nome do artista com a taxa de bits e sufixo do ficheiro - Downloads na Reprodução Transição para atividade de download quando iniciar reprodução Reprodução sem Interrupção Habilita reprodução sem interrupção @@ -298,8 +294,6 @@ Navegar Usando Etiquetas ID3 Usa as etiquetas ID3 ao invés do sistema de ficheiros Vídeo - Somente fazer stream de mídia se conectado por Wi-Fi - Streaming Somente por Wi-Fi %1$s%2$s %d kbps 0 B @@ -352,26 +346,6 @@ %d música %d músicas - - %d música selecionada para ser fixada. - %d músicas selecionadas para serem fixadas. - - - %d música selecionada para ser baixada. - %d músicas selecionadas para serem baixadas. - - - %d música selecionada para ser desfixada. - %d músicas selecionadas para serem desfixadas. - - - %d música adicionada ao final da playlist. - %d músicas adicionadas ao final da playlist. - - - %d música adicionada após a atual. - %d músicas adicionadas após a atual. - %d dia restante do período de teste %d dias restantes do período de teste @@ -389,11 +363,4 @@ Versões incompativeis. Atualize o aplicativo Ultrasonic para Android. Versões incompativeis. Atualize o servidor Ultrasonic. - - Bandeiras de recursos - Use classificação de cinco estrelas para músicas - Use o sistema de classificação de cinco estrelas para músicas - em vez de simplesmente estrelar / não estrelar itens. - - - + diff --git a/ultrasonic/src/main/res/values-ru/strings.xml b/ultrasonic/src/main/res/values-ru/strings.xml index 28c81902..1ea549a1 100644 --- a/ultrasonic/src/main/res/values-ru/strings.xml +++ b/ultrasonic/src/main/res/values-ru/strings.xml @@ -53,7 +53,6 @@ Вы хотите удалить %1$s Закладка удалена Закладка установлена ​​на %s - Плейлист пустой Пульт дистанционного управления не допускается. Пожалуйста, включите режим музыкального автомата в Пользователи > Настройки на вашем Subsonic сервере. Пульт управления выключен. Музыка играет на телефоне Пульт дистанционного управления недоступен в автономном режиме. @@ -141,7 +140,6 @@ Песни Поиск Медиа не найдена - %d треки выбраны. Предупреждение: сеть недоступна. Ошибка: нет SD-карты Воспроизвести все @@ -206,9 +204,7 @@ 1 час Время кэша каталогов Сортировать список песен по номеру диска и треку - Отображать битрейт и суффикс файла Добавить имя исполнителя с битрейтом и суффиксом файла - Показать загрузки при воспроизведении Переход к загрузке активности при запуске воспроизведения Воспроизведение без промежутка Включить воспроизведение без паузы @@ -317,8 +313,6 @@ Показать изображение исполнителя в списке исполнителей Отображает изображение исполнителя в списке исполнителей, если доступно Видео - Потоковое мультимедиа только при подключении к Wi-Fi - Только потоковая передача по Wi-Fi %1$s%2$s %d kbps 0 B @@ -372,7 +366,6 @@ Все устройства Bluetooth Только аудио (A2DP) устройства Отключено - Одна кнопка Воспроизведение/Пауза на устройстве Bluetooth Включение этого может помочь со старыми устройствами Bluetooth, когда Воспроизведение/Пауза работает некорректно. Настройки отладки Записать журнал отладки в файл @@ -381,8 +374,6 @@ Сохранить файлы Удалить файлы Удаленные файлы журналов. - - Настроенные серверы Вы уверены, что хотите удалить сервер? Редактирование сервера @@ -404,36 +395,6 @@ %d песен %d песен - - %d песня выбрана для закрепления. - %d песни выбрано для закрепления. - %d песен выбрано для закрепления. - %d песен выбрано для закрепления. - - - %d песня выбрана для загрузки. - %d песни выбрано для загрузки. - %d песен выбрано для загрузки. - %d песен выбрано для загрузки. - - - %d песня выбрана для открепления. - %d песни выбрано для открепления. - %d песен выбрано для открепления. - %d песен выбрано для открепления. - - - %d песня добавлена в конец очереди воспроизведения. - %d песни добавлено в конец очереди воспроизведения. - %d песен добавлено в конец очереди воспроизведения. - %d песен добавлено в конец очереди воспроизведения. - - - %d песня вставлена после текущей песни. - %d песни вставлено после текущей песни. - %d песен вставлено после текущей песни. - %d песен вставлено после текущей песни. - Остался %d день пробного периода Осталось %d дня пробного периода @@ -453,10 +414,4 @@ Несовместимые версии. Пожалуйста, обновите приложение Ultrasonic для Android. Несовместимые версии. Пожалуйста, обновите Subsonic сервер. - - Флаги - Использовать пятизвездочный рейтинг для песен - Использовать пятизвездочную систему рейтинга для песен - вместо того, чтобы просто ставить/не ставить звезды. - - + diff --git a/ultrasonic/src/main/res/values-zh-rCN/strings.xml b/ultrasonic/src/main/res/values-zh-rCN/strings.xml index 97927f41..aae68a23 100644 --- a/ultrasonic/src/main/res/values-zh-rCN/strings.xml +++ b/ultrasonic/src/main/res/values-zh-rCN/strings.xml @@ -28,7 +28,9 @@ 播放列表 搜索 发送消息 + 专辑 Ultrasonic + 艺术家 取消 评论 确认 @@ -48,11 +50,14 @@ 随机播放 公开 保存 + 选择所有 + 标题 取消固定 群星 确定要删除 %1$s吗 书签已删除。 书签设置为 %s。 + 未下载任何内容 空的播放列表 不允许远程控制. 请在您的服务器上的 Users > Settings 打开点唱机模式。 关闭远程控制,音乐将在手机上播放 @@ -116,6 +121,7 @@ 公共 已删除播放列表 %s 播放列表删除失败%s + 下载 退出 导航 设置 @@ -140,7 +146,6 @@ 歌曲 搜索 找不到歌曲 - 已选择 %d 首曲目。 警告:网络不可用 错误:没有SD卡 播放所有 @@ -163,6 +168,7 @@ 5 秒 1 分钟 8 秒 + 使用自定义的缓存路径 缓存路径 缓存路径错误,正在使用默认路径。 缓存大小 @@ -287,6 +293,7 @@ 服务器端专辑图片缩放 未启用 用户名 + 服务器颜色 锁屏显示控制器 在锁定屏幕上显示播放控件 显示通知 @@ -315,8 +322,8 @@ 在艺术家列表中显示艺术家图片 如果可用,在艺术家列表中显示艺术家图片 视频 - 仅在连接到 WIFI 时使用流媒体 - 仅使用 WIFI + 仅未计量的网络用于下载媒体 + 仅使用Wi-Fi进行下载 %1$s%2$s %d kbps 0 B @@ -330,10 +337,13 @@ 没有 SD 卡 默认分享说明 分享 + 在服务端创建分享时始终要求提供说明和到期时间 始终询问详细信息 默认有效期 不再显示此对话框 设置分享选项 + 在服务端创建分享链接 + 分享将在服务端创建一个链接,如果不能创建,那么只会分享歌曲的信息 无期限 切换播放列表 设为书签 @@ -356,6 +366,7 @@ 有效期 %s已从播放列表中移除 分享播放列表 + 分享当前曲目 默认分享问候语 看看我从 %s 分享的这首音乐 分享歌曲通过 @@ -381,8 +392,6 @@ 删除日志文件 在后台下载媒体… - - 配置服务器 您确定要删除此服务器吗? 编辑服务器 @@ -410,6 +419,9 @@ 已选择 %d 首歌曲取消固定。 + + %d 首歌曲被删除 + 已将 %d 首歌曲添加到播放队列的末尾。 @@ -433,7 +445,7 @@ 不兼容的版本。请升级Subsonic 服务。 - 特性标志 + 特性 为歌曲使用五星评分 对歌曲使用五星级评级系统 而不是简单地为项目加星标/取消星标。 From bb370bfc4441f541dec7a1dbd49f732c228144b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Tue, 21 Dec 2021 10:27:11 +0100 Subject: [PATCH 05/24] Fix lint errors --- ultrasonic/src/main/res/values-cs/strings.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/ultrasonic/src/main/res/values-cs/strings.xml b/ultrasonic/src/main/res/values-cs/strings.xml index 11dd16e9..cc89ff3b 100644 --- a/ultrasonic/src/main/res/values-cs/strings.xml +++ b/ultrasonic/src/main/res/values-cs/strings.xml @@ -375,13 +375,11 @@ %d skladba %d skladby - %d skladeb %d skladeb Zbývá %d den zkušební doby Zbývají %d dny zkušební doby - Zbývá %d dní zkušební doby Zbývá %d dní zkušební doby From fbf5a6339600d18b41ab156007f3cda18ef6b448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Tue, 21 Dec 2021 10:42:54 +0100 Subject: [PATCH 06/24] Avoid lint errors if a language has an unused quantity --- ultrasonic/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle index ced150ab..0f330201 100644 --- a/ultrasonic/build.gradle +++ b/ultrasonic/build.gradle @@ -49,6 +49,7 @@ android { baselineFile file("lint-baseline.xml") ignore 'MissingTranslation' warning 'ImpliedQuantity' + warning 'UnusedQuantity' disable 'IconMissingDensityFolder', "VectorPath" abortOnError true warningsAsErrors true From 10b83805a9df899be36349aeb1d251b89f9ba501 Mon Sep 17 00:00:00 2001 From: tzugen Date: Tue, 21 Dec 2021 12:16:40 +0100 Subject: [PATCH 07/24] Create a correctly typed list from getMusicDirectory() --- .../moire/ultrasonic/domain/MusicDirectory.kt | 28 ++-- .../ultrasonic/domain/APIAlbumConverter.kt | 2 +- .../ultrasonic/domain/APIBookmarkConverter.kt | 2 +- .../domain/APIMusicDirectoryConverter.kt | 121 ++++++++++++------ .../ultrasonic/domain/APIPlaylistConverter.kt | 2 +- .../ultrasonic/domain/APISearchConverter.kt | 6 +- .../ultrasonic/domain/APIShareConverter.kt | 2 +- .../ultrasonic/service/RESTMusicService.kt | 3 +- .../domain/APIAlbumConverterTest.kt | 2 +- .../domain/APIBookmarkConverterTest.kt | 2 +- .../domain/APIMusicDirectoryConverterTest.kt | 8 +- .../domain/APIPlaylistConverterTest.kt | 4 +- .../domain/APISearchConverterTest.kt | 6 +- 13 files changed, 118 insertions(+), 70 deletions(-) diff --git a/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt b/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt index e316dc42..cf28ccdd 100644 --- a/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt +++ b/core/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt @@ -39,15 +39,15 @@ class MusicDirectory : ArrayList() { abstract var album: String? abstract var title: String? abstract override val name: String? - abstract val discNumber: Int? + abstract var discNumber: Int? abstract var coverArt: String? - abstract val songCount: Long? - abstract val created: Date? + abstract var songCount: Long? + abstract var created: Date? abstract var artist: String? - abstract val artistId: String? - abstract val duration: Int? - abstract val year: Int? - abstract val genre: String? + abstract var artistId: String? + abstract var duration: Int? + abstract var year: Int? + abstract var genre: String? abstract var starred: Boolean abstract var path: String? abstract var closeness: Int @@ -120,15 +120,15 @@ class MusicDirectory : ArrayList() { override var album: String? = null, override var title: String? = null, override val name: String? = null, - override val discNumber: Int = 0, + override var discNumber: Int? = 0, override var coverArt: String? = null, - override val songCount: Long? = null, - override val created: Date? = null, + override var songCount: Long? = null, + override var created: Date? = null, override var artist: String? = null, - override val artistId: String? = null, - override val duration: Int = 0, - override val year: Int = 0, - override val genre: String? = null, + override var artistId: String? = null, + override var duration: Int? = 0, + override var year: Int? = 0, + override var genre: String? = null, override var starred: Boolean = false, override var path: String? = null, override var closeness: Int = 0, diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt index eb42d409..5fd70782 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt @@ -21,7 +21,7 @@ fun Album.toDomainEntity(): MusicDirectory.Album = MusicDirectory.Album( ) fun Album.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory().apply { - addAll(this@toMusicDirectoryDomainEntity.songList.map { it.toDomainEntity() }) + addAll(this@toMusicDirectoryDomainEntity.songList.map { it.toTrackEntity() }) } fun List.toDomainEntityList(): List = this.map { it.toDomainEntity() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt index e7ac4e97..19f61f32 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt @@ -10,7 +10,7 @@ fun ApiBookmark.toDomainEntity(): Bookmark = Bookmark( comment = this@toDomainEntity.comment, created = this@toDomainEntity.created?.time, changed = this@toDomainEntity.changed?.time, - entry = this@toDomainEntity.entry.toDomainEntity() + entry = this@toDomainEntity.entry.toTrackEntity() ) fun List.toDomainEntitiesList(): List = map { it.toDomainEntity() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt index adff7ee5..4999751d 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt @@ -1,5 +1,10 @@ -// Converts MusicDirectory entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] -// to app domain entities. +/* + * APIMusicDirectoryConverter.kt + * Copyright (C) 2009-2021 Ultrasonic developers + * + * Distributed under terms of the GNU GPLv3 license. + */ + @file:JvmName("APIMusicDirectoryConverter") package org.moire.ultrasonic.domain @@ -9,48 +14,90 @@ import java.util.Locale import org.moire.ultrasonic.api.subsonic.models.MusicDirectory as APIMusicDirectory import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild +/* + * Converts MusicDirectory entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] + * to app domain entities. + * + * Unlike other API endpoints getMusicDirectory doesn't return instances of Albums or Songs, + * but just children, which can be albums or songs. + */ + internal val dateFormat: DateFormat by lazy { SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault()) } -fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry = MusicDirectory.Entry(id).apply { - parent = this@toDomainEntity.parent - isDirectory = this@toDomainEntity.isDir - title = this@toDomainEntity.title - album = this@toDomainEntity.album - albumId = this@toDomainEntity.albumId - artist = this@toDomainEntity.artist - artistId = this@toDomainEntity.artistId - track = this@toDomainEntity.track - year = this@toDomainEntity.year - genre = this@toDomainEntity.genre - contentType = this@toDomainEntity.contentType - suffix = this@toDomainEntity.suffix - transcodedContentType = this@toDomainEntity.transcodedContentType - transcodedSuffix = this@toDomainEntity.transcodedSuffix - coverArt = this@toDomainEntity.coverArt - size = this@toDomainEntity.size - duration = this@toDomainEntity.duration - bitRate = this@toDomainEntity.bitRate - path = this@toDomainEntity.path - isVideo = this@toDomainEntity.isVideo - created = this@toDomainEntity.created?.time - starred = this@toDomainEntity.starred != null - discNumber = this@toDomainEntity.discNumber - type = this@toDomainEntity.type - if (this@toDomainEntity.streamId.isNotBlank()) { - id = this@toDomainEntity.streamId - } - if (this@toDomainEntity.publishDate != null) { - artist = dateFormat.format(this@toDomainEntity.publishDate!!.time) - } - userRating = this@toDomainEntity.userRating - averageRating = this@toDomainEntity.averageRating +fun MusicDirectoryChild.toTrackEntity(): MusicDirectory.Entry = MusicDirectory.Entry(id).apply { + populateCommonProps(this, this@toTrackEntity) + populateTrackProps(this, this@toTrackEntity) } -fun List.toDomainEntityList() = this.map { it.toDomainEntity() } +fun MusicDirectoryChild.toAlbumEntity(): MusicDirectory.Album = MusicDirectory.Album(id).apply { + populateCommonProps(this, this@toAlbumEntity) +} + +private fun populateCommonProps( + entry: MusicDirectory.Child, + source: MusicDirectoryChild +) { + entry.parent = source.parent + entry.isDirectory = source.isDir + entry.title = source.title + entry.album = source.album + entry.artist = source.artist + entry.artistId = source.artistId + entry.year = source.year + entry.genre = source.genre + entry.coverArt = source.coverArt + entry.duration = source.duration + entry.path = source.path + entry.isVideo = source.isVideo + entry.created = source.created?.time + entry.starred = source.starred != null + entry.discNumber = source.discNumber + + if (source.streamId.isNotBlank()) { + entry.id = source.streamId + } + if (source.publishDate != null) { + entry.artist = dateFormat.format(source.publishDate!!.time) + } +} + +private fun populateTrackProps( + entry: MusicDirectory.Entry, + source: MusicDirectoryChild +) { + entry.size = source.size + entry.contentType = source.contentType + entry.suffix = source.suffix + entry.transcodedContentType = source.transcodedContentType + entry.transcodedSuffix = source.transcodedSuffix + entry.track = source.track + entry.albumId = source.albumId + entry.bitRate = source.bitRate + entry.type = source.type + entry.userRating = source.userRating + entry.averageRating = source.averageRating +} + +fun List.toDomainEntityList(): List { + val newList: MutableList = mutableListOf() + + forEach { + if (it.isDir) + newList.add(it.toAlbumEntity()) + else + newList.add(it.toTrackEntity()) + } + + return newList +} + +fun List.toTrackList(): List = this.map { + it.toTrackEntity() +} fun APIMusicDirectory.toDomainEntity(): MusicDirectory = MusicDirectory().apply { name = this@toDomainEntity.name - addAll(this@toDomainEntity.childList.map { it.toDomainEntity() }) + addAll(this@toDomainEntity.childList.toDomainEntityList()) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt index 57f7e29d..7286163a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt @@ -12,7 +12,7 @@ internal val playlistDateFormat by lazy(NONE) { SimpleDateFormat.getInstance() } fun APIPlaylist.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory().apply { name = this@toMusicDirectoryDomainEntity.name - addAll(this@toMusicDirectoryDomainEntity.entriesList.map { it.toDomainEntity() }) + addAll(this@toMusicDirectoryDomainEntity.entriesList.map { it.toTrackEntity() }) } fun APIPlaylist.toDomainEntity(): Playlist = Playlist( diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt index b1dfdf6a..a8833bbe 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt @@ -9,17 +9,17 @@ import org.moire.ultrasonic.api.subsonic.models.SearchTwoResult fun APISearchResult.toDomainEntity(): SearchResult = SearchResult( emptyList(), emptyList(), - this.matchList.map { it.toDomainEntity() } + this.matchList.map { it.toTrackEntity() } ) fun SearchTwoResult.toDomainEntity(): SearchResult = SearchResult( this.artistList.map { it.toDomainEntity() }, this.albumList.map { it.toDomainEntity() }, - this.songList.map { it.toDomainEntity() } + this.songList.map { it.toTrackEntity() } ) fun SearchThreeResult.toDomainEntity(): SearchResult = SearchResult( this.artistList.map { it.toDomainEntity() }, this.albumList.map { it.toDomainEntity() }, - this.songList.map { it.toDomainEntity() } + this.songList.map { it.toTrackEntity() } ) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt index 408f42f7..39162de2 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt @@ -22,5 +22,5 @@ fun APIShare.toDomainEntity(): Share = Share( url = this@toDomainEntity.url, username = this@toDomainEntity.username, visitCount = this@toDomainEntity.visitCount.toLong(), - entries = this@toDomainEntity.items.toDomainEntityList().toMutableList() + entries = this@toDomainEntity.items.toTrackList().toMutableList() ) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt index 74c7c3ea..0289af48 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt @@ -41,6 +41,7 @@ import org.moire.ultrasonic.domain.toDomainEntity import org.moire.ultrasonic.domain.toDomainEntityList import org.moire.ultrasonic.domain.toIndexList import org.moire.ultrasonic.domain.toMusicDirectoryDomainEntity +import org.moire.ultrasonic.domain.toTrackEntity import org.moire.ultrasonic.util.FileUtil import org.moire.ultrasonic.util.Settings import timber.log.Timber @@ -317,7 +318,7 @@ open class RESTMusicService( "skipped" != podcastEntry.status && "error" != podcastEntry.status ) { - val entry = podcastEntry.toDomainEntity() + val entry = podcastEntry.toTrackEntity() entry.track = null musicDirectory.add(entry) } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt index 4d8eab69..b4b39932 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt @@ -51,7 +51,7 @@ class APIAlbumConverterTest { with(convertedEntity) { name `should be equal to` null size `should be equal to` entity.songList.size - this[0] `should be equal to` entity.songList[0].toDomainEntity() + this[0] `should be equal to` entity.songList[0].toTrackEntity() } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt index b9b24fe0..f20da140 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt @@ -27,7 +27,7 @@ class APIBookmarkConverterTest { comment `should be equal to` entity.comment created `should be equal to` entity.created?.time changed `should be equal to` entity.changed?.time - entry `should be equal to` entity.entry.toDomainEntity() + entry `should be equal to` entity.entry.toTrackEntity() } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt index e1b626cb..3bb559ca 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt @@ -26,7 +26,7 @@ class APIMusicDirectoryConverterTest { name `should be equal to` entity.name size `should be equal to` entity.childList.size getChildren() `should be equal to` entity.childList - .map { it.toDomainEntity() }.toMutableList() + .map { it.toTrackEntity() }.toMutableList() } } @@ -44,7 +44,7 @@ class APIMusicDirectoryConverterTest { starred = Calendar.getInstance(), userRating = 3, averageRating = 2.99F ) - val convertedEntity = entity.toDomainEntity() + val convertedEntity = entity.toTrackEntity() with(convertedEntity) { id `should be equal to` entity.id @@ -84,7 +84,7 @@ class APIMusicDirectoryConverterTest { artist = "some-artist", publishDate = Calendar.getInstance() ) - val convertedEntity = entity.toDomainEntity() + val convertedEntity = entity.toTrackEntity() with(convertedEntity) { id `should be equal to` entity.streamId @@ -100,7 +100,7 @@ class APIMusicDirectoryConverterTest { domainList.size `should be equal to` entitiesList.size domainList.forEachIndexed { index, entry -> - entry `should be equal to` entitiesList[index].toDomainEntity() + entry `should be equal to` entitiesList[index].toTrackEntity() } } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt index 7c06d540..9756af80 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt @@ -27,8 +27,8 @@ class APIPlaylistConverterTest { with(convertedEntity) { name `should be equal to` entity.name size `should be equal to` entity.entriesList.size - this[0] `should be equal to` entity.entriesList[0].toDomainEntity() - this[1] `should be equal to` entity.entriesList[1].toDomainEntity() + this[0] `should be equal to` entity.entriesList[0].toTrackEntity() + this[1] `should be equal to` entity.entriesList[1].toTrackEntity() } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt index ff3b30f8..d54a3a76 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt @@ -34,7 +34,7 @@ class APISearchConverterTest { artists `should not be equal to` null artists.size `should be equal to` 0 songs.size `should be equal to` entity.matchList.size - songs[0] `should be equal to` entity.matchList[0].toDomainEntity() + songs[0] `should be equal to` entity.matchList[0].toTrackEntity() } } @@ -54,7 +54,7 @@ class APISearchConverterTest { albums.size `should be equal to` entity.albumList.size albums[0] `should be equal to` entity.albumList[0].toDomainEntity() songs.size `should be equal to` entity.songList.size - songs[0] `should be equal to` entity.songList[0].toDomainEntity() + songs[0] `should be equal to` entity.songList[0].toTrackEntity() } } @@ -74,7 +74,7 @@ class APISearchConverterTest { albums.size `should be equal to` entity.albumList.size albums[0] `should be equal to` entity.albumList[0].toDomainEntity() songs.size `should be equal to` entity.songList.size - songs[0] `should be equal to` entity.songList[0].toDomainEntity() + songs[0] `should be equal to` entity.songList[0].toTrackEntity() } } } From a5e8daa912e663f529f6feab212ff18b853a3bd5 Mon Sep 17 00:00:00 2001 From: tzugen Date: Tue, 21 Dec 2021 23:44:18 +0100 Subject: [PATCH 08/24] Don't clear random list when appending --- .../main/kotlin/org/moire/ultrasonic/model/AlbumListModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/AlbumListModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/AlbumListModel.kt index 5fd2e86d..c5fd4d41 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/AlbumListModel.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/AlbumListModel.kt @@ -65,7 +65,7 @@ class AlbumListModel(application: Application) : GenericListModel(application) { // If we are refreshing the random list, we want to avoid items moving across the screen, // by clearing the list first - if (refresh && albumListType == "random") { + if (refresh && !append && albumListType == "random") { list.postValue(listOf()) } From 4a996f8edcd5bc6024aae90b4bc4f16fcea43784 Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 22 Dec 2021 13:26:58 +0100 Subject: [PATCH 09/24] Fix Scroll in MainFragment --- .../android-module-bootstrap.gradle | 1 + ultrasonic/build.gradle | 5 + .../moire/ultrasonic/fragment/MainFragment.kt | 4 +- ultrasonic/src/main/res/layout/main.xml | 376 +++++++++--------- 4 files changed, 198 insertions(+), 188 deletions(-) diff --git a/gradle_scripts/android-module-bootstrap.gradle b/gradle_scripts/android-module-bootstrap.gradle index 88519a56..ab63228b 100644 --- a/gradle_scripts/android-module-bootstrap.gradle +++ b/gradle_scripts/android-module-bootstrap.gradle @@ -40,6 +40,7 @@ android { buildFeatures { buildConfig = false + viewBinding true } } diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle index 0f330201..536f5627 100644 --- a/ultrasonic/build.gradle +++ b/ultrasonic/build.gradle @@ -58,6 +58,11 @@ android { kotlinOptions { jvmTarget = "1.8" } + + buildFeatures { + viewBinding true + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt index 6969a47f..a9e3a41a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt @@ -4,7 +4,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.LinearLayout +import android.widget.ScrollView import android.widget.TextView import androidx.core.view.isVisible import androidx.fragment.app.Fragment @@ -21,7 +21,7 @@ import org.moire.ultrasonic.util.Util */ class MainFragment : Fragment(), KoinComponent { - private lateinit var list: LinearLayout + private lateinit var list: ScrollView private lateinit var musicTitle: TextView private lateinit var artistsButton: TextView private lateinit var albumsButton: TextView diff --git a/ultrasonic/src/main/res/layout/main.xml b/ultrasonic/src/main/res/layout/main.xml index e6763155..83d627aa 100644 --- a/ultrasonic/src/main/res/layout/main.xml +++ b/ultrasonic/src/main/res/layout/main.xml @@ -1,211 +1,215 @@ - + a:id="@+id/main_list"> - + a:orientation="vertical"> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + \ No newline at end of file From 5a02467ee8b4c08ca3bf6ae7d7eacd9048d6a7cc Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 22 Dec 2021 13:36:13 +0100 Subject: [PATCH 10/24] Use binding --- .../android-module-bootstrap.gradle | 1 + ultrasonic/build.gradle | 1 + .../moire/ultrasonic/fragment/MainFragment.kt | 53 +-- ultrasonic/src/main/res/layout/main.xml | 351 +++++++++--------- 4 files changed, 207 insertions(+), 199 deletions(-) diff --git a/gradle_scripts/android-module-bootstrap.gradle b/gradle_scripts/android-module-bootstrap.gradle index ab63228b..6bbfec2e 100644 --- a/gradle_scripts/android-module-bootstrap.gradle +++ b/gradle_scripts/android-module-bootstrap.gradle @@ -41,6 +41,7 @@ android { buildFeatures { buildConfig = false viewBinding true + dataBinding true } } diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle index 536f5627..d99c253f 100644 --- a/ultrasonic/build.gradle +++ b/ultrasonic/build.gradle @@ -61,6 +61,7 @@ android { buildFeatures { viewBinding true + dataBinding true } compileOptions { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt index a9e3a41a..127e6a2b 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ScrollView import android.widget.TextView import androidx.core.view.isVisible import androidx.fragment.app.Fragment @@ -12,6 +11,7 @@ import androidx.navigation.Navigation import org.koin.core.component.KoinComponent import org.moire.ultrasonic.R import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline +import org.moire.ultrasonic.databinding.MainBinding import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Util @@ -21,7 +21,6 @@ import org.moire.ultrasonic.util.Util */ class MainFragment : Fragment(), KoinComponent { - private lateinit var list: ScrollView private lateinit var musicTitle: TextView private lateinit var artistsButton: TextView private lateinit var albumsButton: TextView @@ -41,6 +40,8 @@ class MainFragment : Fragment(), KoinComponent { private lateinit var albumsAlphaByArtistButton: TextView private lateinit var videosButton: TextView + private var binding: MainBinding? = null + override fun onCreate(savedInstanceState: Bundle?) { Util.applyTheme(this.context) super.onCreate(savedInstanceState) @@ -50,13 +51,12 @@ class MainFragment : Fragment(), KoinComponent { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.main, container, false) + ): View { + binding = MainBinding.inflate(inflater, container, false) + return binding!!.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - list = view.findViewById(R.id.main_list) - setupButtons() setupClickListener() setupItemVisibility() @@ -81,25 +81,30 @@ class MainFragment : Fragment(), KoinComponent { } } + override fun onDestroyView() { + super.onDestroyView() + binding = null + } + private fun setupButtons() { - musicTitle = list.findViewById(R.id.main_music) - artistsButton = list.findViewById(R.id.main_artists_button) - albumsButton = list.findViewById(R.id.main_albums_button) - genresButton = list.findViewById(R.id.main_genres_button) - videosTitle = list.findViewById(R.id.main_videos_title) - songsTitle = list.findViewById(R.id.main_songs) - randomSongsButton = list.findViewById(R.id.main_songs_button) - songsStarredButton = list.findViewById(R.id.main_songs_starred) - albumsTitle = list.findViewById(R.id.main_albums) - albumsNewestButton = list.findViewById(R.id.main_albums_newest) - albumsRandomButton = list.findViewById(R.id.main_albums_random) - albumsHighestButton = list.findViewById(R.id.main_albums_highest) - albumsStarredButton = list.findViewById(R.id.main_albums_starred) - albumsRecentButton = list.findViewById(R.id.main_albums_recent) - albumsFrequentButton = list.findViewById(R.id.main_albums_frequent) - albumsAlphaByNameButton = list.findViewById(R.id.main_albums_alphaByName) - albumsAlphaByArtistButton = list.findViewById(R.id.main_albums_alphaByArtist) - videosButton = list.findViewById(R.id.main_videos) + musicTitle = binding!!.mainMusic + artistsButton = binding!!.mainArtistsButton + albumsButton = binding!!.mainAlbumsButton + genresButton = binding!!.mainGenresButton + videosTitle = binding!!.mainVideosTitle + songsTitle = binding!!.mainSongs + randomSongsButton = binding!!.mainSongsButton + songsStarredButton = binding!!.mainSongsStarred + albumsTitle = binding!!.mainAlbums + albumsNewestButton = binding!!.mainAlbumsNewest + albumsRandomButton = binding!!.mainAlbumsRandom + albumsHighestButton = binding!!.mainAlbumsHighest + albumsStarredButton = binding!!.mainAlbumsStarred + albumsRecentButton = binding!!.mainAlbumsRecent + albumsFrequentButton = binding!!.mainAlbumsFrequent + albumsAlphaByNameButton = binding!!.mainAlbumsAlphaByName + albumsAlphaByArtistButton = binding!!.mainAlbumsAlphaByArtist + videosButton = binding!!.mainVideos } private fun setupItemVisibility() { diff --git a/ultrasonic/src/main/res/layout/main.xml b/ultrasonic/src/main/res/layout/main.xml index 83d627aa..1b384738 100644 --- a/ultrasonic/src/main/res/layout/main.xml +++ b/ultrasonic/src/main/res/layout/main.xml @@ -1,215 +1,216 @@ - - + + + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + android:id="@+id/main_music" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:paddingStart="6dp" + android:text="@string/main.music" + android:textAllCaps="true" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/cyan" + android:textStyle="bold" /> + android:id="@+id/main_artists_button" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.artists_title" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_albums_button" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.albums_title" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_genres_button" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.genres_title" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_songs" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:paddingStart="6dp" + android:text="@string/main.songs_title" + android:textAllCaps="true" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/cyan" + android:textStyle="bold" /> + android:id="@+id/main_songs_button" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.songs_random" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_songs_starred" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.songs_starred" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_albums" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:paddingStart="6dp" + android:text="@string/main.albums_title" + android:textAllCaps="true" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/cyan" + android:textStyle="bold" /> + android:id="@+id/main_albums_newest" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.albums_newest" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_albums_recent" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.albums_recent" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_albums_frequent" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.albums_frequent" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_albums_highest" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.albums_highest" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_albums_random" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.albums_random" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_albums_starred" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.albums_starred" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_albums_alphaByName" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.albums_alphaByName" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_albums_alphaByArtist" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.albums_alphaByArtist" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:id="@+id/main_videos_title" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:paddingStart="6dp" + android:text="@string/main.videos" + android:textAllCaps="true" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/cyan" + android:textStyle="bold" /> + android:id="@+id/main_videos" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minHeight="40dip" + android:paddingStart="6dip" + android:paddingEnd="6dip" + android:text="@string/main.videos" + android:textAppearance="?android:attr/textAppearanceMedium" /> - \ No newline at end of file + + \ No newline at end of file From 9f5bc85cf240ea263d36e19058547e336a0a701e Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 22 Dec 2021 13:38:30 +0100 Subject: [PATCH 11/24] Fallback to destructive migration on downgrade --- .../kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt index 79209e5b..48e4b9af 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt @@ -30,6 +30,7 @@ val appPermanentStorage = module { .addMigrations(MIGRATION_1_2) .addMigrations(MIGRATION_2_3) .addMigrations(MIGRATION_3_4) + .fallbackToDestructiveMigration() .build() } From 95b78a3c11b15a622cac5a286306466f6c774c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Fri, 24 Dec 2021 17:18:57 +0100 Subject: [PATCH 12/24] More tiny and pretty ic_empty icon --- ultrasonic/src/main/res/drawable/ic_empty.xml | 91 +------------------ 1 file changed, 5 insertions(+), 86 deletions(-) diff --git a/ultrasonic/src/main/res/drawable/ic_empty.xml b/ultrasonic/src/main/res/drawable/ic_empty.xml index 74776517..5e7c170a 100644 --- a/ultrasonic/src/main/res/drawable/ic_empty.xml +++ b/ultrasonic/src/main/res/drawable/ic_empty.xml @@ -1,91 +1,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + From 193fe5ac3a0ab3c01d21b8f0c1957f6d24a3af53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Fri, 24 Dec 2021 18:36:23 +0100 Subject: [PATCH 13/24] Add missing database migrations --- .../org/moire/ultrasonic/data/AppDatabase.kt | 125 ++++++++++++++++++ .../di/AppPermanentStorageModule.kt | 7 +- 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt index ddbb62fb..2eecb7d7 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt @@ -26,6 +26,45 @@ val MIGRATION_1_2: Migration = object : Migration(1, 2) { } } +val MIGRATION_2_1: Migration = object : Migration(2, 1) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL( + """ + CREATE TABLE IF NOT EXISTS ServerSettingMigration ( + id INTEGER NOT NULL PRIMARY KEY, + [index] INTEGER NOT NULL, + name TEXT NOT NULL, + url TEXT NOT NULL, + userName TEXT NOT NULL, + password TEXT NOT NULL, + jukeboxByDefault INTEGER NOT NULL, + allowSelfSignedCertificate INTEGER NOT NULL, + ldapSupport INTEGER NOT NULL, + musicFolderId TEXT + ) + """.trimIndent() + ) + database.execSQL( + """ + INSERT INTO ServerSettingMigration ( + id, [index], name, url, userName, password, jukeboxByDefault, + allowSelfSignedCertificate, ldapSupport, musicFolderId + ) + SELECT + id, [index], name, url, userName, password, jukeboxByDefault, + allowSelfSignedCertificate, ldapSupport, musicFolderId + FROM ServerSetting + """.trimIndent() + ) + database.execSQL( + "DROP TABLE ServerSetting" + ) + database.execSQL( + "ALTER TABLE ServerSettingMigration RENAME TO ServerSetting" + ) + } +} + val MIGRATION_2_3: Migration = object : Migration(2, 3) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL( @@ -43,6 +82,46 @@ val MIGRATION_2_3: Migration = object : Migration(2, 3) { } } +val MIGRATION_3_2: Migration = object : Migration(3, 2) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL( + """ + CREATE TABLE IF NOT EXISTS ServerSettingMigration ( + id INTEGER NOT NULL PRIMARY KEY, + [index] INTEGER NOT NULL, + name TEXT NOT NULL, + url TEXT NOT NULL, + userName TEXT NOT NULL, + password TEXT NOT NULL, + jukeboxByDefault INTEGER NOT NULL, + allowSelfSignedCertificate INTEGER NOT NULL, + ldapSupport INTEGER NOT NULL, + musicFolderId TEXT, + minimumApiVersion TEXT + ) + """.trimIndent() + ) + database.execSQL( + """ + INSERT INTO ServerSettingMigration ( + id, [index], name, url, userName, password, jukeboxByDefault, + allowSelfSignedCertificate, ldapSupport, musicFolderId, minimumApiVersion + ) + SELECT + id, [index], name, url, userName, password, jukeboxByDefault, + allowSelfSignedCertificate, ldapSupport, musicFolderId, minimumApiVersion + FROM ServerSetting + """.trimIndent() + ) + database.execSQL( + "DROP TABLE ServerSetting" + ) + database.execSQL( + "ALTER TABLE ServerSettingMigration RENAME TO ServerSetting" + ) + } +} + val MIGRATION_3_4: Migration = object : Migration(3, 4) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL( @@ -50,3 +129,49 @@ val MIGRATION_3_4: Migration = object : Migration(3, 4) { ) } } + +val MIGRATION_4_3: Migration = object : Migration(4, 3) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL( + """ + CREATE TABLE IF NOT EXISTS ServerSettingMigration ( + id INTEGER NOT NULL PRIMARY KEY, + [index] INTEGER NOT NULL, + name TEXT NOT NULL, + url TEXT NOT NULL, + userName TEXT NOT NULL, + password TEXT NOT NULL, + jukeboxByDefault INTEGER NOT NULL, + allowSelfSignedCertificate INTEGER NOT NULL, + ldapSupport INTEGER NOT NULL, + musicFolderId TEXT, + minimumApiVersion TEXT, + chatSupport INTEGER, + bookmarkSupport INTEGER, + shareSupport INTEGER, + podcastSupport INTEGER + ) + """.trimIndent() + ) + database.execSQL( + """ + INSERT INTO ServerSettingMigration ( + id, [index], name, url, userName, password, jukeboxByDefault, + allowSelfSignedCertificate, ldapSupport, musicFolderId, minimumApiVersion, + chatSupport, bookmarkSupport, shareSupport, podcastSupport + ) + SELECT + id, [index], name, url, userName, password, jukeboxByDefault, + allowSelfSignedCertificate, ldapSupport, musicFolderId, minimumApiVersion, + chatSupport, bookmarkSupport, shareSupport, podcastSupport + FROM ServerSetting + """.trimIndent() + ) + database.execSQL( + "DROP TABLE ServerSetting" + ) + database.execSQL( + "ALTER TABLE ServerSettingMigration RENAME TO ServerSetting" + ) + } +} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt index 48e4b9af..adce9869 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt @@ -7,8 +7,11 @@ import org.koin.core.qualifier.named import org.koin.dsl.module import org.moire.ultrasonic.data.AppDatabase import org.moire.ultrasonic.data.MIGRATION_1_2 +import org.moire.ultrasonic.data.MIGRATION_2_1 import org.moire.ultrasonic.data.MIGRATION_2_3 +import org.moire.ultrasonic.data.MIGRATION_3_2 import org.moire.ultrasonic.data.MIGRATION_3_4 +import org.moire.ultrasonic.data.MIGRATION_4_3 import org.moire.ultrasonic.model.ServerSettingsModel import org.moire.ultrasonic.util.Settings @@ -28,9 +31,11 @@ val appPermanentStorage = module { DB_FILENAME ) .addMigrations(MIGRATION_1_2) + .addMigrations(MIGRATION_2_1) .addMigrations(MIGRATION_2_3) + .addMigrations(MIGRATION_3_2) .addMigrations(MIGRATION_3_4) - .fallbackToDestructiveMigration() + .addMigrations(MIGRATION_4_3) .build() } From 8f43f69a66844c9d8d7f85bf43018afa6c4284c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Mon, 27 Dec 2021 11:15:13 +0100 Subject: [PATCH 14/24] Don't push translations from master --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ef2b3d17..1fdd775d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -125,7 +125,6 @@ workflows: branches: only: - develop - - master - generate_signed_apk: filters: tags: From f68b46678aff88c337b9fd6561e1b28433f1609a Mon Sep 17 00:00:00 2001 From: tzugen Date: Thu, 13 Jan 2022 15:31:21 +0100 Subject: [PATCH 15/24] Deactivate custom color and set DB to version 3 --- .../ultrasonic/activity/NavigationActivity.kt | 4 +- .../ultrasonic/adapters/ServerRowAdapter.kt | 4 +- .../org/moire/ultrasonic/data/AppDatabase.kt | 2 +- .../moire/ultrasonic/data/ServerSetting.kt | 5 +- .../ultrasonic/fragment/EditServerFragment.kt | 66 +++++++++---------- .../ultrasonic/model/ServerSettingsModel.kt | 1 - 6 files changed, 39 insertions(+), 43 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt index 2a915be3..3dfbe830 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt @@ -208,8 +208,8 @@ class NavigationActivity : AppCompatActivity() { selectServerButton?.text = getString(R.string.main_setup_server, activeServer.name) else selectServerButton?.text = activeServer.name - val foregroundColor = ServerColor.getForegroundColor(this, activeServer.color) - val backgroundColor = ServerColor.getBackgroundColor(this, activeServer.color) + val foregroundColor = ServerColor.getForegroundColor(this, null) + val backgroundColor = ServerColor.getBackgroundColor(this, null) if (activeServer.index == 0) selectServerButton?.icon = diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ServerRowAdapter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ServerRowAdapter.kt index 89c7a5ea..1247ac66 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ServerRowAdapter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ServerRowAdapter.kt @@ -108,8 +108,8 @@ internal class ServerRowAdapter( } // Set colors - icon?.setTint(ServerColor.getForegroundColor(context, setting?.color)) - background?.setTint(ServerColor.getBackgroundColor(context, setting?.color)) + icon?.setTint(ServerColor.getForegroundColor(context, null)) + background?.setTint(ServerColor.getBackgroundColor(context, null)) // Set the final drawables image?.setImageDrawable(icon) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt index 2eecb7d7..e12339ae 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt @@ -9,7 +9,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase * Room Database to be used to store global data for the whole app. * This could be settings or data that are not specific to any remote music database */ -@Database(entities = [ServerSetting::class], version = 4) +@Database(entities = [ServerSetting::class], version = 3) abstract class AppDatabase : RoomDatabase() { /** diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ServerSetting.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ServerSetting.kt index e3fb9b04..705f526a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ServerSetting.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ServerSetting.kt @@ -23,7 +23,6 @@ data class ServerSetting( @ColumnInfo(name = "index") var index: Int, @ColumnInfo(name = "name") var name: String, @ColumnInfo(name = "url") var url: String, - @ColumnInfo(name = "color") var color: Int? = null, @ColumnInfo(name = "userName") var userName: String, @ColumnInfo(name = "password") var password: String, @ColumnInfo(name = "jukeboxByDefault") var jukeboxByDefault: Boolean, @@ -37,9 +36,9 @@ data class ServerSetting( @ColumnInfo(name = "podcastSupport") var podcastSupport: Boolean? = null ) { constructor() : this ( - -1, 0, "", "", null, "", "", false, false, false, null, null + -1, 0, "", "", "", "", false, false, false, null, null ) constructor(name: String, url: String) : this( - -1, 0, name, url, null, "", "", false, false, false, null, null + -1, 0, name, url, "", "", false, false, false, null, null ) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt index 29de1289..dce433bc 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt @@ -7,14 +7,11 @@ import android.view.ViewGroup import android.widget.Button import android.widget.ImageView import androidx.core.content.ContextCompat +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.google.android.material.switchmaterial.SwitchMaterial import com.google.android.material.textfield.TextInputLayout -import com.skydoves.colorpickerview.ColorPickerDialog -import com.skydoves.colorpickerview.flag.BubbleFlag -import com.skydoves.colorpickerview.flag.FlagMode -import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener import java.io.IOException import java.net.MalformedURLException import java.net.URL @@ -43,8 +40,6 @@ import org.moire.ultrasonic.util.Util import retrofit2.Response import timber.log.Timber -private const val DIALOG_PADDING = 12 - /** * Displays a form where server settings can be created / edited */ @@ -147,7 +142,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { } else { // Creating a new server FragmentTitle.setTitle(this, R.string.server_editor_new_label) - updateColor(null) + // updateColor(null) currentServerSetting = ServerSetting() saveButton!!.setOnClickListener { if (getFields()) { @@ -163,33 +158,36 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { } } - serverColorImageView!!.setOnClickListener { - val bubbleFlag = BubbleFlag(context) - bubbleFlag.flagMode = FlagMode.LAST - ColorPickerDialog.Builder(context).apply { - this.colorPickerView.setInitialColor(currentColor) - this.colorPickerView.flagView = bubbleFlag - } - .attachAlphaSlideBar(false) - .setPositiveButton( - getString(R.string.common_ok), - ColorEnvelopeListener { envelope, _ -> - selectedColor = envelope.color - updateColor(envelope.color) - } - ) - .setNegativeButton(getString(R.string.common_cancel)) { - dialogInterface, _ -> - dialogInterface.dismiss() - } - .setBottomSpace(DIALOG_PADDING) - .show() - } +// serverColorImageView!!.setOnClickListener { +// val bubbleFlag = BubbleFlag(context) +// bubbleFlag.flagMode = FlagMode.LAST +// ColorPickerDialog.Builder(context).apply { +// this.colorPickerView.setInitialColor(currentColor) +// this.colorPickerView.flagView = bubbleFlag +// } +// .attachAlphaSlideBar(false) +// .setPositiveButton( +// getString(R.string.common_ok), +// ColorEnvelopeListener { envelope, _ -> +// selectedColor = envelope.color +// updateColor(envelope.color) +// } +// ) +// .setNegativeButton(getString(R.string.common_cancel)) { +// dialogInterface, _ -> +// dialogInterface.dismiss() +// } +// .setBottomSpace(DIALOG_PADDING) +// .show() +// } + + serverColorImageView?.isVisible = false } - private fun updateColor(color: Int?) { + @Suppress("unused") + private fun updateColor() { val image = ContextCompat.getDrawable(requireContext(), R.drawable.thumb_drawable) - currentColor = ServerColor.getBackgroundColor(requireContext(), color) + currentColor = ServerColor.getBackgroundColor(requireContext(), null) image?.setTint(currentColor) serverColorImageView?.background = image } @@ -254,7 +252,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { selfSignedSwitch!!.isChecked = savedInstanceState.getBoolean(::selfSignedSwitch.name) ldapSwitch!!.isChecked = savedInstanceState.getBoolean(::ldapSwitch.name) jukeboxSwitch!!.isChecked = savedInstanceState.getBoolean(::jukeboxSwitch.name) - updateColor(savedInstanceState.getInt(::serverColorImageView.name)) + // updateColor(savedInstanceState.getInt(::serverColorImageView.name)) if (savedInstanceState.containsKey(::selectedColor.name)) selectedColor = savedInstanceState.getInt(::selectedColor.name) isInstanceStateSaved = savedInstanceState.getBoolean(::isInstanceStateSaved.name) @@ -273,7 +271,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { selfSignedSwitch!!.isChecked = currentServerSetting!!.allowSelfSignedCertificate ldapSwitch!!.isChecked = currentServerSetting!!.ldapSupport jukeboxSwitch!!.isChecked = currentServerSetting!!.jukeboxByDefault - updateColor(currentServerSetting!!.color) + // updateColor(currentServerSetting!!.color) } /** @@ -322,7 +320,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { if (isValid) { currentServerSetting!!.name = serverNameEditText!!.editText?.text.toString() currentServerSetting!!.url = serverAddressEditText!!.editText?.text.toString() - currentServerSetting!!.color = selectedColor + // currentServerSetting!!.color = selectedColor currentServerSetting!!.userName = userNameEditText!!.editText?.text.toString() currentServerSetting!!.password = passwordEditText!!.editText?.text.toString() currentServerSetting!!.allowSelfSignedCertificate = selfSignedSwitch!!.isChecked diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/ServerSettingsModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/ServerSettingsModel.kt index 2f520617..9261c6c2 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/ServerSettingsModel.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/ServerSettingsModel.kt @@ -212,7 +212,6 @@ class ServerSettingsModel( serverId, settings.getString(PREFERENCES_KEY_SERVER_NAME + preferenceId, "")!!, url, - null, userName, settings.getString(PREFERENCES_KEY_PASSWORD + preferenceId, "")!!, settings.getBoolean(PREFERENCES_KEY_JUKEBOX_BY_DEFAULT + preferenceId, false), From 5e24c3ab400e3bc2bf15dfa0888a5e42bccab4d5 Mon Sep 17 00:00:00 2001 From: Nite Date: Fri, 14 Jan 2022 19:36:05 +0100 Subject: [PATCH 16/24] Fixed text visibility --- .../org/moire/ultrasonic/fragment/EditServerFragment.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt index dce433bc..916c93ca 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.ImageView +import android.widget.TextView import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.fragment.app.Fragment @@ -67,6 +68,8 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { private var currentColor: Int = 0 private var selectedColor: Int? = null + private var editServerColorText: TextView? = null + @Override override fun onCreate(savedInstanceState: Bundle?) { Util.applyTheme(this.context) @@ -94,6 +97,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { jukeboxSwitch = view.findViewById(R.id.edit_jukebox) saveButton = view.findViewById(R.id.edit_save) testButton = view.findViewById(R.id.edit_test) + editServerColorText = view.findViewById(R.id.edit_server_color_text) val index = arguments?.getInt( EDIT_SERVER_INTENT_INDEX, @@ -182,6 +186,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { // } serverColorImageView?.isVisible = false + editServerColorText?.isVisible = false } @Suppress("unused") From 121bcde18a894adc2373b72a50e4de2f36dea0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Tue, 18 Jan 2022 10:55:58 +0100 Subject: [PATCH 17/24] Update translations --- ultrasonic/src/main/res/values-cs/strings.xml | 2 ++ ultrasonic/src/main/res/values-de/strings.xml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ultrasonic/src/main/res/values-cs/strings.xml b/ultrasonic/src/main/res/values-cs/strings.xml index cc89ff3b..11dd16e9 100644 --- a/ultrasonic/src/main/res/values-cs/strings.xml +++ b/ultrasonic/src/main/res/values-cs/strings.xml @@ -375,11 +375,13 @@ %d skladba %d skladby + %d skladeb %d skladeb Zbývá %d den zkušební doby Zbývají %d dny zkušební doby + Zbývá %d dní zkušební doby Zbývá %d dní zkušební doby diff --git a/ultrasonic/src/main/res/values-de/strings.xml b/ultrasonic/src/main/res/values-de/strings.xml index ab621dd9..ba429dd3 100644 --- a/ultrasonic/src/main/res/values-de/strings.xml +++ b/ultrasonic/src/main/res/values-de/strings.xml @@ -103,7 +103,7 @@ Kürzlich gespielt Mit Stern Alben - Künstler*in + Künstler*innen Genres Musik Offline @@ -134,7 +134,7 @@ Aktualisierung der Wiedergabeliste %s ist fehlgeschlagen Bitte warten… Alben - Künstler*in + Künstler*innen Suche Zeige mehr Keine Treffer, bitte erneut versuchen From 22c9db59c313ab1ba9f53edc885d978ec96183bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Tue, 18 Jan 2022 11:23:19 +0100 Subject: [PATCH 18/24] Ignore Unused Quantity --- ultrasonic/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle index d99c253f..f450e09e 100644 --- a/ultrasonic/build.gradle +++ b/ultrasonic/build.gradle @@ -48,8 +48,8 @@ android { lintOptions { baselineFile file("lint-baseline.xml") ignore 'MissingTranslation' + ignore 'UnusedQuantity' warning 'ImpliedQuantity' - warning 'UnusedQuantity' disable 'IconMissingDensityFolder', "VectorPath" abortOnError true warningsAsErrors true From 23d07831648e8e3432682ea1935b2ebe892ed6b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Tue, 18 Jan 2022 11:36:39 +0100 Subject: [PATCH 19/24] Bump version to 3.0.0 --- .../metadata/android/en-US/changelogs/99.txt | 14 ++++++++++++++ .../metadata/android/es-ES/changelogs/99.txt | 17 +++++++++++++++++ ultrasonic/build.gradle | 4 ++-- 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/99.txt create mode 100644 fastlane/metadata/android/es-ES/changelogs/99.txt diff --git a/fastlane/metadata/android/en-US/changelogs/99.txt b/fastlane/metadata/android/en-US/changelogs/99.txt new file mode 100644 index 00000000..ace37403 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/99.txt @@ -0,0 +1,14 @@ +Bug fixes +- #609: Weird scrobbling behaviour (offset). + +Enhancements +- #599: Moved server selector and settings to the Navigation menu. +- #600: Migrate Permission utitlity to Kotlin, increase min SDK to 17. +- #604: Implement a Download view. +- #613: targetSdkVersion must be 30 or higher. +- #622: Refactor events. +- #641: Remove feature storage. +- #642: Remove MergeAdapter and SackOfViewsAdapter. +- #649: Unify error dialog handling. +- #652: Updated custom cache location handling to remove isUri. +- #662: Improve database migrations. diff --git a/fastlane/metadata/android/es-ES/changelogs/99.txt b/fastlane/metadata/android/es-ES/changelogs/99.txt new file mode 100644 index 00000000..08363abc --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/99.txt @@ -0,0 +1,17 @@ +Corrección de errores +- #609: Comportamiento extraño de scrobbling (offset). + +Mejoras +- #599: Se ha movido el selector de servidor y la configuración al menú de + navegación. +- #600: Migración de la utilidad de permisos a Kotlin, aumento del SDK + mínimo a 17. +- #604: Implementar una vista de Descarga. +- #613: targetSdkVersion debe ser 30 o superior. +- #622: Refactorización de eventos. +- #641: Eliminar el almacenamiento de funciones. +- #642: Eliminar MergeAdapter y SackOfViewsAdapter. +- #649: Unificar el manejo del diálogo de error. +- #652: Manejo de ubicación de caché personalizado actualizado para eliminar + isUri. +- #662: Mejorar las migraciones de bases de datos. diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle index f450e09e..34bf88de 100644 --- a/ultrasonic/build.gradle +++ b/ultrasonic/build.gradle @@ -9,8 +9,8 @@ android { defaultConfig { applicationId "org.moire.ultrasonic" - versionCode 98 - versionName "2.24.0" + versionCode 99 + versionName "3.0.0" minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk From 3558479278719cbaff2cd5c079409d1d4a4955f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Wed, 19 Jan 2022 09:39:26 +0100 Subject: [PATCH 20/24] Improve generation of signed apk in CI --- .circleci/config.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1fdd775d..5bacbf21 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -75,7 +75,7 @@ jobs: tx push -s generate_signed_apk: docker: - - image: circleci/android:api-28 + - image: circleci/android:api-30 working_directory: ~/ultrasonic steps: - checkout @@ -93,14 +93,15 @@ jobs: - run: name: sign release apk command: | + export PATH="${JAVA_HOME}/bin:${PATH}" mkdir -p /tmp/ultrasonic-release - jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ~/ultrasonic/ultrasonic-keystore -storepass ${ULTRASONIC_KEYSTORE_STOREPASS} -keypass ${ULTRASONIC_KEYSTORE_KEYPASS} ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk ultrasonic - jarsigner -verify ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk - ${ANDROID_HOME}/build-tools/27.0.0/zipalign -v 4 ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk /tmp/ultrasonic-release/ultrasonic-${CIRCLE_TAG}.apk + ${ANDROID_HOME}/build-tools/30.0.0/zipalign -v 4 ultrasonic/build/outputs/apk/release/ultrasonic-release-unsigned.apk /tmp/ultrasonic-release/ultrasonic-${CIRCLE_TAG}.apk + ${ANDROID_HOME}/build-tools/30.0.0/apksigner sign --verbose --ks ~/ultrasonic/ultrasonic-keystore --ks-pass pass:${ULTRASONIC_KEYSTORE_STOREPASS} --key-pass pass:${ULTRASONIC_KEYSTORE_KEYPASS} /tmp/ultrasonic-release/ultrasonic-${CIRCLE_TAG}.apk + ${ANDROID_HOME}/build-tools/30.0.0/apksigner verify --verbose /tmp/ultrasonic-release/ultrasonic-${CIRCLE_TAG}.apk - persist_to_workspace: root: /tmp/ultrasonic-release paths: - - ultrasonic-*.apk + - ultrasonic-*.apk* publish_github_signed_apk: docker: - image: circleci/golang From ca89d4b55e879f23dbccddd840caae21778412e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 11:01:45 +0000 Subject: [PATCH 21/24] Bump versions.mockito from 4.1.0 to 4.3.1 Bumps `versions.mockito` from 4.1.0 to 4.3.1. Updates `mockito-core` from 4.1.0 to 4.3.1 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.1.0...v4.3.1) Updates `mockito-inline` from 4.1.0 to 4.3.1 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.1.0...v4.3.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-inline dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 2eaca93c..f0f80345 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -33,7 +33,7 @@ ext.versions = [ junit4 : "4.13.2", junit5 : "5.8.1", - mockito : "4.1.0", + mockito : "4.3.1", mockitoKotlin : "4.0.0", kluent : "1.68", apacheCodecs : "1.15", From 4778d18fb9af67f01cc683efdd13de897718c4fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Fri, 4 Feb 2022 09:00:35 +0100 Subject: [PATCH 22/24] Update translations --- ultrasonic/src/main/res/values-de/strings.xml | 51 +++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/ultrasonic/src/main/res/values-de/strings.xml b/ultrasonic/src/main/res/values-de/strings.xml index ba429dd3..efb96fa7 100644 --- a/ultrasonic/src/main/res/values-de/strings.xml +++ b/ultrasonic/src/main/res/values-de/strings.xml @@ -29,14 +29,14 @@ Nachricht senden Album Ultrasonic - Künstler*in + Künstler Abbrechen Kommentar Bestätigen Löschen Herunterladen Details - Mehrere Genre + Mehrere Genres Name OK Anheften @@ -44,15 +44,14 @@ Abspielen Zuletzt spielen Als nächstes spielen - Vorheriges abspielen - + Vorheriges abspielen Jetzt spielen Zufällig spielen Öffentlich Speichern Titel Lösen - Verschiedene Künstler*innen + Verschiedene Künstler Möchtest du %1$s löschen Lesezeichen entfernt Lesezeichen gesetzt als %s. @@ -94,7 +93,7 @@ file:///android_asset/html/de/index.html Jukebox als Standard Keine Liedtexte gefunden - Nach Künstler*innen + Nach Künstler Nach Namen Am häufigsten gespielt Am besten bewertet @@ -103,10 +102,11 @@ Kürzlich gespielt Mit Stern Alben - Künstler*innen + Künstler Genres Musik Offline + %s - Server einrichten Gemischte Wiedergabe Zufällig Mit Stern @@ -125,7 +125,7 @@ Medienbibliothek Offline Medien Netzwerkfehler. Neuer Versuch %1$d von %2$d. - %d Künstler*in gefunden + %d Künstler gefunden Lese vom Server. Lese vom Server. Fertig! Wiedergabelisten @@ -134,7 +134,7 @@ Aktualisierung der Wiedergabeliste %s ist fehlgeschlagen Bitte warten… Alben - Künstler*innen + Künstler Suche Zeige mehr Keine Treffer, bitte erneut versuchen @@ -149,7 +149,7 @@ Ordner wählen Keine Genres gefunden Keine Wiedergabelisten auf dem Server - Kontaktierse Server, bitte warten. + Kontaktiere Server, bitte warten. Aussehen Puffer-Länge Deaktiviert @@ -218,7 +218,7 @@ Bitte eine gültige URL angeben. Bitte einen gültigen Benutzernamen eingeben (ohne führende Leerzeichen). Maximale Alben - Maximale Künstler*innen + Max Künstler 112 Kbps 128 Kbps 160 Kbps @@ -229,12 +229,12 @@ 64 Kbps 80 Kbps 96 Kbps - Maximale Bitragte - Mobil + Max Bitrate - Mobil Unbegrenzt - Maximale Bitrate - WLAN + Max Bitrate - WLAN Maximale Titel Auf Telefon, Headset und Bluetooth-Media-Tasten reagieren - Media Tasten + Medien Tasten Netzwerk Zeitüberschreitung 105 Sekunden 120 Sekunden @@ -257,6 +257,7 @@ Unbegrenzt Fortsetzen mit Kopfhörer Die App setzt eine pausierte Wiedergabe beim Anschließen der Kopfhörer fort. + Gespielte Musik scrobbeln 1 10 100 @@ -301,6 +302,7 @@ Verbindung OK, Server nicht lizensiert. Hell Dunkel + Schwarz Thema Selbst-signierte HTTPS Zertifikate erlauben LDAP Benutzeranmeldung aktivieren @@ -310,6 +312,8 @@ Durchsuchen von ID3-Tags Nutze ID3 Tag Methode anstatt Dateisystem-Methode Film + Medien nur über gebührenfreie Verbindungen herunterladen + Nur über WLAN herunterladen %1$s%2$s %d kbps 0 B @@ -322,11 +326,13 @@ SD Karte nicht verfügbar Keine SD Karte Standard Beschreibung einer Freigabe - Teilen + Freigaben Immer nach Details fragen Standard Ablaufzeit Dialog nicht wieder anzeigen - Ferigabeoptionen + Freigabeoptionen + Freigabe auf Server erstellen + Teilen erzeugt eine Freigabe auf dem Server und sendet die URL. Wenn ausgeschaltet, werden nur die Lied-Details geteilt. Kein Ablaufdatum Wiedergabeliste umschalten Lesezeichen setzen @@ -350,13 +356,13 @@ %s wurde von der Wiedergabeliste entfernt Wiedergabeliste teilen Aktuelles Lied teilen - Standard Begrüßung beim Teilen + Standard Freigabe-Begrüßung Hör dir mal die Musik an, die ich mit dir über %s geteilt habe. Titel teilen über Freigabe - Alle Titel nach Künstler*innen sortieren + Alle Titel nach Künstler sortieren Einen neuen Eintrag in der Künstleransicht hinzufügen, um auf alle Lieder eines Künstlers zuzugreifen - Künstler*in zeigen + Künstler zeigen Mehrere Jahre Wiedergabe fortsetzen, wenn ein Bluetooth Gerät verbunden wurde Wiedergabe pausieren, wenn ein Bluetooth Gerät getrennt wurde @@ -379,4 +385,9 @@ Inkompatible Versionen. Bitte die Ultrasonic App aktualisieren. Inkompatible Versionen. Bitte den subsonic Server aktualisieren. - + + Besonderheiten + Fünf-Stern Bewertung + Benutze Bewertungssystem mit fünf Sternen anstatt Lieder mit bloß einem Stern zu markieren. + + From a53d5378bfa2ae346960d8486dbc1d946ce34a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Garc=C3=ADa=20Amor?= Date: Fri, 4 Feb 2022 09:30:53 +0100 Subject: [PATCH 23/24] Bump version to 3.0.1 --- fastlane/metadata/android/en-US/changelogs/100.txt | 4 ++++ fastlane/metadata/android/es-ES/changelogs/100.txt | 4 ++++ ultrasonic/build.gradle | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/100.txt create mode 100644 fastlane/metadata/android/es-ES/changelogs/100.txt diff --git a/fastlane/metadata/android/en-US/changelogs/100.txt b/fastlane/metadata/android/en-US/changelogs/100.txt new file mode 100644 index 00000000..77f90ee8 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/100.txt @@ -0,0 +1,4 @@ +Others + +- #671: Bump versions.mockito from 4.1.0 to 4.3.1. +- Update translations. diff --git a/fastlane/metadata/android/es-ES/changelogs/100.txt b/fastlane/metadata/android/es-ES/changelogs/100.txt new file mode 100644 index 00000000..6f2ce6d2 --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/100.txt @@ -0,0 +1,4 @@ +Otros + +- #671: Actualizado versions.mockito de 4.1.0 a 4.3.1. +- Traducciones actualizadas. diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle index 34bf88de..d3b16d81 100644 --- a/ultrasonic/build.gradle +++ b/ultrasonic/build.gradle @@ -9,8 +9,8 @@ android { defaultConfig { applicationId "org.moire.ultrasonic" - versionCode 99 - versionName "3.0.0" + versionCode 100 + versionName "3.0.1" minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk From 586bc51a9cf922022c660ef8b3135ff4285afc08 Mon Sep 17 00:00:00 2001 From: Nite Date: Sat, 5 Feb 2022 11:06:20 +0100 Subject: [PATCH 24/24] Revert "Merge pull request #667 from ultrasonic/patchBranch" This reverts commit 41a462708d4a696d988d67f79d59f9424d3b0a05, reversing changes made to fd239e8e72a1361321f1f268d90e3474a2f2685e. --- .../ultrasonic/activity/NavigationActivity.kt | 4 +- .../ultrasonic/adapters/ServerRowAdapter.kt | 4 +- .../org/moire/ultrasonic/data/AppDatabase.kt | 2 +- .../moire/ultrasonic/data/ServerSetting.kt | 5 +- .../ultrasonic/fragment/EditServerFragment.kt | 71 +++++++++---------- .../ultrasonic/model/ServerSettingsModel.kt | 1 + 6 files changed, 43 insertions(+), 44 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt index 3dfbe830..2a915be3 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt @@ -208,8 +208,8 @@ class NavigationActivity : AppCompatActivity() { selectServerButton?.text = getString(R.string.main_setup_server, activeServer.name) else selectServerButton?.text = activeServer.name - val foregroundColor = ServerColor.getForegroundColor(this, null) - val backgroundColor = ServerColor.getBackgroundColor(this, null) + val foregroundColor = ServerColor.getForegroundColor(this, activeServer.color) + val backgroundColor = ServerColor.getBackgroundColor(this, activeServer.color) if (activeServer.index == 0) selectServerButton?.icon = diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ServerRowAdapter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ServerRowAdapter.kt index 1247ac66..89c7a5ea 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ServerRowAdapter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/ServerRowAdapter.kt @@ -108,8 +108,8 @@ internal class ServerRowAdapter( } // Set colors - icon?.setTint(ServerColor.getForegroundColor(context, null)) - background?.setTint(ServerColor.getBackgroundColor(context, null)) + icon?.setTint(ServerColor.getForegroundColor(context, setting?.color)) + background?.setTint(ServerColor.getBackgroundColor(context, setting?.color)) // Set the final drawables image?.setImageDrawable(icon) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt index e12339ae..2eecb7d7 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/AppDatabase.kt @@ -9,7 +9,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase * Room Database to be used to store global data for the whole app. * This could be settings or data that are not specific to any remote music database */ -@Database(entities = [ServerSetting::class], version = 3) +@Database(entities = [ServerSetting::class], version = 4) abstract class AppDatabase : RoomDatabase() { /** diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ServerSetting.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ServerSetting.kt index 705f526a..e3fb9b04 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ServerSetting.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ServerSetting.kt @@ -23,6 +23,7 @@ data class ServerSetting( @ColumnInfo(name = "index") var index: Int, @ColumnInfo(name = "name") var name: String, @ColumnInfo(name = "url") var url: String, + @ColumnInfo(name = "color") var color: Int? = null, @ColumnInfo(name = "userName") var userName: String, @ColumnInfo(name = "password") var password: String, @ColumnInfo(name = "jukeboxByDefault") var jukeboxByDefault: Boolean, @@ -36,9 +37,9 @@ data class ServerSetting( @ColumnInfo(name = "podcastSupport") var podcastSupport: Boolean? = null ) { constructor() : this ( - -1, 0, "", "", "", "", false, false, false, null, null + -1, 0, "", "", null, "", "", false, false, false, null, null ) constructor(name: String, url: String) : this( - -1, 0, name, url, "", "", false, false, false, null, null + -1, 0, name, url, null, "", "", false, false, false, null, null ) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt index 916c93ca..29de1289 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt @@ -6,13 +6,15 @@ import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.ImageView -import android.widget.TextView import androidx.core.content.ContextCompat -import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.google.android.material.switchmaterial.SwitchMaterial import com.google.android.material.textfield.TextInputLayout +import com.skydoves.colorpickerview.ColorPickerDialog +import com.skydoves.colorpickerview.flag.BubbleFlag +import com.skydoves.colorpickerview.flag.FlagMode +import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener import java.io.IOException import java.net.MalformedURLException import java.net.URL @@ -41,6 +43,8 @@ import org.moire.ultrasonic.util.Util import retrofit2.Response import timber.log.Timber +private const val DIALOG_PADDING = 12 + /** * Displays a form where server settings can be created / edited */ @@ -68,8 +72,6 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { private var currentColor: Int = 0 private var selectedColor: Int? = null - private var editServerColorText: TextView? = null - @Override override fun onCreate(savedInstanceState: Bundle?) { Util.applyTheme(this.context) @@ -97,7 +99,6 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { jukeboxSwitch = view.findViewById(R.id.edit_jukebox) saveButton = view.findViewById(R.id.edit_save) testButton = view.findViewById(R.id.edit_test) - editServerColorText = view.findViewById(R.id.edit_server_color_text) val index = arguments?.getInt( EDIT_SERVER_INTENT_INDEX, @@ -146,7 +147,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { } else { // Creating a new server FragmentTitle.setTitle(this, R.string.server_editor_new_label) - // updateColor(null) + updateColor(null) currentServerSetting = ServerSetting() saveButton!!.setOnClickListener { if (getFields()) { @@ -162,37 +163,33 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { } } -// serverColorImageView!!.setOnClickListener { -// val bubbleFlag = BubbleFlag(context) -// bubbleFlag.flagMode = FlagMode.LAST -// ColorPickerDialog.Builder(context).apply { -// this.colorPickerView.setInitialColor(currentColor) -// this.colorPickerView.flagView = bubbleFlag -// } -// .attachAlphaSlideBar(false) -// .setPositiveButton( -// getString(R.string.common_ok), -// ColorEnvelopeListener { envelope, _ -> -// selectedColor = envelope.color -// updateColor(envelope.color) -// } -// ) -// .setNegativeButton(getString(R.string.common_cancel)) { -// dialogInterface, _ -> -// dialogInterface.dismiss() -// } -// .setBottomSpace(DIALOG_PADDING) -// .show() -// } - - serverColorImageView?.isVisible = false - editServerColorText?.isVisible = false + serverColorImageView!!.setOnClickListener { + val bubbleFlag = BubbleFlag(context) + bubbleFlag.flagMode = FlagMode.LAST + ColorPickerDialog.Builder(context).apply { + this.colorPickerView.setInitialColor(currentColor) + this.colorPickerView.flagView = bubbleFlag + } + .attachAlphaSlideBar(false) + .setPositiveButton( + getString(R.string.common_ok), + ColorEnvelopeListener { envelope, _ -> + selectedColor = envelope.color + updateColor(envelope.color) + } + ) + .setNegativeButton(getString(R.string.common_cancel)) { + dialogInterface, _ -> + dialogInterface.dismiss() + } + .setBottomSpace(DIALOG_PADDING) + .show() + } } - @Suppress("unused") - private fun updateColor() { + private fun updateColor(color: Int?) { val image = ContextCompat.getDrawable(requireContext(), R.drawable.thumb_drawable) - currentColor = ServerColor.getBackgroundColor(requireContext(), null) + currentColor = ServerColor.getBackgroundColor(requireContext(), color) image?.setTint(currentColor) serverColorImageView?.background = image } @@ -257,7 +254,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { selfSignedSwitch!!.isChecked = savedInstanceState.getBoolean(::selfSignedSwitch.name) ldapSwitch!!.isChecked = savedInstanceState.getBoolean(::ldapSwitch.name) jukeboxSwitch!!.isChecked = savedInstanceState.getBoolean(::jukeboxSwitch.name) - // updateColor(savedInstanceState.getInt(::serverColorImageView.name)) + updateColor(savedInstanceState.getInt(::serverColorImageView.name)) if (savedInstanceState.containsKey(::selectedColor.name)) selectedColor = savedInstanceState.getInt(::selectedColor.name) isInstanceStateSaved = savedInstanceState.getBoolean(::isInstanceStateSaved.name) @@ -276,7 +273,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { selfSignedSwitch!!.isChecked = currentServerSetting!!.allowSelfSignedCertificate ldapSwitch!!.isChecked = currentServerSetting!!.ldapSupport jukeboxSwitch!!.isChecked = currentServerSetting!!.jukeboxByDefault - // updateColor(currentServerSetting!!.color) + updateColor(currentServerSetting!!.color) } /** @@ -325,7 +322,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { if (isValid) { currentServerSetting!!.name = serverNameEditText!!.editText?.text.toString() currentServerSetting!!.url = serverAddressEditText!!.editText?.text.toString() - // currentServerSetting!!.color = selectedColor + currentServerSetting!!.color = selectedColor currentServerSetting!!.userName = userNameEditText!!.editText?.text.toString() currentServerSetting!!.password = passwordEditText!!.editText?.text.toString() currentServerSetting!!.allowSelfSignedCertificate = selfSignedSwitch!!.isChecked diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/ServerSettingsModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/ServerSettingsModel.kt index 9261c6c2..2f520617 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/ServerSettingsModel.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/model/ServerSettingsModel.kt @@ -212,6 +212,7 @@ class ServerSettingsModel( serverId, settings.getString(PREFERENCES_KEY_SERVER_NAME + preferenceId, "")!!, url, + null, userName, settings.getString(PREFERENCES_KEY_PASSWORD + preferenceId, "")!!, settings.getBoolean(PREFERENCES_KEY_JUKEBOX_BY_DEFAULT + preferenceId, false),