lock_screen.dart 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import 'package:ente_auth/l10n/l10n.dart';
  2. import 'package:ente_auth/ui/common/gradient_button.dart';
  3. import 'package:ente_auth/ui/tools/app_lock.dart';
  4. import 'package:ente_auth/utils/auth_util.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:logging/logging.dart';
  7. class LockScreen extends StatefulWidget {
  8. const LockScreen({Key? key}) : super(key: key);
  9. @override
  10. State<LockScreen> createState() => _LockScreenState();
  11. }
  12. class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
  13. final _logger = Logger("LockScreen");
  14. bool _isShowingLockScreen = false;
  15. bool _hasPlacedAppInBackground = false;
  16. bool _hasAuthenticationFailed = false;
  17. int? lastAuthenticatingTime;
  18. @override
  19. void initState() {
  20. _logger.info("initState");
  21. super.initState();
  22. _showLockScreen(source: "initState");
  23. WidgetsBinding.instance.addObserver(this);
  24. }
  25. @override
  26. Widget build(BuildContext context) {
  27. return Scaffold(
  28. body: Center(
  29. child: Column(
  30. crossAxisAlignment: CrossAxisAlignment.center,
  31. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  32. children: [
  33. Stack(
  34. alignment: Alignment.center,
  35. children: [
  36. Opacity(
  37. opacity: 0.2,
  38. child: Image.asset('assets/loading_photos_background.png'),
  39. ),
  40. SizedBox(
  41. width: 180,
  42. child: GradientButton(
  43. text: context.l10n.unlock,
  44. iconData: Icons.lock_open_outlined,
  45. onTap: () async {
  46. _showLockScreen(source: "tapUnlock");
  47. },
  48. ),
  49. ),
  50. ],
  51. ),
  52. ],
  53. ),
  54. ),
  55. );
  56. }
  57. @override
  58. void didChangeAppLifecycleState(AppLifecycleState state) {
  59. _logger.info(state.toString());
  60. if (state == AppLifecycleState.resumed && !_isShowingLockScreen) {
  61. // This is triggered either when the lock screen is dismissed or when
  62. // the app is brought to foreground
  63. _hasPlacedAppInBackground = false;
  64. final bool didAuthInLast5Seconds = lastAuthenticatingTime != null &&
  65. DateTime.now().millisecondsSinceEpoch - lastAuthenticatingTime! <
  66. 5000;
  67. if (!_hasAuthenticationFailed && !didAuthInLast5Seconds) {
  68. // Show the lock screen again only if the app is resuming from the
  69. // background, and not when the lock screen was explicitly dismissed
  70. Future.delayed(
  71. Duration.zero, () => _showLockScreen(source: "lifeCycle"));
  72. } else {
  73. _hasAuthenticationFailed = false; // Reset failure state
  74. }
  75. } else if (state == AppLifecycleState.paused ||
  76. state == AppLifecycleState.inactive) {
  77. // This is triggered either when the lock screen pops up or when
  78. // the app is pushed to background
  79. if (!_isShowingLockScreen) {
  80. _hasPlacedAppInBackground = true;
  81. _hasAuthenticationFailed = false; // reset failure state
  82. }
  83. }
  84. }
  85. @override
  86. void dispose() {
  87. WidgetsBinding.instance.removeObserver(this);
  88. super.dispose();
  89. }
  90. Future<void> _showLockScreen({String source = ''}) async {
  91. final int id = DateTime.now().millisecondsSinceEpoch;
  92. _logger.info("Showing lock screen $source $id");
  93. try {
  94. _isShowingLockScreen = true;
  95. final result = await requestAuthentication(
  96. context,
  97. context.l10n.authToViewSecrets,
  98. );
  99. _logger.finest("LockScreen Result $result $id");
  100. _isShowingLockScreen = false;
  101. if (result) {
  102. lastAuthenticatingTime = DateTime.now().millisecondsSinceEpoch;
  103. AppLock.of(context)!.didUnlock();
  104. } else {
  105. if (!_hasPlacedAppInBackground) {
  106. // Treat this as a failure only if user did not explicitly
  107. // put the app in background
  108. _hasAuthenticationFailed = true;
  109. _logger.info("Authentication failed");
  110. }
  111. }
  112. } catch (e, s) {
  113. _isShowingLockScreen = false;
  114. _logger.severe(e, s);
  115. }
  116. }
  117. }