diff --git a/assets/icons/community.png b/assets/icons/community.png new file mode 100644 index 0000000..436ed63 Binary files /dev/null and b/assets/icons/community.png differ diff --git a/assets/icons/emergency.png b/assets/icons/emergency.png new file mode 100644 index 0000000..33e7ea7 Binary files /dev/null and b/assets/icons/emergency.png differ diff --git a/assets/icons/package.png b/assets/icons/package.png new file mode 100644 index 0000000..f926627 Binary files /dev/null and b/assets/icons/package.png differ diff --git a/assets/icons/payment.png b/assets/icons/payment.png new file mode 100644 index 0000000..576535b Binary files /dev/null and b/assets/icons/payment.png differ diff --git a/assets/icons/repair.png b/assets/icons/repair.png new file mode 100644 index 0000000..edf7d46 Binary files /dev/null and b/assets/icons/repair.png differ diff --git a/assets/icons/visitor.png b/assets/icons/visitor.png new file mode 100644 index 0000000..ff8638e Binary files /dev/null and b/assets/icons/visitor.png differ diff --git a/lib/activity.dart b/lib/activity.dart index 20aafa7..4af7ff4 100644 --- a/lib/activity.dart +++ b/lib/activity.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'activity_submit.dart'; +import 'activity_detail.dart'; class ActivityListPage extends StatefulWidget { const ActivityListPage({Key? key}) : super(key: key); @@ -94,7 +95,14 @@ class _ActivityListPageState extends State { children: [ TextButton( onPressed: () { - // TODO : 查看詳情 + Navigator.push( + context, + MaterialPageRoute( + builder: + (context) => + const ActivityDetailPage(activityId: 2), + ), + ); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, diff --git a/lib/activity_detail.dart b/lib/activity_detail.dart new file mode 100644 index 0000000..9168961 --- /dev/null +++ b/lib/activity_detail.dart @@ -0,0 +1,160 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; + +class ActivityDetailPage extends StatefulWidget { + final int activityId; + + const ActivityDetailPage({super.key, required this.activityId}); + + @override + State createState() => _ActivityDetailPageState(); +} + +class _ActivityDetailPageState extends State { + Map? activity; + bool isLoading = true; + + // 切換為 false 就會改為從 API 載入資料 + final bool useMockData = true; + + @override + void initState() { + super.initState(); + fetchActivityDetail(); + } + + Future fetchActivityDetail() async { + if (useMockData) { + //await Future.delayed(const Duration(seconds: 1)); // 模擬延遲 + setState(() { + activity = { + "title": "🎉 社區春季市集", + "time": "2025/04/27(日)10:00 - 16:00", + "location": "中庭花園", + "desc": "市集將有手作小物、美食攤販及親子遊戲活動,歡迎全體住戶參與!", + "image": "https://picsum.photos/id/1011/600/300", + "canRegister": true, + }; + isLoading = false; + }); + } else { + try { + final response = await http.get( + // API 位置 + Uri.parse('https://your-api.com/activities/${widget.activityId}'), + ); + if (response.statusCode == 200) { + setState(() { + activity = json.decode(response.body); + isLoading = false; + }); + } else { + throw Exception('Failed to load activity'); + } + } catch (e) { + setState(() { + isLoading = false; + activity = null; + }); + } + } + } + + void _showRegisterDialog() { + int peopleCount = 1; + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('確認報名'), + content: DropdownButtonFormField( + value: peopleCount, + items: + [1, 2, 3, 4] + .map((e) => DropdownMenuItem(value: e, child: Text('$e 人'))) + .toList(), + onChanged: (value) { + if (value != null) peopleCount = value; + }, + decoration: const InputDecoration(labelText: '選擇報名人數'), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('取消'), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(context); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + '已報名活動 ID ${widget.activityId},人數:$peopleCount', + ), + ), + ); + }, + child: const Text('確認報名'), + ), + ], + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('活動詳情')), + body: + isLoading + ? const Center(child: CircularProgressIndicator()) + : activity == null + ? const Center(child: Text('找不到該活動。')) + : SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Image.network( + activity!['image'], + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 16), + Text( + activity!['title'], + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + '時間:${activity!['time']}', + style: const TextStyle(color: Colors.grey), + ), + const SizedBox(height: 4), + Text( + '地點:${activity!['location']}', + style: const TextStyle(color: Colors.grey), + ), + const SizedBox(height: 12), + Text(activity!['desc']), + const SizedBox(height: 24), + if (activity!['canRegister'] == true) + Center( + child: ElevatedButton( + onPressed: _showRegisterDialog, + child: const Text('我要報名'), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/feedback.dart b/lib/feedback.dart index bf1d2f0..bebad14 100644 --- a/lib/feedback.dart +++ b/lib/feedback.dart @@ -50,7 +50,10 @@ class _FeedbackPageState extends State { .map( (value) => DropdownMenuItem( value: value, - child: Text(value), + child: Text( + value, + style: TextStyle(fontSize: 14), + ), ), ) .toList(), @@ -68,7 +71,10 @@ class _FeedbackPageState extends State { .map( (value) => DropdownMenuItem( value: value, - child: Text(value), + child: Text( + value, + style: TextStyle(fontSize: 14), + ), ), ) .toList(), @@ -84,6 +90,7 @@ class _FeedbackPageState extends State { border: OutlineInputBorder(), floatingLabelBehavior: FloatingLabelBehavior.always, ), + style: TextStyle(fontSize: 13), ), const SizedBox(height: 24), Row( diff --git a/lib/home_content_page.dart b/lib/home_content_page.dart index b20e18f..7479d6b 100644 --- a/lib/home_content_page.dart +++ b/lib/home_content_page.dart @@ -94,36 +94,6 @@ class HomeContentPage extends StatelessWidget { ), const SizedBox(width: 8), NotificationIcon(), - /*Stack( - children: [ - IconButton( - icon: const Icon(Icons.notifications), - onPressed: () { - // TODO: 跳轉到通知頁 - }, - ), - Positioned( - right: 8, - top: 8, - child: Container( - padding: const EdgeInsets.all(2), - decoration: BoxDecoration( - color: Colors.red, - borderRadius: BorderRadius.circular(10), - ), - constraints: const BoxConstraints( - minWidth: 16, - minHeight: 16, - ), - child: const Text( - '3', - style: TextStyle(color: Colors.white, fontSize: 10), - textAlign: TextAlign.center, - ), - ), - ), - ], - ),*/ ], ), ], @@ -219,7 +189,7 @@ class HomeContentPage extends StatelessWidget { childAspectRatio: 1, children: [ _buildQuickButton(context, '報修', 'assets/icons/repair.png'), - _buildQuickButton(context, '包裹', 'assets/icons/mail.png'), + _buildQuickButton(context, '包裹', 'assets/icons/package.png'), _buildQuickButton(context, '訪客', 'assets/icons/visitor.png'), _buildQuickButton(context, '繳費', 'assets/icons/payment.png'), _buildQuickButton(context, '社區互動', 'assets/icons/community.png'), diff --git a/lib/personal_page.dart b/lib/personal_page.dart index 60c71ea..665b6f7 100644 --- a/lib/personal_page.dart +++ b/lib/personal_page.dart @@ -21,30 +21,6 @@ class PersonalPage extends StatelessWidget { style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), ), centerTitle: true, - leading: IconButton( - icon: Image.asset('assets/icons/back.png', width: 24, height: 24), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - actions: [ - IconButton( - icon: Image.asset( - 'assets/icons/notification.png', - width: 24, - height: 24, - ), - onPressed: () { - // TODO: 通知按鈕事件 - }, - ), - IconButton( - icon: Image.asset('assets/icons/qr.png', width: 24, height: 24), - onPressed: () { - // TODO: QR碼按鈕事件 - }, - ), - ], ), body: ListView( padding: const EdgeInsets.all(16), @@ -139,19 +115,24 @@ class PersonalPage extends StatelessWidget { ), child: Stack( children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - Text('社區地址:新北市板橋區幸福路 88 號', style: TextStyle(fontSize: 14)), - SizedBox(height: 6), - Text('管理室電話:02-2233-4455', style: TextStyle(fontSize: 14)), - SizedBox(height: 6), - Text( - '管委會 Email:service@garden-community.tw', - style: TextStyle(fontSize: 14), - ), - ], + // 左邊社區資訊,右邊預留空間避免被按鈕擋住 + Padding( + padding: const EdgeInsets.only(right: 120), // 預留右上角空間 + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + Text('社區地址:新北市板橋區幸福路 88 號', style: TextStyle(fontSize: 12)), + SizedBox(height: 6), + Text('管理室電話:02-2233-4455', style: TextStyle(fontSize: 12)), + SizedBox(height: 6), + Text( + '管委會 Email:service@garden-community.tw', + style: TextStyle(fontSize: 12), + ), + ], + ), ), + // 右上角意見箱按鈕 Positioned( top: 0, right: 0, @@ -194,7 +175,7 @@ class PersonalPage extends StatelessWidget { mainAxisSpacing: 12, physics: const NeverScrollableScrollPhysics(), children: [ - _buildMenuItem('繳費通知', 'receipt.png', () { + _buildMenuItem('繳費通知', 'payment.png', () { showModalBottomSheet( context: context, isScrollControlled: true, diff --git a/pubspec.yaml b/pubspec.yaml index 1e9de26..e4a6f74 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,6 +54,7 @@ dev_dependencies: flutter: assets: - assets/images/ + - assets/icons/ # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class.