diff --git a/assets/images/info1.png b/assets/images/info1.png new file mode 100644 index 0000000..5063eba Binary files /dev/null and b/assets/images/info1.png differ diff --git a/assets/images/info2.png b/assets/images/info2.png new file mode 100644 index 0000000..10f4435 Binary files /dev/null and b/assets/images/info2.png differ diff --git a/lib/rental_process_screen.dart b/lib/rental_process_screen.dart index 982205b..18ac8ee 100644 --- a/lib/rental_process_screen.dart +++ b/lib/rental_process_screen.dart @@ -1,8 +1,9 @@ +import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; -class RentalProcessScreen extends StatelessWidget { +class RentalProcessScreen extends StatefulWidget { final String stationName; const RentalProcessScreen({ @@ -10,6 +11,11 @@ class RentalProcessScreen extends StatelessWidget { required this.stationName, }); + @override + State createState() => _RentalProcessScreenState(); +} + +class _RentalProcessScreenState extends State { static const Color _mainBlueColor = Color(0xFF002FA7); static const Color _mainTextColor = Color(0xFF1C1C1E); static const Color _subTextColor = Color(0xFF6A717B); @@ -20,6 +26,46 @@ class RentalProcessScreen extends StatelessWidget { static const Color _primaryGreen = Color(0xFF4CAF50); static const Color _primaryOrange = Color(0xFFFF3D00); + final PageController _pageController = PageController(); + int _currentPage = 0; + Timer? _timer; + final List _imageList = [ + 'assets/images/top.png', + 'assets/images/info1.png', + 'assets/images/info2.png', + ]; + + @override + void initState() { + super.initState(); + _startAutoScroll(); + } + + @override + void dispose() { + _timer?.cancel(); + _pageController.dispose(); + super.dispose(); + } + + void _startAutoScroll() { + _timer = Timer.periodic(const Duration(seconds: 3), (Timer timer) { + if (_currentPage < _imageList.length - 1) { + _currentPage++; + } else { + _currentPage = 0; + } + + if (_pageController.hasClients) { + _pageController.animateToPage( + _currentPage, + duration: const Duration(milliseconds: 350), + curve: Curves.easeIn, + ); + } + }); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -27,7 +73,7 @@ class RentalProcessScreen extends StatelessWidget { appBar: AppBar( scrolledUnderElevation: 0, title: Text( - stationName, + widget.stationName, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, @@ -123,18 +169,63 @@ class RentalProcessScreen extends StatelessWidget { Container( width: 150, height: 150, - padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: _accentContainerColor, borderRadius: BorderRadius.circular(12), ), - child: Image.asset( - 'assets/images/top.png', - fit: BoxFit.contain, - errorBuilder: (context, error, stackTrace) => const Icon( - Icons.inventory_2, - size: 50, - color: _subTextColor), + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + PageView.builder( + controller: _pageController, + itemCount: _imageList.length, + onPageChanged: (int index) { + setState(() { + _currentPage = index; + }); + }, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 25), + child: Image.asset( + _imageList[index], + fit: BoxFit.contain, + errorBuilder: (context, error, stackTrace) => + const Icon(Icons.inventory_2, + size: 50, color: _subTextColor), + ), + ); + }, + ), + Positioned( + bottom: 10, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate(_imageList.length, (index) { + return GestureDetector( + onTap: () { + _pageController.animateToPage( + index, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }, + child: Container( + width: 30, + height: 6, + margin: const EdgeInsets.symmetric(horizontal: 2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(3), + color: _currentPage == index + ? _mainTextColor + : Colors.grey.shade300, + ), + ), + ); + }), + ), + ), + ], ), ), const SizedBox(width: 20), @@ -210,7 +301,7 @@ class RentalProcessScreen extends StatelessWidget { Widget _buildStepRow(int step, String title, IconData icon, {bool isCompleted = false, bool showDivider = true}) { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 18), child: Row( children: [ Column( @@ -220,7 +311,9 @@ class RentalProcessScreen extends StatelessWidget { children: [ Text('STEP $step', style: const TextStyle( - color: _mainTextColor, fontWeight: FontWeight.bold)), + color: _mainBlueColor, + fontSize: 12, + fontWeight: FontWeight.w700)), if (isCompleted) ...[ const SizedBox(width: 8), const Icon(Icons.check_circle, @@ -228,15 +321,19 @@ class RentalProcessScreen extends StatelessWidget { ], ], ), - const SizedBox(height: 4), + const SizedBox(height: 6), Text(title, style: const TextStyle( - color: _mainTextColor, fontSize: 18, letterSpacing: 0.6)), + color: _mainTextColor, + fontSize: 16, + fontWeight: FontWeight.w600, + height: 1.2)), ], ), const Spacer(), Icon(icon, - color: isCompleted ? _mainBlueColor : _subTextColor, size: 48), + color: isCompleted ? _mainBlueColor : _subTextColor.withOpacity(0.5), + size: 32), ], ), ); @@ -244,7 +341,7 @@ class RentalProcessScreen extends StatelessWidget { Widget _buildDivider() { return Divider( - color: _subTextColor.withOpacity(0.5), + color: _subTextColor.withOpacity(0.1), height: 1, thickness: 1, indent: 20, @@ -295,22 +392,21 @@ class RentalProcessScreen extends StatelessWidget { color: _mainTextColor, fontWeight: FontWeight.bold)), InkWell( onTap: () => _showLogHistory(context), - child: Text('더보기 >', + child: const Text('더보기 >', style: TextStyle(color: _subTextColor, fontSize: 12)), ), ], ), const SizedBox(height: 12), Row( - children: [ - const Icon(Icons.check_circle, color: _mainBlueColor, size: 16), - const SizedBox(width: 8), - const Text('Available: 문 닫힘', - style: TextStyle(color: _mainTextColor)), + children: const [ + Icon(Icons.check_circle, color: _mainBlueColor, size: 16), + SizedBox(width: 8), + Text('Available: 문 닫힘', style: TextStyle(color: _mainTextColor)), ], ), - Padding( - padding: const EdgeInsets.only(left: 210, top: 4), + const Padding( + padding: EdgeInsets.only(left: 210, top: 4), child: Text('(2025-11-19)/(08:58)', style: TextStyle(color: _subTextColor, fontSize: 12)), ), @@ -327,9 +423,9 @@ class RentalProcessScreen extends StatelessWidget { builder: (context) { return Container( height: MediaQuery.of(context).size.height * 0.6, - decoration: BoxDecoration( + decoration: const BoxDecoration( color: _cardBackgroundColor, - borderRadius: const BorderRadius.vertical(top: Radius.circular(20)), + borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), child: Column( children: [ @@ -354,12 +450,12 @@ class RentalProcessScreen extends StatelessWidget { child: ListView( padding: const EdgeInsets.all(20), children: [ - _buildLogItem("08:58:33", "문 열림", - Icons.door_front_door, _mainBlueColor), + _buildLogItem("08:58:33", "문 열림", Icons.door_front_door, + _mainBlueColor), _buildLogItem("08:58:30", "헬멧 반납 확인(센서 A)", Icons.check_circle_outline, _mainBlueColor), - _buildLogItem("08:55:12", "사용자 문 잠금 해제", - Icons.lock_open, _mainTextColor), + _buildLogItem("08:55:12", "사용자 문 잠금 해제", Icons.lock_open, + _mainTextColor), _buildLogItem("08:30:00", "UV 살균 완료", Icons.cleaning_services, _mainBlueColor), _buildLogItem("08:00:00", "시스템 가동 중",