1
0
mirror of https://github.com/ultrasonic/ultrasonic synced 2025-02-16 19:50:35 +01:00

Merge pull request #599 from nitehu/navigation-servers

Moved server selector and settings to the Navigation menu
This commit is contained in:
Nite 2021-10-28 10:38:35 +02:00 committed by GitHub
commit ada780ab25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 402 additions and 316 deletions

View File

@ -1,5 +1,5 @@
ext.versions = [ ext.versions = [
minSdk : 17, minSdk : 21,
targetSdk : 29, targetSdk : 29,
compileSdk : 29, compileSdk : 29,
// You need to run ./gradlew wrapper after updating the version // You need to run ./gradlew wrapper after updating the version
@ -42,6 +42,7 @@ ext.versions = [
dexter : "6.2.3", dexter : "6.2.3",
timber : "4.7.1", timber : "4.7.1",
fastScroll : "2.0.1", fastScroll : "2.0.1",
colorPicker : "2.2.3",
] ]
ext.gradlePlugins = [ ext.gradlePlugins = [
@ -89,6 +90,7 @@ ext.other = [
timber : "com.jakewharton.timber:timber:$versions.timber", timber : "com.jakewharton.timber:timber:$versions.timber",
fastScroll : "com.simplecityapps:recyclerview-fastscroll:$versions.fastScroll", fastScroll : "com.simplecityapps:recyclerview-fastscroll:$versions.fastScroll",
sortListView : "com.github.tzugen:drag-sort-listview:$versions.sortListView", sortListView : "com.github.tzugen:drag-sort-listview:$versions.sortListView",
colorPickerView : "com.github.skydoves:colorpickerview:$versions.colorPicker",
] ]
ext.testing = [ ext.testing = [

View File

@ -49,7 +49,7 @@ android {
baselineFile file("lint-baseline.xml") baselineFile file("lint-baseline.xml")
ignore 'MissingTranslation' ignore 'MissingTranslation'
warning 'ImpliedQuantity' warning 'ImpliedQuantity'
disable 'IconMissingDensityFolder' disable 'IconMissingDensityFolder', "VectorPath"
abortOnError true abortOnError true
warningsAsErrors true warningsAsErrors true
} }
@ -105,6 +105,7 @@ dependencies {
implementation other.okhttpLogging implementation other.okhttpLogging
implementation other.fastScroll implementation other.fastScroll
implementation other.sortListView implementation other.sortListView
implementation other.colorPickerView
kapt androidSupport.room kapt androidSupport.room

View File

@ -55,7 +55,6 @@ import static org.moire.ultrasonic.fragment.ServerSelectorFragment.SERVER_SELECT
public class SettingsFragment extends PreferenceFragmentCompat public class SettingsFragment extends PreferenceFragmentCompat
implements SharedPreferences.OnSharedPreferenceChangeListener { implements SharedPreferences.OnSharedPreferenceChangeListener {
private Preference addServerPreference;
private ListPreference theme; private ListPreference theme;
private ListPreference maxBitrateWifi; private ListPreference maxBitrateWifi;
private ListPreference maxBitrateMobile; private ListPreference maxBitrateMobile;
@ -110,7 +109,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
FragmentTitle.Companion.setTitle(this, R.string.menu_settings); FragmentTitle.Companion.setTitle(this, R.string.menu_settings);
addServerPreference = findPreference(Constants.PREFERENCES_KEY_SERVERS_EDIT);
theme = findPreference(Constants.PREFERENCES_KEY_THEME); theme = findPreference(Constants.PREFERENCES_KEY_THEME);
maxBitrateWifi = findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI); maxBitrateWifi = findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI);
maxBitrateMobile = findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE); maxBitrateMobile = findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE);
@ -141,7 +139,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
debugLogToFile = findPreference(Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE); debugLogToFile = findPreference(Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE);
showArtistPicture = findPreference(Constants.PREFERENCES_KEY_SHOW_ARTIST_PICTURE); showArtistPicture = findPreference(Constants.PREFERENCES_KEY_SHOW_ARTIST_PICTURE);
setupServersCategory();
sharingDefaultGreeting.setText(Settings.getShareGreeting()); sharingDefaultGreeting.setText(Settings.getShareGreeting());
setupClearSearchPreference(); setupClearSearchPreference();
setupFeatureFlagsPreferences(); setupFeatureFlagsPreferences();
@ -374,22 +371,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
} }
private void setupServersCategory() {
addServerPreference.setPersistent(false);
addServerPreference.setTitle(getResources().getString(R.string.settings_server_manage_servers));
addServerPreference.setEnabled(true);
addServerPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Bundle bundle = new Bundle();
bundle.putBoolean(SERVER_SELECTOR_MANAGE_MODE, true);
Navigation.findNavController(getView()).navigate(R.id.settingsToServerSelector, bundle);
return true;
}
});
}
private void update() { private void update() {
theme.setSummary(theme.getEntry()); theme.setSummary(theme.getEntry());
maxBitrateWifi.setSummary(maxBitrateWifi.getEntry()); maxBitrateWifi.setSummary(maxBitrateWifi.getEntry());

View File

@ -3,6 +3,7 @@ package org.moire.ultrasonic.activity
import android.app.AlertDialog import android.app.AlertDialog
import android.app.SearchManager import android.app.SearchManager
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList
import android.content.res.Resources import android.content.res.Resources
import android.media.AudioManager import android.media.AudioManager
import android.os.Bundle import android.os.Bundle
@ -12,8 +13,10 @@ import android.view.KeyEvent
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.core.view.GravityCompat import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.FragmentContainerView import androidx.fragment.app.FragmentContainerView
@ -26,12 +29,13 @@ import androidx.navigation.ui.onNavDestinationSelected
import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.material.button.MaterialButton
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline import org.moire.ultrasonic.data.ServerSettingDao
import org.moire.ultrasonic.domain.PlayerState import org.moire.ultrasonic.domain.PlayerState
import org.moire.ultrasonic.fragment.OnBackPressedHandler import org.moire.ultrasonic.fragment.OnBackPressedHandler
import org.moire.ultrasonic.fragment.ServerSettingsModel import org.moire.ultrasonic.fragment.ServerSettingsModel
@ -45,6 +49,7 @@ import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.NowPlayingEventDistributor import org.moire.ultrasonic.util.NowPlayingEventDistributor
import org.moire.ultrasonic.util.NowPlayingEventListener import org.moire.ultrasonic.util.NowPlayingEventListener
import org.moire.ultrasonic.util.PermissionUtil import org.moire.ultrasonic.util.PermissionUtil
import org.moire.ultrasonic.util.ServerColor
import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.SubsonicUncaughtExceptionHandler import org.moire.ultrasonic.util.SubsonicUncaughtExceptionHandler
import org.moire.ultrasonic.util.ThemeChangedEventDistributor import org.moire.ultrasonic.util.ThemeChangedEventDistributor
@ -65,6 +70,8 @@ class NavigationActivity : AppCompatActivity() {
private var navigationView: NavigationView? = null private var navigationView: NavigationView? = null
private var drawerLayout: DrawerLayout? = null private var drawerLayout: DrawerLayout? = null
private var host: NavHostFragment? = null private var host: NavHostFragment? = null
private var selectServerButton: MaterialButton? = null
private var headerBackgroundImage: ImageView? = null
private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var nowPlayingEventListener: NowPlayingEventListener private lateinit var nowPlayingEventListener: NowPlayingEventListener
@ -77,9 +84,12 @@ class NavigationActivity : AppCompatActivity() {
private val nowPlayingEventDistributor: NowPlayingEventDistributor by inject() private val nowPlayingEventDistributor: NowPlayingEventDistributor by inject()
private val themeChangedEventDistributor: ThemeChangedEventDistributor by inject() private val themeChangedEventDistributor: ThemeChangedEventDistributor by inject()
private val permissionUtil: PermissionUtil by inject() private val permissionUtil: PermissionUtil by inject()
private val activeServerProvider: ActiveServerProvider by inject()
private val serverRepository: ServerSettingDao by inject()
private var infoDialogDisplayed = false private var infoDialogDisplayed = false
private var currentFragmentId: Int = 0 private var currentFragmentId: Int = 0
private var cachedServerCount: Int = 0
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setUncaughtExceptionHandler() setUncaughtExceptionHandler()
@ -141,7 +151,7 @@ class NavigationActivity : AppCompatActivity() {
} }
// Hides menu items for Offline mode // Hides menu items for Offline mode
setMenuForServerSetting() setMenuForServerCapabilities()
} }
// Determine first run and migrate server settings to DB as early as possible // Determine first run and migrate server settings to DB as early as possible
@ -180,12 +190,43 @@ class NavigationActivity : AppCompatActivity() {
nowPlayingEventDistributor.subscribe(nowPlayingEventListener) nowPlayingEventDistributor.subscribe(nowPlayingEventListener)
themeChangedEventDistributor.subscribe(themeChangedEventListener) themeChangedEventDistributor.subscribe(themeChangedEventListener)
serverRepository.liveServerCount().observe(
this,
{ count ->
cachedServerCount = count ?: 0
updateNavigationHeaderForServer()
}
)
ActiveServerProvider.liveActiveServerId.observe(this, { updateNavigationHeaderForServer() })
}
private fun updateNavigationHeaderForServer() {
val activeServer = activeServerProvider.getActiveServer()
if (cachedServerCount == 0)
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)
if (activeServer.index == 0)
selectServerButton?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_menu_screen_on_off_dark)
else
selectServerButton?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_menu_select_server_dark)
selectServerButton?.iconTint = ColorStateList.valueOf(foregroundColor)
selectServerButton?.setTextColor(foregroundColor)
headerBackgroundImage?.setBackgroundColor(backgroundColor)
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
setMenuForServerSetting() setMenuForServerCapabilities()
// Lifecycle support's constructor registers some event receivers so it should be created early // Lifecycle support's constructor registers some event receivers so it should be created early
lifecycleSupport.onCreate() lifecycleSupport.onCreate()
@ -233,6 +274,15 @@ class NavigationActivity : AppCompatActivity() {
bookmarksMenuItem = navigationView?.menu?.findItem(R.id.bookmarksFragment) bookmarksMenuItem = navigationView?.menu?.findItem(R.id.bookmarksFragment)
sharesMenuItem = navigationView?.menu?.findItem(R.id.sharesFragment) sharesMenuItem = navigationView?.menu?.findItem(R.id.sharesFragment)
podcastsMenuItem = navigationView?.menu?.findItem(R.id.podcastFragment) podcastsMenuItem = navigationView?.menu?.findItem(R.id.podcastFragment)
selectServerButton =
navigationView?.getHeaderView(0)?.findViewById(R.id.header_select_server)
selectServerButton?.setOnClickListener {
if (drawerLayout?.isDrawerVisible(GravityCompat.START) == true)
this.drawerLayout?.closeDrawer(GravityCompat.START)
navController.navigate(R.id.serverSelectorFragment)
}
headerBackgroundImage =
navigationView?.getHeaderView(0)?.findViewById(R.id.img_header_bg)
} }
private fun setupActionBar(navController: NavController, appBarConfig: AppBarConfiguration) { private fun setupActionBar(navController: NavController, appBarConfig: AppBarConfiguration) {
@ -325,7 +375,7 @@ class NavigationActivity : AppCompatActivity() {
.setNegativeButton(R.string.main_welcome_cancel) { dialog, _ -> .setNegativeButton(R.string.main_welcome_cancel) { dialog, _ ->
// Go to the settings screen // Go to the settings screen
dialog.dismiss() dialog.dismiss()
findNavController(R.id.nav_host_fragment).navigate(R.id.settingsFragment) findNavController(R.id.nav_host_fragment).navigate(R.id.serverSelectorFragment)
} }
.setPositiveButton(R.string.common_ok) { dialog, _ -> .setPositiveButton(R.string.common_ok) { dialog, _ ->
// Add the demo server // Add the demo server
@ -377,15 +427,14 @@ class NavigationActivity : AppCompatActivity() {
nowPlayingView?.visibility = View.GONE nowPlayingView?.visibility = View.GONE
} }
private fun setMenuForServerSetting() { private fun setMenuForServerCapabilities() {
if (isOffline()) { if (ActiveServerProvider.isOffline()) {
chatMenuItem?.isVisible = false chatMenuItem?.isVisible = false
bookmarksMenuItem?.isVisible = false bookmarksMenuItem?.isVisible = false
sharesMenuItem?.isVisible = false sharesMenuItem?.isVisible = false
podcastsMenuItem?.isVisible = false podcastsMenuItem?.isVisible = false
return return
} }
val activeServerProvider: ActiveServerProvider by inject()
val activeServer = activeServerProvider.getActiveServer() val activeServer = activeServerProvider.getActiveServer()
chatMenuItem?.isVisible = activeServer.chatSupport != false chatMenuItem?.isVisible = activeServer.chatSupport != false
bookmarksMenuItem?.isVisible = activeServer.bookmarkSupport != false bookmarksMenuItem?.isVisible = activeServer.bookmarkSupport != false

View File

@ -1,5 +1,6 @@
package org.moire.ultrasonic.data package org.moire.ultrasonic.data
import androidx.lifecycle.MutableLiveData
import androidx.room.Room import androidx.room.Room
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
@ -178,6 +179,7 @@ class ActiveServerProvider(
companion object { companion object {
const val METADATA_DB = "$DB_FILENAME-meta-" const val METADATA_DB = "$DB_FILENAME-meta-"
val liveActiveServerId: MutableLiveData<Int> = MutableLiveData(getActiveServerId())
/** /**
* Queries if the Active Server is the "Offline" mode of Ultrasonic * Queries if the Active Server is the "Offline" mode of Ultrasonic
@ -205,6 +207,8 @@ class ActiveServerProvider(
val editor = preferences.edit() val editor = preferences.edit()
editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, serverId) editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, serverId)
editor.apply() editor.apply()
liveActiveServerId.postValue(serverId)
} }
/** /**

View File

@ -9,7 +9,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase
* Room Database to be used to store global data for the whole app. * 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 * 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() { abstract class AppDatabase : RoomDatabase() {
/** /**
@ -42,3 +42,11 @@ val MIGRATION_2_3: Migration = object : Migration(2, 3) {
) )
} }
} }
val MIGRATION_3_4: Migration = object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"ALTER TABLE ServerSetting ADD COLUMN color INTEGER"
)
}
}

View File

@ -23,6 +23,7 @@ data class ServerSetting(
@ColumnInfo(name = "index") var index: Int, @ColumnInfo(name = "index") var index: Int,
@ColumnInfo(name = "name") var name: String, @ColumnInfo(name = "name") var name: String,
@ColumnInfo(name = "url") var url: String, @ColumnInfo(name = "url") var url: String,
@ColumnInfo(name = "color") var color: Int? = null,
@ColumnInfo(name = "userName") var userName: String, @ColumnInfo(name = "userName") var userName: String,
@ColumnInfo(name = "password") var password: String, @ColumnInfo(name = "password") var password: String,
@ColumnInfo(name = "jukeboxByDefault") var jukeboxByDefault: Boolean, @ColumnInfo(name = "jukeboxByDefault") var jukeboxByDefault: Boolean,
@ -36,9 +37,9 @@ data class ServerSetting(
@ColumnInfo(name = "podcastSupport") var podcastSupport: Boolean? = null @ColumnInfo(name = "podcastSupport") var podcastSupport: Boolean? = null
) { ) {
constructor() : this ( constructor() : this (
-1, 0, "", "", "", "", false, false, false, null, null -1, 0, "", "", null, "", "", false, false, false, null, null
) )
constructor(name: String, url: String) : this( 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
) )
} }

View File

@ -63,6 +63,12 @@ interface ServerSettingDao {
@Query("SELECT COUNT(*) FROM serverSetting") @Query("SELECT COUNT(*) FROM serverSetting")
suspend fun count(): Int? suspend fun count(): Int?
/**
* Retrieves the count of rows in the table as a LiveData
*/
@Query("SELECT COUNT(*) FROM serverSetting")
fun liveServerCount(): LiveData<Int?>
/** /**
* Retrieves the greatest value of the Id column in the table * Retrieves the greatest value of the Id column in the table
*/ */

View File

@ -8,6 +8,7 @@ import org.koin.dsl.module
import org.moire.ultrasonic.data.AppDatabase import org.moire.ultrasonic.data.AppDatabase
import org.moire.ultrasonic.data.MIGRATION_1_2 import org.moire.ultrasonic.data.MIGRATION_1_2
import org.moire.ultrasonic.data.MIGRATION_2_3 import org.moire.ultrasonic.data.MIGRATION_2_3
import org.moire.ultrasonic.data.MIGRATION_3_4
import org.moire.ultrasonic.fragment.ServerSettingsModel import org.moire.ultrasonic.fragment.ServerSettingsModel
import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Settings
@ -28,6 +29,7 @@ val appPermanentStorage = module {
) )
.addMigrations(MIGRATION_1_2) .addMigrations(MIGRATION_1_2)
.addMigrations(MIGRATION_2_3) .addMigrations(MIGRATION_2_3)
.addMigrations(MIGRATION_3_4)
.build() .build()
} }

View File

@ -14,7 +14,6 @@ import androidx.appcompat.widget.AppCompatEditText
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import java.io.File import java.io.File
import java.util.LinkedList import java.util.LinkedList
import kotlin.Comparator
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.util.Util
import timber.log.Timber import timber.log.Timber
@ -24,7 +23,8 @@ import timber.log.Timber
* @author this implementation is loosely based on the work of Yogesh Sundaresan, * @author this implementation is loosely based on the work of Yogesh Sundaresan,
* original license: http://www.apache.org/licenses/LICENSE-2.0 * original license: http://www.apache.org/licenses/LICENSE-2.0
*/ */
internal class FilePickerAdapter : RecyclerView.Adapter<FilePickerAdapter.FileListHolder> { internal class FilePickerAdapter(view: FilePickerView) :
RecyclerView.Adapter<FilePickerAdapter.FileListHolder>() {
private var data: MutableList<FileListItem> = LinkedList() private var data: MutableList<FileListItem> = LinkedList()
var defaultDirectory: File = Environment.getExternalStorageDirectory() var defaultDirectory: File = Environment.getExternalStorageDirectory()
@ -34,32 +34,15 @@ internal class FilePickerAdapter : RecyclerView.Adapter<FilePickerAdapter.FileLi
private set private set
private var context: Context? = null private var context: Context? = null
private var listerView: FilePickerView? = null private var listerView: FilePickerView? = view
private var isRealDirectory: Boolean = false private var isRealDirectory: Boolean = false
private val physicalPaths: Array<String>
get() = arrayOf(
"/storage/sdcard0", "/storage/sdcard1", "/storage/extsdcard",
"/storage/sdcard0/external_sdcard", "/mnt/extsdcard", "/mnt/sdcard/external_sd",
"/mnt/external_sd", "/mnt/media_rw/sdcard1", "/removable/microsd", "/mnt/emmc",
"/storage/external_SD", "/storage/ext_sd", "/storage/removable/sdcard1",
"/data/sdext", "/data/sdext2", "/data/sdext3", "/data/sdext4", "/sdcard1",
"/sdcard2", "/storage/microsd", "/data/user"
)
private var folderIcon: Drawable? = null private var folderIcon: Drawable? = null
private var upIcon: Drawable? = null private var upIcon: Drawable? = null
private var sdIcon: Drawable? = null private var sdIcon: Drawable? = null
constructor(defaultDir: File, view: FilePickerView) : this(view) { init {
this.defaultDirectory = defaultDir
selectedDirectory = defaultDir
}
constructor(view: FilePickerView) {
this.context = view.context this.context = view.context
listerView = view
upIcon = Util.getDrawableFromAttribute(context, R.attr.filepicker_subdirectory_up) upIcon = Util.getDrawableFromAttribute(context, R.attr.filepicker_subdirectory_up)
folderIcon = Util.getDrawableFromAttribute(context, R.attr.filepicker_folder) folderIcon = Util.getDrawableFromAttribute(context, R.attr.filepicker_folder)
sdIcon = Util.getDrawableFromAttribute(context, R.attr.filepicker_sd_card) sdIcon = Util.getDrawableFromAttribute(context, R.attr.filepicker_sd_card)
@ -71,12 +54,10 @@ internal class FilePickerAdapter : RecyclerView.Adapter<FilePickerAdapter.FileLi
private fun fileLister(currentDirectory: File) { private fun fileLister(currentDirectory: File) {
var fileList = LinkedList<FileListItem>() var fileList = LinkedList<FileListItem>()
var storages: List<File>? = null val storages: List<File>?
var storagePaths: List<String>? = null val storagePaths: List<String>?
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { storages = context!!.getExternalFilesDirs(null).filterNotNull()
storages = context!!.getExternalFilesDirs(null).filterNotNull() storagePaths = storages.map { i -> i.absolutePath }
storagePaths = storages.map { i -> i.absolutePath }
}
if (currentDirectory.absolutePath == "/" || if (currentDirectory.absolutePath == "/" ||
currentDirectory.absolutePath == "/storage" || currentDirectory.absolutePath == "/storage" ||
@ -84,13 +65,7 @@ internal class FilePickerAdapter : RecyclerView.Adapter<FilePickerAdapter.FileLi
currentDirectory.absolutePath == "/mnt" currentDirectory.absolutePath == "/mnt"
) { ) {
isRealDirectory = false isRealDirectory = false
fileList = if ( fileList = getKitKatStorageItems(storages)
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT
) {
getKitKatStorageItems(storages!!)
} else {
getStorageItems()
}
} else { } else {
isRealDirectory = true isRealDirectory = true
val files = currentDirectory.listFiles() val files = currentDirectory.listFiles()
@ -103,20 +78,18 @@ internal class FilePickerAdapter : RecyclerView.Adapter<FilePickerAdapter.FileLi
data = LinkedList(fileList) data = LinkedList(fileList)
data.sortWith( data.sortWith { f1, f2 ->
Comparator { f1, f2 -> if (f1.file!!.isDirectory && f2.file!!.isDirectory)
if (f1.file!!.isDirectory && f2.file!!.isDirectory) f1.name.compareTo(f2.name, ignoreCase = true)
f1.name.compareTo(f2.name, ignoreCase = true) else if (f1.file!!.isDirectory && !f2.file!!.isDirectory)
else if (f1.file!!.isDirectory && !f2.file!!.isDirectory) -1
-1 else if (!f1.file!!.isDirectory && f2.file!!.isDirectory)
else if (!f1.file!!.isDirectory && f2.file!!.isDirectory) 1
1 else if (!f1.file!!.isDirectory && !f2.file!!.isDirectory)
else if (!f1.file!!.isDirectory && !f2.file!!.isDirectory) f1.name.compareTo(f2.name, ignoreCase = true)
f1.name.compareTo(f2.name, ignoreCase = true) else
else 0
0 }
}
)
selectedDirectory = currentDirectory selectedDirectory = currentDirectory
selectedDirectoryChanged.invoke( selectedDirectoryChanged.invoke(
@ -129,47 +102,16 @@ internal class FilePickerAdapter : RecyclerView.Adapter<FilePickerAdapter.FileLi
if (currentDirectory.absolutePath != "/" && isRealDirectory) { if (currentDirectory.absolutePath != "/" && isRealDirectory) {
// If we are on KitKat or later, only the default App folder is usable, so we can't // If we are on KitKat or later, only the default App folder is usable, so we can't
// navigate the SD card. Jump to the root if "Up" is selected. // navigate the SD card. Jump to the root if "Up" is selected.
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { if (storagePaths.indexOf(currentDirectory.absolutePath) > 0)
if (storagePaths!!.indexOf(currentDirectory.absolutePath) > 0) data.add(0, FileListItem(File("/"), "..", upIcon!!))
data.add(0, FileListItem(File("/"), "..", upIcon!!)) else
else
data.add(0, FileListItem(selectedDirectory.parentFile!!, "..", upIcon!!))
} else {
data.add(0, FileListItem(selectedDirectory.parentFile!!, "..", upIcon!!)) data.add(0, FileListItem(selectedDirectory.parentFile!!, "..", upIcon!!))
}
} }
notifyDataSetChanged() notifyDataSetChanged()
listerView!!.scrollToPosition(0) listerView!!.scrollToPosition(0)
} }
private fun getStorageItems(): LinkedList<FileListItem> {
val fileList = LinkedList<FileListItem>()
var s = System.getenv("EXTERNAL_STORAGE")
if (!TextUtils.isEmpty(s)) {
val f = File(s!!)
fileList.add(FileListItem(f, f.name, sdIcon!!))
} else {
val paths = physicalPaths
for (path in paths) {
val f = File(path)
if (f.exists())
fileList.add(FileListItem(f, f.name, sdIcon!!))
}
}
s = System.getenv("SECONDARY_STORAGE")
if (s != null && !TextUtils.isEmpty(s)) {
val rawSecondaryStorages =
s.split(File.pathSeparator.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (path in rawSecondaryStorages) {
val f = File(path)
if (f.exists())
fileList.add(FileListItem(f, f.name, sdIcon!!))
}
}
return fileList
}
private fun getKitKatStorageItems(storages: List<File>): LinkedList<FileListItem> { private fun getKitKatStorageItems(storages: List<File>): LinkedList<FileListItem> {
val fileList = LinkedList<FileListItem>() val fileList = LinkedList<FileListItem>()
if (storages.isNotEmpty()) { if (storages.isNotEmpty()) {

View File

@ -6,11 +6,16 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import android.widget.ImageView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.android.material.switchmaterial.SwitchMaterial import com.google.android.material.switchmaterial.SwitchMaterial
import com.google.android.material.textfield.TextInputLayout 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.io.IOException
import java.net.MalformedURLException import java.net.MalformedURLException
import java.net.URL import java.net.URL
@ -32,10 +37,13 @@ import org.moire.ultrasonic.service.MusicServiceFactory
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.ErrorDialog import org.moire.ultrasonic.util.ErrorDialog
import org.moire.ultrasonic.util.ModalBackgroundTask import org.moire.ultrasonic.util.ModalBackgroundTask
import org.moire.ultrasonic.util.ServerColor
import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.util.Util
import retrofit2.Response import retrofit2.Response
import timber.log.Timber import timber.log.Timber
private const val DIALOG_PADDING = 12
/** /**
* Displays a form where server settings can be created / edited * Displays a form where server settings can be created / edited
*/ */
@ -51,6 +59,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
private var serverNameEditText: TextInputLayout? = null private var serverNameEditText: TextInputLayout? = null
private var serverAddressEditText: TextInputLayout? = null private var serverAddressEditText: TextInputLayout? = null
private var serverColorImageView: ImageView? = null
private var userNameEditText: TextInputLayout? = null private var userNameEditText: TextInputLayout? = null
private var passwordEditText: TextInputLayout? = null private var passwordEditText: TextInputLayout? = null
private var selfSignedSwitch: SwitchMaterial? = null private var selfSignedSwitch: SwitchMaterial? = null
@ -59,6 +68,8 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
private var saveButton: Button? = null private var saveButton: Button? = null
private var testButton: Button? = null private var testButton: Button? = null
private var isInstanceStateSaved: Boolean = false private var isInstanceStateSaved: Boolean = false
private var currentColor: Int = 0
private var selectedColor: Int? = null
@Override @Override
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -79,6 +90,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
serverNameEditText = view.findViewById(R.id.edit_server_name) serverNameEditText = view.findViewById(R.id.edit_server_name)
serverAddressEditText = view.findViewById(R.id.edit_server_address) serverAddressEditText = view.findViewById(R.id.edit_server_address)
serverColorImageView = view.findViewById(R.id.edit_server_color_picker)
userNameEditText = view.findViewById(R.id.edit_server_username) userNameEditText = view.findViewById(R.id.edit_server_username)
passwordEditText = view.findViewById(R.id.edit_server_password) passwordEditText = view.findViewById(R.id.edit_server_password)
selfSignedSwitch = view.findViewById(R.id.edit_self_signed) selfSignedSwitch = view.findViewById(R.id.edit_self_signed)
@ -98,7 +110,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
val serverSetting = serverSettingsModel.getServerSetting(index) val serverSetting = serverSettingsModel.getServerSetting(index)
serverSetting.observe( serverSetting.observe(
viewLifecycleOwner, viewLifecycleOwner,
Observer { t -> { t ->
if (t != null) { if (t != null) {
currentServerSetting = t currentServerSetting = t
if (!isInstanceStateSaved) setFields() if (!isInstanceStateSaved) setFields()
@ -134,6 +146,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
} else { } else {
// Creating a new server // Creating a new server
FragmentTitle.setTitle(this, R.string.server_editor_new_label) FragmentTitle.setTitle(this, R.string.server_editor_new_label)
updateColor(null)
currentServerSetting = ServerSetting() currentServerSetting = ServerSetting()
saveButton!!.setOnClickListener { saveButton!!.setOnClickListener {
if (getFields()) { if (getFields()) {
@ -148,6 +161,36 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
testConnection() testConnection()
} }
} }
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, i ->
dialogInterface.dismiss()
}
.setBottomSpace(DIALOG_PADDING)
.show()
}
}
private fun updateColor(color: Int?) {
val image = ContextCompat.getDrawable(requireContext(), R.drawable.thumb_drawable)
currentColor = ServerColor.getBackgroundColor(requireContext(), color)
image?.setTint(currentColor)
serverColorImageView?.background = image
} }
override fun onBackPressed() { override fun onBackPressed() {
@ -176,6 +219,13 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
savedInstanceState.putBoolean( savedInstanceState.putBoolean(
::jukeboxSwitch.name, jukeboxSwitch!!.isChecked ::jukeboxSwitch.name, jukeboxSwitch!!.isChecked
) )
savedInstanceState.putInt(
::serverColorImageView.name, currentColor
)
if (selectedColor != null)
savedInstanceState.putInt(
::selectedColor.name, selectedColor!!
)
savedInstanceState.putBoolean( savedInstanceState.putBoolean(
::isInstanceStateSaved.name, true ::isInstanceStateSaved.name, true
) )
@ -203,6 +253,9 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
selfSignedSwitch!!.isChecked = savedInstanceState.getBoolean(::selfSignedSwitch.name) selfSignedSwitch!!.isChecked = savedInstanceState.getBoolean(::selfSignedSwitch.name)
ldapSwitch!!.isChecked = savedInstanceState.getBoolean(::ldapSwitch.name) ldapSwitch!!.isChecked = savedInstanceState.getBoolean(::ldapSwitch.name)
jukeboxSwitch!!.isChecked = savedInstanceState.getBoolean(::jukeboxSwitch.name) jukeboxSwitch!!.isChecked = savedInstanceState.getBoolean(::jukeboxSwitch.name)
updateColor(savedInstanceState.getInt(::serverColorImageView.name))
if (savedInstanceState.containsKey(::selectedColor.name))
selectedColor = savedInstanceState.getInt(::selectedColor.name)
isInstanceStateSaved = savedInstanceState.getBoolean(::isInstanceStateSaved.name) isInstanceStateSaved = savedInstanceState.getBoolean(::isInstanceStateSaved.name)
} }
@ -219,6 +272,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
selfSignedSwitch!!.isChecked = currentServerSetting!!.allowSelfSignedCertificate selfSignedSwitch!!.isChecked = currentServerSetting!!.allowSelfSignedCertificate
ldapSwitch!!.isChecked = currentServerSetting!!.ldapSupport ldapSwitch!!.isChecked = currentServerSetting!!.ldapSupport
jukeboxSwitch!!.isChecked = currentServerSetting!!.jukeboxByDefault jukeboxSwitch!!.isChecked = currentServerSetting!!.jukeboxByDefault
updateColor(currentServerSetting!!.color)
} }
/** /**
@ -267,6 +321,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
if (isValid) { if (isValid) {
currentServerSetting!!.name = serverNameEditText!!.editText?.text.toString() currentServerSetting!!.name = serverNameEditText!!.editText?.text.toString()
currentServerSetting!!.url = serverAddressEditText!!.editText?.text.toString() currentServerSetting!!.url = serverAddressEditText!!.editText?.text.toString()
currentServerSetting!!.color = selectedColor
currentServerSetting!!.userName = userNameEditText!!.editText?.text.toString() currentServerSetting!!.userName = userNameEditText!!.editText?.text.toString()
currentServerSetting!!.password = passwordEditText!!.editText?.text.toString() currentServerSetting!!.password = passwordEditText!!.editText?.text.toString()
currentServerSetting!!.allowSelfSignedCertificate = selfSignedSwitch!!.isChecked currentServerSetting!!.allowSelfSignedCertificate = selfSignedSwitch!!.isChecked

View File

@ -7,14 +7,10 @@ import android.view.ViewGroup
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import android.widget.ListView import android.widget.ListView
import android.widget.TextView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.Navigation import androidx.navigation.Navigation
import java.util.Locale
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.MergeAdapter import org.moire.ultrasonic.util.MergeAdapter
@ -27,8 +23,6 @@ import org.moire.ultrasonic.util.Util
class MainFragment : Fragment(), KoinComponent { class MainFragment : Fragment(), KoinComponent {
private var list: ListView? = null private var list: ListView? = null
private lateinit var serverButton: View
private lateinit var serverTextView: TextView
private lateinit var musicTitle: View private lateinit var musicTitle: View
private lateinit var artistsButton: View private lateinit var artistsButton: View
private lateinit var albumsButton: View private lateinit var albumsButton: View
@ -48,8 +42,6 @@ class MainFragment : Fragment(), KoinComponent {
private lateinit var albumsAlphaByArtistButton: View private lateinit var albumsAlphaByArtistButton: View
private lateinit var videosButton: View private lateinit var videosButton: View
private val activeServerProvider: ActiveServerProvider by inject()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Util.applyTheme(this.context) Util.applyTheme(this.context)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -65,7 +57,6 @@ class MainFragment : Fragment(), KoinComponent {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
list = view.findViewById(R.id.main_list) list = view.findViewById(R.id.main_list)
cachedActiveServerProperties = getActiveServerProperties()
setupButtons() setupButtons()
@ -78,7 +69,6 @@ class MainFragment : Fragment(), KoinComponent {
super.onResume() super.onResume()
var shouldRestart = false var shouldRestart = false
val currentId3Setting = Settings.shouldUseId3Tags val currentId3Setting = Settings.shouldUseId3Tags
val currentActiveServerProperties = getActiveServerProperties()
// If setting has changed... // If setting has changed...
if (currentId3Setting != shouldUseId3) { if (currentId3Setting != shouldUseId3) {
@ -86,12 +76,6 @@ class MainFragment : Fragment(), KoinComponent {
shouldRestart = true shouldRestart = true
} }
// or the server has changed...
if (currentActiveServerProperties != cachedActiveServerProperties) {
cachedActiveServerProperties = currentActiveServerProperties
shouldRestart = true
}
// then setup the list anew. // then setup the list anew.
if (shouldRestart) { if (shouldRestart) {
if (list != null) setupMenuList(list!!) if (list != null) setupMenuList(list!!)
@ -100,8 +84,6 @@ class MainFragment : Fragment(), KoinComponent {
private fun setupButtons() { private fun setupButtons() {
val buttons = layoutInflater.inflate(R.layout.main_buttons, list, false) val buttons = layoutInflater.inflate(R.layout.main_buttons, list, false)
serverButton = buttons.findViewById(R.id.main_select_server)
serverTextView = serverButton.findViewById(R.id.main_select_server_2)
musicTitle = buttons.findViewById(R.id.main_music) musicTitle = buttons.findViewById(R.id.main_music)
artistsButton = buttons.findViewById(R.id.main_artists_button) artistsButton = buttons.findViewById(R.id.main_artists_button)
albumsButton = buttons.findViewById(R.id.main_albums_button) albumsButton = buttons.findViewById(R.id.main_albums_button)
@ -123,15 +105,10 @@ class MainFragment : Fragment(), KoinComponent {
} }
private fun setupMenuList(list: ListView) { private fun setupMenuList(list: ListView) {
// Set title
val activeServerName = activeServerProvider.getActiveServer().name
serverTextView.text = activeServerName
// TODO: Should use RecyclerView // TODO: Should use RecyclerView
val adapter = MergeAdapter() val adapter = MergeAdapter()
adapter.addView(serverButton, true)
shouldUseId3 = Settings.shouldUseId3Tags shouldUseId3 = Settings.shouldUseId3Tags
if (!isOffline()) { if (!isOffline()) {
@ -177,9 +154,6 @@ class MainFragment : Fragment(), KoinComponent {
private val listListener = private val listListener =
OnItemClickListener { _: AdapterView<*>?, view: View, _: Int, _: Long -> OnItemClickListener { _: AdapterView<*>?, view: View, _: Int, _: Long ->
when { when {
view === serverButton -> {
showServers()
}
view === albumsNewestButton -> { view === albumsNewestButton -> {
showAlbumList("newest", R.string.main_albums_newest) showAlbumList("newest", R.string.main_albums_newest)
} }
@ -225,20 +199,6 @@ class MainFragment : Fragment(), KoinComponent {
} }
} }
private fun getActiveServerProperties(): String {
val server = activeServerProvider.getActiveServer()
return String.format(
Locale.ROOT,
"%s;%s;%s;%s;%s;%s",
server.url,
server.userName,
server.password,
server.allowSelfSignedCertificate,
server.ldapSupport,
server.minimumApiVersion
)
}
private fun showStarredSongs() { private fun showStarredSongs() {
val bundle = Bundle() val bundle = Bundle()
bundle.putInt(Constants.INTENT_EXTRA_NAME_STARRED, 1) bundle.putInt(Constants.INTENT_EXTRA_NAME_STARRED, 1)
@ -281,12 +241,7 @@ class MainFragment : Fragment(), KoinComponent {
Navigation.findNavController(requireView()).navigate(R.id.mainToTrackCollection, bundle) Navigation.findNavController(requireView()).navigate(R.id.mainToTrackCollection, bundle)
} }
private fun showServers() {
Navigation.findNavController(requireView()).navigate(R.id.mainToServerSelector)
}
companion object { companion object {
private var shouldUseId3 = false private var shouldUseId3 = false
private var cachedActiveServerProperties: String? = null
} }
} }

View File

@ -2,6 +2,7 @@ package org.moire.ultrasonic.fragment
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.Build import android.os.Build
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
@ -12,12 +13,13 @@ import android.widget.BaseAdapter
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import android.widget.PopupMenu import android.widget.PopupMenu
import android.widget.RelativeLayout
import android.widget.TextView import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.data.ServerSetting import org.moire.ultrasonic.data.ServerSetting
import org.moire.ultrasonic.util.ServerColor
import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.util.Util
/** /**
@ -67,8 +69,10 @@ internal class ServerRowAdapter(
/** /**
* Creates the Row representation of a Server Setting * Creates the Row representation of a Server Setting
*/ */
@Suppress("LongMethod")
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? { override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
var index = position var index = position
// Skip "Offline" in manage mode // Skip "Offline" in manage mode
if (manageMode) index++ if (manageMode) index++
@ -77,28 +81,43 @@ internal class ServerRowAdapter(
val text = vi?.findViewById<TextView>(R.id.server_name) val text = vi?.findViewById<TextView>(R.id.server_name)
val description = vi?.findViewById<TextView>(R.id.server_description) val description = vi?.findViewById<TextView>(R.id.server_description)
val layout = vi?.findViewById<RelativeLayout>(R.id.server_layout) val layout = vi?.findViewById<ConstraintLayout>(R.id.server_layout)
val image = vi?.findViewById<ImageView>(R.id.server_image) val image = vi?.findViewById<ImageView>(R.id.server_image)
val serverMenu = vi?.findViewById<ImageButton>(R.id.server_menu) val serverMenu = vi?.findViewById<ImageButton>(R.id.server_menu)
val setting = data.singleOrNull { t -> t.index == index }
if (index == 0) { if (index == 0) {
text?.text = context.getString(R.string.main_offline) text?.text = context.getString(R.string.main_offline)
description?.text = "" description?.text = ""
} else { } else {
val setting = data.singleOrNull { t -> t.index == index }
text?.text = setting?.name ?: "" text?.text = setting?.name ?: ""
description?.text = setting?.url ?: "" description?.text = setting?.url ?: ""
if (setting == null) serverMenu?.visibility = View.INVISIBLE if (setting == null) serverMenu?.visibility = View.INVISIBLE
} }
// Provide icons for the row val icon: Drawable?
val background: Drawable?
// Configure icons for the row
if (index == 0) { if (index == 0) {
serverMenu?.visibility = View.INVISIBLE serverMenu?.visibility = View.INVISIBLE
image?.setImageDrawable(Util.getDrawableFromAttribute(context, R.attr.screen_on_off)) icon = Util.getDrawableFromAttribute(context, R.attr.screen_on_off)
background = ContextCompat.getDrawable(context, R.drawable.circle)
} else { } else {
image?.setImageDrawable(Util.getDrawableFromAttribute(context, R.attr.server)) icon = ContextCompat.getDrawable(context, R.drawable.ic_menu_server_dark)
background = ContextCompat.getDrawable(context, R.drawable.circle)
} }
// Set colors
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
icon?.setTint(ServerColor.getForegroundColor(context, setting?.color))
background?.setTint(ServerColor.getBackgroundColor(context, setting?.color))
}
// Set the final drawables
image?.setImageDrawable(icon)
image?.background = background
// Highlight the Active Server's row by changing its background // Highlight the Active Server's row by changing its background
if (index == activeServerProvider.getActiveServer().index) { if (index == activeServerProvider.getActiveServer().index) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

View File

@ -88,7 +88,7 @@ class ServerSelectorFragment : Fragment() {
editServer(position + 1) editServer(position + 1)
} else { } else {
setActiveServer(position) setActiveServer(position)
findNavController().navigateUp() findNavController().popBackStack(R.id.mainFragment, false)
} }
} }

View File

@ -212,6 +212,7 @@ class ServerSettingsModel(
serverId, serverId,
settings.getString(PREFERENCES_KEY_SERVER_NAME + preferenceId, "")!!, settings.getString(PREFERENCES_KEY_SERVER_NAME + preferenceId, "")!!,
url, url,
null,
userName, userName,
settings.getString(PREFERENCES_KEY_PASSWORD + preferenceId, "")!!, settings.getString(PREFERENCES_KEY_PASSWORD + preferenceId, "")!!,
settings.getBoolean(PREFERENCES_KEY_JUKEBOX_BY_DEFAULT + preferenceId, false), settings.getBoolean(PREFERENCES_KEY_JUKEBOX_BY_DEFAULT + preferenceId, false),

View File

@ -65,10 +65,6 @@ class BitmapUtils {
opt.inPreferQualityOverSpeed = true opt.inPreferQualityOverSpeed = true
} }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
opt.inPurgeable = true
}
opt.inSampleSize = Util.calculateInSampleSize( opt.inSampleSize = Util.calculateInSampleSize(
opt, opt,
size, size,
@ -103,10 +99,6 @@ class BitmapUtils {
opt.inPreferQualityOverSpeed = true opt.inPreferQualityOverSpeed = true
} }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
opt.inPurgeable = true
}
opt.inSampleSize = Util.calculateInSampleSize( opt.inSampleSize = Util.calculateInSampleSize(
opt, opt,
size, size,

View File

@ -54,7 +54,6 @@ object Constants {
// Preferences keys. // Preferences keys.
const val PREFERENCES_KEY_SERVER_INSTANCE = "serverInstanceId" const val PREFERENCES_KEY_SERVER_INSTANCE = "serverInstanceId"
const val PREFERENCES_KEY_SERVERS_EDIT = "editServers"
const val PREFERENCES_KEY_THEME = "theme" const val PREFERENCES_KEY_THEME = "theme"
const val PREFERENCES_KEY_THEME_LIGHT = "light" const val PREFERENCES_KEY_THEME_LIGHT = "light"
const val PREFERENCES_KEY_THEME_DARK = "dark" const val PREFERENCES_KEY_THEME_DARK = "dark"

View File

@ -0,0 +1,36 @@
/*
* ServerColor.kt
* Copyright (C) 2009-2021 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.util
import android.content.Context
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import org.moire.ultrasonic.R
private const val LUMINANCE_LIMIT = 0.5
/**
* Contains functions for computing server display colors
*/
object ServerColor {
fun getBackgroundColor(context: Context, serverColor: Int?): Int {
return serverColor ?: ContextCompat.getColor(
context, Util.getResourceFromAttribute(context, R.attr.colorPrimary)
)
}
fun getForegroundColor(context: Context, serverColor: Int?): Int {
val backgroundColor = getBackgroundColor(context, serverColor)
val luminance = ColorUtils.calculateLuminance(backgroundColor)
return if (luminance < LUMINANCE_LIMIT) {
ContextCompat.getColor(context, R.color.selected_menu_dark)
} else {
ContextCompat.getColor(context, R.color.selected_menu_light)
}
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/navigation_header_dark" />
<size
android:width="120dp"
android:height="120dp"/>
</shape>

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="192dp"
android:height="96dp"
android:viewportWidth="67.733"
android:viewportHeight="33.867">
<path
android:fillColor="#FF000000"
android:pathData="m28.575,0h39.158v33.867h-67.733z"
android:strokeAlpha="0.26667"
android:strokeWidth="3.7213"
android:fillAlpha="0.1"/>
<path
android:fillColor="#FF000000"
android:pathData="m39.158,33.87h-39.158v-33.867h67.733z"
android:strokeAlpha="0.26667"
android:strokeWidth="3.7213"
android:fillAlpha="0.1"/>
<path
android:fillColor="#FF000000"
android:pathData="m19.579,33.87h-19.579v-33.867h33.867z"
android:strokeAlpha="0.26667"
android:strokeWidth="2.6313"
android:fillAlpha="0.15"/>
<path
android:fillColor="#FF000000"
android:pathData="m48.154,0h19.579v33.867h-33.867z"
android:strokeAlpha="0.26667"
android:strokeWidth="2.6313"
android:fillAlpha="0.05"/>
</vector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:topLeftRadius="44dp"
android:topRightRadius="44dp"
android:bottomRightRadius="44dp"
android:bottomLeftRadius="44dp" />
<stroke android:width="2dp" android:color="?attr/colorOnBackground" />
</shape>

View File

@ -2,38 +2,6 @@
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
a:orientation="vertical" a:layout_width="fill_parent" a:layout_height="fill_parent"> a:orientation="vertical" a:layout_width="fill_parent" a:layout_height="fill_parent">
<LinearLayout a:id="@+id/main_select_server"
a:orientation="horizontal" a:paddingTop="2dip" a:paddingBottom="2dip"
a:paddingStart="10dp" a:layout_width="fill_parent" a:layout_height="wrap_content"
a:minHeight="?android:attr/listPreferredItemHeight">
<ImageView a:layout_width="wrap_content" a:layout_height="wrap_content"
a:layout_gravity="center_vertical" a:src="?attr/select_server" />
<LinearLayout
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:orientation="vertical">
<TextView
a:id="@+id/main.select_server_1"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_marginStart="10dip"
a:layout_marginTop="6dip"
a:text="@string/main.select_server"
a:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
a:id="@+id/main.select_server_2"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_marginStart="10dip"
a:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</LinearLayout>
<TextView a:id="@+id/main_music" a:text="@string/main.music" <TextView a:id="@+id/main_music" a:text="@string/main.music"
a:layout_width="fill_parent" a:layout_height="wrap_content" a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceSmall" a:textColor="@color/cyan" a:textAppearance="?android:attr/textAppearanceSmall" a:textColor="@color/cyan"

View File

@ -1,40 +1,46 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout
xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
a:id="@+id/view_container" a:id="@+id/view_container"
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="96dp" a:layout_height="wrap_content"
a:gravity="bottom" a:gravity="bottom"
a:orientation="vertical" a:orientation="vertical">
a:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView <ImageView
a:id="@+id/img_header_bg" a:id="@+id/img_header_bg"
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="match_parent" a:layout_height="0dp"
a:scaleType="fitXY" a:scaleType="fitXY"
a:src="@drawable/ic_launcher_background" /> a:src="@drawable/ic_header_bg"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
a:importantForAccessibility="no" />
<LinearLayout <Button
a:layout_width="wrap_content" a:id="@+id/header_select_server"
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
a:layout_width="match_parent"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:layout_centerVertical="true" a:layout_marginTop="0dp"
a:orientation="horizontal" a:background="@drawable/default_ripple"
a:padding="16dp"> a:gravity="center_vertical"
a:paddingHorizontal="22dp"
a:paddingTop="16dp"
a:paddingBottom="16dp"
a:text="@string/main.offline"
a:textAppearance="@style/MenuDrawer.Widget"
a:textColor="?attr/colorOnPrimary"
a:textSize="17sp"
a:textStyle="bold"
app:icon="@drawable/ic_menu_select_server_dark"
app:iconPadding="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:iconTint="@color/selected_menu_dark"
tools:textColor="@color/selected_menu_dark" />
<ImageView </androidx.constraintlayout.widget.ConstraintLayout>
a:id="@+id/img_profile"
a:layout_width="52dp"
a:layout_height="52dp"
a:src="@drawable/ic_stat_ultrasonic" />
<TextView
a:id="@+id/name"
a:layout_width="wrap_content"
a:layout_height="match_parent"
a:gravity="center_vertical"
a:paddingStart="16dp"
a:text="@string/common.appname"
a:textAppearance="@style/TextAppearance.AppCompat.Title" />
</LinearLayout>
</RelativeLayout>

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:a="http://schemas.android.com/apk/res/android" <ScrollView xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="match_parent" a:layout_height="match_parent"
a:fillViewport="true" > a:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
a:layout_width="match_parent" a:layout_width="match_parent"
@ -14,7 +15,6 @@
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:hint="@string/settings.server_name" a:hint="@string/settings.server_name"
app:layout_constraintBottom_toTopOf="@id/edit_server_address"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
@ -33,7 +33,6 @@
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:layout_marginBottom="20dp" a:layout_marginBottom="20dp"
a:hint="@string/settings.server_address" a:hint="@string/settings.server_address"
app:layout_constraintBottom_toTopOf="@id/edit_authentication_header"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/edit_server_name"> app:layout_constraintTop_toBottomOf="@id/edit_server_name">
@ -46,15 +45,38 @@
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<TextView
a:id="@+id/edit_server_color_text"
style="@style/Widget.AppCompat.CompoundButton.Switch"
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_marginStart="5dp"
a:layout_marginLeft="5dp"
a:text="@string/settings.server_color"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/edit_server_color_picker"
app:layout_constraintBottom_toBottomOf="@id/edit_server_color_picker"/>
<ImageView
a:id="@+id/edit_server_color_picker"
a:layout_width="48dp"
a:layout_height="32dp"
a:layout_margin="8dp"
a:src="@drawable/rounded_border"
app:layout_constraintTop_toBottomOf="@id/edit_server_address"
app:layout_constraintRight_toRightOf="parent"
tools:ignore="ContentDescription" />
<TextView <TextView
a:id="@+id/edit_authentication_header" a:id="@+id/edit_authentication_header"
style="@style/MenuDrawer.Widget.Category" style="@style/MenuDrawer.Widget.Category"
a:layout_width="wrap_content" a:layout_width="wrap_content"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:layout_marginTop="15dp"
a:text="@string/server_editor.authentication" a:text="@string/server_editor.authentication"
app:layout_constraintBottom_toTopOf="@id/edit_server_username" app:layout_constraintBottom_toTopOf="@id/edit_server_username"
app:layout_constraintStart_toStartOf="@id/edit_server_username" app:layout_constraintStart_toStartOf="@id/edit_server_username"
app:layout_constraintTop_toBottomOf="@id/edit_server_address" /> app:layout_constraintTop_toBottomOf="@id/edit_server_color_picker" />
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
a:id="@+id/edit_server_username" a:id="@+id/edit_server_username"

View File

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout
xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
a:id="@+id/server_layout" a:id="@+id/server_layout"
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="wrap_content" a:layout_height="wrap_content"
@ -8,42 +11,58 @@
<ImageView <ImageView
a:id="@+id/server_image" a:id="@+id/server_image"
a:layout_width="wrap_content" a:layout_width="48dp"
a:layout_height="match_parent" a:layout_height="48dp"
a:background="@android:color/transparent"
a:focusable="false"
a:layout_centerVertical="true" a:layout_centerVertical="true"
a:paddingHorizontal="15dp" /> a:layout_margin="10dp"
a:background="@drawable/circle"
a:focusable="false"
a:paddingHorizontal="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_menu_server_dark"
a:importantForAccessibility="no" />
<TextView <TextView
a:id="@+id/server_name" a:id="@+id/server_name"
a:layout_width="wrap_content" a:layout_width="0dp"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:layout_marginStart="15dp"
a:textAppearance="?android:attr/textAppearanceListItem" a:textAppearance="?android:attr/textAppearanceListItem"
a:paddingTop="10dp" app:layout_constraintStart_toEndOf="@id/server_image"
a:layout_toEndOf="@id/server_image" /> app:layout_constraintTop_toTopOf="@id/server_image"
app:layout_constraintEnd_toStartOf="@id/server_menu"
tools:text="Server name" />
<TextView <TextView
a:id="@+id/server_description" a:id="@+id/server_description"
a:layout_width="wrap_content" a:layout_width="0dp"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:layout_marginStart="15dp"
a:textAppearance="?android:attr/textAppearanceSmall" a:textAppearance="?android:attr/textAppearanceSmall"
a:layout_below="@id/server_name" app:layout_constraintBottom_toBottomOf="@id/server_image"
a:paddingBottom="10dp" app:layout_constraintStart_toEndOf="@id/server_image"
a:layout_toEndOf="@id/server_image" /> app:layout_constraintTop_toBottomOf="@id/server_name"
app:layout_constraintEnd_toStartOf="@id/server_menu"
tools:text="Server description" />
<ImageButton <ImageButton
a:id="@+id/server_menu" a:id="@+id/server_menu"
a:layout_width="wrap_content" a:layout_width="wrap_content"
a:layout_height="match_parent" a:layout_height="wrap_content"
a:layout_alignParentEnd="true" a:layout_alignParentEnd="true"
a:layout_alignParentRight="true" a:layout_alignParentRight="true"
a:layout_centerVertical="true" a:layout_centerVertical="true"
a:layout_gravity="end" a:layout_gravity="end"
a:layout_marginEnd="15dp" a:layout_marginEnd="15dp"
a:contentDescription="@string/server_editor.advanced"
a:focusable="false" a:focusable="false"
a:src="?attr/more_vert" a:src="?attr/more_vert"
tools:src="@drawable/ic_more_vert_dark"
app:layout_constraintTop_toTopOf="@id/server_name"
app:layout_constraintBottom_toBottomOf="@+id/server_description"
app:layout_constraintEnd_toEndOf="parent"
a:padding="5dp" /> a:padding="5dp" />
</RelativeLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -7,18 +7,18 @@
<ListView <ListView
a:id="@+id/server_list" a:id="@+id/server_list"
a:layout_width="fill_parent" a:layout_width="fill_parent"
a:layout_height="fill_parent" /> a:layout_height="fill_parent"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
a:id="@+id/server_add_fab" a:id="@+id/server_add_fab"
a:layout_width="wrap_content" a:layout_width="wrap_content"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:layout_alignRight="@id/server_list"
a:layout_alignEnd="@id/server_list" a:layout_alignEnd="@id/server_list"
a:layout_alignBottom="@id/server_list" a:layout_alignBottom="@id/server_list"
a:layout_margin="16dp" a:layout_margin="16dp"
a:clickable="true" a:clickable="true"
a:focusable="true" a:focusable="true"
a:src="@drawable/ic_add_white" /> a:src="@drawable/ic_add_white"
a:contentDescription="@string/server_editor.new_label" />
</RelativeLayout> </RelativeLayout>

View File

@ -4,8 +4,7 @@
a:layout_width="fill_parent" a:layout_width="fill_parent"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:minHeight="?android:attr/listPreferredItemHeight" a:minHeight="?android:attr/listPreferredItemHeight"
a:orientation="horizontal" a:orientation="horizontal">
a:background="?attr/color_menu_background">
<ImageView <ImageView
a:id="@+id/song_drag" a:id="@+id/song_drag"

View File

@ -19,9 +19,6 @@
<action <action
android:id="@+id/mainToSelectGenre" android:id="@+id/mainToSelectGenre"
app:destination="@id/selectGenreFragment" /> app:destination="@id/selectGenreFragment" />
<action
android:id="@+id/mainToServerSelector"
app:destination="@id/serverSelectorFragment" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/mediaLibraryFragment" android:id="@+id/mediaLibraryFragment"
@ -86,9 +83,6 @@
<fragment <fragment
android:id="@+id/settingsFragment" android:id="@+id/settingsFragment"
android:name="org.moire.ultrasonic.fragment.SettingsFragment" > android:name="org.moire.ultrasonic.fragment.SettingsFragment" >
<action
android:id="@+id/settingsToServerSelector"
app:destination="@id/serverSelectorFragment" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/aboutFragment" android:id="@+id/aboutFragment"

View File

@ -95,7 +95,6 @@
<string name="main.genres_title">Žánry</string> <string name="main.genres_title">Žánry</string>
<string name="main.music">Hudba</string> <string name="main.music">Hudba</string>
<string name="main.offline">Bez připojení</string> <string name="main.offline">Bez připojení</string>
<string name="main.select_server">Vybrat server</string>
<string name="main.shuffle">Náhodné přehrávání</string> <string name="main.shuffle">Náhodné přehrávání</string>
<string name="main.songs_random">Náhodné</string> <string name="main.songs_random">Náhodné</string>
<string name="main.songs_starred">Označené hvězdičkou</string> <string name="main.songs_starred">Označené hvězdičkou</string>
@ -277,7 +276,6 @@
<string name="settings.server_scaling_title">Škálování obrázků alb na serveru</string> <string name="settings.server_scaling_title">Škálování obrázků alb na serveru</string>
<string name="settings.server_unused">Nepoužitý</string> <string name="settings.server_unused">Nepoužitý</string>
<string name="settings.server_username">Uživatelské jméno</string> <string name="settings.server_username">Uživatelské jméno</string>
<string name="settings.servers_title">Servery</string>
<string name="settings.show_lockscreen_controls">Zobrazit ovládání na zamknuté obrazovce</string> <string name="settings.show_lockscreen_controls">Zobrazit ovládání na zamknuté obrazovce</string>
<string name="settings.show_lockscreen_controls_summary">Zobrazí ovládání přehrávače na zamknuté obrazovce</string> <string name="settings.show_lockscreen_controls_summary">Zobrazí ovládání přehrávače na zamknuté obrazovce</string>
<string name="settings.show_notification">Zobrazení upozornění</string> <string name="settings.show_notification">Zobrazení upozornění</string>

View File

@ -94,7 +94,6 @@
<string name="main.genres_title">Genres</string> <string name="main.genres_title">Genres</string>
<string name="main.music">Musik</string> <string name="main.music">Musik</string>
<string name="main.offline">Offline</string> <string name="main.offline">Offline</string>
<string name="main.select_server">Server wählen</string>
<string name="main.shuffle">Gemischte Wiedergabe</string> <string name="main.shuffle">Gemischte Wiedergabe</string>
<string name="main.songs_random">Zufällig</string> <string name="main.songs_random">Zufällig</string>
<string name="main.songs_starred">Mit Stern</string> <string name="main.songs_starred">Mit Stern</string>
@ -276,7 +275,6 @@
<string name="settings.server_scaling_title">Serverseitige Skalierung der Cover</string> <string name="settings.server_scaling_title">Serverseitige Skalierung der Cover</string>
<string name="settings.server_unused">Unbenutzt</string> <string name="settings.server_unused">Unbenutzt</string>
<string name="settings.server_username">Benutzername</string> <string name="settings.server_username">Benutzername</string>
<string name="settings.servers_title">Server</string>
<string name="settings.show_lockscreen_controls">Steuerelemente auf Sperrbildschirm</string> <string name="settings.show_lockscreen_controls">Steuerelemente auf Sperrbildschirm</string>
<string name="settings.show_lockscreen_controls_summary">Wiedergabeelemente auf dem Sperrbildschirm anzeigen</string> <string name="settings.show_lockscreen_controls_summary">Wiedergabeelemente auf dem Sperrbildschirm anzeigen</string>
<string name="settings.show_notification">Benachrichtigungen anzeigen</string> <string name="settings.show_notification">Benachrichtigungen anzeigen</string>

View File

@ -108,7 +108,6 @@
<string name="main.genres_title">Géneros</string> <string name="main.genres_title">Géneros</string>
<string name="main.music">Música</string> <string name="main.music">Música</string>
<string name="main.offline">Sin conexión</string> <string name="main.offline">Sin conexión</string>
<string name="main.select_server">Seleccionar Servidor</string>
<string name="main.shuffle">Reproducción aleatoria</string> <string name="main.shuffle">Reproducción aleatoria</string>
<string name="main.songs_random">Aleatorio</string> <string name="main.songs_random">Aleatorio</string>
<string name="main.songs_starred">Me gusta</string> <string name="main.songs_starred">Me gusta</string>
@ -296,7 +295,6 @@
<string name="settings.server_scaling_title">Escalado de caratulas en el servidor</string> <string name="settings.server_scaling_title">Escalado de caratulas en el servidor</string>
<string name="settings.server_unused">Sin usar</string> <string name="settings.server_unused">Sin usar</string>
<string name="settings.server_username">Nombre de usuario</string> <string name="settings.server_username">Nombre de usuario</string>
<string name="settings.servers_title">Servidores</string>
<string name="settings.show_lockscreen_controls">Mostrar controles en la pantalla de bloqueo</string> <string name="settings.show_lockscreen_controls">Mostrar controles en la pantalla de bloqueo</string>
<string name="settings.show_lockscreen_controls_summary">Mostrar controles de reproducción en la pantalla de bloqueo</string> <string name="settings.show_lockscreen_controls_summary">Mostrar controles de reproducción en la pantalla de bloqueo</string>
<string name="settings.show_notification">Mostrar notificación</string> <string name="settings.show_notification">Mostrar notificación</string>

View File

@ -105,7 +105,6 @@
<string name="main.genres_title">Genres</string> <string name="main.genres_title">Genres</string>
<string name="main.music">Musique</string> <string name="main.music">Musique</string>
<string name="main.offline">Hors-ligne</string> <string name="main.offline">Hors-ligne</string>
<string name="main.select_server">Sélectionner un serveur</string>
<string name="main.shuffle">Lecture aléatoire</string> <string name="main.shuffle">Lecture aléatoire</string>
<string name="main.songs_random">Aléatoire</string> <string name="main.songs_random">Aléatoire</string>
<string name="main.songs_starred">Favoris</string> <string name="main.songs_starred">Favoris</string>
@ -291,7 +290,6 @@
<string name="settings.server_scaling_title">Mise à l\'échelle des pochettes d\'album sur le serveur</string> <string name="settings.server_scaling_title">Mise à l\'échelle des pochettes d\'album sur le serveur</string>
<string name="settings.server_unused">Inutilisé</string> <string name="settings.server_unused">Inutilisé</string>
<string name="settings.server_username">Nom d\'utilisateur</string> <string name="settings.server_username">Nom d\'utilisateur</string>
<string name="settings.servers_title">Serveurs</string>
<string name="settings.show_lockscreen_controls">Boutons de contrôle sur l\'écran de verrouillage</string> <string name="settings.show_lockscreen_controls">Boutons de contrôle sur l\'écran de verrouillage</string>
<string name="settings.show_lockscreen_controls_summary">Afficher les contrôles de lecture sur l\'écran de verrouillage</string> <string name="settings.show_lockscreen_controls_summary">Afficher les contrôles de lecture sur l\'écran de verrouillage</string>
<string name="settings.show_notification">Notifications</string> <string name="settings.show_notification">Notifications</string>

View File

@ -105,7 +105,6 @@
<string name="main.genres_title">Műfajok</string> <string name="main.genres_title">Műfajok</string>
<string name="main.music">Zenék</string> <string name="main.music">Zenék</string>
<string name="main.offline">Kapcsolat nélküli</string> <string name="main.offline">Kapcsolat nélküli</string>
<string name="main.select_server">Kiszolgáló kiválasztása</string>
<string name="main.shuffle">Véletlen sorrendű</string> <string name="main.shuffle">Véletlen sorrendű</string>
<string name="main.songs_random">Véletlenszerű</string> <string name="main.songs_random">Véletlenszerű</string>
<string name="main.songs_starred">Csillaggal megjelölt</string> <string name="main.songs_starred">Csillaggal megjelölt</string>
@ -289,7 +288,6 @@
<string name="settings.server_scaling_title">Albumborító átméretezés (Kiszolgáló-oldali)</string> <string name="settings.server_scaling_title">Albumborító átméretezés (Kiszolgáló-oldali)</string>
<string name="settings.server_unused">Kiszolgáló</string> <string name="settings.server_unused">Kiszolgáló</string>
<string name="settings.server_username">Felhasználónév</string> <string name="settings.server_username">Felhasználónév</string>
<string name="settings.servers_title">Kiszolgálók</string>
<string name="settings.show_lockscreen_controls">Képernyőzár kezelése</string> <string name="settings.show_lockscreen_controls">Képernyőzár kezelése</string>
<string name="settings.show_lockscreen_controls_summary">Lejátszó-kezelőpanel megjelenítése a képernyőzáron.</string> <string name="settings.show_lockscreen_controls_summary">Lejátszó-kezelőpanel megjelenítése a képernyőzáron.</string>
<string name="settings.show_notification">Értesítések megjelenítése</string> <string name="settings.show_notification">Értesítések megjelenítése</string>

View File

@ -92,7 +92,6 @@
<string name="main.genres_title">Generi</string> <string name="main.genres_title">Generi</string>
<string name="main.music">Musica</string> <string name="main.music">Musica</string>
<string name="main.offline">Disconnesso</string> <string name="main.offline">Disconnesso</string>
<string name="main.select_server">Seleziona Server</string>
<string name="main.shuffle">Riproduzione casuale</string> <string name="main.shuffle">Riproduzione casuale</string>
<string name="main.songs_random">Casuale</string> <string name="main.songs_random">Casuale</string>
<string name="main.songs_starred">Preferiti</string> <string name="main.songs_starred">Preferiti</string>
@ -270,7 +269,6 @@
<string name="settings.server_scaling_title">Ridimensionamento copertine Album lato server</string> <string name="settings.server_scaling_title">Ridimensionamento copertine Album lato server</string>
<string name="settings.server_unused">Inutilizzato</string> <string name="settings.server_unused">Inutilizzato</string>
<string name="settings.server_username">Username</string> <string name="settings.server_username">Username</string>
<string name="settings.servers_title">Server</string>
<string name="settings.show_lockscreen_controls">Mostra i controlli del blocco schermo</string> <string name="settings.show_lockscreen_controls">Mostra i controlli del blocco schermo</string>
<string name="settings.show_lockscreen_controls_summary">Mostra i controlli di riproduzione sulla schermata di blocco</string> <string name="settings.show_lockscreen_controls_summary">Mostra i controlli di riproduzione sulla schermata di blocco</string>
<string name="settings.show_notification">Mostra notifica</string> <string name="settings.show_notification">Mostra notifica</string>

View File

@ -108,7 +108,6 @@
<string name="main.genres_title">Genres</string> <string name="main.genres_title">Genres</string>
<string name="main.music">Muziek</string> <string name="main.music">Muziek</string>
<string name="main.offline">Offline</string> <string name="main.offline">Offline</string>
<string name="main.select_server">Kies een server</string>
<string name="main.shuffle">Willekeurig afspelen</string> <string name="main.shuffle">Willekeurig afspelen</string>
<string name="main.songs_random">Willekeurig</string> <string name="main.songs_random">Willekeurig</string>
<string name="main.songs_starred">Favorieten</string> <string name="main.songs_starred">Favorieten</string>
@ -296,7 +295,6 @@
<string name="settings.server_scaling_title">Verkleinde afbeeldingen ophalen van server</string> <string name="settings.server_scaling_title">Verkleinde afbeeldingen ophalen van server</string>
<string name="settings.server_unused">Ongebruikt</string> <string name="settings.server_unused">Ongebruikt</string>
<string name="settings.server_username">Gebruikersnaam</string> <string name="settings.server_username">Gebruikersnaam</string>
<string name="settings.servers_title">Servers</string>
<string name="settings.show_lockscreen_controls">Vergrendelschermbediening tonen</string> <string name="settings.show_lockscreen_controls">Vergrendelschermbediening tonen</string>
<string name="settings.show_lockscreen_controls_summary">Toont afspeelbediening op het vergrendelscherm</string> <string name="settings.show_lockscreen_controls_summary">Toont afspeelbediening op het vergrendelscherm</string>
<string name="settings.show_notification">Melding tonen</string> <string name="settings.show_notification">Melding tonen</string>

View File

@ -94,7 +94,6 @@
<string name="main.genres_title">Gatunki</string> <string name="main.genres_title">Gatunki</string>
<string name="main.music">Muzyka</string> <string name="main.music">Muzyka</string>
<string name="main.offline">Offline</string> <string name="main.offline">Offline</string>
<string name="main.select_server">Wybierz serwer</string>
<string name="main.shuffle">Losowo</string> <string name="main.shuffle">Losowo</string>
<string name="main.songs_random">Losowe</string> <string name="main.songs_random">Losowe</string>
<string name="main.songs_starred">Ulubione</string> <string name="main.songs_starred">Ulubione</string>
@ -275,7 +274,6 @@
<string name="settings.server_scaling_title">Skalowanie okładek po stronie serwera</string> <string name="settings.server_scaling_title">Skalowanie okładek po stronie serwera</string>
<string name="settings.server_unused">Bez nazwy</string> <string name="settings.server_unused">Bez nazwy</string>
<string name="settings.server_username">Nazwa użytkownika</string> <string name="settings.server_username">Nazwa użytkownika</string>
<string name="settings.servers_title">Serwery</string>
<string name="settings.show_lockscreen_controls">Wyświetlaj na ekranie blokady</string> <string name="settings.show_lockscreen_controls">Wyświetlaj na ekranie blokady</string>
<string name="settings.show_lockscreen_controls_summary">Wyświetla widżet odtwarzacza na ekranie blokady</string> <string name="settings.show_lockscreen_controls_summary">Wyświetla widżet odtwarzacza na ekranie blokady</string>
<string name="settings.show_notification">Wyświetlaj powiadomienia</string> <string name="settings.show_notification">Wyświetlaj powiadomienia</string>

View File

@ -105,7 +105,6 @@
<string name="main.genres_title">Gêneros</string> <string name="main.genres_title">Gêneros</string>
<string name="main.music">Música</string> <string name="main.music">Música</string>
<string name="main.offline">Offline</string> <string name="main.offline">Offline</string>
<string name="main.select_server">Selecione o Servidor</string>
<string name="main.shuffle">Misturar Músicas</string> <string name="main.shuffle">Misturar Músicas</string>
<string name="main.songs_random">Aleatórias</string> <string name="main.songs_random">Aleatórias</string>
<string name="main.songs_starred">Favoritas</string> <string name="main.songs_starred">Favoritas</string>
@ -293,7 +292,6 @@
<string name="settings.server_scaling_title">Reduzir Arte dos Álbuns</string> <string name="settings.server_scaling_title">Reduzir Arte dos Álbuns</string>
<string name="settings.server_unused">Não usado</string> <string name="settings.server_unused">Não usado</string>
<string name="settings.server_username">Login</string> <string name="settings.server_username">Login</string>
<string name="settings.servers_title">Servidores</string>
<string name="settings.show_lockscreen_controls">Controles na Tela de Bloqueio</string> <string name="settings.show_lockscreen_controls">Controles na Tela de Bloqueio</string>
<string name="settings.show_lockscreen_controls_summary">Mostrar controles de reprodução na tela de bloqueio</string> <string name="settings.show_lockscreen_controls_summary">Mostrar controles de reprodução na tela de bloqueio</string>
<string name="settings.show_notification">Mostrar Notificações</string> <string name="settings.show_notification">Mostrar Notificações</string>

View File

@ -94,7 +94,6 @@
<string name="main.genres_title">Gêneros</string> <string name="main.genres_title">Gêneros</string>
<string name="main.music">Música</string> <string name="main.music">Música</string>
<string name="main.offline">Offline</string> <string name="main.offline">Offline</string>
<string name="main.select_server">Selecione o Servidor</string>
<string name="main.shuffle">Misturar Músicas</string> <string name="main.shuffle">Misturar Músicas</string>
<string name="main.songs_random">Aleatórias</string> <string name="main.songs_random">Aleatórias</string>
<string name="main.songs_starred">Favoritas</string> <string name="main.songs_starred">Favoritas</string>
@ -275,7 +274,6 @@
<string name="settings.server_scaling_title">Reduzir Arte dos Álbuns</string> <string name="settings.server_scaling_title">Reduzir Arte dos Álbuns</string>
<string name="settings.server_unused">Não usado</string> <string name="settings.server_unused">Não usado</string>
<string name="settings.server_username">Login</string> <string name="settings.server_username">Login</string>
<string name="settings.servers_title">Servidores</string>
<string name="settings.show_lockscreen_controls">Controles no Ecrã de Bloqueio</string> <string name="settings.show_lockscreen_controls">Controles no Ecrã de Bloqueio</string>
<string name="settings.show_lockscreen_controls_summary">Mostra controles de reprodução no ecrã de bloqueio</string> <string name="settings.show_lockscreen_controls_summary">Mostra controles de reprodução no ecrã de bloqueio</string>
<string name="settings.show_notification">Mostrar Notificações</string> <string name="settings.show_notification">Mostrar Notificações</string>

View File

@ -105,7 +105,6 @@
<string name="main.genres_title">Жанры</string> <string name="main.genres_title">Жанры</string>
<string name="main.music">Музыка</string> <string name="main.music">Музыка</string>
<string name="main.offline">Не в сети</string> <string name="main.offline">Не в сети</string>
<string name="main.select_server">Выбрать сервер</string>
<string name="main.shuffle">Играть в случайном порядке</string> <string name="main.shuffle">Играть в случайном порядке</string>
<string name="main.songs_random">Случайный</string> <string name="main.songs_random">Случайный</string>
<string name="main.songs_starred">Отмеченные</string> <string name="main.songs_starred">Отмеченные</string>
@ -291,7 +290,6 @@
<string name="settings.server_scaling_title">Серверное масштабирование обложек альбомов</string> <string name="settings.server_scaling_title">Серверное масштабирование обложек альбомов</string>
<string name="settings.server_unused">Неиспользуемый</string> <string name="settings.server_unused">Неиспользуемый</string>
<string name="settings.server_username">Имя пользователя</string> <string name="settings.server_username">Имя пользователя</string>
<string name="settings.servers_title">Серверы</string>
<string name="settings.show_lockscreen_controls">Показать блокировку экрана</string> <string name="settings.show_lockscreen_controls">Показать блокировку экрана</string>
<string name="settings.show_lockscreen_controls_summary">Показать элементы управления воспроизведением на экране блокировки</string> <string name="settings.show_lockscreen_controls_summary">Показать элементы управления воспроизведением на экране блокировки</string>
<string name="settings.show_notification">Показывать уведомления</string> <string name="settings.show_notification">Показывать уведомления</string>

View File

@ -104,7 +104,6 @@
<string name="main.genres_title">流派</string> <string name="main.genres_title">流派</string>
<string name="main.music">音乐</string> <string name="main.music">音乐</string>
<string name="main.offline">离线</string> <string name="main.offline">离线</string>
<string name="main.select_server">选择服务器</string>
<string name="main.shuffle">随机播放</string> <string name="main.shuffle">随机播放</string>
<string name="main.songs_random">随机</string> <string name="main.songs_random">随机</string>
<string name="main.songs_starred">收藏夹</string> <string name="main.songs_starred">收藏夹</string>
@ -289,7 +288,6 @@
<string name="settings.server_scaling_title">服务器端专辑图片缩放</string> <string name="settings.server_scaling_title">服务器端专辑图片缩放</string>
<string name="settings.server_unused">未启用</string> <string name="settings.server_unused">未启用</string>
<string name="settings.server_username">用户名</string> <string name="settings.server_username">用户名</string>
<string name="settings.servers_title">服务器</string>
<string name="settings.show_lockscreen_controls">锁屏显示控制器</string> <string name="settings.show_lockscreen_controls">锁屏显示控制器</string>
<string name="settings.show_lockscreen_controls_summary">在锁定屏幕上显示播放控件</string> <string name="settings.show_lockscreen_controls_summary">在锁定屏幕上显示播放控件</string>
<string name="settings.show_notification">显示通知</string> <string name="settings.show_notification">显示通知</string>

View File

@ -3,17 +3,20 @@
<color name="dividerColor">#555555</color> <color name="dividerColor">#555555</color>
<color name="appwidget_text">#FFFFFF</color> <color name="appwidget_text">#FFFFFF</color>
<color name="transparent">#00000000</color> <color name="transparent">#00000000</color>
<color name="cyan">#ff0099cc</color> <color name="cyan">#0099cc</color>
<color name="navigation_header_light">#6200EE</color>
<color name="navigation_header_dark">#BB86FC</color>
<color name="ics_opaque">#8033b5e5</color> <color name="ics_opaque">#8033b5e5</color>
<color name="md__transparent">#00000000</color> <color name="md__transparent">#00000000</color>
<color name="translucent">#80000000</color> <color name="translucent">#80000000</color>
<color name="background_color_dark">#ff000000</color> <color name="background_color_dark">#000000</color>
<color name="background_color_light">#fff3f3f3</color> <color name="background_color_grey">#333333</color>
<color name="background_color_light">#ffffff</color>
<color name="selected_color_dark">#424242</color> <color name="selected_color_dark">#424242</color>
<color name="selected_color_light">#B1B1B1</color> <color name="selected_color_light">#B6B6B6</color>
<color name="selected_menu_dark">#fff3f3f3</color> <color name="selected_menu_dark">#F3F3F3</color>
<color name="selected_menu_light">#ff000000</color> <color name="selected_menu_light">#000000</color>
<color name="selected_menu_background_dark">#ff333333</color> <color name="selected_menu_background_dark">#333333</color>
<color name="selected_menu_background_black">#ff111111</color> <color name="selected_menu_background_black">#111111</color>
<color name="selected_menu_background_light">#fff3f3f3</color> <color name="selected_menu_background_light">#f3f3f3</color>
</resources> </resources>

View File

@ -108,7 +108,7 @@
<string name="main.genres_title">Genres</string> <string name="main.genres_title">Genres</string>
<string name="main.music">Music</string> <string name="main.music">Music</string>
<string name="main.offline">Offline</string> <string name="main.offline">Offline</string>
<string name="main.select_server">Select Server</string> <string name="main.setup_server">%s - Set up Server</string>
<string name="main.shuffle">Shuffle Play</string> <string name="main.shuffle">Shuffle Play</string>
<string name="main.songs_random">Random</string> <string name="main.songs_random">Random</string>
<string name="main.songs_starred">Starred</string> <string name="main.songs_starred">Starred</string>
@ -299,7 +299,7 @@
<string name="settings.server_scaling_title">Server-Side Album Art Scaling</string> <string name="settings.server_scaling_title">Server-Side Album Art Scaling</string>
<string name="settings.server_unused">Unused</string> <string name="settings.server_unused">Unused</string>
<string name="settings.server_username">Username</string> <string name="settings.server_username">Username</string>
<string name="settings.servers_title">Servers</string> <string name="settings.server_color">Server color</string>
<string name="settings.show_lockscreen_controls">Show Lock Screen Controls</string> <string name="settings.show_lockscreen_controls">Show Lock Screen Controls</string>
<string name="settings.show_lockscreen_controls_summary">Show playback controls on the lock screen</string> <string name="settings.show_lockscreen_controls_summary">Show playback controls on the lock screen</string>
<string name="settings.show_notification">Show Notification</string> <string name="settings.show_notification">Show Notification</string>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="NoActionBar" parent="@style/Theme.AppCompat"> <style name="NoActionBar" parent="@style/Theme.MaterialComponents">
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
</style> </style>
@ -30,7 +30,7 @@
<item name="cornerSize">2dp</item> <item name="cornerSize">2dp</item>
</style> </style>
<style name="ThemeOverlay.AppCompat.navTheme"> <style name="ThemeOverlay.AppCompat.navTheme">
<item name="colorPrimary">?attr/color_menu_selected</item> <item name="colorPrimary">?attr/color_menu_selected</item>
<item name="colorControlHighlight">?attr/color_selected</item> <item name="colorControlHighlight">?attr/color_selected</item>
</style> </style>
@ -86,6 +86,7 @@
<attr name="color_selected" format="reference"/> <attr name="color_selected" format="reference"/>
<attr name="color_menu_selected" format="reference"/> <attr name="color_menu_selected" format="reference"/>
<attr name="color_menu_background" format="reference"/> <attr name="color_menu_background" format="reference"/>
<attr name="color_navigation_header_background" format="reference"/>
<attr name="filepicker_create_new_folder" format="reference"/> <attr name="filepicker_create_new_folder" format="reference"/>
<attr name="filepicker_folder" format="reference"/> <attr name="filepicker_folder" format="reference"/>
<attr name="filepicker_subdirectory_left" format="reference"/> <attr name="filepicker_subdirectory_left" format="reference"/>

View File

@ -7,6 +7,7 @@
<item name="color_selected">@color/selected_color_dark</item> <item name="color_selected">@color/selected_color_dark</item>
<item name="color_menu_selected">@color/selected_menu_dark</item> <item name="color_menu_selected">@color/selected_menu_dark</item>
<item name="color_menu_background">@color/selected_menu_background_black</item> <item name="color_menu_background">@color/selected_menu_background_black</item>
<item name="color_navigation_header_background">@color/navigation_header_dark</item>
<item name="star_hollow">@drawable/ic_star_hollow_dark</item> <item name="star_hollow">@drawable/ic_star_hollow_dark</item>
<item name="star_full">@drawable/ic_star_full_dark</item> <item name="star_full">@drawable/ic_star_full_dark</item>
<item name="about">@drawable/ic_menu_about_dark</item> <item name="about">@drawable/ic_menu_about_dark</item>
@ -63,13 +64,15 @@
<item name="list_selector_holo_selected">@drawable/list_selector_holo_dark_selected</item> <item name="list_selector_holo_selected">@drawable/list_selector_holo_dark_selected</item>
</style> </style>
<style name="UltrasonicTheme" parent="Theme.AppCompat"> <style name="UltrasonicTheme" parent="Theme.MaterialComponents">
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
<item name="color_background">@color/background_color_dark</item> <item name="color_background">@color/background_color_grey</item>
<item name="android:colorBackground">@color/background_color_grey</item>
<item name="color_selected">@color/selected_color_dark</item> <item name="color_selected">@color/selected_color_dark</item>
<item name="color_menu_selected">@color/selected_menu_dark</item> <item name="color_menu_selected">@color/selected_menu_dark</item>
<item name="color_menu_background">@color/selected_menu_background_dark</item> <item name="color_menu_background">@color/selected_menu_background_dark</item>
<item name="color_navigation_header_background">@color/navigation_header_dark</item>
<item name="star_hollow">@drawable/ic_star_hollow_dark</item> <item name="star_hollow">@drawable/ic_star_hollow_dark</item>
<item name="star_full">@drawable/ic_star_full_dark</item> <item name="star_full">@drawable/ic_star_full_dark</item>
<item name="about">@drawable/ic_menu_about_dark</item> <item name="about">@drawable/ic_menu_about_dark</item>
@ -126,13 +129,14 @@
<item name="list_selector_holo_selected">@drawable/list_selector_holo_dark_selected</item> <item name="list_selector_holo_selected">@drawable/list_selector_holo_dark_selected</item>
</style> </style>
<style name="UltrasonicTheme.Light" parent="Theme.AppCompat.Light"> <style name="UltrasonicTheme.Light" parent="Theme.MaterialComponents.Light">
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
<item name="color_background">@color/background_color_light</item> <item name="color_background">@color/background_color_light</item>
<item name="color_selected">@color/selected_color_light</item> <item name="color_selected">@color/selected_color_light</item>
<item name="color_menu_selected">@color/selected_menu_light</item> <item name="color_menu_selected">@color/selected_menu_light</item>
<item name="color_menu_background">@color/selected_menu_background_light</item> <item name="color_menu_background">@color/selected_menu_background_light</item>
<item name="color_navigation_header_background">@color/navigation_header_light</item>
<item name="star_hollow">@drawable/ic_star_hollow_light</item> <item name="star_hollow">@drawable/ic_star_hollow_light</item>
<item name="star_full">@drawable/ic_star_full_light</item> <item name="star_full">@drawable/ic_star_full_light</item>
<item name="about">@drawable/ic_menu_about_light</item> <item name="about">@drawable/ic_menu_about_light</item>

View File

@ -2,15 +2,6 @@
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" a:title="@string/common.appname"> xmlns:app="http://schemas.android.com/apk/res-auto" a:title="@string/common.appname">
<PreferenceCategory
a:key="serversKey"
a:title="@string/settings.servers_title"
app:iconSpaceReserved="false">
<Preference
a:key="editServers"
a:title="@string/settings.server_manage_servers"
app:iconSpaceReserved="false"/>
</PreferenceCategory>
<PreferenceCategory <PreferenceCategory
a:title="@string/settings.appearance_title" a:title="@string/settings.appearance_title"
app:iconSpaceReserved="false"> app:iconSpaceReserved="false">