map fragment kinda works

pull/12/head
geeksville 2020-04-07 11:27:51 -07:00
rodzic 5403b15044
commit 58e6f840ea
5 zmienionych plików z 157 dodań i 166 usunięć

Wyświetl plik

@ -12,18 +12,16 @@ import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.*
import android.widget.FrameLayout
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.Composable
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.ui.core.setContent
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.geeksville.android.GeeksvilleApplication
import com.geeksville.android.Logging
import com.geeksville.android.ServiceClient
import com.geeksville.mesh.model.MessagesState
@ -92,50 +90,6 @@ eventually:
val utf8 = Charset.forName("UTF-8")
fun androidx.fragment.app.Fragment.setComposable(
id: Int,
content: @Composable() () -> Unit
): View? =
context?.let {
FrameLayout(it).apply {
this.id =
id // Compose requires a unique ID for the containing view to make savedInstanceState work
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
setContent(content)
}
}
/**
* A fragment that represents a current 'screen' in our app.
*
* Useful for tracking analytics
*/
open class ScreenFragment(private val screenName: String) : Fragment() {
override fun onResume() {
super.onResume()
GeeksvilleApplication.analytics.sendScreenView(screenName)
}
override fun onPause() {
GeeksvilleApplication.analytics.endScreenView()
super.onPause()
}
}
class ComposeFragment(screenName: String, id: Int, private val content: @Composable() () -> Unit) :
ScreenFragment(screenName),
Logging {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? =
setComposable(id, content)
}
class MainActivity : AppCompatActivity(), Logging,
ActivityCompat.OnRequestPermissionsResultCallback {
@ -195,7 +149,8 @@ class MainActivity : AppCompatActivity(), Logging,
TabInfo(
"Map",
R.drawable.ic_twotone_map_24,
ComposeFragment("Map", 5) { MapContent() })
MapFragment()
)
)
private

Wyświetl plik

@ -0,0 +1,38 @@
package com.geeksville.mesh.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.compose.Composable
import androidx.ui.core.setContent
import com.geeksville.android.Logging
fun androidx.fragment.app.Fragment.setComposable(
id: Int,
content: @Composable() () -> Unit
): View? =
context?.let {
FrameLayout(it).apply {
this.id =
id // Compose requires a unique ID for the containing view to make savedInstanceState work
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
setContent(content)
}
}
class ComposeFragment(screenName: String, id: Int, private val content: @Composable() () -> Unit) :
ScreenFragment(screenName),
Logging {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? =
setComposable(id, content)
}

Wyświetl plik

@ -1,15 +1,10 @@
package com.geeksville.mesh.ui
import android.app.Activity
import android.app.Application
import android.graphics.Color
import android.os.Bundle
import androidx.compose.Composable
import androidx.compose.onCommit
import androidx.ui.core.ContextAmbient
import androidx.ui.fakeandroidview.AndroidView
import androidx.ui.material.MaterialTheme
import androidx.ui.tooling.preview.Preview
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.geeksville.android.Logging
import com.geeksville.mesh.R
import com.geeksville.mesh.model.NodeDB
@ -32,114 +27,65 @@ import com.mapbox.mapboxsdk.style.layers.SymbolLayer
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
object mapLog : Logging
class MapFragment : ScreenFragment("Map"), Logging {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.map_view, container, false)
lateinit var mapView: MapView
/**
* mapbox requires this, until compose has a nicer way of doing it, do it here
*/
private val mapLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks {
var view: MapView? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
override fun onActivityPaused(activity: Activity) {
view?.onPause()
}
mapView = view.findViewById(R.id.mapView)
mapView.onCreate(UIState.savedInstanceState)
override fun onActivityStarted(activity: Activity) {
view?.onStart()
}
mapView.getMapAsync { map ->
override fun onActivityDestroyed(activity: Activity) {
view?.onDestroy()
}
// Find all nodes with valid locations
val nodesWithPosition = NodeDB.nodes.values.filter { it.validPosition != null }
val locations = nodesWithPosition.map { node ->
val p = node.position!!
debug("Showing on map: $node")
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
view?.onSaveInstanceState(outState)
}
val f = Feature.fromGeometry(
Point.fromLngLat(
p.longitude,
p.latitude
)
)
node.user?.let {
f.addStringProperty("name", it.longName)
}
f
}
val nodeSourceId = "node-positions"
val nodeLayerId = "node-layer"
val labelLayerId = "label-layer"
val markerImageId = "my-marker-image"
val nodePositions =
GeoJsonSource(nodeSourceId, FeatureCollection.fromFeatures(locations))
override fun onActivityStopped(activity: Activity) {
view?.onStop()
}
// val markerIcon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_twotone_person_pin_24)
val markerIcon = activity!!.getDrawable(R.drawable.ic_twotone_person_pin_24)!!
/**
* Called when the Activity calls [super.onCreate()][Activity.onCreate].
*/
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
}
override fun onActivityResumed(activity: Activity) {
view?.onResume()
}
}
@Composable
fun MapContent() {
val context = ContextAmbient.current
// FIXME - remove onCommit
onCommit() {
onDispose {
// We no longer care about activity lifecycle
(context.applicationContext as Application).unregisterActivityLifecycleCallbacks(
mapLifecycleCallbacks
val nodeLayer = SymbolLayer(nodeLayerId, nodeSourceId).withProperties(
iconImage(markerImageId),
iconAnchor(Property.ICON_ANCHOR_BOTTOM),
iconAllowOverlap(true)
)
mapLifecycleCallbacks.view = null
}
}
// Find all nodes with valid locations
val nodesWithPosition = NodeDB.nodes.values.filter { it.validPosition != null }
val locations = nodesWithPosition.map { node ->
val p = node.position!!
mapLog.debug("Showing on map: $node")
val f = Feature.fromGeometry(
Point.fromLngLat(
p.longitude,
p.latitude
val labelLayer = SymbolLayer(labelLayerId, nodeSourceId).withProperties(
textField(Expression.get("name")),
textSize(12f),
textColor(Color.RED),
textVariableAnchor(arrayOf(TEXT_ANCHOR_TOP)),
textJustify(TEXT_JUSTIFY_AUTO),
textAllowOverlap(true)
)
)
node.user?.let {
f.addStringProperty("name", it.longName)
}
f
}
val nodeSourceId = "node-positions"
val nodeLayerId = "node-layer"
val labelLayerId = "label-layer"
val markerImageId = "my-marker-image"
val nodePositions =
GeoJsonSource(nodeSourceId, FeatureCollection.fromFeatures(locations))
// val markerIcon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_twotone_person_pin_24)
val markerIcon = context.getDrawable(R.drawable.ic_twotone_person_pin_24)!!
val nodeLayer = SymbolLayer(nodeLayerId, nodeSourceId).withProperties(
iconImage(markerImageId),
iconAnchor(Property.ICON_ANCHOR_BOTTOM),
iconAllowOverlap(true)
)
val labelLayer = SymbolLayer(labelLayerId, nodeSourceId).withProperties(
textField(Expression.get("name")),
textSize(12f),
textColor(Color.RED),
textVariableAnchor(arrayOf(TEXT_ANCHOR_TOP)),
textJustify(TEXT_JUSTIFY_AUTO),
textAllowOverlap(true)
)
AndroidView(R.layout.map_view) { view ->
view as MapView
view.onCreate(UIState.savedInstanceState)
mapLifecycleCallbacks.view = view
(context.applicationContext as Application).registerActivityLifecycleCallbacks(
mapLifecycleCallbacks
)
view.getMapAsync { map ->
map.setStyle(Style.OUTDOORS) { style ->
style.addSource(nodePositions)
style.addImage(markerImageId, markerIcon)
@ -173,14 +119,38 @@ fun MapContent() {
}
}
}
}
override fun onPause() {
mapView.onPause()
super.onPause()
}
@Preview
@Composable
fun previewMap() {
// another bug? It seems modaldrawerlayout not yet supported in preview
MaterialTheme(colors = palette) {
MapContent()
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onStop() {
mapView.onStop()
super.onStop()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onDestroy() {
mapView.onDestroy()
super.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle) {
mapView.onSaveInstanceState(outState)
super.onSaveInstanceState(outState)
}
}

Wyświetl plik

@ -0,0 +1,21 @@
package com.geeksville.mesh.ui
import androidx.fragment.app.Fragment
import com.geeksville.android.GeeksvilleApplication
/**
* A fragment that represents a current 'screen' in our app.
*
* Useful for tracking analytics
*/
open class ScreenFragment(private val screenName: String) : Fragment() {
override fun onResume() {
super.onResume()
GeeksvilleApplication.analytics.sendScreenView(screenName)
}
override fun onPause() {
GeeksvilleApplication.analytics.endScreenView()
super.onPause()
}
}

Wyświetl plik

@ -1,10 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<com.mapbox.mapboxsdk.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
mapbox:mapbox_uiZoomGestures="true"
mapbox:mapbox_uiScrollGestures="true"></com.mapbox.mapboxsdk.maps.MapView>
android:id="@+id/mapFrame"> <!-- tab layout requires a unique ID -->
<com.mapbox.mapboxsdk.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
mapbox:mapbox_uiZoomGestures="true"
mapbox:mapbox_uiScrollGestures="true"></com.mapbox.mapboxsdk.maps.MapView>
</FrameLayout>