lock_screen.dart 3.4 KB

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