diff --git a/app/build.gradle b/app/build.gradle index c2616ce5b..c50e6d23c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,8 +28,8 @@ android { applicationId "com.geeksville.mesh" minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works) targetSdkVersion 29 - versionCode 10901 // format is Mmmss (where M is 1+the numeric major number - versionName "0.9.01" + versionCode 10902 // format is Mmmss (where M is 1+the numeric major number + versionName "0.9.02" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -112,7 +112,7 @@ dependencies { implementation 'androidx.fragment:fragment-ktx:1.2.5' implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.recyclerview:recyclerview:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta8' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0-rc1' implementation 'com.google.android.material:material:1.2.0-rc01' implementation 'androidx.viewpager2:viewpager2:1.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 787784e77..de99050b4 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -750,7 +750,7 @@ class MainActivity : AppCompatActivity(), Logging, // Init our messages table with the service's record of past text messages val msgs = service.oldMessages debug("Service provided ${msgs.size} messages") - model.messagesState.messages.value = msgs + model.messagesState.setMessages(msgs) val connectionState = MeshService.ConnectionState.valueOf(service.connectionState()) diff --git a/app/src/main/java/com/geeksville/mesh/model/Channel.kt b/app/src/main/java/com/geeksville/mesh/model/Channel.kt index 05735ad42..745fe2853 100644 --- a/app/src/main/java/com/geeksville/mesh/model/Channel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/Channel.kt @@ -8,6 +8,7 @@ import com.google.zxing.BarcodeFormat import com.google.zxing.MultiFormatWriter import com.journeyapps.barcodescanner.BarcodeEncoder import java.net.MalformedURLException +import kotlin.experimental.xor /** 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() } @@ -52,6 +53,17 @@ data class Channel( val name: String get() = settings.name val modemConfig: MeshProtos.ChannelSettings.ModemConfig get() = settings.modemConfig + /** + * Return a name that is formatted as #channename-suffix + * + * Where suffix indicates the hash of the PSK + */ + val humanName: String + get() { + val code = settings.psk.fold(0.toByte(), { acc, x -> acc xor x }) + return "#${settings.name}-${'A' + (code % 26)}" + } + /// Can this channel be changed right now? var editable = false diff --git a/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt b/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt index a69541dd2..5400937c0 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MessagesState.kt @@ -20,40 +20,44 @@ class MessagesState(private val ui: UIViewModel) : Logging { ) ) + /// This is the inner storage for messages + private val messagesList = (if (isEmulator) testTexts else emptyList()).toMutableList() + // If the following (unused otherwise) line is commented out, the IDE preview window works. // if left in the preview always renders as empty. val messages = - object : MutableLiveData>(if (isEmulator) testTexts else emptyList()) { + object : MutableLiveData>(messagesList) { } + fun setMessages(m: List) { + messagesList.clear() + messagesList.addAll(m) + messages.value = messagesList + } + /// add a message our GUI list of past msgs fun addMessage(m: DataPacket) { debug("Adding message to view id=${m.id}") // FIXME - don't just slam in a new list each time, it probably causes extra drawing. - // FIXME - possible kotlin bug in 1.3.72 - it seems that if we start with the (globally shared) emptyList, - // then adding items are affecting that shared list rather than a copy. This was causing aliasing of - // recentDataPackets with messages.value in the GUI. So if the current list is empty we are careful to make a new list - messages.value = if (messages.value.isNullOrEmpty()) - listOf(m) - else - messages.value!! + m + messagesList.add(m) + + messages.value = messagesList } fun updateStatus(id: Int, status: MessageStatus) { // Super inefficent but this is rare debug("Handling message status change $id: $status") - val msgs = messages.value!! - msgs.find { it.id == id }?.let { p -> + messagesList.find { it.id == id }?.let { p -> // Note: it seems that the service is keeping only a reference to our original packet (so it has already updated p.status) // This seems to be an AIDL optimization when both the service and the client are in the same process. But we still want to trigger // a GUI update // if (p.status != status) { p.status = status // Trigger an expensive complete redraw FIXME - messages.value = msgs + messages.value = messagesList // } } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt index a17d978f1..63b9b28ee 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt @@ -77,7 +77,7 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { if (channel != null) { qrView.visibility = View.VISIBLE channelNameEdit.visibility = View.VISIBLE - channelNameEdit.setText(channel.name) + channelNameEdit.setText(channel.humanName) // For now, we only let the user edit/save channels while the radio is awake - because the service // doesn't cache radioconfig writes. @@ -134,7 +134,12 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { } editableCheckbox.setOnCheckedChangeListener { _, checked -> - if (!checked) { + if (checked) { + // User just unlocked for editing - remove the # goo around the channel name + UIViewModel.getChannel(model.radioConfig.value)?.let { channel -> + channelNameEdit.setText(channel.name) + } + } else { // User just locked it, we should warn and then apply changes to radio MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.change_channel) @@ -177,7 +182,7 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { // Since we are writing to radioconfig, that will trigger the rest of the GUI update (QR code etc) } catch (ex: RemoteException) { errormsg("ignoring channel problem", ex) - + setGUIfromModel() // Throw away user edits // Tell the user to try again