Flutter- change variable to zero after 1 day - flutter

I am developing a flutter app that user click the button and the counter increase by one.
I want to rest the value of the counter to zero after one day.
Can u please tell me is there anyway to achieve that?
Thank you

You can use flutter_cache package
https://pub.dev/packages/flutter_cache/
import 'package:flutter_cache/flutter_cache.dart' as cache;
void main() async {
// create new cache.
cache.remember('key', 'data');
cache.write('key', 'data');
// add Cache lifetime on create
cache.remember('key', 'data', 120);
cache.write('key', 'data', 120);
// load Cache by key
// return `defaultValue` if key not exists
cache.load('key', 'defaultValue');
// destroy single cache by key
cache.destroy('key');
// destroy all cache
cache.clear();
await cache.remember('key', () {
return 'test'; // or logic fetching data from api;
});
// or
await cache.remember('key', () => 'test');
cache.remember('key', 'data', 120); // saved for 2 mins or 120 seconds
cache.write('key', 'data', 120);
// multi depth map datatype.
cache.remember('key', {
'name': 'Ashraf Kamarudin',
'depth2': {
'name': 'depth2',
'depth3': {'name': 'depth3'}
}
});
cache.load('key'); // will return data in map datatype.
}

Is your requirement passive or active? If it is active, you can refer to the following code. If it is passive, you need to poll regularly
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> with WidgetsBindingObserver {
DateTime? _presedDate;
var number = 0;
#override
void initState() {
_presedDate = DateTime.now();
super.initState();
}
#override
void didChangeAppLifecycleState(AppLifecycleState lifeCycle) async {
var _isForeground = (lifeCycle == AppLifecycleState.resumed);
if (_isForeground) checkNumber();
super.didChangeAppLifecycleState(lifeCycle);
}
void checkNumber() {
var currenDate = DateTime.now();
var isToday = DateUtils.isSameDay(_presedDate, currenDate);
if (!isToday) {
number == 0;
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('$number'),
TextButton(
onPressed: () {
number++;
setState(() {});
checkNumber();
},
child: Text('incrementNumber')),
],
),
)));
}
}

Related

Why is the flutter setState not updating the list?

I have two api's from which I get data, I wanna check if any of the desired field match with each other data coming but it don't seem to work.
I have two api's from which I get data, I wanna check if any of the desired field match with each other data coming but it don't seem to work.
I have two api's from which I get data, I wanna check if any of the desired field match with each other data coming but it don't seem to work.
class Home extends StatefulWidget {
const Home({ Key? key }) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List compaints = [];
List found = [];
List match = [];
var u_imei;
var d_imei;
Future fetch() async {
http.Response response_one;
http.Response response_two;
response_one = await http.get(Uri.parse("https://script.google.com/macros/s/AKfycbxi9kN6NWvoFjkQZE1OVJDPpWmQeYk0V5hNfRKqXS19wjz86SYq_FoQ51fjNQY22bN4/exec"));
response_two = await http.get(Uri.parse("https://script.google.com/macros/s/AKfycbx20kfm1g4Hno9DzO1uccmLgmuIQBkXQcA9tnhcup873TsEMEy9ejszCluhf4FzW-YJqQ/exec"));
if(response_one == 200 && response_two == 200){
if(mounted){
setState(() {
compaints = jsonDecode(response_one.body);
found = jsonDecode(response_two.body);
u_imei = compaints[2];
d_imei = found[1];
if(d_imei == u_imei) {
if(mounted){
print("working");
setState(() {
match.add(d_imei);
});
}
}
});
}
}
}
#override
Widget build(BuildContext context) {
// fetchu();
// fetchd();
// check();
fetch();
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(compaints.length.toString()),
SizedBox(height: 20,),
Text(found.length.toString()),
],
),
);
}
}
There are several issues:
fetch is called in build, which causes rebuild loop. First step to move it to initState.
Response is compared to 200 (response_one == 200). There is property statusCode.
Parsing imei's is not correct. Responses:
[{time: 2022-07-03T16:07:15.491Z, name: Asif, imei: 1234, number: 9014580667}]
[{time: 2022-07-05T08:12:31.029Z, imei: 1234}]
So should be something like this:
u_imei = compaints[0]['imei'];
d_imei = found[0]['imei'];
Calling the fetch method inside the build will loop as the fetch method calls the setState(). Use initState() to call on the load or on refresh indicator while the user pulls to refresh or any other method.
class Home extends StatefulWidget {
const Home({ Key? key }) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List compaints = [];
List found = [];
List match = [];
var u_imei;
var d_imei;
#override
void initState() {
super.initState();
fetch();
}
#override
void dispose() {
super.dispose();
}
Future fetch() async {
http.Response response_one;
http.Response response_two;
response_one = await http.get(Uri.parse("https://script.google.com/macros/s/AKfycbxi9kN6NWvoFjkQZE1OVJDPpWmQeYk0V5hNfRKqXS19wjz86SYq_FoQ51fjNQY22bN4/exec"));
response_two = await http.get(Uri.parse("https://script.google.com/macros/s/AKfycbxEDXZAmieRWk-8kOX-07ta8Q4TIa9Lf_NAiArEWhaU4jXO8d_DM9Jwuc0DRIwmUpPh/exec"));
if(response_one.statusCode == 200 && response_two.statusCode == 200){
if(mounted){
setState(() {
compaints = jsonDecode(response_one.body);
found = jsonDecode(response_two.body);
u_imei = compaints[2];
d_imei = found[1];
if(d_imei == u_imei) {
if(mounted){
print("working");
setState(() {
match.add(d_imei);
});
}
}
});
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(compaints.length.toString()),
SizedBox(height: 20,),
Text(found.length.toString()),
],
),
);
}
}

Observe List with GetX outside of widget

I have isolate that makes some heavy calculations then on receive the list with the result run a for loop to add them to observable list with items var items = [].obs;
The thing is I'm trying to observe the items list from a splash controller and once the list != [] I'll navigate to another screen, so in onInit() I have this code:
class SplashController extends GetxController {
#override
void onInit() {
final ItemsController _itemsController = Get.put(ItemsController());
// TODO: implement onInit
super.onInit();
ever(_itemsController.items, (newItems) {
print('new items here $newItems');
});
}
}
Despite the itemsController.items is populated (after the for loop I print the itemsController.items and it's not empty) the worker on the splash controller doesn't trigger when the items are added.
What am I doing wrong here? Is this the correct way to observe variable outside of widget using Getx?
Can anyone help me with this, please?
Edit: In the items controller I’m adding the items this way
add(item) => items.add(item)
Continuing with the Isolate example, but without using a StatefulWidget i.e. no setState usage.
The ever worker in SplashX will receive items generated from the Isolate. The Stateless Widget page will display the latest item emitted from the Isolate.
SplashController + ever worker
class SplashX extends GetxController {
ItemsX itemsX;
SplashX({this.itemsX});
#override
void onInit() {
super.onInit();
ever(itemsX.items, (items) => print('Ever items: $items'));
}
}
Items Controller
class ItemsX extends GetxController {
RxList<String> items = RxList<String>();
bool running = false;
void add(String item) {
items.add(item);
}
void updateStatus(bool isRunning) {
running = isRunning;
update();
}
void reset() {
items.clear();
}
/// Only relevant for UnusedControllerPage
List<Widget> get texts => items.map((item) => Text('$item')).toList();
}
Isolate Controller
class IsolateX extends GetxController {
IsolateX({this.itemsX});
ItemsX itemsX;
Isolate _isolate;
static int _counter = 0;
ReceivePort _receivePort;
bool running = false;
static void _checkTimer(SendPort sendPort) async {
Timer.periodic(Duration(seconds: 1), (Timer t) {
_counter++;
String msg = 'notification ' + _counter.toString();
print('SEND: ' + msg);
sendPort.send(msg);
});
}
void _handleMessage(dynamic data) {
itemsX.add(data); // update observable
}
void updateStatus(bool isRunning) {
running = isRunning;
update();
}
void start() async {
itemsX.reset();
updateStatus(true);
_receivePort = ReceivePort();
_isolate = await Isolate.spawn(_checkTimer, _receivePort.sendPort);
_receivePort.listen(_handleMessage, onDone:() {
print("done!");
});
}
void stop() {
if (_isolate != null) {
updateStatus(false);
_receivePort.close();
_isolate.kill(priority: Isolate.immediate);
_isolate = null;
}
}
}
Stateless Page
class MyHomePageStateless extends StatelessWidget {
#override
Widget build(BuildContext context) {
ItemsX ix = Get.put(ItemsX()); // Instantiate ItemsController
IsolateX isox = Get.put(IsolateX(itemsX: ix));
SplashX sx = Get.put(SplashX(itemsX: ix));
return Scaffold(
appBar: AppBar(
title: Text('Isolate Stateless'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GetX<ItemsX>(
builder: (ix) => Text(ix.items.isNotEmpty ? ix.items.last : ''),
),
],
),
),
floatingActionButton: GetBuilder<IsolateX>(
builder: (_ix) => FloatingActionButton(
onPressed: _ix.running ? isox.stop : isox.start,
tooltip: _ix.running ? 'Timer stop' : 'Timer start',
child: _ix.running ? Icon(Icons.stop) : Icon(Icons.play_arrow),
),
),
);
}
}
Here's two controllers, with one ever worker listening for events of another controller, where that controller's events are coming from data generated in an Isolate.
I'm not aware of anything special about generating data in an Isolate as opposed to any other async data source, but I'm not overly familiar with Isolates.
Controllers
class SplashX extends GetxController {
ItemsX itemsX;
SplashX({this.itemsX});
#override
void onInit() {
super.onInit();
ever(itemsX.items, (items) => print('Received items: $items'));
}
}
class ItemsX extends GetxController {
RxList<String> items = RxList<String>();
void add(String item) {
items.add(item);
}
/// Only relevant for SimplePage at bottom
List<Widget> get texts => items.map((item) => Text('$item')).toList();
}
Page /w Isolate
And here's the edits to the Isolate snippet which you're using.
I've instantiated ItemsX controller as a field and SplashX in onInit.
(There shouldn't be a need to use Stateful Widgets since you can put all state into a Controller, but I didn't want to rewrite the Isolate example).
class _MyHomePageState extends State<MyHomePage> {
Isolate _isolate;
bool _running = false;
static int _counter = 0;
String notification = "";
ReceivePort _receivePort;
ItemsX ix = Get.put(ItemsX()); // Instantiate ItemsController
#override
void initState() {
super.initState();
SplashX sx = Get.put(SplashX(itemsX: ix));
// ↑ Instantiate SplashCont with ever worker
}
Change to the _handleMessage method:
void _handleMessage(dynamic data) {
//print('RECEIVED: ' + data);
ix.add(data); // update observable
setState(() {
notification = data;
});
}
And finally the debug output results showing ever worker handling observable events (Received items...) :
[GETX] "ItemsX" has been initialized
[GETX] "SplashX" has been initialized
I/flutter (19012): SEND: notification 1
I/flutter (19012): Received items: [notification 1]
I/flutter (19012): SEND: notification 2
I/flutter (19012): Received items: [notification 1, notification 2]
I/flutter (19012): SEND: notification 3
I/flutter (19012): Received items: [notification 1, notification 2, notification 3]
I/flutter (19012): done!
Controllers in Non-Isolate Page
Example of using the same controllers above, without the noise of a Stateful Widget page and all the Isolate stuff.
class SplashX extends GetxController {
ItemsX itemsX;
SplashX({this.itemsX});
#override
void onInit() {
super.onInit();
ever(itemsX.items, (items) => print('Received items: $items'));
}
}
class ItemsX extends GetxController {
RxList<String> items = RxList<String>();
void add(String item) {
items.add(item);
}
/// Only relevant for SimplePage
List<Widget> get texts => items.map((item) => Text('$item')).toList();
}
class SimplePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
ItemsX ix = Get.put(ItemsX());
SplashX sx = Get.put(SplashX(itemsX: ix));
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
flex: 10,
child: Obx(
() => ListView(
children: ix.texts,
),
),
),
Expanded(
flex: 1,
child: RaisedButton(
child: Text('Add'),
onPressed: () => ix.add('more...'),
)
)
],
),
),
);
}
}

Why does not the picture change for every period of time?

I want my flutter web page display a photo , and change for every 3 seconds to display another photo ..
here is my code
class _contactPageState extends State<contactPage> {
List<String> randomPics= ['profiles/github.png', 'profiles/linkedIn.png', 'profiles/stack.png'];
Timer timer;
var random= Random();
String photo;
#override
void initState() {
photo = randomPics[random.nextInt(randomPics.length)];
openLink = new linksToOpen();
super.initState();
timer = new Timer(new Duration(seconds: 1), ( ){
setState(() {
photo= randomPics[random.nextInt(randomPics.length)];
print('${photo}');
});
});
}
#override
Widget build(BuildContext context) {
Container(
child: Image(image : AssetImage(photo),gaplessPlayback: true,),
width: 400, height: 400,
),
What is the problem with my code ?
Please , can anyone help me !
I did some test and I think this could work for you:
import 'dart:async';
import 'dart:math';
import 'package:flutter/widgets.dart';
class ContactPageState extends StatefulWidget {
ContactPageState({Key key}) : super(key: key);
#override
_ContactPageState createState() => _ContactPageState();
}
class _ContactPageState extends State<ContactPageState> {
List<String> randomPics = ['assets/a.jpg', 'assets/b.jpg', 'assets/c.jpg'];
String photo;
final random = new Random();
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) => configureTimer());
super.initState();
}
configureTimer() {
Timer.periodic(Duration(milliseconds: 3000), (timer) {
final int index = random.nextInt(randomPics.length);
setState(() {
photo = randomPics[index];
debugPrint('Select picture $photo in index $index');
});
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Image(
image: AssetImage(photo != null ? photo : 'assets/a.jpg'),
gaplessPlayback: true,
),
width: 400,
height: 400,
);
}
}
For a quick fix, you need to add function setStatus ... as a callback function so it can call itself infinitely.
void _nextPic(){
setState(() {
photo= randomPics[random.nextInt(randomPics.length)];
print('${photo}');
});
timer = new Timer(new Duration(seconds: 1), _nextPic);
}
This function create another timer after this one is done. So you can just need to create the first timer in initState...
#override
void initState() {
photo = randomPics[random.nextInt(randomPics.length)];
super.initState();
timer = new Timer(new Duration(seconds: 1), _nextPic);
}
For one thing, you will need to specify 3 seconds instead of 1. Another, you may be looking for timer.periodic to have this execute multiple times (until you tell it to stop) instead of a single timer countdown that happens starting from state initialization.
An example, see selected answer here:
Flutter Countdown Timer
Documentation:
https://api.flutter.dev/flutter/dart-async/Timer/Timer.periodic.html

Data is showing only after I hot reload or refresh in flutter

In my database I have a user table where username, some marks are stored. I want to view that data in a table when user go to a particular page. So, when I go to that page at first the data(username and marks) doesn't show. But if I hot reload or use a button to refresh then the data shows properly. My question is how can I do that without hot reload or using a refresh button. Here is my code:
import 'package:flutter/material.dart';
import 'package:flutter_app/database/db_helper.dart';
import 'package:flutter_app/database/user.dart';
class ViewResult extends StatefulWidget {
#override
_ViewResult createState() => _ViewResult();
}
GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey();
class _ViewResult extends State<ViewResult> {
String tempEmail;
bool check = true;
var dbHelper;
var data = List<User>();
#override
void initState() {
setState(() {
dbHelper = DBHelper();
resultData();
});
super.initState();
}
void resultData() {
dbHelper.getUser().then((users) {
for (User temp in users) {
if (temp.type == "student") data.add(temp);
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Result"),
),
body: DataTable(
columnSpacing: 22,
columns: [
DataColumn(label: Text("Username")),
DataColumn(label: Text("Beginner")),
DataColumn(label: Text("Intermediate")),
DataColumn(label: Text("Advanced")),
],
rows: data
.map((user) => DataRow(cells: [
DataCell(Text(user.email)),
DataCell(Text(user.beginnerMark.toString())),
DataCell(Text(user.intermediateMark.toString())),
DataCell(Text(user.advancedMark.toString())),
]))
.toList(),
),
backgroundColor: Color.fromRGBO(130, 178, 220, 1),
);
}
}
TLDR: Call setState() from inside then() if not, it will be executed before everything completes and have no effect at all.
getUser().then((response) {
//Your stuff
setState(() {}); //refresh
});
You have to use setState after you have loaded the data and your resultData functions is working with then, that is executed after the initial setState in the initState is finished.
#override
void initState() {
// super.initState(); should be at the start of the method
super.initState();
dbHelper = DBHelper();
resultData();
}
void resultData() {
dbHelper.getUser().then((users) {
for (User temp in users) {
if (temp.type == "student") data.add(temp);
}
// since you have already added the results to data
// setState can have an empty function body
setState(() {});
});
}
I prefer working with async/await instead of then so my solutions would be as follows:
Future<void> resultData() async {
List<User> users = await dbHelper.getUser();
setState(() {
data = users.where((user) => user.type == "student");
});
}
You need setState(() {});.
Add it near the end of resultData function:
void resultData() {
dbHelper.getUser().then((users) {
for (User temp in users) {
if (temp.type == "student") data.add(temp);
}
setState(() {});
});
}
See setState for more information.

Show timer progress on a CircularProgressIndicator in flutter

I'm using a RestartableTimer (subclass of Timer) as a countdown timer, to "kick people out" of a form after a certain duration.
I would like to display the progress of that timer, and I like the idea of a circular progress slowly filling up.
I'm not showing my code because I don't really have anything to show. I have a completely static progress indicator and a working timer, in a widget (stateful or stateless, whichever works best).
I face two issues and this is where I need help for :
I don't know how to check every x milliseconds for the timer progress. How can I do that? I don't need copy-pasta code, but more of "what object / which direction" should I go for?
The timer progress in ticks is not implemented (NotImplementedException) ; is there any way to have an equivalent somewhere else? That object works really well for me, except for that part.
Am I SOL or is there a way to make it?
There's nothing to be implemented in the getter tick, since RestartableTimer is not periodic. What you want is a much more complex thing, and RestartableTimer is not able to help you with that.
First, you need something to control the progress of the CircularProgressIndicator:
class ProgressController {
static const double smoothnessConstant = 250;
final Duration duration;
final Duration tickPeriod;
Timer _timer;
Timer _periodicTimer;
Stream<void> get progressStream => _progressController.stream;
StreamController<void> _progressController = StreamController<void>.broadcast();
Stream<void> get timeoutStream => _timeoutController.stream;
StreamController<void> _timeoutController = StreamController<void>.broadcast();
double get progress => _progress;
double _progress = 0;
ProgressController({#required this.duration})
: assert(duration != null),
tickPeriod = _calculateTickPeriod(duration);
void start() {
_timer = Timer(duration, () {
_cancelTimers();
_setProgressAndNotify(1);
_timeoutController.add(null);
});
_periodicTimer = Timer.periodic(
tickPeriod,
(Timer timer) {
double progress = _calculateProgress(timer);
_setProgressAndNotify(progress);
},
);
}
void restart() {
_cancelTimers();
start();
}
Future<void> dispose() async {
await _cancelStreams();
_cancelTimers();
}
double _calculateProgress(Timer timer) {
double progress = timer.tick / smoothnessConstant;
if (progress > 1) return 1;
if (progress < 0) return 0;
return progress;
}
void _setProgressAndNotify(double value) {
_progress = value;
_progressController.add(null);
}
Future<void> _cancelStreams() async {
if (!_progressController.isClosed) await _progressController.close();
if (!_timeoutController.isClosed) await _timeoutController.close();
}
void _cancelTimers() {
if (_timer?.isActive == true) _timer.cancel();
if (_periodicTimer?.isActive == true) _periodicTimer.cancel();
}
static Duration _calculateTickPeriod(Duration duration) {
double tickPeriodMs = duration.inMilliseconds / smoothnessConstant;
return Duration(milliseconds: tickPeriodMs.toInt());
}
}
Then you can implement a CircularProgressIndicator that listens to the Streams from ProgressController:
class RestartableCircularProgressIndicator extends StatefulWidget {
final ProgressController controller;
final VoidCallback onTimeout;
RestartableCircularProgressIndicator({
Key key,
#required this.controller,
this.onTimeout,
}) : assert(controller != null),
super(key: key);
#override
_RestartableCircularProgressIndicatorState createState() =>
_RestartableCircularProgressIndicatorState();
}
class _RestartableCircularProgressIndicatorState
extends State<RestartableCircularProgressIndicator> {
ProgressController get controller => widget.controller;
VoidCallback get onTimeout => widget.onTimeout;
#override
void initState() {
super.initState();
controller.progressStream.listen((_) => updateState());
controller.timeoutStream.listen((_) => onTimeout());
}
#override
Widget build(BuildContext context) {
return CircularProgressIndicator(
value: controller.progress,
);
}
void updateState() => setState(() {});
}
You can also pass some of the paramers of CircularProgressIndicator to RestartableCircularProgressIndicator, so you can customize it.
A usage example:
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ProgressController controller;
#override
void initState() {
super.initState();
controller = ProgressController(
duration: Duration(seconds: 5),
);
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RestartableCircularProgressIndicator(
controller: controller,
onTimeout: () => print('timeout'),
),
RaisedButton(
onPressed: controller.start,
child: Text('Start'),
),
RaisedButton(
onPressed: controller.restart,
child: Text('Restart'),
),
],
),
),
),
);
}
}
I'll convert this into a library someday, but until then I cannot provide the tests and documentation to this code, so you have to study it if you want to understand what's going on here (I'm sorry...).