182 lines
5.9 KiB
Dart
182 lines
5.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
class Announcement {
|
|
final String date;
|
|
final String title;
|
|
final String preview;
|
|
final String full;
|
|
|
|
Announcement({
|
|
required this.date,
|
|
required this.title,
|
|
required this.preview,
|
|
required this.full,
|
|
});
|
|
|
|
factory Announcement.fromJson(Map<String, dynamic> json) {
|
|
return Announcement(
|
|
date: json['date'],
|
|
title: json['title'],
|
|
preview: json['preview'],
|
|
full: json['full'],
|
|
);
|
|
}
|
|
}
|
|
|
|
class AnnouncementWrapper extends StatefulWidget {
|
|
const AnnouncementWrapper({super.key});
|
|
|
|
@override
|
|
State<AnnouncementWrapper> createState() => _AnnouncementWrapperState();
|
|
}
|
|
|
|
class _AnnouncementWrapperState extends State<AnnouncementWrapper> {
|
|
List<Announcement> _announcements = [];
|
|
bool _isLoading = true;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_fetchAnnouncements();
|
|
}
|
|
|
|
Future<void> _fetchAnnouncements() async {
|
|
// 模擬 API 延遲
|
|
//await Future.delayed(const Duration(milliseconds: 100));
|
|
|
|
// 模擬 API 回傳資料
|
|
final mockData = [
|
|
{
|
|
'date': '2025/04/28',
|
|
'title': '水塔清洗通知',
|
|
'preview': '本社區將於 2025/05/05 進行水塔清洗作業,請住戶提前儲水...',
|
|
'full': '本社區將於 2025/05/05 進行水塔清洗作業,請住戶提前儲水,造成不便敬請見諒。',
|
|
},
|
|
{
|
|
'date': '2025/04/25',
|
|
'title': '停電通知',
|
|
'preview': '台電預計於 5/1 上午進行電路維修,期間將暫時停電,請提前準備...',
|
|
'full': '台電預計於 2025/05/01 08:00~12:00 進行電路維修,期間將暫時停電,請提前準備。',
|
|
},
|
|
{
|
|
'date': '2025/04/20',
|
|
'title': '消防演練公告',
|
|
'preview': '消防演練將於 5/10 下午舉行,請住戶配合參與並聆聽安全說明...',
|
|
'full': '消防演練將於 2025/05/10 下午 3 點舉行,請各位住戶配合參與。',
|
|
},
|
|
];
|
|
|
|
setState(() {
|
|
_announcements =
|
|
mockData.map((json) => Announcement.fromJson(json)).toList();
|
|
_isLoading = false;
|
|
});
|
|
}
|
|
|
|
void _showDetailModal(BuildContext context, String title, String content) {
|
|
showDialog(
|
|
context: context,
|
|
builder:
|
|
(_) => AlertDialog(
|
|
title: Text(title),
|
|
content: Text(content),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
child: const Text('關閉'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
decoration: const BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
|
),
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
|
|
child:
|
|
_isLoading
|
|
? const Center(child: CircularProgressIndicator())
|
|
: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
IconButton(
|
|
icon: const Icon(Icons.arrow_back),
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
),
|
|
const Expanded(
|
|
child: Center(
|
|
child: Text(
|
|
'公告列表',
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 48),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
const Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Text('📢 最新公告', style: TextStyle(fontSize: 16)),
|
|
),
|
|
const SizedBox(height: 12),
|
|
..._announcements.map(
|
|
(item) => Column(
|
|
children: [
|
|
ListTile(
|
|
title: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
item.date,
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
color: Colors.black54,
|
|
),
|
|
),
|
|
Text(
|
|
item.title,
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
subtitle: Padding(
|
|
padding: const EdgeInsets.only(top: 6.0),
|
|
child: Text(
|
|
item.preview,
|
|
style: const TextStyle(
|
|
fontSize: 13,
|
|
color: Colors.black45,
|
|
),
|
|
),
|
|
),
|
|
onTap:
|
|
() => _showDetailModal(
|
|
context,
|
|
item.title,
|
|
item.full,
|
|
),
|
|
),
|
|
const Divider(),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|