feat(app): 곡 상세 화면 뮤직비디오 앱 내 재생 + YouTube 이동 버튼
- 썸네일+재생 버튼 → OmniVideoPlayer로 교체 (앱 내 직접 재생) - 하단에 'YouTube에서 보기' 텍스트 버튼 추가 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5f70b6852f
commit
aa750b19d4
1 changed files with 26 additions and 51 deletions
|
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:lucide_icons/lucide_icons.dart';
|
import 'package:lucide_icons/lucide_icons.dart';
|
||||||
|
import 'package:omni_video_player/omni_video_player.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import '../../core/constants.dart';
|
import '../../core/constants.dart';
|
||||||
import '../../models/album.dart';
|
import '../../models/album.dart';
|
||||||
|
|
@ -326,59 +327,33 @@ class _MusicVideoSection extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
// 썸네일
|
// 영상 플레이어
|
||||||
GestureDetector(
|
ClipRRect(
|
||||||
onTap: onTap,
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: Container(
|
child: AspectRatio(
|
||||||
width: double.infinity,
|
aspectRatio: 16 / 9,
|
||||||
decoration: BoxDecoration(
|
child: OmniVideoPlayer(
|
||||||
borderRadius: BorderRadius.circular(12),
|
configuration: VideoPlayerConfiguration(
|
||||||
boxShadow: [
|
videoSourceConfiguration: VideoSourceConfiguration.youtube(
|
||||||
BoxShadow(
|
videoUrl: Uri.parse('https://www.youtube.com/watch?v=$videoId'),
|
||||||
color: Colors.black.withValues(alpha: 0.1),
|
preferredQualities: [OmniVideoQuality.high720],
|
||||||
blurRadius: 8,
|
|
||||||
offset: const Offset(0, 2),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
child: AspectRatio(
|
|
||||||
aspectRatio: 16 / 9,
|
|
||||||
child: Stack(
|
|
||||||
fit: StackFit.expand,
|
|
||||||
children: [
|
|
||||||
CachedNetworkImage(
|
|
||||||
imageUrl: 'https://img.youtube.com/vi/$videoId/maxresdefault.jpg',
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
placeholder: (context, url) => Container(color: Colors.black),
|
|
||||||
errorWidget: (context, url, error) => CachedNetworkImage(
|
|
||||||
imageUrl: 'https://img.youtube.com/vi/$videoId/hqdefault.jpg',
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 재생 버튼 오버레이
|
|
||||||
Container(
|
|
||||||
color: Colors.black.withValues(alpha: 0.3),
|
|
||||||
child: Center(
|
|
||||||
child: Container(
|
|
||||||
width: 56,
|
|
||||||
height: 56,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.red,
|
|
||||||
borderRadius: BorderRadius.circular(28),
|
|
||||||
),
|
|
||||||
child: const Icon(
|
|
||||||
LucideIcons.play,
|
|
||||||
color: Colors.white,
|
|
||||||
size: 28,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
callbacks: const VideoPlayerCallbacks(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
// YouTube에서 보기 버튼
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: TextButton.icon(
|
||||||
|
onPressed: onTap,
|
||||||
|
icon: const Icon(LucideIcons.externalLink, size: 14),
|
||||||
|
label: const Text('YouTube에서 보기', style: TextStyle(fontSize: 13)),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor: Colors.red,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue