mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 11:05:19 +00:00
Teleport persistence: store per-geohash teleported state in UserDefaults; initialize on startup; OR with location-derived status; sheet writes persisted flag on select/teleport
This commit is contained in:
@@ -21,6 +21,7 @@ final class LocationChannelManager: NSObject, CLLocationManagerDelegate, Observa
|
|||||||
private var lastLocation: CLLocation?
|
private var lastLocation: CLLocation?
|
||||||
private var refreshTimer: Timer?
|
private var refreshTimer: Timer?
|
||||||
private let userDefaultsKey = "locationChannel.selected"
|
private let userDefaultsKey = "locationChannel.selected"
|
||||||
|
private let teleportedStoreKey = "locationChannel.teleportedSet"
|
||||||
private var isGeocoding: Bool = false
|
private var isGeocoding: Bool = false
|
||||||
|
|
||||||
// Published state for UI bindings
|
// Published state for UI bindings
|
||||||
@@ -31,6 +32,9 @@ final class LocationChannelManager: NSObject, CLLocationManagerDelegate, Observa
|
|||||||
@Published var teleported: Bool = false
|
@Published var teleported: Bool = false
|
||||||
@Published private(set) var locationNames: [GeohashChannelLevel: String] = [:]
|
@Published private(set) var locationNames: [GeohashChannelLevel: String] = [:]
|
||||||
|
|
||||||
|
// Persisted set of geohashes that were selected via teleport
|
||||||
|
private var teleportedSet: Set<String> = []
|
||||||
|
|
||||||
private override init() {
|
private override init() {
|
||||||
super.init()
|
super.init()
|
||||||
cl.delegate = self
|
cl.delegate = self
|
||||||
@@ -41,6 +45,15 @@ final class LocationChannelManager: NSObject, CLLocationManagerDelegate, Observa
|
|||||||
let channel = try? JSONDecoder().decode(ChannelID.self, from: data) {
|
let channel = try? JSONDecoder().decode(ChannelID.self, from: data) {
|
||||||
selectedChannel = channel
|
selectedChannel = channel
|
||||||
}
|
}
|
||||||
|
// Load persisted teleported set
|
||||||
|
if let data = UserDefaults.standard.data(forKey: teleportedStoreKey),
|
||||||
|
let arr = try? JSONDecoder().decode([String].self, from: data) {
|
||||||
|
teleportedSet = Set(arr)
|
||||||
|
}
|
||||||
|
// Initialize teleported flag from persisted state if a location channel is selected
|
||||||
|
if case .location(let ch) = selectedChannel {
|
||||||
|
teleported = teleportedSet.contains(ch.geohash)
|
||||||
|
}
|
||||||
let status: CLAuthorizationStatus
|
let status: CLAuthorizationStatus
|
||||||
if #available(iOS 14.0, *) {
|
if #available(iOS 14.0, *) {
|
||||||
status = cl.authorizationStatus
|
status = cl.authorizationStatus
|
||||||
@@ -104,6 +117,24 @@ final class LocationChannelManager: NSObject, CLLocationManagerDelegate, Observa
|
|||||||
if let data = try? JSONEncoder().encode(channel) {
|
if let data = try? JSONEncoder().encode(channel) {
|
||||||
UserDefaults.standard.set(data, forKey: self.userDefaultsKey)
|
UserDefaults.standard.set(data, forKey: self.userDefaultsKey)
|
||||||
}
|
}
|
||||||
|
// Update teleported flag based on persisted state for immediate UI behavior
|
||||||
|
switch channel {
|
||||||
|
case .mesh:
|
||||||
|
self.teleported = false
|
||||||
|
case .location(let ch):
|
||||||
|
self.teleported = self.teleportedSet.contains(ch.geohash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark or unmark a geohash as teleported in persistence and update current flag if relevant
|
||||||
|
func markTeleported(for geohash: String, _ flag: Bool) {
|
||||||
|
if flag { teleportedSet.insert(geohash) } else { teleportedSet.remove(geohash) }
|
||||||
|
if let data = try? JSONEncoder().encode(Array(teleportedSet)) {
|
||||||
|
UserDefaults.standard.set(data, forKey: teleportedStoreKey)
|
||||||
|
}
|
||||||
|
if case .location(let ch) = selectedChannel, ch.geohash == geohash {
|
||||||
|
Task { @MainActor in self.teleported = flag }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,13 +195,14 @@ final class LocationChannelManager: NSObject, CLLocationManagerDelegate, Observa
|
|||||||
}
|
}
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
self.availableChannels = result
|
self.availableChannels = result
|
||||||
// Recompute teleported status based on current location vs selected channel
|
// Recompute teleported status based on persisted state OR current location vs selected channel
|
||||||
switch self.selectedChannel {
|
switch self.selectedChannel {
|
||||||
case .mesh:
|
case .mesh:
|
||||||
self.teleported = false
|
self.teleported = false
|
||||||
case .location(let ch):
|
case .location(let ch):
|
||||||
|
let persisted = self.teleportedSet.contains(ch.geohash)
|
||||||
let currentGH = Geohash.encode(latitude: coord.latitude, longitude: coord.longitude, precision: ch.level.precision)
|
let currentGH = Geohash.encode(latitude: coord.latitude, longitude: coord.longitude, precision: ch.level.precision)
|
||||||
self.teleported = (currentGH != ch.geohash)
|
self.teleported = persisted || (currentGH != ch.geohash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ struct LocationChannelsSheet: View {
|
|||||||
let subtitlePrefix = "#\(channel.geohash) • \(coverage)"
|
let subtitlePrefix = "#\(channel.geohash) • \(coverage)"
|
||||||
let highlight = viewModel.geohashParticipantCount(for: channel.geohash) > 0
|
let highlight = viewModel.geohashParticipantCount(for: channel.geohash) > 0
|
||||||
channelRow(title: geohashTitleWithCount(for: channel), subtitlePrefix: subtitlePrefix, subtitleName: namePart, isSelected: isSelected(channel), titleBold: highlight) {
|
channelRow(title: geohashTitleWithCount(for: channel), subtitlePrefix: subtitlePrefix, subtitleName: namePart, isSelected: isSelected(channel), titleBold: highlight) {
|
||||||
// Selecting a suggested nearby channel is not a teleport
|
// Selecting a suggested nearby channel is not a teleport. Persist this.
|
||||||
manager.teleported = false
|
manager.markTeleported(for: channel.geohash, false)
|
||||||
manager.select(ChannelID.location(channel))
|
manager.select(ChannelID.location(channel))
|
||||||
isPresented = false
|
isPresented = false
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ struct LocationChannelsSheet: View {
|
|||||||
let level = levelForLength(gh.count)
|
let level = levelForLength(gh.count)
|
||||||
let ch = GeohashChannel(level: level, geohash: gh)
|
let ch = GeohashChannel(level: level, geohash: gh)
|
||||||
// Mark this selection as a manual teleport
|
// Mark this selection as a manual teleport
|
||||||
manager.teleported = true
|
manager.markTeleported(for: ch.geohash, true)
|
||||||
manager.select(ChannelID.location(ch))
|
manager.select(ChannelID.location(ch))
|
||||||
isPresented = false
|
isPresented = false
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
Reference in New Issue
Block a user