From 29e887cb14f26a1ba72662b5dc855602c2623dea Mon Sep 17 00:00:00 2001 From: 230404 <230404@epvc.pt> Date: Thu, 11 Jun 2026 09:52:06 +0100 Subject: [PATCH] espero que nao presisse mudar. --- lib/controllers/game_controller.dart | 8 ++ lib/main.dart | 39 +++++++- lib/pages/home.dart | 129 +++++++++++++-------------- lib/utils/session_manager.dart | 20 +++++ 4 files changed, 128 insertions(+), 68 deletions(-) create mode 100644 lib/utils/session_manager.dart diff --git a/lib/controllers/game_controller.dart b/lib/controllers/game_controller.dart index cd82fe7..a150329 100644 --- a/lib/controllers/game_controller.dart +++ b/lib/controllers/game_controller.dart @@ -1,4 +1,5 @@ import 'package:supabase_flutter/supabase_flutter.dart'; +import '../utils/session_manager.dart'; import '../models/game_model.dart'; class GameController { @@ -53,6 +54,9 @@ class GameController { // CRIAR JOGO Future createGame(String myTeam, String opponent, String season) async { try { + // Marca que existe uma sessão/jogo em progresso localmente + // (será limpa quando o jogo terminar ou em falha) + await SessionManager.setInProgress(true); final response = await _supabase.from('games').insert({ 'user_id': myUserId, 'my_team': myTeam, @@ -77,6 +81,10 @@ class GameController { return response['id']?.toString(); } catch (e) { print("Erro ao criar jogo: $e"); + // Se houve erro, limpa o flag para não exigir logout indevido + try { + await SessionManager.clear(); + } catch (_) {} return null; } diff --git a/lib/main.dart b/lib/main.dart index 095a6ba..89dbb57 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // Para as orientações import 'package:supabase_flutter/supabase_flutter.dart'; -import 'package:playmaker/classe/theme.dart'; +import 'package:playmaker/classe/theme.dart'; import 'pages/login.dart'; +import 'utils/session_manager.dart'; // Variável global para controlar o Tema final ValueNotifier themeNotifier = ValueNotifier(ThemeMode.system); @@ -25,9 +26,41 @@ void main() async { runApp(const MyApp()); } -class MyApp extends StatelessWidget { +class MyApp extends StatefulWidget { const MyApp({super.key}); - + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State with WidgetsBindingObserver { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) async { + super.didChangeAppLifecycleState(state); + // Quando a app for para background/terminar, se houver sessão em progresso, desliga a sessão + if (state == AppLifecycleState.paused || state == AppLifecycleState.detached) { + final inProgress = await SessionManager.isInProgress(); + if (inProgress) { + try { + await Supabase.instance.client.auth.signOut(); + await SessionManager.clear(); + } catch (_) {} + } + } + } + @override Widget build(BuildContext context) { return ValueListenableBuilder( diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 29cd71f..b64fe9a 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -677,74 +677,73 @@ class _HomeScreenState extends State { ], ); - Widget mainContent = Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InkWell( - onTap: () => _showTeamSelector(context), - child: Container( - padding: EdgeInsets.all(12 * context.sf), - decoration: BoxDecoration( - color: Theme.of(context).cardTheme.color, - borderRadius: - BorderRadius.circular(15 * context.sf), - border: - Border.all(color: Colors.grey.withOpacity(0.2)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row(children: [ - (_selectedTeamLogo != null && - _selectedTeamLogo!.isNotEmpty) - ? ClipOval( - child: CachedNetworkImage( - imageUrl: _selectedTeamLogo!, - width: 24 * context.sf, - height: 24 * context.sf, - fit: BoxFit.cover, - placeholder: (context, url) => Icon( - Icons.shield, - color: AppTheme.primaryRed, - size: 24 * context.sf), - errorWidget: - (context, url, error) => Icon( - Icons.shield, - color: AppTheme.primaryRed, - size: 24 * context.sf), - ), - ) - : Icon(Icons.shield, - color: AppTheme.primaryRed, - size: 24 * context.sf), - SizedBox(width: 10 * context.sf), - Text(_selectedTeamName, - style: TextStyle( - fontSize: 16 * context.sf, - fontWeight: FontWeight.bold, - color: textColor)), - ]), - Icon(Icons.arrow_drop_down, color: textColor), - ], - ), - ), + final Widget teamSelector = InkWell( + onTap: () => _showTeamSelector(context), + child: Container( + padding: EdgeInsets.all(12 * context.sf), + decoration: BoxDecoration( + color: Theme.of(context).cardTheme.color, + borderRadius: BorderRadius.circular(15 * context.sf), + border: Border.all(color: Colors.grey.withOpacity(0.2)), ), - SizedBox(height: 20 * context.sf), - if (!isWide) ...[ + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row(children: [ + (_selectedTeamLogo != null && _selectedTeamLogo!.isNotEmpty) + ? ClipOval( + child: CachedNetworkImage( + imageUrl: _selectedTeamLogo!, + width: 24 * context.sf, + height: 24 * context.sf, + fit: BoxFit.cover, + placeholder: (context, url) => Icon( + Icons.shield, + color: AppTheme.primaryRed, + size: 24 * context.sf), + errorWidget: (context, url, error) => Icon( + Icons.shield, + color: AppTheme.primaryRed, + size: 24 * context.sf), + ), + ) + : Icon(Icons.shield, color: AppTheme.primaryRed, size: 24 * context.sf), + SizedBox(width: 10 * context.sf), + Text(_selectedTeamName, + style: TextStyle(fontSize: 16 * context.sf, fontWeight: FontWeight.bold, color: textColor)), + ]), + Icon(Icons.arrow_drop_down, color: textColor), + ], + ), + ), + ); + + Widget mainContent; + if (isWide) { + mainContent = Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + teamSelector, + SizedBox(height: 20 * context.sf), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(flex: 5, child: statsSection), + SizedBox(width: 20 * context.sf), + Expanded(flex: 6, child: historySection), + ], + ), + ], + ); + } else { + mainContent = Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + teamSelector, + SizedBox(height: 20 * context.sf), statsSection, SizedBox(height: 40 * context.sf), historySection, - ] - ], - ); - - if (isWide) { - mainContent = Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded(flex: 5, child: statsSection), - SizedBox(width: 20 * context.sf), - Expanded(flex: 6, child: historySection), ], ); } @@ -1116,4 +1115,4 @@ class _HomeScreenState extends State { ], ); } -} \ No newline at end of file +} \ No newline at end of file diff --git a/lib/utils/session_manager.dart b/lib/utils/session_manager.dart new file mode 100644 index 0000000..cb4c02b --- /dev/null +++ b/lib/utils/session_manager.dart @@ -0,0 +1,20 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +class SessionManager { + static const _key = 'session_in_progress'; + + static Future setInProgress(bool v) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool(_key, v); + } + + static Future isInProgress() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getBool(_key) ?? false; + } + + static Future clear() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(_key); + } +}