diff --git a/CHANGELOG.md b/CHANGELOG.md index 370e878..ece4ba2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,8 @@ Versions follow [semver](https://semver.org/): MAJOR.MINOR.PATCH off the same deadline it already enforces, so the warning still arrives when the app is closed, and a support top-up moves it with the deadline. - **"Disconnected — not protected" notification** when a session ends without - you asking: the 2-hour expiry, the data limit, the server ending the session, - or the tunnel reporting an error. + you asking: the 2-hour expiry, the data limit, or the server ending the + session. - **SOCKS5 mode now asks for the notification permission.** It never did, because it never raises the VPN consent dialog, so on Android 13+ these alerts would have been dropped before they were shown. diff --git a/lib/logic/session_timer.dart b/lib/logic/session_timer.dart index fb59bf4..9e8b138 100644 --- a/lib/logic/session_timer.dart +++ b/lib/logic/session_timer.dart @@ -426,6 +426,20 @@ class SessionTimer extends ChangeNotifier with WidgetsBindingObserver { final elapsed = clock.elapsed.inSeconds; _remainingSeconds = (_remainingAtLastSync - elapsed).clamp(0, 1 << 31).toInt(); + + // The Stopwatch is CLOCK_MONOTONIC and stops while the device is + // suspended, so after a long sleep it over-reports - and with the server + // unreachable no sync arrives to correct it, which is exactly the state + // the app now stays in rather than disconnecting. Take whichever is + // smaller, never the wall clock alone: a clock set backwards must not be + // able to extend a session. + final deadline = _deadlineAt; + if (deadline != null) { + final byWallClock = deadline.difference(DateTime.now()).inSeconds; + if (byWallClock < _remainingSeconds) { + _remainingSeconds = byWallClock.clamp(0, 1 << 31).toInt(); + } + } } @override