Last active
June 21, 2024 09:47
-
-
Save urusaich/290d96eac64a3d7047b8187805d18107 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:flutter/widgets.dart'; | |
import 'resume_lock_action.dart'; | |
import 'resume_lock_delegate.dart'; | |
export 'resume_lock_action.dart'; | |
export 'resume_lock_delegate.dart'; | |
typedef LockerRouteBuilder<T> = Route<T> Function(Widget child); | |
abstract base class ResumeLock extends StatefulWidget { | |
const ResumeLock({ | |
super.key, | |
required this.delegate, | |
required this.navigatorKey, | |
this.locked = false, | |
required this.child, | |
}); | |
final ResumeLockDelegate delegate; | |
final GlobalKey<NavigatorState> navigatorKey; | |
final bool locked; | |
final Widget child; | |
@override | |
ResumeLockState createState() => ResumeLockState(); | |
Widget buildLocker(BuildContext context); | |
Route<dynamic> buildRoute(Widget child); | |
static ResumeLockState? maybeOf(BuildContext context) => | |
context.findAncestorStateOfType<ResumeLockState>(); | |
static ResumeLockState of(BuildContext context) => maybeOf(context)!; | |
} | |
class ResumeLockState extends State<ResumeLock> with WidgetsBindingObserver { | |
late bool _locked; | |
NavigatorState? get navigator => widget.navigatorKey.currentState; | |
@override | |
void initState() { | |
super.initState(); | |
WidgetsBinding.instance.addObserver(this); | |
_locked = widget.locked; | |
} | |
@override | |
void dispose() { | |
WidgetsBinding.instance.removeObserver(this); | |
super.dispose(); | |
} | |
@override | |
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async { | |
switch (state) { | |
case AppLifecycleState.paused: | |
widget.delegate.onPaused(); | |
case AppLifecycleState.resumed: | |
switch (await widget.delegate.onResumed(context)) { | |
case ResumeLockActionNone(): | |
return; | |
case ResumeLockActionLock(): | |
lock(); | |
} | |
case _: | |
} | |
} | |
Widget buildChild(Widget child) => PopScope(canPop: false, child: child); | |
void lock() { | |
if (_locked || navigator == null) { | |
return; | |
} | |
_locked = true; | |
unawaited( | |
navigator!.push( | |
widget.buildRoute(buildChild(widget.buildLocker(context))), | |
), | |
); | |
widget.delegate.onLocked(); | |
} | |
void unlock() { | |
if (!_locked || navigator == null) { | |
return; | |
} | |
_locked = false; | |
navigator!.pop(); | |
widget.delegate.onUnlocked(); | |
} | |
@override | |
Widget build(BuildContext context) => widget.child; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed class ResumeLockAction { | |
const ResumeLockAction._(); | |
const factory ResumeLockAction.none() = ResumeLockActionNone._; | |
const factory ResumeLockAction.lock() = ResumeLockActionLock._; | |
} | |
class ResumeLockActionNone extends ResumeLockAction { | |
const ResumeLockActionNone._() : super._(); | |
} | |
class ResumeLockActionLock extends ResumeLockAction { | |
const ResumeLockActionLock._() : super._(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/widgets.dart'; | |
import 'resume_lock_action.dart'; | |
abstract class ResumeLockDelegate { | |
const ResumeLockDelegate(); | |
Future<ResumeLockAction> onResumed(BuildContext context); | |
void onPaused() {} | |
void onLocked() {} | |
void onUnlocked() {} | |
@protected | |
ResumeLockAction doNone() => const ResumeLockAction.none(); | |
@protected | |
ResumeLockAction doLock() => const ResumeLockAction.lock(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'resume_lock_delegate.dart'; | |
abstract class TimeResumeLockDelegate extends ResumeLockDelegate { | |
TimeResumeLockDelegate({required this.lockTimeout}); | |
final Duration lockTimeout; | |
DateTime? _pauseTime; | |
bool shouldLock() { | |
if (_pauseTime == null) { | |
return false; | |
} | |
final shouldLockAt = _pauseTime!.add(lockTimeout); | |
final should = DateTime.now().isAfter(shouldLockAt); | |
if (should) { | |
return true; | |
} | |
_pauseTime = null; | |
return false; | |
} | |
@override | |
void onPaused() => _pauseTime = DateTime.now(); | |
@override | |
void onUnlocked() => _pauseTime = null; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyResumeLockDelegate extends TimeResumeLockDelegate { | |
MyResumeLockDelegate({required super.lockTimeout}); | |
@override | |
Future<ResumeLockAction> onResumed(BuildContext context) async { | |
// return doNone() or doLock() | |
// unauth and route user to auth page here and return doNone() after | |
} | |
} | |
base class MyResumeLock extends ResumeLock { | |
const MyResumeLock({ | |
super.key, | |
required super.delegate, | |
required super.navigatorKey, | |
required super.child, | |
}); | |
@override | |
Widget buildLocker(BuildContext context) => const ResumeView(); | |
@override | |
Route<dynamic> buildRoute(Widget child) => | |
MaterialPageRoute(builder: (context) => child) | |
} | |
class ResumeView extends StatelessWidget { | |
Widget build(BuildContext context) { | |
// ResumeLock.of(context) - ResumeLockState.lock() or ResumeLockState.unlock() available here | |
} | |
} | |
MaterialApp.router( | |
builder: (context, child) => MyResumeLock(navigatorKey: navigatorKey, delegate: MyResumeLockDelegate(lockTimeout: const Duration(seconds: 10)), child: child) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment