1+ package org.blitzortung.android.app.view
2+
3+ import android.content.Context
4+ import android.content.SharedPreferences
5+ import android.graphics.Canvas
6+ import android.graphics.Paint
7+ import android.graphics.RectF
8+ import android.preference.PreferenceManager
9+ import android.util.AttributeSet
10+ import android.util.Log
11+ import android.view.ViewGroup
12+ import android.widget.RelativeLayout
13+ import org.blitzortung.android.app.Main
14+ import org.blitzortung.android.app.R
15+ import org.blitzortung.android.data.beans.GridParameters
16+ import org.blitzortung.android.data.provider.result.ResultEvent
17+ import org.blitzortung.android.protocol.Event
18+ import org.blitzortung.android.util.TabletAwareView
19+ import org.osmdroid.events.MapListener
20+ import org.osmdroid.events.ScrollEvent
21+ import org.osmdroid.events.ZoomEvent
22+ import org.osmdroid.tileprovider.tilesource.TileSourceFactory
23+ import org.osmdroid.util.BoundingBox
24+
25+ private const val SMALL_TEXT_SCALE = 0.6f
26+
27+ class RegionView @JvmOverloads constructor(
28+ context : Context ,
29+ attrs : AttributeSet ? = null ,
30+ defStyle : Int = 0
31+ ) : TabletAwareView(context, attrs, defStyle), MapListener, OnSharedPreferenceChangeListener {
32+
33+ private val backgroundPaint: Paint = Paint (Paint .ANTI_ALIAS_FLAG )
34+ private val foregroundPaint: Paint = Paint (Paint .ANTI_ALIAS_FLAG )
35+ private val textPaint: Paint
36+ private val defaultForegroundColor: Int
37+ private val backgroundRect: RectF
38+ private var mapArea: BoundingBox ? = null
39+ private var zoomLevel: Double? = null
40+
41+ private var gridParameters: GridParameters ? = null
42+
43+ val dataConsumer = { event: Event ->
44+ if (event is ResultEvent ) {
45+ updateHistogram(event)
46+ }
47+ }
48+
49+ init {
50+ backgroundPaint.color = 0x00b0b0b0
51+
52+ defaultForegroundColor = context.resources.getColor(R .color.text_foreground)
53+
54+ textPaint = Paint (Paint .ANTI_ALIAS_FLAG ).apply {
55+ color = defaultForegroundColor
56+ textSize = this @RegionView.textSize * SMALL_TEXT_SCALE
57+ textAlign = Paint .Align .RIGHT
58+ }
59+
60+ foregroundPaint.strokeWidth = 5f
61+
62+ backgroundRect = RectF ()
63+
64+ val preferences = PreferenceManager .getDefaultSharedPreferences(context)
65+ preferences.registerOnSharedPreferenceChangeListener(this )
66+ onSharedPreferenceChanged(preferences, PreferenceKey .DIAGNOSIS_ENABLED )
67+ }
68+
69+ override fun onMeasure (widthMeasureSpec : Int , heightMeasureSpec : Int ) {
70+ val getSize = fun (spec : Int ) = MeasureSpec .getSize(spec)
71+
72+ val parentWidth = getSize(widthMeasureSpec) * sizeFactor
73+ val parentHeight = getSize(heightMeasureSpec) * sizeFactor
74+
75+ super .onMeasure(
76+ MeasureSpec .makeMeasureSpec(parentWidth.toInt(), MeasureSpec .EXACTLY ),
77+ MeasureSpec .makeMeasureSpec(parentHeight.toInt(), MeasureSpec .EXACTLY )
78+ )
79+ }
80+
81+ override fun onDraw (canvas : Canvas ) {
82+
83+ backgroundRect.set(0f , 0f , width.toFloat(), height.toFloat())
84+ canvas.drawRect(backgroundRect, backgroundPaint)
85+
86+
87+ var topCoordinate = 2 * padding
88+
89+ gridParameters?.let {
90+ if (! it.isGlobal) {
91+ val text = " %.1f..%.1f %.1f..%.1f" .format(
92+ it.longitudeStart,
93+ it.longitudeEnd,
94+ it.latitudeEnd,
95+ it.latitudeStart
96+ )
97+ canvas.drawText(
98+ text,
99+ width - 2 * padding,
100+ topCoordinate + textSize / 1.2f * SMALL_TEXT_SCALE ,
101+ textPaint
102+ )
103+ topCoordinate + = (textSize + padding) * SMALL_TEXT_SCALE
104+
105+ val xdelta = it.longitudeEnd - it.longitudeStart
106+ val ydelta = it.latitudeStart - it.latitudeEnd
107+ val text2 = " %.1f %.1f" .format(
108+ xdelta,
109+ ydelta,
110+ )
111+ canvas.drawText(
112+ text2,
113+ width - 2 * padding,
114+ topCoordinate + textSize / 1.2f * SMALL_TEXT_SCALE ,
115+ textPaint
116+ )
117+ topCoordinate + = (textSize + padding) * SMALL_TEXT_SCALE
118+
119+ val x0 = it.longitudeStart
120+ val y0 = it.latitudeStart
121+
122+ val xs = xdelta / (width - 2 * padding)
123+ val ys = ydelta / (height - 2 * padding)
124+
125+ mapArea?.let {
126+ val x1 = padding + ((it.lonEast - x0) / xs).toFloat()
127+ val x2 = padding + ((it.lonWest - x0) / xs).toFloat()
128+ val y1 = padding + ((y0 - it.latNorth) / ys).toFloat()
129+ val y2 = padding + ((y0 - it.latSouth) / ys).toFloat()
130+
131+ foregroundPaint.strokeWidth = 1f
132+ drawBox(canvas, x1, y1, x2, y2, foregroundPaint);
133+ }
134+ topCoordinate + = textSize
135+
136+ foregroundPaint.strokeWidth = 3f
137+ foregroundPaint.color = defaultForegroundColor
138+ drawBox(canvas, padding, padding, width - padding, height - padding, foregroundPaint)
139+ }
140+
141+ zoomLevel?.let {
142+ val text = " Zoom %.1f" .format(it )
143+ canvas.drawText(
144+ text,
145+ width - 2 * padding,
146+ height - 2 * padding ,
147+ textPaint
148+ )
149+ }
150+ }
151+ }
152+
153+ private fun drawBox (
154+ canvas : Canvas ,
155+ x1 : Float ,
156+ y1 : Float ,
157+ x2 : Float ,
158+ y2 : Float ,
159+ paint : Paint
160+ ) {
161+ canvas.drawLine(x1, y2, x2, y2, paint)
162+ canvas.drawLine(x1, y1, x2, y1, paint)
163+ canvas.drawLine(x2, y1, x2, y2, paint)
164+ canvas.drawLine(x1, y1, x1, y2, paint)
165+ }
166+
167+
168+ private fun updateHistogram (dataEvent : ResultEvent ) {
169+ if (dataEvent.failed) {
170+ visibility = INVISIBLE
171+ gridParameters = null
172+ } else {
173+ gridParameters = dataEvent.gridParameters
174+
175+ invalidate()
176+ }
177+ }
178+
179+ private fun isVisible (gridParameters : GridParameters ? ) = gridParameters != null && ! gridParameters.isGlobal
180+ override fun onScroll (event : ScrollEvent ? ): Boolean {
181+ return if (event != null ) {
182+ this .mapArea = event.source.boundingBox
183+ zoomLevel = event.source.zoomLevelDouble
184+ updateViewSize()
185+ true
186+ } else {
187+ false
188+ }
189+ }
190+
191+ override fun onZoom (event : ZoomEvent ? ): Boolean {
192+ return if (event != null ) {
193+ mapArea = event.source.boundingBox
194+ zoomLevel = event.zoomLevel
195+ updateViewSize()
196+ true
197+ } else {
198+ false
199+ }
200+ }
201+
202+ private fun updateViewSize () {
203+ mapArea?.let {
204+ val lonDelta = it.lonEast - it.lonWest
205+ val pixelSize = lonDelta / width
206+ val latDelta = it.latNorth - it.latSouth
207+ val height = Math .max((latDelta / pixelSize).toInt(), (3 * padding + 3 * textSize).toInt())
208+ layoutParams.height= height
209+ invalidate()
210+ }
211+ }
212+
213+ override fun onSharedPreferenceChanged (
214+ sharedPreferences : SharedPreferences ,
215+ key : PreferenceKey
216+ ) {
217+ when (key) {
218+ PreferenceKey .DIAGNOSIS_ENABLED -> {
219+ val diagnosisEnabled = sharedPreferences.get(key, false )
220+ visibility = if (diagnosisEnabled) {
221+ VISIBLE
222+ } else {
223+ INVISIBLE
224+ }
225+ }
226+
227+ else -> {}
228+ }
229+ }
230+
231+ }
0 commit comments