Implemented navigation header coloring based on selected server

This commit is contained in:
Nite 2021-10-15 16:26:06 +02:00
parent 477f6f5d7c
commit 7c66bc7ec8
No known key found for this signature in database
GPG Key ID: 1D1AD59B1C6386C1
7 changed files with 81 additions and 45 deletions

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
} }

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,9 +13,11 @@ 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.Button import android.widget.ImageView
import android.widget.TextView
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
@ -27,6 +30,7 @@ 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
@ -46,6 +50,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
@ -66,7 +71,10 @@ 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: Button? = null private var selectServerButton: MaterialButton? = null
private var headerBackgroundImage: ImageView? = null
private var ultrasonicLogoImage: ImageView? = null
private var ultrasonicNameText: TextView? = null
private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var nowPlayingEventListener: NowPlayingEventListener private lateinit var nowPlayingEventListener: NowPlayingEventListener
@ -189,17 +197,35 @@ class NavigationActivity : AppCompatActivity() {
this, this,
{ count -> { count ->
cachedServerCount = count ?: 0 cachedServerCount = count ?: 0
setSelectServerButtonText() updateNavigationHeaderForServer()
} }
) )
ActiveServerProvider.liveActiveServerId.observe(this, { setSelectServerButtonText() }) ActiveServerProvider.liveActiveServerId.observe(this, { updateNavigationHeaderForServer() })
} }
private fun setSelectServerButtonText() { private fun updateNavigationHeaderForServer() {
val activeServerName = activeServerProvider.getActiveServer().name val activeServer = activeServerProvider.getActiveServer()
if (cachedServerCount == 0) if (cachedServerCount == 0)
selectServerButton?.text = getString(R.string.main_setup_server, activeServerName) selectServerButton?.text = getString(R.string.main_setup_server, activeServer.name)
else selectServerButton?.text = activeServerName 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)
ultrasonicLogoImage?.imageTintList = ColorStateList.valueOf(foregroundColor)
selectServerButton?.setTextColor(foregroundColor)
ultrasonicNameText?.setTextColor(foregroundColor)
headerBackgroundImage?.setBackgroundColor(backgroundColor)
} }
override fun onResume() { override fun onResume() {
@ -260,6 +286,12 @@ class NavigationActivity : AppCompatActivity() {
this.drawerLayout?.closeDrawer(GravityCompat.START) this.drawerLayout?.closeDrawer(GravityCompat.START)
navController.navigate(R.id.serverSelectorFragment) navController.navigate(R.id.serverSelectorFragment)
} }
headerBackgroundImage =
navigationView?.getHeaderView(0)?.findViewById(R.id.img_header_bg)
ultrasonicLogoImage =
navigationView?.getHeaderView(0)?.findViewById(R.id.img_profile)
ultrasonicNameText =
navigationView?.getHeaderView(0)?.findViewById(R.id.name)
} }
private fun setupActionBar(navController: NavController, appBarConfig: AppBarConfiguration) { private fun setupActionBar(navController: NavController, appBarConfig: AppBarConfiguration) {

View File

@ -73,10 +73,8 @@ internal class FilePickerAdapter : RecyclerView.Adapter<FilePickerAdapter.FileLi
var fileList = LinkedList<FileListItem>() var fileList = LinkedList<FileListItem>()
var storages: List<File>? = null var storages: List<File>? = null
var storagePaths: List<String>? = null var storagePaths: List<String>? = null
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 +82,8 @@ internal class FilePickerAdapter : RecyclerView.Adapter<FilePickerAdapter.FileLi
currentDirectory.absolutePath == "/mnt" currentDirectory.absolutePath == "/mnt"
) { ) {
isRealDirectory = false isRealDirectory = false
fileList = if ( fileList =
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT
) {
getKitKatStorageItems(storages!!) getKitKatStorageItems(storages!!)
} else {
getStorageItems()
}
} else { } else {
isRealDirectory = true isRealDirectory = true
val files = currentDirectory.listFiles() val files = currentDirectory.listFiles()
@ -129,14 +122,10 @@ 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()

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

@ -1,3 +1,10 @@
/*
* ServerColor.kt
* Copyright (C) 2009-2021 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.util package org.moire.ultrasonic.util
import android.content.Context import android.content.Context
@ -7,6 +14,9 @@ import org.moire.ultrasonic.R
private const val LUMINANCE_LIMIT = 0.25 private const val LUMINANCE_LIMIT = 0.25
/**
* Contains functions for computing server display colors
*/
object ServerColor { object ServerColor {
fun getBackgroundColor(context: Context, serverColor: Int?): Int { fun getBackgroundColor(context: Context, serverColor: Int?): Int {
return serverColor ?: ContextCompat.getColor( return serverColor ?: ContextCompat.getColor(

View File

@ -2,6 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
xmlns:a="http://schemas.android.com/apk/res/android" 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:id="@+id/view_container" a:id="@+id/view_container"
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="wrap_content" a:layout_height="wrap_content"
@ -13,9 +14,9 @@
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="0dp" a:layout_height="0dp"
a:scaleType="fitXY" a:scaleType="fitXY"
a:src="?attr/color_navigation_header_background"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<ImageView <ImageView
a:id="@+id/img_profile" a:id="@+id/img_profile"
@ -25,9 +26,10 @@
a:layout_marginLeft="16dp" a:layout_marginLeft="16dp"
a:layout_marginTop="32dp" a:layout_marginTop="32dp"
a:src="@drawable/ic_stat_ultrasonic" a:src="@drawable/ic_stat_ultrasonic"
app:tint="?attr/colorOnPrimary" tools:tint="@color/selected_menu_dark"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<TextView <TextView
a:id="@+id/name" a:id="@+id/name"
@ -39,6 +41,7 @@
a:text="@string/common.appname" a:text="@string/common.appname"
a:textAppearance="@style/TextAppearance.AppCompat.Title" a:textAppearance="@style/TextAppearance.AppCompat.Title"
a:textColor="?attr/colorOnPrimary" a:textColor="?attr/colorOnPrimary"
tools:textColor="@color/selected_menu_dark"
app:layout_constraintBottom_toBottomOf="@+id/img_profile" app:layout_constraintBottom_toBottomOf="@+id/img_profile"
app:layout_constraintStart_toEndOf="@+id/img_profile" app:layout_constraintStart_toEndOf="@+id/img_profile"
app:layout_constraintTop_toTopOf="@+id/img_profile" /> app:layout_constraintTop_toTopOf="@+id/img_profile" />
@ -53,16 +56,25 @@
a:textSize="14sp" a:textSize="14sp"
app:icon="@drawable/ic_menu_select_server_dark" app:icon="@drawable/ic_menu_select_server_dark"
app:iconPadding="16dp" app:iconPadding="16dp"
app:iconTint="?attr/colorOnPrimary" a:paddingHorizontal="22dp"
a:paddingTop="16dp" a:paddingTop="14dp"
a:paddingBottom="16dp" a:paddingBottom="14dp"
a:paddingStart="22dp"
a:paddingEnd="22dp"
a:text="@string/main.offline" a:text="@string/main.offline"
a:textColor="?attr/colorOnPrimary" a:textColor="?attr/colorOnPrimary"
a:background="@drawable/default_ripple" a:background="@drawable/default_ripple"
tools:iconTint="@color/selected_menu_dark"
tools:textColor="@color/selected_menu_dark"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/img_profile" /> app:layout_constraintTop_toBottomOf="@+id/img_profile" />
<ImageView
a:id="@+id/img_shadow"
a:layout_width="match_parent"
a:layout_height="6dp"
a:layout_marginTop="-6dp"
a:scaleType="fitXY"
a:src="@drawable/drop_shadow"
app:layout_constraintTop_toBottomOf="@+id/header_select_server" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

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"
@ -64,7 +65,7 @@
a:src="@drawable/rounded_border" a:src="@drawable/rounded_border"
app:layout_constraintTop_toBottomOf="@id/edit_server_address" app:layout_constraintTop_toBottomOf="@id/edit_server_address"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
/> tools:ignore="ContentDescription" />
<TextView <TextView
a:id="@+id/edit_authentication_header" a:id="@+id/edit_authentication_header"