Deleting entry and undoing deletion in snackbar – WeightTracker 7
In this post, I will go through how I added delete functionality to my WeightTracker app. I will also show how to implement ‘undo’ action on Snackbar with help from Redux Library. Let’s get to it!
Note: I am using Redux library for application’s state management. If you are not familiar with Redux concept, I highly recommend reading my post about it before going forward.
Delete action
Logic
At first, I implemented the logic behind removing an entry. It is quite straight forward.
I added two actions:
Then in the middleware function I implemented performing request to Firebase:
The only thing RemoveEntryAction does is telling middleware to remove an entry from the database. When it’s done listener gets called and invokes OnRemovedAction which will change our local state.
Next step is to change the reducer method:
When OnRemovedAction is invoked, all I do is remove an entry from the local list and pass a new list to the new state. As you can see, I also pass removed entry and flag confirming that entry has been removed. I will explain it in the next chapter so don’t worry about that now.
At this point, we have implemented whole logic behind removing an entry from the list using Redux and Firebase. Now let’s move to UI.
. . .
User interface
In my app, users can delete entry only by going to full-screen edit dialog and clicking DELETE. When I created that dialog (described here) I designed it to return a WeightEntry. However, since I introduced DELETE action simple model cannot contain this information. That’s why my dialog is now returning Redux Action.
Now let’s get into the code. The only change I needed to do in my dialog class was adding DELETE action into AppBar:
What I do is I check if there is WeightEntry to edit, if so I create action containing FlatButton which will return proper redux action. If there no entry to edit (meaning also no entry to delete) I display empty Container instead of Button.
When it comes to invoking result action coming from dialog, I implemented it in following way:
Where removeEntryCallback parameter is (action) => store.dispatch(action);.
Now we have fully working delete functionality using Firebase and Redux. Next step is to allow the user to undo his action in case of a mistake.
. . .
Undo action
Logic
To perform undo action, it is required to save removed entry. To do that I added new field in redux state:
I am saving it when weight entry gets deleted (showed 4 listings above).
Then I have to introduce undo action, there is nothing surprising in that:
It’s that simple! I just get the value from state and push it to Firebase. When a child is added, it will call the same listener as in normal addition.
. . .
User interface
Now let’s add Snackbar on which user can click the UNDO button. Since every build method is invoked when the state gets changed, I had to store information if snackbar should be displayed. I did it by simply adding a flag to state class:
I set this flag to true when an entry is getting removed.
Then, in actual Widget displaying Snackbar I added the following code:
How it works:
- When Entry is removed, hasEntryBeenRemovedflag is set up to true and setState function gets invoked.
- In build function (if the flag is set to true) I create a Scaffold which has action with UndoRemoval which was described earlier.
- AcceptEntryRemovalAction gets invoked. What it does is change hasEntryBeenRemoved flag to false, so that we won’t show snackbar on every build.
If the user clicks UNDO button, the app adds last removed entry.
What’s worth mentioning is that in order to get Scaffold inside build function (before it’s actually built) I used Future’s delayed method with duration equal to 0.
And that’s it!
If you are interested in full code, I encourage you to check out my repository.
Cheers! ?
Marcin Szałek
Founder of Fidev
Flutter enthusiast since Alpha release in 2017. Believes that sharing is caring, which lead him to start a technical blog dedicated fo Flutter in its early days. Loves to see beautiful designs become real apps and is willing to help make it happen. Enjoys sunny beaches far from home.
Join the newsletter!
Join the newsletter to keep track with latest posts and get my special Widget to animate views' entrances without any hassle for FREE!
Check out other posts!
Stripe Checkout in Flutter Web
Flutter Web is getting more mature every day. If you want to accept payments using Stripe Checkout in your Flutter web application, this article is just for you!
Stripe Checkout in mobile Flutter app
Have you ever struggled to integrate card payments into your mobile Flutter app? If so, today is your lucky day! In this post, I present how to use Stripe Checkout in the Flutter app without any hassle!
Interacting with Widgets using Framy
Have you ever developed a widget or a page and you wanted to make sure it works correctly in different scenarios but then it turned out that you can’t just reproduce all the cases you want to cover? Framy may solve such problems!
hello there.
i have issue when i try compile your code.
can you help me?
thank you
compiler message: lib/screens/main.dart:13:33: Error: The argument type ‘(#lib1::ReduxState, dynamic) → #lib1::ReduxState’ can’t be assigned to the parameter type ‘(dynamic, dynamic) → dynamic’.
compiler message: Try changing the type of the parameter, or casting the argument to ‘(dynamic, dynamic) → dynamic’.
compiler message: final Store store = new Store(stateReducer,
compiler message: ^
Compiler failed on /Users/mac/Downloads/weight_tracker/lib/screens/main.dart
Error launching application on iPhone XS Max.
Hi there,
Try launching the app with the most recent code (https://github.com/MSzalek-Mobile/weight_tracker). The error is probably caused by strong typing which wasn’t needed when I created that post. Tell me how it goes 🙂