Flutter: Calling a function once in a lifetime of the flutter app - flutter

I want to call a function when app runs for the first time, which will ask the user to enter firstName , lastName and add a profile picture.
Once the above process is done the function will never again be called during the lifetime of the app.

For something like this you need to check if the user has already entered that data or not. If not then show him the page where he can enter information otherwise take him to HomePage. For this When the user enters the information you need to save it to some persistent storage and check it whenever the app runs. In this way, your function will be called only once until the user deletes the app or clear its memory. You could use the following libraries to store the data.
Hive,
Shared Preference
These libraries save the data in key-value pair and read data faster especially hive.

Use SharePreference
see below code snippet with little advancement in code you can achieve your result.
Future<bool> isFirstTime() async {
var firstTime = SharedPref.pref.getBool('first_time');
if (firstTime != null && !firstTime) {
SharedPref.pref.setBool('first_time', false);
return false;
} else {
SharedPref.pref.setBool('first_time', false);
return true;
}
}

Related

Allow the user to acces a specific function only once a day

What if I want to make a page resets itself at 12:00 am or after specific time.
Let's say I want the user to use a specific functionality once every day. For example, if the user click on a button will sees a pic of a dag, and after 12:00 am the user can click on the button again to see another picture of another dog in a specific list of dogs' pics stored in the app. How this is can be implemented in Flutter?
Definitely there are different ways to do it. Assuming you'd like to handle the logic in the client side, you can store a local boolean value called 'seen' in the SharedPreferences.
Then somewhere in your app (startup for example), you can update the value to false if the time is after midnight. Assuming you already have SharedPreferences setup and it's in a variable called sharedPreferences
DateTime time = DateTime.now();
String resetTime = "${time.year}-${time.month.toString().padLeft(2,'0')}-${time.day.toString().padLeft(2, '0')} 00:00:00";
if(time.isAfter(DateTime.parse(resetTiem){
sharedPreferences.setBool('seen', false)
}
Now on the other side of the code, where the user clicks to see the picture, you can check if the sharedPreferences value is true or false in order to show the picture.
if(sharedPreferences.getBool('seen')){
return SomeWidgetWithThePicture;
} else {
return AnotherWidgetWithoutPicture // tell the user they can see it after midnight
}

How to get inital state of the sapui5 app without reopening

My 'create new User' app can only create one new user. If I want to create an additional user I have to restart the app. What I want to do is, create some button which does this task without restarting the app.
To be more specific, after the initial call of the app I create a new user (include save). The user is stored in the back-end and still visible on the front-end (so I can further edit the user). In case I want to create an additional user, I want to push some button and the view will be restarted/reloaded (and also the Model). Eventually I want the inital state of my app. Then I want to be able to create the next new user (include save) and maybe another one.
What I already tried:
'CrossApplicationNavigation' to my 'create new user' app without any
parameters. It works only the first time, because when I push the
button the second time nothing happens. The URL stays the same (no parameters are changing).
Deleting data of the Model and subsequently calling the oninit()
function. But I get problem with refilling the model.
Is there some function or something else I can try?
As descripted in comment (component.js):
init: function () {
//set model
this.setModel(models.createTableModel(this), "table");
if (this.getComponentData().startupParameters.ID) {
var sID = this.getComponentData().startupParameters.ID[0];
if (sID !== "") {
this.getModel("table").setProperty("/ID", sID);
} else {
this.getModel("table").setProperty("/ID", "");
}
}
}
I think, you're using a local model? Then you'll have to reset your local model. Reset your local model in onInit function and on pressing button "Add new user".
onInit: function(){
this.oLocalModel = this.getModel("myLocalModel");
this._resetModel(this.oLocalModel);
},
_resetModel: function(oModel){
oModel.setData();
},
onPressAddNewUser: function(){
this._resetModel(this.oLocalModel);
}

How can I check if the user is playing the game for the first time?

I want to show a text for the first time running like "Hi, my name is NAVI." and then when the player will start the game again the next time it will another text for example "Welcome back."
Using player prefs is probably the easiest solution, though definitely not the only one*.
Due to the lack of boolean playerpref I usually opt to use SetInt/GetInt instead, but that's personal preference. You could also do it with a string or float.
private void Start()
{
if(PlayerPrefs.GetInt("HasLaunched", 0) == 0)//Game hasn't launched before. 0 is the default value if the player pref doesn't exist yet.
{
//Code to display your first time text
}
else
{
//Code to show the returning user's text.
}
PlayerPrefs.SetInt("HasLaunched", 1); //Set to 1, so we know the user has been here before
}
Playerpref stores values between sessions, so the next session will still have "HasLaunched" set to 1. This is however stored on the local device. so users can manually reset it if they'd really want to.
If you ever want to show the "first launch" text again, simply set HasLaunched back to zero, or delete it altogether with DeleteKey("HasLaunched");
*There are plenty of alternative solutions, like storing it in a config file locally, or using a remote database (this would be required if you don't want users to be able to reset it). They would however come down to the same principle. Setting a value to true or 1 somewhere, and checking that value on launch.

Async/Await/then in Dart/Flutter

I have a flutter application where I am using the SQFLITE plugin to fetch data from SQLite DB. Here I am facing a weird problem. As per my understanding, we use either async/await or then() function for async programming.
Here I have a db.query() method which is conducting some SQL queries to fetch data from the DB. After this function fetches the data, we do some further processing in the .then() function. However, in this approach, I was facing some issues. From where I am calling this getExpensesByFundId(int fundId)function, it doesn't seem to fetch the data properly. It's supposed to return Future> object which will be then converted to List when the data is available. But when I call it doesn't work.
However, I just did some experimentation with it and added "await" keyword in front of the db.query() function and somehow it just started to work fine. Can you explain why adding the await keyword is solving this issue? I thought when using .then() function, we don't need to use the await keyword.
Here are my codes:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
// The await in the below line is what I'm talking about
await db.query(expTable,where: '$expTable.$expFundId = $fundId')
.then((List<Map<String,dynamic>> expList){
expList.forEach((Map<String, dynamic> expMap){
expenseList.add(Expense.fromMap(expMap));
});
});
return expenseList;
}
In simple words:
await is meant to interrupt the process flow until the async method has finished.
then however does not interrupt the process flow (meaning the next instructions will be executed) but enables you to run code when the async method is finished.
In your example, you cannot achieve what you want when you use then because the code is not 'waiting' and the return statement is processed and thus returns an empty list.
When you add the await, you explicitly say: 'don't go further until my Future method is completed (namely the then part).
You could write your code as follows to achieve the same result using only await:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
List<Map<String,dynamic>> expList = await db.query(expTable,where: '$expTable.$expFundId = $fundId');
expList.forEach((Map<String, dynamic> expMap) {
expenseList.add(Expense.fromMap(expMap));
});
return expenseList;
}
You could also choose to use only the then part, but you need to ensure that you call getExpensesByFundId properly afterwards:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
return db.query(expTable,where: '$expTable.$expFundId = $fundId')
.then((List<Map<String,dynamic>> expList){
expList.forEach((Map<String, dynamic> expMap){
expenseList.add(Expense.fromMap(expMap));
});
});
}
// call either with an await
List<Expense> list = await getExpensesByFundId(1);
// or with a then (knowing that this will not interrupt the process flow and process the next instruction
getExpensesByFundId(1).then((List<Expense> l) { /*...*/ });
Adding to the above answers.
Flutter Application is said to be a step by step execution of code, but it's not like that.
There are a lot of events going to be triggered in the lifecycle of applications like Click Event, Timers, and all. There must be some code that should be running in the background thread.
How background work execute:
So there are two Queues
Microtask Queue
Event Queue
Microtask Queue runs the code which not supposed to be run by any event(click, timer, etc). It can contain both sync and async work.
Event Queue runs when any external click event occurs in the application like Click event, then that block execution done inside the event loop.
The below diagram will explain in detail how execution will proceed.
Note: At any given point of application development Microtask queue will run then only Event Queue will be able to run.
When making class use async for using await its simple logic to make a wait state in your function until your data is retrieve to show.
Example: 1) Its like when you follow click button 2) Data first store in database than Future function use to retrieve data 3) Move that data into variable and than show in screen 4) Variable show like increment in your following/profile.
And then is use one by one step of code, store data in variable and then move to next.
Example: If I click in follow button until data store in variable it continuously retrieve some data to store and not allow next function to run, and if one task is complete than move to another.
Same as your question i was also doing experiment in social media flutter app and this is my understanding. I hope this would help.
A Flutter question from an answer from your answer.
await is meant to interrupt the process flow until the async method has finished. then however does not interrupt the process flow but enables you to run code when the async method is finished. So, I am asking diff. between top down & bottom down process in programming.

How to update ion-toggle status real in time?

I have an ion toggle in my application that stores his status in a firebase Database, is there a way to change his status with the data loaded from firebase?
For example, if in the database the status is true, then when I load the view the toggle will be on. I've tried using checked:
<ion-toggle checked="status()" >
where status() returns a boolean.
But due to the async function of firebase, the view loads 1st before the value in status(). Can't find a solution to this problem so far, I'd apreciate any help.
Yes there's a way to do this, but using a function in your attribute is no good. When using a function in the DOM that returns a value you'll make that function executes every time there's a change in the DOM, so since this is a function that fetchs something on Firebase you'll make your user do an request to Firebase every time the DOM is updated.
A good way to do this is storing the Firebase result in a variable. you can do like this when you enter de page:
public myStatus: boolean;
// USING A LIFECYCLE HOOK
ionViewWillLoad(){
firebase.database().ref(`Path/To/Your/Status`).once('value', snapshot => {
this.myStatus = snapshot.val();
});
}
And in your HTML
<ion-toggle [checked]="myStatus">
<!-- You need to bind your checked attribute to myStatus, using checked="{{myStatus}}" also works -->
If you need to always check if your status has changed you can also create and observable on firebase, so if your status change you can change your toggle:
ionViewWillLoad(){
firebase.database().ref(`Path/To/Your/Status`).once('value', snapshot => {
this.myStatus = snapshot.val();
});
firebase.database().ref(`Path/To/Your/Status`).on('child_changed', snapshot => {
this.myStatus = snapshot.val();
});
// YOU'LL NEED BOTH SINCE THE FIRST LOADS THE STATUS FOR THE FIRST TIME AND THE SECCOND CREATES AN OBSERVABLE FOR WHEN THE STATUS CHANGE.
}
Hope this helps.