mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
76 lines
2.9 KiB
Kotlin
76 lines
2.9 KiB
Kotlin
|
|
package com.geeksville.mesh.model
|
||
|
|
|
||
|
|
import android.graphics.Bitmap
|
||
|
|
import android.net.Uri
|
||
|
|
import android.util.Base64
|
||
|
|
import com.geeksville.mesh.AppOnlyProtos
|
||
|
|
import com.geeksville.mesh.MeshProtos
|
||
|
|
import com.google.protobuf.ByteString
|
||
|
|
import com.google.zxing.BarcodeFormat
|
||
|
|
import com.google.zxing.MultiFormatWriter
|
||
|
|
import com.journeyapps.barcodescanner.BarcodeEncoder
|
||
|
|
import java.net.MalformedURLException
|
||
|
|
|
||
|
|
/** Utility function to make it easy to declare byte arrays - FIXME move someplace better */
|
||
|
|
fun byteArrayOfInts(vararg ints: Int) = ByteArray(ints.size) { pos -> ints[pos].toByte() }
|
||
|
|
|
||
|
|
|
||
|
|
data class ChannelSet(
|
||
|
|
val protobuf: AppOnlyProtos.ChannelSet = AppOnlyProtos.ChannelSet.getDefaultInstance()
|
||
|
|
) {
|
||
|
|
companion object {
|
||
|
|
|
||
|
|
// Placeholder when emulating
|
||
|
|
val emulated = ChannelSet(
|
||
|
|
AppOnlyProtos.ChannelSet.newBuilder().addSettings(Channel.emulated.settings).build()
|
||
|
|
)
|
||
|
|
|
||
|
|
const val prefix = "https://www.meshtastic.org/d/#"
|
||
|
|
|
||
|
|
private const val base64Flags = Base64.URL_SAFE + Base64.NO_WRAP + Base64.NO_PADDING
|
||
|
|
|
||
|
|
private fun urlToChannels(url: Uri): AppOnlyProtos.ChannelSet {
|
||
|
|
val urlStr = url.toString()
|
||
|
|
|
||
|
|
// We no longer support the super old (about 0.8ish? verison of the URLs that don't use the # separator - I doubt
|
||
|
|
// anyone is still using that old format
|
||
|
|
val pathRegex = Regex("$prefix(.*)", RegexOption.IGNORE_CASE)
|
||
|
|
val (base64) = pathRegex.find(urlStr)?.destructured
|
||
|
|
?: throw MalformedURLException("Not a meshtastic URL: ${urlStr.take(40)}")
|
||
|
|
val bytes = Base64.decode(base64, base64Flags)
|
||
|
|
|
||
|
|
return AppOnlyProtos.ChannelSet.parseFrom(bytes)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
constructor(url: Uri) : this(urlToChannels(url))
|
||
|
|
|
||
|
|
/// Can this channel be changed right now?
|
||
|
|
var editable = false
|
||
|
|
|
||
|
|
/// Return an URL that represents the current channel values
|
||
|
|
/// @param upperCasePrefix - portions of the URL can be upper case to make for more efficient QR codes
|
||
|
|
fun getChannelUrl(upperCasePrefix: Boolean = false): Uri {
|
||
|
|
// If we have a valid radio config use it, othterwise use whatever we have saved in the prefs
|
||
|
|
|
||
|
|
val channelBytes = protobuf.toByteArray() ?: ByteArray(0) // if unset just use empty
|
||
|
|
val enc = Base64.encodeToString(channelBytes, base64Flags)
|
||
|
|
|
||
|
|
val p = if(upperCasePrefix)
|
||
|
|
prefix.toUpperCase()
|
||
|
|
else
|
||
|
|
prefix
|
||
|
|
return Uri.parse("$p$enc")
|
||
|
|
}
|
||
|
|
|
||
|
|
fun getChannelQR(): Bitmap {
|
||
|
|
val multiFormatWriter = MultiFormatWriter()
|
||
|
|
|
||
|
|
// We encode as UPPER case for the QR code URL because QR codes are more efficient for that special case
|
||
|
|
val bitMatrix =
|
||
|
|
multiFormatWriter.encode(getChannelUrl(true).toString(), BarcodeFormat.QR_CODE, 192, 192);
|
||
|
|
val barcodeEncoder = BarcodeEncoder()
|
||
|
|
return barcodeEncoder.createBitmap(bitMatrix)
|
||
|
|
}
|
||
|
|
}
|