Preserving the State of a Drawer in Flutter - flutter

I have a stateful Scaffold widget, where the body contains a list of entities with various properties (e.g. shoes or cars) and Drawer widget, which is empty at first, except for two buttons at the bottom ("Cancel" and "Filter") and a FAB. The user can add various filters with the FAB (e.g. the user can add a shoesize-filter, or a color-filter).
The problem I have is the following: Let's say the user selects various filters and works with them (i.e. ticks checkboxes, enters a shoesize, changes sliders, etc.). When the user is ready to apply the filters, he can click the "Filter" button, which closes the Drawer (onTap -> callback -> Navigator.of(context).pop()). But when the user wants to go back, reopen the Drawer, and adjust one of the filters, it obviously doesn't work, since the widget is being rebuilt from scratch.
Currently, the way the filtering works is, once the "Filter" Button is pressed, all the various values from the added filters are collected into an object FilterPackage, which is then passed via callback to the Scaffold widget, which then applies the values from the FilterPackage to the list of entities.
One solution I came up with, would be feeding this FilterPackage object to the Drawer widget in its constructor, which would provide all the information necessary to rebuild the widget just how it has to be.
Is that a reasonable solution? I have already made some research, but struggled finding a solution on what would clearly be the best and recommended way to preserve the drawer's state. Using PageStorage / PageStorageBucket seems overly complicated for this case. Or am I wrong?
Thanks in advance for any guidance.

Related

How to validate TextFormFields, that are at different pages inside a PageView

So lets say I have 3 Pages : [StartingPage, NamePage, AdressPage] inside a PageView.
Each of those children has a TextFormField inside it.
When I am at StartingPage I want to call .validate() on the keys of the TextFormFields on NamePage and AdressPage and I want the errorLabels to show, when the user navigates to the other pages. The problem is that currently, the validation only works for the TextFormFields that are on screen.
So basically there are two questions:
Is it possible to pre-build pages of a pageview? Otherwise when I call formFieldKey.currentState the state is null if I haven't navigated to the respective page.
Is there another way to validate offscreen TextFormField content and show the errorlabel, when they come into view?
Unfortunately Flutter Dosen't Support Multi-Page Forms So You Need To Implement Advanced State Management To Make This Happen.
I Used Riverpod To Create a 4 Page Form By Creating A Form Key For Every Page And Saving The State of the Forms, This Way Every Form Will keep Its State Until You Dispose Of it, Hope This Helped.

Flutter nested lists - custom CheckBox

I'm really confused about this situation, I'm trying to build this app just like in the image below, the app is all about having a list of ExpansionTiles inside each one there is a list of items, each item has it's own three checkboxes[true, false, avoid], and also the ExpansionTile it self has it's own three checkboxes that can be clicked globally, instead of selecting them one by one,what I need is to get to the best solution to implement this, to know which item in which list were selected and to give a result depending on it, I'm really confused and tried many ways, many models for data, but failed, any help will be really app, I'd be more than glad with any help.enter image description here
I'd create a controlled widget for the three checkboxes, passing parameters for onChange and value (Value can be determined using an enum)
Then I'd reuse that widget everywhere I need
Then I'd go for an expansible widget that contains the list (Column widget maybe?)
Try to handle as many states as possible, having controlled widgets
Or if you're using BloC you can easily implement your core logic with this UI:)

How to check visibility of a Flutter widget even when covered by another

I'm trying to find a way to check the visibility of a Flutter widget when it's either off screen or when it's obscured by another, for example Drawer, Dialog or BottomSheet.
visibility_detector helps with checking whether it's on the screen or not but does not work with the second use case (known limitation).
Is there a lower lever api that I can use to check whether a widget is actually visible to the user?
My use case: I'm adding a widget to the Overlay when something external happens (similar to Tooltip but not on long press). If the user opens for example the Drawer, the widget will appear on top. I want to detect that the child is not visible and delay or cancel the action.
Do I understand your problem?
You have a widget you want to always be on top?
You want the user to interact with that widget first before doing other things?
Use design patterns to make coding easier, your users will thank you.
You can show a Dialog on-top of other widgets with the showGeneralDialog or showDialog functions. Because Dialogs are a design-pattern used in many apps, users will already know how to use them.
Define app behavior with explicit state.
It is too hard to derive app behavior from rendered UI, not all devices are the same size and shape. This means you should try to write a variable that describes your situation and then write the code you need to make that variable's value correct. It sounds like you want a variable like bool overlayIsShowing.

Reuse Widget Across Two Pages With Keys

Long-winded context, scroll to bottom for specific question:
I have a page with a custom widget (EntrySearch) containing a ListView and a search bar. When the user clicks on an item in the list view, I push a new page with the same list view and a panel displaying item details. The list view's items are lazily loaded from a Stream backed by an asynchronous query (the stream is paused until the user scrolls to the end of elements fetched so far). The stream is replaced whenever the user types in a new string in the search bar.
I want the widget to have the same list view (elements, scroll position, etc.) and search bar state across both pages.
I could achieve this with any of the many state management solutions suggested on similar questions about shared widget state across pages (eg this one). However, because my ListView is backed by an asynchronous stream along with a ton of other state, this becomes a total pain of caching results fetched so far, creating a new Stream that starts where the old one left off (can't have two StreamBuilders backed by the same non-broadcast stream), etc. etc. I'd really like to avoid such a messy solution.
Giving the top level Widget whose state I want to share a global key is one line (instead of ~50) and results in shared state across the pages. However, when I push the new page, the old page stays in the Widget tree on standby, so I get an error for having two widgets with the same global key in the widget tree at the same time. I can set maintainState to false on the first page, but then when I pop the second the first page shows up as just a black screen.
Is there:
a way to use a global key widget across two pages without them both being in the tree at the same time
a specialized key specifically for reusing a widget across two different pages
some other approach I'm not thinking of?
Here's my widget tree with the two pages. EntrySearch is the widget I want to reuse across the two pages.
If none of the above works, I'll have to use a traditional state management strategy which is going to be at least an order of magnitude more verbose and bug-prone.
Here's the solution I went with, if anyone else is approaching a similar problem:
I couldn't find a way to use keys for this problem. What I'm doing now is I have a single class that contains all the state my custom widget needs to build itself. Whenever I push a route to the navigator, I copy the current page's state object with the desired changes and then add the new state to the RouteSettings.argument field. I can then access the page's state object anywhere within the page using ModalRoute.of(context).settings.arguments.
As expected, this solution was massively complex and painful with a lot of subtle bugs I had to work through. It works and at least has slightly more desirable behavior than simply maintaining identical state across both pages: when I pop a page, the state pops too. This means a user can go back to their previous scroll position in the ListView with the back gesture.

How to prevent Stateful Widget stored in List to be disposed?

Let me start by explaining the problem. I have several buttons which are created based on data I'm getting from a server. On each button click I need to create and display a widget which will present me some data (this widget is also built dynamically). The state of this widget has to be preserved during the lifetime of the app. (for example if I click another button and show a different widget, I need to be able to click on the first button and show the first widget in its preserved state). Number of buttons can also be changed during the app lifetime.
I tried using IndexedStack to achieve this, but when the number of buttons is changed I need to add "pages" to IndexedStack, therefore I need to recreate a new IndexedStack which will have some of my old widgets, so I pull widgets from a List or create new ones if needed. This works great, except Flutter calls dispose() method on my widgets which are stored in the list. I tried using the AutomaticKeepAliveClientMixIn but it didn't help.
I'm guessing this has something to do that the widgets get detached from the parent, but when I reattach them to new parent (new Indexed stack) Flutter doesn't figure out this properly.
Any ideas?
Try to store data to local storage or sqlite for persistence data.