From ac7d5f39389b3b12bbc6bbfa3830647125cd8c60 Mon Sep 17 00:00:00 2001 From: ggurdin <46800240+ggurdin@users.noreply.github.com> Date: Mon, 31 Mar 2025 11:10:51 -0400 Subject: [PATCH] chore: replace future builder in morph edit widget to prevent infinite rebuild loop (#2273) --- .../morph_meaning_widget.dart | 4 +- .../widgets/word_zoom/morph_focus_widget.dart | 161 ++++++++++-------- 2 files changed, 87 insertions(+), 78 deletions(-) diff --git a/lib/pangea/analytics_details_popup/morph_meaning_widget.dart b/lib/pangea/analytics_details_popup/morph_meaning_widget.dart index 752f25b13..b4b1bb423 100644 --- a/lib/pangea/analytics_details_popup/morph_meaning_widget.dart +++ b/lib/pangea/analytics_details_popup/morph_meaning_widget.dart @@ -67,9 +67,7 @@ class MorphMeaningWidgetState extends State { } catch (e) { _error = e.toString(); } finally { - setState(() { - _isLoading = false; - }); + if (mounted) setState(() => _isLoading = false); } } diff --git a/lib/pangea/toolbar/widgets/word_zoom/morph_focus_widget.dart b/lib/pangea/toolbar/widgets/word_zoom/morph_focus_widget.dart index 93a3d739b..4747da0e2 100644 --- a/lib/pangea/toolbar/widgets/word_zoom/morph_focus_widget.dart +++ b/lib/pangea/toolbar/widgets/word_zoom/morph_focus_widget.dart @@ -53,27 +53,33 @@ class MorphFocusWidgetState extends State { /// the morphological tag that the user has selected in edit mode String selectedMorphTag = ""; + List morphFeatures = []; + final ScrollController _scrollController = ScrollController(); - void resetMorphTag() => setState( - () => selectedMorphTag = - widget.token.getMorphTag(widget.morphFeature) ?? "X", - ); - - @override - void didUpdateWidget(MorphFocusWidget oldWidget) { - if (widget.token != oldWidget.token || - widget.morphFeature != oldWidget.morphFeature) { - resetMorphTag(); - setState(() => editMode = false); - } - super.didUpdateWidget(oldWidget); + void resetMorphTag() { + setState( + () => selectedMorphTag = + widget.token.getMorphTag(widget.morphFeature) ?? "X", + ); } @override void initState() { super.initState(); resetMorphTag(); + _setAvailableMorphs(); + } + + @override + void didUpdateWidget(MorphFocusWidget oldWidget) { + if (widget.token != oldWidget.token || + widget.morphFeature != oldWidget.morphFeature) { + resetMorphTag(); + _setAvailableMorphs(); + setState(() => editMode = false); + } + super.didUpdateWidget(oldWidget); } @override @@ -90,6 +96,21 @@ class MorphFocusWidgetState extends State { PangeaMessageEvent get pm => widget.pangeaMessageEvent; + Future _setAvailableMorphs() async { + try { + final resp = await MorphsRepo.get(); + morphFeatures = resp.getDisplayTags( + widget.morphFeature.name, + ); + } catch (e) { + morphFeatures = defaultMorphMapping.getDisplayTags( + widget.morphFeature.name, + ); + } finally { + if (mounted) setState(() {}); + } + } + /// confirm the changes made by the user /// this will send a new message to the server /// with the new morphological tag @@ -230,73 +251,63 @@ class MorphFocusWidgetState extends State { textAlign: TextAlign.center, style: const TextStyle(fontStyle: FontStyle.italic), ), - FutureBuilder( - future: MorphsRepo.get(), - builder: (context, snapshot) { - final allMorphTagsForEdit = snapshot.data - ?.getDisplayTags(widget.morphFeature.name) ?? - defaultMorphMapping.getDisplayTags(widget.morphFeature.name); - - if (snapshot.connectionState == ConnectionState.waiting) { - return const CircularProgressIndicator(); - } - - return Wrap( - children: allMorphTagsForEdit.map((tag) { - return Container( - margin: const EdgeInsets.all(2), - padding: EdgeInsets.zero, - decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(10), + if (morphFeatures.isEmpty) + const CircularProgressIndicator() + else + Wrap( + children: morphFeatures.map((tag) { + return Container( + margin: const EdgeInsets.all(2), + padding: EdgeInsets.zero, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(10), + ), + border: Border.all( + color: selectedMorphTag == tag + ? Theme.of(context).colorScheme.primary + : Colors.transparent, + style: BorderStyle.solid, + width: 2.0, + ), + ), + child: TextButton( + style: ButtonStyle( + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric( + horizontal: 7, + ), ), - border: Border.all( - color: selectedMorphTag == tag - ? Theme.of(context).colorScheme.primary + backgroundColor: WidgetStateProperty.all( + selectedMorphTag == tag + ? Theme.of(context) + .colorScheme + .primary + .withAlpha(50) : Colors.transparent, - style: BorderStyle.solid, - width: 2.0, + ), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), ), ), - child: TextButton( - style: ButtonStyle( - padding: WidgetStateProperty.all( - const EdgeInsets.symmetric( - horizontal: 7, - ), - ), - backgroundColor: WidgetStateProperty.all( - selectedMorphTag == tag - ? Theme.of(context) - .colorScheme - .primary - .withAlpha(50) - : Colors.transparent, - ), - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - ), - onPressed: () { - setState(() => selectedMorphTag = tag); - }, - child: Text( - getGrammarCopy( - category: widget.morphFeature.name, - lemma: tag, - context: context, - ) ?? - tag, - textAlign: TextAlign.center, - ), + onPressed: () { + setState(() => selectedMorphTag = tag); + }, + child: Text( + getGrammarCopy( + category: widget.morphFeature.name, + lemma: tag, + context: context, + ) ?? + tag, + textAlign: TextAlign.center, ), - ); - }).toList(), - ); - }, - ), + ), + ); + }).toList(), + ), Row( mainAxisAlignment: MainAxisAlignment.center, spacing: 10,