Skip to content

Commit 1641ea4

Browse files
committed
fix: back up empty groups and floating layouts in auto back up
1 parent e18aa39 commit 1641ea4

5 files changed

Lines changed: 186 additions & 153 deletions

File tree

app/src/main/java/io/github/sds100/keymapper/backup/BackupManager.kt

Lines changed: 119 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import io.github.sds100.keymapper.data.entities.FingerprintMapEntity
2626
import io.github.sds100.keymapper.data.entities.FloatingButtonEntity
2727
import io.github.sds100.keymapper.data.entities.FloatingButtonKeyEntity
2828
import io.github.sds100.keymapper.data.entities.FloatingLayoutEntity
29+
import io.github.sds100.keymapper.data.entities.FloatingLayoutEntityWithButtons
2930
import io.github.sds100.keymapper.data.entities.GroupEntity
3031
import io.github.sds100.keymapper.data.entities.KeyMapEntity
3132
import io.github.sds100.keymapper.data.entities.TriggerEntity
@@ -59,13 +60,11 @@ import io.github.sds100.keymapper.util.then
5960
import kotlinx.coroutines.CoroutineScope
6061
import kotlinx.coroutines.flow.Flow
6162
import kotlinx.coroutines.flow.MutableSharedFlow
62-
import kotlinx.coroutines.flow.collectLatest
63-
import kotlinx.coroutines.flow.drop
63+
import kotlinx.coroutines.flow.collect
64+
import kotlinx.coroutines.flow.combine
6465
import kotlinx.coroutines.flow.filterIsInstance
6566
import kotlinx.coroutines.flow.first
66-
import kotlinx.coroutines.flow.launchIn
6767
import kotlinx.coroutines.flow.map
68-
import kotlinx.coroutines.flow.onEach
6968
import kotlinx.coroutines.launch
7069
import kotlinx.coroutines.withContext
7170
import timber.log.Timber
@@ -128,39 +127,25 @@ class BackupManagerImpl(
128127
.get(Keys.automaticBackupLocation).map { it != null }
129128

130129
init {
131-
val doAutomaticBackup = MutableSharedFlow<AutomaticBackup>()
132-
133130
coroutineScope.launch {
134-
doAutomaticBackup.collectLatest { backupData ->
135-
if (!backupAutomatically.first()) return@collectLatest
136-
137-
val backupLocation = preferenceRepository.get(Keys.automaticBackupLocation).first()
138-
?: return@collectLatest
131+
combine(
132+
backupAutomatically,
133+
preferenceRepository.get(Keys.automaticBackupLocation),
134+
keyMapRepository.keyMapList.filterIsInstance<State.Data<List<KeyMapEntity>>>(),
135+
groupRepository.getAllGroups(),
136+
floatingLayoutRepository.layouts.filterIsInstance<State.Data<List<FloatingLayoutEntityWithButtons>>>(),
137+
) { backupAutomatically, location, keyMaps, groups, floatingLayouts ->
138+
if (!backupAutomatically) {
139+
return@combine
140+
}
139141

140-
val outputFile = fileAdapter.getFileFromUri(backupLocation)
141-
val result = backupAsync(outputFile, backupData.keyMapList)
142+
location ?: return@combine
142143

144+
val outputFile = fileAdapter.getFileFromUri(location)
145+
val result = backupAsync(outputFile, keyMaps.data, groups, floatingLayouts.data)
143146
onAutomaticBackupResult.emit(result)
144-
}
147+
}.collect()
145148
}
146-
147-
coroutineScope.launch {
148-
keyMapRepository.requestBackup.collectLatest { keyMapList ->
149-
val backupData = AutomaticBackup(keyMapList = keyMapList)
150-
151-
doAutomaticBackup.emit(backupData)
152-
}
153-
}
154-
155-
// automatically back up when the location changes
156-
preferenceRepository.get(Keys.automaticBackupLocation).drop(1).onEach {
157-
val keyMaps =
158-
keyMapRepository.keyMapList.first { it is State.Data } as State.Data
159-
160-
val data = AutomaticBackup(keyMapList = keyMaps.data)
161-
162-
doAutomaticBackup.emit(data)
163-
}.launchIn(coroutineScope)
164149
}
165150

166151
override suspend fun backupKeyMaps(output: IFile, keyMapIds: List<String>): Result<Unit> {
@@ -186,7 +171,11 @@ class BackupManagerImpl(
186171

187172
val groups = groupRepository.getAllGroups().first()
188173

189-
backupAsync(output, keyMaps.data, groups)
174+
val layouts = floatingLayoutRepository.layouts
175+
.filterIsInstance<State.Data<List<FloatingLayoutEntityWithButtons>>>()
176+
.first()
177+
178+
backupAsync(output, keyMaps.data, groups, layouts.data)
190179

191180
Success(Unit)
192181
}
@@ -624,8 +613,9 @@ class BackupManagerImpl(
624613

625614
private suspend fun backupAsync(
626615
output: IFile,
627-
keyMapList: List<KeyMapEntity>? = null,
616+
keyMapList: List<KeyMapEntity> = emptyList(),
628617
extraGroups: List<GroupEntity> = emptyList(),
618+
extraLayouts: List<FloatingLayoutEntityWithButtons> = emptyList(),
629619
): Result<IFile> {
630620
return withContext(dispatchers.io()) {
631621
val backupUid = uuidGenerator.random()
@@ -637,80 +627,7 @@ class BackupManagerImpl(
637627
// delete the contents of the file
638628
output.clear()
639629

640-
val floatingLayouts: MutableList<FloatingLayoutEntity> = mutableListOf()
641-
val floatingButtons: MutableList<FloatingButtonEntity> = mutableListOf()
642-
val groupMap: MutableMap<String, GroupEntity> = mutableMapOf()
643-
644-
if (keyMapList != null) {
645-
val floatingButtonTriggerKeys = keyMapList
646-
.flatMap { it.trigger.keys }
647-
.filterIsInstance<FloatingButtonKeyEntity>()
648-
.map { it.buttonUid }
649-
.distinct()
650-
651-
for (buttonUid in floatingButtonTriggerKeys) {
652-
val buttonWithLayout = floatingButtonRepository.get(buttonUid) ?: continue
653-
654-
if (floatingLayouts.none { it.uid == buttonWithLayout.layout.uid }) {
655-
floatingLayouts.add(buttonWithLayout.layout)
656-
}
657-
658-
floatingButtons.add(buttonWithLayout.button)
659-
}
660-
661-
for (keyMap in keyMapList) {
662-
val groupUid = keyMap.groupUid ?: continue
663-
if (!groupMap.containsKey(groupUid)) {
664-
val groupEntity = groupRepository.getGroup(groupUid) ?: continue
665-
groupMap[groupUid] = groupEntity
666-
}
667-
}
668-
669-
for (group in extraGroups) {
670-
if (!groupMap.containsKey(group.uid)) {
671-
groupMap[group.uid] = group
672-
}
673-
}
674-
}
675-
676-
val backupContent = BackupContent(
677-
AppDatabase.DATABASE_VERSION,
678-
Constants.VERSION_CODE,
679-
keyMapList,
680-
defaultLongPressDelay =
681-
preferenceRepository
682-
.get(Keys.defaultLongPressDelay)
683-
.first()
684-
.takeIf { it != PreferenceDefaults.LONG_PRESS_DELAY },
685-
defaultDoublePressDelay =
686-
preferenceRepository
687-
.get(Keys.defaultDoublePressDelay)
688-
.first()
689-
.takeIf { it != PreferenceDefaults.DOUBLE_PRESS_DELAY },
690-
defaultRepeatDelay =
691-
preferenceRepository
692-
.get(Keys.defaultRepeatDelay)
693-
.first()
694-
.takeIf { it != PreferenceDefaults.REPEAT_DELAY },
695-
defaultRepeatRate =
696-
preferenceRepository
697-
.get(Keys.defaultRepeatRate)
698-
.first()
699-
.takeIf { it != PreferenceDefaults.REPEAT_RATE },
700-
defaultSequenceTriggerTimeout =
701-
preferenceRepository
702-
.get(Keys.defaultSequenceTriggerTimeout)
703-
.first()
704-
.takeIf { it != PreferenceDefaults.SEQUENCE_TRIGGER_TIMEOUT },
705-
defaultVibrationDuration =
706-
preferenceRepository
707-
.get(Keys.defaultVibrateDuration)
708-
.first()
709-
.takeIf { it != PreferenceDefaults.VIBRATION_DURATION },
710-
floatingLayouts = floatingLayouts.takeIf { it.isNotEmpty() },
711-
floatingButtons = floatingButtons.takeIf { it.isNotEmpty() },
712-
groups = groupMap.values.toList(),
713-
)
630+
val backupContent = createBackupContent(keyMapList, extraGroups, extraLayouts)
714631

715632
val json = gson.toJson(backupContent)
716633

@@ -758,9 +675,100 @@ class BackupManagerImpl(
758675
}
759676
}
760677

761-
private data class AutomaticBackup(
762-
val keyMapList: List<KeyMapEntity>?,
763-
)
678+
suspend fun createBackupContent(
679+
keyMapList: List<KeyMapEntity>,
680+
extraGroups: List<GroupEntity>,
681+
extraLayouts: List<FloatingLayoutEntityWithButtons>,
682+
): BackupContent {
683+
val floatingLayoutsMap: MutableMap<String, FloatingLayoutEntity> = mutableMapOf()
684+
val floatingButtonsMap: MutableMap<String, FloatingButtonEntity> = mutableMapOf()
685+
val groupMap: MutableMap<String, GroupEntity> = mutableMapOf()
686+
687+
val floatingButtonTriggerKeys = keyMapList
688+
.flatMap { it.trigger.keys }
689+
.filterIsInstance<FloatingButtonKeyEntity>()
690+
.map { it.buttonUid }
691+
.distinct()
692+
693+
for (buttonUid in floatingButtonTriggerKeys) {
694+
val buttonWithLayout = floatingButtonRepository.get(buttonUid) ?: continue
695+
val layoutUid = buttonWithLayout.layout.uid
696+
697+
if (!floatingLayoutsMap.containsKey(layoutUid)) {
698+
floatingLayoutsMap[layoutUid] = buttonWithLayout.layout
699+
}
700+
701+
if (!floatingButtonsMap.containsKey(buttonUid)) {
702+
floatingButtonsMap[buttonUid] = buttonWithLayout.button
703+
}
704+
}
705+
706+
for (keyMap in keyMapList) {
707+
val groupUid = keyMap.groupUid ?: continue
708+
if (!groupMap.containsKey(groupUid)) {
709+
val groupEntity = groupRepository.getGroup(groupUid) ?: continue
710+
groupMap[groupUid] = groupEntity
711+
}
712+
}
713+
714+
for (group in extraGroups) {
715+
if (!groupMap.containsKey(group.uid)) {
716+
groupMap[group.uid] = group
717+
}
718+
}
719+
720+
for (layoutWithButtons in extraLayouts) {
721+
if (!floatingLayoutsMap.containsKey(layoutWithButtons.layout.uid)) {
722+
floatingLayoutsMap[layoutWithButtons.layout.uid] = layoutWithButtons.layout
723+
}
724+
725+
for (button in layoutWithButtons.buttons) {
726+
if (!floatingButtonsMap.containsKey(button.uid)) {
727+
floatingButtonsMap[button.uid] = button
728+
}
729+
}
730+
}
731+
732+
val backupContent = BackupContent(
733+
AppDatabase.DATABASE_VERSION,
734+
Constants.VERSION_CODE,
735+
keyMapList,
736+
defaultLongPressDelay =
737+
preferenceRepository
738+
.get(Keys.defaultLongPressDelay)
739+
.first()
740+
.takeIf { it != PreferenceDefaults.LONG_PRESS_DELAY },
741+
defaultDoublePressDelay =
742+
preferenceRepository
743+
.get(Keys.defaultDoublePressDelay)
744+
.first()
745+
.takeIf { it != PreferenceDefaults.DOUBLE_PRESS_DELAY },
746+
defaultRepeatDelay =
747+
preferenceRepository
748+
.get(Keys.defaultRepeatDelay)
749+
.first()
750+
.takeIf { it != PreferenceDefaults.REPEAT_DELAY },
751+
defaultRepeatRate =
752+
preferenceRepository
753+
.get(Keys.defaultRepeatRate)
754+
.first()
755+
.takeIf { it != PreferenceDefaults.REPEAT_RATE },
756+
defaultSequenceTriggerTimeout =
757+
preferenceRepository
758+
.get(Keys.defaultSequenceTriggerTimeout)
759+
.first()
760+
.takeIf { it != PreferenceDefaults.SEQUENCE_TRIGGER_TIMEOUT },
761+
defaultVibrationDuration =
762+
preferenceRepository
763+
.get(Keys.defaultVibrateDuration)
764+
.first()
765+
.takeIf { it != PreferenceDefaults.VIBRATION_DURATION },
766+
floatingLayouts = floatingLayoutsMap.values.toList().takeIf { it.isNotEmpty() },
767+
floatingButtons = floatingButtonsMap.values.toList().takeIf { it.isNotEmpty() },
768+
groups = groupMap.values.toList().takeIf { it.isNotEmpty() },
769+
)
770+
return backupContent
771+
}
764772
}
765773

766774
interface BackupManager {

app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonEntity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ data class FloatingButtonEntity(
8080

8181
@ColumnInfo(name = KEY_BACKGROUND_OPACITY)
8282
@SerializedName(NAME_BACKGROUND_OPACITY)
83-
val backgroundOpacity: Float? = 1f,
83+
val backgroundOpacity: Float?,
8484

8585
) : Parcelable {
8686
companion object {

app/src/main/java/io/github/sds100/keymapper/data/repositories/RoomKeyMapRepository.kt

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import io.github.sds100.keymapper.util.State
1212
import io.github.sds100.keymapper.util.splitIntoBatches
1313
import kotlinx.coroutines.CoroutineScope
1414
import kotlinx.coroutines.flow.Flow
15-
import kotlinx.coroutines.flow.MutableSharedFlow
1615
import kotlinx.coroutines.flow.SharingStarted
1716
import kotlinx.coroutines.flow.first
1817
import kotlinx.coroutines.flow.flowOn
@@ -38,13 +37,9 @@ class RoomKeyMapRepository(
3837
.flowOn(dispatchers.io())
3938
.stateIn(coroutineScope, SharingStarted.Eagerly, State.Loading)
4039

41-
override val requestBackup = MutableSharedFlow<List<KeyMapEntity>>()
42-
4340
init {
4441
coroutineScope.launch {
4542
migrateFingerprintMaps()
46-
47-
requestBackup()
4843
}
4944
}
5045

@@ -61,8 +56,6 @@ class RoomKeyMapRepository(
6156
for (it in keyMap.splitIntoBatches(MAX_KEY_MAP_BATCH_SIZE)) {
6257
keyMapDao.insert(*it)
6358
}
64-
65-
requestBackup()
6659
}
6760
}
6861

@@ -77,8 +70,6 @@ class RoomKeyMapRepository(
7770
for (it in keyMap.splitIntoBatches(MAX_KEY_MAP_BATCH_SIZE)) {
7871
keyMapDao.update(*it)
7972
}
80-
81-
requestBackup()
8273
}
8374
}
8475

@@ -89,8 +80,6 @@ class RoomKeyMapRepository(
8980
for (it in uid.splitIntoBatches(MAX_KEY_MAP_BATCH_SIZE)) {
9081
keyMapDao.deleteById(*it)
9182
}
92-
93-
requestBackup()
9483
}
9584
}
9685

@@ -106,8 +95,6 @@ class RoomKeyMapRepository(
10695

10796
keyMapDao.insert(*keymaps.toTypedArray())
10897
}
109-
110-
requestBackup()
11198
}
11299
}
113100

@@ -116,8 +103,6 @@ class RoomKeyMapRepository(
116103
for (it in uid.splitIntoBatches(MAX_KEY_MAP_BATCH_SIZE)) {
117104
keyMapDao.enableKeyMapByUid(*it)
118105
}
119-
120-
requestBackup()
121106
}
122107
}
123108

@@ -126,8 +111,6 @@ class RoomKeyMapRepository(
126111
for (it in uid.splitIntoBatches(MAX_KEY_MAP_BATCH_SIZE)) {
127112
keyMapDao.disableKeyMapByUid(*it)
128113
}
129-
130-
requestBackup()
131114
}
132115
}
133116

@@ -136,8 +119,6 @@ class RoomKeyMapRepository(
136119
for (it in uid.splitIntoBatches(MAX_KEY_MAP_BATCH_SIZE)) {
137120
keyMapDao.setKeyMapGroup(groupUid, *it)
138121
}
139-
140-
requestBackup()
141122
}
142123
}
143124

@@ -153,11 +134,4 @@ class RoomKeyMapRepository(
153134
fingerprintMapDao.update(migratedFingerprintMapEntity)
154135
}
155136
}
156-
157-
private fun requestBackup() {
158-
coroutineScope.launch {
159-
val keyMapList = keyMapList.first { it is State.Data } as State.Data
160-
requestBackup.emit(keyMapList.data)
161-
}
162-
}
163137
}

0 commit comments

Comments
 (0)