import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'plan_page_detail.dart'; // <<< plan_page_detail.dart 파일을 import 합니다. // HomePage에서 사용하던 CaseStudyPlan 모델을 PlanPage에서도 사용하거나, // PlanPage에 필요한 별도의 데이터 모델을 정의할 수 있습니다. // 여기서는 동일한 모델을 재사용한다고 가정합니다. class CaseStudyPlan { final String planId; final String planTitle; final String planTeacher; final String thumbnail; CaseStudyPlan({ required this.planId, required this.planTitle, required this.planTeacher, required this.thumbnail, }); factory CaseStudyPlan.fromJson(Map json) { return CaseStudyPlan( planId: json['planId'] ?? 'ID 없음', planTitle: json['planTitle'] ?? '제목 없음', planTeacher: json['planTeacher'] ?? '선생님 정보 없음', thumbnail: json['thumbnail'] ?? '', ); } } class PlanPage extends StatefulWidget { const PlanPage({super.key}); @override State createState() => _PlanPageState(); } class _PlanPageState extends State { late Future> _planPageData; @override void initState() { super.initState(); // PlanPage가 처음 생성되거나 화면에 표시될 때 데이터를 가져옵니다. _planPageData = _fetchPlanData(); } Future> _fetchPlanData() async { // HomePage와 동일한 API 주소를 사용합니다. final response = await http .get(Uri.parse('https://helloworld2-ad2uqhckxq-uc.a.run.app')); if (response.statusCode == 200) { final Map decodedJson = json.decode(response.body); if (decodedJson.containsKey('data') && decodedJson['data'] is List) { final List plansJson = decodedJson['data']; return plansJson .map((jsonItem) => CaseStudyPlan.fromJson(jsonItem as Map)) .toList(); } else { throw Exception( 'Invalid data format for PlanPage: "data" field is missing or not a list.'); } } else { throw Exception( 'Failed to load data for PlanPage. Status Code: ${response.statusCode}'); } } @override Widget build(BuildContext context) { return FutureBuilder>( future: _planPageData, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Text('Error loading PlanPage data: ${snapshot.error}', textAlign: TextAlign.center), )); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text('No data available for PlanPage.')); } else { // 데이터 로딩 성공 시 ListView 표시 final plans = snapshot.data!; return ListView.builder( itemCount: plans.length, itemBuilder: (context, index) { final plan = plans[index]; return InkWell( // <<< Card를 InkWell로 감싸서 탭 이벤트를 추가합니다. onTap: () { // plan_page_detail로 이동하면서 planId를 arguments로 전달 if (plan.planId == 'ID 없음' || plan.planId.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('유효한 Plan ID가 없어 상세 페이지로 이동할 수 없습니다.')), ); return; } Navigator.push( context, MaterialPageRoute( builder: (context) => const plan_page_detail(), // plan_page_detail 위젯을 생성 settings: RouteSettings( arguments: plan.planId, // 선택된 plan의 ID를 전달 ), ), ); // 만약 Named Route를 사용하고 main.dart에 '/plan_detail' 라우트가 정의되어 있다면: // Navigator.pushNamed( // context, // '/plan_detail', // MaterialApp에 정의된 라우트 이름 // arguments: plan.planId, // ); }, child: Card( // <<< 기존 Card 위젯 margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), elevation: 2.0, child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( plan.planTitle, style: const TextStyle( fontSize: 17.0, fontWeight: FontWeight.bold), overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8.0), Text( plan.planTeacher, style: const TextStyle( fontSize: 13.0, color: Colors.grey), ), ], ), const SizedBox(height: 8.0), if (plan.thumbnail.isNotEmpty) ClipRRect( borderRadius: BorderRadius.circular(8.0), child: Image.network( plan.thumbnail, height: 140, // 약간 작은 이미지 크기 width: double.infinity, fit: BoxFit.cover, loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) { if (loadingProgress == null) return child; return Center( child: CircularProgressIndicator( value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, ), ); }, errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { return Container( height: 140, color: Colors.grey[200], child: const Center( child: Icon(Icons.broken_image, color: Colors.grey, size: 40))); }, ), ) else Container( height: 140, color: Colors.grey[200], child: const Center( child: Text('No Image', style: TextStyle(color: Colors.grey)))), // const SizedBox(height: 8.0), // // PlanPage용 ListView 아이템에 추가적인 정보를 표시하거나 다른 UI를 구성할 수 있습니다. // Text('Plan ID: ${plan.planId}', style: TextStyle(fontSize: 12.0, color: Colors.blueGrey)), ], ), ), ), ); }, ); } }, ); } }