I'm making a screen with creating a pin code to enter the application. But unfortunately my code doesn't work.
I'm trying to implement this through local storage. Here's the logic - as soon as the user goes to the create screen, I check if there is a pin code in the local storage.
Here is the function -
Future<int?> sharedPrefsGet() async {
final prefs = await SharedPreferences.getInstance();
print(await prefs.getInt('pinCode'));
return await prefs.getInt('pinCode');
}
late final Future<int?> future = sharedPrefsGet();
void initState() {
super.initState();
sharedPrefsGet();
}
Further, when entering the pin code, I check if there is a pin code and what will happen -
onCompleted: (value) async {
pinCode = int parse(value);
sharedPrefsSet(pinCode);
if(sharedPrefsGet() == value) {
context.go('/home');
} else {
context.go('/createPinCode');
}
context.go('/createPinCode');
},
and of course, there I try to save the pin code to the local storage. Here is the function -
var pinCode;
sharedPrefsSet(int pin) async {
final prefs = await SharedPreferences.getInstance();
return await prefs.setInt('pinCode', pin);
}
but my code doesn't work, I don't get any errors.
The user enters the password, this screen opens again, he enters the code again, but navigation to the home page no longer occurs. Why?
full code -
class CreatePinCode extends StatefulWidget {
#override
_CreatePinCodeState createState() => _CreatePinCodeState();
}
class _CreatePinCodeState extends State<CreatePinCode> {
final TextEditingController _controller = TextEditingController();
var pinCode;
sharedPrefsSet(int pin) async {
final prefs = await SharedPreferences.getInstance();
return await prefs.setInt('pinCode', pin);
}
Future<int?> sharedPrefsGet() async {
final prefs = await SharedPreferences.getInstance();
print(await prefs.getInt('pinCode'));
return await prefs.getInt('pinCode');
}
late final Future<int?> future = sharedPrefsGet();
#override
void initState() {
super.initState();
sharedPrefsGet();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ConfigColor.background,
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FutureBuilder(
future: future,
builder: (context, snapshot) =>
snapshot.hasData? Text('123123123123123') : Text('ababababab')
),
Padding(
padding: const EdgeInsets.all(100),
child: SizedBox(
height: 70,
child: Center(
child: PinCodeTextField(
controller: _controller,
mainAxisAlignment: MainAxisAlignment.spaceAround,
obscuringWidget: Container(
width: 15,
height: 15,
decoration: BoxDecoration(
color: ConfigColor.green,
shape: BoxShape.circle
),
),
appContext: context,
length: 4,
onChanged: (value) {
print(value);
},
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(50),
fieldHeight: 15,
fieldWidth: 15,
activeColor: ConfigColor.green,
inactiveColor: Colors.white.withOpacity(0.3),
disabledColor: Colors.white.withOpacity(0.3),
),
onCompleted: (values) async {
final prefs = await SharedPreferences.getInstance();
final pinCod = await prefs.setInt('pinCod', int.parse(values));
if(!pinCod) {// either true or false
if(pinCod == int.parse(values)) {
log('Все хорошо');
} else {
log('Код не совпадает!');
}
}
pinCode = int.parse(values);
final int? value = await sharedPrefsGet() ;
if(value== null) {
context.go('/createPinCode');
} else if (value == pinCode){
await sharedPrefsSet(pinCode);
context.go('/home');
} else {
}
},
)
),
),
),
// implement the custom NumPad
NumPad(
buttonSize: 65,
buttonColor: ConfigColor.background,
iconColor: Colors.deepOrange,
controller: _controller,
delete: () {
_controller.text = _controller.text
.substring(0, _controller.text.length - 1);
},
// do something with the input numbers
onSubmit: () {
debugPrint('Your code: ${_controller.text}');
showDialog(
context: context,
builder: (_) => AlertDialog(
content: Text(
"You code is ${_controller.text}",
style: const TextStyle(fontSize: 30),
),
));
},
),
],
)
);
}
}
It would better add return type on sharedPrefsGet while it is returning a future.
Future<int> sharedPrefsGet() async {
Using Future builder to get data.
sharedPrefsSet(int pin) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('pinCode', pin);
}
Future<int?> sharedPrefsGet() async {
final prefs = await SharedPreferences.getInstance();
print(await prefs.getInt('pinCode'));
return await prefs.getInt('pinCode');
}
late final Future<int?> future = sharedPrefsGet();
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: future,
builder: (context, snapshot) =>
snapshot.hasData?
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
!snapshot.hasData ? Text('ababababab') : Text('123123123'),
.........
And use await to get data
onCompleted: (value) async {
final prefs = await SharedPreferences.getInstance();
final pinCod = await prefs.setInt('pinCod', int.parse(value));
if(!pinCod) {// either true or false
if(pinCod == int.parse(value)) {
log('Все хорошо');
} else {
log('Код не совпадает!');
}
}
pinCode = int.parse(value);
final int? value = await sharedPrefsGet() ;
if(value== null) {
} else if (value== youValue){
await sharedPrefsSet(pinCode);
} else {
}
},
problem is here :
sharedPrefsGet() async {
final prefs = await SharedPreferences.getInstance();
print(await prefs.getInt('pinCode'));
return await prefs.getInt('pinCode');
}
when you are doing this : prefs.getInt('pinCode')
Instead of this Try to do this :
sharedPrefsGet() async {
final prefs = await SharedPreferences.getInstance();
print(await prefs.getInt('pinCode') ?? -1);
return await prefs.getInt('pinCode') ?? -1; //here -1 means not given pin
}
now add your code for this logic
Related
I am using [background_locator_2][1] plugin, However when I run it with some modification I get this error
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Null' is not a subtype of type 'LocationDto'
This is the code i am using
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ReceivePort port = ReceivePort();
String logStr = '';
bool? isRunning;
LocationDto? lastLocation;
#override
void initState() {
super.initState();
if (IsolateNameServer.lookupPortByName(
LocationServiceRepository.isolateName) !=
null) {
IsolateNameServer.removePortNameMapping(
LocationServiceRepository.isolateName);
}
IsolateNameServer.registerPortWithName(
port.sendPort, LocationServiceRepository.isolateName);
port.listen(
(dynamic data) async {
await updateUI(data);
},
);
initPlatformState();
}
#override
void dispose() {
super.dispose();
}
Future<void> updateUI(LocationDto data) async {
final log = await FileManager.readLogFile();
await _updateNotificationText(data);
setState(() {
lastLocation = data;
logStr = log;
});
}
Future<void> _updateNotificationText(LocationDto data) async {
if (data == null) {
return;
}
await BackgroundLocator.updateNotificationText(
title: "new location received",
msg: "${DateTime.now()}",
bigMsg: "${data.latitude}, ${data.longitude}");
}
Future<void> initPlatformState() async {
print('Initializing...');
await BackgroundLocator.initialize();
logStr = await FileManager.readLogFile();
print('Initialization done');
final _isRunning = await BackgroundLocator.isServiceRunning();
setState(() {
isRunning = _isRunning;
});
print('Running ${isRunning.toString()}');
}
#override
Widget build(BuildContext context) {
final start = SizedBox(
width: double.maxFinite,
child: ElevatedButton(
child: Text('Start'),
onPressed: () {
_onStart();
},
),
);
final stop = SizedBox(
width: double.maxFinite,
child: ElevatedButton(
child: Text('Stop'),
onPressed: () {
onStop();
},
),
);
final clear = SizedBox(
width: double.maxFinite,
child: ElevatedButton(
child: Text('Clear Log'),
onPressed: () {
FileManager.clearLogFile();
setState(() {
logStr = '';
});
},
),
);
String msgStatus = "-";
if (isRunning != null) {
if (isRunning!) {
msgStatus = 'Is running';
} else {
msgStatus = 'Is not running';
}
}
final status = Text("Status: $msgStatus");
final log = Text(
logStr,
);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter background Locator'),
),
body: Container(
width: double.maxFinite,
padding: const EdgeInsets.all(22),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[start, stop, clear, status, log],
),
),
),
),
);
}
void onStop() async {
await BackgroundLocator.unRegisterLocationUpdate();
final _isRunning = await BackgroundLocator.isServiceRunning();
setState(() {
isRunning = _isRunning;
});
}
void _onStart() async {
//if (await isLocationAlwaysGranted()) {
await _startLocator();
final _isRunning = await BackgroundLocator.isServiceRunning();
setState(() {
isRunning = _isRunning;
lastLocation = null;
});
// } else {
// show error
}
}
Future<bool> isLocationAlwaysGranted() async =>
await Permission.locationAlways.isGranted;
/// Tries to ask for "location always" permissions from the user.
/// Returns `true` if successful, `false` othervise.
Future<bool> askForLocationAlwaysPermission() async {
bool granted = await Permission.locationAlways.isGranted;
if (!granted) {
granted =
await Permission.locationAlways.request() == PermissionStatus.granted;
}
return granted;
}
Future<void> _startLocator() async {
Map<String, dynamic> data = {'countInit': 1};
return await BackgroundLocator.registerLocationUpdate(
LocationCallbackHandler.callback,
initCallback: LocationCallbackHandler.initCallback,
initDataCallback: data,
disposeCallback: LocationCallbackHandler.disposeCallback,
iosSettings: IOSSettings(
accuracy: LocationAccuracy.NAVIGATION,
distanceFilter: 0,
stopWithTerminate: true),
autoStop: false,
androidSettings: AndroidSettings(
accuracy: LocationAccuracy.NAVIGATION,
interval: 5,
distanceFilter: 0,
client: LocationClient.google,
androidNotificationSettings: AndroidNotificationSettings(
notificationChannelName: 'Location tracking',
notificationTitle: 'Start Location Tracking',
notificationMsg: 'Track location in background',
notificationBigMsg:
'Background location is on to keep the app up-tp-date with your location. This is required for main features to work properly when the app is not running.',
notificationIconColor: Colors.grey,
notificationTapCallback:
LocationCallbackHandler.notificationCallback)));
}
The error is in this line under initState when I start or stop the plugin.
port.listen(
(dynamic data) async {
await updateUI(data);
},
);
The original code didn't have null safety so i tried to modify it. However it is pretty evident my knowledge is limited.
[1]: https://pub.dev/packages/background_locator_2
the data you are listening to from the port (dynamic data) can be null and you are sending it to the function updateUI which does not accept nullable type.
you can either check if the data is not null before calling await updateUI(data); or you can make the function updateUI accepts null, i.e (Future<void> updateUI(LocationDto? data) async {) and handle the case that the data is nullable inside the function
I'm trying to add one alert box for language selection, but couldn't figure out the builder error I'm facing.
it was working fine with flutter older version but not with 2.2.3 version of flutter
Thanks
for the help
Looking forward for the solution
The named parameter 'builder' is required, but there's no corresponding argument.
The named parameter 'child' isn't defined.
Undefined name 'Utils'.
Future <void> _languageCheck() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final firstRun = prefs.getBool("firstRunLanguage");
(firstRun ?? false)
? () {}
: await showDialog(
barrierDismissible: false,
context: context,
child: AlertDialog(content: LanguageDialog()));
await prefs.setBool('firstRunLanguage', true);
}
Widget
class LanguageDialog extends StatefulWidget {
#override
_LanguageDialogState createState() => _LanguageDialogState();
}
class _LanguageDialogState extends State<LanguageDialog> {
var langCode = "en";
void getLanguage() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
langCode = prefs.getString("language") ?? kAdvanceConfig['DefaultLanguage'];
printLog("langCode-->$langCode");
setState(() {});
}
#override
void initState() {
super.initState();
getLanguage();
}
#override
Widget build(BuildContext context) {
List<Widget> list = [];
List<Map<String, dynamic>> languages = Utils.getLanguagesList(context);
for (var i = 0; i < languages.length; i++) {
// if (langCode == languages[i]["code"]) {
// print(languages[i]["code"]);
// }
list.add(
ListTile(
leading: Image.asset(
languages[i]["icon"],
width: 30,
height: 20,
fit: BoxFit.cover,
),
title: Text(languages[i]["name"]),
trailing: langCode == languages[i]["code"]
? const Icon(
Icons.radio_button_checked,
color: Colors.teal,
)
: const Icon(
Icons.radio_button_off,
color: Colors.teal,
),
onTap: () async {
setState(() {
langCode = languages[i]["code"];
});
await Provider.of<AppModel>(context, listen: false)
.changeLanguage(languages[i]["code"], context);
},
),
);
if (i < languages.length - 1) {
list.add(
Divider(
color: Theme.of(context).primaryColorLight,
height: 1.0,
indent: 75,
//endIndent: 20,
),
);
}
}
return SingleChildScrollView(
child: Column(
children: [
...list,
const LinearProgressIndicator(),
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("OK")),
],
),
);
}
}
showDialog doesn't have child, use its builder like
await showDialog(
barrierDismissible: false,
context: context,
builder: (context) => // here
AlertDialog(content: LanguageDialog()))
More on showDialog
You used showDialog() method which has a required parameter caller builder so you must provide the builder argument so try like below
Future <void> _languageCheck(BuildContext context) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final firstRun = prefs.getBool("firstRunLanguage");
(firstRun ?? false)
? () {}
: await showDialog(
barrierDismissible: false,
context: context,
/// this builder parameter is required
builder:(context) => AlertDialog(content: LanguageDialog()));
await prefs.setBool('firstRunLanguage', true);
}
I'm trying to display a loading while doing an API Request and when finished to show the list with the response or a custom widget to show a message(EmptyListWidget). The problem is that the whenComplete() method is being executed before the async function is finished.
I also tried using then() and using FutureBuilder but I also can't make it work using Provider (allways returns null).
If someone could help, I would really appreciate it.. thanks :)
My List Widget:
class _AbsencesListState extends State<AbsencesList> {
bool _isLoading = false;
bool _isInit = true;
#override
void didChangeDependencies() {
super.didChangeDependencies();
if (_isInit) {
setState(() => _isLoading = true);
Provider.of<AbsencesTypes>(context, listen: false)
.getAbsencesTypes(widget.ctx)
.whenComplete(() {
setState(() => _isLoading = false);
});
_isInit = false;
}
}
#override
Widget build(BuildContext context) {
final absences = Provider.of<Absences>(context).items;
return Stack(
children: [
_isLoading
? const Center(child: CircularProgressIndicator())
: absences.length > 0
? Container()
: EmptyListWidget(ListType.InconsistenciesList),
ListView.builder(
itemBuilder: (_, index) {
return GestureDetector(
onTap: () {},
child: Card(
elevation: 2.0,
child: ListTile(
leading: CircleAvatar(
child: const Icon(Icons.sick),
backgroundColor: Theme.of(context).accentColor,
foregroundColor: Colors.white,
),
title: Padding(
padding: const EdgeInsets.only(top: 3),
child: Text(absences[index].absenceType.name),
),
subtitle: Text(
absences[index].firstDate
),
),
),
);
},
itemCount: absences.length,
)
],
);
}
}
The async function:
class AbsencesTypes with ChangeNotifier {
List<AbsenceType> _absencesTypesList = [];
List<AbsenceType> get items {
return [..._absencesTypesList];
}
void emptyAbsencesTypeList() {
_absencesTypesList.clear();
}
Future<void> getAbsencesTypes(BuildContext context) async {
SharedPreferences _prefs = await SharedPreferences.getInstance();
String token = _prefs.getString(TOKEN_KEY);
http.get(
API_URL,
headers: {"Authorization": token},
).then(
(http.Response response) async {
if (response.statusCode == 200) {
final apiResponse = json.decode(utf8.decode(response.bodyBytes));
final extractedData = apiResponse['content'];
final List<AbsenceType> loadedAbsencesTypes = [];
for (var absenceType in extractedData) {
loadedAbsencesTypes.add(
AbsenceType(
id: absenceType["id"],
name: absenceType["name"].toString(),
code: absenceType["code"].toString(),
totalAllowedDays: absenceType["totalAllowedDays"],
),
);
}
_absencesTypesList = loadedAbsencesTypes;
} else if (response.statusCode == 401) {
Utility.showToast(
AppLocalizations.of(context).translate("expired_session_string"));
Utility.sendUserToLogin(_prefs, context);
}
notifyListeners();
},
);
}
}
Your problem here is probably that you're calling http.get without awaiting for it's result.
The getAbsencesTypes returns the Future<void> as soon as the http.get method is executed, without waiting for the answer, and it results in your onComplete method to be triggered.
A simple fix would be to add the await keyword before the http.get, but you could do even better.
In your code, you're not fully using the ChangeNotifierProvider which could solve your problem. You should check the Consumer class which will be pretty useful for you here, but since it's not your initial question I won't go more in depth on this subject.
In my flutter project, i have a method that returns a String from the firebase:
Future<String> getNomeById(bool retirada, String userId) async {
QuerySnapshot snapshot = await firestore
.collection('users')
.where(FieldPath.documentId, isEqualTo: userId)
.getDocuments();
users = snapshot.documents.map((d) => User.fromDocument(d)).toList();
if (retirada) {
name = users[0].name;
} else {
name = 'Other';
}
return name;
}
Here I get the method return
u.getNomeById(retirada, userId).then((value) {
returnFutureString = value;
print(returnFutureString);//It's OK here
});
I need to use the return Future String in the title of my alertDialog,
I can't because my variable is null there, I know I'm doing it wrong, but I couldn't make it work by searching for similar examples.
class ExportAddressDialog extends StatelessWidget {
ExportAddressDialog(this.address, this.retirada, this.userId);
final Firestore firestore = Firestore.instance;
final Address address;
final bool retirada;
final String userId;
final ScreenshotController screenshotController = ScreenshotController();
#override
Widget build(BuildContext context) {
String returnFutureString;
Util u = new Util();
u.getNomeById(retirada, userId).then((value) {
returnFutureString = value;
print(returnFutureString);//It's OK here
});
return AlertDialog(
title: Text(returnFutureString),//I need to use my returnFutureString as the alert title, but is null here
content: Screenshot(
controller: screenshotController,
child: Container(
padding: const EdgeInsets.all(8),
color: Colors.white,
child: Text(
'${address.street}, ${address.number} ${address.complement}\n'
'${address.district}\n'
'${address.city}/${address.state}\n'
'${address.zipCode}',
),
),
),
contentPadding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
actions: <Widget>[
FlatButton(
onPressed: () async {
Navigator.of(context).pop();
final file = await screenshotController.capture();
await GallerySaver.saveImage(file.path);
},
textColor: Theme.of(context).primaryColor,
child: const Text('Exportar'),
)
],
);
}
Future<String> _getTitle() async {
String returnFutureString = await u.getNomeById(retirada, userId)
return returnFutureString;
}
Use FutureBuilder to fetch async values:
FutureBuilder<String>(
future: _getTitle(),
builder: (ctx, snapshot) {
if (snapshot.hasData) {
return AlertDialog(
title: Text(snapshot.data)
);
}
return Center(child: CircularProgressIndicator());
}
),);
I want launch the notification when the background process is triggered,
I tried call the notification class inside BackgroundFetch method but didn't work ,However when i print a debug message it works.
and i want to make this functionality isolated from the business logic of the app
this is my attempt
1-the notification class:
class LocalNotificationWidget extends StatefulWidget {
#override
_LocalNotificationWidgetState createState() =>
_LocalNotificationWidgetState();
}
class _LocalNotificationWidgetState extends State<LocalNotificationWidget> {
final notifications = FlutterLocalNotificationsPlugin();
#override
void initState() {
super.initState();
final settingsAndroid = AndroidInitializationSettings('app_icon');
final settingsIOS = IOSInitializationSettings(
onDidReceiveLocalNotification: (id, title, body, payload) =>
onSelectNotification(payload));
notifications.initialize(
InitializationSettings(settingsAndroid, settingsIOS),
onSelectNotification: onSelectNotification);
showOngoingNotification(notifications,
title: 'Tite', body: 'hello');
}
Future onSelectNotification(String payload) async => await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen( payload)),
);
#override
Widget build(BuildContext context) => Container();
Widget title(String text) => Container(
margin: EdgeInsets.symmetric(vertical: 4),
child: Text(
text,
style: Theme.of(context).textTheme.title,
textAlign: TextAlign.center,
),
);
}
2-the background service class:
const EVENTS_KEY = "fetch_events";
/// This "Headless Task" is run when app is terminated.
void backgroundFetchHeadlessTask() async {
print('[BackgroundFetch] Headless event received.');
SharedPreferences prefs = await SharedPreferences.getInstance();
// Read fetch_events from SharedPreferences
List<String> events = [];
String json = prefs.getString(EVENTS_KEY);
if (json != null) {
events = jsonDecode(json).cast<String>();
}
// Add new event.
events.insert(0, new DateTime.now().toString() + ' [Headless]');
// Persist fetch events in SharedPreferences
prefs.setString(EVENTS_KEY, jsonEncode(events));
BackgroundFetch.finish();
}
void main() {
// Enable integration testing with the Flutter Driver extension.
// See https://flutter.io/testing/ for more info.
runApp(new MyApp());
// Register to receive BackgroundFetch events after app is terminated.
// Requires {stopOnTerminate: false, enableHeadless: true}
BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _enabled = true;
int _status = 0;
List<String> _events = [];
#override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
// Load persisted fetch events from SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
String json = prefs.getString(EVENTS_KEY);
if (json != null) {
setState(() {
_events = jsonDecode(json).cast<String>();
});
}
// Configure BackgroundFetch.
BackgroundFetch.configure(BackgroundFetchConfig(
minimumFetchInterval: 15,
stopOnTerminate: false,
enableHeadless: true,
forceReload: false
), _onBackgroundFetch).then((int status) {
LocalNotificationWidget();
print('[BackgroundFetch] SUCCESS: $status');
setState(() {
_status = status;
});
}).catchError((e) {
print('[BackgroundFetch] ERROR: $e');
setState(() {
_status = e;
});
});
// Optionally query the current BackgroundFetch status.
int status = await BackgroundFetch.status;
setState(() {
_status = status;
});
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
}
void _onBackgroundFetch() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
// This is the fetch-event callback.
print('[BackgroundFetch] Event received');
setState(() {
_events.insert(0, new DateTime.now().toString());
});
// Persist fetch events in SharedPreferences
prefs.setString(EVENTS_KEY, jsonEncode(_events));
// IMPORTANT: You must signal completion of your fetch task or the OS can punish your app
// for taking too long in the background.
BackgroundFetch.finish();
}
void _onClickEnable(enabled) {
setState(() {
_enabled = enabled;
});
if (enabled) {
BackgroundFetch.start().then((int status) {
print('[BackgroundFetch] start success: $status');
}).catchError((e) {
print('[BackgroundFetch] start FAILURE: $e');
});
} else {
BackgroundFetch.stop().then((int status) {
print('[BackgroundFetch] stop success: $status');
});
}
}
void _onClickStatus() async {
int status = await BackgroundFetch.status;
print('[BackgroundFetch] status: $status');
setState(() {
_status = status;
});
}
void _onClickClear() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove(EVENTS_KEY);
setState(() {
_events = [];
});
}
#override
Widget build(BuildContext context) {
const EMPTY_TEXT = Center(child: Text('Waiting for fetch events. Simulate one.\n [Android] \$ ./scripts/simulate-fetch\n [iOS] XCode->Debug->Simulate Background Fetch'));
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('BackgroundFetch Example', style: TextStyle(color: Colors.black)),
backgroundColor: Colors.amberAccent,
brightness: Brightness.light,
actions: <Widget>[
Switch(value: _enabled, onChanged: _onClickEnable),
]
),
body: (_events.isEmpty) ? EMPTY_TEXT : Container(
child: new ListView.builder(
itemCount: _events.length,
itemBuilder: (BuildContext context, int index) {
String timestamp = _events[index];
return InputDecorator(
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 5.0, top: 5.0, bottom: 5.0),
labelStyle: TextStyle(color: Colors.blue, fontSize: 20.0),
labelText: "[background fetch event]"
),
child: new Text(timestamp, style: TextStyle(color: Colors.black, fontSize: 16.0))
);
}
),
),
bottomNavigationBar: BottomAppBar(
child: Container(
padding: EdgeInsets.only(left: 5.0, right:5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RaisedButton(onPressed: _onClickStatus, child: Text('Status: $_status')),
RaisedButton(onPressed: _onClickClear, child: Text('Clear'))
]
)
)
),
),
);
}
}