kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
WIP is a little better
rodzic
9491a74fc6
commit
5403b15044
|
@ -21,9 +21,9 @@ import androidx.core.app.ActivityCompat
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.ui.core.setContent
|
||||
import androidx.ui.foundation.Text
|
||||
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
|
||||
|
@ -31,7 +31,7 @@ import com.geeksville.mesh.model.NodeDB
|
|||
import com.geeksville.mesh.model.TextMessage
|
||||
import com.geeksville.mesh.model.UIState
|
||||
import com.geeksville.mesh.service.*
|
||||
import com.geeksville.mesh.ui.ScanState
|
||||
import com.geeksville.mesh.ui.*
|
||||
import com.geeksville.util.Exceptions
|
||||
import com.geeksville.util.exceptionReporter
|
||||
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||
|
@ -109,23 +109,31 @@ fun androidx.fragment.app.Fragment.setComposable(
|
|||
}
|
||||
}
|
||||
|
||||
class ComposeFragment(id: Int, private val content: @Composable() () -> Unit) : Fragment(),
|
||||
/**
|
||||
* 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)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
debug("view w=${view.width}, h=${view.height}")
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
debug("view w=${view?.width}, h=${view?.height}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,9 +152,56 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
bluetoothManager.adapter
|
||||
}
|
||||
|
||||
private val tabsAdapter = object : FragmentStateAdapter(this) {
|
||||
/*
|
||||
<!-- Screen.messages -> MessagesContent()
|
||||
Screen.settings -> SettingsContent()
|
||||
Screen.users -> UsersContent()
|
||||
Screen.channel -> ChannelContent(UIState.getChannel())
|
||||
Screen.map -> MapContent() -->
|
||||
|
||||
override fun getItemCount(): Int = 2
|
||||
/--
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:icon="@drawable/ic_twotone_message_24"
|
||||
android:text="Messages"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:icon="@drawable/ic_twotone_settings_applications_24"
|
||||
android:text="Settings"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content" /> -->
|
||||
*/
|
||||
data class TabInfo(val text: String, val icon: Int, val content: Fragment)
|
||||
|
||||
// private val tabIndexes = generateSequence(0) { it + 1 } FIXME, instead do withIndex or zip? to get the ids below, also stop duplicating strings
|
||||
private val tabInfos = arrayOf(
|
||||
TabInfo(
|
||||
"Messages",
|
||||
R.drawable.ic_twotone_message_24,
|
||||
ComposeFragment("Messages", 1) { MessagesContent() }),
|
||||
TabInfo(
|
||||
"Settings",
|
||||
R.drawable.ic_twotone_settings_applications_24,
|
||||
ComposeFragment("Settings", 2) { SettingsContent() }),
|
||||
TabInfo(
|
||||
"Users",
|
||||
R.drawable.ic_twotone_people_24,
|
||||
ComposeFragment("Users", 3) { UsersContent() }),
|
||||
TabInfo(
|
||||
"Channel",
|
||||
R.drawable.ic_twotone_contactless_24,
|
||||
ComposeFragment("Channel", 4) { ChannelContent(UIState.getChannel()) }),
|
||||
TabInfo(
|
||||
"Map",
|
||||
R.drawable.ic_twotone_map_24,
|
||||
ComposeFragment("Map", 5) { MapContent() })
|
||||
)
|
||||
|
||||
private
|
||||
val tabsAdapter = object : FragmentStateAdapter(this) {
|
||||
|
||||
override fun getItemCount(): Int = tabInfos.size
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
// Return a NEW fragment instance in createFragment(int)
|
||||
|
@ -155,9 +210,7 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
// Our object is just an integer :-P
|
||||
putInt(ARG_OBJECT, position + 1)
|
||||
} */
|
||||
return ComposeFragment(position + 1) {
|
||||
Text("Jetpack Compose")
|
||||
}
|
||||
return tabInfos[position].content
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,7 +308,11 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, "Error - this app requires bluetooth", Toast.LENGTH_LONG)
|
||||
Toast.makeText(
|
||||
this,
|
||||
"Error - this app requires bluetooth",
|
||||
Toast.LENGTH_LONG
|
||||
)
|
||||
.show()
|
||||
}
|
||||
|
||||
|
@ -289,7 +346,8 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
val pager = findViewById<ViewPager2>(R.id.pager)
|
||||
pager.adapter = tabsAdapter
|
||||
TabLayoutMediator(tab_layout, pager) { tab, position ->
|
||||
tab.text = "OBJECT ${(position + 1)}"
|
||||
tab.text = tabInfos[position].text
|
||||
tab.icon = getDrawable(tabInfos[position].icon)
|
||||
}.attach()
|
||||
}
|
||||
|
||||
|
@ -323,7 +381,11 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
/**
|
||||
* Dispatch incoming result to the correct fragment.
|
||||
*/
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
override fun onActivityResult(
|
||||
requestCode: Int,
|
||||
resultCode: Int,
|
||||
data: Intent?
|
||||
) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
// Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
|
||||
|
@ -350,7 +412,8 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
} */
|
||||
}
|
||||
|
||||
private var receiverRegistered = false
|
||||
private
|
||||
var receiverRegistered = false
|
||||
|
||||
private fun registerMeshReceiver() {
|
||||
logAssert(!receiverRegistered)
|
||||
|
@ -418,57 +481,67 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
}
|
||||
}
|
||||
|
||||
private val meshServiceReceiver = object : BroadcastReceiver() {
|
||||
private
|
||||
val meshServiceReceiver = object : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) = exceptionReporter {
|
||||
debug("Received from mesh service $intent")
|
||||
override fun onReceive(context: Context, intent: Intent) =
|
||||
exceptionReporter {
|
||||
debug("Received from mesh service $intent")
|
||||
|
||||
when (intent.action) {
|
||||
MeshService.ACTION_NODE_CHANGE -> {
|
||||
val info: NodeInfo = intent.getParcelableExtra(EXTRA_NODEINFO)!!
|
||||
debug("UI nodechange $info")
|
||||
when (intent.action) {
|
||||
MeshService.ACTION_NODE_CHANGE -> {
|
||||
val info: NodeInfo =
|
||||
intent.getParcelableExtra(EXTRA_NODEINFO)!!
|
||||
debug("UI nodechange $info")
|
||||
|
||||
// We only care about nodes that have user info
|
||||
info.user?.id?.let {
|
||||
NodeDB.nodes[it] = info
|
||||
}
|
||||
}
|
||||
|
||||
MeshService.ACTION_RECEIVED_DATA -> {
|
||||
debug("TODO rxdata")
|
||||
val sender = intent.getStringExtra(EXTRA_SENDER)!!
|
||||
val payload = intent.getByteArrayExtra(EXTRA_PAYLOAD)!!
|
||||
val typ = intent.getIntExtra(EXTRA_TYP, -1)
|
||||
|
||||
when (typ) {
|
||||
MeshProtos.Data.Type.CLEAR_TEXT_VALUE -> {
|
||||
// FIXME - use the real time from the packet
|
||||
// FIXME - don't just slam in a new list each time, it probably causes extra drawing. Figure out how to be Compose smarter...
|
||||
val msg = TextMessage(sender, payload.toString(utf8))
|
||||
|
||||
MessagesState.addMessage(msg)
|
||||
// We only care about nodes that have user info
|
||||
info.user?.id?.let {
|
||||
NodeDB.nodes[it] = info
|
||||
}
|
||||
else -> TODO()
|
||||
}
|
||||
|
||||
MeshService.ACTION_RECEIVED_DATA -> {
|
||||
debug("TODO rxdata")
|
||||
val sender =
|
||||
intent.getStringExtra(EXTRA_SENDER)!!
|
||||
val payload =
|
||||
intent.getByteArrayExtra(EXTRA_PAYLOAD)!!
|
||||
val typ = intent.getIntExtra(EXTRA_TYP, -1)
|
||||
|
||||
when (typ) {
|
||||
MeshProtos.Data.Type.CLEAR_TEXT_VALUE -> {
|
||||
// FIXME - use the real time from the packet
|
||||
// FIXME - don't just slam in a new list each time, it probably causes extra drawing. Figure out how to be Compose smarter...
|
||||
val msg = TextMessage(
|
||||
sender,
|
||||
payload.toString(utf8)
|
||||
)
|
||||
|
||||
MessagesState.addMessage(msg)
|
||||
}
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
MeshService.ACTION_MESH_CONNECTED -> {
|
||||
val connected =
|
||||
MeshService.ConnectionState.valueOf(
|
||||
intent.getStringExtra(
|
||||
EXTRA_CONNECTED
|
||||
)!!
|
||||
)
|
||||
onMeshConnectionChanged(connected)
|
||||
}
|
||||
else -> TODO()
|
||||
}
|
||||
MeshService.ACTION_MESH_CONNECTED -> {
|
||||
val connected =
|
||||
MeshService.ConnectionState.valueOf(
|
||||
intent.getStringExtra(
|
||||
EXTRA_CONNECTED
|
||||
)!!
|
||||
)
|
||||
onMeshConnectionChanged(connected)
|
||||
}
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val mesh = object : ServiceClient<com.geeksville.mesh.IMeshService>({
|
||||
com.geeksville.mesh.IMeshService.Stub.asInterface(it)
|
||||
}) {
|
||||
private
|
||||
val mesh = object :
|
||||
ServiceClient<com.geeksville.mesh.IMeshService>({
|
||||
com.geeksville.mesh.IMeshService.Stub.asInterface(it)
|
||||
}) {
|
||||
override fun onConnected(service: com.geeksville.mesh.IMeshService) {
|
||||
UIState.meshService = service
|
||||
|
||||
|
@ -476,7 +549,8 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
registerMeshReceiver()
|
||||
|
||||
// We won't receive a notify for the initial state of connection, so we force an update here
|
||||
val connectionState = MeshService.ConnectionState.valueOf(service.connectionState())
|
||||
val connectionState =
|
||||
MeshService.ConnectionState.valueOf(service.connectionState())
|
||||
onMeshConnectionChanged(connectionState)
|
||||
|
||||
debug("connected to mesh service, isConnected=${UIState.isConnected.value}")
|
||||
|
@ -522,7 +596,8 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
|
||||
bindMeshService()
|
||||
|
||||
val bonded = RadioInterfaceService.getBondedDeviceAddress(this) != null
|
||||
val bonded =
|
||||
RadioInterfaceService.getBondedDeviceAddress(this) != null
|
||||
/* FIXME - not yet working
|
||||
if (!bonded)
|
||||
AppStatus.currentScreen = Screen.settings
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package com.geeksville.mesh.ui
|
||||
|
||||
import androidx.compose.Composable
|
||||
import androidx.compose.onCommit
|
||||
import com.geeksville.android.GeeksvilleApplication
|
||||
|
||||
/**
|
||||
* Track compose screen visibility
|
||||
*/
|
||||
/*
|
||||
@Composable
|
||||
fun analyticsScreen(name: String) {
|
||||
onCommit(AppStatus.currentScreen) {
|
||||
|
@ -16,4 +14,4 @@ fun analyticsScreen(name: String) {
|
|||
GeeksvilleApplication.analytics.endScreenView()
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
|
@ -1,21 +1,6 @@
|
|||
package com.geeksville.mesh.ui
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.Composable
|
||||
import androidx.ui.core.Modifier
|
||||
import androidx.ui.foundation.Text
|
||||
import androidx.ui.foundation.shape.corner.RoundedCornerShape
|
||||
import androidx.ui.graphics.Color
|
||||
import androidx.ui.layout.*
|
||||
import androidx.ui.material.Divider
|
||||
import androidx.ui.material.MaterialTheme
|
||||
import androidx.ui.material.Surface
|
||||
import androidx.ui.material.TextButton
|
||||
import androidx.ui.tooling.preview.Preview
|
||||
import androidx.ui.unit.dp
|
||||
import com.geeksville.mesh.R
|
||||
|
||||
|
||||
/*
|
||||
@Composable
|
||||
fun AppDrawer(
|
||||
currentScreen: ScreenInfo,
|
||||
|
@ -111,4 +96,4 @@ fun previewDrawer() {
|
|||
currentScreen = AppStatus.currentScreen,
|
||||
closeDrawer = { }
|
||||
)
|
||||
}
|
||||
} */
|
|
@ -73,8 +73,8 @@ fun BTScanScreen() {
|
|||
val bluetoothAdapter =
|
||||
(context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
|
||||
|
||||
analyticsScreen(name = "settings")
|
||||
onCommit(AppStatus.currentScreen) {
|
||||
// FIXME - remove onCommit now that we have a fragement to run in
|
||||
onCommit() {
|
||||
ScanState.debug("BTScan component active")
|
||||
ScanUIState.selectedMacAddr = RadioInterfaceService.getBondedDeviceAddress(context)
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ object ChannelLog : Logging
|
|||
|
||||
@Composable
|
||||
fun ChannelContent(channel: Channel?) {
|
||||
analyticsScreen(name = "channel")
|
||||
|
||||
val typography = MaterialTheme.typography
|
||||
val context = ContextAmbient.current
|
||||
|
|
|
@ -75,11 +75,10 @@ private val mapLifecycleCallbacks = object : Application.ActivityLifecycleCallba
|
|||
|
||||
@Composable
|
||||
fun MapContent() {
|
||||
analyticsScreen(name = "map")
|
||||
|
||||
val context = ContextAmbient.current
|
||||
|
||||
onCommit(AppStatus.currentScreen) {
|
||||
// FIXME - remove onCommit
|
||||
onCommit() {
|
||||
onDispose {
|
||||
// We no longer care about activity lifecycle
|
||||
(context.applicationContext as Application).unregisterActivityLifecycleCallbacks(
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
package com.geeksville.mesh.ui
|
||||
|
||||
import androidx.compose.Composable
|
||||
import androidx.compose.state
|
||||
import androidx.ui.foundation.Text
|
||||
import androidx.ui.material.*
|
||||
import androidx.ui.tooling.preview.Preview
|
||||
import androidx.ui.material.lightColorPalette
|
||||
import com.geeksville.android.Logging
|
||||
import com.geeksville.mesh.R
|
||||
import com.geeksville.mesh.model.UIState
|
||||
|
||||
|
||||
object UILog : Logging
|
||||
|
||||
val palette = lightColorPalette() // darkColorPalette()
|
||||
|
||||
/*
|
||||
@Composable
|
||||
fun MeshApp() {
|
||||
val (drawerState, onDrawerStateChange) = state { DrawerState.Closed }
|
||||
|
@ -73,3 +68,4 @@ private fun AppContent(openDrawer: () -> Unit) {
|
|||
}
|
||||
//}
|
||||
}
|
||||
*/
|
|
@ -67,8 +67,6 @@ fun MessageCard(msg: TextMessage, modifier: Modifier = Modifier.None) {
|
|||
|
||||
@Composable
|
||||
fun MessagesContent() {
|
||||
analyticsScreen(name = "messages")
|
||||
|
||||
Column(modifier = LayoutSize.Fill) {
|
||||
|
||||
val sidePad = 8.dp
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package com.geeksville.mesh.ui
|
||||
|
||||
import androidx.compose.Model
|
||||
import com.geeksville.mesh.R
|
||||
|
||||
|
||||
/*
|
||||
data class ScreenInfo(val icon: Int, val label: String)
|
||||
|
||||
// defines the screens we have in the app
|
||||
|
@ -28,3 +25,4 @@ object AppStatus {
|
|||
fun navigateTo(destination: ScreenInfo) {
|
||||
AppStatus.currentScreen = destination
|
||||
}
|
||||
*/
|
|
@ -27,8 +27,6 @@ fun getInitials(name: String): String {
|
|||
|
||||
@Composable
|
||||
fun UsersContent() {
|
||||
analyticsScreen(name = "users")
|
||||
|
||||
Column {
|
||||
Row {
|
||||
fun connected() = UIState.isConnected.value != MeshService.ConnectionState.DISCONNECTED
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
Screen.channel -> ChannelContent(UIState.getChannel())
|
||||
Screen.map -> MapContent() -->
|
||||
|
||||
/--
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:icon="@drawable/ic_twotone_message_24"
|
||||
android:text="Messages"
|
||||
|
@ -43,6 +45,7 @@
|
|||
android:text="Settings"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content" />
|
||||
-->
|
||||
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue