I am creating a Card with Flutter, where the Card as the Text section and a Youtube Video Section:
I have two issues here:
With the following error on XCode:
Could anyone tell me what would the issue in my flutter code?
//main.dart
import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'features/drills/presentation/pages/drills_home_page.dart';
import 'core/config/supabase_config.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Supabase.initialize(url: SupabaseConfig.projectUrl, anonKey: SupabaseConfig.anonKey);
runApp(const TennisDrillsApp());
}
class TennisDrillsApp extends StatelessWidget {
const TennisDrillsApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Tennis Drills App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF339933), // Tennis court green
),
useMaterial3: true,
),
home: const DrillsHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
// drills_home_page.dart
import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
// import '../widgets/drill_card.dart';
import '../widgets/drill_card_with_youtube_video.dart';
import '../../data/repositories/supabase_drill_repository.dart';
import '../../domain/models/drill.dart';
class DrillsHomePage extends StatefulWidget {
const DrillsHomePage({super.key});
@override
State<DrillsHomePage> createState() => _DrillsHomePageState();
}
class _DrillsHomePageState extends State<DrillsHomePage> {
String _selectedCategory = 'all';
late final SupabaseDrillRepository _drillRepository;
List<Drill> _drills = [];
bool _isLoading = true;
String? _error;
@override
void initState() {
super.initState();
_drillRepository = SupabaseDrillRepository(Supabase.instance.client);
_loadDrills();
}
Future<void> _loadDrills() async {
try {
setState(() {
_isLoading = true;
_error = null;
});
final drills = await _drillRepository.getDrills();
setState(() {
_drills = drills;
_isLoading = false;
});
} catch (e) {
setState(() {
_error = 'Failed to load drills: ${e.toString()}';
_isLoading = false;
});
}
}
List<Drill> get filteredDrills {
if (_selectedCategory == 'all') {
return _drills;
}
return _drills.where((drill) => drill.category == _selectedCategory).toList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Tennis Drills'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
actions: [
// Forehand filter icon
IconButton(
icon: Icon(
Icons.sports_tennis,
color: _selectedCategory == 'forehand' ? Theme.of(context).colorScheme.primary : null,
),
tooltip: 'Forehand Drills',
onPressed: () {
setState(() {
_selectedCategory = _selectedCategory == 'forehand' ? 'all' : 'forehand';
});
},
),
// Backhand filter icon
IconButton(
icon: Transform(
alignment: Alignment.center,
transform: Matrix4.rotationY(3.14), // Flip the icon horizontally
child: Icon(
Icons.sports_tennis,
color: _selectedCategory == 'backhand' ? Theme.of(context).colorScheme.primary : null,
),
),
tooltip: 'Backhand Drills',
onPressed: () {
setState(() {
_selectedCategory = _selectedCategory == 'backhand' ? 'all' : 'backhand';
});
},
),
// Refresh button
IconButton(icon: const Icon(Icons.refresh), tooltip: 'Refresh Drills', onPressed: _loadDrills),
],
),
body: _buildBody(),
);
}
Widget _buildBody() {
if (_isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (_error != null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_error!, style: const TextStyle(color: Colors.red)),
const SizedBox(height: 16),
ElevatedButton(onPressed: _loadDrills, child: const Text('Retry')),
],
),
);
}
if (filteredDrills.isEmpty) {
return const Center(child: Text('No drills found'));
}
return ListView.builder(
itemCount: filteredDrills.length,
itemBuilder: (context, index) {
final drill = filteredDrills[index];
// return DrillCard(drill: drill.toJson());
return DrillCardWithYoutubeVideo(drill: drill.toJson(), videoId: '928wJjWeVyk');
},
);
}
}
// drill_card_with_youtube_video.dart
import 'package:flutter/material.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
class DrillCardWithYoutubeVideo extends StatefulWidget {
final Map<String, dynamic> drill;
final String videoId;
const DrillCardWithYoutubeVideo({super.key, required this.drill, required this.videoId});
@override
State<DrillCardWithYoutubeVideo> createState() => _DrillCardWithYoutubeVideoState();
}
class _DrillCardWithYoutubeVideoState extends State<DrillCardWithYoutubeVideo> {
late YoutubePlayerController _controller;
@override
void initState() {
super.initState();
_controller = YoutubePlayerController(
initialVideoId: widget.videoId,
flags: const YoutubePlayerFlags(autoPlay: false, mute: false),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Text Section
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(widget.drill['title'], style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8.0),
Text('Category: ${widget.drill['category']}', style: Theme.of(context).textTheme.bodyMedium),
if (widget.drill['description'] != null) ...[
const SizedBox(height: 8.0),
Text(widget.drill['description'], style: Theme.of(context).textTheme.bodyMedium),
],
],
),
),
// YouTube Video Section
AspectRatio(
aspectRatio: 16 / 9,
child: YoutubePlayer(
controller: _controller,
showVideoProgressIndicator: true,
progressIndicatorColor: Theme.of(context).colorScheme.primary,
progressColors: ProgressBarColors(
playedColor: Theme.of(context).colorScheme.primary,
handleColor: Theme.of(context).colorScheme.primary,
),
),
),
],
),
);
}
}
If fullscreen support is required, wrap your player with YoutubePlayerBuilder
doc: youtube_player_flutter pub dev
YoutubePlayerBuilder(
player: YoutubePlayer(
controller: _controller,
),
builder: (context, player){
return Column(
children: [
// some widgets
player,
//some other widgets
],
);
),
),