I am building a basic emoji guessing app where when we click on a button having a letter, it gets transferred to the answer box and when we click on a answer box having a letter, the letter moves back. Here we also have a list cards clicking on which we can enter in different quizes. I have a icon in that card which is initially a play icon which should be update to check icon when a quiz is completed, but is not getting updated. When a quiz is completed, and we click the restart button, it firstly shows up play button only. Now if we refresh the page, then it shows tick. The problem lies with state management only I guess. I have used provider in this.
This is the widget for keyboard in quiz screen :
import 'package:flutter/material.dart';
import 'package:new_app/widgets/char_box.dart';
class KeyboardArea extends StatelessWidget {
const KeyboardArea({super.key, required this.quizIndex});
final int quizIndex;
@override
Widget build(BuildContext context) {
return Column(
children: [
for (int i = 0; i < 3; i++)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (int j = 0; j < 7; j++)
Padding(
padding: const EdgeInsets.all(6.0),
child: CharBox(
boxIndex: 7 * i + j,
quizIndex: quizIndex,
type: "key",
),
),
],
)
],
);
}
}
This is the widget for the box having the letter:
import 'package:flutter/material.dart';
// import 'package:new_app/data_models/quiz.dart';
import 'package:new_app/providers/quiz_model.dart';
import 'package:new_app/widgets/modal_content.dart';
import 'package:provider/provider.dart';
class CharBox extends StatelessWidget {
const CharBox({
super.key,
required this.boxIndex, // representing the index of box
required this.quizIndex, // representing the index of quiz
required this.type,
this.activeColor = const Color.fromARGB(255, 4, 96, 209),
});
final int quizIndex, boxIndex;
final String type; final Color activeColor;
void onPressedKey(BuildContext context) {
// context.read<QuizModel>().onPressKey(boxIndex);
final Widget popUp;
bool isComplete = context.read<QuizModel>().onPressKey(boxIndex);
if (isComplete) {
bool isWin = context.read<QuizModel>().checkIsWon(quizIndex);
if (isWin) {
popUp = ModalContent(
text: 'YOU WON!!!',
bgColor: const Color.fromARGB(255, 93, 207, 56),
reloadQuiz: () {
// context.watch<QuizModel>().quizData[quizIndex].isComplete = true;
},
);
} else {
popUp = ModalContent(
reloadQuiz: () {
context
.read<QuizModel>()
.answerArrayInitialiser(quizIndex, isNotify: true);
context
.read<QuizModel>()
.keyboardArrayInitialiser(quizIndex, isNotify: true);
},
text: "YOU LOOSE!!!",
bgColor: const Color.fromARGB(255, 238, 62, 62),
);
}
showDialog(
context: context,
builder: (cntx) {
return popUp;
});
}
}
@override
Widget build(BuildContext context) {
final Color deactiveColor = activeColor.withOpacity(0.2);
final Color bgColor;
final void Function()? onPressed;
if (type == "answer") {
if (context.read<QuizModel>().answerArray![boxIndex] == ' ') {
onPressed = null;
bgColor = deactiveColor;
} else {
bgColor = activeColor;
onPressed = () => context.read<QuizModel>().onPressAnswer(boxIndex);
}
} else {
if (context.read<QuizModel>().keyboardArray![boxIndex] == ' ') {
onPressed = null;
bgColor = deactiveColor;
} else {
bgColor = activeColor;
onPressed = () => onPressedKey(context);
}
}
final String ch;
if (type == "answer") {
ch = context.watch<QuizModel>().answerArray![boxIndex];
} else {
ch = context.watch<QuizModel>().keyboardArray![boxIndex];
}
return SizedBox(
height: 40,
width: 40,
child: ElevatedButton(
onPressed: onPressed,
style: ButtonStyle(
shape: const MaterialStatePropertyAll(RoundedRectangleBorder()),
backgroundColor: MaterialStatePropertyAll(bgColor)),
child: Text(
ch,
style: const TextStyle(color: Colors.white),
),
),
);
}
}
This is the modal which is popping up for restart button:
import 'package:flutter/material.dart';
class ModalContent extends StatelessWidget {
const ModalContent(
{super.key,
required this.reloadQuiz,
required this.text,
required this.bgColor});
final Function() reloadQuiz;
final String text;
final Color bgColor;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(
text,
textAlign: TextAlign.center,
),
backgroundColor: bgColor,
actions: [
OutlinedButton(
onPressed: () {
reloadQuiz();
Navigator.pop(context);
},
child: const Text("Replay")),
ElevatedButton(
onPressed: () {
Navigator.popUntil(
context, ModalRoute.withName("/PuzzleListPage"));
},
child: const Text("New Puzzle"))
],
);
}
}
Also the Quiz card widget is :
import 'package:flutter/material.dart';
// import 'package:new_app/data_models/quiz.dart';
import 'package:new_app/providers/quiz_model.dart';
import 'package:new_app/screens/puzzle_screen.dart';
import 'package:new_app/widgets/image_box.dart';
import 'package:provider/provider.dart';
class QuizCard extends StatelessWidget {
const QuizCard({super.key, required this.index});
// final Quiz quiz;
final int index;
@override
Widget build(BuildContext context) {
// final Icon quizIcon =
// Provider.of<QuizModel>(context, listen: true).quizData[index].isComplete
// ? const Icon(Icons.check)
// : const Icon(Icons.play_arrow);
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return PuzzleScreen(
quiz: context.read<QuizModel>().quizData[index],
quizIndex: index,
);
}),
);
},
splashColor: Colors.white,
borderRadius: BorderRadius.circular(14),
child: Card(
color: const Color.fromARGB(216, 195, 238, 226),
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(18.0),
child: Consumer<QuizModel>(
builder: (context, quizModel, child) {
if (quizModel.isComplete[index]) {
return const Icon(Icons.check);
}
return const Icon(Icons.play_arrow);
},
)),
Padding(
padding: const EdgeInsets.all(18.0),
child: Text(
'Puzzle ${context.watch<QuizModel>().quizData[index].id}',
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Expanded(
child: ImageBox(
images: context.watch<QuizModel>().quizData[index].images)),
],
),
),
);
}
}
And the providor is :
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:new_app/data/quiz_data.dart';
import 'package:new_app/data_models/quiz.dart';
class QuizModel with ChangeNotifier {
List<Quiz> quizData = quizes;
List<String>? keyboardArray;
List<String>? answerArray;
List<bool> get isComplete{
return List.generate(quizes.length, (index) => false);
}
List<String> _randomCreator(String answer) {
const String alps = "abcdefghijklmnopqrstuvwxyz";
List<String> ranStr =
List.generate(21, (int index) => alps[Random().nextInt(26)]);
List<int> charChanged = [-1];
for (int i = 0; i < answer.length; i++) {
if (answer[i] != ' ') {
int k = Random().nextInt(21);
while (charChanged.contains(k)) {
k = Random().nextInt(21);
}
charChanged.add(k);
ranStr[k] = answer[i];
}
}
return ranStr;
}
void keyboardArrayInitialiser(int quizIndex, {bool isNotify = false}) {
keyboardArray = _randomCreator(quizData[quizIndex].answer);
if (isNotify) notifyListeners();
}
void answerArrayInitialiser(int quizIndex, {bool isNotify = false}) {
answerArray =
List.generate(quizData[quizIndex].answer.length, (index) => " ");
for (int i = 0; i < quizData[quizIndex].answer.length; i++) {
if (quizData[quizIndex].answer[i] == ' ') {
answerArray![i] = '-';
}
}
if (isNotify) notifyListeners();
}
bool onPressKey(int keyIndex) {
// return true if quiz is complete else false
int i;
for (i = 0; i < answerArray!.length; i++) {
if (answerArray![i] == " ") {
answerArray![i] = keyboardArray![keyIndex];
keyboardArray![keyIndex] = " ";
break;
}
}
notifyListeners();
for (; i < answerArray!.length; i++) {
if (answerArray![i] == " ") {
return false;
}
}
return true;
}
void onPressAnswer(int answerIndex) {
int i;
for (i = 0; i < keyboardArray!.length; i++) {
if (keyboardArray![i] == " ") {
keyboardArray![i] = answerArray![answerIndex];
answerArray![answerIndex] = " ";
break;
}
}
notifyListeners();
}
bool isWon(int quizIndex) {
// notifyListeners();
return quizData[quizIndex].isComplete;
}
bool checkIsWon(int quizIndex) {
bool isWon = true;
for (int i = 0; i < quizData[quizIndex].answer.length; i++) {
if (!(quizData[quizIndex].answer[i] == ' ' ||
quizData[quizIndex].answer[i] == answerArray![i])) {
isWon = false;
}
}
if(isWon) isComplete[quizIndex] = true;
notifyListeners();
return isWon;
}
}
Please look into this and help.
When we click the restart button, the previous page should get refreshed.