@@ -40,6 +40,7 @@ import androidx.compose.runtime.remember
4040import androidx.compose.runtime.saveable.listSaver
4141import androidx.compose.runtime.saveable.rememberSaveable
4242import androidx.compose.runtime.setValue
43+ import androidx.compose.runtime.snapshots.SnapshotStateList
4344import androidx.compose.runtime.toMutableStateList
4445import androidx.compose.ui.Alignment
4546import androidx.compose.ui.Modifier
@@ -70,6 +71,7 @@ import org.meshtastic.feature.settings.radio.channel.component.ChannelCard
7071import org.meshtastic.feature.settings.radio.channel.component.ChannelConfigHeader
7172import org.meshtastic.feature.settings.radio.channel.component.ChannelLegend
7273import org.meshtastic.feature.settings.radio.channel.component.ChannelLegendDialog
74+ import org.meshtastic.feature.settings.radio.channel.component.ChannelPskEditState
7375import org.meshtastic.feature.settings.radio.channel.component.EditChannelDialog
7476import org.meshtastic.feature.settings.radio.component.LoadingOverlay
7577import org.meshtastic.feature.settings.radio.component.PacketResponseStateDialog
@@ -122,12 +124,17 @@ private fun ChannelConfigScreen(
122124 rememberSaveable(saver = listSaver(save = { it.toList() }, restore = { it.toMutableStateList() })) {
123125 settingsList.toMutableStateList()
124126 }
127+ val pskEditStatesInput =
128+ rememberSaveable(saver = channelPskEditStatesSaver) {
129+ List (settingsListInput.size) { ChannelPskEditState () }.toMutableStateList()
130+ }
125131
126132 val listState = rememberLazyListState()
127133 val dragDropState =
128134 rememberDragDropState(listState) { fromIndex, toIndex ->
129135 if (toIndex in settingsListInput.indices && fromIndex in settingsListInput.indices) {
130- settingsListInput.apply { add(toIndex, removeAt(fromIndex)) }
136+ settingsListInput.move(fromIndex, toIndex)
137+ pskEditStatesInput.move(fromIndex, toIndex)
131138 }
132139 }
133140
@@ -143,11 +150,14 @@ private fun ChannelConfigScreen(
143150 EditChannelDialog (
144151 channelSettings = settingsListInput.getOrNull(index) ? : ChannelSettings (),
145152 modemPresetName = modemPresetName,
146- onAddClick = {
153+ initialPskEditState = pskEditStatesInput.getOrElse(index) { ChannelPskEditState () },
154+ onAddClick = { settings, pskEditState ->
147155 if (settingsListInput.size > index) {
148- settingsListInput[index] = it
156+ settingsListInput[index] = settings
157+ pskEditStatesInput[index] = pskEditState
149158 } else {
150- settingsListInput.add(it)
159+ settingsListInput.add(settings)
160+ pskEditStatesInput.add(pskEditState)
151161 }
152162 showEditChannelDialog = null
153163 },
@@ -176,7 +186,8 @@ private fun ChannelConfigScreen(
176186 FloatingActionButton (
177187 onClick = {
178188 if (maxChannels > settingsListInput.size) {
179- settingsListInput.add(ChannelSettings (psk = Channel .default.settings.psk))
189+ settingsListInput.add(Channel .default.settings)
190+ pskEditStatesInput.add(ChannelPskEditState (canGeneratePskForName = true ))
180191 showEditChannelDialog = settingsListInput.lastIndex
181192 }
182193 },
@@ -231,7 +242,10 @@ private fun ChannelConfigScreen(
231242 channelSettings = channel,
232243 loraConfig = loraConfig,
233244 onEditClick = { showEditChannelDialog = index },
234- onDeleteClick = { settingsListInput.removeAt(index) },
245+ onDeleteClick = {
246+ settingsListInput.removeAt(index)
247+ pskEditStatesInput.removeAt(index)
248+ },
235249 sharesLocation = locationChannel == index,
236250 )
237251 }
@@ -242,13 +256,16 @@ private fun ChannelConfigScreen(
242256 negativeText = stringResource(Res .string.cancel),
243257 onNegativeClicked = {
244258 focusManager.clearFocus()
245- settingsListInput.clear( )
246- settingsListInput.addAll (settingsList)
259+ settingsListInput.replaceWith(settingsList )
260+ pskEditStatesInput.replaceAll (settingsList.size, ChannelPskEditState () )
247261 },
248262 positiveText = stringResource(Res .string.send),
249263 onPositiveClicked = {
250264 focusManager.clearFocus()
251- onPositiveClicked(settingsListInput)
265+ val committedSettings = settingsListInput.toList()
266+ onPositiveClicked(committedSettings)
267+ settingsListInput.replaceWith(committedSettings)
268+ pskEditStatesInput.replaceAll(committedSettings.size, ChannelPskEditState ())
252269 },
253270 )
254271 }
@@ -273,6 +290,44 @@ private fun ChannelConfigScreen(
273290 }
274291}
275292
293+ private val channelPskEditStatesSaver =
294+ listSaver<SnapshotStateList <ChannelPskEditState >, Int > (
295+ save = { states -> states.map { it.toSaveableFlags() } },
296+ restore = { flags -> flags.map { it.toChannelPskEditState() }.toMutableStateList() },
297+ )
298+
299+ internal fun <T > MutableList<T>.move (fromIndex : Int , toIndex : Int ) {
300+ add(toIndex, removeAt(fromIndex))
301+ }
302+
303+ internal fun <T > MutableList<T>.replaceWith (values : List <T >) {
304+ clear()
305+ addAll(values)
306+ }
307+
308+ internal fun MutableList<ChannelPskEditState>.replaceAll (size : Int , value : ChannelPskEditState ) {
309+ clear()
310+ repeat(size) { add(value) }
311+ }
312+
313+ internal fun ChannelPskEditState.toSaveableFlags (): Int {
314+ var flags = 0
315+ if (canGeneratePskForName) flags = flags or CAN_GENERATE_PSK_FOR_NAME_FLAG
316+ if (generatedPskForName) flags = flags or GENERATED_PSK_FOR_NAME_FLAG
317+ if (pskExplicitlyEdited) flags = flags or PSK_EXPLICITLY_EDITED_FLAG
318+ return flags
319+ }
320+
321+ internal fun Int.toChannelPskEditState (): ChannelPskEditState = ChannelPskEditState (
322+ canGeneratePskForName = this and CAN_GENERATE_PSK_FOR_NAME_FLAG != 0 ,
323+ generatedPskForName = this and GENERATED_PSK_FOR_NAME_FLAG != 0 ,
324+ pskExplicitlyEdited = this and PSK_EXPLICITLY_EDITED_FLAG != 0 ,
325+ )
326+
327+ private const val CAN_GENERATE_PSK_FOR_NAME_FLAG = 1
328+ private const val GENERATED_PSK_FOR_NAME_FLAG = 1 shl 1
329+ private const val PSK_EXPLICITLY_EDITED_FLAG = 1 shl 2
330+
276331/* *
277332 * Determines what [Channel] if any is enabled to conduct automatic location sharing.
278333 *
0 commit comments