2025-07-11
작업 시작전 저장
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'main.dart';
|
||||
import 'youtube_player_page.dart'; // YoutubePlayerPage import
|
||||
import 'common/widgets/custom_bottom_nav_bar.dart';
|
||||
|
||||
@@ -10,12 +11,16 @@ class PlanDetailItem {
|
||||
final String lessonTag;
|
||||
final String lessonUrl;
|
||||
final String thumbnail;
|
||||
final String lessonName;
|
||||
final String lessonDescription;
|
||||
|
||||
PlanDetailItem({
|
||||
required this.lessonId,
|
||||
required this.lessonTag,
|
||||
required this.lessonUrl,
|
||||
required this.thumbnail,
|
||||
required this.lessonName,
|
||||
required this.lessonDescription,
|
||||
});
|
||||
|
||||
factory PlanDetailItem.fromJson(Map<String, dynamic> json) {
|
||||
@@ -24,6 +29,8 @@ class PlanDetailItem {
|
||||
lessonTag: json['lesson tag'] ?? '태그 없음',
|
||||
lessonUrl: json['lesson url'] ?? 'URL 없음',
|
||||
thumbnail: json['thumbnail'] ?? '',
|
||||
lessonName: json['lesson_name'] ?? '이름 없음',
|
||||
lessonDescription: json['lesson_description'] ?? '설명 없음',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -43,6 +50,7 @@ class _PlanPageDetailState extends State<PlanPageDetail> {
|
||||
Future<List<PlanDetailItem>>? _planDetails;
|
||||
late int _currentBottomNavIndex;
|
||||
String? _selectedYoutubeUrl;
|
||||
PlanDetailItem? _selectedItem; // <<< 선택된 아이템을 저장할 변수 추가
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -80,7 +88,6 @@ class _PlanPageDetailState extends State<PlanPageDetail> {
|
||||
});
|
||||
_planDetails =
|
||||
Future.error(Exception("전달된 인자가 올바르지 않습니다. (Map<String, String> 형태여야 함)"));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,28 +118,10 @@ class _PlanPageDetailState extends State<PlanPageDetail> {
|
||||
setState(() {
|
||||
_currentBottomNavIndex = index;
|
||||
});
|
||||
if (index == 0) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
} else {
|
||||
String tabName = '';
|
||||
switch (index) {
|
||||
case 1:
|
||||
tabName = 'Plan';
|
||||
break;
|
||||
case 2:
|
||||
tabName = 'Statistics';
|
||||
break;
|
||||
case 3:
|
||||
tabName = 'Jobs'; // New case for Jobs
|
||||
break;
|
||||
case 4:
|
||||
tabName = 'More'; // Updated case for More
|
||||
break;
|
||||
}
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('$tabName 탭으로 이동 (구현 필요)')),
|
||||
);
|
||||
}
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(builder: (context) => MyHomePage(initialIndex: index)),
|
||||
(Route<dynamic> route) => false,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -171,6 +160,9 @@ class _PlanPageDetailState extends State<PlanPageDetail> {
|
||||
return const Center(child: Text('세부 계획 데이터가 없습니다.'));
|
||||
} else {
|
||||
final details = snapshot.data!;
|
||||
if (_selectedItem == null && details.isNotEmpty) {
|
||||
_selectedItem = details.first;
|
||||
}
|
||||
|
||||
// 첫 번째 비디오의 URL을 가져와 _selectedYoutubeUrl을 초기화합니다.
|
||||
if (_selectedYoutubeUrl == null && details.isNotEmpty) {
|
||||
@@ -178,12 +170,12 @@ class _PlanPageDetailState extends State<PlanPageDetail> {
|
||||
(item) => item.lessonUrl.isNotEmpty &&
|
||||
(item.lessonUrl.contains('youtube.com') ||
|
||||
item.lessonUrl.contains('youtu.be')),
|
||||
orElse: () => PlanDetailItem(lessonId: '', lessonTag: '', lessonUrl: '', thumbnail: ''),
|
||||
orElse: () => PlanDetailItem(lessonId: '', lessonTag: '', lessonUrl: '', thumbnail: '',lessonName: '', lessonDescription: ''),
|
||||
).lessonUrl.isNotEmpty ? details.firstWhere(
|
||||
(item) => item.lessonUrl.isNotEmpty &&
|
||||
(item.lessonUrl.contains('youtube.com') ||
|
||||
item.lessonUrl.contains('youtu.be')),
|
||||
orElse: () => PlanDetailItem(lessonId: '', lessonTag: '', lessonUrl: '', thumbnail: ''),
|
||||
orElse: () => PlanDetailItem(lessonId: '', lessonTag: '', lessonUrl: '', thumbnail: '',lessonName: '', lessonDescription: ''),
|
||||
).lessonUrl : null;
|
||||
}
|
||||
|
||||
@@ -199,19 +191,20 @@ class _PlanPageDetailState extends State<PlanPageDetail> {
|
||||
final item = details[index];
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (item.lessonUrl.isNotEmpty &&
|
||||
(item.lessonUrl.contains('youtube.com') ||
|
||||
item.lessonUrl.contains('youtu.be'))) {
|
||||
setState(() {
|
||||
setState(() {
|
||||
_selectedItem = item;
|
||||
if (item.lessonUrl.isNotEmpty &&
|
||||
(item.lessonUrl.contains('youtube.com') ||
|
||||
item.lessonUrl.contains('youtu.be'))) {
|
||||
_selectedYoutubeUrl = item.lessonUrl;
|
||||
});
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'유효한 YouTube URL이 아닙니다: ${item.lessonUrl}')),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'유효한 YouTube URL이 아닙니다: ${item.lessonUrl}')),
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
width: 110,
|
||||
@@ -289,7 +282,82 @@ class _PlanPageDetailState extends State<PlanPageDetail> {
|
||||
);
|
||||
},
|
||||
),
|
||||
)],
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_selectedItem!.thumbnail.isNotEmpty
|
||||
? ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
child: Image.network(
|
||||
_selectedItem!.thumbnail,
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
child: const Icon(Icons.broken_image, size: 60, color: Colors.grey),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
child: const Icon(Icons.image_not_supported, size: 60, color: Colors.grey),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
_selectedItem!.lessonName,
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.play_circle_fill, size: 40, color: Colors.red),
|
||||
onPressed: () {
|
||||
if (_selectedYoutubeUrl != null && _selectedYoutubeUrl!.isNotEmpty) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => YoutubePlayerPage(lessonUrl: _selectedYoutubeUrl!),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('재생할 수 있는 영상이 없습니다.')),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
_selectedItem!.lessonDescription,
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user