Set duplicate as current inside ProfileManager
When setting duplicate as current, batch save original profile and duplicate in a single call via profilesToSave. This is to avoid a double call to willUpdateProfiles() when saving Core Data context. In order to set current profile to one that has not been persisted yet (the duplicate), we need to resort to a pendingProfiles map where to look the duplicate up when setting currentProfileId. Either way, iOS 14 cannot handle updating a "hot" change in a presented NavigationLink. Changing currentProfileId binding while in ProfileView messes up navigation completely (multiple push and pop events). Avoid.
This commit is contained in:
parent
943bce5515
commit
4cb18965c9
|
@ -105,7 +105,7 @@ extension OrganizerView {
|
|||
private func profileMenu(forHeader header: Profile.Header) -> some View {
|
||||
ProfileView.DuplicateButton(
|
||||
header: header,
|
||||
switchCurrentProfile: false
|
||||
setAsCurrent: false
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ extension ProfileView {
|
|||
)
|
||||
DuplicateButton(
|
||||
header: currentProfile.value.header,
|
||||
switchCurrentProfile: true
|
||||
setAsCurrent: true
|
||||
)
|
||||
uninstallVPNButton
|
||||
Divider()
|
||||
|
@ -191,12 +191,12 @@ extension ProfileView {
|
|||
|
||||
private let header: Profile.Header
|
||||
|
||||
private let switchCurrentProfile: Bool
|
||||
private let setAsCurrent: Bool
|
||||
|
||||
init(header: Profile.Header, switchCurrentProfile: Bool) {
|
||||
init(header: Profile.Header, setAsCurrent: Bool) {
|
||||
profileManager = .shared
|
||||
self.header = header
|
||||
self.switchCurrentProfile = switchCurrentProfile
|
||||
self.setAsCurrent = setAsCurrent
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
|
@ -208,12 +208,7 @@ extension ProfileView {
|
|||
}
|
||||
|
||||
private func duplicateProfile(withId id: UUID) {
|
||||
guard let copy = profileManager.duplicateProfile(withId: id) else {
|
||||
return
|
||||
}
|
||||
if switchCurrentProfile {
|
||||
profileManager.currentProfileId = copy.id
|
||||
}
|
||||
profileManager.duplicateProfile(withId: id, setAsCurrent: setAsCurrent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,8 @@ public class ProfileManager: ObservableObject {
|
|||
|
||||
public let didCreateProfile = PassthroughSubject<Profile, Never>()
|
||||
|
||||
private var pendingProfiles: [UUID: Profile] = [:]
|
||||
|
||||
private var cancellables: Set<AnyCancellable> = []
|
||||
|
||||
public init(
|
||||
|
@ -172,9 +174,13 @@ extension ProfileManager {
|
|||
|
||||
// IMPORTANT: fetch live copy first (see intents)
|
||||
if isCurrentProfile(id) {
|
||||
pp_log.debug("Profile \(currentProfile.value.logDescription) found in memory")
|
||||
pp_log.debug("Profile \(currentProfile.value.logDescription) found in memory (current profile)")
|
||||
return currentProfile.value
|
||||
}
|
||||
if let pending = pendingProfiles[id] {
|
||||
pp_log.debug("Profile \(pending.logDescription) found in memory (pending profile)")
|
||||
return pending
|
||||
}
|
||||
|
||||
guard let profile = strategy.profile(withId: id) else {
|
||||
assertionFailure("Profile in headers yet not found in persistent store")
|
||||
|
@ -239,16 +245,34 @@ extension ProfileManager {
|
|||
removeProfiles(withIds: ids)
|
||||
}
|
||||
|
||||
public func duplicateProfile(withId id: UUID) -> Profile? {
|
||||
public func duplicateProfile(withId id: UUID, setAsCurrent: Bool) {
|
||||
guard let source = liveProfile(withId: id) else {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
let copy = source
|
||||
.withNewId()
|
||||
.renamedUniquely(withLastUpdate: false)
|
||||
|
||||
saveProfile(copy, isActive: nil)
|
||||
return copy
|
||||
|
||||
//
|
||||
// XXX: we want to batch save the duplicate together with the former current
|
||||
// profile, which is done in setCurrentProfile(). however, setting
|
||||
// currentProfileId (for navigation), requires the profile ID to exist in
|
||||
// the persistent store when looked up via liveProfile(withId:)
|
||||
//
|
||||
// the pendingProfiles workaround allows setting currentProfileId to a
|
||||
// profile that has not been persisted yet
|
||||
//
|
||||
if setAsCurrent {
|
||||
if #available(iOS 15, *) {
|
||||
pendingProfiles[copy.id] = copy
|
||||
currentProfileId = copy.id
|
||||
pendingProfiles.removeValue(forKey: copy.id)
|
||||
} else {
|
||||
setCurrentProfile(copy)
|
||||
}
|
||||
} else {
|
||||
strategy.saveProfile(copy)
|
||||
}
|
||||
}
|
||||
|
||||
public func persist() {
|
||||
|
|
Loading…
Reference in New Issue