[auth] Reduce progress bar refresh rate to lower CPU usage (#4517)

## Description
Related
https://github.com/ente-io/ente/issues/2003#issuecomment-2563380828
## Tests
This commit is contained in:
Neeraj Gupta
2024-12-27 13:20:32 +05:30
committed by GitHub
5 changed files with 53 additions and 46 deletions

View File

@@ -1,58 +1,58 @@
import 'package:ente_auth/services/preference_service.dart';
import 'dart:async';
import 'dart:io';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class CodeTimerProgressCache {
static final Map<int, CodeTimerProgress> _cache = {};
static CodeTimerProgress getCachedWidget(int period) {
if (!_cache.containsKey(period)) {
_cache[period] = CodeTimerProgress(period: period);
}
return _cache[period]!;
}
}
class CodeTimerProgress extends StatefulWidget {
final int period;
final bool isCompactMode;
const CodeTimerProgress({
super.key,
required this.period,
this.isCompactMode = false,
});
@override
State<CodeTimerProgress> createState() => _CodeTimerProgressState();
}
class _CodeTimerProgressState extends State<CodeTimerProgress>
with SingleTickerProviderStateMixin {
late final Ticker _ticker;
class _CodeTimerProgressState extends State<CodeTimerProgress> {
late final Timer _timer;
late final ValueNotifier<double> _progress;
late final int _microSecondsInPeriod;
late bool _isCompactMode=false;
late final int _periodInMicros;
// Cache the start time to avoid repeated system calls
late final int _startMicros;
// Reduce update frequency
final int _updateIntervalMs =
(Platform.isAndroid || Platform.isIOS) ? 16 : 500; // approximately 60 FPS
@override
void initState() {
super.initState();
_microSecondsInPeriod = widget.period * 1000000;
_periodInMicros = widget.period * 1000000;
_progress = ValueNotifier<double>(0.0);
_ticker = createTicker(_updateTimeRemaining);
_ticker.start();
_isCompactMode = PreferenceService.instance.isCompactMode();
_updateTimeRemaining(Duration.zero);
_startMicros = DateTime.now().microsecondsSinceEpoch;
// Use a Timer instead of a Ticker
_timer = Timer.periodic(Duration(milliseconds: _updateIntervalMs), (timer) {
final now = DateTime.now().microsecondsSinceEpoch;
_updateTimeRemaining(now);
});
}
void _updateTimeRemaining(Duration elapsed) {
int timeRemaining = _microSecondsInPeriod -
(DateTime.now().microsecondsSinceEpoch % _microSecondsInPeriod);
_progress.value = timeRemaining / _microSecondsInPeriod;
void _updateTimeRemaining(int currentMicros) {
// More efficient time calculation using modulo
final elapsed = (currentMicros - _startMicros) % _periodInMicros;
final timeRemaining = _periodInMicros - elapsed;
_progress.value = timeRemaining / _periodInMicros;
}
@override
void dispose() {
_ticker.dispose();
_timer.cancel();
_progress.dispose();
super.dispose();
}
@@ -60,18 +60,19 @@ class _CodeTimerProgressState extends State<CodeTimerProgress>
@override
Widget build(BuildContext context) {
return SizedBox(
height: _isCompactMode ?1:3,
height: widget.isCompactMode ? 1 : 3,
child: ValueListenableBuilder<double>(
valueListenable: _progress,
builder: (context, progress, _) {
return CustomPaint(
key: Key(progress.toString()), // Add key here
painter: _ProgressPainter(
progress: progress,
color: progress > 0.4
? getEnteColorScheme(context).primary700
: Colors.orange,
),
size: Size.infinite,
size: const Size.fromHeight(double.infinity),
);
},
),
@@ -83,7 +84,10 @@ class _ProgressPainter extends CustomPainter {
final double progress;
final Color color;
_ProgressPainter({required this.progress, required this.color});
const _ProgressPainter({
required this.progress,
required this.color,
});
@override
void paint(Canvas canvas, Size size) {

View File

@@ -146,8 +146,10 @@ class _CodeWidgetState extends State<CodeWidget> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (widget.code.type.isTOTPCompatible)
CodeTimerProgressCache.getCachedWidget(
widget.code.period,
CodeTimerProgress(
key: ValueKey('period_${widget.code.period}'),
period: widget.code.period,
isCompactMode: widget.isCompactMode,
),
widget.isCompactMode
? const SizedBox(height: 4)

View File

@@ -429,6 +429,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.ente.auth.mac;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;

View File

@@ -42,10 +42,10 @@ packages:
dependency: "direct main"
description:
name: app_links
sha256: ad1a6d598e7e39b46a34f746f9a8b011ee147e4c275d407fa457e7a62f84dd99
sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950"
url: "https://pub.dev"
source: hosted
version: "6.3.2"
version: "6.3.3"
app_links_linux:
dependency: transitive
description:
@@ -528,10 +528,10 @@ packages:
dependency: "direct main"
description:
name: flutter_inappwebview
sha256: "93cfcca02bdda4b26cd700cf70d9ddba09d8348e3e8f2857638c23ed23a4fcb4"
sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5"
url: "https://pub.dev"
source: hosted
version: "6.1.4"
version: "6.1.5"
flutter_inappwebview_android:
dependency: transitive
description:
@@ -584,10 +584,10 @@ packages:
dependency: transitive
description:
name: flutter_inappwebview_windows
sha256: "95ebc65aecfa63b2084c822aec6ba0545f0a0afaa3899f2c752ec96c09108db5"
sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055"
url: "https://pub.dev"
source: hosted
version: "0.5.0+2"
version: "0.6.0"
flutter_launcher_icons:
dependency: "direct main"
description:
@@ -985,10 +985,10 @@ packages:
dependency: "direct main"
description:
name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
macros:
dependency: transitive
description:
@@ -1655,10 +1655,10 @@ packages:
dependency: "direct main"
description:
name: url_launcher
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603"
url: "https://pub.dev"
source: hosted
version: "6.3.0"
version: "6.3.1"
url_launcher_android:
dependency: transitive
description:
@@ -1668,7 +1668,7 @@ packages:
source: hosted
version: "6.3.11"
url_launcher_ios:
dependency: transitive
dependency: "direct main"
description:
name: url_launcher_ios
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e

View File

@@ -1,6 +1,6 @@
name: ente_auth
description: ente two-factor authenticator
version: 4.2.0+420
version: 4.2.1+421
publish_to: none
environment: