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) } }