OsmAnd/OsmAnd-telegram/src/net/osmand/telegram/utils/UiUtils.kt

216 lines
6 KiB
Kotlin
Raw Normal View History

2018-06-13 19:14:08 +02:00
package net.osmand.telegram.utils
import android.content.Context
2018-06-13 19:14:08 +02:00
import android.graphics.*
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.hardware.Sensor
import android.hardware.SensorManager
2018-06-13 19:14:08 +02:00
import android.support.annotation.ColorInt
import android.support.annotation.ColorRes
import android.support.annotation.DrawableRes
import android.support.v4.content.ContextCompat
import android.support.v4.graphics.drawable.DrawableCompat
import android.view.Surface
import android.view.WindowManager
import android.widget.ImageView
import android.widget.TextView
import net.osmand.Location
import net.osmand.data.LatLon
2018-06-13 19:14:08 +02:00
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.ui.views.DirectionDrawable
2018-06-13 19:14:08 +02:00
import java.util.*
class UiUtils(private val app: TelegramApplication) {
private val drawableCache = LinkedHashMap<Long, Drawable>()
private val circleBitmapCache = LinkedHashMap<String, Bitmap>()
private val isLightContent: Boolean
get() = true
fun getCircleBitmap(path: String): Bitmap? {
var bmp: Bitmap? = circleBitmapCache[path]
if (bmp == null) {
bmp = BitmapFactory.decodeFile(path)
if (bmp != null) {
bmp = app.uiUtils.createCircleBitmap(bmp, true)
circleBitmapCache[path] = bmp
}
}
return bmp
}
private fun getDrawable(@DrawableRes resId: Int, @ColorRes clrId: Int): Drawable? {
val hash = (resId.toLong() shl 31) + clrId
var d: Drawable? = drawableCache[hash]
if (d == null) {
d = ContextCompat.getDrawable(app, resId)
if (d != null) {
d = DrawableCompat.wrap(d)
d!!.mutate()
if (clrId != 0) {
DrawableCompat.setTint(d, ContextCompat.getColor(app, clrId))
}
drawableCache[hash] = d
}
}
return d
}
private fun getPaintedDrawable(@DrawableRes resId: Int, @ColorInt color: Int): Drawable? {
val hash = (resId.toLong() shl 31) + color
var d: Drawable? = drawableCache[hash]
if (d == null) {
d = ContextCompat.getDrawable(app, resId)
if (d != null) {
d = DrawableCompat.wrap(d)
d!!.mutate()
DrawableCompat.setTint(d, color)
drawableCache[hash] = d
}
}
return d
}
fun getPaintedIcon(@DrawableRes id: Int, @ColorInt color: Int): Drawable? {
return getPaintedDrawable(id, color)
}
fun getIcon(@DrawableRes id: Int, @ColorRes colorId: Int): Drawable? {
return getDrawable(id, colorId)
}
fun getIcon(@DrawableRes backgroundId: Int, @DrawableRes id: Int, @ColorRes colorId: Int): Drawable {
val b = getDrawable(backgroundId, 0)
val f = getDrawable(id, colorId)
val layers = arrayOfNulls<Drawable>(2)
layers[0] = b
layers[1] = f
return LayerDrawable(layers)
}
fun getThemedIcon(@DrawableRes id: Int): Drawable? {
2018-06-20 18:46:14 +02:00
return getDrawable(id, if (isLightContent) R.color.icon_light else 0)
2018-06-13 19:14:08 +02:00
}
fun getIcon(@DrawableRes id: Int): Drawable? {
return getDrawable(id, 0)
}
fun getIcon(@DrawableRes id: Int, light: Boolean): Drawable? {
2018-06-20 18:46:14 +02:00
return getDrawable(id, if (light) R.color.icon_light else 0)
2018-06-13 19:14:08 +02:00
}
2018-06-14 20:01:10 +02:00
private fun createCircleBitmap(source: Bitmap, recycleSource: Boolean = false): Bitmap {
2018-06-13 19:14:08 +02:00
val size = Math.min(source.width, source.height)
val width = (source.width - size) / 2
val height = (source.height - size) / 2
val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
val paint = Paint()
val shader = BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
if (width != 0 || height != 0) {
// source isn't square, move viewport to center
val matrix = Matrix()
matrix.setTranslate((-width).toFloat(), (-height).toFloat())
shader.setLocalMatrix(matrix)
}
paint.shader = shader
paint.isAntiAlias = true
val r = size / 2f
canvas.drawCircle(r, r, r, paint)
if (recycleSource) {
source.recycle()
}
return bitmap
}
fun updateLocationView(
arrow: ImageView?,
text: TextView?,
lat: Double,
lon: Double,
cache: UpdateLocationViewCache
) {
updateLocationView(arrow, text, LatLon(lat, lon), cache)
}
fun updateLocationView(
arrow: ImageView?,
text: TextView?,
toLoc: LatLon,
cache: UpdateLocationViewCache
) {
val fromLoc = app.locationProvider.lastKnownLocationLatLon
val heading = app.locationProvider.heading
val mes = FloatArray(2)
val locPassive = fromLoc == null || cache.outdatedLocation
val colorId = if (locPassive) R.color.icon_light else R.color.ctrl_active_light
fromLoc?.also { l ->
Location.distanceBetween(toLoc.latitude, toLoc.longitude, l.latitude, l.longitude, mes)
}
if (arrow != null) {
var newImage = false
val drawable = arrow.drawable
val dd = if (drawable is DirectionDrawable) {
drawable
} else {
newImage = true
DirectionDrawable(app)
}
dd.setImage(R.drawable.ic_direction_arrow, colorId)
if (fromLoc == null || heading == null) {
dd.setAngle(0f)
} else {
dd.setAngle(mes[1] - heading + 180 + cache.screenOrientation)
}
if (newImage) {
arrow.setImageDrawable(dd)
}
arrow.invalidate()
}
if (text != null) {
text.setTextColor(ContextCompat.getColor(app, colorId))
val meters = if (fromLoc == null) 0f else mes[1]
text.text = OsmandFormatter.getFormattedDistance(meters, app)
}
}
fun getUpdateLocationViewCache() =
UpdateLocationViewCache().apply { screenOrientation = getScreenOrientation() }
private fun getScreenOrientation(): Int {
// screenOrientation correction must not be applied for devices without compass
val sensorManager = app.getSystemService(Context.SENSOR_SERVICE) as SensorManager?
if (sensorManager?.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) == null) {
return 0
}
val windowManager = app.getSystemService(Context.WINDOW_SERVICE) as WindowManager?
val rotation = windowManager?.defaultDisplay?.rotation ?: return 0
return when (rotation) {
Surface.ROTATION_90 -> 90
Surface.ROTATION_180 -> 180
Surface.ROTATION_270 -> 270
else -> 0
}
}
class UpdateLocationViewCache {
var screenOrientation: Int = 0
var outdatedLocation: Boolean = false
}
2018-06-13 19:14:08 +02:00
}