From 206eec03bcec8b5e63f71f1f57378f7be4324c84 Mon Sep 17 00:00:00 2001 From: sihoo Date: Wed, 30 Sep 2026 05:12:55 +0000 Subject: [PATCH] =?UTF-8?q?=EA=B7=B8=EB=A3=B9=20=EC=8A=A4=ED=84=B0?= =?UTF-8?q?=EB=94=94=20=EB=A9=A4=EB=B2=84=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=EC=97=90=2030=EB=B6=84=20=EB=8B=A8=EC=9C=84=20=EC=83=89?= =?UTF-8?q?=EC=83=81=20=ED=85=8C=EB=91=90=EB=A6=AC=20=EC=97=B0=EC=B6=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 오늘 공부 시간이 30분씩 늘어날 때마다 프로필 원형 테두리가 흰→노랑→주황→빨강→보라 순으로 진해지도록(2시간 이상은 보라 고정) 꾸며서 누가 얼마나 공부하고 있는지 한눈에 보이게 함. 범례도 추가. Co-Authored-By: Claude Sonnet 5 --- lib/ui/group_detail_screen.dart | 77 ++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 11 deletions(-) diff --git a/lib/ui/group_detail_screen.dart b/lib/ui/group_detail_screen.dart index 573109b..4a9f0d9 100644 --- a/lib/ui/group_detail_screen.dart +++ b/lib/ui/group_detail_screen.dart @@ -217,6 +217,21 @@ class _GroupDetailScreenState extends State { return '$s초'; } + /// 🎨 오늘 공부 시간 30분 단위로 프로필 테두리 색이 흰→노랑→주황→빨강→보라로 + /// 진해진다. 2시간(4단계) 넘으면 보라색에서 멈춘다. + static const List _studyFrameColors = [ + Color(0xFFE0E0E0), // 흰(기본) + Color(0xFFFFC107), // 노랑 + Color(0xFFFF9800), // 주황 + Color(0xFFE53935), // 빨강 + Color(0xFF8E24AA), // 보라 + ]; + + Color _studyFrameColor(int todaySeconds) { + final tier = (todaySeconds ~/ 1800).clamp(0, _studyFrameColors.length - 1); + return _studyFrameColors[tier]; + } + void _openTimer() { pushLaunchpad( context, @@ -423,6 +438,31 @@ class _GroupDetailScreenState extends State { color: Colors.grey[500], ), ), + const SizedBox(height: 4), + Row( + children: [ + Text( + '프로필 테두리는 30분마다 색이 진해져요', + style: TextStyle( + fontSize: 11.5, + color: Colors.grey[500], + ), + ), + const SizedBox(width: 6), + for (final c in _studyFrameColors) + Padding( + padding: const EdgeInsets.only(left: 2), + child: Container( + width: 10, + height: 10, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: c, + ), + ), + ), + ], + ), const SizedBox(height: 10), GridView.builder( shrinkWrap: true, @@ -438,6 +478,8 @@ class _GroupDetailScreenState extends State { itemBuilder: (context, index) { final m = members[index]; final attended = m['attendedToday'] == true; + final todaySeconds = + (m['todaySeconds'] as num?)?.toInt() ?? 0; return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( @@ -454,14 +496,29 @@ class _GroupDetailScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Icon( - attended - ? Icons.check_circle_rounded - : Icons.radio_button_unchecked_rounded, - color: attended - ? Colors.white - : Colors.grey[350], - size: 18, + Container( + width: 30, + height: 30, + padding: const EdgeInsets.all(2.5), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: _studyFrameColor(todaySeconds), + width: 3, + ), + ), + child: CircleAvatar( + backgroundColor: attended + ? Colors.white24 + : AppPalette.linen, + child: Icon( + Icons.person_rounded, + size: 13, + color: attended + ? Colors.white + : AppPalette.ink, + ), + ), ), const Spacer(), Text( @@ -488,9 +545,7 @@ class _GroupDetailScreenState extends State { ), const SizedBox(height: 2), Text( - _formatMinutes( - (m['todaySeconds'] as num?)?.toInt() ?? 0, - ), + _formatMinutes(todaySeconds), style: TextStyle( fontSize: 11, color: attended