Restore active profile on top

Flashing on activation was caused by VPNManager.disable() in
ProfileView+VPN, because by setting lastError to nil it would
notify a change to ProfileRow (via VPNStateView) during the
profile row activation animation. That caused the flicker.

Instead, disable VPN first, then start the animation.

Anyway, avoid clearing a nil lastError.
This commit is contained in:
Davide De Rosa 2022-05-01 15:35:40 +02:00
parent edc7cdf045
commit cfc0d4f572
4 changed files with 32 additions and 24 deletions

View File

@ -220,18 +220,15 @@ struct OrganizerView: View {
private var sortedHeaders: [Profile.Header] {
profileManager.headers
.sorted()
// FIXME: layout, moving active profile on top breaks row animation (content flashes on Mac)
// .sorted {
// if profileManager.isActiveProfile($0.id) {
// return true
// } else if profileManager.isActiveProfile($1.id) {
// return false
// } else {
// return $0 < $1
// }
// }
.sorted {
if profileManager.isActiveProfile($0.id) {
return true
} else if profileManager.isActiveProfile($1.id) {
return false
} else {
return $0 < $1
}
}
}
}

View File

@ -32,7 +32,8 @@ struct ProfileRow: View {
let isActive: Bool
var body: some View {
VStack(alignment: .leading, spacing: 5) {
debugChanges()
return VStack(alignment: .leading, spacing: 5) {
nameView
.font(.headline)
.themeLongTextStyle()

View File

@ -113,14 +113,18 @@ extension ProfileView {
header: headerView
) {
Button(L10n.Profile.Items.UseProfile.caption) {
withAnimation {
profileManager.activateCurrentProfile()
// IMPORTANT: save immediately to keep in sync with VPN status
appManager.activeProfileId = profileManager.activeHeader?.id
}
Task {
// do this first to not override subsequent animation
// active profile may flicker due to unnecessary VPN updates
await vpnManager.disable()
withAnimation {
profileManager.activateCurrentProfile()
// IMPORTANT: save immediately to keep in sync with VPN status
appManager.activeProfileId = profileManager.activeHeader?.id
}
}
}
}

View File

@ -86,7 +86,7 @@ public class VPNManager: ObservableObject {
}
Task {
pp_log.info("Toggling VPN (enabled: \(currentState.isEnabled) -> \(!currentState.isEnabled))")
currentState.lastError = nil
clearLastError()
if !currentState.isEnabled {
await strategy.connect(configuration: configuration)
} else {
@ -98,25 +98,24 @@ public class VPNManager: ObservableObject {
func reinstate(_ configuration: VPNConfiguration) async {
pp_log.info("Reinstating VPN")
currentState.lastError = nil
clearLastError()
await strategy.reinstate(configuration: configuration)
}
func reconnect(_ configuration: VPNConfiguration) async {
pp_log.info("Reconnecting VPN")
currentState.lastError = nil
await strategy.connect(configuration: configuration)
}
public func disable() async {
pp_log.info("Disabling VPN")
currentState.lastError = nil
clearLastError()
await strategy.disconnect()
}
public func uninstall() async {
pp_log.info("Uninstalling VPN")
currentState.lastError = nil
clearLastError()
await strategy.removeConfigurations()
}
@ -127,6 +126,13 @@ public class VPNManager: ObservableObject {
public func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL? {
return strategy.debugLogURL(forProtocol: vpnProtocol)
}
private func clearLastError() {
guard currentState.lastError != nil else {
return
}
currentState.lastError = nil
}
}
// MARK: Observation