新增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 'package:flutter/material.dart';
|
||||||
import 'activity_submit.dart';
|
import 'activity_submit.dart';
|
||||||
|
import 'activity_detail.dart';
|
||||||
|
|
||||||
class ActivityListPage extends StatefulWidget {
|
class ActivityListPage extends StatefulWidget {
|
||||||
const ActivityListPage({Key? key}) : super(key: key);
|
const ActivityListPage({Key? key}) : super(key: key);
|
||||||
@ -94,7 +95,14 @@ class _ActivityListPageState extends State<ActivityListPage> {
|
|||||||
children: [
|
children: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// TODO : 查看詳情
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder:
|
||||||
|
(context) =>
|
||||||
|
const ActivityDetailPage(activityId: 2),
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.transparent,
|
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(
|
.map(
|
||||||
(value) => DropdownMenuItem(
|
(value) => DropdownMenuItem(
|
||||||
value: value,
|
value: value,
|
||||||
child: Text(value),
|
child: Text(
|
||||||
|
value,
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
@ -68,7 +71,10 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
|||||||
.map(
|
.map(
|
||||||
(value) => DropdownMenuItem(
|
(value) => DropdownMenuItem(
|
||||||
value: value,
|
value: value,
|
||||||
child: Text(value),
|
child: Text(
|
||||||
|
value,
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
@ -84,6 +90,7 @@ class _FeedbackPageState extends State<FeedbackPage> {
|
|||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||||
),
|
),
|
||||||
|
style: TextStyle(fontSize: 13),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Row(
|
Row(
|
||||||
|
@ -94,36 +94,6 @@ class HomeContentPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
NotificationIcon(),
|
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,
|
childAspectRatio: 1,
|
||||||
children: [
|
children: [
|
||||||
_buildQuickButton(context, '報修', 'assets/icons/repair.png'),
|
_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/visitor.png'),
|
||||||
_buildQuickButton(context, '繳費', 'assets/icons/payment.png'),
|
_buildQuickButton(context, '繳費', 'assets/icons/payment.png'),
|
||||||
_buildQuickButton(context, '社區互動', 'assets/icons/community.png'),
|
_buildQuickButton(context, '社區互動', 'assets/icons/community.png'),
|
||||||
|
@ -21,30 +21,6 @@ class PersonalPage extends StatelessWidget {
|
|||||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
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(
|
body: ListView(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
@ -139,19 +115,24 @@ class PersonalPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Column(
|
// 左邊社區資訊,右邊預留空間避免被按鈕擋住
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Padding(
|
||||||
children: const [
|
padding: const EdgeInsets.only(right: 120), // 預留右上角空間
|
||||||
Text('社區地址:新北市板橋區幸福路 88 號', style: TextStyle(fontSize: 14)),
|
child: Column(
|
||||||
SizedBox(height: 6),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Text('管理室電話:02-2233-4455', style: TextStyle(fontSize: 14)),
|
children: const [
|
||||||
SizedBox(height: 6),
|
Text('社區地址:新北市板橋區幸福路 88 號', style: TextStyle(fontSize: 12)),
|
||||||
Text(
|
SizedBox(height: 6),
|
||||||
'管委會 Email:service@garden-community.tw',
|
Text('管理室電話:02-2233-4455', style: TextStyle(fontSize: 12)),
|
||||||
style: TextStyle(fontSize: 14),
|
SizedBox(height: 6),
|
||||||
),
|
Text(
|
||||||
],
|
'管委會 Email:service@garden-community.tw',
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
// 右上角意見箱按鈕
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
@ -194,7 +175,7 @@ class PersonalPage extends StatelessWidget {
|
|||||||
mainAxisSpacing: 12,
|
mainAxisSpacing: 12,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
children: [
|
children: [
|
||||||
_buildMenuItem('繳費通知', 'receipt.png', () {
|
_buildMenuItem('繳費通知', 'payment.png', () {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
|
@ -54,6 +54,7 @@ dev_dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
assets:
|
assets:
|
||||||
- assets/images/
|
- assets/images/
|
||||||
|
- assets/icons/
|
||||||
# The following line ensures that the Material Icons font is
|
# The following line ensures that the Material Icons font is
|
||||||
# included with your application, so that you can use the icons in
|
# included with your application, so that you can use the icons in
|
||||||
# the material Icons class.
|
# the material Icons class.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user