MIF_E31222656/lib/widgets/session_guard_wrapper.dart

151 lines
4.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:tugas_akhir_supabase/services/session_manager.dart';
import 'package:tugas_akhir_supabase/widgets/session_expired_dialog.dart';
/// A widget that enforces session validation for authenticated routes.
///
/// This widget should wrap any screen that requires authentication.
/// It will automatically check if the session is valid and redirect to login
/// if the session has expired.
class SessionGuardWrapper extends StatefulWidget {
final Widget child;
final bool enforceAuthentication;
const SessionGuardWrapper({
Key? key,
required this.child,
this.enforceAuthentication = true,
}) : super(key: key);
@override
State<SessionGuardWrapper> createState() => _SessionGuardWrapperState();
}
class _SessionGuardWrapperState extends State<SessionGuardWrapper> {
bool _isCheckingSession = false;
bool _sessionExpired = false;
bool _showingDialog = false;
@override
void initState() {
super.initState();
// Check session on widget initialization
if (widget.enforceAuthentication) {
_checkSession();
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// Check session when dependencies change (e.g., after navigation)
if (widget.enforceAuthentication && !_isCheckingSession) {
_checkSession();
}
}
Future<void> _checkSession() async {
// Skip check if not enforcing authentication
if (!widget.enforceAuthentication) return;
// Skip check if already checking
if (_isCheckingSession) return;
// Skip check if no user is logged in
final currentUser = Supabase.instance.client.auth.currentUser;
if (currentUser == null) return;
_isCheckingSession = true;
try {
// Check if session is already marked as expired
if (SessionManager.isExpired) {
if (mounted && !_sessionExpired) {
setState(() {
_sessionExpired = true;
});
_showExpiredDialog();
}
_isCheckingSession = false;
return;
}
// Check session validity
final isValid = await SessionManager.isSessionValid();
if (mounted && !isValid && !_sessionExpired) {
setState(() {
_sessionExpired = true;
});
_showExpiredDialog();
}
} catch (e) {
debugPrint('SessionGuard: Error checking session - $e');
} finally {
_isCheckingSession = false;
}
}
void _showExpiredDialog() {
if (_showingDialog) return;
_showingDialog = true;
// Show dialog on next frame to avoid build phase issues
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) {
_showingDialog = false;
return;
}
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => const SessionExpiredDialog(),
).then((_) {
_showingDialog = false;
});
});
}
@override
Widget build(BuildContext context) {
// If not enforcing authentication, just show the child
if (!widget.enforceAuthentication) {
return widget.child;
}
// If session is expired, show a restricted UI
if (_sessionExpired) {
return Material(
child: Stack(
children: [
// Blur the background content
Opacity(
opacity: 0.3,
child: AbsorbPointer(
child: widget.child,
),
),
// Show a loading indicator if dialog is not showing yet
if (!_showingDialog)
const Center(
child: CircularProgressIndicator(),
),
],
),
);
}
// Session is valid, show the child with a gesture detector to update activity
return GestureDetector(
onTap: () => SessionManager.updateLastUserInteraction(),
onPanDown: (_) => SessionManager.updateLastUserInteraction(),
behavior: HitTestBehavior.translucent,
child: widget.child,
);
}
}