新增icon,新增活動詳情
This commit is contained in:
parent
30c2c953a1
commit
4eb4fb918b
BIN
assets/icons/community.png
Normal file
BIN
assets/icons/community.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 655 B |
BIN
assets/icons/emergency.png
Normal file
BIN
assets/icons/emergency.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 370 B |
BIN
assets/icons/package.png
Normal file
BIN
assets/icons/package.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 501 B |
BIN
assets/icons/payment.png
Normal file
BIN
assets/icons/payment.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 845 B |
BIN
assets/icons/repair.png
Normal file
BIN
assets/icons/repair.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 324 B |
BIN
assets/icons/visitor.png
Normal file
BIN
assets/icons/visitor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 876 B |
@ -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<ActivityListPage> {
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// TODO : 查看詳情
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) =>
|
||||
const ActivityDetailPage(activityId: 2),
|
||||
),
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
|
160
lib/activity_detail.dart
Normal file
160
lib/activity_detail.dart
Normal file
@ -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<ActivityDetailPage> createState() => _ActivityDetailPageState();
|
||||
}
|
||||
|
||||
class _ActivityDetailPageState extends State<ActivityDetailPage> {
|
||||
Map<String, dynamic>? activity;
|
||||
bool isLoading = true;
|
||||
|
||||
// 切換為 false 就會改為從 API 載入資料
|
||||
final bool useMockData = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
fetchActivityDetail();
|
||||
}
|
||||
|
||||
Future<void> 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<int>(
|
||||
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('我要報名'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -50,7 +50,10 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
||||
.map(
|
||||
(value) => DropdownMenuItem(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
child: Text(
|
||||
value,
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
@ -68,7 +71,10 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
||||
.map(
|
||||
(value) => DropdownMenuItem(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
child: Text(
|
||||
value,
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
@ -84,6 +90,7 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
||||
border: OutlineInputBorder(),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
),
|
||||
style: TextStyle(fontSize: 13),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
|
@ -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'),
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user