SubwayTooter-Android-App/base/src/main/java/jp/juggler/util/ui/ViewUtils.kt

195 lines
6.3 KiB
Kotlin
Raw Normal View History

package jp.juggler.util.ui
2018-12-01 00:02:18 +01:00
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
2020-09-27 12:59:54 +02:00
import android.graphics.Color
import android.os.Build
2018-12-01 00:02:18 +01:00
import android.view.View
import android.view.ViewGroup
2020-09-27 12:59:54 +02:00
import android.view.WindowInsetsController
2018-12-01 00:02:18 +01:00
import android.view.inputmethod.InputMethodManager
import android.widget.CompoundButton
2021-12-04 09:55:28 +01:00
import android.widget.TextView
2021-06-28 09:09:00 +02:00
import androidx.annotation.ColorInt
2020-09-27 12:59:54 +02:00
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import jp.juggler.util.log.LogCategory
2020-09-27 12:59:54 +02:00
import kotlin.math.pow
2018-12-01 00:02:18 +01:00
2018-12-04 10:59:01 +01:00
private val log = LogCategory("ViewUtils")
2018-12-01 00:02:18 +01:00
2021-06-20 05:02:30 +02:00
fun View?.scan(callback: (view: View) -> Unit) {
this ?: return
callback(this)
if (this is ViewGroup) {
for (i in 0 until this.childCount) {
this.getChildAt(i)?.scan(callback)
}
}
2018-12-01 00:02:18 +01:00
}
2021-06-20 05:02:30 +02:00
val View?.activity: Activity?
get() {
var context = this?.context
while (context is ContextWrapper) {
if (context is Activity) return context
context = context.baseContext
}
return null
}
2018-12-01 00:02:18 +01:00
fun View.hideKeyboard() {
2021-06-20 05:02:30 +02:00
try {
when (val imm = this.context?.getSystemService(Context.INPUT_METHOD_SERVICE)) {
is InputMethodManager ->
imm.hideSoftInputFromWindow(this.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
else -> log.e("hideKeyboard: can't get InputMethodManager")
2021-06-20 05:02:30 +02:00
}
} catch (ex: Throwable) {
2023-01-13 07:33:28 +01:00
log.e(ex, "hideKeyboard failed.")
2021-06-20 05:02:30 +02:00
}
2018-12-01 00:02:18 +01:00
}
fun View.showKeyboard() {
2021-06-20 05:02:30 +02:00
try {
ContextCompat.getSystemService(context, InputMethodManager::class.java)!!
.showSoftInput(this, InputMethodManager.HIDE_NOT_ALWAYS)
2021-06-20 05:02:30 +02:00
} catch (ex: Throwable) {
2023-01-13 07:33:28 +01:00
log.e(ex, "showKeyboard failed.")
2021-06-20 05:02:30 +02:00
}
2018-12-01 00:02:18 +01:00
}
// set visibility VISIBLE or GONE
// return this or null
// レシーバがnullableなのはplatform typeによるnull例外を避ける目的
2021-06-20 05:02:30 +02:00
fun <T : View> T?.vg(visible: Boolean): T? {
this?.visibility = if (visible) View.VISIBLE else View.GONE
return if (visible) this else null
2018-12-01 00:02:18 +01:00
}
// set visibility VISIBLE or INVISIBLE
// return this or null
// レシーバがnullableなのはplatform typeによるnull例外を避ける目的
fun <T : View> T?.visibleOrInvisible(visible: Boolean): T? {
this?.visibility = if (visible) View.VISIBLE else View.INVISIBLE
return if (visible) this else null
}
fun <T : View> T.visible(): T = apply { visibility = View.VISIBLE }
fun <T : View> T.invisible(): T = apply { visibility = View.INVISIBLE }
fun <T : View> T.gone(): T = apply { visibility = View.GONE }
// isChecked with skipping animation
2021-06-20 05:02:30 +02:00
var CompoundButton.isCheckedNoAnime: Boolean
get() = isChecked
set(value) {
isChecked = value
jumpDrawablesToCurrentState()
}
fun mixColor(col1: Int, col2: Int): Int = Color.rgb(
2021-06-20 05:02:30 +02:00
(Color.red(col1) + Color.red(col2)) ushr 1,
(Color.green(col1) + Color.green(col2)) ushr 1,
(Color.blue(col1) + Color.blue(col2)) ushr 1
2020-09-27 12:59:54 +02:00
)
2021-06-20 05:02:30 +02:00
private fun rgbToLab(rgb: Int): Triple<Float, Float, Float> {
fun Int.revGamma(): Float {
val v = toFloat() / 255f
return when {
v > 0.04045f -> ((v + 0.055f) / 1.055f).pow(2.4f)
else -> v / 12.92f
}
}
val r = Color.red(rgb).revGamma()
val g = Color.green(rgb).revGamma()
val b = Color.blue(rgb).revGamma()
//https://en.wikipedia.org/wiki/Lab_color_space#CIELAB-CIEXYZ_conversions
fun f(src: Float, k: Float): Float {
val v = src * k
return when {
v > 0.008856f -> v.pow(1f / 3f)
else -> (7.787f * v) + (4f / 29f)
}
}
val x = f(r * 0.4124f + g * 0.3576f + b * 0.1805f, 100f / 95.047f)
val y = f(r * 0.2126f + g * 0.7152f + b * 0.0722f, 100f / 100f)
val z = f(r * 0.0193f + g * 0.1192f + b * 0.9505f, 100f / 108.883f)
return Triple(
(116 * y) - 16, // L
500 * (x - y), // a
200 * (y - z) //b
)
2020-09-27 12:59:54 +02:00
}
2024-03-17 11:05:30 +01:00
fun Activity.setStatusBarColorCompat(@ColorInt c: Int) {
2021-06-28 09:09:00 +02:00
window?.apply {
statusBarColor = Color.BLACK or c
2021-06-20 05:02:30 +02:00
if (Build.VERSION.SDK_INT >= 30) {
decorView.windowInsetsController?.run {
val bit = WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
setSystemBarsAppearance(if (rgbToLab(c).first >= 50f) bit else 0, bit)
}
2022-08-11 09:51:49 +02:00
} else {
2021-06-20 05:02:30 +02:00
@Suppress("DEPRECATION")
val bit = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
@Suppress("DEPRECATION")
decorView.systemUiVisibility =
2022-08-11 09:51:49 +02:00
when {
rgbToLab(c).first >= 50f -> {
//Dark Text to show up on your light status bar
decorView.systemUiVisibility or bit
}
else -> {
//Light Text to show up on your dark status bar
decorView.systemUiVisibility and bit.inv()
}
2021-06-20 05:02:30 +02:00
}
}
2021-06-28 09:09:00 +02:00
}
}
2021-06-20 05:02:30 +02:00
2024-03-17 11:05:30 +01:00
fun Activity.setNavigationBarColorCompat(@ColorInt c: Int) {
2021-06-28 09:09:00 +02:00
if (c == 0) {
// no way to restore to system default, need restart app.
return
}
2021-06-20 05:02:30 +02:00
2021-06-28 09:09:00 +02:00
window?.apply {
navigationBarColor = c or Color.BLACK
2021-06-20 05:02:30 +02:00
2021-06-28 09:09:00 +02:00
if (Build.VERSION.SDK_INT >= 30) {
decorView.windowInsetsController?.run {
val bit = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
setSystemBarsAppearance(if (rgbToLab(c).first >= 50f) bit else 0, bit)
}
2022-08-11 09:51:49 +02:00
} else {
2021-06-28 09:09:00 +02:00
@Suppress("DEPRECATION")
val bit = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
@Suppress("DEPRECATION")
decorView.systemUiVisibility = when {
2022-08-11 09:51:49 +02:00
//Dark Text to show up on your light status bar
rgbToLab(c).first >= 50f ->
2021-06-28 09:09:00 +02:00
decorView.systemUiVisibility or bit
2022-08-11 09:51:49 +02:00
//Light Text to show up on your dark status bar
else ->
2021-06-28 09:09:00 +02:00
decorView.systemUiVisibility and bit.inv()
2021-06-20 05:02:30 +02:00
}
2021-06-28 09:09:00 +02:00
}
2021-06-20 05:02:30 +02:00
}
2020-09-27 12:59:54 +02:00
}
2021-12-04 09:55:28 +01:00
var TextView.textOrGone: CharSequence?
2021-12-04 09:55:28 +01:00
get() = text
set(value) {
vg(value?.isNotEmpty() == true)?.text = value
2021-12-04 09:55:28 +01:00
}