diff --git a/lib/core/sdui/sdui_form_builder.dart b/lib/core/sdui/sdui_form_builder.dart index 0eeb1d8..5da85b5 100644 --- a/lib/core/sdui/sdui_form_builder.dart +++ b/lib/core/sdui/sdui_form_builder.dart @@ -137,9 +137,10 @@ class SduiFormBuilderState extends material.State { final path = picker != null ? await picker(field) : (await openFile())?.path; if (path == null || !mounted) return; - _textControllers[field.id]?.text = path; + setState(() { + _textControllers[field.id]?.text = path; + }); _notifyChanged(); - setState(() {}); } @override diff --git a/lib/features/connections/new_folder_dialog.dart b/lib/features/connections/new_folder_dialog.dart index 37c3753..513e7d2 100644 --- a/lib/features/connections/new_folder_dialog.dart +++ b/lib/features/connections/new_folder_dialog.dart @@ -80,7 +80,6 @@ class _NewFolderDialogContentState child: TextField( controller: _nameController, placeholder: const Text('Folder name'), - onChanged: (_) => setState(() {}), ), ), ], @@ -106,11 +105,14 @@ class _NewFolderDialogContentState child: const Text('Cancel'), ), const material.SizedBox(width: 12), - PrimaryButton( - onPressed: _name.isEmpty - ? null - : () => material.Navigator.of(context).pop(_name), - child: const Text('Create'), + ListenableBuilder( + listenable: _nameController, + builder: (context, _) => PrimaryButton( + onPressed: _name.isEmpty + ? null + : () => material.Navigator.of(context).pop(_name), + child: const Text('Create'), + ), ), ], ), diff --git a/lib/features/extensions/extension_stats_view.dart b/lib/features/extensions/extension_stats_view.dart index f7788a5..ed07fa7 100644 --- a/lib/features/extensions/extension_stats_view.dart +++ b/lib/features/extensions/extension_stats_view.dart @@ -104,7 +104,7 @@ class _ExtensionStatsViewState extends material.State { .getServerStats(widget.connectionRow); if (!mounted) return; if (!replaceIfChanged(_stats, stats, (v) => _stats = v)) return; - setState(() {}); + setState(() => _stats = stats); } catch (_) {} } diff --git a/lib/features/mongodb/mongo_database_dialog.dart b/lib/features/mongodb/mongo_database_dialog.dart index 2bb39f8..567f9af 100644 --- a/lib/features/mongodb/mongo_database_dialog.dart +++ b/lib/features/mongodb/mongo_database_dialog.dart @@ -26,14 +26,6 @@ class _CreateMongoDBDialogContentState extends material.State<_CreateMongoDBDialogContent> { final _nameController = material.TextEditingController(); - @override - void initState() { - super.initState(); - _nameController.addListener(_onFieldChanged); - } - - void _onFieldChanged() => setState(() {}); - bool get _formValid => _nameController.text.trim().isNotEmpty; void _save() { @@ -43,7 +35,6 @@ class _CreateMongoDBDialogContentState @override void dispose() { - _nameController.removeListener(_onFieldChanged); _nameController.dispose(); super.dispose(); } @@ -106,9 +97,12 @@ class _CreateMongoDBDialogContentState child: const Text('Cancel'), ), const Gap(12), - PrimaryButton( - onPressed: _formValid ? _save : null, - child: const Text('Create'), + ListenableBuilder( + listenable: _nameController, + builder: (context, _) => PrimaryButton( + onPressed: _formValid ? _save : null, + child: const Text('Create'), + ), ), ], ), diff --git a/lib/features/mysql/mysql_stats_view.dart b/lib/features/mysql/mysql_stats_view.dart index d281bb0..1c6c73a 100644 --- a/lib/features/mysql/mysql_stats_view.dart +++ b/lib/features/mysql/mysql_stats_view.dart @@ -126,7 +126,7 @@ class _MysqlStatsViewState extends material.State { final stats = await conn.serverStats(); if (!mounted) return; if (!replaceIfChanged(_stats, stats, (v) => _stats = v)) return; - setState(() {}); + setState(() => _stats = stats); } catch (_) {} } diff --git a/lib/features/postgresql/postgres_stats_view.dart b/lib/features/postgresql/postgres_stats_view.dart index 48cd198..08c3d73 100644 --- a/lib/features/postgresql/postgres_stats_view.dart +++ b/lib/features/postgresql/postgres_stats_view.dart @@ -143,7 +143,7 @@ class _PostgresStatsViewState extends material.State { final stats = await c.serverStats(); if (!mounted) return; if (!replaceIfChanged(_stats, stats, (v) => _stats = v)) return; - setState(() {}); + setState(() => _stats = stats); } catch (_) {} } diff --git a/lib/features/redis/redis_explorer_view.dart b/lib/features/redis/redis_explorer_view.dart index 48665b4..af037da 100644 --- a/lib/features/redis/redis_explorer_view.dart +++ b/lib/features/redis/redis_explorer_view.dart @@ -45,6 +45,7 @@ class _RedisExplorerViewState extends material.State { // View mode bool _showStats = false; + int _refreshEpoch = 0; // Navigation state String? _selectedKey; @@ -224,7 +225,7 @@ class _RedisExplorerViewState extends material.State { _BreadcrumbBar( crumbs: _crumbs, onCrumbTap: _onCrumbTap, - onRefresh: () => setState(() {}), + onRefresh: () => setState(() => _refreshEpoch++), onStats: () => setState(() => _showStats = true), ), const Divider(height: 1), @@ -238,7 +239,7 @@ class _RedisExplorerViewState extends material.State { // Key editor if (_selectedKey != null) { return RedisKeyEditor( - key: ValueKey('key_${widget.database}_$_selectedKey'), + key: ValueKey('key_${widget.database}_${_selectedKey}_$_refreshEpoch'), connection: conn, database: widget.database, keyName: _selectedKey!, @@ -250,7 +251,7 @@ class _RedisExplorerViewState extends material.State { // Keys list return RedisKeysView( - key: ValueKey('keys_${widget.database}'), + key: ValueKey('keys_${widget.database}_$_refreshEpoch'), connection: conn, database: widget.database, onKeyTap: _navigateToKey, diff --git a/lib/features/redis/redis_view.dart b/lib/features/redis/redis_view.dart index 4ffa5d0..d78a561 100644 --- a/lib/features/redis/redis_view.dart +++ b/lib/features/redis/redis_view.dart @@ -156,7 +156,7 @@ class _RedisViewState extends material.State { final info = parseRedisInfo(raw); if (!mounted) return; if (!replaceIfChanged(_info, info, (v) => _info = v)) return; - setState(() {}); + setState(() => _info = info); } catch (_) {} } diff --git a/lib/features/settings/preferences_appearance_section.dart b/lib/features/settings/preferences_appearance_section.dart index 1c0d93b..89ccc92 100644 --- a/lib/features/settings/preferences_appearance_section.dart +++ b/lib/features/settings/preferences_appearance_section.dart @@ -35,22 +35,6 @@ class _PreferencesAppearanceSectionState bool _installingFromUrl = false; bool _openingThemesFolder = false; - @override - void initState() { - super.initState(); - _controller.addListener(_onThemeChanged); - } - - @override - void dispose() { - _controller.removeListener(_onThemeChanged); - super.dispose(); - } - - void _onThemeChanged() { - if (mounted) setState(() {}); - } - Future _setThemeMode(ThemeMode mode) async { await _controller.setThemeMode(mode); } @@ -160,9 +144,12 @@ class _PreferencesAppearanceSectionState @override material.Widget build(material.BuildContext context) { - final c = _controller; - final themes = c.availableThemes; - final refreshingThemes = c.isLoadingAvailableThemes; + return ListenableBuilder( + listenable: _controller, + builder: (context, _) { + final c = _controller; + final themes = c.availableThemes; + final refreshingThemes = c.isLoadingAvailableThemes; return material.Column( crossAxisAlignment: material.CrossAxisAlignment.start, @@ -364,5 +351,7 @@ class _PreferencesAppearanceSectionState ), ], ); + }, +); } } diff --git a/lib/features/settings/preferences_controls.dart b/lib/features/settings/preferences_controls.dart index a897eaa..61817ed 100644 --- a/lib/features/settings/preferences_controls.dart +++ b/lib/features/settings/preferences_controls.dart @@ -205,7 +205,9 @@ class _InterfaceScaleSliderState extends material.State { void _onCommittedScaleChanged() { if (_dragScale != null || !mounted) return; - setState(() {}); + setState(() { + _dragScale = null; + }); } bool _onKeyEvent(KeyEvent event) { diff --git a/lib/features/settings/theme_picker_button.dart b/lib/features/settings/theme_picker_button.dart index 01b8cea..30cdd59 100644 --- a/lib/features/settings/theme_picker_button.dart +++ b/lib/features/settings/theme_picker_button.dart @@ -174,8 +174,12 @@ class _ThemePickerButtonState extends material.State { }); } + String _searchQuery = ''; + void _onSearchChanged() { - setState(() {}); + setState(() { + _searchQuery = _searchController.text; + }); if (_scrollController.hasClients) { _scrollController.jumpTo(0); } @@ -187,7 +191,7 @@ class _ThemePickerButtonState extends material.State { } List get _filteredThemes => - filterThemeDefinitions(widget.themes, _searchController.text); + filterThemeDefinitions(widget.themes, _searchQuery); bool get _enabled => !widget.isLoading; diff --git a/lib/features/updater/update_available_badge.dart b/lib/features/updater/update_available_badge.dart index 832de9b..d776225 100644 --- a/lib/features/updater/update_available_badge.dart +++ b/lib/features/updater/update_available_badge.dart @@ -63,7 +63,6 @@ class UpdateAvailableBadgeState extends material.State void _onControllerChanged() { if (!mounted) return; - setState(() {}); _syncPulse(); } @@ -100,9 +99,12 @@ class UpdateAvailableBadgeState extends material.State @override material.Widget build(material.BuildContext context) { - if (!widget.controller.showBadge) { - return const material.SizedBox.shrink(); - } + return ListenableBuilder( + listenable: widget.controller, + builder: (context, _) { + if (!widget.controller.showBadge) { + return const material.SizedBox.shrink(); + } final version = widget.controller.pendingUpdate?.version ?? ''; final wb = context.workbench; @@ -160,5 +162,7 @@ class UpdateAvailableBadgeState extends material.State ), ), ); + }, +); } } diff --git a/lib/shared/widgets/querya_tab_strip.dart b/lib/shared/widgets/querya_tab_strip.dart index d91709b..688d35b 100644 --- a/lib/shared/widgets/querya_tab_strip.dart +++ b/lib/shared/widgets/querya_tab_strip.dart @@ -251,7 +251,7 @@ class _QueryaTabStripState extends material.State } /// Sliding pill; listens to springs so the tab [Row] is not rebuilt per tick. -class _TabStripIndicator extends material.StatefulWidget { +class _TabStripIndicator extends material.StatelessWidget { const _TabStripIndicator({ required this.left, required this.width, @@ -262,63 +262,31 @@ class _TabStripIndicator extends material.StatefulWidget { final QueryaSpringController width; final material.Color color; - @override - material.State<_TabStripIndicator> createState() => - _TabStripIndicatorState(); -} - -class _TabStripIndicatorState extends material.State<_TabStripIndicator> { - @override - void initState() { - super.initState(); - widget.left.addListener(_onTick); - widget.width.addListener(_onTick); - } - - @override - void didUpdateWidget(covariant _TabStripIndicator oldWidget) { - super.didUpdateWidget(oldWidget); - if (oldWidget.left != widget.left) { - oldWidget.left.removeListener(_onTick); - widget.left.addListener(_onTick); - } - if (oldWidget.width != widget.width) { - oldWidget.width.removeListener(_onTick); - widget.width.addListener(_onTick); - } - } - - @override - void dispose() { - widget.left.removeListener(_onTick); - widget.width.removeListener(_onTick); - super.dispose(); - } - - void _onTick() { - if (mounted) setState(() {}); - } - @override material.Widget build(material.BuildContext context) { - final w = widget.width.value; - if (w <= 0) return const material.SizedBox.shrink(); - return material.Positioned( - key: const material.ValueKey('querya_tab_indicator'), - left: widget.left.value, - width: w, - top: 0, - bottom: 0, - child: material.RepaintBoundary( - child: material.IgnorePointer( - child: material.DecoratedBox( - decoration: material.BoxDecoration( - color: widget.color, - borderRadius: material.BorderRadius.circular(6), + return ListenableBuilder( + listenable: Listenable.merge([left, width]), + builder: (context, _) { + final w = width.value; + if (w <= 0) return const material.SizedBox.shrink(); + return material.Positioned( + key: const material.ValueKey('querya_tab_indicator'), + left: left.value, + width: w, + top: 0, + bottom: 0, + child: material.RepaintBoundary( + child: material.IgnorePointer( + child: material.DecoratedBox( + decoration: material.BoxDecoration( + color: color, + borderRadius: material.BorderRadius.circular(6), + ), + ), ), ), - ), - ), + ); + }, ); } }