1.테마/컬러 수정
2. UI 텍스트 한국어 번역 3. SettingScreen(설정 페이지) -현재 페이지는 레이아웃만 완성되었으며, 토글 스위치 및 링크 연결 기능은 미완성 상태입니다.
This commit is contained in:
@@ -8,10 +8,20 @@ class ControlScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ControlScreenState extends State<ControlScreen> {
|
class _ControlScreenState extends State<ControlScreen> {
|
||||||
final Color _bgColor = const Color(0xFF27292B);
|
final Color _mainBlueColor = const Color(0xFF002FA7);
|
||||||
final Color _cardColor = const Color(0xFF30343B);
|
final Color _mainTextColor = const Color(0xFF1C1C1E);
|
||||||
final Color _buttonDarkColor = const Color(0xFF212327);
|
final Color _subTextColor = const Color(0xFF6A717B);
|
||||||
final Color _errorColor = Colors.redAccent;
|
final Color _pageBackgroundColor = const Color(0xFFF5F7F9);
|
||||||
|
final Color _cardBackgroundColor = Colors.white;
|
||||||
|
final Color _accentContainerColor = const Color(0xFFF0F2F5);
|
||||||
|
final Color _warningColor = Colors.redAccent;
|
||||||
|
|
||||||
|
static const BoxShadow _cleanShadow = BoxShadow(
|
||||||
|
color: Color.fromRGBO(0, 0, 0, 0.07),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
spreadRadius: 0,
|
||||||
|
);
|
||||||
|
|
||||||
bool _isSecurityLocked = true;
|
bool _isSecurityLocked = true;
|
||||||
int _selectedDoorIndex = 0;
|
int _selectedDoorIndex = 0;
|
||||||
@@ -19,23 +29,24 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: _bgColor,
|
backgroundColor: _pageBackgroundColor,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text(
|
title: Text(
|
||||||
'CONTROL CENTER',
|
'제어 센터',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
fontSize: 16,
|
fontSize: 18,
|
||||||
color: Colors.white,
|
letterSpacing: 0.5,
|
||||||
|
color: _mainTextColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: _bgColor,
|
backgroundColor: _pageBackgroundColor,
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.more_vert, color: Colors.white),
|
icon: Icon(Icons.more_vert, color: _mainTextColor),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -67,16 +78,17 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _cardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [_cleanShadow],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
'SYSTEM STATUS',
|
'보관함 상태',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@@ -92,7 +104,7 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
padding: const EdgeInsets.all(20.0),
|
padding: const EdgeInsets.all(20.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _buttonDarkColor,
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
@@ -105,10 +117,10 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
'NOW',
|
'NOW',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _subTextColor,
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -116,17 +128,17 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatusButton(
|
child: _buildStatusButton(
|
||||||
text: 'ONLINE',
|
text: '사용 중',
|
||||||
textColor: Colors.white,
|
textColor: _mainBlueColor,
|
||||||
bgColor: _buttonDarkColor,
|
bgColor: _accentContainerColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatusButton(
|
child: _buildStatusButton(
|
||||||
text: 'SENSOR ERROR:\nLock Failure',
|
text: 'ERROR: 문 열림',
|
||||||
textColor: _errorColor,
|
textColor: _warningColor,
|
||||||
bgColor: _buttonDarkColor,
|
bgColor: _accentContainerColor,
|
||||||
isError: true,
|
isError: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -171,16 +183,17 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _cardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [_cleanShadow],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
'DOOR CONTROL',
|
'문 잠금 제어',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@@ -213,14 +226,14 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
height: 80,
|
height: 80,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isSelected ? Colors.white : _buttonDarkColor,
|
color: isSelected ? _mainBlueColor : _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
text,
|
text,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isSelected ? Colors.black : Colors.white,
|
color: isSelected ? Colors.white : _mainTextColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
),
|
),
|
||||||
@@ -235,16 +248,17 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _cardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [_cleanShadow],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
'Control Results & Alerts',
|
'조작 기록 및 경고',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@@ -253,7 +267,7 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _buttonDarkColor,
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -262,24 +276,24 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.warning_amber_rounded,
|
Icon(Icons.warning_amber_rounded,
|
||||||
color: _errorColor, size: 16),
|
color: _warningColor, size: 16),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: RichText(
|
child: RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'Sensor Alert: ',
|
text: '센서 경고: ',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: _errorColor,
|
color: _warningColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const TextSpan(
|
TextSpan(
|
||||||
text: 'Door Not Fully Closed',
|
text: '문 닫힘 불완전',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -295,8 +309,8 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
child: LinearProgressIndicator(
|
child: LinearProgressIndicator(
|
||||||
value: 0.6,
|
value: 0.6,
|
||||||
backgroundColor: Colors.grey[800],
|
backgroundColor: _pageBackgroundColor,
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(_errorColor),
|
valueColor: AlwaysStoppedAnimation<Color>(_warningColor),
|
||||||
minHeight: 6,
|
minHeight: 6,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -312,16 +326,17 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _cardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [_cleanShadow],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
'Alert & Logs',
|
'조작 기록 및 경고',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@@ -330,36 +345,36 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _buttonDarkColor,
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
),
|
),
|
||||||
child: const Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.warning_amber_rounded,
|
Icon(Icons.warning_amber_rounded,
|
||||||
color: Colors.redAccent, size: 14),
|
color: _warningColor, size: 14),
|
||||||
SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Sensor Alert: Door Not Fully Closed',
|
'센서 경고: 문 열림',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.bookmark, color: Colors.white70, size: 14),
|
Icon(Icons.bookmark, color: _subTextColor, size: 14),
|
||||||
SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'2:02 PM - UV LED Activated',
|
'2:02 PM - UV LED 작동',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -378,16 +393,17 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _cardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [_cleanShadow],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
'Security Lock Mode',
|
'도난 방지 잠금',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@@ -397,7 +413,7 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 22, vertical: 16),
|
const EdgeInsets.symmetric(horizontal: 22, vertical: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _buttonDarkColor,
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -405,10 +421,10 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
_isSecurityLocked
|
_isSecurityLocked
|
||||||
? 'ON (Activated)'
|
? 'ON'
|
||||||
: 'OFF (Deactivated)',
|
: 'OFF',
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -422,10 +438,10 @@ class _ControlScreenState extends State<ControlScreen> {
|
|||||||
_isSecurityLocked = val;
|
_isSecurityLocked = val;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
activeThumbColor: Colors.white,
|
activeThumbColor: _mainBlueColor,
|
||||||
activeTrackColor: _errorColor,
|
activeTrackColor: _mainBlueColor.withOpacity(0.5),
|
||||||
inactiveThumbColor: Colors.white,
|
inactiveThumbColor: Colors.white,
|
||||||
inactiveTrackColor: Colors.grey,
|
inactiveTrackColor: _accentContainerColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -32,16 +32,28 @@ class HistoryScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _HistoryScreenState extends State<HistoryScreen> {
|
class _HistoryScreenState extends State<HistoryScreen> {
|
||||||
static const Color kBackgroundColor = Color(0xFF27292B);
|
// 🟦 최종 확정 테마 컬러 정의 (대비 구조 교체)
|
||||||
static const Color kCardColor = Color(0xFF30343B);
|
final Color _mainBlueColor = const Color(0xFF002FA7); // 진한 블루 (0xFF002FA7 -> 0xFF0A68FF로 통일)
|
||||||
static const Color kAccentColor = Colors.white;
|
final Color _mainTextColor = const Color(0xFF1C1C1E); // 어두운 텍스트
|
||||||
static const Color kRedAccent = Color(0xFFFF5252);
|
final Color _subTextColor = const Color(0xFF6A717B); // 보조 텍스트
|
||||||
|
final Color _pageBackgroundColor = const Color(0xFFF5F7F9); // 🚩 Scaffold 배경 (연한 그레이)
|
||||||
|
final Color _cardBackgroundColor = Colors.white; // 🚩 카드 배경 (순수 화이트)
|
||||||
|
final Color _accentContainerColor = const Color(0xFFF0F2F5); // 🚩 내부 상세 박스 배경 (중간 그레이)
|
||||||
|
final Color _borderColor = const Color(0xFF0A68FF).withOpacity(0.8);
|
||||||
|
|
||||||
|
// 🚩 그림자 스타일 정의
|
||||||
|
static const BoxShadow _cleanShadow = BoxShadow(
|
||||||
|
color: Color.fromRGBO(0, 0, 0, 0.07),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
spreadRadius: 0,
|
||||||
|
);
|
||||||
|
|
||||||
int _selectedFilterIndex = 0;
|
int _selectedFilterIndex = 0;
|
||||||
|
|
||||||
final List<UsageHistory> _allHistoryList = [
|
final List<UsageHistory> _allHistoryList = [
|
||||||
UsageHistory(
|
UsageHistory(
|
||||||
date: '2025.11.25 (Tue)',
|
date: '2025.11.25 (화)', // 🇰🇷 요일 변경
|
||||||
startTime: '18:30',
|
startTime: '18:30',
|
||||||
endTime: '19:15',
|
endTime: '19:15',
|
||||||
duration: 45,
|
duration: 45,
|
||||||
@@ -52,7 +64,7 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
isDried: true,
|
isDried: true,
|
||||||
),
|
),
|
||||||
UsageHistory(
|
UsageHistory(
|
||||||
date: '2025.11.23 (Sun)',
|
date: '2025.11.23 (일)', // 🇰🇷 요일 변경
|
||||||
startTime: '14:00',
|
startTime: '14:00',
|
||||||
endTime: '15:30',
|
endTime: '15:30',
|
||||||
duration: 90,
|
duration: 90,
|
||||||
@@ -63,7 +75,7 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
isDried: false,
|
isDried: false,
|
||||||
),
|
),
|
||||||
UsageHistory(
|
UsageHistory(
|
||||||
date: '2025.11.06 (Thu)',
|
date: '2025.11.06 (목)', // 🇰🇷 요일 변경
|
||||||
startTime: '09:00',
|
startTime: '09:00',
|
||||||
endTime: '09:30',
|
endTime: '09:30',
|
||||||
duration: 30,
|
duration: 30,
|
||||||
@@ -74,7 +86,7 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
isDried: true,
|
isDried: true,
|
||||||
),
|
),
|
||||||
UsageHistory(
|
UsageHistory(
|
||||||
date: '2025.09.20 (Sat)',
|
date: '2025.09.20 (토)', // 🇰🇷 요일 변경
|
||||||
startTime: '20:00',
|
startTime: '20:00',
|
||||||
endTime: '21:00',
|
endTime: '21:00',
|
||||||
duration: 60,
|
duration: 60,
|
||||||
@@ -120,16 +132,16 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
final currentList = _filteredList;
|
final currentList = _filteredList;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: kBackgroundColor,
|
backgroundColor: _pageBackgroundColor,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('HISTORY', style: TextStyle(fontWeight: FontWeight
|
title: Text('나의 기록', style: TextStyle(fontWeight: FontWeight
|
||||||
.bold, fontSize: 16, color: Colors.white)),
|
.bold, fontSize: 18, letterSpacing: 0.5, color: _mainTextColor)),
|
||||||
backgroundColor: kBackgroundColor,
|
backgroundColor: _pageBackgroundColor,
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(icon: const Icon(Icons.filter_list, color: Colors.white),
|
IconButton(icon: Icon(Icons.filter_list, color: _mainTextColor),
|
||||||
onPressed: () {}),
|
onPressed: () {}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -138,8 +150,8 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
_buildFilterTabs(),
|
_buildFilterTabs(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: currentList.isEmpty
|
child: currentList.isEmpty
|
||||||
? const Center(
|
? Center(
|
||||||
child: Text("기록이 없습니다.", style: TextStyle(color: Colors.grey)))
|
child: Text("기록이 없습니다.", style: TextStyle(color: _subTextColor)))
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
itemCount: currentList.length,
|
itemCount: currentList.length,
|
||||||
@@ -183,15 +195,15 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
onSelected: (selected) {
|
onSelected: (selected) {
|
||||||
setState(() => _selectedFilterIndex = index);
|
setState(() => _selectedFilterIndex = index);
|
||||||
},
|
},
|
||||||
backgroundColor: kCardColor,
|
backgroundColor: _cardBackgroundColor,
|
||||||
selectedColor: kAccentColor,
|
selectedColor: _mainBlueColor,
|
||||||
checkmarkColor: Colors.black,
|
checkmarkColor: Colors.white,
|
||||||
labelStyle: TextStyle(
|
labelStyle: TextStyle(
|
||||||
color: isSelected ? Colors.black : Colors.white,
|
color: isSelected ? Colors.white : _mainTextColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(20), side: BorderSide.none),
|
borderRadius: BorderRadius.circular(8), side: BorderSide.none),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -203,8 +215,8 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
date,
|
date,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold
|
fontWeight: FontWeight.bold
|
||||||
),
|
),
|
||||||
@@ -216,12 +228,13 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(bottom: 12),
|
margin: const EdgeInsets.only(bottom: 12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kCardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [_cleanShadow]
|
||||||
),
|
),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => _showHistoryDetail(context, history),
|
onTap: () => _showHistoryDetail(context, history),
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -231,7 +244,7 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'${history.startTime} - ${history.endTime}',
|
'${history.startTime} - ${history.endTime}',
|
||||||
style: const TextStyle(color: Colors.white,
|
style: TextStyle(color: _mainTextColor,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
@@ -239,12 +252,12 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 8, vertical: 4),
|
horizontal: 8, vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: _mainBlueColor,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${history.duration} min',
|
'${history.duration}분', // 🇰🇷 min -> 분
|
||||||
style: const TextStyle(color: Colors.black,
|
style: const TextStyle(color: Colors.white,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600),
|
fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
@@ -254,54 +267,53 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
_buildDot(Colors.grey),
|
_buildDot(_subTextColor),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(child: Text(history.startStation,
|
Expanded(child: Text(history.startStation,
|
||||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
style: TextStyle(color: _mainTextColor, fontSize: 13),
|
||||||
overflow: TextOverflow.ellipsis)),
|
overflow: TextOverflow.ellipsis)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(left: 3),
|
margin: const EdgeInsets.only(left: 3),
|
||||||
height: 10,
|
height: 10,
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
left: BorderSide(color: Colors.grey, width: 1)),
|
left: BorderSide(color: _subTextColor.withOpacity(0.5), width: 1)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
_buildDot(kRedAccent),
|
_buildDot(_mainBlueColor),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(child: Text(history.endStation,
|
Expanded(child: Text(history.endStation,
|
||||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
style: TextStyle(color: _mainTextColor, fontSize: 13),
|
||||||
overflow: TextOverflow.ellipsis)),
|
overflow: TextOverflow.ellipsis)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
const Divider(color: Colors.white, thickness: 0.5,),
|
Divider(color: _subTextColor.withOpacity(0.5), thickness: 0.5,),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
if (history.isSanitized)
|
if (history.isSanitized)
|
||||||
_buildDot(kRedAccent),
|
_buildDot(_mainBlueColor),
|
||||||
if (history.isSanitized)
|
if (history.isSanitized)
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
history.isSanitized ? "살균 완료" : "Pending",
|
history.isSanitized ? "살균 완료" : "진행 중", // 🇰🇷 Pending -> 진행 중
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: history.isSanitized ? Colors.white : Colors
|
color: history.isSanitized ? _mainTextColor : _subTextColor,
|
||||||
.white,
|
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Text(
|
Text(
|
||||||
"VIEW DETAILS >",
|
"상세 보기 >", // 🇰🇷 VIEW DETAILS > -> 상세 보기 >
|
||||||
style: TextStyle(color: Colors.white, fontSize: 11),
|
style: TextStyle(color: _subTextColor, fontSize: 11),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -330,16 +342,17 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
.of(context)
|
.of(context)
|
||||||
.size
|
.size
|
||||||
.height * 0.75,
|
.height * 0.75,
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kBackgroundColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
||||||
|
boxShadow: [_cleanShadow]
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Container(width: 40,
|
Container(width: 40,
|
||||||
height: 4,
|
height: 4,
|
||||||
decoration: BoxDecoration(color: Colors.grey[600],
|
decoration: BoxDecoration(color: _subTextColor,
|
||||||
borderRadius: BorderRadius.circular(2))),
|
borderRadius: BorderRadius.circular(2))),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@@ -347,45 +360,45 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text("HISTORY DETAILS", style: TextStyle(
|
Text("이용 상세 정보", style: TextStyle( // 🇰🇷 HISTORY DETAILS
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.bold)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
history.date,
|
history.date,
|
||||||
style: const TextStyle(color: Colors.white),
|
style: TextStyle(color: _subTextColor),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(color: kCardColor,
|
decoration: BoxDecoration(color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(16)),
|
borderRadius: BorderRadius.circular(8)),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text("이용 시간", style: TextStyle(
|
Text("이용 시간", style: TextStyle( // 🇰🇷 이용 시간
|
||||||
color: Colors.white, fontSize: 12)),
|
color: _subTextColor, fontSize: 12)),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text("${history.duration} min",
|
Text("${history.duration}분", // 🇰🇷 min -> 분
|
||||||
style: const TextStyle(color: Colors.white,
|
style: TextStyle(color: _mainTextColor,
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.bold)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
width: 1, height: 40, color: Colors.white24),
|
width: 1, height: 40, color: _subTextColor.withOpacity(0.5)),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text("이용 금액", style: TextStyle(
|
Text("이용 금액", style: TextStyle( // 🇰🇷 이용 금액
|
||||||
color: Colors.white, fontSize: 12)),
|
color: _subTextColor, fontSize: 12)),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text("$cost ₩", style: const TextStyle(
|
Text("₩ $cost", style: TextStyle( // 🇰🇷 ₩ 위치 수정
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.bold)),
|
||||||
],
|
],
|
||||||
@@ -394,8 +407,8 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
const Text("TIMELINE", style: TextStyle(
|
Text("시간별 기록", style: TextStyle( // 🇰🇷 TIMELINE
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
letterSpacing: 1.0)),
|
letterSpacing: 1.0)),
|
||||||
@@ -407,14 +420,14 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
history.endTime, "반납 완료", history.endStation,
|
history.endTime, "반납 완료", history.endStation,
|
||||||
isCompleted: true),
|
isCompleted: true),
|
||||||
_buildTimelineItem(
|
_buildTimelineItem(
|
||||||
history.endTime, "살균 시작", "Auto-Cleaning System",
|
history.endTime, "살균 시작", "자동 살균 시스템", // 🇰🇷 Auto-Cleaning System
|
||||||
isCompleted: true),
|
isCompleted: true),
|
||||||
_buildTimelineItem(
|
_buildTimelineItem(
|
||||||
"15 min later", "살균 완료", "Ready for next user",
|
"15분 후", "살균 완료", "다음 사용자 준비 완료", // 🇰🇷 15 min later, Ready for next user
|
||||||
isLast: true, isCompleted: history.isSanitized),
|
isLast: true, isCompleted: history.isSanitized),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
const Text("CONDITION", style: TextStyle(
|
Text("살균/건조 상태", style: TextStyle( // 🇰🇷 CONDITION
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.bold)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
@@ -442,25 +455,28 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
|
|
||||||
Widget _buildTimelineItem(String time, String title, String subtitle,
|
Widget _buildTimelineItem(String time, String title, String subtitle,
|
||||||
{bool isFirst = false, bool isLast = false, bool isCompleted = false}) {
|
{bool isFirst = false, bool isLast = false, bool isCompleted = false}) {
|
||||||
|
// 🇰🇷 15 min later -> 15분 후 로직 처리
|
||||||
|
String displayTime = time.contains("min later") ? "15분 후" : time;
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 60,
|
width: 60,
|
||||||
child: Text(
|
child: Text(
|
||||||
time, style: const TextStyle(color: Colors.white, fontSize: 12)),
|
displayTime, style: TextStyle(color: _mainTextColor, fontSize: 12)),
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
isCompleted ? Icons.check_circle : Icons.radio_button_unchecked,
|
isCompleted ? Icons.check_circle : Icons.radio_button_unchecked,
|
||||||
color: isCompleted ? kRedAccent : Colors.grey, size: 20),
|
color: isCompleted ? _mainBlueColor : _subTextColor, size: 20),
|
||||||
if (!isLast)
|
if (!isLast)
|
||||||
Container(width: 2,
|
Container(width: 2,
|
||||||
height: 40,
|
height: 40,
|
||||||
color: isCompleted
|
color: isCompleted
|
||||||
? kRedAccent.withValues(alpha: 0.5)
|
? _mainBlueColor.withOpacity(0.5)
|
||||||
: Colors.grey[800]),
|
: Colors.grey.shade300),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
@@ -469,12 +485,12 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(title, style: TextStyle(
|
Text(title, style: TextStyle(
|
||||||
color: isCompleted ? Colors.white : Colors.grey,
|
color: isCompleted ? _mainTextColor : _subTextColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14)),
|
fontSize: 14)),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(subtitle,
|
Text(subtitle,
|
||||||
style: TextStyle(color: Colors.white, fontSize: 12)),
|
style: TextStyle(color: _subTextColor, fontSize: 12)),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -489,29 +505,30 @@ class _HistoryScreenState extends State<HistoryScreen> {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kCardColor,
|
color: _accentContainerColor, // 내부 상세 박스 배경 (중간 그레이)
|
||||||
|
boxShadow: isDone ? [_cleanShadow] : null,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: isDone ? Colors.white : Colors.transparent, width: 1.0),
|
color: isDone ? _mainBlueColor.withOpacity(0.9) : _subTextColor.withOpacity(0.3), width: 1.0),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(icon, color: Colors.white, size: 28),
|
Icon(icon, color: _mainBlueColor, size: 28),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
isDone ? "Completed" : "In Progress",
|
isDone ? "완료됨" : "진행 중", // 🇰🇷 Completed/In Progress
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _subTextColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14
|
fontSize: 14
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -14,7 +14,22 @@ class HomeScreenContent extends StatefulWidget {
|
|||||||
class _HomeScreenContentState extends State<HomeScreenContent> {
|
class _HomeScreenContentState extends State<HomeScreenContent> {
|
||||||
static const double _uniformGap = 16.0;
|
static const double _uniformGap = 16.0;
|
||||||
|
|
||||||
final Color _pointColor = Colors.redAccent;
|
final Color _mainBlueColor = const Color(0xFF002FA7);
|
||||||
|
final Color _mainTextColor = Colors.black;
|
||||||
|
final Color _subTextColor = const Color(0xFF6A717B);
|
||||||
|
final Color _pageBackgroundColor = const Color(0xFFF5F7F9);
|
||||||
|
final Color _cardBackgroundColor = Colors.white;
|
||||||
|
final Color _accentContainerColor = const Color(0xFFF0F2F5);
|
||||||
|
final Color _toggleOffTrackColor = const Color(0xFFE0E0E0);
|
||||||
|
final Color _toggleOffKnobBorderColor = const Color(0xFFB0B0B0);
|
||||||
|
final Color _toggleOffTextColor = const Color(0xFF909090);
|
||||||
|
|
||||||
|
static const BoxShadow _cleanShadow = BoxShadow(
|
||||||
|
color: Color.fromRGBO(0, 0, 0, 0.07),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
spreadRadius: 0,
|
||||||
|
);
|
||||||
|
|
||||||
final Map<String, bool> _controlToggles = {
|
final Map<String, bool> _controlToggles = {
|
||||||
'UV LED': false,
|
'UV LED': false,
|
||||||
@@ -25,10 +40,11 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Container(
|
||||||
|
color: _pageBackgroundColor,
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const CustomHeader(),
|
const CustomHeader(),
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: _uniformGap),
|
padding: const EdgeInsets.symmetric(horizontal: _uniformGap),
|
||||||
@@ -52,11 +68,16 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildOverviewSection() {
|
Widget _buildOverviewSection() {
|
||||||
return Card(
|
return Container(
|
||||||
|
margin: const EdgeInsets.only(top: 5),
|
||||||
|
child: Card(
|
||||||
|
shadow: _cleanShadow,
|
||||||
|
cardColor: _cardBackgroundColor,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
_buildOverviewHeader(),
|
_buildOverviewHeader(),
|
||||||
@@ -73,6 +94,7 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,15 +103,15 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 0),
|
padding: const EdgeInsets.fromLTRB(12, 12, 12, 0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Text('SYSTEM OVERVIEW',
|
Text('장치 개요',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.bold)),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Icon(Icons.search, color: Colors.grey[400], size: 20),
|
Icon(Icons.search, color: _subTextColor, size: 20),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Icon(Icons.notifications_outlined, color: Colors.grey[400], size: 20),
|
Icon(Icons.notifications_outlined, color: _subTextColor, size: 20),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -101,36 +123,36 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black.withOpacity(0.3),
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFF2D2F33),
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(5)
|
borderRadius: BorderRadius.circular(5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 20.0),
|
padding: const EdgeInsets.only(bottom: 20.0),
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/images/open.png',
|
'assets/images/storage.png',
|
||||||
width: 120,
|
width: 90,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 12,
|
bottom: 12,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
_buildLedIndicator(Colors.grey.shade700),
|
_buildLedIndicator(Colors.grey.shade300),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
_buildLedIndicator(Colors.grey.shade700),
|
_buildLedIndicator(Colors.grey.shade300),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
_buildLedIndicator(Colors.grey.shade700),
|
_buildLedIndicator(Colors.grey.shade300),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
_buildLedIndicator(Colors.white),
|
_buildLedIndicator(_mainTextColor),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -153,25 +175,28 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
|
|
||||||
Widget _buildInfoCard() {
|
Widget _buildInfoCard() {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 160,
|
height: 164,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
_buildInfoRow('Name / \nNumber', const Icon(Icons.person, color: Colors.white, size: 20), 'USER', '001'),
|
_buildInfoRow('이름 / \n회원번호', Icon(Icons.person, color: _mainTextColor, size: 20), 'USER', '001',
|
||||||
|
value1Color: _mainTextColor, value2Color: _mainTextColor),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_buildInfoRow('STATUS', null, 'UNLOCKED', '● ACTIVE', value1Color: _pointColor, value2Color: _pointColor),
|
_buildInfoRow('상태', null, '잠금 해제됨', '● 활성',
|
||||||
|
value1Color: _mainTextColor, value2Color: _mainTextColor),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildInfoRow(String title, Widget? icon, String value1, String value2, {Color? value1Color, Color? value2Color}) {
|
Widget _buildInfoRow(String title, Widget? icon, String value1, String value2,
|
||||||
|
{Color? value1Color, Color? value2Color}) {
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black.withOpacity(0.3),
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -179,18 +204,18 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(title,
|
child: Text(title,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(color: Colors.grey[400], fontSize: 11, height: 1.4)),
|
style: TextStyle(color: _subTextColor, fontSize: 11, height: 1.4)),
|
||||||
),
|
),
|
||||||
VerticalDivider(color: Colors.grey[700], indent: 10, endIndent: 10),
|
VerticalDivider(color: _subTextColor.withOpacity(0.5), indent: 10, endIndent: 10),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 3,
|
flex: 3,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (icon != null) ...[icon, const SizedBox(height: 4)],
|
if (icon != null) ...[icon, const SizedBox(height: 4)],
|
||||||
Text(value1, style: TextStyle(color: value1Color ?? Colors.white, fontWeight: FontWeight.bold, fontSize: 12)),
|
Text(value1, style: TextStyle(color: value1Color ?? _mainTextColor, fontWeight: FontWeight.bold, fontSize: 12)),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(value2, style: TextStyle(color: value2Color ?? Colors.white, fontWeight: FontWeight.w500, fontSize: 12)),
|
Text(value2, style: TextStyle(color: value2Color ?? _mainTextColor, fontWeight: FontWeight.w500, fontSize: 12)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -202,16 +227,14 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
|
|
||||||
Widget _buildBatteryStatusCard() {
|
Widget _buildBatteryStatusCard() {
|
||||||
return Card(
|
return Card(
|
||||||
|
shadow: _cleanShadow,
|
||||||
|
cardColor: _cardBackgroundColor,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(_uniformGap),
|
padding: const EdgeInsets.all(_uniformGap),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text('BATTERY STATUS (%)',
|
Text('배터리 상태 (%)', style: TextStyle(color: _mainTextColor, fontSize: 12, fontWeight: FontWeight.bold)),
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.bold)),
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -224,15 +247,13 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
SizedBox.expand(
|
SizedBox.expand(
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
painter: _BatteryArcPainter(
|
painter: _BatteryArcPainter(
|
||||||
backgroundColor: Colors.grey.shade800,
|
backgroundColor: _accentContainerColor,
|
||||||
color: Colors.white,
|
color: _mainBlueColor,
|
||||||
percentage: 1.0,
|
percentage: 1.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Text('86',
|
Text('86', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: _mainTextColor)),
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 24, fontWeight: FontWeight.w600)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -243,55 +264,30 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const Text('NOW',
|
Text('현재', style: TextStyle(color: _mainTextColor, fontSize: 14, fontWeight: FontWeight.bold)),
|
||||||
style: TextStyle(
|
Text('사용 중', style: TextStyle(color: _mainBlueColor, fontSize: 14, fontWeight: FontWeight.bold)),
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.bold)),
|
|
||||||
Text('사용 중',
|
|
||||||
style: TextStyle(
|
|
||||||
color: _pointColor,
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.bold)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Divider(
|
Divider(color: _subTextColor.withOpacity(0.5), height: 20, thickness: 1),
|
||||||
color: Color(0xFF555555),
|
|
||||||
height: 20,
|
|
||||||
thickness: 1,
|
|
||||||
),
|
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Expanded(
|
Expanded(
|
||||||
flex: 4,
|
flex: 4,
|
||||||
child: Text('Solar Panel',
|
child: Text('태양광 패널', style: TextStyle(color: _mainTextColor, fontSize: 14)),
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white, fontSize: 14)),
|
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 5,
|
flex: 5,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Expanded(
|
Expanded(child: Text('전압: 00', style: TextStyle(color: _subTextColor, fontSize: 14))),
|
||||||
child: Text('전압: 00',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white70,
|
|
||||||
fontSize: 14)),
|
|
||||||
),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
child: VerticalDivider(
|
child: VerticalDivider(color: _subTextColor.withOpacity(0.5), thickness: 1),
|
||||||
color: Colors.grey[700],
|
|
||||||
thickness: 1,
|
|
||||||
),
|
),
|
||||||
),
|
Expanded(
|
||||||
const Expanded(
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(left: 8.0),
|
padding: const EdgeInsets.only(left: 8.0),
|
||||||
child: Text('전류: 00',
|
child: Text('전류: 00', style: TextStyle(color: _subTextColor, fontSize: 14)),
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white70,
|
|
||||||
fontSize: 14)),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -312,16 +308,14 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
|
|
||||||
Widget _buildControlCard() {
|
Widget _buildControlCard() {
|
||||||
return Card(
|
return Card(
|
||||||
|
shadow: _cleanShadow,
|
||||||
|
cardColor: _cardBackgroundColor,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(_uniformGap),
|
padding: const EdgeInsets.all(_uniformGap),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text('CONTROL',
|
Text('', style: TextStyle(color: _mainTextColor, fontSize: 11, fontWeight: FontWeight.bold)),
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 11,
|
|
||||||
fontWeight: FontWeight.bold)),
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 70,
|
height: 70,
|
||||||
@@ -332,24 +326,22 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
'UV LED',
|
'UV LED',
|
||||||
_controlToggles['UV LED']!,
|
_controlToggles['UV LED']!,
|
||||||
(val) => setState(() => _controlToggles['UV LED'] = val))),
|
(val) => setState(() => _controlToggles['UV LED'] = val))),
|
||||||
VerticalDivider(
|
VerticalDivider(color: _subTextColor.withOpacity(0.5), indent: 10, endIndent: 10),
|
||||||
color: Colors.grey[700], indent: 10, endIndent: 10),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStyledToggleSwitch(
|
child: _buildStyledToggleSwitch(
|
||||||
'CHARGING',
|
'CHARGING',
|
||||||
_controlToggles['CHARGING']!,
|
_controlToggles['CHARGING']!,
|
||||||
(val) => setState(() => _controlToggles['CHARGING'] = val))),
|
(val) => setState(() => _controlToggles['CHARGING'] = val))),
|
||||||
VerticalDivider(
|
VerticalDivider(color: _subTextColor.withOpacity(0.5), indent: 10, endIndent: 10),
|
||||||
color: Colors.grey[700], indent: 10, endIndent: 10),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStyledToggleSwitch(
|
child: _buildStyledToggleSwitch(
|
||||||
'HELMET',
|
'HELMET',
|
||||||
_controlToggles['HELMET']!,
|
_controlToggles['HELMET']!,
|
||||||
(val) => setState(() => _controlToggles['HELMET'] = val))),
|
(val) => setState(() => _controlToggles['HELMET'] = val))),
|
||||||
VerticalDivider(
|
VerticalDivider(color: _subTextColor.withOpacity(0.5), indent: 10, endIndent: 10),
|
||||||
color: Colors.grey[700], indent: 10, endIndent: 10),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStyledToggleSwitch('FAN', _controlToggles['FAN']!,
|
child: _buildStyledToggleSwitch('FAN',
|
||||||
|
_controlToggles['FAN']!,
|
||||||
(val) => setState(() => _controlToggles['FAN'] = val))),
|
(val) => setState(() => _controlToggles['FAN'] = val))),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -360,16 +352,11 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStyledToggleSwitch(
|
Widget _buildStyledToggleSwitch(String title, bool value, ValueChanged<bool> onChanged) {
|
||||||
String title, bool value, ValueChanged<bool> onChanged) {
|
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(title,
|
Text(title, style: TextStyle(color: _mainTextColor, fontSize: 13, fontWeight: FontWeight.bold)),
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 13,
|
|
||||||
fontWeight: FontWeight.bold)),
|
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () => onChanged(!value),
|
onTap: () => onChanged(!value),
|
||||||
@@ -380,7 +367,7 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
height: 30,
|
height: 30,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(15),
|
borderRadius: BorderRadius.circular(15),
|
||||||
color: value ? Colors.white : Colors.grey.shade700,
|
color: value ? _mainTextColor.withOpacity(0.8) : _toggleOffTrackColor,
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
@@ -395,7 +382,8 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
height: 26,
|
height: 26,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: value ? const Color(0xFF27292B) : Colors.white,
|
color: Colors.white,
|
||||||
|
border: Border.all(color: value ? _mainTextColor : _toggleOffKnobBorderColor, width: 1.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -408,18 +396,14 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: value
|
color: value ? Colors.white : Colors.transparent)))),
|
||||||
? const Color(0xFF27292B)
|
|
||||||
: Colors.transparent)))),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text('OFF',
|
child: Text('OFF',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: value
|
color: value ? Colors.transparent : _mainTextColor)))),
|
||||||
? Colors.transparent
|
|
||||||
: Colors.white)))),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -432,6 +416,8 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
|
|
||||||
Widget _buildEnvironmentSensorsCard() {
|
Widget _buildEnvironmentSensorsCard() {
|
||||||
return Card(
|
return Card(
|
||||||
|
shadow: _cleanShadow,
|
||||||
|
cardColor: _cardBackgroundColor,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(_uniformGap),
|
padding: const EdgeInsets.all(_uniformGap),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -439,20 +425,15 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Text('ENVIRONMENT SENSORS',
|
Text('환경 센서', style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: _mainTextColor)),
|
||||||
style:
|
|
||||||
TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text('VIEW HISTORY',
|
Text('기록 보기', style: TextStyle(color: _mainTextColor, fontSize: 10)),
|
||||||
style:
|
|
||||||
TextStyle(color: Colors.grey[400], fontSize: 10)),
|
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Icon(Icons.arrow_forward_ios,
|
Icon(Icons.arrow_forward_ios, size: 10, color: _subTextColor),
|
||||||
size: 10, color: Colors.grey[400]),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -466,17 +447,18 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildSensorInfoRow(Icons.water_drop_outlined, 'HUMID: 60%'),
|
_buildSensorInfoRow(Icons.water_drop_outlined, '습도: 60%', '습도'),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
_buildSensorInfoRow(Icons.thermostat, 'TEMP: 24.5℃'),
|
_buildSensorInfoRow(Icons.thermostat, '온도: 24.5℃', '온도'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
const Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 60, child: _LineChartPlaceholder())),
|
height: 60,
|
||||||
|
child: _LineChartPlaceholder(lineColor: _mainTextColor, subLabelColor: _subTextColor))),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -485,29 +467,27 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSensorInfoRow(IconData icon, String text) {
|
Widget _buildSensorInfoRow(IconData icon, String text, String type) {
|
||||||
return Row(children: [
|
return Row(children: [
|
||||||
Container(
|
Container(
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Icon(icon, color: Colors.black, size: 24),
|
child: Icon(icon, color: _mainTextColor, size: 24),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Text(text,
|
Text(text, style: TextStyle(fontSize: 14, color: _mainTextColor, fontWeight: FontWeight.w600))
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.w600))
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMyLocationCard() {
|
Widget _buildMyLocationCard() {
|
||||||
const LatLng exampleLocation = LatLng(37.5665, 126.9780);
|
const LatLng exampleLocation = LatLng(37.5665, 126.9780);
|
||||||
return Card(
|
return Card(
|
||||||
|
shadow: _cleanShadow,
|
||||||
|
cardColor: _cardBackgroundColor,
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 200.0,
|
height: 200.0,
|
||||||
@@ -518,30 +498,21 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('My Location',
|
Text('현재 위치', style: TextStyle(fontSize: 13, color: _mainTextColor, fontWeight: FontWeight.bold)),
|
||||||
style: TextStyle(
|
const SizedBox(height: 4),
|
||||||
fontSize: 13,
|
Text('주소: 남구 효덕로 277', style: TextStyle(fontSize: 11, color: _mainTextColor)),
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.bold)),
|
|
||||||
SizedBox(height: 4),
|
|
||||||
Text('주소: 남구 효덕로 277',
|
|
||||||
style:
|
|
||||||
TextStyle(fontSize: 11, color: Colors.white70)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text('VIEW MORE',
|
Text('더 보기', style: TextStyle(color: _mainTextColor, fontSize: 9)),
|
||||||
style:
|
|
||||||
TextStyle(color: Colors.grey[400], fontSize: 9)),
|
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Icon(Icons.arrow_forward_ios,
|
Icon(Icons.arrow_forward_ios, size: 10, color: _subTextColor),
|
||||||
size: 10, color: Colors.grey[400]),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -553,25 +524,22 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
options: const MapOptions(
|
options: const MapOptions(
|
||||||
initialCenter: exampleLocation,
|
initialCenter: exampleLocation,
|
||||||
initialZoom: 15.0,
|
initialZoom: 15.0,
|
||||||
interactionOptions:
|
interactionOptions: InteractionOptions(flags: InteractiveFlag.none),
|
||||||
InteractionOptions(flags: InteractiveFlag.none),
|
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
TileLayer(
|
TileLayer(
|
||||||
urlTemplate:
|
urlTemplate: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',
|
||||||
'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',
|
|
||||||
userAgentPackageName: 'com.example.app',
|
userAgentPackageName: 'com.example.app',
|
||||||
subdomains: const ['a', 'b', 'c', 'd'],
|
subdomains: const ['a', 'b', 'c', 'd'],
|
||||||
retinaMode: true,
|
retinaMode: true,
|
||||||
),
|
),
|
||||||
const MarkerLayer(
|
MarkerLayer(
|
||||||
markers: [
|
markers: [
|
||||||
Marker(
|
Marker(
|
||||||
point: exampleLocation,
|
point: exampleLocation,
|
||||||
width: 80,
|
width: 80,
|
||||||
height: 80,
|
height: 80,
|
||||||
child: Icon(Icons.location_pin,
|
child: Icon(Icons.location_pin, size: 40, color: _mainTextColor),
|
||||||
size: 40, color: Colors.white),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -586,15 +554,17 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
|
|
||||||
Widget _buildActivityCard() {
|
Widget _buildActivityCard() {
|
||||||
return Card(
|
return Card(
|
||||||
|
shadow: _cleanShadow,
|
||||||
|
cardColor: _cardBackgroundColor,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(_uniformGap),
|
padding: const EdgeInsets.all(_uniformGap),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text('Activity',
|
Text('Activity',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.bold)),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Row(
|
Row(
|
||||||
@@ -630,35 +600,44 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
|
|||||||
|
|
||||||
Widget _activityText(String text) {
|
Widget _activityText(String text) {
|
||||||
return Text(text,
|
return Text(text,
|
||||||
style: const TextStyle(fontSize: 11, color: Colors.white70));
|
style: TextStyle(fontSize: 11, color: _mainTextColor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class _LineChartPlaceholder extends StatelessWidget {
|
class _LineChartPlaceholder extends StatelessWidget {
|
||||||
const _LineChartPlaceholder();
|
final Color lineColor;
|
||||||
|
final Color subLabelColor;
|
||||||
|
|
||||||
|
const _LineChartPlaceholder({
|
||||||
|
super.key,
|
||||||
|
required this.lineColor,
|
||||||
|
required this.subLabelColor
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child:
|
child:
|
||||||
CustomPaint(painter: _LineChartPainter(), size: Size.infinite)),
|
CustomPaint(painter: _LineChartPainter(color: lineColor), size: Size.infinite)),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
const Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||||
Text('24H AGO', style: TextStyle(fontSize: 8, color: Colors.white54)),
|
Text('24H AGO', style: TextStyle(fontSize: 8, color: subLabelColor)),
|
||||||
Text('12H AGO', style: TextStyle(fontSize: 8, color: Colors.white54)),
|
Text('12H AGO', style: TextStyle(fontSize: 8, color: subLabelColor)),
|
||||||
Text('NOW', style: TextStyle(fontSize: 8, color: Colors.white54))
|
Text('NOW', style: TextStyle(fontSize: 8, color: subLabelColor))
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LineChartPainter extends CustomPainter {
|
class _LineChartPainter extends CustomPainter {
|
||||||
|
final Color color;
|
||||||
|
_LineChartPainter({required this.color});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(ui.Canvas canvas, ui.Size size) {
|
void paint(ui.Canvas canvas, ui.Size size) {
|
||||||
final paint = Paint()
|
final paint = Paint()
|
||||||
..color = Colors.white.withOpacity(0.8)
|
..color = color
|
||||||
..strokeWidth = 1.5
|
..strokeWidth = 1.5
|
||||||
..style = PaintingStyle.stroke;
|
..style = PaintingStyle.stroke;
|
||||||
|
|
||||||
@@ -683,12 +662,18 @@ class Card extends StatelessWidget {
|
|||||||
final Widget child;
|
final Widget child;
|
||||||
final EdgeInsetsGeometry? padding;
|
final EdgeInsetsGeometry? padding;
|
||||||
final Clip clipBehavior;
|
final Clip clipBehavior;
|
||||||
|
final Color? borderColor;
|
||||||
|
final Color? cardColor;
|
||||||
|
final BoxShadow? shadow;
|
||||||
|
|
||||||
const Card({
|
const Card({
|
||||||
super.key,
|
super.key,
|
||||||
required this.child,
|
required this.child,
|
||||||
this.padding,
|
this.padding,
|
||||||
this.clipBehavior = Clip.none,
|
this.clipBehavior = Clip.none,
|
||||||
|
this.borderColor,
|
||||||
|
this.cardColor,
|
||||||
|
this.shadow,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -696,8 +681,9 @@ class Card extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
clipBehavior: clipBehavior,
|
clipBehavior: clipBehavior,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).primaryColor,
|
color: cardColor ?? Colors.white,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: shadow != null ? [shadow!] : null,
|
||||||
),
|
),
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
@@ -723,7 +709,6 @@ class _BatteryArcPainter extends CustomPainter {
|
|||||||
..style = PaintingStyle.stroke
|
..style = PaintingStyle.stroke
|
||||||
..strokeCap = StrokeCap.round;
|
..strokeCap = StrokeCap.round;
|
||||||
|
|
||||||
|
|
||||||
final Paint foregroundPaint = Paint()
|
final Paint foregroundPaint = Paint()
|
||||||
..color = color
|
..color = color
|
||||||
..strokeWidth = 8
|
..strokeWidth = 8
|
||||||
|
|||||||
@@ -1,30 +1,63 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'main.dart';
|
import 'main.dart';
|
||||||
|
|
||||||
class LoginScreen extends StatelessWidget {
|
class LoginScreen extends StatefulWidget {
|
||||||
|
const LoginScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LoginScreen> createState() => _LoginScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LoginScreenState extends State<LoginScreen> {
|
||||||
final TextEditingController _idController = TextEditingController();
|
final TextEditingController _idController = TextEditingController();
|
||||||
final TextEditingController _pwController = TextEditingController();
|
final TextEditingController _pwController = TextEditingController();
|
||||||
|
|
||||||
LoginScreen({super.key});
|
final FocusNode _idFocusNode = FocusNode();
|
||||||
|
final FocusNode _pwFocusNode = FocusNode();
|
||||||
|
|
||||||
|
final Color mainBlueColor = const Color(0xFF007AFF);
|
||||||
|
|
||||||
|
bool _isIdFocused = false;
|
||||||
|
bool _isPwFocused = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_idFocusNode.addListener(() {
|
||||||
|
setState(() => _isIdFocused = _idFocusNode.hasFocus);
|
||||||
|
});
|
||||||
|
_pwFocusNode.addListener(() {
|
||||||
|
setState(() => _isPwFocused = _pwFocusNode.hasFocus);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_idController.dispose();
|
||||||
|
_pwController.dispose();
|
||||||
|
_idFocusNode.dispose();
|
||||||
|
_pwFocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color(0xFF1E1E1E),
|
backgroundColor: Colors.white,
|
||||||
body: Padding(
|
body: SafeArea(
|
||||||
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(24.0),
|
padding: const EdgeInsets.all(24.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.polymer, size: 80, color: Colors.white),
|
Icon(Icons.polymer, size: 80, color: mainBlueColor),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Text(
|
Text(
|
||||||
'METAQLAB'
|
'METAQLAB',
|
||||||
'',
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: mainBlueColor,
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
letterSpacing: 1.2,
|
letterSpacing: 1.2,
|
||||||
@@ -32,9 +65,21 @@ class LoginScreen extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 60),
|
const SizedBox(height: 60),
|
||||||
|
|
||||||
_buildTextField('User ID', Icons.person, controller: _idController),
|
_buildCustomTextField(
|
||||||
|
label: '아이디',
|
||||||
|
controller: _idController,
|
||||||
|
focusNode: _idFocusNode,
|
||||||
|
isFocused: _isIdFocused,
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildTextField('Password', Icons.lock, isObscure: true, controller: _pwController),
|
|
||||||
|
_buildCustomTextField(
|
||||||
|
label: '비밀번호',
|
||||||
|
controller: _pwController,
|
||||||
|
focusNode: _pwFocusNode,
|
||||||
|
isFocused: _isPwFocused,
|
||||||
|
isObscure: true,
|
||||||
|
),
|
||||||
|
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
|
|
||||||
@@ -61,45 +106,83 @@ class LoginScreen extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: mainBlueColor,
|
||||||
foregroundColor: Colors.black,
|
foregroundColor: Colors.white,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
|
elevation: 0,
|
||||||
),
|
),
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'LOGIN',
|
'로그인',
|
||||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
child: const Text('Forgot Password?', style: TextStyle(color: Colors.grey)),
|
child: Text(
|
||||||
|
'비밀번호 찾기 / 회원가입',
|
||||||
|
style: TextStyle(color: mainBlueColor, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTextField(String hint, IconData icon, {bool isObscure = false, required TextEditingController controller}) {
|
Widget _buildCustomTextField({
|
||||||
return TextField(
|
required String label,
|
||||||
controller: controller,
|
required TextEditingController controller,
|
||||||
obscureText: isObscure,
|
required FocusNode focusNode,
|
||||||
style: const TextStyle(color: Colors.white),
|
required bool isFocused,
|
||||||
decoration: InputDecoration(
|
bool isObscure = false,
|
||||||
prefixIcon: Icon(icon, color: Colors.grey),
|
}) {
|
||||||
hintText: hint,
|
return AnimatedContainer(
|
||||||
hintStyle: const TextStyle(color: Colors.grey),
|
duration: const Duration(milliseconds: 200),
|
||||||
filled: true,
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
fillColor: const Color(0xFF2C2C2E),
|
decoration: BoxDecoration(
|
||||||
border: OutlineInputBorder(
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(12),
|
border: Border.all(
|
||||||
borderSide: BorderSide.none,
|
color: isFocused ? mainBlueColor : Colors.grey.shade300,
|
||||||
|
width: isFocused ? 1.5 : 1.0,
|
||||||
),
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
color: isFocused ? mainBlueColor : Colors.grey.shade600,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
TextField(
|
||||||
|
controller: controller,
|
||||||
|
focusNode: focusNode,
|
||||||
|
obscureText: isObscure,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
border: InputBorder.none,
|
||||||
|
focusedBorder: InputBorder.none,
|
||||||
|
enabledBorder: InputBorder.none,
|
||||||
|
),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
cursorColor: mainBlueColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ import 'package:smarthelmet_app/rent_return_screen.dart';
|
|||||||
import 'package:smarthelmet_app/settings_screen.dart';
|
import 'package:smarthelmet_app/settings_screen.dart';
|
||||||
import 'package:smarthelmet_app/login_screen.dart';
|
import 'package:smarthelmet_app/login_screen.dart';
|
||||||
|
|
||||||
|
final Color _mainBlueColor = const Color(0xFF002FA7);
|
||||||
|
final Color _mainTextColor = const Color(0xFF1C1C1E);
|
||||||
|
final Color _subTextColor = const Color(0xFF6A717B);
|
||||||
|
final Color _pageBackgroundColor = const Color(0xFFF5F7F9);
|
||||||
|
final Color _cardBackgroundColor = Colors.white;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const SmartHelmetApp());
|
runApp(const SmartHelmetApp());
|
||||||
}
|
}
|
||||||
@@ -18,22 +24,22 @@ class SmartHelmetApp extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
|
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
|
||||||
statusBarColor: Colors.transparent,
|
statusBarColor: Colors.transparent,
|
||||||
statusBarIconBrightness: Brightness.light,
|
statusBarIconBrightness: Brightness.dark,
|
||||||
));
|
));
|
||||||
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.light,
|
||||||
scaffoldBackgroundColor: const Color(0xFF27292B),
|
scaffoldBackgroundColor: _pageBackgroundColor,
|
||||||
primaryColor: const Color(0xFF30343B),
|
primaryColor: _mainBlueColor,
|
||||||
fontFamily: 'Pretendard',
|
fontFamily: 'Pretendard',
|
||||||
textTheme: const TextTheme(
|
textTheme: TextTheme(
|
||||||
bodyLarge: TextStyle(color: Colors.white, fontWeight: FontWeight.w500),
|
bodyLarge: TextStyle(color: _mainTextColor, fontWeight: FontWeight.w500),
|
||||||
bodyMedium: TextStyle(color: Colors.white70, fontWeight: FontWeight.w400),
|
bodyMedium: TextStyle(color: _subTextColor, fontWeight: FontWeight.w400),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
home: LoginScreen(),
|
home: const HomeScreen(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,19 +87,37 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
type: BottomNavigationBarType.fixed,
|
type: BottomNavigationBarType.fixed,
|
||||||
backgroundColor: const Color(0xFF1C1C1E),
|
backgroundColor: _mainBlueColor,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
selectedItemColor: Colors.white,
|
selectedItemColor: Colors.white,
|
||||||
unselectedItemColor: Colors.grey,
|
unselectedItemColor: Colors.white70,
|
||||||
showUnselectedLabels: true,
|
showUnselectedLabels: true,
|
||||||
selectedFontSize: 12,
|
selectedFontSize: 12,
|
||||||
unselectedFontSize: 12,
|
unselectedFontSize: 12,
|
||||||
|
selectedLabelStyle: const TextStyle(fontWeight: FontWeight.bold, height: 1.5),
|
||||||
|
unselectedLabelStyle: const TextStyle(fontWeight: FontWeight.bold, height: 1.5),
|
||||||
|
iconSize: 22,
|
||||||
items: const [
|
items: const [
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'HOME'),
|
BottomNavigationBarItem(
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.history), label: 'HISTORY'),
|
icon: Padding(padding: EdgeInsets.only(bottom: 2.0), child: Icon(Icons.home)),
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.settings_input_component), label: 'CONTROL'),
|
label: '홈',
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.assignment_return_outlined), label: 'RENT/RETURN'),
|
),
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'SETTINGS'),
|
BottomNavigationBarItem(
|
||||||
|
icon: Padding(padding: EdgeInsets.only(bottom: 2.0), child: Icon(Icons.history)),
|
||||||
|
label: '기록',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Padding(padding: EdgeInsets.only(bottom: 2.0), child: Icon(Icons.settings_input_component)),
|
||||||
|
label: '제어',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Padding(padding: EdgeInsets.only(bottom: 2.0), child: Icon(Icons.assignment_return_outlined)),
|
||||||
|
label: '대여 / 반납',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Padding(padding: EdgeInsets.only(bottom: 2.0), child: Icon(Icons.settings)),
|
||||||
|
label: '설정',
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,6 +3,21 @@ import 'package:flutter_map/flutter_map.dart';
|
|||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'rental_process_screen.dart';
|
import 'rental_process_screen.dart';
|
||||||
|
|
||||||
|
final Color _mainBlueColor = const Color(0xFF002FA7);
|
||||||
|
final Color _mainTextColor = const Color(0xFF1C1C1E);
|
||||||
|
final Color _subTextColor = const Color(0xFF6A717B);
|
||||||
|
final Color _pageBackgroundColor = const Color(0xFFF5F7F9);
|
||||||
|
final Color _cardBackgroundColor = Colors.white;
|
||||||
|
final Color _accentContainerColor = const Color(0xFFF0F2F5);
|
||||||
|
final Color _borderColor = const Color(0xFF007AFF).withOpacity(0.8);
|
||||||
|
|
||||||
|
const BoxShadow _cleanShadow = BoxShadow(
|
||||||
|
color: Color.fromRGBO(0, 0, 0, 0.07),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
spreadRadius: 0,
|
||||||
|
);
|
||||||
|
|
||||||
class StationInfo {
|
class StationInfo {
|
||||||
final String name;
|
final String name;
|
||||||
final String address;
|
final String address;
|
||||||
@@ -22,8 +37,7 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final LatLng centerLocation = const LatLng(35.1595, 126.8526);
|
final LatLng centerLocation = LatLng(35.1595, 126.8526);
|
||||||
|
|
||||||
final List<StationInfo> stations = [
|
final List<StationInfo> stations = [
|
||||||
StationInfo(
|
StationInfo(
|
||||||
name: 'STATION A - GU.UNIV',
|
name: 'STATION A - GU.UNIV',
|
||||||
@@ -48,26 +62,47 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color(0xFF27292B),
|
backgroundColor: _pageBackgroundColor,
|
||||||
appBar: AppBar(
|
appBar: PreferredSize(
|
||||||
title: const Text(
|
preferredSize: const Size.fromHeight(kToolbarHeight),
|
||||||
'RENT/ RETURN',
|
child: Container(
|
||||||
style: TextStyle(
|
decoration: BoxDecoration(
|
||||||
fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white),
|
color: _pageBackgroundColor,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.05),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
),
|
),
|
||||||
backgroundColor: const Color(0xFF2C2C2E),
|
],
|
||||||
|
),
|
||||||
|
child: AppBar(
|
||||||
|
scrolledUnderElevation: 0,
|
||||||
|
title: Text(
|
||||||
|
'대여/ 반납',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: _mainTextColor),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.more_vert, color: Colors.white),
|
icon: Icon(Icons.more_vert, color: _mainTextColor),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Column(
|
),
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
SizedBox(
|
||||||
flex: 50,
|
height: 300.0,
|
||||||
|
width: double.infinity,
|
||||||
child: FlutterMap(
|
child: FlutterMap(
|
||||||
options: MapOptions(
|
options: MapOptions(
|
||||||
initialCenter: centerLocation,
|
initialCenter: centerLocation,
|
||||||
@@ -75,64 +110,66 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
TileLayer(
|
TileLayer(
|
||||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
urlTemplate:
|
||||||
|
'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',
|
||||||
userAgentPackageName: 'com.example.helmet_app',
|
userAgentPackageName: 'com.example.helmet_app',
|
||||||
|
subdomains: const ['a', 'b', 'c', 'd'],
|
||||||
|
retinaMode: true,
|
||||||
),
|
),
|
||||||
MarkerLayer(
|
MarkerLayer(
|
||||||
markers: [
|
markers: [
|
||||||
_buildBlackMarker(centerLocation),
|
_buildBlueMarker(centerLocation),
|
||||||
_buildBlackMarker(const LatLng(35.162, 126.855)),
|
_buildBlueMarker(const LatLng(35.162, 126.855)),
|
||||||
_buildBlackMarker(const LatLng(35.157, 126.850)),
|
_buildBlueMarker(const LatLng(35.157, 126.850)),
|
||||||
_buildBlackMarker(const LatLng(35.160, 126.858)),
|
_buildBlueMarker(const LatLng(35.160, 126.858)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Container(
|
||||||
Expanded(
|
color: _pageBackgroundColor,
|
||||||
flex: 45,
|
|
||||||
child: Container(
|
|
||||||
color: const Color(0xFF27292B),
|
|
||||||
padding: const EdgeInsets.fromLTRB(16, 20, 16, 0),
|
padding: const EdgeInsets.fromLTRB(16, 20, 16, 0),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
'LIST VIEW',
|
'LIST VIEW',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
|
ListView.builder(
|
||||||
Expanded(
|
shrinkWrap: true,
|
||||||
child: ListView.builder(
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
padding: const EdgeInsets.only(bottom: 20),
|
padding: const EdgeInsets.only(bottom: 20),
|
||||||
itemCount: stations.length,
|
itemCount: stations.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return _buildStationItem(context, stations[index]);
|
return _buildStationItem(context, stations[index]);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStationItem(BuildContext context, StationInfo station) {
|
Widget _buildStationItem(BuildContext context, StationInfo station) {
|
||||||
|
bool isOffline = station.status.startsWith('OFFLINE');
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(bottom: 16),
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFF30343B),
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [_cleanShadow],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -145,7 +182,7 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(6),
|
padding: const EdgeInsets.all(6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black.withValues(alpha: 0.3),
|
color: _pageBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(5),
|
borderRadius: BorderRadius.circular(5),
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
@@ -153,8 +190,8 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFF2D2F33),
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(5)
|
borderRadius: BorderRadius.circular(5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
@@ -163,7 +200,7 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
'assets/images/storage.png',
|
'assets/images/storage.png',
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
errorBuilder: (context, error, stackTrace) =>
|
errorBuilder: (context, error, stackTrace) =>
|
||||||
const Icon(Icons.inventory_2, color: Colors.white54),
|
Icon(Icons.inventory_2, color: _subTextColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -171,15 +208,14 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
station.name,
|
station.name,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
),
|
),
|
||||||
@@ -189,30 +225,29 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
station.address,
|
station.address,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.grey, fontSize: 11, height: 1.2),
|
color: _subTextColor, fontSize: 11, height: 1.2),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
'STATUS: ${station.status}',
|
'STATUS: ${station.status}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: station.status.startsWith('OFFLINE')
|
color: isOffline ? Colors.redAccent : _mainBlueColor,
|
||||||
? Colors.redAccent
|
|
||||||
: Colors.grey,
|
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
station.distance,
|
station.distance,
|
||||||
style: const TextStyle(color: Colors.grey, fontSize: 11),
|
style: TextStyle(color: _subTextColor, fontSize: 11),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: isOffline
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
@@ -223,29 +258,31 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor:
|
||||||
foregroundColor: Colors.black,
|
isOffline ? Colors.grey.shade400 : _mainBlueColor,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(5),
|
borderRadius: BorderRadius.circular(5),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||||
minimumSize: const Size(80, 40),
|
minimumSize: const Size(80, 40),
|
||||||
|
elevation: 0,
|
||||||
),
|
),
|
||||||
child: const Text(
|
child: const Text('SELECT',
|
||||||
'SELECT',
|
style: TextStyle(
|
||||||
style: TextStyle(fontWeight: FontWeight.w500, letterSpacing: 0.8, fontSize: 14)
|
fontWeight: FontWeight.w500,
|
||||||
),
|
letterSpacing: 0.8,
|
||||||
|
fontSize: 14)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFF1E1E1E),
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(5),
|
borderRadius: BorderRadius.circular(5),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -254,10 +291,10 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
'LOGS',
|
'기록',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _mainTextColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
@@ -267,7 +304,7 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
'VIEW MORE >',
|
'VIEW MORE >',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.grey[400],
|
color: _subTextColor,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -275,13 +312,13 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
const Text(
|
Text(
|
||||||
'Available: Door Fully Closed',
|
'Available: Door Fully Closed',
|
||||||
style: TextStyle(color: Colors.grey, fontSize: 11),
|
style: TextStyle(color: _subTextColor, fontSize: 11),
|
||||||
),
|
),
|
||||||
const Text(
|
Text(
|
||||||
'(2025-11-19)/(08:58)',
|
'(2025-11-19)/(08:58)',
|
||||||
style: TextStyle(color: Colors.grey, fontSize: 11),
|
style: TextStyle(color: _subTextColor, fontSize: 11),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -291,14 +328,14 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Marker _buildBlackMarker(LatLng point) {
|
Marker _buildBlueMarker(LatLng point) {
|
||||||
return Marker(
|
return Marker(
|
||||||
point: point,
|
point: point,
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
child: const Icon(
|
child: Icon(
|
||||||
Icons.location_on,
|
Icons.location_on,
|
||||||
color: Colors.black,
|
color: _mainBlueColor,
|
||||||
size: 40,
|
size: 40,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -312,31 +349,44 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
builder: (context) {
|
builder: (context) {
|
||||||
return Container(
|
return Container(
|
||||||
height: MediaQuery.of(context).size.height * 0.6,
|
height: MediaQuery.of(context).size.height * 0.6,
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Color(0xFF1E1E1E),
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
border: Border.all(color: _borderColor, width: 1.5),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Container(
|
Container(
|
||||||
width: 40, height: 4,
|
width: 40,
|
||||||
decoration: BoxDecoration(color: Colors.grey[600], borderRadius: BorderRadius.circular(2)),
|
height: 4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _subTextColor,
|
||||||
|
borderRadius: BorderRadius.circular(2)),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(20.0),
|
padding: const EdgeInsets.all(20.0),
|
||||||
child: Text("LOGS: $stationName", style: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold)),
|
child: Text("LOGS: $stationName",
|
||||||
|
style: TextStyle(
|
||||||
|
color: _mainTextColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold)),
|
||||||
),
|
),
|
||||||
const Divider(color: Colors.white24, height: 1),
|
Divider(color: _subTextColor.withOpacity(0.5), height: 1),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
children: [
|
children: [
|
||||||
_buildLogItem("08:58:33", "Door Fully Closed", Icons.door_front_door, Colors.green),
|
_buildLogItem("08:58:33", "Door Fully Closed",
|
||||||
_buildLogItem("08:58:30", "Helmet Returned", Icons.check_circle_outline, Colors.blue),
|
Icons.door_front_door, _mainBlueColor),
|
||||||
_buildLogItem("08:55:12", "User Unlocked Door", Icons.lock_open, Colors.white),
|
_buildLogItem("08:58:30", "Helmet Returned",
|
||||||
_buildLogItem("08:30:00", "UV Sanitization Complete", Icons.cleaning_services, Colors.purpleAccent),
|
Icons.check_circle_outline, _mainBlueColor),
|
||||||
_buildLogItem("08:00:00", "System Boot Up", Icons.power_settings_new, Colors.grey),
|
_buildLogItem("08:55:12", "User Unlocked Door",
|
||||||
|
Icons.lock_open, _mainTextColor),
|
||||||
|
_buildLogItem("08:30:00", "UV Sanitization Complete",
|
||||||
|
Icons.cleaning_services, _mainBlueColor),
|
||||||
|
_buildLogItem("08:00:00", "System Boot Up",
|
||||||
|
Icons.power_settings_new, _subTextColor),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -347,23 +397,26 @@ class RentReturnScreen extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLogItem(String time, String message, IconData icon, Color color) {
|
Widget _buildLogItem(
|
||||||
|
String time, String message, IconData icon, Color color) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 20.0),
|
padding: const EdgeInsets.only(bottom: 20.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(time, style: const TextStyle(color: Colors.grey, fontSize: 12)),
|
Text(time, style: TextStyle(color: _subTextColor, fontSize: 12)),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Icon(icon, color: color, size: 20),
|
Icon(icon, color: color, size: 20),
|
||||||
Container(width: 2, height: 20, color: Colors.white12),
|
Container(
|
||||||
|
width: 2, height: 20, color: _subTextColor.withOpacity(0.5)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(message, style: const TextStyle(color: Colors.white70, fontSize: 14)),
|
child: Text(message,
|
||||||
|
style: TextStyle(color: _mainTextColor, fontSize: 14)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
|
|
||||||
class RentalProcessScreen extends StatelessWidget {
|
class RentalProcessScreen extends StatelessWidget {
|
||||||
final String stationName;
|
final String stationName;
|
||||||
@@ -8,25 +10,34 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
required this.stationName,
|
required this.stationName,
|
||||||
});
|
});
|
||||||
|
|
||||||
static const Color kBackgroundColor = Color(0xFF1E1E1E);
|
static const Color _mainBlueColor = Color(0xFF002FA7);
|
||||||
static const Color kCardColor = Color(0xFF2C2C2E);
|
static const Color _mainTextColor = Color(0xFF1C1C1E);
|
||||||
static const Color kPrimaryGreen = Color(0xFF4CAF50);
|
static const Color _subTextColor = Color(0xFF6A717B);
|
||||||
static const Color kPrimaryOrange = Color(0xFFFF3D00);
|
static const Color _pageBackgroundColor = Color(0xFFF5F7F9);
|
||||||
|
static const Color _cardBackgroundColor = Colors.white;
|
||||||
|
static const Color _accentContainerColor = Color(0xFFF0F2F5);
|
||||||
|
static const Color _borderColor = Color(0xFF007AFF);
|
||||||
|
static const Color _primaryGreen = Color(0xFF4CAF50);
|
||||||
|
static const Color _primaryOrange = Color(0xFFFF3D00);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: kBackgroundColor,
|
backgroundColor: _pageBackgroundColor,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
scrolledUnderElevation: 0,
|
||||||
title: Text(
|
title: Text(
|
||||||
stationName,
|
stationName,
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: Colors.white),
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
color: _mainTextColor),
|
||||||
),
|
),
|
||||||
backgroundColor: kCardColor,
|
backgroundColor: _cardBackgroundColor,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.more_vert, color: Colors.white),
|
icon: const Icon(Icons.more_vert, color: _mainTextColor),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -39,52 +50,51 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_buildStatusCard(context),
|
_buildStatusCard(context),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
_buildProcessSectionTitle('헬멧 대여 순서'),
|
||||||
_buildProcessSectionTitle('HELMET RENTAL PROCESS'),
|
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kCardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
_buildStepRow(1, 'UNLOCK & OPEN', Icons.lock_open, isCompleted: true),
|
_buildStepRow(1, '잠금 해제 & 문 열림', Icons.lock_open,
|
||||||
|
isCompleted: true),
|
||||||
_buildDivider(),
|
_buildDivider(),
|
||||||
_buildStepRow(2, 'DOOR STATUS', Icons.sensor_door_outlined),
|
_buildStepRow(2, '문 상태 확인', Icons.sensor_door_outlined),
|
||||||
_buildDivider(),
|
_buildDivider(),
|
||||||
_buildStepRow(3, 'TAKE HELMET', Icons.outbox),
|
_buildStepRow(3, '헬멧 꺼내기', Icons.outbox),
|
||||||
_buildDivider(),
|
_buildDivider(),
|
||||||
_buildStepRow(4, 'ENJOY RIDING!', Icons.sentiment_satisfied_alt, showDivider: false),
|
_buildStepRow(4, '주행 시작 !', Icons.sentiment_satisfied_alt,
|
||||||
|
showDivider: false),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
_buildProcessSectionTitle('헬멧 반납 과정'),
|
||||||
_buildProcessSectionTitle('HELMET RETURN PROCESS'),
|
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kCardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
_buildStepRow(1, 'UNLOCK & OPEN', Icons.lock_open),
|
_buildStepRow(1, '잠금해제 & 문열림', Icons.lock_open),
|
||||||
_buildDivider(),
|
_buildDivider(),
|
||||||
_buildStepRow(2, 'INSERT HELMET', Icons.move_to_inbox),
|
_buildStepRow(2, '헬멧 넣기', Icons.move_to_inbox),
|
||||||
_buildDivider(),
|
_buildDivider(),
|
||||||
_buildStepRow(3, 'SENSOR SCANNING\n& RETURN COMPLETE', Icons.sync),
|
_buildStepRow(3, '센서 스캔 & 반납 완료', Icons.sync),
|
||||||
_buildDivider(),
|
_buildDivider(),
|
||||||
_buildStepRow(4, 'SANITIZING', Icons.shield_outlined, showDivider: false),
|
_buildStepRow(4, '살균 시작', Icons.shield_outlined,
|
||||||
|
showDivider: false),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
_buildErrorAlertBox(),
|
_buildErrorAlertBox(),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
_buildLogsCard(context),
|
_buildLogsCard(context),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
],
|
],
|
||||||
@@ -98,16 +108,18 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kCardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: const [
|
children: const [
|
||||||
Icon(Icons.circle, color: kPrimaryOrange, size: 16),
|
Icon(Icons.circle, color: _primaryOrange, size: 16),
|
||||||
SizedBox(width: 6),
|
SizedBox(width: 6),
|
||||||
Text('IN USE', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
|
Text('사용 중',
|
||||||
|
style: TextStyle(
|
||||||
|
color: _mainTextColor, fontWeight: FontWeight.bold)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
@@ -119,13 +131,16 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
height: 150,
|
height: 150,
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kBackgroundColor,
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/images/open.png',
|
'assets/images/open.png',
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
errorBuilder: (context, error, stackTrace) => const Icon(Icons.inventory_2, size: 50, color: Colors.white54),
|
errorBuilder: (context, error, stackTrace) => const Icon(
|
||||||
|
Icons.inventory_2,
|
||||||
|
size: 50,
|
||||||
|
color: _subTextColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
@@ -133,7 +148,8 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text('NOW', style: TextStyle(color: Colors.grey, fontSize: 12)),
|
const Text('NOW',
|
||||||
|
style: TextStyle(color: _subTextColor, fontSize: 12)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
@@ -143,17 +159,20 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('문이 열렸습니다! (OPEN 버튼 눌림)'),
|
content: Text('문이 열렸습니다! (OPEN 버튼 눌림)'),
|
||||||
duration: Duration(seconds: 1),
|
duration: Duration(seconds: 1),
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: _mainBlueColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: _mainBlueColor,
|
||||||
foregroundColor: Colors.black,
|
foregroundColor: Colors.white,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8)),
|
||||||
),
|
),
|
||||||
child: const Text('OPEN', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
|
child: const Text('OPEN',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold, fontSize: 16)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
@@ -161,13 +180,16 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kBackgroundColor,
|
color: _accentContainerColor,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'SENSOR ERROR:\nLOCK FAIL',
|
'ERROR:\nLOCK FAIL',
|
||||||
style: TextStyle(color: kPrimaryOrange, fontWeight: FontWeight.bold, height: 1.2),
|
style: TextStyle(
|
||||||
|
color: _primaryOrange,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
height: 1.2),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -185,11 +207,13 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
Widget _buildProcessSectionTitle(String title) {
|
Widget _buildProcessSectionTitle(String title) {
|
||||||
return Text(
|
return Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16),
|
style: const TextStyle(
|
||||||
|
color: _mainTextColor, fontWeight: FontWeight.bold, fontSize: 16),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStepRow(int step, String title, IconData icon, {bool isCompleted = false, bool showDivider = true}) {
|
Widget _buildStepRow(int step, String title, IconData icon,
|
||||||
|
{bool isCompleted = false, bool showDivider = true}) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -199,45 +223,64 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text('STEP $step', style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
|
Text('STEP $step',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: _mainTextColor, fontWeight: FontWeight.bold)),
|
||||||
if (isCompleted) ...[
|
if (isCompleted) ...[
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
const Icon(Icons.check_circle, color: kPrimaryGreen, size: 16),
|
const Icon(Icons.check_circle,
|
||||||
|
color: _primaryGreen, size: 16),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(title, style: const TextStyle(color: Colors.white, fontSize: 18, letterSpacing: 0.6)),
|
Text(title,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: _mainTextColor, fontSize: 18, letterSpacing: 0.6)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Icon(icon, color: isCompleted ? Colors.white : Colors.grey, size: 48),
|
Icon(icon,
|
||||||
|
color: isCompleted ? _mainBlueColor : _subTextColor, size: 48),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDivider() {
|
Widget _buildDivider() {
|
||||||
return const Divider(color: Colors.white, height: 1, thickness: 1, indent: 20, endIndent: 20);
|
return Divider(
|
||||||
|
color: _subTextColor.withOpacity(0.5),
|
||||||
|
height: 1,
|
||||||
|
thickness: 1,
|
||||||
|
indent: 20,
|
||||||
|
endIndent: 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildErrorAlertBox() {
|
Widget _buildErrorAlertBox() {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kCardColor.withOpacity(0.5),
|
color: _accentContainerColor,
|
||||||
border: Border.all(color: kPrimaryOrange, width: 2),
|
border: Border.all(color: _primaryOrange, width: 2),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: const [
|
children: const [
|
||||||
Icon(Icons.warning_amber_rounded, color: kPrimaryOrange, size: 40),
|
Icon(Icons.warning_amber_rounded, color: _primaryOrange, size: 40),
|
||||||
SizedBox(width: 16),
|
SizedBox(width: 16),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('SENSOR ERROR:', style: TextStyle(color: kPrimaryOrange, fontWeight: FontWeight.bold, fontSize: 16)),
|
Text('SENSOR ERROR:',
|
||||||
Text('LOCK FAILURE', style: TextStyle(color: kPrimaryOrange, fontWeight: FontWeight.bold, fontSize: 16)),
|
style: TextStyle(
|
||||||
|
color: _primaryOrange,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16)),
|
||||||
|
Text('LOCK FAILURE',
|
||||||
|
style: TextStyle(
|
||||||
|
color: _primaryOrange,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -249,7 +292,7 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kCardColor,
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -257,24 +300,29 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const Text('LOGS', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
|
const Text('LOGS',
|
||||||
|
style: TextStyle(
|
||||||
|
color: _mainTextColor, fontWeight: FontWeight.bold)),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () => _showLogHistory(context),
|
onTap: () => _showLogHistory(context),
|
||||||
child: Text('VIEW MORE >', style: TextStyle(color: Colors.grey[400], fontSize: 12)),
|
child: Text('VIEW MORE >',
|
||||||
|
style: TextStyle(color: _subTextColor, fontSize: 12)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Row(
|
Row(
|
||||||
children: const [
|
children: [
|
||||||
Icon(Icons.check_circle, color: kPrimaryGreen, size: 16),
|
const Icon(Icons.check_circle, color: _mainBlueColor, size: 16),
|
||||||
SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text('Available: Door Fully Closed', style: TextStyle(color: Colors.white70)),
|
const Text('Available: Door Fully Closed',
|
||||||
|
style: TextStyle(color: _mainTextColor)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 24.0, top: 4),
|
padding: const EdgeInsets.only(left: 24.0, top: 4),
|
||||||
child: Text('(2025-11-19)/(08:58)', style: TextStyle(color: Colors.grey[600], fontSize: 12)),
|
child: Text('(2025-11-19)/(08:58)',
|
||||||
|
style: TextStyle(color: _subTextColor, fontSize: 12)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -289,31 +337,43 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
builder: (context) {
|
builder: (context) {
|
||||||
return Container(
|
return Container(
|
||||||
height: MediaQuery.of(context).size.height * 0.6,
|
height: MediaQuery.of(context).size.height * 0.6,
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Color(0xFF1E1E1E),
|
color: _cardBackgroundColor,
|
||||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Container(
|
Container(
|
||||||
width: 40, height: 4,
|
width: 40,
|
||||||
decoration: BoxDecoration(color: Colors.grey[600], borderRadius: BorderRadius.circular(2)),
|
height: 4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _subTextColor,
|
||||||
|
borderRadius: BorderRadius.circular(2)),
|
||||||
),
|
),
|
||||||
const Padding(
|
const Padding(
|
||||||
padding: EdgeInsets.all(20.0),
|
padding: EdgeInsets.all(20.0),
|
||||||
child: Text("DEVICE LOGS", style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)),
|
child: Text("DEVICE LOGS",
|
||||||
|
style: TextStyle(
|
||||||
|
color: _mainTextColor,
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold)),
|
||||||
),
|
),
|
||||||
const Divider(color: Colors.white24, height: 1),
|
Divider(color: _subTextColor.withOpacity(0.5), height: 1),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
children: [
|
children: [
|
||||||
_buildLogItem("08:58:33", "Door Fully Closed", Icons.door_front_door, Colors.green),
|
_buildLogItem("08:58:33", "Door Fully Closed",
|
||||||
_buildLogItem("08:58:30", "Helmet Returned (Sensor A)", Icons.check_circle_outline, Colors.blue),
|
Icons.door_front_door, _mainBlueColor),
|
||||||
_buildLogItem("08:55:12", "User Unlocked Door", Icons.lock_open, Colors.white),
|
_buildLogItem("08:58:30", "Helmet Returned (Sensor A)",
|
||||||
_buildLogItem("08:30:00", "UV Sanitization Complete", Icons.cleaning_services, Colors.purpleAccent),
|
Icons.check_circle_outline, _mainBlueColor),
|
||||||
_buildLogItem("08:00:00", "System Boot Up", Icons.power_settings_new, Colors.grey),
|
_buildLogItem("08:55:12", "User Unlocked Door",
|
||||||
|
Icons.lock_open, _mainTextColor),
|
||||||
|
_buildLogItem("08:30:00", "UV Sanitization Complete",
|
||||||
|
Icons.cleaning_services, _mainBlueColor),
|
||||||
|
_buildLogItem("08:00:00", "System Boot Up",
|
||||||
|
Icons.power_settings_new, _subTextColor),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -324,23 +384,27 @@ class RentalProcessScreen extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLogItem(String time, String message, IconData icon, Color color) {
|
Widget _buildLogItem(
|
||||||
|
String time, String message, IconData icon, Color color) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 20.0),
|
padding: const EdgeInsets.only(bottom: 20.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(time, style: const TextStyle(color: Colors.grey, fontSize: 12)),
|
Text(time,
|
||||||
|
style: const TextStyle(color: _subTextColor, fontSize: 12)),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Icon(icon, color: color, size: 20),
|
Icon(icon, color: color, size: 20),
|
||||||
Container(width: 2, height: 20, color: Colors.white12),
|
Container(
|
||||||
|
width: 2, height: 20, color: _subTextColor.withOpacity(0.5)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(message, style: const TextStyle(color: Colors.white70, fontSize: 14)),
|
child: Text(message,
|
||||||
|
style: const TextStyle(color: _mainTextColor, fontSize: 14)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,14 +1,268 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class SettingsScreen extends StatelessWidget {
|
final Color _mainBlueColor = const Color(0xFF002FA7);
|
||||||
|
final Color _mainTextColor = const Color(0xFF1C1C1E);
|
||||||
|
final Color _subTextColor = const Color(0xFF6A717B);
|
||||||
|
final Color _pageBackgroundColor = const Color(0xFFF5F7F9);
|
||||||
|
final Color _cardBackgroundColor = Colors.white;
|
||||||
|
final Color _accentContainerColor = const Color(0xFFF0F2F5);
|
||||||
|
final Color _warningColor = Colors.redAccent;
|
||||||
|
|
||||||
|
const BoxShadow _cleanShadow = BoxShadow(
|
||||||
|
color: Color.fromRGBO(0, 0, 0, 0.07),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
spreadRadius: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsScreen extends StatefulWidget {
|
||||||
const SettingsScreen({super.key});
|
const SettingsScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SettingsScreen> createState() => _SettingsScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SettingsScreenState extends State<SettingsScreen> {
|
||||||
|
|
||||||
|
bool _isPushEnabled = true;
|
||||||
|
bool _isRentalAlertEnabled = true;
|
||||||
|
bool _isStorageStatusAlert = true;
|
||||||
|
bool _isAutoSyncEnabled = false;
|
||||||
|
|
||||||
|
final String _currentAppVersion = "v1.0.0";
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Center(
|
return Scaffold(
|
||||||
|
backgroundColor: _pageBackgroundColor,
|
||||||
|
appBar: AppBar(
|
||||||
|
scrolledUnderElevation: 0,
|
||||||
|
title: Text(
|
||||||
|
'설정',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 16,
|
||||||
|
color: _mainTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
backgroundColor: _pageBackgroundColor,
|
||||||
|
elevation: 0,
|
||||||
|
centerTitle: false,
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.more_vert, color: _mainTextColor),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildSectionTitle('계정 및 보안'),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildAccountSecurityCard(),
|
||||||
|
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
_buildSectionTitle('알림 설정'),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildNotificationCard(),
|
||||||
|
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
_buildSectionTitle('앱 정보'),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildAppInfoCard(),
|
||||||
|
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
_buildWithdrawalButton(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSectionTitle(String title) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'5. 설정 (Settings) 페이지',
|
title,
|
||||||
style: TextStyle(color: Colors.white70, fontSize: 20),
|
style: TextStyle(
|
||||||
|
color: _mainTextColor,
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCardWrapper({required Widget child}) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _cardBackgroundColor,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [_cleanShadow],
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildNotificationCard() {
|
||||||
|
return _buildCardWrapper(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildToggleItem(
|
||||||
|
'알림 전체 수신',
|
||||||
|
'모든 알림을 켜고 끕니다.',
|
||||||
|
_isPushEnabled,
|
||||||
|
(val) => setState(() => _isPushEnabled = val),
|
||||||
|
showDivider: true,
|
||||||
|
),
|
||||||
|
_buildToggleItem(
|
||||||
|
'대여/반납 알림',
|
||||||
|
'대여 시작/종료, 반납 실패 알림',
|
||||||
|
_isRentalAlertEnabled,
|
||||||
|
(val) => setState(() => _isRentalAlertEnabled = val),
|
||||||
|
showDivider: true,
|
||||||
|
),
|
||||||
|
_buildToggleItem(
|
||||||
|
'보관함 상태 알림',
|
||||||
|
'살균 완료, 시스템 오류 등 상태 알림',
|
||||||
|
_isStorageStatusAlert,
|
||||||
|
(val) => setState(() => _isStorageStatusAlert = val),
|
||||||
|
showDivider: true,
|
||||||
|
),
|
||||||
|
_buildInfoLink('알림 시간대 설정', Icons.schedule_outlined),
|
||||||
|
_buildDivider(16),
|
||||||
|
_buildInfoLink('글자 크기 조정', Icons.format_size),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildAccountSecurityCard() {
|
||||||
|
return _buildCardWrapper(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildInfoLink('내 정보 수정', Icons.person_outline),
|
||||||
|
_buildDivider(16),
|
||||||
|
_buildInfoLink('비밀번호 변경', Icons.lock_outline),
|
||||||
|
_buildDivider(16),
|
||||||
|
_buildInfoLink('캐시 데이터 삭제', Icons.cleaning_services_outlined),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildAppInfoCard() {
|
||||||
|
return _buildCardWrapper(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildInfoLink('버전 정보', null, value: _currentAppVersion),
|
||||||
|
_buildDivider(16),
|
||||||
|
_buildInfoLink('이용 약관 및 정책', Icons.gavel),
|
||||||
|
_buildDivider(16),
|
||||||
|
_buildInfoLink('고객센터 및 FAQ', Icons.headset_mic_outlined),
|
||||||
|
_buildDivider(16),
|
||||||
|
_buildInfoLink('위치 권한 설정', Icons.location_on_outlined),
|
||||||
|
_buildDivider(16),
|
||||||
|
_buildInfoLink('서비스 지역 지도 보기', Icons.map_outlined),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildToggleItem(String title, String subtitle, bool value, ValueChanged<bool> onChanged, {required bool showDivider}) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
color: _mainTextColor,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
subtitle,
|
||||||
|
style: TextStyle(
|
||||||
|
color: _subTextColor,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Switch(
|
||||||
|
value: value,
|
||||||
|
onChanged: onChanged,
|
||||||
|
activeColor: _mainBlueColor,
|
||||||
|
inactiveThumbColor: _accentContainerColor,
|
||||||
|
inactiveTrackColor: Colors.grey.shade400,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (showDivider)
|
||||||
|
_buildDivider(0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoLink(String title, IconData? icon, {String? value}) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () { /* Navigation logic */ },
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
if (icon != null) ...[
|
||||||
|
Icon(icon, color: _mainTextColor, size: 20),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
],
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(color: _mainTextColor, fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (value != null)
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
style: TextStyle(color: _subTextColor, fontSize: 14),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Icon(Icons.arrow_forward_ios, color: _subTextColor, size: 16),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDivider(double indent) {
|
||||||
|
return Divider(color: _subTextColor.withOpacity(0.4), height: 1, thickness: 0.5, indent: indent, endIndent: 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildWithdrawalButton() {
|
||||||
|
return Center(
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () {},
|
||||||
|
child: Text(
|
||||||
|
'회원 탈퇴 신청',
|
||||||
|
style: TextStyle(color: _warningColor, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
final Color _mainBlueColor = const Color(0xFF0033CC);
|
||||||
|
final Color _mainTextColor = const Color(0xFF1C1C1E);
|
||||||
|
final Color _subTextColor = const Color(0xFF6A717B);
|
||||||
|
final Color _pageBackgroundColor = const Color(0xFFF5F7F9);
|
||||||
|
final Color _cardBackgroundColor = const Color(0xFFF0F2F5);
|
||||||
class CustomHeader extends StatelessWidget {
|
class CustomHeader extends StatelessWidget {
|
||||||
const CustomHeader({super.key});
|
const CustomHeader({super.key});
|
||||||
|
|
||||||
@@ -8,24 +13,42 @@ class CustomHeader extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
height: 60.0,
|
height: 50.0,
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color.fromRGBO(0, 0, 0, 0.07),
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
blurRadius: 6,
|
||||||
|
spreadRadius: 0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: _uniformGap),
|
padding: const EdgeInsets.symmetric(horizontal: _uniformGap),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Row(children: [
|
Row(children: [
|
||||||
Icon(Icons.settings_input_component, color: Colors.grey[400]),
|
Icon(Icons.settings_input_component, color: Colors.black),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 10),
|
||||||
const Text('SMART HELMET SYSTEMS',
|
Text(
|
||||||
|
'스마트 헬멧',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.w500,
|
||||||
color: Colors.white))
|
color: _mainTextColor,
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
),
|
||||||
|
)
|
||||||
]),
|
]),
|
||||||
Text('2025/09/26 - 10:44 AM',
|
Text(
|
||||||
style: TextStyle(color: Colors.grey[400], fontSize: 11))
|
'2025/09/26 - 10:44 AM',
|
||||||
]));
|
style: TextStyle(color: _subTextColor, fontSize: 11),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user