Nova tela de login | Adaptaçao nova da AppBar | Animções novas
This commit is contained in:
@@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:lottie/lottie.dart';
|
||||
|
||||
import '../screens/video_screen.dart';
|
||||
import '../widgets/entrance.dart';
|
||||
import '../widgets/tap_bounce.dart';
|
||||
|
||||
typedef QuizNextBuilder =
|
||||
Route<void> Function(BuildContext context, int nextScore);
|
||||
@@ -90,6 +92,10 @@ class _QuizQuestionScreenState extends State<QuizQuestionScreen> {
|
||||
canProceed = _numberValue != null && _numberValue! >= 0 && !_navigating;
|
||||
}
|
||||
|
||||
final bool hasSuggestedVideo =
|
||||
(widget.suggestedVideoPath?.isNotEmpty ?? false) ||
|
||||
(widget.suggestedYoutubeId?.isNotEmpty ?? false);
|
||||
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
@@ -127,267 +133,391 @@ class _QuizQuestionScreenState extends State<QuizQuestionScreen> {
|
||||
),
|
||||
),
|
||||
SafeArea(
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 520),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 18, 20, 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.black.withValues(alpha: 0.55),
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
if (widget.questionImagePaths.isNotEmpty) ...[
|
||||
const SizedBox(height: 6),
|
||||
_QuestionReferenceImages(
|
||||
paths: widget.questionImagePaths,
|
||||
),
|
||||
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,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Color(0xFFFF55A7),
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
widget.answerType == QuizAnswerType.number
|
||||
? 'Insira o número'
|
||||
: widget.answerType == QuizAnswerType.yesNo
|
||||
? 'Escolha uma opção'
|
||||
: 'Escolha apenas uma opção',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.black.withValues(alpha: 0.55),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 44,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.black.withValues(alpha: 0.55),
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: widget.answerType == QuizAnswerType.number
|
||||
? _buildNumberInput()
|
||||
: ListView.separated(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
itemCount: widget.answers.length,
|
||||
separatorBuilder: (context, index) =>
|
||||
const SizedBox(height: 12),
|
||||
itemBuilder: (context, i) {
|
||||
return _QuizAnswerTile(
|
||||
answer: widget.answers[i],
|
||||
selected: _selected == i,
|
||||
onTap: () => setState(() => _selected = i),
|
||||
);
|
||||
},
|
||||
if (widget.showBackButton)
|
||||
Positioned(
|
||||
left: 4,
|
||||
child: TapBounce(
|
||||
scale: 0.9,
|
||||
child: Material(
|
||||
color: Colors.white.withValues(alpha: 0.85),
|
||||
shape: const CircleBorder(),
|
||||
elevation: 4,
|
||||
shadowColor: Colors.black.withValues(
|
||||
alpha: 0.15,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 8, 20, 18),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: size.width * 0.62,
|
||||
height: 46,
|
||||
child: FilledButton(
|
||||
style:
|
||||
FilledButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2F9E94),
|
||||
foregroundColor: Colors.white,
|
||||
shape: const StadiumBorder(),
|
||||
textStyle: const TextStyle(
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
).copyWith(
|
||||
animationDuration: const Duration(
|
||||
milliseconds: 180,
|
||||
),
|
||||
splashFactory: InkSparkle.splashFactory,
|
||||
overlayColor:
|
||||
WidgetStateProperty.resolveWith<Color?>(
|
||||
(states) {
|
||||
if (states.contains(
|
||||
WidgetState.pressed,
|
||||
)) {
|
||||
return Colors.white.withValues(
|
||||
alpha: 0.14,
|
||||
);
|
||||
}
|
||||
if (states.contains(
|
||||
WidgetState.hovered,
|
||||
) ||
|
||||
states.contains(
|
||||
WidgetState.focused,
|
||||
)) {
|
||||
return Colors.white.withValues(
|
||||
alpha: 0.08,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
child: InkWell(
|
||||
customBorder: const CircleBorder(),
|
||||
onTap: () => Navigator.of(context).maybePop(),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Icon(
|
||||
Icons.arrow_back_rounded,
|
||||
color: Color(0xFF2F9E94),
|
||||
size: 22,
|
||||
),
|
||||
onPressed: !canProceed
|
||||
? null
|
||||
: () {
|
||||
setState(() => _navigating = true);
|
||||
int nextScore = widget.currentScore;
|
||||
if (widget.answerType ==
|
||||
QuizAnswerType.number) {
|
||||
nextScore =
|
||||
widget.currentScore +
|
||||
(_numberValue ?? 0);
|
||||
} else {
|
||||
final picked =
|
||||
widget.answers[_selected!];
|
||||
nextScore =
|
||||
widget.currentScore + picked.weight;
|
||||
}
|
||||
|
||||
if (widget.isFinal) {
|
||||
final finishedRoute = widget.nextRoute(
|
||||
context,
|
||||
nextScore,
|
||||
);
|
||||
Navigator.of(
|
||||
context,
|
||||
).pushReplacement(finishedRoute);
|
||||
return;
|
||||
}
|
||||
|
||||
Navigator.of(context).push(
|
||||
widget.nextRoute(context, nextScore),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
widget.isFinal ? 'Concluir' : 'Avançar',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.showBackButton) ...[
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
width: size.width * 0.62,
|
||||
height: 42,
|
||||
child: FilledButton(
|
||||
style:
|
||||
FilledButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2F9E94),
|
||||
foregroundColor: Colors.white,
|
||||
shape: const StadiumBorder(),
|
||||
textStyle: const TextStyle(
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
).copyWith(
|
||||
animationDuration: const Duration(
|
||||
milliseconds: 180,
|
||||
),
|
||||
splashFactory: InkSparkle.splashFactory,
|
||||
overlayColor:
|
||||
WidgetStateProperty.resolveWith<
|
||||
Color?
|
||||
>((states) {
|
||||
if (states.contains(
|
||||
WidgetState.pressed,
|
||||
)) {
|
||||
return Colors.white.withValues(
|
||||
alpha: 0.14,
|
||||
);
|
||||
}
|
||||
if (states.contains(
|
||||
WidgetState.hovered,
|
||||
) ||
|
||||
states.contains(
|
||||
WidgetState.focused,
|
||||
)) {
|
||||
return Colors.white.withValues(
|
||||
alpha: 0.08,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
),
|
||||
onPressed: () =>
|
||||
Navigator.of(context).maybePop(),
|
||||
child: const Text('Voltar'),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
width: size.width * 0.62,
|
||||
height: 42,
|
||||
child: OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: const Color(0xFF2F9E94),
|
||||
side: const BorderSide(
|
||||
color: Color(0xFF2F9E94),
|
||||
width: 1.3,
|
||||
),
|
||||
shape: const StadiumBorder(),
|
||||
textStyle: const TextStyle(
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
),
|
||||
onPressed: () => Navigator.of(
|
||||
context,
|
||||
).popUntil((route) => route.isFirst),
|
||||
child: const Text('Voltar para homepage'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return SingleChildScrollView(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: constraints.maxHeight,
|
||||
),
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 520,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FadeSlideIn(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
20,
|
||||
4,
|
||||
20,
|
||||
10,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (widget
|
||||
.questionImagePaths
|
||||
.isNotEmpty) ...[
|
||||
const SizedBox(height: 6),
|
||||
_QuestionReferenceImages(
|
||||
paths:
|
||||
widget.questionImagePaths,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
if (hasSuggestedVideo) ...[
|
||||
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,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Color(0xFFFF55A7),
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
widget.answerType ==
|
||||
QuizAnswerType.number
|
||||
? 'Insira o número'
|
||||
: widget.answerType ==
|
||||
QuizAnswerType.yesNo
|
||||
? 'Escolha uma opção'
|
||||
: 'Escolha apenas uma opção',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.black
|
||||
.withValues(alpha: 0.55),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
),
|
||||
child:
|
||||
widget.answerType ==
|
||||
QuizAnswerType.number
|
||||
? _buildNumberInput()
|
||||
: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (
|
||||
int i = 0;
|
||||
i < widget.answers.length;
|
||||
i++
|
||||
) ...[
|
||||
if (i > 0)
|
||||
const SizedBox(height: 12),
|
||||
FadeSlideIn(
|
||||
delay: Duration(
|
||||
milliseconds: 60 * i,
|
||||
),
|
||||
child: _QuizAnswerTile(
|
||||
answer:
|
||||
widget.answers[i],
|
||||
selected:
|
||||
_selected == i,
|
||||
onTap: () => setState(
|
||||
() => _selected = i,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
20,
|
||||
0,
|
||||
20,
|
||||
0,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
TapBounce(
|
||||
child: SizedBox(
|
||||
width: size.width * 0.62,
|
||||
height: 46,
|
||||
child: FilledButton(
|
||||
style:
|
||||
FilledButton.styleFrom(
|
||||
backgroundColor:
|
||||
const Color(
|
||||
0xFF2F9E94,
|
||||
),
|
||||
foregroundColor:
|
||||
Colors.white,
|
||||
shape:
|
||||
const StadiumBorder(),
|
||||
textStyle:
|
||||
const TextStyle(
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w900,
|
||||
),
|
||||
).copyWith(
|
||||
animationDuration:
|
||||
const Duration(
|
||||
milliseconds: 180,
|
||||
),
|
||||
splashFactory: InkSparkle
|
||||
.splashFactory,
|
||||
overlayColor:
|
||||
WidgetStateProperty.resolveWith<
|
||||
Color?
|
||||
>((states) {
|
||||
if (states
|
||||
.contains(
|
||||
WidgetState
|
||||
.pressed,
|
||||
)) {
|
||||
return Colors
|
||||
.white
|
||||
.withValues(
|
||||
alpha:
|
||||
0.14,
|
||||
);
|
||||
}
|
||||
if (states.contains(
|
||||
WidgetState
|
||||
.hovered,
|
||||
) ||
|
||||
states.contains(
|
||||
WidgetState
|
||||
.focused,
|
||||
)) {
|
||||
return Colors
|
||||
.white
|
||||
.withValues(
|
||||
alpha:
|
||||
0.08,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
),
|
||||
onPressed: !canProceed
|
||||
? null
|
||||
: () async {
|
||||
setState(
|
||||
() => _navigating =
|
||||
true,
|
||||
);
|
||||
int nextScore =
|
||||
widget
|
||||
.currentScore;
|
||||
if (widget.answerType ==
|
||||
QuizAnswerType
|
||||
.number) {
|
||||
nextScore =
|
||||
widget
|
||||
.currentScore +
|
||||
(_numberValue ??
|
||||
0);
|
||||
} else {
|
||||
final picked = widget
|
||||
.answers[_selected!];
|
||||
nextScore =
|
||||
widget
|
||||
.currentScore +
|
||||
picked.weight;
|
||||
}
|
||||
|
||||
if (widget.isFinal) {
|
||||
final finishedRoute =
|
||||
widget.nextRoute(
|
||||
context,
|
||||
nextScore,
|
||||
);
|
||||
Navigator.of(
|
||||
context,
|
||||
).pushReplacement(
|
||||
finishedRoute,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await Navigator.of(
|
||||
context,
|
||||
).push(
|
||||
widget.nextRoute(
|
||||
context,
|
||||
nextScore,
|
||||
),
|
||||
);
|
||||
if (mounted) {
|
||||
setState(
|
||||
() => _navigating =
|
||||
false,
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
widget.isFinal
|
||||
? 'Concluir'
|
||||
: 'Avançar',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TapBounce(
|
||||
child: SizedBox(
|
||||
width: size.width * 0.62,
|
||||
height: 42,
|
||||
child: OutlinedButton(
|
||||
style:
|
||||
OutlinedButton.styleFrom(
|
||||
foregroundColor:
|
||||
const Color(
|
||||
0xFF2F9E94,
|
||||
),
|
||||
side: const BorderSide(
|
||||
color: Color(
|
||||
0xFF2F9E94,
|
||||
),
|
||||
width: 1.3,
|
||||
),
|
||||
shape:
|
||||
const StadiumBorder(),
|
||||
textStyle:
|
||||
const TextStyle(
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w900,
|
||||
),
|
||||
),
|
||||
onPressed: () =>
|
||||
Navigator.of(
|
||||
context,
|
||||
).popUntil(
|
||||
(route) =>
|
||||
route.isFirst,
|
||||
),
|
||||
child: const Text(
|
||||
'Voltar para homepage',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -469,67 +599,109 @@ class _QuizAnswerTile extends StatelessWidget {
|
||||
? Colors.white.withValues(alpha: 0.88)
|
||||
: Colors.white.withValues(alpha: 0.70);
|
||||
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 220),
|
||||
curve: Curves.easeOutCubic,
|
||||
decoration: BoxDecoration(
|
||||
color: bg,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: borderColor, width: selected ? 1.4 : 1.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.06),
|
||||
blurRadius: 18,
|
||||
offset: const Offset(0, 10),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
onTap: onTap,
|
||||
splashFactory: InkSparkle.splashFactory,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (answer.imagePath != null) ...[
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 4 / 3,
|
||||
child: Image.asset(
|
||||
answer.imagePath!,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) => Container(
|
||||
color: Colors.black.withValues(alpha: 0.06),
|
||||
child: const Center(
|
||||
child: Icon(
|
||||
Icons.image_not_supported_outlined,
|
||||
color: Colors.black38,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
Text(
|
||||
answer.title,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
color: Color(0xFF2F9E94),
|
||||
),
|
||||
return TapBounce(
|
||||
scale: 0.97,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
fit: StackFit.passthrough,
|
||||
children: [
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 220),
|
||||
curve: Curves.easeOutCubic,
|
||||
decoration: BoxDecoration(
|
||||
color: bg,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: borderColor,
|
||||
width: selected ? 1.4 : 1.0,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.06),
|
||||
blurRadius: 18,
|
||||
offset: const Offset(0, 10),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
onTap: onTap,
|
||||
splashFactory: InkSparkle.splashFactory,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 14,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (answer.imagePath != null) ...[
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 4 / 3,
|
||||
child: Image.asset(
|
||||
answer.imagePath!,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) =>
|
||||
Container(
|
||||
color: Colors.black.withValues(
|
||||
alpha: 0.06,
|
||||
),
|
||||
child: const Center(
|
||||
child: Icon(
|
||||
Icons.image_not_supported_outlined,
|
||||
color: Colors.black38,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
Text(
|
||||
answer.title,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
color: Color(0xFF2F9E94),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 8,
|
||||
child: IgnorePointer(
|
||||
child: AnimatedScale(
|
||||
scale: selected ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 220),
|
||||
curve: Curves.easeOutBack,
|
||||
child: Container(
|
||||
width: 22,
|
||||
height: 22,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFF2F9E94),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.check_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user