3 Commits

Author SHA1 Message Date
sora 18725261e3 Update app/build.gradle 2026-06-06 19:34:25 +02:00
soraefir cc1a0c1aca Fix region saving bug 2026-06-06 19:30:18 +02:00
soraefir f2a5efcec5 Update saving logic 2026-06-06 18:54:09 +02:00
7 changed files with 75 additions and 25 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ android {
applicationId 'net.helcel.beans' applicationId 'net.helcel.beans'
minSdk = 28 minSdk = 28
targetSdk = 37 targetSdk = 37
versionName "1.3" versionName "1.3b"
versionCode project.hasProperty('VERSION_CODE') ? project.property('VERSION_CODE').toInteger() : 1 versionCode project.hasProperty('VERSION_CODE') ? project.property('VERSION_CODE').toInteger() : 1
} }
signingConfigs { signingConfigs {
@@ -50,8 +50,8 @@ class MainScreen : ComponentActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
actionBar?.hide() actionBar?.hide()
Settings.start(this) Settings.start(this)
GeoLocImporter.importStates(this)
Data.loadData(this, Int.MIN_VALUE) Data.loadData(this, Int.MIN_VALUE)
GeoLocImporter.importStates(this)
setContent { setContent {
SysTheme { SysTheme {
@@ -168,8 +168,10 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
EditPlaceDialog(true) { EditPlaceDialog(true) {
showEdit = false showEdit = false
val g = Data.selected_group val g = Data.selected_group
if (it && g != null) if (it && g != null) {
Data.visits.reassignAllVisitedToGroup(g.key) Data.visits.reassignAllVisitedToGroup(g.key)
Data.saveData()
}
} }
LazyColumn( LazyColumn(
@@ -216,8 +218,10 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
deleteMode = true, deleteMode = true,
onDismiss = { onDismiss = {
val g = Data.selected_group val g = Data.selected_group
if (g != null) if (g != null) {
Data.visits.reassignAllVisitedToGroup(g.key) Data.visits.reassignAllVisitedToGroup(g.key)
Data.saveData()
}
showDialog = false showDialog = false
}) })
} }
@@ -54,27 +54,51 @@ fun EditPlaceScreenPreview(){
EditPlaceScreen(Group.EEE) EditPlaceScreen(Group.EEE)
} }
fun syncVisited(loc: GeoLoc?=World.WWW){ fun syncVisited(loc: GeoLoc?=World.WWW): Boolean {
var changed = false
loc?.children?.forEach { tt -> loc?.children?.forEach { tt ->
tt.children.forEach {itc-> tt.children.forEach {itc->
if(Data.visits.getVisited(itc) in listOf(AUTO_GROUP,NO_GROUP)) { if(Data.visits.getVisited(itc) in listOf(AUTO_GROUP,NO_GROUP)) {
if(itc.children.any { c -> Data.visits.getVisited(c) != NO_GROUP }) val newState = if(itc.children.any { c -> Data.visits.getVisited(c) != NO_GROUP })
Data.visits.setVisited(itc, AUTO_GROUP) AUTO_GROUP
else else
Data.visits.setVisited(itc, NO_GROUP) NO_GROUP
if (Data.visits.getVisited(itc) != newState) {
Data.visits.setVisited(itc, newState)
changed = true
}
} }
} }
if(Data.visits.getVisited(tt) in listOf(AUTO_GROUP,NO_GROUP)) { if(Data.visits.getVisited(tt) in listOf(AUTO_GROUP,NO_GROUP)) {
if(tt.children.any { itc -> Data.visits.getVisited(itc) != NO_GROUP }) val newState = if(tt.children.any { itc -> Data.visits.getVisited(itc) != NO_GROUP })
Data.visits.setVisited(tt, AUTO_GROUP) AUTO_GROUP
else else
Data.visits.setVisited(tt, NO_GROUP) NO_GROUP
if (Data.visits.getVisited(tt) != newState) {
Data.visits.setVisited(tt, newState)
changed = true
}
} }
} }
// Sync World from Continents
if (loc != null && Data.visits.getVisited(loc) in listOf(AUTO_GROUP, NO_GROUP)) {
val newState = if(loc.children.any { Data.visits.getVisited(it) != NO_GROUP })
AUTO_GROUP
else
NO_GROUP
if (Data.visits.getVisited(loc) != newState) {
Data.visits.setVisited(loc, newState)
changed = true
}
}
return changed
} }
@Composable @Composable
fun EditPlaceScreen(loc: GeoLoc, onExit:()->Unit={}) { fun EditPlaceScreen(loc: GeoLoc, onExit:()->Unit={}) {
val visits by Data.visits.visitsFlow.collectAsState()
var showEdit by remember { mutableStateOf(false) } var showEdit by remember { mutableStateOf(false) }
val tabs : SnapshotStateList<GeoLoc> = remember { mutableStateListOf(loc) } val tabs : SnapshotStateList<GeoLoc> = remember { mutableStateListOf(loc) }
val ctx = LocalContext.current val ctx = LocalContext.current
@@ -84,7 +108,12 @@ fun EditPlaceScreen(loc: GeoLoc, onExit:()->Unit={}) {
selectedTab = tabs.lastIndex selectedTab = tabs.lastIndex
} }
SideEffect { SideEffect {
syncVisited() // visits is used to trigger sync whenever data changes
if (visits.isNotEmpty() || true) {
if (syncVisited()) {
Data.saveData()
}
}
} }
BackHandler { BackHandler {
if (tabs.size > 1) tabs.removeAt(tabs.lastIndex) if (tabs.size > 1) tabs.removeAt(tabs.lastIndex)
@@ -95,6 +124,7 @@ fun EditPlaceScreen(loc: GeoLoc, onExit:()->Unit={}) {
showEdit = false showEdit = false
if (it) { if (it) {
Data.visits.setVisited(Data.selected_geoloc, NO_GROUP) Data.visits.setVisited(Data.selected_geoloc, NO_GROUP)
syncVisited()
Data.saveData() Data.saveData()
if (Data.selected_geoloc!=null && Data.selected_geoloc!!.children.any { itc-> Data.visits.getVisited(itc) != NO_GROUP }) { if (Data.selected_geoloc!=null && Data.selected_geoloc!!.children.any { itc-> Data.visits.getVisited(itc) != NO_GROUP }) {
@@ -103,6 +133,7 @@ fun EditPlaceScreen(loc: GeoLoc, onExit:()->Unit={}) {
} }
if (Data.selected_group != null && Data.selected_geoloc != null) { if (Data.selected_group != null && Data.selected_geoloc != null) {
Data.visits.setVisited(Data.selected_geoloc, Data.selected_group!!.key) Data.visits.setVisited(Data.selected_geoloc, Data.selected_group!!.key)
syncVisited()
Data.saveData() Data.saveData()
} }
Data.selected_geoloc = null Data.selected_geoloc = null
@@ -144,12 +175,14 @@ fun EditPlaceScreen(loc: GeoLoc, onExit:()->Unit={}) {
Data.visits.getVisited(itc)!= NO_GROUP } == true) AUTO_GROUP Data.visits.getVisited(itc)!= NO_GROUP } == true) AUTO_GROUP
else NO_GROUP else NO_GROUP
) )
Data.saveData()
Data.selected_group = null Data.selected_group = null
} else { } else {
Data.selected_group = null Data.selected_group = null
showEdit=true showEdit=true
} }
syncVisited()
Data.saveData()
}) })
} }
@@ -43,14 +43,14 @@ object Data {
if (groups.size() == 0) { if (groups.size() == 0) {
groups.setGroup(DEFAULT_GROUP, "Visited", groups.setGroup(DEFAULT_GROUP, "Visited",
ContextCompat.getColor(ctx, R.color.blue).toDrawable()) ContextCompat.getColor(ctx, R.color.blue).toDrawable())
saveData()
} }
saveData()
} }
fun saveData() { fun saveData() {
if(groups.id != visits.id) return if(groups.id != visits.id) return
val id = groups.id val id = groups.id
sharedPreferences.edit { sharedPreferences.edit(commit=true) {
putString("groups_$id", groupsSerial.writeTo(groups)) putString("groups_$id", groupsSerial.writeTo(groups))
putString("visits_$id", visitsSerial.writeTo(visits)) putString("visits_$id", visitsSerial.writeTo(visits))
} }
@@ -32,12 +32,18 @@ class Groups(val id: Int, @SerialName("grps") private val groups: HashMap<Int, G
val groupsFlow: StateFlow<List<Group>> = _groupsFlow.asStateFlow() val groupsFlow: StateFlow<List<Group>> = _groupsFlow.asStateFlow()
fun setGroup(key: Int, name: String, col: ColorDrawable) { fun setGroup(key: Int, name: String, col: ColorDrawable) {
val old = groups[key]
if (old != null && old.name == name && old.color.color == col.color) return
groups[key] = Group(key, name, col) groups[key] = Group(key, name, col)
_groupsFlow.value = groups.values.toList() updateFlow()
} }
fun deleteGroup(key: Int) { fun deleteGroup(key: Int) {
groups.remove(key) groups.remove(key)
updateFlow()
}
private fun updateFlow() {
_groupsFlow.value = groups.values.toList() _groupsFlow.value = groups.values.toList()
} }
@@ -19,24 +19,25 @@ class Visits(val id: Int, private val locs: HashMap<String, Int>) {
val visitsFlow: StateFlow<Map<String,Int>> = _visitsFlow val visitsFlow: StateFlow<Map<String,Int>> = _visitsFlow
fun setVisited(key: GeoLoc?, b: Int) { fun setVisited(key: GeoLoc?, b: Int) {
if (key == null) if (key == null || locs[key.code] == b)
return return
_visitsFlow.value = _visitsFlow.value.toMutableMap().apply {
this[key.code] = b
}
locs[key.code] = b locs[key.code] = b
updateFlow()
}
private fun updateFlow() {
_visitsFlow.value = locs.toMap()
} }
fun deleteVisited(key: Int) { fun deleteVisited(key: Int) {
val keysToDelete = locs val keysToDelete = locs
.filter { it.value == key } .filter { it.value == key }
.map { it.key } .map { it.key }
_visitsFlow.value = _visitsFlow.value.toMutableMap().apply { if (keysToDelete.isEmpty()) return
keysToDelete.forEach { this.remove(it)}
}
keysToDelete.forEach { keysToDelete.forEach {
locs.remove(it) locs.remove(it)
} }
updateFlow()
} }
fun getVisited(key: GeoLoc): Int { fun getVisited(key: GeoLoc): Int {
@@ -60,13 +61,19 @@ class Visits(val id: Int, private val locs: HashMap<String, Int>) {
} }
fun reassignAllVisitedToGroup(group: Int) { fun reassignAllVisitedToGroup(group: Int) {
var changed = false
val keys = locs.filter { (_, grp) -> val keys = locs.filter { (_, grp) ->
grp !in listOf(NO_GROUP, AUTO_GROUP) grp !in listOf(NO_GROUP, AUTO_GROUP)
}.keys }.keys
keys.forEach { keys.forEach {
locs[it] = group if (locs[it] != group) {
locs[it] = group
changed = true
}
}
if (changed) {
updateFlow()
} }
_visitsFlow.value = locs
} }
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)