123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- import "dart:io";
- import 'package:flutter/material.dart';
- import 'package:logging/logging.dart';
- import "package:photos/l10n/l10n.dart";
- import 'package:photos/ui/common/gradient_button.dart';
- import 'package:photos/ui/tools/app_lock.dart';
- import 'package:photos/utils/auth_util.dart';
- class LockScreen extends StatefulWidget {
- const LockScreen({Key? key}) : super(key: key);
- @override
- State<LockScreen> createState() => _LockScreenState();
- }
- class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
- final _logger = Logger("LockScreen");
- bool _isShowingLockScreen = false;
- bool _hasPlacedAppInBackground = false;
- bool _hasAuthenticationFailed = false;
- int? lastAuthenticatingTime;
- @override
- void initState() {
- _logger.info("initiatingState");
- super.initState();
- WidgetsBinding.instance.addObserver(this);
- WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
- if (isNonMobileIOSDevice()) {
- _logger.info('ignore init for non mobile iOS device');
- return;
- }
- _showLockScreen(source: "postFrameInit");
- });
- }
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Center(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Stack(
- alignment: Alignment.center,
- children: [
- Opacity(
- opacity: 0.2,
- child: Image.asset('assets/loading_photos_background.png'),
- ),
- SizedBox(
- width: 180,
- child: GradientButton(
- text: context.l10n.unlock,
- iconData: Icons.lock_open_outlined,
- onTap: () async {
- _showLockScreen(source: "tapUnlock");
- },
- ),
- ),
- ],
- ),
- ],
- ),
- ),
- );
- }
- bool isNonMobileIOSDevice() {
- if (Platform.isAndroid) {
- return false;
- }
- var shortestSide = MediaQuery.of(context).size.shortestSide;
- return shortestSide > 600 ? true : false;
- }
- @override
- void didChangeAppLifecycleState(AppLifecycleState state) {
- _logger.info(state.toString());
- if (state == AppLifecycleState.resumed && !_isShowingLockScreen) {
- // This is triggered either when the lock screen is dismissed or when
- // the app is brought to foreground
- _hasPlacedAppInBackground = false;
- final bool didAuthInLast5Seconds = lastAuthenticatingTime != null &&
- DateTime.now().millisecondsSinceEpoch - lastAuthenticatingTime! <
- 5000;
- if (!_hasAuthenticationFailed && !didAuthInLast5Seconds) {
- // Show the lock screen again only if the app is resuming from the
- // background, and not when the lock screen was explicitly dismissed
- Future.delayed(
- Duration.zero,
- () => _showLockScreen(source: "lifeCycle"),
- );
- } else {
- _hasAuthenticationFailed = false; // Reset failure state
- }
- } else if (state == AppLifecycleState.paused ||
- state == AppLifecycleState.inactive) {
- // This is triggered either when the lock screen pops up or when
- // the app is pushed to background
- if (!_isShowingLockScreen) {
- _hasPlacedAppInBackground = true;
- _hasAuthenticationFailed = false; // reset failure state
- }
- }
- }
- @override
- void dispose() {
- _logger.info('disposing');
- WidgetsBinding.instance.removeObserver(this);
- super.dispose();
- }
- Future<void> _showLockScreen({String source = ''}) async {
- final int id = DateTime.now().millisecondsSinceEpoch;
- _logger.info("Showing lock screen $source $id");
- try {
- _isShowingLockScreen = true;
- final result = await requestAuthentication(
- context,
- context.l10n.authToViewYourMemories,
- );
- _logger.finest("LockScreen Result $result $id");
- _isShowingLockScreen = false;
- if (result) {
- lastAuthenticatingTime = DateTime.now().millisecondsSinceEpoch;
- AppLock.of(context)!.didUnlock();
- } else {
- if (!_hasPlacedAppInBackground) {
- // Treat this as a failure only if user did not explicitly
- // put the app in background
- _hasAuthenticationFailed = true;
- _logger.info("Authentication failed");
- }
- }
- } catch (e, s) {
- _isShowingLockScreen = false;
- _logger.severe(e, s);
- }
- }
- }
|