전체 UI 색상 통일 - 제각각이던 빨강/주황/파랑 계열을 의미별 토큰 4종으로 정리
danger/warning/success/approved(+각 Bg 버전)를 AppPalette에 추가하고, 화면마다 다르게 쓰이던 Colors.red[400/600/700]/redAccent, orange/amber 계열, blue 계열 리터럴을 전부 해당 토큰으로 교체. NFC 체크인 화면의 홀로 튀던 Colors.blueAccent도 함께 정리.
This commit is contained in:
@@ -11,4 +11,15 @@ class AppPalette {
|
|||||||
static const Color linen = Color(0xFFECEBE4); // 은은한 카드/배지 배경
|
static const Color linen = Color(0xFFECEBE4); // 은은한 카드/배지 배경
|
||||||
static const Color mist = Color(0xFFEEF0F2); // 페이지 배경
|
static const Color mist = Color(0xFFEEF0F2); // 페이지 배경
|
||||||
static const Color paper = Color(0xFFFAFAFF); // 카드 표면(거의 흰색)
|
static const Color paper = Color(0xFFFAFAFF); // 카드 표면(거의 흰색)
|
||||||
|
|
||||||
|
// 🚨 경고성 색상 3종 - 예전엔 화면마다 Colors.red/red[400]/red[700]/redAccent처럼
|
||||||
|
// 제각각 써서 같은 의미인데 색이 미묘하게 달랐다. 이제 의미별로 딱 하나씩만 쓴다.
|
||||||
|
static const Color danger = Color(0xFFE13B3B); // 삭제/위반/거절/신고 등 위험/경고
|
||||||
|
static const Color dangerBg = Color(0xFFFCE9E9); // danger의 연한 배경(배지 등)
|
||||||
|
static const Color warning = Color(0xFFF08A24); // 대기중/수업중/진행중 등 주의
|
||||||
|
static const Color warningBg = Color(0xFFFDF0E1); // warning의 연한 배경
|
||||||
|
static const Color success = Color(0xFF2E9E5B); // 완료/성공(NFC 스캔 성공 등)
|
||||||
|
static const Color successBg = Color(0xFFE4F5EB); // success의 연한 배경
|
||||||
|
static const Color approved = Color(0xFF3B78C2); // 승인됨/완료 상태 표시
|
||||||
|
static const Color approvedBg = Color(0xFFE7F0FA); // approved의 연한 배경
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,10 @@ class _AdminDashboardState extends State<AdminDashboard> {
|
|||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text(
|
title: const Text(
|
||||||
'DB 초기화 경고',
|
'DB 초기화 경고',
|
||||||
style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),
|
style: TextStyle(
|
||||||
|
color: AppPalette.danger,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
content: const Text(
|
content: const Text(
|
||||||
'모든 학생의 출석 및 휴대폰 제출 데이터가 영구적으로 삭제됩니다.\n\n정말 초기화하시겠습니까?',
|
'모든 학생의 출석 및 휴대폰 제출 데이터가 영구적으로 삭제됩니다.\n\n정말 초기화하시겠습니까?',
|
||||||
@@ -50,7 +53,9 @@ class _AdminDashboardState extends State<AdminDashboard> {
|
|||||||
child: const Text('취소', style: TextStyle(color: Colors.grey)),
|
child: const Text('취소', style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: AppPalette.danger,
|
||||||
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(dialogContext);
|
Navigator.pop(dialogContext);
|
||||||
_resetDatabase();
|
_resetDatabase();
|
||||||
@@ -113,16 +118,18 @@ class _AdminDashboardState extends State<AdminDashboard> {
|
|||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
|
|
||||||
_controller.isLoading
|
_controller.isLoading
|
||||||
? const CircularProgressIndicator(color: Colors.red)
|
? const CircularProgressIndicator(
|
||||||
|
color: AppPalette.danger,
|
||||||
|
)
|
||||||
: SizedBox(
|
: SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 60,
|
height: 60,
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.red[50],
|
backgroundColor: AppPalette.dangerBg,
|
||||||
foregroundColor: Colors.red,
|
foregroundColor: AppPalette.danger,
|
||||||
side: const BorderSide(
|
side: const BorderSide(
|
||||||
color: Colors.red,
|
color: AppPalette.danger,
|
||||||
width: 2,
|
width: 2,
|
||||||
),
|
),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ class _BoardPostDetailScreenState extends State<BoardPostDetailScreen> {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(dialogContext, true),
|
onPressed: () => Navigator.pop(dialogContext, true),
|
||||||
child: const Text('삭제', style: TextStyle(color: Colors.red)),
|
child: const Text('삭제', style: TextStyle(color: AppPalette.danger)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ class _BoardReportScreenState extends State<BoardReportScreen> {
|
|||||||
Text(
|
Text(
|
||||||
'신고 사유: ${report['reason']}',
|
'신고 사유: ${report['reason']}',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.redAccent,
|
color: AppPalette.danger,
|
||||||
fontSize: 12.5,
|
fontSize: 12.5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -145,7 +145,7 @@ class _BoardReportScreenState extends State<BoardReportScreen> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.red[400],
|
backgroundColor: AppPalette.danger,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
onPressed: _controller.isBusy
|
onPressed: _controller.isBusy
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
title: const Row(
|
title: const Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.warning_amber_rounded, color: Colors.orange),
|
Icon(Icons.warning_amber_rounded, color: AppPalette.warning),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text('많은 시간요청 학생'),
|
Text('많은 시간요청 학생'),
|
||||||
],
|
],
|
||||||
@@ -147,7 +147,7 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
'${_timeRange(r['requestedStart'], r['requestedEnd'])} '
|
'${_timeRange(r['requestedStart'], r['requestedEnd'])} '
|
||||||
'(약 ${hours?.toStringAsFixed(1)}시간)',
|
'(약 ${hours?.toStringAsFixed(1)}시간)',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.orange,
|
color: AppPalette.warning,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
),
|
),
|
||||||
@@ -172,8 +172,10 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
_reject(r['id']);
|
_reject(r['id']);
|
||||||
},
|
},
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
foregroundColor: Colors.red,
|
foregroundColor: AppPalette.danger,
|
||||||
side: const BorderSide(color: Colors.red),
|
side: const BorderSide(
|
||||||
|
color: AppPalette.danger,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: const Text('거절'),
|
child: const Text('거절'),
|
||||||
),
|
),
|
||||||
@@ -224,13 +226,13 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
({Color color, String label}) _statusInfo(String status) {
|
({Color color, String label}) _statusInfo(String status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'PENDING':
|
case 'PENDING':
|
||||||
return (color: Colors.orange, label: '대기중');
|
return (color: AppPalette.warning, label: '대기중');
|
||||||
case 'APPROVED':
|
case 'APPROVED':
|
||||||
return (color: Colors.blue, label: '승인됨');
|
return (color: AppPalette.approved, label: '승인됨');
|
||||||
case 'RETURNED':
|
case 'RETURNED':
|
||||||
return (color: Colors.grey, label: '반납완료');
|
return (color: Colors.grey, label: '반납완료');
|
||||||
case 'REJECTED':
|
case 'REJECTED':
|
||||||
return (color: Colors.red, label: '거절됨');
|
return (color: AppPalette.danger, label: '거절됨');
|
||||||
default:
|
default:
|
||||||
return (color: Colors.grey, label: status);
|
return (color: Colors.grey, label: status);
|
||||||
}
|
}
|
||||||
@@ -276,7 +278,7 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
icon: Badge(
|
icon: Badge(
|
||||||
isLabelVisible: longCount > 0,
|
isLabelVisible: longCount > 0,
|
||||||
label: Text('$longCount'),
|
label: Text('$longCount'),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: AppPalette.danger,
|
||||||
child: const Icon(Icons.warning_amber_rounded),
|
child: const Icon(Icons.warning_amber_rounded),
|
||||||
),
|
),
|
||||||
onPressed: _showLongRequestsDialog,
|
onPressed: _showLongRequestsDialog,
|
||||||
@@ -297,14 +299,14 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
vertical: 10,
|
vertical: 10,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.orange[100],
|
color: AppPalette.warningBg,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(color: Colors.orange[400]!),
|
border: Border.all(color: AppPalette.warning),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'승인 대기 중인 요청이 $pendingCount건 있습니다.',
|
'승인 대기 중인 요청이 $pendingCount건 있습니다.',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.orange[900],
|
color: AppPalette.warning,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -340,15 +342,15 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
side: isLong
|
side: isLong
|
||||||
? BorderSide(
|
? const BorderSide(
|
||||||
color: Colors.red[400]!,
|
color: AppPalette.danger,
|
||||||
width: 2,
|
width: 2,
|
||||||
)
|
)
|
||||||
: (isPending
|
: (isPending
|
||||||
? BorderSide(
|
? const BorderSide(
|
||||||
color: Colors.orange[300]!,
|
color: AppPalette.warning,
|
||||||
)
|
)
|
||||||
: BorderSide(
|
: const BorderSide(
|
||||||
color: AppPalette.sage,
|
color: AppPalette.sage,
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
@@ -419,7 +421,7 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
Text(
|
Text(
|
||||||
'${r['approvedByTeacherName']} 선생님이 허용했습니다',
|
'${r['approvedByTeacherName']} 선생님이 허용했습니다',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.blue[700],
|
color: AppPalette.approved,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@@ -438,9 +440,10 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
style:
|
style:
|
||||||
OutlinedButton.styleFrom(
|
OutlinedButton.styleFrom(
|
||||||
foregroundColor:
|
foregroundColor:
|
||||||
Colors.red,
|
AppPalette.danger,
|
||||||
side: const BorderSide(
|
side: const BorderSide(
|
||||||
color: Colors.red,
|
color:
|
||||||
|
AppPalette.danger,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: const Text('거절'),
|
child: const Text('거절'),
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class _FriendsScreenState extends State<FriendsScreen> {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(dialogContext, true),
|
onPressed: () => Navigator.pop(dialogContext, true),
|
||||||
child: const Text('삭제', style: TextStyle(color: Colors.red)),
|
child: const Text('삭제', style: TextStyle(color: AppPalette.danger)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -196,7 +196,10 @@ class _GroupDetailScreenState extends State<GroupDetailScreen> {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(dialogContext, true),
|
onPressed: () => Navigator.pop(dialogContext, true),
|
||||||
child: const Text('나가기', style: TextStyle(color: Colors.red)),
|
child: const Text(
|
||||||
|
'나가기',
|
||||||
|
style: TextStyle(color: AppPalette.danger),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -344,20 +344,23 @@ class _GroupListScreenState extends State<GroupListScreen> {
|
|||||||
vertical: 1,
|
vertical: 1,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.red[50],
|
color:
|
||||||
|
AppPalette.warningBg,
|
||||||
borderRadius:
|
borderRadius:
|
||||||
BorderRadius.circular(
|
BorderRadius.circular(
|
||||||
20,
|
20,
|
||||||
),
|
),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Colors.red,
|
color:
|
||||||
|
AppPalette.warning,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'대기 ${g['pendingRequestCount']}',
|
'대기 ${g['pendingRequestCount']}',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
color: Colors.red,
|
color:
|
||||||
|
AppPalette.warning,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
children: [
|
children: [
|
||||||
const Text(
|
const Text(
|
||||||
'보안을 위해 새로운 비밀번호를 설정해 주세요.',
|
'보안을 위해 새로운 비밀번호를 설정해 주세요.',
|
||||||
style: TextStyle(color: Colors.redAccent),
|
style: TextStyle(color: AppPalette.danger),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextField(
|
TextField(
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ class _MainDashboardState extends State<MainDashboard> {
|
|||||||
),
|
),
|
||||||
title: const Row(
|
title: const Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.warning_amber_rounded, color: Colors.redAccent),
|
Icon(Icons.warning_amber_rounded, color: AppPalette.danger),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
'계정 강제 삭제',
|
'계정 강제 삭제',
|
||||||
@@ -142,10 +142,13 @@ class _MainDashboardState extends State<MainDashboard> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: '학번 또는 교직원 번호',
|
labelText: '학번 또는 교직원 번호',
|
||||||
hintText: '예: 201101 또는 T1001',
|
hintText: '예: 201101 또는 T1001',
|
||||||
labelStyle: TextStyle(color: Colors.red[400]),
|
labelStyle: const TextStyle(color: AppPalette.danger),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
borderSide: BorderSide(color: Colors.red[400]!, width: 2),
|
borderSide: const BorderSide(
|
||||||
|
color: AppPalette.danger,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
@@ -175,7 +178,7 @@ class _MainDashboardState extends State<MainDashboard> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.redAccent,
|
backgroundColor: AppPalette.danger,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ class _NfcPocketCheckInScreenState extends State<NfcPocketCheckInScreen> {
|
|||||||
void _handleMessage(String text, WatchMessageLevel level) {
|
void _handleMessage(String text, WatchMessageLevel level) {
|
||||||
final Color color = switch (level) {
|
final Color color = switch (level) {
|
||||||
WatchMessageLevel.info => Colors.blueGrey,
|
WatchMessageLevel.info => Colors.blueGrey,
|
||||||
WatchMessageLevel.success => Colors.green,
|
WatchMessageLevel.success => AppPalette.success,
|
||||||
WatchMessageLevel.warning => Colors.orange,
|
WatchMessageLevel.warning => AppPalette.warning,
|
||||||
WatchMessageLevel.error => Colors.red,
|
WatchMessageLevel.error => AppPalette.danger,
|
||||||
};
|
};
|
||||||
_showSnackBar(text, color);
|
_showSnackBar(text, color);
|
||||||
}
|
}
|
||||||
@@ -73,10 +73,13 @@ class _NfcPocketCheckInScreenState extends State<NfcPocketCheckInScreen> {
|
|||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (context) => AlertDialog(
|
||||||
backgroundColor: Colors.red[50],
|
backgroundColor: AppPalette.dangerBg,
|
||||||
title: const Text(
|
title: const Text(
|
||||||
"무단 반출 감지",
|
"무단 반출 감지",
|
||||||
style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),
|
style: TextStyle(
|
||||||
|
color: AppPalette.danger,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
content: Text(
|
content: Text(
|
||||||
"[${pocketNumber ?? _controller.activePocketNumber}] 주머니에서 휴대폰이 꺼내진 것으로 감지되었습니다.\n담당 선생님께 알림이 전송되었습니다.",
|
"[${pocketNumber ?? _controller.activePocketNumber}] 주머니에서 휴대폰이 꺼내진 것으로 감지되었습니다.\n담당 선생님께 알림이 전송되었습니다.",
|
||||||
@@ -177,8 +180,8 @@ class _NfcPocketCheckInScreenState extends State<NfcPocketCheckInScreen> {
|
|||||||
_controller.isProcessing ? Icons.sync : Icons.nfc,
|
_controller.isProcessing ? Icons.sync : Icons.nfc,
|
||||||
size: 100,
|
size: 100,
|
||||||
color: _controller.isProcessing
|
color: _controller.isProcessing
|
||||||
? Colors.orange
|
? AppPalette.warning
|
||||||
: Colors.blueAccent,
|
: AppPalette.ink,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
|
|
||||||
@@ -190,7 +193,7 @@ class _NfcPocketCheckInScreenState extends State<NfcPocketCheckInScreen> {
|
|||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: _controller.isProcessing
|
color: _controller.isProcessing
|
||||||
? Colors.orange
|
? AppPalette.warning
|
||||||
: Colors.black87,
|
: Colors.black87,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -227,13 +230,13 @@ class _NfcPocketCheckInScreenState extends State<NfcPocketCheckInScreen> {
|
|||||||
height: 160,
|
height: 160,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: Colors.greenAccent.withValues(alpha: 0.15),
|
color: AppPalette.success.withValues(alpha: 0.15),
|
||||||
border: Border.all(color: Colors.greenAccent, width: 3),
|
border: Border.all(color: AppPalette.success, width: 3),
|
||||||
),
|
),
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
Icons.shield_rounded,
|
Icons.shield_rounded,
|
||||||
size: 72,
|
size: 72,
|
||||||
color: Colors.greenAccent,
|
color: AppPalette.success,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class _NfcTagWriterScreenState extends State<NfcTagWriterScreen> {
|
|||||||
AppNotice.show(
|
AppNotice.show(
|
||||||
context,
|
context,
|
||||||
text,
|
text,
|
||||||
color: isError ? Colors.red[700] : Colors.green[700],
|
color: isError ? AppPalette.danger : AppPalette.success,
|
||||||
icon: isError ? Icons.error_outline_rounded : Icons.check_circle_rounded,
|
icon: isError ? Icons.error_outline_rounded : Icons.check_circle_rounded,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ class _NfcTagWriterScreenState extends State<NfcTagWriterScreen> {
|
|||||||
Icon(
|
Icon(
|
||||||
isWriting ? Icons.nfc : Icons.edit_note_rounded,
|
isWriting ? Icons.nfc : Icons.edit_note_rounded,
|
||||||
size: 80,
|
size: 80,
|
||||||
color: isWriting ? Colors.orange : AppPalette.ink,
|
color: isWriting ? AppPalette.warning : AppPalette.ink,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ class _StudyCalendarScreenState extends State<StudyCalendarScreen> {
|
|||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'삭제',
|
'삭제',
|
||||||
style: TextStyle(color: Colors.red),
|
style: TextStyle(color: AppPalette.danger),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -347,7 +347,7 @@ class _StudyCalendarScreenState extends State<StudyCalendarScreen> {
|
|||||||
size: 12,
|
size: 12,
|
||||||
color: studied
|
color: studied
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.orange,
|
: AppPalette.warning,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -363,7 +363,7 @@ class _StudyCalendarScreenState extends State<StudyCalendarScreen> {
|
|||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
_legendIcon(
|
_legendIcon(
|
||||||
Icons.card_giftcard_rounded,
|
Icons.card_giftcard_rounded,
|
||||||
Colors.orange,
|
AppPalette.warning,
|
||||||
'이벤트',
|
'이벤트',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -196,7 +196,10 @@ class _StudyTimerScreenState extends State<StudyTimerScreen>
|
|||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
const Text(
|
const Text(
|
||||||
'타이머가 멈춰있을 때만 설정을 바꿀 수 있어요.',
|
'타이머가 멈춰있을 때만 설정을 바꿀 수 있어요.',
|
||||||
style: TextStyle(color: Colors.redAccent, fontSize: 12.5),
|
style: TextStyle(
|
||||||
|
color: AppPalette.danger,
|
||||||
|
fontSize: 12.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
const SizedBox(height: 18),
|
const SizedBox(height: 18),
|
||||||
@@ -442,7 +445,7 @@ class _StudyTimerScreenState extends State<StudyTimerScreen>
|
|||||||
size: 140,
|
size: 140,
|
||||||
icon: Icons.stop_rounded,
|
icon: Icons.stop_rounded,
|
||||||
label: '공부 종료',
|
label: '공부 종료',
|
||||||
color: Colors.red[400]!,
|
color: AppPalette.danger,
|
||||||
onTap: () => _runAction(_controller.stop),
|
onTap: () => _runAction(_controller.stop),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -453,7 +456,7 @@ class _StudyTimerScreenState extends State<StudyTimerScreen>
|
|||||||
size: 110,
|
size: 110,
|
||||||
icon: isPaused ? Icons.play_arrow_rounded : Icons.pause_rounded,
|
icon: isPaused ? Icons.play_arrow_rounded : Icons.pause_rounded,
|
||||||
label: isPaused ? '재개' : '일시정지',
|
label: isPaused ? '재개' : '일시정지',
|
||||||
color: isPaused ? AppPalette.ink : Colors.amber[700]!,
|
color: isPaused ? AppPalette.ink : AppPalette.warning,
|
||||||
onTap: () =>
|
onTap: () =>
|
||||||
_runAction(isPaused ? _controller.resume : _controller.pause),
|
_runAction(isPaused ? _controller.resume : _controller.pause),
|
||||||
),
|
),
|
||||||
@@ -462,7 +465,7 @@ class _StudyTimerScreenState extends State<StudyTimerScreen>
|
|||||||
size: 110,
|
size: 110,
|
||||||
icon: Icons.stop_rounded,
|
icon: Icons.stop_rounded,
|
||||||
label: '공부 종료',
|
label: '공부 종료',
|
||||||
color: Colors.red[400]!,
|
color: AppPalette.danger,
|
||||||
onTap: () => _runAction(_controller.stop),
|
onTap: () => _runAction(_controller.stop),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -360,8 +360,10 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
|||||||
final bool isPending = student['attendanceStatus'] == 'PENDING';
|
final bool isPending = student['attendanceStatus'] == 'PENDING';
|
||||||
final bool isComplete = student['attendanceStatus'] == 'COMPLETE';
|
final bool isComplete = student['attendanceStatus'] == 'COMPLETE';
|
||||||
final Color statusColor = hasViolation
|
final Color statusColor = hasViolation
|
||||||
? Colors.red
|
? AppPalette.danger
|
||||||
: (isPending ? Colors.orange : (isComplete ? Colors.blue : Colors.red));
|
: (isPending
|
||||||
|
? AppPalette.warning
|
||||||
|
: (isComplete ? AppPalette.approved : AppPalette.danger));
|
||||||
final String statusLine = hasViolation
|
final String statusLine = hasViolation
|
||||||
? '무단반출 (${student['violationTime']})'
|
? '무단반출 (${student['violationTime']})'
|
||||||
: (isPending
|
: (isPending
|
||||||
@@ -373,10 +375,10 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(14),
|
padding: const EdgeInsets.all(14),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: hasViolation ? Colors.red[50] : AppPalette.paper,
|
color: hasViolation ? AppPalette.dangerBg : AppPalette.paper,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: hasViolation ? Colors.red[300]! : AppPalette.sage,
|
color: hasViolation ? AppPalette.danger : AppPalette.sage,
|
||||||
width: hasViolation ? 1.5 : 1,
|
width: hasViolation ? 1.5 : 1,
|
||||||
),
|
),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
@@ -451,10 +453,10 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: hasViolation
|
color: hasViolation
|
||||||
? Colors.red[700]
|
? AppPalette.danger
|
||||||
: (isPending
|
: (isPending
|
||||||
? Colors.orange[800]
|
? AppPalette.warning
|
||||||
: (isComplete ? Colors.grey[600] : Colors.red[400])),
|
: (isComplete ? Colors.grey[600] : AppPalette.danger)),
|
||||||
fontSize: 11.5,
|
fontSize: 11.5,
|
||||||
fontWeight: hasViolation ? FontWeight.bold : FontWeight.normal,
|
fontWeight: hasViolation ? FontWeight.bold : FontWeight.normal,
|
||||||
),
|
),
|
||||||
@@ -470,7 +472,7 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
|||||||
student['studentName'],
|
student['studentName'],
|
||||||
),
|
),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.red[600],
|
backgroundColor: AppPalette.danger,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
@@ -781,18 +783,18 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
|||||||
final bool isPending = student['attendanceStatus'] == 'PENDING';
|
final bool isPending = student['attendanceStatus'] == 'PENDING';
|
||||||
final bool isComplete = student['attendanceStatus'] == 'COMPLETE';
|
final bool isComplete = student['attendanceStatus'] == 'COMPLETE';
|
||||||
final Color background = hasViolation
|
final Color background = hasViolation
|
||||||
? Colors.red[50]!
|
? AppPalette.dangerBg
|
||||||
: isComplete
|
: isComplete
|
||||||
? Colors.blue[50]!
|
? AppPalette.approvedBg
|
||||||
: isPending
|
: isPending
|
||||||
? Colors.orange[50]!
|
? AppPalette.warningBg
|
||||||
: AppPalette.paper;
|
: AppPalette.paper;
|
||||||
final Color border = hasViolation
|
final Color border = hasViolation
|
||||||
? Colors.red[300]!
|
? AppPalette.danger
|
||||||
: isComplete
|
: isComplete
|
||||||
? Colors.blue[200]!
|
? AppPalette.approved
|
||||||
: isPending
|
: isPending
|
||||||
? Colors.orange[200]!
|
? AppPalette.warning
|
||||||
: AppPalette.sage;
|
: AppPalette.sage;
|
||||||
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
@@ -828,7 +830,7 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
|||||||
'무단반출',
|
'무단반출',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 7.5,
|
fontSize: 7.5,
|
||||||
color: Colors.red[700],
|
color: AppPalette.danger,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -849,19 +851,19 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
|||||||
margin: const EdgeInsets.fromLTRB(16, 8, 16, 0),
|
margin: const EdgeInsets.fromLTRB(16, 8, 16, 0),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.amber[100],
|
color: AppPalette.warningBg,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(color: Colors.amber[400]!),
|
border: Border.all(color: AppPalette.warning),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.lock_open_rounded, color: Colors.amber[800], size: 20),
|
Icon(Icons.lock_open_rounded, color: AppPalette.warning, size: 20),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'지금 전체 반출 허용 중입니다 ($until 까지) — 이 시간 동안은 무단반출 경고가 뜨지 않아요.',
|
'지금 전체 반출 허용 중입니다 ($until 까지) — 이 시간 동안은 무단반출 경고가 뜨지 않아요.',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.amber[900],
|
color: AppPalette.warning,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12.5,
|
fontSize: 12.5,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ class _TeacherCallScreenState extends State<TeacherCallScreen> {
|
|||||||
final location = t['location'] ?? '교무실';
|
final location = t['location'] ?? '교무실';
|
||||||
final isSelected = _selectedTeacherId == t['teacherId'];
|
final isSelected = _selectedTeacherId == t['teacherId'];
|
||||||
final inClass = _controller.isInClassNow(name);
|
final inClass = _controller.isInClassNow(name);
|
||||||
final statusColor = inClass ? Colors.orange : AppPalette.ink;
|
final statusColor = inClass ? AppPalette.warning : AppPalette.ink;
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => setState(() {
|
onTap: () => setState(() {
|
||||||
@@ -428,17 +428,21 @@ class _TeacherCallScreenState extends State<TeacherCallScreen> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? Colors.white.withValues(alpha: 0.15)
|
? Colors.white.withValues(alpha: 0.15)
|
||||||
: Colors.orange[50],
|
: AppPalette.warningBg,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: isSelected ? Colors.white54 : Colors.orange,
|
color: isSelected
|
||||||
|
? Colors.white54
|
||||||
|
: AppPalette.warning,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'수업중',
|
'수업중',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
color: isSelected ? Colors.white : Colors.orange,
|
color: isSelected
|
||||||
|
? Colors.white
|
||||||
|
: AppPalette.warning,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -223,7 +223,10 @@ class _TeacherStudentManagementPageState
|
|||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Text(
|
child: Text(
|
||||||
result.failures.join('\n'),
|
result.failures.join('\n'),
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.red),
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: AppPalette.danger,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -321,7 +324,7 @@ class _TeacherStudentManagementPageState
|
|||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
|
||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.warning_amber_rounded, color: Colors.red[700]),
|
Icon(Icons.warning_amber_rounded, color: AppPalette.danger),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
const Text(
|
const Text(
|
||||||
'계정 완전 삭제',
|
'계정 완전 삭제',
|
||||||
@@ -339,7 +342,7 @@ class _TeacherStudentManagementPageState
|
|||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.red[600],
|
backgroundColor: AppPalette.danger,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
@@ -519,10 +522,10 @@ class _TeacherStudentManagementPageState
|
|||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _isDragging ? Colors.orange[50] : AppPalette.paper,
|
color: _isDragging ? AppPalette.warningBg : AppPalette.paper,
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: _isDragging ? Colors.orange : AppPalette.sage,
|
color: _isDragging ? AppPalette.warning : AppPalette.sage,
|
||||||
width: _isDragging ? 2 : 1,
|
width: _isDragging ? 2 : 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -532,7 +535,7 @@ class _TeacherStudentManagementPageState
|
|||||||
Icon(
|
Icon(
|
||||||
Icons.upload_file_rounded,
|
Icons.upload_file_rounded,
|
||||||
size: 40,
|
size: 40,
|
||||||
color: _isDragging ? Colors.orange : AppPalette.sage,
|
color: _isDragging ? AppPalette.warning : AppPalette.sage,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Text(
|
Text(
|
||||||
@@ -540,7 +543,7 @@ class _TeacherStudentManagementPageState
|
|||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: _isDragging ? Colors.orange[800] : AppPalette.ink,
|
color: _isDragging ? AppPalette.warning : AppPalette.ink,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
@@ -584,15 +587,13 @@ class _TeacherStudentManagementPageState
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: needsReset
|
color: needsReset ? AppPalette.dangerBg : AppPalette.linen,
|
||||||
? Colors.red.withValues(alpha: 0.1)
|
|
||||||
: AppPalette.linen,
|
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
needsReset ? Icons.lock_reset : Icons.person,
|
needsReset ? Icons.lock_reset : Icons.person,
|
||||||
size: 18,
|
size: 18,
|
||||||
color: needsReset ? Colors.red : AppPalette.ink,
|
color: needsReset ? AppPalette.danger : AppPalette.ink,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
@@ -609,7 +610,7 @@ class _TeacherStudentManagementPageState
|
|||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11.5,
|
fontSize: 11.5,
|
||||||
color: needsReset ? Colors.red[700] : Colors.grey[600],
|
color: needsReset ? AppPalette.danger : Colors.grey[600],
|
||||||
fontWeight: needsReset ? FontWeight.bold : FontWeight.normal,
|
fontWeight: needsReset ? FontWeight.bold : FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -650,7 +651,7 @@ class _TeacherStudentManagementPageState
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.delete_forever_rounded,
|
Icons.delete_forever_rounded,
|
||||||
color: Colors.redAccent,
|
color: AppPalette.danger,
|
||||||
size: 18,
|
size: 18,
|
||||||
),
|
),
|
||||||
tooltip: '계정 영구 삭제',
|
tooltip: '계정 영구 삭제',
|
||||||
|
|||||||
Reference in New Issue
Block a user