Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an hourly device state read to update the header bar view #4925

Merged

Conversation

buggmagnet
Copy link
Contributor

@buggmagnet buggmagnet commented Jul 25, 2023

This PR introduces a new method in the TunnelObserver protocol.
func tunnelManager(_ manager: TunnelManager, didPeriodicallyRead deviceState: DeviceState)

As the name implies, periodic reads from the DeviceState are now scheduled when the app becomes active via
func didBecomeActive(_ notification: Notification)

Right now, the timer will fire once, and then every hour. It is only active when the app is running, otherwise the timer is cancelled. This is to avoid impact on the battery.

Whenever users now resume the app, the HeaderBarView should display the most recent information it has available.


This change is Reviewable

@buggmagnet buggmagnet added the iOS Issues related to iOS label Jul 25, 2023
@buggmagnet buggmagnet self-assigned this Jul 25, 2023
@linear
Copy link

linear bot commented Jul 25, 2023

IOS-233 Time left in header bar is not updated

Users report that time left label in the header isn't being updated as time passes. We should add a timer that bumps the time left label so that it decrements accurately with time passing.

#4909

Copy link
Collaborator

@mojganii mojganii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 5 files reviewed, 4 unresolved discussions (waiting on @buggmagnet)


ios/MullvadVPN/TunnelManager/TunnelManager.swift line 68 at r1 (raw file):

    private var deviceStateRefreshTimer: DispatchSourceTimer?
    private var isRunningPeriodicStateRefresh = false
    private let deviceStateRefreshPeriod: TimeInterval = 60 * 60

Did you get confirmation about the interval? it seems to me it's a little bit long and the result of that doesn't effects on having better user experience


ios/MullvadVPN/TunnelManager/TunnelManager.swift line 136 at r1 (raw file):

    }

    func startPeriodicStateRefresh() {

nit: StartPeriodicDeviceStateRefresh(). when it comes to state it's not well defined what it's talked about.


ios/MullvadVPN/TunnelManager/TunnelManager.swift line 154 at r1 (raw file):

    }

    func stopPeriodicStateRefresh() {

nit: StopPeriodicDeviceStateRefresh()


ios/MullvadVPN/TunnelManager/TunnelManager.swift line 941 at r1 (raw file):

            guard let deviceState = try? SettingsManager.readDeviceState(),
                  let self = self else { return }
            nslock.withLock {

do we need to do this part of the code with locking while this method is not accessible from others ?

@buggmagnet buggmagnet force-pushed the time-left-in-header-bar-is-not-updated-ios-233 branch from de61147 to 1e6813a Compare July 26, 2023 09:02
Copy link
Contributor Author

@buggmagnet buggmagnet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 5 files reviewed, 4 unresolved discussions (waiting on @mojganii)


ios/MullvadVPN/TunnelManager/TunnelManager.swift line 68 at r1 (raw file):

Previously, mojganii wrote…

Did you get confirmation about the interval? it seems to me it's a little bit long and the result of that doesn't effects on having better user experience

It's by design. The timer will fire immediately when the application re enters foreground which is the desired effect -- refreshing the header bar view to display accurate information.

I don't think people spend hours showing the UI of the application, so this is high enough as to not impact battery life by firing too often.


ios/MullvadVPN/TunnelManager/TunnelManager.swift line 136 at r1 (raw file):

Previously, mojganii wrote…

nit: StartPeriodicDeviceStateRefresh(). when it comes to state it's not well defined what it's talked about.

Fair enough, I will also remove the refresh work as we already use it for a different purposes.
Since we only read the device state, I will rename this "Readings"


ios/MullvadVPN/TunnelManager/TunnelManager.swift line 941 at r1 (raw file):

Previously, mojganii wrote…

do we need to do this part of the code with locking while this method is not accessible from others ?

You're right, the lock is not needed here, thanks for catching that I will remove it.

@buggmagnet buggmagnet force-pushed the time-left-in-header-bar-is-not-updated-ios-233 branch from 1e6813a to e624583 Compare July 26, 2023 09:04
Copy link
Collaborator

@mojganii mojganii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 5 files reviewed, 3 unresolved discussions (waiting on @buggmagnet)


ios/MullvadVPN/TunnelManager/TunnelManager.swift line 68 at r1 (raw file):

Previously, buggmagnet wrote…

It's by design. The timer will fire immediately when the application re enters foreground which is the desired effect -- refreshing the header bar view to display accurate information.

I don't think people spend hours showing the UI of the application, so this is high enough as to not impact battery life by firing too often.

I am wondering if user buys more credit via other platforms while the app is active,our app will be notified quickly or user has to be wait for fire time?

Copy link
Contributor Author

@buggmagnet buggmagnet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 5 files reviewed, 1 unresolved discussion (waiting on @mojganii)


ios/MullvadVPN/TunnelManager/TunnelManager.swift line 68 at r1 (raw file):

Previously, mojganii wrote…

I am wondering if user buys more credit via other platforms while the app is active,our app will be notified quickly or user has to be wait for fire time?

The original mechanism in place hasn't changed for that, so whatever was in place should still work.
Also this fix is only for making sure the HeaderBarView is up to date when the app goes to the foreground after dormancy

Copy link
Collaborator

@mojganii mojganii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 5 files reviewed, all discussions resolved

Copy link
Contributor

@pronebird pronebird left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 3 of 5 files at r1, 2 of 2 files at r2.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @buggmagnet)

a discussion (no related file):
I think we already handle the device state refresh. This is the logic that's currently in place:

  • When the app becomes active we call TunnelManager.refreshDeviceState() in tunnel manager, that makes sure to read new state from settings and propagate it to observers. (TunnelManager.setDeviceState() does the caching, persistence and propagation part).
  • We poll tunnel status periodically to obtain the connection related info, but also last device check (see TunnelManager.setTunnelStatus()). Based on the last and new device check received from packet tunnel, tunnel manager infers whether it needs to refresh device state from settings or switch device to revoked state or any other.

Since we already implement the refresh of device state, I think the only missing piece here is to implement a timer in HeaderBarView that would re-format the label every once in a while. The date assigned to HeaderBar.timeLeft is probably up to date, but the timeLeftLabel.text is only assigned on didSet.


@buggmagnet buggmagnet force-pushed the time-left-in-header-bar-is-not-updated-ios-233 branch from e624583 to c534dd2 Compare August 1, 2023 11:34
Copy link
Contributor

@pronebird pronebird left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 6 files reviewed, 2 unresolved discussions (waiting on @buggmagnet)


ios/MullvadVPN/Containers/Root/HeaderBarView.swift line 250 at r3 (raw file):

        timeLeftTimer = Timer.scheduledTimer(withTimeInterval: timeLeftUpdateInterval, repeats: true) { _ in
            DispatchQueue.main.async { [weak self] in
                self?.timeLeft = self?.timeLeft

Couple of things:

  1. I know it works but it would be cleaner to extract the didSet from var timeLeft: Date? into a separate function and call it from here and from there instead to keep it straightforward what we're trying to achieve.
  2. Block timer will retain self strongly before retaining it weak before passing it into DispatchQueue.main.async {}. That's because strong is default I think.
  3. Repeating Timer still needs to be invalidated from deinit because RunLoop holds a strong reference to it once the timer is scheduled.
  4. Perhaps you don't need to wrap the timer handler into DispatchQueue.main because the timer is scheduled on current runloop which is RunLoop.main so the timer handler block should execute on main thread.

@buggmagnet buggmagnet force-pushed the time-left-in-header-bar-is-not-updated-ios-233 branch 2 times, most recently from 4c0d770 to 3cdaeb2 Compare August 1, 2023 14:21
@buggmagnet buggmagnet force-pushed the time-left-in-header-bar-is-not-updated-ios-233 branch from 3cdaeb2 to 063682c Compare August 1, 2023 14:23
Copy link
Contributor

@pronebird pronebird left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 6 of 6 files at r3, 1 of 1 files at r6.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @buggmagnet)

Copy link
Collaborator

@mojganii mojganii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @buggmagnet)

@pronebird pronebird merged commit abd72c8 into ios-prepare-2023.4 Aug 1, 2023
3 checks passed
@pronebird pronebird deleted the time-left-in-header-bar-is-not-updated-ios-233 branch August 1, 2023 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
iOS Issues related to iOS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants