CTK 1.0.2
This commit is contained in:
@@ -83,7 +83,7 @@ class Quiz1Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 1/28',
|
||||
title: 'Quiz 1/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'O seu filho/a tem problemas respiratórios diagnosticados?',
|
||||
answers: const [
|
||||
@@ -127,7 +127,7 @@ class Quiz2Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 2/28',
|
||||
title: 'Quiz 2/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
question: 'O seu filho/a respira habitualmente pela boca?',
|
||||
answers: const [
|
||||
@@ -171,7 +171,7 @@ class Quiz3Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 3/28',
|
||||
title: 'Quiz 3/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'O seu filho/a ressona habitualmente durante a noite?',
|
||||
answers: const [
|
||||
@@ -215,7 +215,7 @@ class Quiz4Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 4/28',
|
||||
title: 'Quiz 4/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'O seu filho/a sente habitualmente o nariz "tapado"?',
|
||||
answers: const [
|
||||
@@ -259,7 +259,7 @@ class Quiz5Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 5/28',
|
||||
title: 'Quiz 5/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question:
|
||||
'Durante o sono, o seu filho/a tem habitualmente interrupções da respiração?',
|
||||
@@ -305,7 +305,7 @@ class Quiz6Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 6/28',
|
||||
title: 'Quiz 6/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
question: 'O seu filho/a range os dentes com frequência?',
|
||||
answers: const [
|
||||
@@ -342,7 +342,7 @@ class Quiz7Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 7/28',
|
||||
title: 'Quiz 7/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'O seu filho/a habitualmente tem alergias sazonais?',
|
||||
answers: const [
|
||||
@@ -386,7 +386,7 @@ class Quiz8Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 8/28',
|
||||
title: 'Quiz 8/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'O seu filho/a acorda com saliva seca na cara ou na almofada?',
|
||||
answers: const [
|
||||
@@ -430,7 +430,7 @@ class Quiz9Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 9/28',
|
||||
title: 'Quiz 9/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
question: 'O seu filho/a teve ou costuma ter com frequência otites?',
|
||||
answers: const [
|
||||
@@ -474,7 +474,7 @@ class Quiz10Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 10/28',
|
||||
title: 'Quiz 10/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'O seu filho/a teve ou costuma ter com frequência amigdalites?',
|
||||
answers: const [
|
||||
@@ -518,7 +518,7 @@ class Quiz11Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 11/28',
|
||||
title: 'Quiz 11/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
question:
|
||||
'O seu filho/a teve ou costuma ter com frequência bronquiolites?',
|
||||
@@ -563,7 +563,7 @@ class Quiz12Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 12/28',
|
||||
title: 'Quiz 12/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'O seu filho/a apresenta dificuldades a mastigar?',
|
||||
answers: const [
|
||||
@@ -600,7 +600,7 @@ class Quiz13Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 13/28',
|
||||
title: 'Quiz 13/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
question: 'O seu filho/a habitualmente é lento a comer?',
|
||||
answers: const [
|
||||
@@ -637,7 +637,7 @@ class Quiz14Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 14/28',
|
||||
title: 'Quiz 14/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'O seu filho/a habitualmente prefere comer alimentos moles?',
|
||||
answers: const [
|
||||
@@ -674,7 +674,7 @@ class Quiz15Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 15/28',
|
||||
title: 'Quiz 15/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'Em bebé apenas foi alimentado por biberão?',
|
||||
answers: const [
|
||||
@@ -718,7 +718,7 @@ class Quiz16Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 16/28',
|
||||
title: 'Quiz 16/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
question: 'O seu filho/a usa ou usou chupeta com frequência?',
|
||||
answers: const [
|
||||
@@ -762,7 +762,7 @@ class Quiz17Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 17/28',
|
||||
title: 'Quiz 17/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question: 'O seu filho/a chucha ou já chuchou o dedo com frequência?',
|
||||
answers: const [
|
||||
@@ -814,7 +814,7 @@ class Quiz18Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 18/28',
|
||||
title: 'Quiz 18/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
answerImageAspectRatio: 1.5,
|
||||
question:
|
||||
@@ -857,7 +857,7 @@ class Quiz19Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 19/28',
|
||||
title: 'Quiz 19/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question:
|
||||
'Qual das seguintes imagens é mais parecida com o perfil do seu filho/a?',
|
||||
@@ -919,7 +919,7 @@ class Quiz20Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 20/28',
|
||||
title: 'Quiz 20/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
question: 'Qual é a posição da boca do seu filho/a habitualmente?',
|
||||
answers: [
|
||||
@@ -964,7 +964,7 @@ class Quiz21Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 21/28',
|
||||
title: 'Quiz 21/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question:
|
||||
'Qual das imagens, na zona abaixo dos olhos, se assemelha mais ao seu filho/a?',
|
||||
@@ -1014,7 +1014,7 @@ class Quiz22Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 22/28',
|
||||
title: 'Quiz 22/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
isSignQuestion: true,
|
||||
question:
|
||||
@@ -1070,12 +1070,20 @@ class Quiz23Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 23/28',
|
||||
title: 'Quiz 23/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
isSignQuestion: true,
|
||||
question:
|
||||
'Qual das seguintes imagens se assemelha à boca do seu filho/a?',
|
||||
answers: const [
|
||||
QuizAnswer(
|
||||
title: 'Dentição sobreposta',
|
||||
description: 'Dentes sobrepostos/tortos',
|
||||
weight: 2,
|
||||
hideTitle: true,
|
||||
value: 'dentes_sobrepostos',
|
||||
imagePath: 'assets/mockup_images/10.png',
|
||||
),
|
||||
QuizAnswer(
|
||||
title: 'Dentição alinhada',
|
||||
description: 'Dentição bem alinhada, sem apinhamento',
|
||||
@@ -1092,14 +1100,6 @@ class Quiz23Screen extends StatelessWidget {
|
||||
value: 'dentes_desalinhados',
|
||||
imagePath: 'assets/mockup_images/13.png',
|
||||
),
|
||||
QuizAnswer(
|
||||
title: 'Dentição sobreposta',
|
||||
description: 'Dentes sobrepostos/tortos',
|
||||
weight: 2,
|
||||
hideTitle: true,
|
||||
value: 'dentes_sobrepostos',
|
||||
imagePath: 'assets/mockup_images/10.png',
|
||||
),
|
||||
],
|
||||
currentScore: currentScore,
|
||||
nextRoute: (context, nextScore) => quizPageRoute(
|
||||
@@ -1121,7 +1121,7 @@ class Quiz24Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 24/28',
|
||||
title: 'Quiz 24/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
isSignQuestion: true,
|
||||
question:
|
||||
@@ -1172,7 +1172,7 @@ class Quiz25Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 25/28',
|
||||
title: 'Quiz 25/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question:
|
||||
'Qual das seguintes imagens se assemelha ao freio labial do seu filho/a?',
|
||||
@@ -1214,7 +1214,7 @@ class Quiz26Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 26/28',
|
||||
title: 'Quiz 26/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
question:
|
||||
'Qual das seguintes imagens se assemelha ao freio lingual do seu filho/a?',
|
||||
@@ -1256,7 +1256,58 @@ class Quiz27Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 27/28',
|
||||
title: 'Quiz 27/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
isSignQuestion: true,
|
||||
question:
|
||||
'Qual das seguintes imagens se assemelha com a boca do seu filho/a?',
|
||||
answers: const [
|
||||
QuizAnswer(
|
||||
title: 'Dentição desalinhada',
|
||||
description: 'Dentição desalinhada/apinhada',
|
||||
weight: 2,
|
||||
hideTitle: true,
|
||||
value: 'dentes_desalinhados_3',
|
||||
imagePath: 'assets/mockup_images/23.JPEG',
|
||||
),
|
||||
QuizAnswer(
|
||||
title: 'Dentição sobreposta',
|
||||
description: 'Dentes sobrepostos/tortos',
|
||||
weight: 2,
|
||||
hideTitle: true,
|
||||
value: 'dentes_sobrepostos_3',
|
||||
imagePath: 'assets/mockup_images/24.png',
|
||||
),
|
||||
QuizAnswer(
|
||||
title: 'Dentição alinhada',
|
||||
description: 'Dentição bem alinhada, sem apinhamento',
|
||||
weight: 1,
|
||||
hideTitle: true,
|
||||
value: 'dentes_alinhados_3',
|
||||
imagePath: 'assets/mockup_images/25.jpg',
|
||||
),
|
||||
],
|
||||
currentScore: currentScore,
|
||||
nextRoute: (context, nextScore) => quizPageRoute(
|
||||
builder: (_) => Quiz28Screen(currentScore: nextScore, scopeId: scopeId),
|
||||
),
|
||||
answerType: QuizAnswerType.image,
|
||||
showBackButton: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Quiz 28: Boca / dentição 2 (Image-choice)
|
||||
class Quiz28Screen extends StatelessWidget {
|
||||
const Quiz28Screen({super.key, required this.currentScore, this.scopeId});
|
||||
|
||||
final QuizScore currentScore;
|
||||
final String? scopeId;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 28/29',
|
||||
fallbackColor: const Color(0xFF2F9E94),
|
||||
isSignQuestion: true,
|
||||
question:
|
||||
@@ -1281,7 +1332,7 @@ class Quiz27Screen extends StatelessWidget {
|
||||
],
|
||||
currentScore: currentScore,
|
||||
nextRoute: (context, nextScore) => quizPageRoute(
|
||||
builder: (_) => Quiz28Screen(currentScore: nextScore, scopeId: scopeId),
|
||||
builder: (_) => Quiz29Screen(currentScore: nextScore, scopeId: scopeId),
|
||||
),
|
||||
answerType: QuizAnswerType.image,
|
||||
showBackButton: true,
|
||||
@@ -1289,9 +1340,9 @@ class Quiz27Screen extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// Quiz 28: Céu da boca (Image-choice, final)
|
||||
class Quiz28Screen extends StatelessWidget {
|
||||
const Quiz28Screen({super.key, required this.currentScore, this.scopeId});
|
||||
// Quiz 29: Céu da boca (Image-choice, final)
|
||||
class Quiz29Screen extends StatelessWidget {
|
||||
const Quiz29Screen({super.key, required this.currentScore, this.scopeId});
|
||||
|
||||
final QuizScore currentScore;
|
||||
final String? scopeId;
|
||||
@@ -1299,9 +1350,10 @@ class Quiz28Screen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return QuizQuestionScreen(
|
||||
title: 'Quiz 28/28',
|
||||
title: 'Quiz 29/29',
|
||||
fallbackColor: const Color(0xFFFF55A7),
|
||||
isSignQuestion: true,
|
||||
correctBadgeLabel: 'Posição saudável',
|
||||
question:
|
||||
'Qual das seguintes imagens se assemelha ao céu da boca do seu filho/a?',
|
||||
answers: const [
|
||||
|
||||
@@ -82,6 +82,7 @@ class QuizQuestionScreen extends StatefulWidget {
|
||||
this.suggestedVideoTitle,
|
||||
this.fallbackColor,
|
||||
this.answerImageAspectRatio,
|
||||
this.correctBadgeLabel = 'Posição certa',
|
||||
});
|
||||
|
||||
final String title;
|
||||
@@ -115,6 +116,11 @@ class QuizQuestionScreen extends StatefulWidget {
|
||||
/// imagem colapsar, mostra-se um bloco colorido com o ícone da app.
|
||||
final Color? fallbackColor;
|
||||
|
||||
/// Texto do selo mostrado sobre a imagem certa ao revelar a resposta —
|
||||
/// customizável por pergunta (ex.: "Posição saudável" em vez do genérico
|
||||
/// "Posição certa", quando faz mais sentido para o contexto da pergunta).
|
||||
final String correctBadgeLabel;
|
||||
|
||||
@override
|
||||
State<QuizQuestionScreen> createState() => _QuizQuestionScreenState();
|
||||
}
|
||||
@@ -445,6 +451,8 @@ class _QuizQuestionScreenState extends State<QuizQuestionScreen> {
|
||||
? 2.3
|
||||
: 1.5),
|
||||
reveal: _revealed,
|
||||
correctLabel: widget
|
||||
.correctBadgeLabel,
|
||||
onTap: _revealed
|
||||
? null
|
||||
: () =>
|
||||
@@ -820,6 +828,7 @@ class _QuizAnswerTile extends StatelessWidget {
|
||||
required this.onTap,
|
||||
this.imageAspectRatio = 4 / 3,
|
||||
this.reveal = false,
|
||||
this.correctLabel = 'Posição certa',
|
||||
});
|
||||
|
||||
final QuizAnswer answer;
|
||||
@@ -831,6 +840,10 @@ class _QuizAnswerTile extends StatelessWidget {
|
||||
/// errada — ver [_QuizQuestionScreenState._revealed].
|
||||
final bool reveal;
|
||||
|
||||
/// Texto do selo quando [isCorrect] — customizável por pergunta (ex.:
|
||||
/// "Posição saudável" em vez do genérico "Posição certa").
|
||||
final String correctLabel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool isCorrect = answer.weight == 1;
|
||||
@@ -991,7 +1004,7 @@ class _QuizAnswerTile extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
isCorrect ? 'Resposta certa' : 'Resposta inadequada',
|
||||
isCorrect ? correctLabel : 'Posição inadequada',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w800,
|
||||
|
||||
@@ -13,11 +13,12 @@ import 'quiz_video_guide.dart';
|
||||
|
||||
const String _resultGuideYoutubeId = '3q7C7txH1dE';
|
||||
|
||||
// Fase 3 tem 28 perguntas no total: 5 são sinais de má oclusão já
|
||||
// instalados (queixo, boca/dentição, apinhamento, boca/dentição 2, céu da
|
||||
// boca) — as restantes 23 são fatores de risco associados. Ver o diagrama
|
||||
// de planeamento partilhado com o utilizador para o racional completo.
|
||||
const int kSignsMax = 5;
|
||||
// Fase 3 tem 29 perguntas no total: 6 são sinais de má oclusão já
|
||||
// instalados (queixo, boca/dentição, apinhamento, boca/dentição 2,
|
||||
// boca/dentição 3, céu da boca) — as restantes 23 são fatores de risco
|
||||
// associados. Ver o diagrama de planeamento partilhado com o utilizador
|
||||
// para o racional completo.
|
||||
const int kSignsMax = 6;
|
||||
const int kFactorsMax = 23;
|
||||
|
||||
/// A partir de quantos sinais/fatores presentes se recomenda avaliação.
|
||||
@@ -73,13 +74,16 @@ class _QuizResultScreenState extends State<QuizResultScreen> {
|
||||
scope.startsWith('${userId}_')) {
|
||||
final childId = scope.substring(userId.length + 1).trim();
|
||||
if (childId.isNotEmpty) {
|
||||
// Fire-and-forget: avoid blocking UI on erros de rede. Requer as
|
||||
// Aguarda a gravação (em vez de fire-and-forget) para que, ao voltar
|
||||
// à Home logo a seguir, _loadQuizResult já encontre o valor novo na
|
||||
// base de dados — caso contrário havia uma corrida em que a Home
|
||||
// consultava a tabela antes desta escrita terminar, mostrando o
|
||||
// resultado antigo até trocar de aba ou reabrir a app. Requer as
|
||||
// colunas last_signs/last_signs_max/last_factors/last_factors_max
|
||||
// na tabela children — se ainda não existirem na base de dados,
|
||||
// esta chamada falha silenciosamente e o resultado fica só local
|
||||
// (SharedPreferences, acima), tal como já acontecia antes.
|
||||
unawaited(
|
||||
supabase
|
||||
// na tabela children — se ainda não existirem, falha silenciosamente
|
||||
// e o resultado fica só local (SharedPreferences, acima).
|
||||
try {
|
||||
await supabase
|
||||
.from('children')
|
||||
.update({
|
||||
'last_signs': widget.finalScore.signs,
|
||||
@@ -87,13 +91,12 @@ class _QuizResultScreenState extends State<QuizResultScreen> {
|
||||
'last_factors': widget.finalScore.factors,
|
||||
'last_factors_max': kFactorsMax,
|
||||
})
|
||||
.eq('id', childId)
|
||||
.catchError((e) {
|
||||
debugPrint(
|
||||
'[QuizResult] Falha ao gravar score na base de dados: $e',
|
||||
);
|
||||
}),
|
||||
);
|
||||
.eq('id', childId);
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'[QuizResult] Falha ao gravar score na base de dados: $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +115,11 @@ class _QuizResultScreenState extends State<QuizResultScreen> {
|
||||
'de leite como de permanentes).\n\nO seu propósito é '
|
||||
'identificar, prevenir ou reduzir a gravidade de maloclusões '
|
||||
'e problemas no desenvolvimento dos maxilares enquanto os '
|
||||
'ossos e dentes ainda estão em crescimento.',
|
||||
'ossos e dentes ainda estão em crescimento.\n\nEsta '
|
||||
'intervenção aproveita a fase de desenvolvimento craniofacial '
|
||||
'para influenciar o crescimento ósseo, redirecionar a '
|
||||
'mandíbula, corrigir o alinhamento dos maxilares ou criar '
|
||||
'espaço para a erupção correta dos dentes permanentes.',
|
||||
onAdvance: (context) =>
|
||||
Navigator.of(context).popUntil((r) => r.isFirst),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user