Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ final class VPNDaemon: Daemon, DatabaseAccess, ProvidersAccess {
numberOfAttempts = 0
}

deinit {
NotificationCenter.default.removeObserver(self)
}

func start() {
let nc = NotificationCenter.default
nc.addObserver(self, selector: #selector(neStatusDidChange(notification:)), name: .NEVPNStatusDidChange, object: nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public final class MockVPNProvider: VPNProvider, ConfigurationAccess, DatabaseAc
return nil
}

public var connectionDate: Date? { nil }

/// :nodoc:
public func prepare() {
accessedDatabase.transient.isNetworkReachable = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public final class DefaultVPNProvider: VPNProvider, ConfigurationAccess, Databas
return nil
}

public var connectionDate: Date? { activeProfile?.connectionDate }

private var vpnLog: String {
return accessedDatabase.transient.vpnLog
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public final class IKEv2Profile: NetworkExtensionProfile {
return currentVPN
}

public var connectionDate: Date? { currentVPN.connection.connectedDate }

/// :nodoc:
public func prepare() {
currentVPN.loadFromPreferences { (_) in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
/// :nodoc:
public var native: Any?

public var connectionDate: Date? {
guard let native = native as? NETunnelProviderManager else { return nil }
return native.connection.connectedDate
}

/// :nodoc:
public func prepare() {
find(completionHandler: nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ import Foundation
/// :nodoc:
public var native: Any?

public var connectionDate: Date? {
guard let native = native as? NETunnelProviderManager else { return nil }
return native.connection.connectedDate
}

/// :nodoc:
Comment thread
kp-mario-nachbaur marked this conversation as resolved.
public func prepare() {
find(completionHandler: nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public protocol VPNProfile: AnyObject {
/// The underlying native profile implementation.
var native: Any? { get }

/// The connection date time, if connected. Otherwise nil.
var connectionDate: Date? { get }

/**
Prepares the profile for use, like synchronizing with the current VPN status and making sure that the profile is not corrupt.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public protocol VPNProvider: AnyObject {
/// The `Server` associated with the current profile.
var profileServer: Server? { get }

/// The connection date time, if connected. Otherwise nil.
var connectionDate: Date? { get }

/**
Prepares the provider for VPN operations. Normally invoked when initializing the library.
*/
Expand Down
53 changes: 37 additions & 16 deletions PIA VPN/UI/Dashboard/DashboardViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,31 @@ final class DashboardViewController: AutolayoutViewController {

private var connectionTimer: Timer?

private var formattedConnectionTime: String? {
guard let startTime = Client.preferences.lastVPNConnectionSuccess else {
return nil
private func getOrUpdateConnectionTime(isConnected: Bool) -> TimeInterval? {
let now: TimeInterval = Date.now.timeIntervalSince1970
let connectionTime: TimeInterval?

// by default use the time we know we established the connection
if let lastVPNConnectionSuccess = Client.preferences.lastVPNConnectionSuccess {
connectionTime = now - lastVPNConnectionSuccess
// as fallback use system connected time and use that as connection success
} else if let connectedDate = Client.providers.vpnProvider.connectionDate {
let timeInterval = connectedDate.timeIntervalSince1970
Client.preferences.lastVPNConnectionSuccess = timeInterval
connectionTime = now - timeInterval
// last resort store current time because we know status is connected
} else if isConnected {
Client.preferences.lastVPNConnectionSuccess = now
Comment thread
kp-mario-nachbaur marked this conversation as resolved.
connectionTime = 0
} else {
connectionTime = nil
}

let connectionTime = Date().timeIntervalSince1970 - startTime
return connectionTime
}

private func formatted(connectionTime: TimeInterval?) -> String? {
guard let connectionTime else { return nil }

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
Expand Down Expand Up @@ -1050,7 +1069,8 @@ final class DashboardViewController: AutolayoutViewController {

let titleLabelView = UILabel(frame: CGRect.zero)
titleLabelView.style(style: TextStyle.textStyleNavigationBarTitle)
titleLabelView.text = formattedConnectionTime
let connectionTime = getOrUpdateConnectionTime(isConnected: true)
titleLabelView.text = formatted(connectionTime: connectionTime)
setNavBarTheme(.green, with: titleLabelView)

AppPreferences.shared.todayWidgetVpnStatus = VPNStatus.connected.rawValue
Expand Down Expand Up @@ -1157,18 +1177,18 @@ final class DashboardViewController: AutolayoutViewController {
private func setNavBar(titleLabel: UILabel) {
navigationTitleLabel = titleLabel
#if targetEnvironment(macCatalyst)
if #available(iOS 16.0, *) {
let title = UIBarButtonItem(customView: titleLabel)
if #available(macCatalyst 26.0, *) {
title.hidesSharedBackground = true
if #available(iOS 16.0, *) {
let title = UIBarButtonItem(customView: titleLabel)
if #available(macCatalyst 26.0, *) {
title.hidesSharedBackground = true
}
let titleGroup = UIBarButtonItemGroup.fixedGroup(items: [title])
navigationItem.centerItemGroups = [titleGroup]
} else {
navigationItem.titleView = titleLabel
}
let titleGroup = UIBarButtonItemGroup.fixedGroup(items: [title])
navigationItem.centerItemGroups = [titleGroup]
} else {
navigationItem.title = titleLabel.text
}
#else
navigationItem.titleView = titleLabel
navigationItem.titleView = titleLabel
#endif
setNeedsStatusBarAppearanceUpdate()
}
Expand Down Expand Up @@ -1220,7 +1240,8 @@ final class DashboardViewController: AutolayoutViewController {
}

@objc private func updateConnectionTime() {
navigationTitleLabel?.text = formattedConnectionTime
let connectionTime = getOrUpdateConnectionTime(isConnected: currentStatus == .connected)
navigationTitleLabel?.text = formatted(connectionTime: connectionTime)
}

// MARK: Restylable
Expand Down
Loading