0

Been stuck for hours lol

This started happening after I made changes to some files that had no global key in them and I just can't seem to understand the problem since I have tried to change the files that do use global keys and I just can not correct it. I am far from being experienced so probably the solution is easy, but still I tried and I still can't do it and would be very grateful if anyone could help me.

When I try to acess my deck_screen this happens :

The following assertion was thrown while finalizing the widget tree: Duplicate GlobalKey detected in widget tree.

and the screen doesn't open and just turns red.

//deck_screen.dart (doesn't contain Global Key see below code that does):

import 'package:flutter/material.dart';
import 'package:song/widgets/exercise_widget.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:song/core/providers/deck_provider.dart';
import 'package:song/screens/add_exercise.dart';

class DeckScreen extends ConsumerStatefulWidget {
  final String deckId;

  DeckScreen({required this.deckId});

  @override
  _DeckScreenState createState() => _DeckScreenState();
}

class _DeckScreenState extends ConsumerState<DeckScreen> {
  @override
  Widget build(BuildContext context) {
    final deck = ref.watch(deckProvider.select((state) => state.firstWhere((deck) => deck.id == widget.deckId)));
    final exercises = deck.exercises;

    return Scaffold(
      appBar: AppBar(
        title: Text(deck.name),
      ),
      body: ReorderableListView(
        onReorder: (int oldIndex, int newIndex) {
          ref.read(deckProvider.notifier).reorderExercises(deck.id, oldIndex, newIndex);
        },
        children: exercises.map((exercise) {
          return ExerciseWidget(
            key: ValueKey('${widget.deckId}_${exercise.id}'),
            exercise: exercise,
          );
        }).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => AddExercise(deckId: widget.deckId),
            ),
          );
        },
        child: Icon(Icons.add),
      ),
    );
  }
}


The global key isn't use there it is only used in these 2 files :

// exercise_form.dart

import 'package:flutter/material.dart';
import 'package:song/core/models/exercise.dart';
import 'package:song/core/models/exercise_types/fill_in_the_blank.dart';
import 'package:song/core/models/exercise_types/front_back.dart';
import 'package:song/core/models/exercise_types/multiple_choice.dart';
import 'package:song/widgets/type_forms/multiple_choice_form.dart';
import 'package:song/widgets/type_forms/fill_in_the_blank_form.dart';
import 'package:song/widgets/type_forms/front_back_form.dart';
import 'package:song/core/models/exercise.dart';
import 'package:song/widgets/type_forms/type_controllers.dart';


class ExerciseForm extends StatefulWidget {
  final Exercise exercise;
  final **GlobalKey<FormState> formKey;**
  final TypeControllers controllers;

  ExerciseForm({Key? key, required this.exercise, required this.formKey, required this.controllers}) : super(key: key);

  @override
  _ExerciseFormState createState() => _ExerciseFormState();
}

class _ExerciseFormState extends State<ExerciseForm> {
  TextEditingController? _questionController;
  TextEditingController? _answerController;

  @override
  void initState() {
    super.initState();
    _questionController = TextEditingController(text: widget.exercise.question);
    _answerController = TextEditingController(text: widget.exercise.answer);
  }

  @override
  void dispose() {
    _questionController?.dispose();
    _answerController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (widget.exercise is FillInTheBlank) {
      return Form(
        key: widget.formKey,
        child: FillInTheBlankForm(
          questionController: _questionController!,
          answerController: _answerController!,
        ),
      );
    } else if (widget.exercise is MultipleChoice) {
      return Form(
        key: widget.formKey,
        child: MultipleChoiceForm(
          questionController: _questionController!,
          answerController: _answerController!,
          choicesControllers: [], // you should initialize the list with the proper TextEditingController instances
        ),
      );
    } else if (widget.exercise is FrontBack) {
      return Form(
        key: widget.formKey,
        child: FrontBackForm(
          frontController: _questionController!,
          backController: _answerController!,
        ),
      );
    } else {
      // Render a default form or throw an exception for unsupported exercise types
      return Container();
    }
  }
}

//exercise_screen

import 'package:flutter/material.dart';
import 'package:song/core/models/exercise.dart';
import 'package:song/widgets/exercise_form.dart';
import 'package:song/core/models/exercise_types/front_back.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:song/widgets/type_forms/type_controllers.dart';
import 'package:song/core/providers/exercise_provider.dart';

class ExerciseScreen extends ConsumerStatefulWidget {
  final Exercise? exercise;

  ExerciseScreen({Key? key, this.exercise}) : super(key: key);

  @override
  _ExerciseScreenState createState() => _ExerciseScreenState();
}

class _ExerciseScreenState extends ConsumerState<ExerciseScreen> {
  **GlobalKey<FormState> _formKey = GlobalKey<FormState>();**
  TypeControllers? _controllers;

  @override
  void initState() {
    super.initState();
    _controllers = TypeControllers(
      questionController: TextEditingController(text: widget.exercise?.question ?? ''),
      answerController: TextEditingController(text: widget.exercise?.answer ?? ''),
    );
  }

  @override
  void dispose() {
    _controllers?.questionController.dispose();
    _controllers?.answerController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.exercise == null ? 'Create Exercise' : 'Edit Exercise'),
      ),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: ExerciseForm(
          exercise: widget.exercise ?? FrontBack(id: '', front: '', back: ''),
          formKey: _formKey,
          controllers: _controllers!,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {
            _formKey.currentState!.save();
            if (widget.exercise == null) {
              Exercise newExercise = FrontBack(id: '', front: _controllers!.questionController.text, back: _controllers!.answerController.text);
              ref.read(exerciseControllerProvider.notifier).addExercise(newExercise);
            } else {
              Exercise updatedExercise = widget.exercise!.copyWith(
                  question: _controllers!.questionController.text,
                  answer: _controllers!.answerController.text
              );
              ref.read(exerciseControllerProvider.notifier).editExercise(updatedExercise);
            }
            Navigator.pop(context);
          }
        },
        child: Icon(Icons.check),
      ),
    );
  }
}

I've tried to no sucess to change it. If you need to see any other files that may be involved I will post it. Thanks you for the help! rest of the error for more information : The following GlobalKey was specified multiple times in the widget tree. This will lead to parts of the widget tree being truncated unexpectedly, because the second time a key is seen, the previous instance is moved to the new location. The key was:

  • [GlobalKey#28607] This was determined by noticing that after the widget with the above global key was moved out of its previous parent, that previous parent never updated during this frame, meaning that it either did not update at all or updated before the widget was moved, in either case implying that it still thinks that it should have a child with that global key. The specific parent that did not update after having one or more children forcibly removed due to GlobalKey reparenting is:
  • IgnorePointer(ignoring: false, renderObject: RenderIgnorePointer#cbb1d NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE DETACHED) A GlobalKey can only be specified on one widget at a time in the widget tree.

0 Answers0