Skip to content

Commit 8ff6fec

Browse files
committed
Implemented undo functionality for happy path
- yet to. update the UI of undo screen
1 parent eccabd5 commit 8ff6fec

File tree

5 files changed

+84
-92
lines changed

5 files changed

+84
-92
lines changed

GoInfoGame/GoInfoGame/DataBase/DBModels/StoredChangeset.swift

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,43 @@ class StoredChangeset: Object {
4242
@Persisted var version: Int = 0
4343
@Persisted var point: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
4444
@Persisted var nodes: List<Int64> = List<Int64>()
45+
@Persisted var updatedVersion: Int = -1
4546

46-
public func asOSMWay() -> OSMWay {
47+
public func asOSMWay(isUndo: Bool = false) -> OSMWay {
4748
var storage = originalTags.toDictionary()
48-
for tag in tags {
49-
storage[tag.key] = tag.value
49+
if !isUndo {
50+
for tag in tags {
51+
storage[tag.key] = tag.value
52+
}
5053
}
5154
let nodes = Array(nodes.map { Int($0) })
52-
return OSMWay(type: "way", id: elementId, timestamp: Date(), version: version, changeset: -1, user: "", uid: -1, nodes: nodes, tags: storage)
55+
return OSMWay(type: "way",
56+
id: elementId,
57+
timestamp: Date(),
58+
version: isUndo ? updatedVersion : version,
59+
changeset: -1,
60+
user: "",
61+
uid: -1,
62+
nodes: nodes,
63+
tags: storage)
5364
}
5465

55-
public func asOSMNode() -> OSMNode {
66+
public func asOSMNode(isUndo: Bool = false) -> OSMNode {
5667
var storage = originalTags.toDictionary()
57-
for tag in tags {
58-
storage[tag.key] = tag.value
68+
if !isUndo {
69+
for tag in tags {
70+
storage[tag.key] = tag.value
71+
}
5972
}
60-
return OSMNode(type: "node", id: elementId, lat: point.latitude, lon: point.longitude, timestamp: Date(), version: version, changeset: -1, user: "", uid: -1, tags: storage)
73+
return OSMNode(type: "node",
74+
id: elementId,
75+
lat: point.latitude,
76+
lon: point.longitude,
77+
timestamp: Date(),
78+
version: isUndo ? updatedVersion : version,
79+
changeset: -1,
80+
user: "",
81+
uid: -1,
82+
tags: storage)
6183
}
6284
}

GoInfoGame/GoInfoGame/DataBase/DatabaseConnector.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,23 +416,23 @@ class DatabaseConnector {
416416

417417
func getChangeset(for id: Int64, type: ElementType) -> StoredChangeset? {
418418
let storedType: StoredElementEnum = (type == .way) ? .way : .node
419-
let stringId = String(id)
420419
return realm.objects(StoredChangeset.self)
421-
.filter("elementId == %@ AND elementType == %@", stringId, storedType.rawValue)
420+
.filter("elementId == %@ AND elementType == %@", id, storedType.rawValue)
422421
.first
423422
}
424423

425424
/// Assigns changesetId for a stored changeset
426425
/// - parameter obj: Internal id for the changeset in the database (unique ID)
427426
/// - parameter changesetId: Assigned changeset ID from the server
428427
/// - Returns updated `StoredChangeset`
429-
func assignChangesetId(obj:String, changesetId: Int) -> StoredChangeset? {
428+
func assignChangesetId(obj:String, changesetId: Int, updatedVersion: Int) -> StoredChangeset? {
430429
guard let changeset = realm.object(ofType: StoredChangeset.self, forPrimaryKey: obj) else {
431430
return nil
432431
}
433432
do {
434433
try realm.write {
435434
changeset.changesetId = changesetId // Not sure if this changes the value
435+
changeset.updatedVersion = updatedVersion
436436
}
437437
return changeset
438438
} catch (let error){
@@ -442,7 +442,7 @@ class DatabaseConnector {
442442

443443
func updateNodeVersion(nodeId: String, version:Int) -> StoredNode?{
444444
let intId = Int(nodeId) ?? -1
445-
guard let theNode = getNode(id: intId, version: .edited) else { return nil }
445+
guard let theNode = getNode(id: intId, version: .original) else { return nil }
446446
do {
447447
try realm.write {
448448
theNode.version = version
@@ -457,7 +457,7 @@ class DatabaseConnector {
457457

458458
func updateWayVersion(wayId: String, version: Int) -> StoredWay? {
459459
let intId = Int(wayId) ?? -1
460-
guard let theWay = getWay(id: intId, version: .edited) else { return nil }
460+
guard let theWay = getWay(id: intId, version: .original) else { return nil }
461461

462462
do {
463463
try realm.write {

GoInfoGame/GoInfoGame/data/DatasyncManager.swift

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ class DatasyncManager {
111111
print("📤 Syncing node ID: \(node.id)")
112112
let payload = node.asOSMNode()
113113
do {
114-
let isFinished = try await syncNode(node: payload)
115-
if isFinished {
114+
let status = try await syncNode(node: payload, exclude_gig_tags: exclude_gig_tags)
115+
if status.result {
116116
DispatchQueue.main.async {
117-
self.dbInstance.assignChangesetId(obj: key, changesetId: 0)
117+
self.dbInstance.assignChangesetId(obj: key, changesetId: 0, updatedVersion: status.version)
118118
}
119119
print("✅ Node sync finished: \(payload.id)")
120120
} else {
@@ -132,10 +132,10 @@ class DatasyncManager {
132132
print("📤 Syncing way ID: \(way.id)")
133133
let payload = way.asOSMWay()
134134
do {
135-
let isFinished = try await syncWay(way: payload, exclude_gig_tags: exclude_gig_tags)
136-
if isFinished {
135+
let status = try await syncWay(way: payload, exclude_gig_tags: exclude_gig_tags)
136+
if status.result {
137137
DispatchQueue.main.async {
138-
self.dbInstance.assignChangesetId(obj: key, changesetId: 0)
138+
self.dbInstance.assignChangesetId(obj: key, changesetId: 0, updatedVersion: status.version)
139139
}
140140
print("✅ Way sync finished: \(payload.id)")
141141
} else {
@@ -252,7 +252,7 @@ class DatasyncManager {
252252
}
253253

254254
// utility function to act as substitute for osmConnection functions
255-
func updateWay(way: OSMWay, exclude_gig_tags: Bool = false) async throws -> Int {
255+
func updateWay(way: OSMWay, exclude_gig_tags: Bool) async throws -> Int {
256256
var localWay = way
257257
let wayBodyString = localWay.toPayload(exclude_gig_tags: exclude_gig_tags)
258258
let changesetUploadBody = "<osmChange version=\"0.6\" generator=\"GIG Change generator\">" + wayBodyString + "</osmChange>"
@@ -372,22 +372,22 @@ class DatasyncManager {
372372
print(localWay)
373373
print("Merged way")
374374
print(mergedWay)
375-
return try await updateWay(way: mergedWay)
375+
return try await updateWay(way: mergedWay, exclude_gig_tags: exclude_gig_tags)
376376
default:
377377
throw error
378378
}
379379
}
380380
}
381381

382-
func updateNode2(node: OSMNode) async throws -> Int {
382+
func updateNode2(node: OSMNode, exclude_gig_tags: Bool) async throws -> Int {
383383
var localNode = node
384384

385385
let nodeId = "\(localNode.id)"
386386
SyncLogger.shared.logStep("Updating node \(nodeId) under new changeset")
387387

388388
var updatedResult: Int = -1
389389
do {
390-
updatedResult = try await updateNode(node: localNode)
390+
updatedResult = try await updateNode(node: localNode, exclude_gig_tags: exclude_gig_tags)
391391
return updatedResult
392392

393393
} catch let error as APIError {
@@ -500,7 +500,7 @@ class DatasyncManager {
500500
Syncs the node along with the updated
501501
*/
502502
@MainActor
503-
func syncNode(node: OSMNode) async throws -> Bool {
503+
func syncNode(node: OSMNode, exclude_gig_tags: Bool) async throws -> (result:Bool, version: Int) {
504504
var localNode = node
505505

506506
SyncLogger.shared.logStep("Open Changeset")
@@ -513,15 +513,16 @@ class DatasyncManager {
513513
localNode.changeset = changesetID
514514

515515
//Step 2: Update Node
516-
let newVersion = try await updateNode2(node: localNode)
516+
let newVersion = try await updateNode2(node: localNode, exclude_gig_tags: exclude_gig_tags)
517517
localNode.version = newVersion
518518
DispatchQueue.main.async {
519519
self.dbInstance.updateNodeVersion(nodeId: String(localNode.id), version: newVersion)
520520
}
521521

522522
//Stepp 3:Close changeset
523523
SyncLogger.shared.logStep("Close Changeset")
524-
return try await closeChangeset(id: String(changesetID))
524+
let result = try await closeChangeset(id: String(changesetID))
525+
return (result, newVersion)
525526

526527
} catch {
527528
print("Failed to open changeset:", error.localizedDescription)
@@ -551,7 +552,7 @@ class DatasyncManager {
551552
}
552553

553554
@MainActor
554-
func syncWay(way: OSMWay, exclude_gig_tags: Bool = false) async throws -> Bool {
555+
func syncWay(way: OSMWay, exclude_gig_tags: Bool = false) async throws -> (result: Bool, version: Int) {
555556
var localWay = way
556557

557558
do {
@@ -567,7 +568,8 @@ class DatasyncManager {
567568
DispatchQueue.main.async {
568569
self.dbInstance.updateWayVersion(wayId: String(localWay.id), version: newVersion)
569570
}
570-
return try await closeChangeset(id: String(changesetID))
571+
let result = try await closeChangeset(id: String(changesetID))
572+
return (result, newVersion)
571573

572574
} catch {
573575
throw error

GoInfoGame/GoInfoGame/quests/QuestProtocols.swift

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,35 @@ class QuestBase {
3737

3838
private var elementSubmittingToPOSM: ElementSubmittingToPOSM?
3939

40+
func updateUndoTags(changeSet: StoredChangeset) {
41+
// Convert from ElementType enum to StoredElementEnum
42+
Task.detached(operation: { @MainActor in
43+
let storedElementType: StoredElementEnum = changeSet.elementType
44+
do {
45+
var result: (result: Bool, version: Int) = (false, -1)
46+
switch storedElementType {
47+
case .node:
48+
result = try await DatasyncManager.shared.syncNode(node: changeSet.asOSMNode(isUndo: true), exclude_gig_tags: true)
49+
case .way:
50+
result = try await DatasyncManager.shared.syncWay(way: changeSet.asOSMWay(isUndo: true), exclude_gig_tags: true)
51+
case .unknown:
52+
print("❌ Undo failed: Element type not found")
53+
}
54+
}
55+
catch {
56+
print("❌ Undo failed: \(error)")
57+
}
58+
})
59+
}
60+
4061
// Add a custom implementation
4162

4263
public func updateTags(id: Int64, tags:[String:String], type: ElementType, exclude_gig_tags: Bool = false) {
4364

44-
MapUndoManager.shared.updateTagsHandler = { [weak self] id, tags, type in
45-
self?.updateTags(id: id, tags: tags, type: type, exclude_gig_tags: true)
65+
MapUndoManager.shared.updateTagsHandler = { [weak self] changeset in
66+
guard let changeSet = changeset else { return }
67+
68+
self?.updateUndoTags(changeSet: changeSet)
4669
}
4770

4871

GoInfoGame/GoInfoGame/quests/QuestUndoManager.swift

Lines changed: 7 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -20,73 +20,18 @@ class MapUndoManager {
2020
realm = try! Realm()
2121
}
2222

23-
var updateTagsHandler: ((_ id: Int64, _ tags: [String: String], _ type: ElementType) -> Void)?
23+
var updateTagsHandler: ((_ changeset: StoredChangeset?) -> Void)?
2424

2525
func undo(for id: Int64, type: ElementType) {
2626
MapUndoManager.shared.isUndoInProgress = true
2727

28-
switch type {
29-
case .way:
30-
guard let original = DatabaseConnector.shared.getWay(id: Int(id), version: .original),
31-
let edited = DatabaseConnector.shared.getWay(id: Int(id), version: .edited) else {
32-
print("❌ Undo failed: Way not found")
33-
return
34-
}
35-
36-
do {
37-
try realm.write {
38-
edited.tags.removeAll()
39-
40-
for entry in original.tags {
41-
let key = entry.key
42-
let value = entry.value
43-
if key != "ext:gig_complete", key != "ext:gig_last_updated" {
44-
edited.tags[key] = value
45-
}
46-
}
47-
48-
edited.polyline.removeAll()
49-
edited.polyline.append(objectsIn: original.polyline)
50-
51-
edited.nodes.removeAll()
52-
edited.nodes.append(objectsIn: original.nodes)
53-
}
54-
} catch {
55-
print("❌ Realm write failed during undo (way): \(error)")
56-
}
57-
58-
updateTagsHandler?(id, edited.tags.toDictionary(), .way)
59-
60-
case .node:
61-
guard let original = DatabaseConnector.shared.getNode(id: Int(id), version: .original),
62-
let edited = DatabaseConnector.shared.getNode(id: Int(id), version: .edited) else {
63-
print("❌ Undo failed: Node not found")
64-
return
65-
}
66-
67-
do {
68-
try realm.write {
69-
edited.tags.removeAll()
70-
71-
for entry in original.tags {
72-
let key = entry.key
73-
let value = entry.value
74-
if key != "ext:gig_complete", key != "ext:gig_last_updated" {
75-
edited.tags[key] = value
76-
}
77-
}
78-
79-
edited.point = original.point
80-
}
81-
} catch {
82-
print("❌ Realm write failed during undo (node): \(error)")
83-
}
84-
85-
updateTagsHandler?(id, edited.tags.toDictionary(), .node)
86-
87-
default:
88-
print("Unknown element type")
28+
guard let changeSet = DatabaseConnector.shared.getChangeset(for: id, type: type) else {
29+
print("❌ Undo failed: Element not found")
30+
updateTagsHandler?(nil)
31+
return
8932
}
33+
34+
updateTagsHandler?(changeSet)
9035
}
9136

9237

0 commit comments

Comments
 (0)