channel qrs are now sharable and real

1.2-legacy
Kevin Hester 2020-03-02 08:41:16 -08:00
rodzic 90cee2f202
commit 44ebac1758
4 zmienionych plików z 56 dodań i 28 usunięć

Wyświetl plik

@ -9,8 +9,6 @@ Work items for soon alpha builds
* fix app icon in title bar * fix app icon in title bar
* show direction on the nodeinfo cards * show direction on the nodeinfo cards
* take video of the app * take video of the app
* make channel button look like a button
* generate real channel QR codes
* register app link for our URLs https://developer.android.com/studio/write/app-link-indexing.html * register app link for our URLs https://developer.android.com/studio/write/app-link-indexing.html
* let users change & share channels (but no saving them yet) * let users change & share channels (but no saving them yet)
* treat macaddrs as the unique id, not the app layer user id * treat macaddrs as the unique id, not the app layer user id
@ -160,3 +158,5 @@ Don't leave device discoverable. Don't let unpaired users do things with device
* have notification (individually maskable) notifications for received texts - use file:///home/kevinh/packages/android-sdk-linux/docs/reference/android/support/v4/app/NotificationCompat.BigTextStyle.html * have notification (individually maskable) notifications for received texts - use file:///home/kevinh/packages/android-sdk-linux/docs/reference/android/support/v4/app/NotificationCompat.BigTextStyle.html
* startforegroundservice only if we have a valid radio * startforegroundservice only if we have a valid radio
* when we select a new radio, restart the service * when we select a new radio, restart the service
* make channel button look like a button
* generate real channel QR codes

Wyświetl plik

@ -179,7 +179,7 @@ class MainActivity : AppCompatActivity(), Logging,
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val prefs = getSharedPreferences("ui-prefs", Context.MODE_PRIVATE) val prefs = UIState.getPreferences(this)
UIState.ownerName = prefs.getString("owner", "")!! UIState.ownerName = prefs.getString("owner", "")!!
UIState.meshService = null UIState.meshService = null
@ -276,9 +276,9 @@ class MainActivity : AppCompatActivity(), Logging,
val bytes = UIState.meshService!!.radioConfig val bytes = UIState.meshService!!.radioConfig
val config = MeshProtos.RadioConfig.parseFrom(bytes) val config = MeshProtos.RadioConfig.parseFrom(bytes)
UIState.radioConfig.value = config UIState.setRadioConfig(this, config)
debug("Read config from radio, channel URL ${UIState.channelUrl}") debug("Read config from radio")
} }
/// Called when we gain/lose a connection to our mesh radio /// Called when we gain/lose a connection to our mesh radio

Wyświetl plik

@ -1,6 +1,7 @@
package com.geeksville.mesh.model package com.geeksville.mesh.model
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.RemoteException import android.os.RemoteException
import android.util.Base64 import android.util.Base64
@ -26,7 +27,7 @@ object UIState : Logging {
val isConnected = mutableStateOf(false) val isConnected = mutableStateOf(false)
/// various radio settings (including the channel) /// various radio settings (including the channel)
val radioConfig = mutableStateOf(MeshProtos.RadioConfig.getDefaultInstance()) private val radioConfig = mutableStateOf<MeshProtos.RadioConfig?>(null)
/// our name in hte radio /// our name in hte radio
/// Note, we generate owner initials automatically for now /// Note, we generate owner initials automatically for now
@ -34,22 +35,44 @@ object UIState : Logging {
var ownerName: String = "MrInIDE Ownername" var ownerName: String = "MrInIDE Ownername"
/// Return an URL that represents the current channel values /// Return an URL that represents the current channel values
val channelUrl fun getChannelUrl(context: Context): String {
get(): String { // If we have a valid radio config use it, othterwise use whatever we have saved in the prefs
val channelBytes = radioConfig.value.channelSettings.toByteArray() val radio = radioConfig.value
if (radio != null) {
val settings = radio.channelSettings
val channelBytes = settings.toByteArray()
val enc = Base64.encodeToString(channelBytes, Base64.URL_SAFE + Base64.NO_WRAP) val enc = Base64.encodeToString(channelBytes, Base64.URL_SAFE + Base64.NO_WRAP)
return "https://www.meshtastic.org/c/$enc" return "https://www.meshtastic.org/c/$enc"
} else {
return getPreferences(context).getString(
"owner",
"https://www.meshtastic.org/c/unset"
)!!
} }
}
val channelQR fun getChannelQR(context: Context): Bitmap
get(): Bitmap { {
val multiFormatWriter = MultiFormatWriter() val multiFormatWriter = MultiFormatWriter()
val bitMatrix = multiFormatWriter.encode(channelUrl, BarcodeFormat.QR_CODE, 192, 192); val bitMatrix =
val barcodeEncoder = BarcodeEncoder() multiFormatWriter.encode(getChannelUrl(context), BarcodeFormat.QR_CODE, 192, 192);
return barcodeEncoder.createBitmap(bitMatrix) val barcodeEncoder = BarcodeEncoder()
return barcodeEncoder.createBitmap(bitMatrix)
}
fun getPreferences(context: Context): SharedPreferences =
context.getSharedPreferences("ui-prefs", Context.MODE_PRIVATE)
/// Set the radio config (also updates our saved copy in preferences)
fun setRadioConfig(context: Context, c: MeshProtos.RadioConfig) {
radioConfig.value = c
getPreferences(context).edit(commit = true) {
this.putString("channel-url", getChannelUrl(context))
} }
}
// clean up all this nasty owner state management FIXME // clean up all this nasty owner state management FIXME
fun setOwner(context: Context, s: String? = null) { fun setOwner(context: Context, s: String? = null) {
@ -58,8 +81,7 @@ object UIState : Logging {
ownerName = s ownerName = s
// note: we allow an empty userstring to be written to prefs // note: we allow an empty userstring to be written to prefs
val prefs = context.getSharedPreferences("ui-prefs", Context.MODE_PRIVATE) getPreferences(context).edit(commit = true) {
prefs.edit(commit = true) {
putString("owner", s) putString("owner", s)
} }
} }

Wyświetl plik

@ -1,27 +1,24 @@
package com.geeksville.mesh.ui package com.geeksville.mesh.ui
import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Build
import androidx.compose.Composable import androidx.compose.Composable
import androidx.compose.ambient
import androidx.ui.core.ContextAmbient import androidx.ui.core.ContextAmbient
import androidx.ui.core.Text import androidx.ui.core.Text
import androidx.ui.foundation.Clickable
import androidx.ui.foundation.DrawImage import androidx.ui.foundation.DrawImage
import androidx.ui.graphics.* import androidx.ui.graphics.Image
import androidx.ui.graphics.ImageConfig
import androidx.ui.graphics.NativeImage
import androidx.ui.graphics.colorspace.ColorSpace import androidx.ui.graphics.colorspace.ColorSpace
import androidx.ui.graphics.colorspace.ColorSpaces import androidx.ui.graphics.colorspace.ColorSpaces
import androidx.ui.layout.* import androidx.ui.layout.*
import androidx.ui.material.Button
import androidx.ui.material.MaterialTheme import androidx.ui.material.MaterialTheme
import androidx.ui.material.OutlinedButton import androidx.ui.material.OutlinedButton
import androidx.ui.material.ripple.Ripple import androidx.ui.material.ripple.Ripple
import androidx.ui.res.imageResource
import androidx.ui.tooling.preview.Preview import androidx.ui.tooling.preview.Preview
import androidx.ui.unit.dp import androidx.ui.unit.dp
import com.geeksville.android.GeeksvilleApplication import com.geeksville.android.GeeksvilleApplication
import com.geeksville.android.Logging import com.geeksville.android.Logging
import com.geeksville.android.toast
import com.geeksville.mesh.R import com.geeksville.mesh.R
import com.geeksville.mesh.model.UIState import com.geeksville.mesh.model.UIState
@ -88,7 +85,7 @@ fun ChannelContent(channel: Channel = Channel("Default", 7)) {
Row(modifier = LayoutGravity.Center) { Row(modifier = LayoutGravity.Center) {
// simulated qr code // simulated qr code
// val image = imageResource(id = R.drawable.qrcode) // val image = imageResource(id = R.drawable.qrcode)
val image = AndroidImage(UIState.channelQR) val image = AndroidImage(UIState.getChannelQR(context))
Container(modifier = LayoutGravity.Center + LayoutSize.Min(200.dp, 200.dp)) { Container(modifier = LayoutGravity.Center + LayoutSize.Min(200.dp, 200.dp)) {
DrawImage(image = image) DrawImage(image = image)
@ -97,9 +94,18 @@ fun ChannelContent(channel: Channel = Channel("Default", 7)) {
Ripple(bounded = false) { Ripple(bounded = false) {
OutlinedButton(modifier = LayoutGravity.Center + LayoutPadding(left = 24.dp), OutlinedButton(modifier = LayoutGravity.Center + LayoutPadding(left = 24.dp),
onClick = { onClick = {
GeeksvilleApplication.analytics.track("channel_share") // track how many times users share channels GeeksvilleApplication.analytics.track("channel_share") // track how many times users share channels
context.toast("Channel sharing is not yet implemented")
}) { val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, UIState.getChannelUrl(context))
putExtra(Intent.EXTRA_TITLE, "A URL for joining a Meshtastic mesh")
type = "text/plain"
}
val shareIntent = Intent.createChooser(sendIntent, null)
context.startActivity(shareIntent)
}) {
VectorImage( VectorImage(
id = R.drawable.ic_twotone_share_24, id = R.drawable.ic_twotone_share_24,
tint = palette.onBackground tint = palette.onBackground