From c94f51a033c7d17d08dae5afb6229abb8ce7993c Mon Sep 17 00:00:00 2001 From: sihoo Date: Mon, 7 Sep 2026 22:47:07 +0900 Subject: [PATCH] =?UTF-8?q?=ED=83=80=EC=9D=BC=20UI=20=ED=8E=B8=EC=A7=91=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=9E=84=EC=8B=9C=20=EB=B3=B4=EB=A5=98=20?= =?UTF-8?q?+=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=9C=A0=EC=A7=80=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=EB=B0=95=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 폰처럼 작은 화면에서 6칸 고정 격자 때문에 레이아웃이 깨지는 문제로, 타일 드래그 이동/크기조절 기능을 kTileEditingEnabled 플래그로 임시 비활성화 (관련 코드는 그대로 유지 - 작은 화면 대응 방안 마련 후 플래그만 켜면 재사용 가능) - 비활성화 상태에서는 화면 폭에 따라 열이 자동으로 줄어드는 기본 그리드 사용 - 설정 화면의 "UI 편집" 항목은 비활성화 표시로 안내 - 로그인 화면에 "로그인 상태 유지" 체크박스 추가 (기본 체크됨, 해제 시 세션 저장 안 함) Co-Authored-By: Claude Sonnet 5 --- lib/models/dashboard_tile_layout.dart | 7 +++ lib/ui/dashboard_settings_page.dart | 17 +++++-- lib/ui/login_screen.dart | 67 ++++++++++++++++++++------- lib/ui/main_dashboard.dart | 43 +++++++++++++---- 4 files changed, 106 insertions(+), 28 deletions(-) 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,