Atualização do quiz e videos(incompleto)

This commit is contained in:
Carlos Correia
2026-05-26 16:21:11 +01:00
parent ea009af0d3
commit e292256a98
59 changed files with 351 additions and 405 deletions

View File

@@ -2,14 +2,6 @@ import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
class VideoItem {
const VideoItem({required this.title, required this.url});
final String title;
final String url;
}
class VideoScreen extends StatelessWidget {
const VideoScreen({super.key});
@@ -17,10 +9,6 @@ class VideoScreen extends StatelessWidget {
static const Color _teal = Color(0xFF2F9E94);
static const Color _accentPink = Color(0xFFFF55A7);
static const List<VideoItem> library = [
VideoItem(title: 'Como escovar da maneira certa', url: 'https://www.youtube.com/watch?v=uH8dBWkD__0'),
];
@override
Widget build(BuildContext context) {
final size = MediaQuery.sizeOf(context);
@@ -29,9 +17,8 @@ class VideoScreen extends StatelessWidget {
backgroundColor: _teal,
foregroundColor: Colors.white,
elevation: 0,
title: const Text(
'Vídeos Educativos',
'Videos Educativos',
style: TextStyle(fontWeight: FontWeight.w900),
),
),
@@ -44,10 +31,7 @@ class VideoScreen extends StatelessWidget {
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFFFE6F1),
Color(0xFFFFC9DF),
],
colors: [Color(0xFFFFE6F1), Color(0xFFFFC9DF)],
),
),
),
@@ -74,63 +58,48 @@ class VideoScreen extends StatelessWidget {
),
),
SafeArea(
child: Align(
alignment: Alignment.topCenter,
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 560),
constraints: const BoxConstraints(maxWidth: 480),
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.65),
borderRadius: BorderRadius.circular(14),
border: Border.all(color: Colors.black.withValues(alpha: 0.08)),
),
child: const Row(
children: [
Icon(Icons.play_circle_fill_rounded, color: _accentPink),
SizedBox(width: 10),
Expanded(
child: Text(
'Vídeos Educativos',
style: TextStyle(
fontWeight: FontWeight.w900,
color: _accentPink,
),
),
),
],
),
padding: const EdgeInsets.all(24),
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.85),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: Colors.black.withValues(alpha: 0.08),
),
const SizedBox(height: 14),
Expanded(
child: GridView.count(
crossAxisCount: 2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 0.92,
children: library.map((item) {
final videoId = YoutubePlayer.convertUrlToId(item.url);
final thumb = videoId == null ? null : 'https://img.youtube.com/vi/$videoId/0.jpg';
return _VideoCard(
title: item.title,
thumbnailUrl: thumb,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => VideoPlayerScreen(url: item.url, title: item.title),
),
);
},
);
}).toList(),
),
child: const Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.play_circle_fill_rounded,
size: 64,
color: _accentPink,
),
),
],
SizedBox(height: 12),
Text(
'Em breve',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w900,
color: _teal,
),
),
SizedBox(height: 8),
Text(
'Os videos educativos serao disponibilizados em breve.',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
],
),
),
),
),
@@ -141,175 +110,3 @@ class VideoScreen extends StatelessWidget {
);
}
}
class _VideoCard extends StatelessWidget {
const _VideoCard({required this.title, required this.thumbnailUrl, required this.onTap});
final String title;
final String? thumbnailUrl;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return Material(
color: Colors.white.withValues(alpha: 0.80),
borderRadius: BorderRadius.circular(16),
child: InkWell(
borderRadius: BorderRadius.circular(16),
onTap: onTap,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
child: Stack(
fit: StackFit.expand,
children: [
if (thumbnailUrl != null)
Image.network(
thumbnailUrl!,
fit: BoxFit.cover,
)
else
Container(color: Colors.black.withValues(alpha: 0.06)),
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black.withValues(alpha: 0.10),
Colors.black.withValues(alpha: 0.42),
],
),
),
),
const Align(
alignment: Alignment.center,
child: Icon(Icons.play_circle_fill_rounded, size: 54, color: Colors.white),
),
],
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(12, 10, 12, 12),
child: Text(
title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontWeight: FontWeight.w900,
color: Color(0xFF2F9E94),
),
),
),
],
),
),
);
}
}
class VideoPlayerScreen extends StatefulWidget {
const VideoPlayerScreen({super.key, required this.url, required this.title});
final String url;
final String title;
@override
State<VideoPlayerScreen> createState() => _VideoPlayerScreenState();
}
class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
static const Color _teal = Color(0xFF2F9E94);
static const Color _bg = Color(0xFFFFE6F1);
late final YoutubePlayerController _controller;
@override
void initState() {
super.initState();
final id = YoutubePlayer.convertUrlToId(widget.url);
_controller = YoutubePlayerController(
initialVideoId: id ?? '',
flags: const YoutubePlayerFlags(
autoPlay: true,
mute: false,
enableCaption: true,
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final hasVideo = _controller.initialVideoId.isNotEmpty;
return Scaffold(
appBar: AppBar(
backgroundColor: _teal,
foregroundColor: Colors.white,
elevation: 0,
title: Text(
widget.title,
style: const TextStyle(fontWeight: FontWeight.w900),
),
),
body: Container(
color: _bg,
child: SafeArea(
child: ListView(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 16),
children: [
ClipRRect(
borderRadius: BorderRadius.circular(16),
child: AspectRatio(
aspectRatio: 16 / 9,
child: hasVideo
? YoutubePlayer(
controller: _controller,
showVideoProgressIndicator: true,
progressIndicatorColor: Colors.white,
)
: Container(
color: Colors.black.withValues(alpha: 0.10),
child: const Center(
child: Text(
'Link de vídeo inválido',
style: TextStyle(fontWeight: FontWeight.w800),
),
),
),
),
),
const SizedBox(height: 14),
Text(
widget.title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w900,
color: Color(0xFFFF55A7),
),
),
const SizedBox(height: 6),
Text(
'Assista ao vídeo e aprenda mais sobre saúde bucal.',
style: TextStyle(
color: Colors.black.withValues(alpha: 0.70),
fontWeight: FontWeight.w600,
),
),
],
),
),
),
);
}
}