Atualização geral de optimazação e desing

This commit is contained in:
Carlos Correia
2026-07-07 11:41:15 +01:00
parent e8afe36cd2
commit a8e04ceeb2
37 changed files with 1688 additions and 2900 deletions

View File

@@ -3,6 +3,8 @@ import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import '../screens/video_screen.dart';
typedef QuizNextBuilder =
Route<void> Function(BuildContext context, int nextScore);
@@ -37,6 +39,9 @@ class QuizQuestionScreen extends StatefulWidget {
this.showBackButton = false,
this.answerType = QuizAnswerType.text,
this.questionImagePaths = const [],
this.suggestedVideoPath,
this.suggestedYoutubeId,
this.suggestedVideoTitle,
});
final String title;
@@ -49,6 +54,9 @@ class QuizQuestionScreen extends StatefulWidget {
final bool showBackButton;
final QuizAnswerType answerType;
final List<String> questionImagePaths;
final String? suggestedVideoPath;
final String? suggestedYoutubeId;
final String? suggestedVideoTitle;
@override
State<QuizQuestionScreen> createState() => _QuizQuestionScreenState();
@@ -58,6 +66,7 @@ class _QuizQuestionScreenState extends State<QuizQuestionScreen> {
int? _selected;
TextEditingController? _numberController;
int? _numberValue;
bool _navigating = false;
@override
void initState() {
@@ -76,9 +85,9 @@ class _QuizQuestionScreenState extends State<QuizQuestionScreen> {
@override
Widget build(BuildContext context) {
final size = MediaQuery.sizeOf(context);
bool canProceed = _selected != null;
bool canProceed = _selected != null && !_navigating;
if (widget.answerType == QuizAnswerType.number) {
canProceed = _numberValue != null && _numberValue! >= 0;
canProceed = _numberValue != null && _numberValue! >= 0 && !_navigating;
}
return Scaffold(
@@ -145,6 +154,35 @@ class _QuizQuestionScreenState extends State<QuizQuestionScreen> {
),
const SizedBox(height: 10),
],
if (widget.suggestedVideoPath != null ||
widget.suggestedYoutubeId != null) ...[
TextButton.icon(
onPressed: () => showVideoPlayerDialog(
context,
VideoData(
id: 0,
title:
widget.suggestedVideoTitle ?? 'Vídeo',
description: '',
videoPath: widget.suggestedVideoPath,
youtubeId: widget.suggestedYoutubeId,
),
),
icon: const Icon(
Icons.play_circle_outline_rounded,
color: Color(0xFF2F9E94),
),
label: Text(
widget.suggestedVideoTitle ??
'Ver vídeo (opcional)',
style: const TextStyle(
color: Color(0xFF2F9E94),
fontWeight: FontWeight.w800,
),
),
),
const SizedBox(height: 4),
],
Text(
widget.question,
textAlign: TextAlign.center,
@@ -239,6 +277,7 @@ class _QuizQuestionScreenState extends State<QuizQuestionScreen> {
onPressed: !canProceed
? null
: () {
setState(() => _navigating = true);
int nextScore = widget.currentScore;
if (widget.answerType ==
QuizAnswerType.number) {
@@ -454,7 +493,7 @@ class _QuizAnswerTile extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (answer.imagePath != null) ...[
ClipRRect(
@@ -478,19 +517,14 @@ class _QuizAnswerTile extends StatelessWidget {
),
const SizedBox(height: 10),
],
Row(
children: [
Expanded(
child: Text(
answer.title,
style: const TextStyle(
fontWeight: FontWeight.w900,
fontSize: 15,
color: Color(0xFF2F9E94),
),
),
),
],
Text(
answer.title,
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.w900,
fontSize: 15,
color: Color(0xFF2F9E94),
),
),
],
),
@@ -516,6 +550,7 @@ class _QuestionReferenceImages extends StatelessWidget {
child: Image.asset(
paths.first,
fit: BoxFit.cover,
cacheWidth: 800,
errorBuilder: (context, error, stackTrace) => _placeholder(),
),
),
@@ -534,6 +569,7 @@ class _QuestionReferenceImages extends StatelessWidget {
borderRadius: BorderRadius.circular(12),
child: Image.asset(
paths[i],
cacheWidth: 300,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => _placeholder(),
),