Explorar o código

Simplify state management on search suggestion screen to get rid of an edge case bug + add comments + use better variable names

ashilkn hai 1 ano
pai
achega
234c1ad15e

+ 0 - 57
lib/states/search_results_state.dart

@@ -1,57 +0,0 @@
-import "package:flutter/cupertino.dart";
-import "package:photos/models/search/search_result.dart";
-import "package:photos/models/typedefs.dart";
-
-class SearchResultsProvider extends StatefulWidget {
-  final Widget child;
-  const SearchResultsProvider({
-    required this.child,
-    super.key,
-  });
-
-  @override
-  State<SearchResultsProvider> createState() => _SearchResultsProviderState();
-}
-
-class _SearchResultsProviderState extends State<SearchResultsProvider> {
-  Stream<List<SearchResult>>? searchResultsStream;
-  @override
-  Widget build(BuildContext context) {
-    return InheritedSearchResults(
-      searchResultsStream,
-      updateSearchResults,
-      child: widget.child,
-    );
-  }
-
-  void updateSearchResults(Stream<List<SearchResult>> newStream) {
-    setState(() {
-      print(
-        "_____updating stream from ${searchResultsStream.hashCode} to ${newStream.hashCode} in inherited widget",
-      );
-      searchResultsStream = null;
-      searchResultsStream = newStream;
-    });
-  }
-}
-
-class InheritedSearchResults extends InheritedWidget {
-  final Stream<List<SearchResult>>? searchResultsStream;
-  final VoidCallbackParamSearchResutlsStream updateStream;
-  const InheritedSearchResults(
-    this.searchResultsStream,
-    this.updateStream, {
-    required super.child,
-    super.key,
-  });
-
-  static InheritedSearchResults of(BuildContext context) {
-    return context
-        .dependOnInheritedWidgetOfExactType<InheritedSearchResults>()!;
-  }
-
-  @override
-  bool updateShouldNotify(covariant InheritedSearchResults oldWidget) {
-    return searchResultsStream != oldWidget.searchResultsStream;
-  }
-}

+ 78 - 81
lib/ui/tabs/home_widget.dart

@@ -33,7 +33,6 @@ import 'package:photos/services/local_sync_service.dart';
 import "package:photos/services/notification_service.dart";
 import "package:photos/services/notification_service.dart";
 import 'package:photos/services/update_service.dart';
 import 'package:photos/services/update_service.dart';
 import 'package:photos/services/user_service.dart';
 import 'package:photos/services/user_service.dart';
-import "package:photos/states/search_results_state.dart";
 import 'package:photos/states/user_details_state.dart';
 import 'package:photos/states/user_details_state.dart';
 import 'package:photos/theme/colors.dart';
 import 'package:photos/theme/colors.dart';
 import "package:photos/theme/effects.dart";
 import "package:photos/theme/effects.dart";
@@ -393,90 +392,88 @@ class _HomeWidgetState extends State<HomeWidget> {
             !LocalSyncService.instance.hasGrantedLimitedPermissions() &&
             !LocalSyncService.instance.hasGrantedLimitedPermissions() &&
             CollectionsService.instance.getActiveCollections().isEmpty;
             CollectionsService.instance.getActiveCollections().isEmpty;
 
 
-    return SearchResultsProvider(
-      child: Stack(
-        children: [
-          Builder(
-            builder: (context) {
-              return ExtentsPageView(
-                onPageChanged: (page) {
-                  Bus.instance.fire(
-                    TabChangedEvent(
-                      page,
-                      TabChangedEventSource.pageView,
-                    ),
-                  );
-                },
-                controller: _pageController,
-                openDrawer: Scaffold.of(context).openDrawer,
-                physics: const BouncingScrollPhysics(),
-                children: [
-                  _showShowBackupHook
-                      ? const StartBackupHookWidget(headerWidget: _headerWidget)
-                      : HomeGalleryWidget(
-                          header: _headerWidget,
-                          footer: const SizedBox(
-                            height: 160,
-                          ),
-                          selectedFiles: _selectedFiles,
-                        ),
-                  _userCollectionsTab,
-                  _sharedCollectionTab,
-                  _searchTab,
-                ],
-              );
-            },
-          ),
-          Align(
-            alignment: Alignment.bottomCenter,
-            child: ValueListenableBuilder(
-              valueListenable: isOnSearchTabNotifier,
-              builder: (context, value, child) {
-                return Container(
-                  decoration: value
-                      ? BoxDecoration(
-                          color: getEnteColorScheme(context).backgroundElevated,
-                          boxShadow: shadowFloatFaintLight,
-                        )
-                      : null,
-                  child: Column(
-                    mainAxisSize: MainAxisSize.min,
-                    children: [
-                      value
-                          ? const SearchWidget()
-                              .animate()
-                              .fadeIn(
-                                duration: const Duration(milliseconds: 225),
-                                curve: Curves.easeInOutSine,
-                              )
-                              .scale(
-                                begin: const Offset(0.8, 0.8),
-                                end: const Offset(1, 1),
-                                duration: const Duration(
-                                  milliseconds: 225,
-                                ),
-                                curve: Curves.easeInOutSine,
-                              )
-                              .slide(
-                                begin: const Offset(0, 0.4),
-                                curve: Curves.easeInOutSine,
-                                duration: const Duration(
-                                  milliseconds: 225,
-                                ),
-                              )
-                          : const SizedBox.shrink(),
-                      HomeBottomNavigationBar(
-                        _selectedFiles,
-                        selectedTabIndex: _selectedTabIndex,
-                      ),
-                    ],
+    return Stack(
+      children: [
+        Builder(
+          builder: (context) {
+            return ExtentsPageView(
+              onPageChanged: (page) {
+                Bus.instance.fire(
+                  TabChangedEvent(
+                    page,
+                    TabChangedEventSource.pageView,
                   ),
                   ),
                 );
                 );
               },
               },
-            ),
+              controller: _pageController,
+              openDrawer: Scaffold.of(context).openDrawer,
+              physics: const BouncingScrollPhysics(),
+              children: [
+                _showShowBackupHook
+                    ? const StartBackupHookWidget(headerWidget: _headerWidget)
+                    : HomeGalleryWidget(
+                        header: _headerWidget,
+                        footer: const SizedBox(
+                          height: 160,
+                        ),
+                        selectedFiles: _selectedFiles,
+                      ),
+                _userCollectionsTab,
+                _sharedCollectionTab,
+                _searchTab,
+              ],
+            );
+          },
+        ),
+        Align(
+          alignment: Alignment.bottomCenter,
+          child: ValueListenableBuilder(
+            valueListenable: isOnSearchTabNotifier,
+            builder: (context, value, child) {
+              return Container(
+                decoration: value
+                    ? BoxDecoration(
+                        color: getEnteColorScheme(context).backgroundElevated,
+                        boxShadow: shadowFloatFaintLight,
+                      )
+                    : null,
+                child: Column(
+                  mainAxisSize: MainAxisSize.min,
+                  children: [
+                    value
+                        ? const SearchWidget()
+                            .animate()
+                            .fadeIn(
+                              duration: const Duration(milliseconds: 225),
+                              curve: Curves.easeInOutSine,
+                            )
+                            .scale(
+                              begin: const Offset(0.8, 0.8),
+                              end: const Offset(1, 1),
+                              duration: const Duration(
+                                milliseconds: 225,
+                              ),
+                              curve: Curves.easeInOutSine,
+                            )
+                            .slide(
+                              begin: const Offset(0, 0.4),
+                              curve: Curves.easeInOutSine,
+                              duration: const Duration(
+                                milliseconds: 225,
+                              ),
+                            )
+                        : const SizedBox.shrink(),
+                    HomeBottomNavigationBar(
+                      _selectedFiles,
+                      selectedTabIndex: _selectedTabIndex,
+                    ),
+                  ],
+                ),
+              );
+            },
           ),
           ),
-        ],
-      ),
+        ),
+      ],
     );
     );
   }
   }
 
 

+ 16 - 29
lib/ui/viewer/search/search_suggestions.dart

@@ -30,43 +30,30 @@ class SearchSuggestionsWidget extends StatefulWidget {
 
 
 class _SearchSuggestionsWidgetState extends State<SearchSuggestionsWidget> {
 class _SearchSuggestionsWidgetState extends State<SearchSuggestionsWidget> {
   Stream<List<SearchResult>>? resultsStream;
   Stream<List<SearchResult>>? resultsStream;
-  final queueOfEvents = <List<SearchResult>>[];
+  final queueOfSearchResults = <List<SearchResult>>[];
   var searchResultWidgets = <Widget>[];
   var searchResultWidgets = <Widget>[];
   StreamSubscription<List<SearchResult>>? subscription;
   StreamSubscription<List<SearchResult>>? subscription;
   Timer? timer;
   Timer? timer;
 
 
-  // @override
-  // void didChangeDependencies() {
-  //   super.didChangeDependencies();
-
-  //   searchResultWidgets.clear();
-  //   releaseResources();
-  //   resultsStream = InheritedSearchResults.of(context).searchResultsStream;
-  //   subscription = resultsStream?.listen((event) {
-  //     if (event.isNotEmpty) {
-  //       //update a index value notifier for indexed stack here and rebuild the indexedStack widget.
-  //       //Also, add dependecy to inherited widget on changing stream in this widget and not on the serach tab.
-  //       queueOfEvents.add(event);
-  //     }
-  //   });
-  //   generateResultWidgetsInIntervalsFromQueue();
-  // }
-
   @override
   @override
   void initState() {
   void initState() {
     super.initState();
     super.initState();
     SearchWidgetState.searchResultsStreamNotifier.addListener(() {
     SearchWidgetState.searchResultsStreamNotifier.addListener(() {
-      final value = SearchWidgetState.searchResultsStreamNotifier.value;
+      final resultsStream = SearchWidgetState.searchResultsStreamNotifier.value;
+
       searchResultWidgets.clear();
       searchResultWidgets.clear();
       releaseResources();
       releaseResources();
-      resultsStream = value;
-      subscription = resultsStream?.listen((event) {
-        if (event.isNotEmpty) {
-          //update a index value notifier for indexed stack here and rebuild the indexedStack widget.
-          //Also, add dependecy to inherited widget on changing stream in this widget and not on the serach tab.
-          queueOfEvents.add(event);
-        }
+
+      subscription = resultsStream!.listen((searchResults) {
+        //Currently, we add searchResults even if the list is empty. So we are adding
+        //empty list to the queue, which will trigger rebuilds with no change in UI
+        //(see [generateResultWidgetsInIntervalsFromQueue]'s setState()).
+        //This is needed to clear the search results in this widget when the
+        //search bar is cleared, and the event fired by the stream will be an
+        //empty list. Can optimize rebuilds if there are performance issues in future.
+        queueOfSearchResults.add(searchResults);
       });
       });
+
       generateResultWidgetsInIntervalsFromQueue();
       generateResultWidgetsInIntervalsFromQueue();
     });
     });
   }
   }
@@ -81,8 +68,8 @@ class _SearchSuggestionsWidgetState extends State<SearchSuggestionsWidget> {
   ///generates the widgets and clears the queue and updates the UI.
   ///generates the widgets and clears the queue and updates the UI.
   void generateResultWidgetsInIntervalsFromQueue() {
   void generateResultWidgetsInIntervalsFromQueue() {
     timer = Timer.periodic(const Duration(milliseconds: 50), (timer) {
     timer = Timer.periodic(const Duration(milliseconds: 50), (timer) {
-      if (queueOfEvents.isNotEmpty) {
-        for (List<SearchResult> event in queueOfEvents) {
+      if (queueOfSearchResults.isNotEmpty) {
+        for (List<SearchResult> event in queueOfSearchResults) {
           for (SearchResult result in event) {
           for (SearchResult result in event) {
             searchResultWidgets.add(
             searchResultWidgets.add(
               SearchResultsWidgetGenerator(result).animate().fadeIn(
               SearchResultsWidgetGenerator(result).animate().fadeIn(
@@ -92,7 +79,7 @@ class _SearchSuggestionsWidgetState extends State<SearchSuggestionsWidget> {
             );
             );
           }
           }
         }
         }
-        queueOfEvents.clear();
+        queueOfSearchResults.clear();
         setState(() {});
         setState(() {});
       }
       }
     });
     });