diff --git a/front/lib/bus_arrival_page.dart b/front/lib/bus_arrival_page.dart index a470c25..c614f89 100644 --- a/front/lib/bus_arrival_page.dart +++ b/front/lib/bus_arrival_page.dart @@ -1,3 +1,4 @@ +//버스 도착 정보 페이지 import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; @@ -250,7 +251,7 @@ class _BusArrivalPageState extends State { fontWeight: FontWeight.bold, ), ), - const TextSpan(text: '째 정류장\n'), + const TextSpan(text: '번째 정류장\n'), const TextSpan( text: '사색의광장', ), diff --git a/front/lib/bus_company.dart b/front/lib/bus_company.dart index 8d18e24..9b90704 100644 --- a/front/lib/bus_company.dart +++ b/front/lib/bus_company.dart @@ -1,3 +1,4 @@ +//버스 회사 데이터 const Map companyData = {"1": { "name":"용남고속", diff --git a/front/lib/bus_history_page.dart b/front/lib/bus_history_page.dart index c61144d..8092ae3 100644 --- a/front/lib/bus_history_page.dart +++ b/front/lib/bus_history_page.dart @@ -1,3 +1,4 @@ +//과거 버스 도착 정보(버스별) 페이지 import 'package:flutter/material.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; diff --git a/front/lib/bus_info.dart b/front/lib/bus_info.dart index 6b2f25f..a8d975f 100644 --- a/front/lib/bus_info.dart +++ b/front/lib/bus_info.dart @@ -1,3 +1,4 @@ +//버스 노선 데이터 const Map busRouteMap={ "9": "200000103", "1112": "234000016", diff --git a/front/lib/bus_screen.dart b/front/lib/bus_screen.dart index 4d282d7..e4705b6 100644 --- a/front/lib/bus_screen.dart +++ b/front/lib/bus_screen.dart @@ -1,6 +1,5 @@ +//버스 노선 페이지 import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; import 'bus_timetable_page.dart'; import 'bus_arrival_page.dart'; class BusScreen extends StatelessWidget { diff --git a/front/lib/bus_timetable_page.dart b/front/lib/bus_timetable_page.dart index 3c73fa1..46fe45e 100644 --- a/front/lib/bus_timetable_page.dart +++ b/front/lib/bus_timetable_page.dart @@ -1,3 +1,4 @@ +//버스 시간표 페이지 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/front/lib/company_info_page.dart b/front/lib/company_info_page.dart new file mode 100644 index 0000000..443dbf7 --- /dev/null +++ b/front/lib/company_info_page.dart @@ -0,0 +1,109 @@ +//회사 정보 페이지 +import 'package:flutter/material.dart'; +import 'bus_company.dart'; + + +class CompanyInfoPage extends StatelessWidget { + final String companyId; + + const CompanyInfoPage({super.key, required this.companyId}); + + @override + Widget build(BuildContext context) { + final company = companyData[companyId]; + + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.pop(context), + ), + title: Text('${company['name']}'), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '회사 정보', + style: TextStyle( + fontSize: 16, + color: Colors.grey, + ), + ), + const SizedBox(height: 16), + _buildInfoCard(company), + ], + ), + ), + ); + } + + Widget _buildInfoCard(Map company) { + return Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + _buildInfoItem( + icon: Icons.link, + title: '웹사이트 주소', + content: company['url'] ?? 'none', + ), + _buildDivider(), + _buildInfoItem( + icon: Icons.phone, + title: '전화번호', + content: _formatPhones(company['phones']), + ), + if (company['address'] != null) ...[ + _buildDivider(), + _buildInfoItem( + icon: Icons.home, + title: '주소', + content: company['address'], + ), + ], + ], + ), + ); + } + + Widget _buildInfoItem({ + required IconData icon, + required String title, + required String content, + }) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(icon, size: 24, color: Colors.black54), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(content), + ], + ), + ), + ], + ), + ); + } + + Widget _buildDivider() { + return const Divider(height: 1, thickness: 1); + } + + String _formatPhones(Map phones) { + return phones.entries + .map((e) => '${e.key}: ${e.value}') + .join('\n'); + } +} \ No newline at end of file diff --git a/front/lib/compliant_service_screen.dart b/front/lib/compliant_service_screen.dart new file mode 100644 index 0000000..317b68a --- /dev/null +++ b/front/lib/compliant_service_screen.dart @@ -0,0 +1,329 @@ +//민원 도우미 서비스 페이지 +import 'package:flutter/material.dart'; +import 'company_info_page.dart'; +import 'passed_bus_page.dart'; + +class ComplaintServiceScreen extends StatelessWidget { + const ComplaintServiceScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + // 뒤로가기 동작 + }, + ), + title: const Text('민원 도우미 서비스'), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + _buildBusInfoCard( + companyName: "용남고속", + routes: "9 | 5100 | 7000", + stopInfo: "교내 정류장 존재", + phone: "031-273-8335", + context: context, + ), + const SizedBox(height: 10), + _buildBusInfoCard( + companyName: "대원고속", + routes: "1112 | 1560(A,B)", + stopInfo: "1112: 교내 정류장 존재\n1560: 교내 정류장 없음", + phone: "031-204-6657", + context: context, + ), + const SizedBox(height: 10), + _buildBusInfoCard( + companyName: "경기고속", + routes: "M5107", + stopInfo: "교내 정류장 없음", + phone: "031-206-1570", + context: context, + ), + const SizedBox(height: 10), + _buildGeneralInfoCard( + title: "경기도 버스 민원", + phone1: "031-120", + phone2: "031-246-4211", + button1Text: "경기도청-버스불편신고", + button2Text: "경기도버스운송조합", + context: context, + ), + const SizedBox(height: 10), + _buildGeneralInfoCard( + title: "경희대학교", + phone1: "031-201-2004", + phone2: "031-201-3051~4", + button1Text: "경희옴부즈민원", + button2Text: "학생지원센터", + context: context, + ), + ], + ), + ), + ), + ); + } + + Widget _buildBusInfoCard({ + required String companyName, + required String routes, + required String stopInfo, + required String phone, + required BuildContext context, + }) { + String getCompanyId() { + switch (companyName) { + case "용남고속": + return "1"; + case "대원고속": + return "2"; + case "경기고속": + return "3"; + default: + return "1"; + } + } + return Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0), + side: const BorderSide(color: Colors.lightBlue, width: 2), // 하늘색 테두리 + ), + elevation: 4, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + companyName, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 10), + const Icon(Icons.directions_bus, size: 18), + const Spacer(), + Row( + children: [ + const Icon(Icons.phone, size: 16, color: Colors.black), + const SizedBox(width: 5), + Text( + phone, + style: const TextStyle(fontSize: 14, color: Colors.black), + ), + ], + ), + ], + ), + const SizedBox(height: 10), + Text( + routes, + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 10), + Row( + children: [ + const Icon(Icons.location_on, size: 16), + const SizedBox(width: 5), + Expanded( + child: Text( + stopInfo, + style: const TextStyle(fontSize: 14), + ), + ), + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + OutlinedButton( + style: OutlinedButton.styleFrom( + foregroundColor: Colors.lightBlue, + side: const BorderSide(color: Colors.lightBlue), + ), + onPressed: () { + // 회사 정보 보기 버튼 동작 + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CompanyInfoPage( + companyId: getCompanyId(), + ), + ), + ); + }, + child: const Text('회사 정보 보기'), + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, // 버튼 배경색 + foregroundColor: Colors.white, // 버튼 텍스트 색상 + ), + onPressed: () { + // 방금 지나간 버스 버튼 동작 + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PassedBusPage( + companyId: getCompanyId(), // 회사 ID 전달 + ), + ), + ); + }, + child: const Text('방금 지나간 버스'), + ), + ], + ), + ], + ), + ), + ); + } + + Widget _buildGeneralInfoCard({ + required String title, + required String phone1, + required String phone2, + required String button1Text, + required String button2Text, + required BuildContext context, + }) { + String getCompanyId(String buttonText) { + switch (buttonText) { + case "경기도청-버스불편신고": + return "4"; + case "경기도버스운송조합": + return "5"; + case "경희옴부즈민원": + return "6"; + case "학생지원센터": + return "7"; + default: + return "4"; + } + } + return Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0), + side: const BorderSide(color: Colors.lightBlue, width: 2), + ), + elevation: 4, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 10), + Row( + children: [ + Expanded( + child: Row( + children: [ + const Icon(Icons.phone, size: 16), + const SizedBox(width: 5), + Flexible( + child: Text( + phone1, + style: const TextStyle(fontSize: 14), + ), + ), + ], + ), + ), + const SizedBox(width: 10), + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + const Icon(Icons.phone, size: 16), + const SizedBox(width: 5), + Flexible( + child: Text( + phone2, + style: const TextStyle(fontSize: 14), + ), + ), + ], + ), + ), + ], + ), + const SizedBox(height: 10), + Row( + children: [ + Expanded( + child: OutlinedButton( + style: OutlinedButton.styleFrom( + foregroundColor: Colors.lightBlue, + side: const BorderSide(color: Colors.lightBlue), + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CompanyInfoPage( + companyId: getCompanyId(button1Text), + ), + ), + ); + }, + child: Text( + button1Text, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 12), + + ), + ), + ), + const SizedBox(width: 8), + Expanded( + child: OutlinedButton( + style: OutlinedButton.styleFrom( + foregroundColor: Colors.lightBlue, + side: const BorderSide(color: Colors.lightBlue), + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CompanyInfoPage( + companyId: getCompanyId(button2Text), + ), + ), + ); + }, + child: Text( + button2Text, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 12), + ), + ), + ), + ], + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/front/lib/main.dart b/front/lib/main.dart index 515031e..6c2f275 100644 --- a/front/lib/main.dart +++ b/front/lib/main.dart @@ -1,12 +1,11 @@ +//메인 페이지 import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; -import 'bus_company.dart'; -import "bus_info.dart"; -import "passed_bus_page.dart"; import "bus_screen.dart"; import "station_screen.dart"; import "map_screen.dart"; +import "compliant_service_screen.dart"; void main() { runApp(const MyApp()); } @@ -348,430 +347,3 @@ class UserInfoScreen extends StatelessWidget { ); } } - -class ComplaintServiceScreen extends StatelessWidget { - const ComplaintServiceScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () { - // 뒤로가기 동작 - }, - ), - title: const Text('민원 도우미 서비스'), - ), - body: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - _buildBusInfoCard( - companyName: "용남고속", - routes: "9 | 5100 | 7000", - stopInfo: "교내 정류장 존재", - phone: "031-273-8335", - context: context, - ), - const SizedBox(height: 10), - _buildBusInfoCard( - companyName: "대원고속", - routes: "1112 | 1560(A,B)", - stopInfo: "1112: 교내 정류장 존재\n1560: 교내 정류장 없음", - phone: "031-204-6657", - context: context, - ), - const SizedBox(height: 10), - _buildBusInfoCard( - companyName: "경기고속", - routes: "M5107", - stopInfo: "교내 정류장 없음", - phone: "031-206-1570", - context: context, - ), - const SizedBox(height: 10), - _buildGeneralInfoCard( - title: "경기도 버스 민원", - phone1: "031-120", - phone2: "031-246-4211", - button1Text: "경기도청-버스불편신고", - button2Text: "경기도버스운송조합", - context: context, - ), - const SizedBox(height: 10), - _buildGeneralInfoCard( - title: "경희대학교", - phone1: "031-201-2004", - phone2: "031-201-3051~4", - button1Text: "경희옴부즈민원", - button2Text: "학생지원센터", - context: context, - ), - ], - ), - ), - ), - ); - } - - Widget _buildBusInfoCard({ - required String companyName, - required String routes, - required String stopInfo, - required String phone, - required BuildContext context, - }) { - String getCompanyId() { - switch (companyName) { - case "용남고속": - return "1"; - case "대원고속": - return "2"; - case "경기고속": - return "3"; - default: - return "1"; - } - } - return Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0), - side: const BorderSide(color: Colors.lightBlue, width: 2), // 하늘색 테두리 - ), - elevation: 4, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - companyName, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(width: 10), - const Icon(Icons.directions_bus, size: 18), - const Spacer(), - Row( - children: [ - const Icon(Icons.phone, size: 16, color: Colors.black), - const SizedBox(width: 5), - Text( - phone, - style: const TextStyle(fontSize: 14, color: Colors.black), - ), - ], - ), - ], - ), - const SizedBox(height: 10), - Text( - routes, - style: const TextStyle(fontSize: 16), - ), - const SizedBox(height: 10), - Row( - children: [ - const Icon(Icons.location_on, size: 16), - const SizedBox(width: 5), - Expanded( - child: Text( - stopInfo, - style: const TextStyle(fontSize: 14), - ), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - OutlinedButton( - style: OutlinedButton.styleFrom( - foregroundColor: Colors.lightBlue, - side: const BorderSide(color: Colors.lightBlue), - ), - onPressed: () { - // 회사 정보 보기 버튼 동작 - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CompanyInfoPage( - companyId: getCompanyId(), - ), - ), - ); - }, - child: const Text('회사 정보 보기'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.blue, // 버튼 배경색 - foregroundColor: Colors.white, // 버튼 텍스트 색상 - ), - onPressed: () { - // 방금 지나간 버스 버튼 동작 - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const PassedBusPage(), - ), - ); - }, - child: const Text('방금 지나간 버스'), - ), - ], - ), - ], - ), - ), - ); - } - - Widget _buildGeneralInfoCard({ - required String title, - required String phone1, - required String phone2, - required String button1Text, - required String button2Text, - required BuildContext context, - }) { - String getCompanyId(String buttonText) { - switch (buttonText) { - case "경기도청-버스불편신고": - return "4"; - case "경기도버스운송조합": - return "5"; - case "경희옴부즈민원": - return "6"; - case "학생지원센터": - return "7"; - default: - return "4"; - } - } - return Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0), - side: const BorderSide(color: Colors.lightBlue, width: 2), - ), - elevation: 4, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 10), - Row( - children: [ - Expanded( - child: Row( - children: [ - const Icon(Icons.phone, size: 16), - const SizedBox(width: 5), - Flexible( - child: Text( - phone1, - style: const TextStyle(fontSize: 14), - ), - ), - ], - ), - ), - const SizedBox(width: 10), - Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - const Icon(Icons.phone, size: 16), - const SizedBox(width: 5), - Flexible( - child: Text( - phone2, - style: const TextStyle(fontSize: 14), - ), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 10), - Row( - children: [ - Expanded( - child: OutlinedButton( - style: OutlinedButton.styleFrom( - foregroundColor: Colors.lightBlue, - side: const BorderSide(color: Colors.lightBlue), - ), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CompanyInfoPage( - companyId: getCompanyId(button1Text), - ), - ), - ); - }, - child: Text( - button1Text, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 12), - - ), - ), - ), - const SizedBox(width: 8), - Expanded( - child: OutlinedButton( - style: OutlinedButton.styleFrom( - foregroundColor: Colors.lightBlue, - side: const BorderSide(color: Colors.lightBlue), - ), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CompanyInfoPage( - companyId: getCompanyId(button2Text), - ), - ), - ); - }, - child: Text( - button2Text, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 12), - ), - ), - ), - ], - ), - ], - ), - ), - ); - } -} -class CompanyInfoPage extends StatelessWidget { - final String companyId; - - const CompanyInfoPage({super.key, required this.companyId}); - - @override - Widget build(BuildContext context) { - final company = companyData[companyId]; - - return Scaffold( - appBar: AppBar( - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => Navigator.pop(context), - ), - title: Text('${company['name']}'), - ), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '회사 정보', - style: TextStyle( - fontSize: 16, - color: Colors.grey, - ), - ), - const SizedBox(height: 16), - _buildInfoCard(company), - ], - ), - ), - ); - } - - Widget _buildInfoCard(Map company) { - return Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - children: [ - _buildInfoItem( - icon: Icons.link, - title: '웹사이트 주소', - content: company['url'] ?? 'none', - ), - _buildDivider(), - _buildInfoItem( - icon: Icons.phone, - title: '전화번호', - content: _formatPhones(company['phones']), - ), - if (company['address'] != null) ...[ - _buildDivider(), - _buildInfoItem( - icon: Icons.home, - title: '주소', - content: company['address'], - ), - ], - ], - ), - ); - } - - Widget _buildInfoItem({ - required IconData icon, - required String title, - required String content, - }) { - return Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(icon, size: 24, color: Colors.black54), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(content), - ], - ), - ), - ], - ), - ); - } - - Widget _buildDivider() { - return const Divider(height: 1, thickness: 1); - } - - String _formatPhones(Map phones) { - return phones.entries - .map((e) => '${e.key}: ${e.value}') - .join('\n'); - } -} \ No newline at end of file diff --git a/front/lib/map_screen.dart b/front/lib/map_screen.dart index 49ca194..6f61e6e 100644 --- a/front/lib/map_screen.dart +++ b/front/lib/map_screen.dart @@ -1,6 +1,7 @@ +//캠퍼스 지도 페이지 import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:flutter/material.dart'; -import 'station_screen.dart'; // StationScreen import 필요 +import 'station_bus_info_page.dart'; class MapScreen extends StatefulWidget { const MapScreen({super.key}); @@ -21,6 +22,17 @@ class _MapScreenState extends State { "생명과학대(사색행)": const LatLng(37.2430333, 127.0806167), "사색의광장(사색행)": const LatLng(37.2403667, 127.0820833), }; + final Map stationIdMap = { + "사색의광장(정문행)": "228001174", + "생명과학대.산업대학(정문행)": "228000704", + "경희대체육대학.외대(정문행)": "228000703", + "경희대학교(정문행)": "203000125", + "경희대정문(사색행)": "228000723", + "외국어대학(사색행)": "228000710", + "생명과학대(사색행)": "228000709", + "사색의광장(사색행)": "228000708" + }; + // 마커들을 저장할 Set Set _markers = {}; @@ -40,7 +52,7 @@ class _MapScreenState extends State { icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue), infoWindow: InfoWindow( title: station.key, - snippet: '클릭하여 정류장 정보 보기', + snippet: '클릭하여 버스 도착 정보 보기', ), onTap: () => _onMarkerTapped(station.key), ); @@ -49,12 +61,27 @@ class _MapScreenState extends State { } void _onMarkerTapped(String stationName) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StationScreen(stationName: stationName), - ), - ); + // 정류장 ID 가져오기 + String? stationId = stationIdMap[stationName]; + + if (stationId != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StationBusInfoPage( + stationId: stationId, + stationName: stationName, + ), + ), + ); + } else { + // 정류장 ID를 찾을 수 없는 경우 에러 처리 + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('정류장 정보를 찾을 수 없습니다.'), + ), + ); + } } static const CameraPosition _kGooglePlex = CameraPosition( @@ -66,7 +93,7 @@ class _MapScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('캠퍼스 지도'), + title: const Text('경희대학교 지도'), ), body: GoogleMap( mapType: MapType.normal, diff --git a/front/lib/passed_bus_page.dart b/front/lib/passed_bus_page.dart index 2303d3a..8fe6e97 100644 --- a/front/lib/passed_bus_page.dart +++ b/front/lib/passed_bus_page.dart @@ -1,9 +1,13 @@ +//방금 지나간 버스 페이지 import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; +import 'dart:async'; class PassedBusPage extends StatefulWidget { - const PassedBusPage({super.key}); + final String? companyId; // nullable로 선언 (기본 화면에서는 null) + + const PassedBusPage({super.key, this.companyId}); @override State createState() => _PassedBusPageState(); @@ -11,13 +15,40 @@ class PassedBusPage extends StatefulWidget { class _PassedBusPageState extends State { String currentStationId = "228000723"; // 기본값: 사색방향 + final Map> companyRoutes = { + "1": ["9", "5100", "7000"], // 용남고속 + "2": ["1112", "1560A", "1560B"], // 대원고속 + "3": ["M5107"], // 경기고속 + }; List busData = []; bool isLoading = false; + Timer? _timer; + List getFilteredBusData() { + if (widget.companyId == null) { + return busData; // companyId가 없으면 모든 데이터 반환 + } + + final companyBusRoutes = companyRoutes[widget.companyId]; + if (companyBusRoutes == null) { + return busData; + } + return busData.where((bus) => + companyBusRoutes.contains(bus['routeName']) + ).toList(); + } @override void initState() { super.initState(); fetchBusData(); + _timer = Timer.periodic(const Duration(seconds: 30), (timer) { + fetchBusData(); + }); + } + @override + void dispose() { + _timer?.cancel(); // 페이지 dispose 시 타이머 취소 + super.dispose(); } Future fetchBusData() async { @@ -66,64 +97,161 @@ class _PassedBusPageState extends State { children: [ Padding( padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SegmentedButton( - segments: const [ - ButtonSegment( - value: "228000723", - label: Text("사색방향"), - ), - ButtonSegment( - value: "203000125", - label: Text("정문방향"), - ), - - ], - selected: {currentStationId}, - onSelectionChanged: (Set newSelection) { - setState(() { - currentStationId = newSelection.first; - }); - fetchBusData(); - }, - style: ButtonStyle( - side: WidgetStateProperty.all( - const BorderSide(color: Colors.blue), - ), - ), + const Text( + 'ⓘ 정문, 정건 정류장 기준 도착이 임박한 버스를', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.grey, + ), + ), + const Text( + ' 현재 시간으로부터 10분 전까지 조회가능합니다', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.grey, + ), ), - ], + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SegmentedButton( + segments: const [ + ButtonSegment( + value: "228000723", + label: Text("사색방향"), + ), + ButtonSegment( + value: "203000125", + label: Text("정문방향"), + ), + ], + selected: {currentStationId}, + onSelectionChanged: (Set newSelection) { + setState(() { + currentStationId = newSelection.first; + }); + fetchBusData(); + }, + style: ButtonStyle( + side: WidgetStateProperty.all( + const BorderSide(color: Colors.grey), + ), + ), + ), + Container( + decoration: BoxDecoration( + color: Colors.grey.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: IconButton( + icon: const Icon( + Icons.refresh, + size: 28, + ), + onPressed: isLoading ? null : () => fetchBusData(), + style: IconButton.styleFrom( + foregroundColor: Colors.grey, + padding: const EdgeInsets.all(8), + ), + ), + ), + ], + ), + ], ), ), Expanded( child: isLoading ? const Center(child: CircularProgressIndicator()) - : ListView.builder( - itemCount: busData.length, - itemBuilder: (context, index) { - final bus = busData[index]; - final expectedArrival = DateTime.parse(bus['expectedArrival']); - final formattedTime = '${expectedArrival.hour.toString().padLeft(2, '0')}:${expectedArrival.minute.toString().padLeft(2, '0')}'; - return Card( - margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), - child: ListTile( - leading: const Icon(Icons.directions_bus, color: Colors.blue), - title: Text( - bus['routeName'], - style: const TextStyle(fontWeight: FontWeight.bold), + : getFilteredBusData().isEmpty // busData 대신 getFilteredBusData() 사용 + ? Card( + margin: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide( + color: Colors.grey[800]!, + width: 2, ), - subtitle: Text( - '${bus['plateNo']}\n$formattedTime 도착 예정', + ), + child: const Padding( + padding: EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.info_outline, + color: Colors.grey, + size: 24, + ), + SizedBox(width: 12), + Text( + '최근 지나간 버스가 없습니다', + style: TextStyle( + fontSize: 18, + color: Colors.grey, + fontWeight: FontWeight.bold, + ), + ), + ], ), ), - ); - }, - ), + ) + : ListView.builder( + itemCount: getFilteredBusData().length, + itemBuilder: (context, index) { + final bus = getFilteredBusData()[index]; + final expectedArrival = DateTime.parse(bus['expectedArrival']); + final formattedTime = + '${expectedArrival.hour.toString().padLeft(2, '0')}:${expectedArrival.minute.toString().padLeft(2, '0')}'; + return Card( + margin: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 8.0), + child: ListTile( + leading: Icon(Icons.directions_bus, + color: getBusColor(bus['routeName'])), + title: Text( + bus['routeName'], + style: TextStyle(fontWeight: FontWeight.bold,color: getBusColor(bus['routeName'])), + ), + subtitle: Text( + '${bus['plateNo']}\n$formattedTime 도착 예정', + ), + ), + ); + }, + ), ), ], ), ); } +} +Color getBusColor(String routeNumber) { + switch (routeNumber) { + case "9": + return const Color(0xff33CC99); // 지선버스 + case "1112": + return const Color(0xffE60012); // 지선버스 + case "5100": + return const Color(0xffE60012); // 광역버스 + case "7000": + return const Color(0xffE60012); // 광역버스 + case "M5107": + return const Color(0xff006896); // M버스 + case "1560A": + return const Color(0xffE60012); // 지선버스 + case "1560B": + return const Color(0xffE60012); // 지선버스 + default: + return Colors.black; + } } \ No newline at end of file diff --git a/front/lib/station_bus_info_page.dart b/front/lib/station_bus_info_page.dart index 34e2fe3..ab3097f 100644 --- a/front/lib/station_bus_info_page.dart +++ b/front/lib/station_bus_info_page.dart @@ -1,3 +1,4 @@ +//정류장 버스 도착 정보 페이지 import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; @@ -143,7 +144,7 @@ class _StationBusInfoPageState extends State { ), onPressed: isLoading ? null : () => fetchBusData(), style: IconButton.styleFrom( - foregroundColor: Colors.blue, + foregroundColor: Colors.grey, padding: const EdgeInsets.all(8), ), ), @@ -159,7 +160,15 @@ class _StationBusInfoPageState extends State { ), ), const Text( - 'ⓘ M5107과 1560은 교내 버스 이동 시간을 고려하여 보정된 버스 도착 정보를 제공합니다.', + 'ⓘ M5107과 1560은 교내 버스 이동 시간을 고려하여', + style: TextStyle( + color: Colors.grey, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + const Text( + ' 보정된 버스 도착 정보를 제공합니다.', style: TextStyle( color: Colors.grey, fontSize: 12, diff --git a/front/lib/station_bus_list_page.dart b/front/lib/station_bus_list_page.dart index 8f7cbd0..a3009ec 100644 --- a/front/lib/station_bus_list_page.dart +++ b/front/lib/station_bus_list_page.dart @@ -1,5 +1,5 @@ +//과거 도착 정보(시간순) 페이지 import 'package:flutter/material.dart'; -import 'station_bus_info_page.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; import 'bus_history_page.dart'; diff --git a/front/lib/station_screen.dart b/front/lib/station_screen.dart index debda24..98a445c 100644 --- a/front/lib/station_screen.dart +++ b/front/lib/station_screen.dart @@ -1,3 +1,4 @@ +//정류장 페이지 import 'package:flutter/material.dart'; import 'station_bus_info_page.dart'; import 'bus_info.dart'; @@ -58,12 +59,19 @@ class _StationScreenState extends State { ), SizedBox(height: 4), Text( - 'ⓘ M5107과 1560은 교내 버스 이동 시간을 고려하여 보정된 버스 도착 정보를 제공합니다.', + 'ⓘ M5107과 1560은 교내 버스 이동 시간을 고려하여', style: TextStyle( color: Colors.grey, fontSize: 12, ), ), + Text( + ' 보정된 버스 도착 정보를 제공합니다.', + style: TextStyle( + color: Colors.grey, + fontSize: 12, + ), + ), ], ), ),