diff --git a/lib/models/dashboard_tile_layout.dart b/lib/models/dashboard_tile_layout.dart index 484e643..6b17732 100644 --- a/lib/models/dashboard_tile_layout.dart +++ b/lib/models/dashboard_tile_layout.dart @@ -1,5 +1,12 @@ // ๐Ÿงฉ ๋Œ€์‹œ๋ณด๋“œ ํƒ€์ผ์˜ ๊ฒฉ์ž ์œ„์น˜/ํฌ๊ธฐ(1x1 ~ 4x4)๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๊ฐ’ ๊ฐ์ฒด. // ์ „์ฒด ๋ฐฐ์น˜ ์บ”๋ฒ„์Šค๋Š” ๊ฐ€๋กœ 6์นธ ร— ์„ธ๋กœ 4์นธ์œผ๋กœ ๊ณ ์ •ํ•œ๋‹ค. + +// ๐Ÿ“ฑ [๊ธฐ๋Šฅ ๋ณด๋ฅ˜] ๋ฐ์Šคํฌํƒ‘์—์„œ๋Š” ์ž˜ ๋‚˜์˜ค์ง€๋งŒ, ํฐ์ฒ˜๋Ÿผ ํ™”๋ฉด์ด ์ž‘์€ ๊ธฐ๊ธฐ์—์„œ๋Š” +// 6์นธ ๊ณ ์ • ๊ฒฉ์ž ๋•Œ๋ฌธ์— ํƒ€์ผ์ด ๋„ˆ๋ฌด ์ž‘์•„์ ธ ๋ ˆ์ด์•„์›ƒ์ด ๊นจ์ง„๋‹ค. +// ์ž‘์€ ํ™”๋ฉด ๋Œ€์‘ ๋ฐฉ์•ˆ์„ ๋งˆ๋ จํ•˜๊ธฐ ์ „๊นŒ์ง€ ํŽธ์ง‘ ๊ธฐ๋Šฅ์„ ์ž„์‹œ๋กœ ๊บผ๋‘”๋‹ค. +// (๋‹ค์‹œ ์ผœ๋ ค๋ฉด ์ด ๊ฐ’๋งŒ true๋กœ ๋ฐ”๊พธ๋ฉด ๋จ โ€” ๊ด€๋ จ ์ฝ”๋“œ๋Š” ๊ทธ๋Œ€๋กœ ๋‚จ๊ฒจ๋‘ ) +const bool kTileEditingEnabled = false; + const int kGridCols = 6; const int kGridRows = 4; const int kMinTileSize = 1; diff --git a/lib/ui/dashboard_settings_page.dart b/lib/ui/dashboard_settings_page.dart index c8f05da..f81cd02 100644 --- a/lib/ui/dashboard_settings_page.dart +++ b/lib/ui/dashboard_settings_page.dart @@ -1,6 +1,7 @@ // โš™๏ธ ๋Œ€์‹œ๋ณด๋“œ ์„ค์ • ํ™”๋ฉด (UI ์ „์šฉ). ์ง€๊ธˆ์€ "UI ํŽธ์ง‘" ์ง„์ž…์  ํ•˜๋‚˜๋งŒ ์žˆ๋‹ค. // "UI ํŽธ์ง‘"์„ ๋ˆ„๋ฅด๋ฉด ์ด ํ™”๋ฉด์„ pop('edit_ui')๋กœ ๋‹ซ๊ณ , ๋Œ€์‹œ๋ณด๋“œ๊ฐ€ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ ํŽธ์ง‘ ๋ชจ๋“œ๋กœ ๋“ค์–ด๊ฐ„๋‹ค. import 'package:flutter/material.dart'; +import '../models/dashboard_tile_layout.dart'; import '../theme/app_palette.dart'; class DashboardSettingsPage extends StatelessWidget { @@ -29,6 +30,7 @@ class DashboardSettingsPage extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), + enabled: kTileEditingEnabled, leading: const Icon( Icons.grid_view_rounded, color: AppPalette.ink, @@ -37,9 +39,18 @@ class DashboardSettingsPage extends StatelessWidget { 'UI ํŽธ์ง‘', style: TextStyle(fontWeight: FontWeight.bold), ), - subtitle: const Text('ํƒ€์ผ์„ ๋“œ๋ž˜๊ทธํ•ด์„œ ์˜ฎ๊ธฐ๊ณ  ํฌ๊ธฐ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์š”.'), - trailing: const Icon(Icons.chevron_right_rounded), - onTap: () => Navigator.pop(context, 'edit_ui'), + // ๐Ÿ“ฑ [๊ธฐ๋Šฅ ๋ณด๋ฅ˜] ์ž‘์€ ํ™”๋ฉด์—์„œ ๋ ˆ์ด์•„์›ƒ์ด ๊นจ์ง€๋Š” ๋ฌธ์ œ๋กœ ์ž ์‹œ ๋ง‰์•„๋‘ . + subtitle: Text( + kTileEditingEnabled + ? 'ํƒ€์ผ์„ ๋“œ๋ž˜๊ทธํ•ด์„œ ์˜ฎ๊ธฐ๊ณ  ํฌ๊ธฐ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์š”.' + : '์ž‘์€ ํ™”๋ฉด ๋Œ€์‘์„ ์ค€๋น„ ์ค‘์ด๋ผ ์ž ์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์–ด์š”.', + ), + trailing: kTileEditingEnabled + ? const Icon(Icons.chevron_right_rounded) + : null, + onTap: kTileEditingEnabled + ? () => Navigator.pop(context, 'edit_ui') + : null, ), ), ], diff --git a/lib/ui/login_screen.dart b/lib/ui/login_screen.dart index 7c79629..6ac3348 100644 --- a/lib/ui/login_screen.dart +++ b/lib/ui/login_screen.dart @@ -23,6 +23,7 @@ class _LoginScreenState extends State { final LoginController _controller = LoginController(); final TextEditingController _idController = TextEditingController(); final TextEditingController _pwController = TextEditingController(); + bool _keepLoggedIn = true; @override void dispose() { @@ -44,14 +45,18 @@ class _LoginScreenState extends State { _showErrorDialog(result.errorMessage!); break; case LoginOutcome.masterSuccess: - await SessionStore.save( - SavedSession( - userId: result.studentId!, - userName: result.name!, - role: 'student', - isDeviceMatched: true, - ), - ); + if (_keepLoggedIn) { + await SessionStore.save( + SavedSession( + userId: result.studentId!, + userName: result.name!, + role: 'student', + isDeviceMatched: true, + ), + ); + } else { + await SessionStore.clear(); + } if (!mounted) return; ScaffoldMessenger.of( context, @@ -194,14 +199,18 @@ class _LoginScreenState extends State { String name, bool isDeviceMatched, ) async { - await SessionStore.save( - SavedSession( - userId: studentId, - userName: name, - role: role, - isDeviceMatched: isDeviceMatched, - ), - ); + if (_keepLoggedIn) { + await SessionStore.save( + SavedSession( + userId: studentId, + userName: name, + role: role, + isDeviceMatched: isDeviceMatched, + ), + ); + } else { + await SessionStore.clear(); + } if (!mounted) return; Navigator.pushReplacement( context, @@ -349,7 +358,31 @@ class _LoginScreenState extends State { prefixIcon: Icon(Icons.lock), ), ), - const SizedBox(height: 24), + const SizedBox(height: 8), + InkWell( + onTap: () => + setState(() => _keepLoggedIn = !_keepLoggedIn), + borderRadius: BorderRadius.circular(8), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Checkbox( + value: _keepLoggedIn, + activeColor: AppPalette.ink, + onChanged: (value) => + setState(() => _keepLoggedIn = value ?? true), + ), + const Text( + '๋กœ๊ทธ์ธ ์ƒํƒœ ์œ ์ง€', + style: TextStyle(color: AppPalette.ink), + ), + ], + ), + ), + ), + const SizedBox(height: 16), _controller.isLoading ? const CircularProgressIndicator() : SizedBox( diff --git a/lib/ui/main_dashboard.dart b/lib/ui/main_dashboard.dart index dd2708b..b552c55 100644 --- a/lib/ui/main_dashboard.dart +++ b/lib/ui/main_dashboard.dart @@ -60,7 +60,10 @@ class _MainDashboardState extends State { void initState() { super.initState(); _layout = DashboardLayoutController(_displayId); - _layout.load(_tileSpecs().map((t) => t.id).toList()); + // ๐Ÿ“ฑ [๊ธฐ๋Šฅ ๋ณด๋ฅ˜] kTileEditingEnabled๊ฐ€ false์ธ ๋™์•ˆ์€ ์„œ๋ฒ„์—์„œ ๋ฐฐ์น˜๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ํ•„์š”๊ฐ€ ์—†๋‹ค. + if (kTileEditingEnabled) { + _layout.load(_tileSpecs().map((t) => t.id).toList()); + } } @override @@ -193,7 +196,7 @@ class _MainDashboardState extends State { context, MaterialPageRoute(builder: (context) => const DashboardSettingsPage()), ); - if (result == 'edit_ui') { + if (result == 'edit_ui' && kTileEditingEnabled) { _layout.enterEditMode(); } } @@ -577,12 +580,16 @@ class _MainDashboardState extends State { ), ), const SizedBox(height: 16), - _layout.isLoading - ? const Padding( - padding: EdgeInsets.symmetric(vertical: 40), - child: Center(child: CircularProgressIndicator()), - ) - : _buildGridCanvas(tiles, isEditing), + // ๐Ÿ“ฑ [๊ธฐ๋Šฅ ๋ณด๋ฅ˜] kTileEditingEnabled๊ฐ€ ๊บผ์ ธ ์žˆ๋Š” ๋™์•ˆ์€ ํ™”๋ฉด ํฌ๊ธฐ์— ๋งž์ถฐ + // ์•Œ์•„์„œ ์ค„์„œ๋Š” ๊ธฐ๋ณธ ๊ทธ๋ฆฌ๋“œ๋ฅผ ์“ฐ๊ณ , ๋“œ๋ž˜๊ทธ ํŽธ์ง‘์šฉ ์บ”๋ฒ„์Šค๋Š” ์“ฐ์ง€ ์•Š๋Š”๋‹ค. + kTileEditingEnabled + ? (_layout.isLoading + ? const Padding( + padding: EdgeInsets.symmetric(vertical: 40), + child: Center(child: CircularProgressIndicator()), + ) + : _buildGridCanvas(tiles, isEditing)) + : _buildSimpleGrid(tiles), const SizedBox(height: 32), ], ), @@ -592,6 +599,26 @@ class _MainDashboardState extends State { ); } + // ๐Ÿ“ฑ [๊ธฐ๋Šฅ ๋ณด๋ฅ˜] kTileEditingEnabled๊ฐ€ ๊บผ์ ธ ์žˆ์„ ๋•Œ ์“ฐ๋Š” ๊ธฐ๋ณธ ๊ทธ๋ฆฌ๋“œ. + // ํ™”๋ฉด ํญ์— ๋งž์ถฐ ์—ด ๊ฐœ์ˆ˜๊ฐ€ ์ž๋™์œผ๋กœ ์ค„์–ด๋“ค๊ธฐ ๋•Œ๋ฌธ์— ํฐ์—์„œ๋„ ์•ˆ ๊นจ์ง„๋‹ค. + Widget _buildSimpleGrid(List<({String id, Widget child})> tiles) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 160, + mainAxisSpacing: 12, + crossAxisSpacing: 12, + childAspectRatio: 1, + ), + itemCount: tiles.length, + itemBuilder: (context, index) => tiles[index].child, + ), + ); + } + Widget _buildGridCanvas( List<({String id, Widget child})> tiles, bool isEditing,