import 'package:flutter/material.dart'; import './house_note_model.dart'; import './house_note_api.dart'; import './house_photo_form.dart'; import './house_tag_form.dart'; import './house_evaluation_form.dart'; class HouseNoteDetail extends StatefulWidget { final House house; const HouseNoteDetail({required this.house, super.key}); @override State createState() => _HouseNoteDetailState(); } class _HouseNoteDetailState extends State { final HouseNoteApiService _api = HouseNoteApiService(); List _evaluations = []; List _photos = []; bool _isLoading = true; @override void initState() { super.initState(); _loadAllData(); } // 同步抓取評估紀錄與照片 Future _loadAllData() async { setState(() => _isLoading = true); try { final results = await Future.wait([ _api.fetchEvaluations(widget.house.id), _api.fetchPhotos(widget.house.id), ]); if (mounted) { setState(() { _evaluations = results[0] as List; _photos = results[1] as List; _isLoading = false; }); } } catch (e) { if (mounted) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('資料載入失敗: $e')), ); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('賞屋詳細內容'), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: _loadAllData, ) ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : SingleChildScrollView( child: Column( children: [ // a. 基本資料區塊 _buildSectionHeader('房屋基本資料', Icons.info_outline), _buildBasicInfoCard(), // b. 屋況檢查區塊 (與照片主鍵關聯) _buildSectionHeader('屋況檢查評估', Icons.checklist_rtl), _buildEvaluationList(), // c. 照片總覽區塊 _buildSectionHeader('照片總覽 (點擊可放大)', Icons.photo_library_outlined), _buildPhotoGrid(), const SizedBox(height: 100), // 留白空間 ], ), ), // 底部懸浮按鈕區 bottomSheet: _buildBottomActions(context), ); } // --- UI 元件函式 --- // 分區標題 Widget _buildSectionHeader(String title, IconData icon) { return Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), color: Colors.grey.shade100, child: Row( children: [ Icon(icon, size: 20, color: Colors.blueAccent), const SizedBox(width: 8), Text(title, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)), ], ), ); } // 基本資料卡片 Widget _buildBasicInfoCard() { return Padding( padding: const EdgeInsets.all(16), child: Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: BorderSide(color: Colors.grey.shade200), ), child: Padding( padding: const EdgeInsets.all(16), child: Column( children: [ _buildDetailRow(Icons.home, '物件名稱', widget.house.title), const Divider(), _buildDetailRow(Icons.location_on, '完整地址', widget.house.address ?? '未填寫'), const Divider(), _buildDetailRow(Icons.monetization_on, '預估價格', widget.house.priceTag), const Divider(), _buildDetailRow(Icons.layers, '物件規格', widget.house.infoSummary), ], ), ), ), ); } // 輔助明細列 Widget _buildDetailRow(IconData icon, String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(icon, size: 18, color: Colors.grey), const SizedBox(width: 8), Text(label, style: const TextStyle(color: Colors.grey, fontSize: 14)), const Spacer(), Expanded( child: Text( value, textAlign: TextAlign.end, style: const TextStyle(fontWeight: FontWeight.w600), ), ), ], ), ); } // 屋況檢查清單 Widget _buildEvaluationList() { if (_evaluations.isEmpty) { return const Padding( padding: EdgeInsets.all(30), child: Text('目前尚無評估數據', style: TextStyle(color: Colors.grey)), ); } return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _evaluations.length, separatorBuilder: (_, __) => const Divider(height: 1), itemBuilder: (context, index) { final eval = _evaluations[index]; // 關鍵:找出有沒有照片是關聯到這個評估項目的 (透過 evaluation_id) final HousePhoto? linkedPhoto = _photos.cast().firstWhere( (p) => p?.evaluationId == eval.id, orElse: () => null, ); return ListTile( title: Text(eval.itemName, style: const TextStyle(fontWeight: FontWeight.w500)), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: List.generate(5, (i) => Icon( Icons.star, size: 16, color: i < eval.score ? Colors.orange : Colors.grey.shade300 )), ), if (eval.itemMemo != null && eval.itemMemo!.isNotEmpty) Text(eval.itemMemo!, style: const TextStyle(fontSize: 12, color: Colors.blueGrey)), ], ), trailing: linkedPhoto != null ? GestureDetector( onTap: () => _showFullScreenImage(context, linkedPhoto.fullUrl), child: ClipRRect( borderRadius: BorderRadius.circular(4), child: Image.network( linkedPhoto.fullUrl, width: 50, height: 50, fit: BoxFit.cover, errorBuilder: (_, __, ___) => const Icon(Icons.broken_image, size: 30), ), ), ) : null, ); }, ); } // 照片總覽 Grid Widget _buildPhotoGrid() { if (_photos.isEmpty) { return const Padding( padding: EdgeInsets.all(30), child: Text('尚未拍攝照片', style: TextStyle(color: Colors.grey)), ); } return GridView.builder( padding: const EdgeInsets.all(16), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 8, mainAxisSpacing: 8, ), itemCount: _photos.length, itemBuilder: (context, index) { final photo = _photos[index]; return GestureDetector( onTap: () => _showFullScreenImage(context, photo.fullUrl), child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Image.network( photo.fullUrl, fit: BoxFit.cover, errorBuilder: (_, __, ___) => Container( color: Colors.grey.shade200, child: const Icon(Icons.broken_image, color: Colors.grey), ), ), ), ); }, ); } // --- 互動功能 --- // 圖片放大功能 (支援雙指縮放) void _showFullScreenImage(BuildContext context, String imageUrl) { Navigator.push( context, MaterialPageRoute( builder: (context) => Scaffold( backgroundColor: Colors.black, appBar: AppBar(backgroundColor: Colors.black, foregroundColor: Colors.white), body: Center( child: InteractiveViewer( panEnabled: true, minScale: 0.5, maxScale: 4.0, child: Image.network( imageUrl, fit: BoxFit.contain, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return const CircularProgressIndicator(color: Colors.white); }, ), ), ), ), ), ); } // 底部按鈕 Widget _buildBottomActions(BuildContext context) { return Container( padding: const EdgeInsets.fromLTRB(16, 12, 16, 32), decoration: BoxDecoration( color: Colors.white, border: Border(top: BorderSide(color: Colors.grey.shade200)), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)] ), child: Row( children: [ Expanded( child: ElevatedButton.icon( onPressed: () async { final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => HouseEvaluationForm( houseId: widget.house.id, houseTitle: widget.house.title, ), ), ); // 返回後刷新詳情頁 if (result == true) { _loadAllData(); } }, icon: const Icon(Icons.rate_review), label: const Text('賞屋評估'), style: ElevatedButton.styleFrom( backgroundColor: Colors.orange, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), // 保持與拍照按鈕一致的圓角 ), ), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton.icon( onPressed: () async { final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => HousePhotoForm( houseId: widget.house.id, houseTitle: widget.house.title ) ) ); // 拍完照回來自動刷新頁面 if (result == true) { _loadAllData(); } }, icon: const Icon(Icons.camera_alt), label: const Text('拍照紀錄'), style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), // 保持與拍照按鈕一致的圓角 ), ), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton.icon( onPressed: () async { // 跳轉至標籤編輯頁面 (HouseTagForm) final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => HouseTagForm( houseId: widget.house.id, houseTitle: widget.house.title, ), ), ); // 當從標籤頁面返回,且 result 為 true 時,自動刷新詳情頁資料 if (result == true) { _loadAllData(); } }, icon: const Icon(Icons.local_offer_outlined), label: const Text('編輯標籤'), style: ElevatedButton.styleFrom( backgroundColor: Colors.teal, // 背景顏色設定為藍綠色 foregroundColor: Colors.white, // 文字與圖示顏色設定為白色 padding: const EdgeInsets.symmetric(vertical: 12), // 設定垂直內距 shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), // 保持與拍照按鈕一致的圓角 ), ), ), ), ], ), ); } }