Posts in the “flutter” category

Getting Flutter notifications working on Android

Over the last two days I started to get my Just Be notifications working on Android. I’m rewriting the app using Flutter, and this is what a notification currently looks like if you do a long-press on the app icon after receiving a notification.

Flutter: A few ways to simulate slow-responding functions and methods

As a quick note, here are a couple of examples of how to simulate a slow-responding Flutter method:

Future<bool> _getFutureBool() {
    return Future.delayed(Duration(milliseconds: 500))
                 .then((onValue) => true);
}

static Future<bool> getEnableNotifications() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    return Future.delayed(const Duration(milliseconds: 1000), () {
        return prefs.getBool(KEY_ENABLE_NOTIFICATIONS) ?? false;      
    });
}

As shown, the first example uses Future.delayed followed by a then call, and the second example shows Future.delayed with a lambda function.

You’ll want to use this code/technique when you’re working with Flutter futures and its FutureBuilder class.

I was reminded about the need to test things likes futures and FutureBuilder when some code I found on the internet wasn’t working properly. As a result I wrote my tutorial, How to correctly create a Flutter FutureBuilder

How to use the Flutter CupertinoDatePicker in “time picker” mode

As a brief note, if you ever need to use the Flutter CupertinoDatePicker — a spinning wheel chooser — in “time-picker/time-chooser” mode, I can confirm that this example works:

child: CupertinoDatePicker(
    mode: CupertinoDatePickerMode.time,
    initialDateTime: DateTime(1969, 1, 1, _timeOfDay.hour, _timeOfDay.minute),
    onDateTimeChanged: (DateTime newDateTime) {
        var newTod = TimeOfDay.fromDateTime(newDateTime);
        _updateTimeFunction(newTod);
    },
    use24hFormat: false,
    minuteInterval: 1,
)

Note that even when you only want to set an initial time value, the CupertinoDatePicker in CupertinoDatePickerMode.time mode requires that you pass it a DateTime value, so I just give it a date/time back in 1969:

initialDateTime: DateTime(1969, 1, 1, _timeOfDay.hour, _timeOfDay.minute),

You can set the year, month, and day to whatever you want; the only important values in CupertinoDatePickerMode.time mode are the hour and minute.

A complete CupertinoDatePicker/CupertinoDatePickerMode example

If it helps to see a complete CupertinoDatePicker/CupertinoDatePickerMode example, here you go:

import 'package:flutter/material.dart';
import 'shared_prefs_helper.dart';
import 'package:flutter/cupertino.dart';

class PreferencesSelectTime extends StatefulWidget {
    String _title;
    TimeOfDay _timeOfDay;
    Function _updateTimeFunction;

    PreferencesSelectTime(this._title, this._timeOfDay, this._updateTimeFunction);

    @override
    PreferencesSelectTimeState createState() => PreferencesSelectTimeState(_title, _timeOfDay, _updateTimeFunction);
}

class PreferencesSelectTimeState extends State<PreferencesSelectTime> {

    String _title;
    TimeOfDay _timeOfDay;
    Function _updateTimeFunction;
    PreferencesSelectTimeState(this._title, this._timeOfDay, this._updateTimeFunction);

    @override
    Widget build(BuildContext context) {

        return Scaffold(
            appBar: AppBar(
                title: Text(_title),
            ),
            body: FutureBuilder<TimeOfDay>(
                future: SharedPreferencesHelper.getStartTime(),
                builder: (BuildContext context, AsyncSnapshot snapshot) {
                    if (snapshot.connectionState == ConnectionState.done) {
                        return Container(
                            height: MediaQuery.of(context).size.height / 4,
                                child: CupertinoDatePicker(
                                    mode: CupertinoDatePickerMode.time,
                                    initialDateTime: DateTime(1969, 1, 1, _timeOfDay.hour, _timeOfDay.minute),
                                    onDateTimeChanged: (DateTime newDateTime) {
                                        var newTod = TimeOfDay.fromDateTime(newDateTime);
                                        _updateTimeFunction(newTod);
                                    },
                                    use24hFormat: false,
                                    minuteInterval: 1,
                                )
                        );
                    } else {
                        return new CircularProgressIndicator();
                    }
                }
            )
        );
    }
}

I call that code from another widget like this:

onTap: () {
    Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => PreferencesSelectTime(
            'Notification Stop Time',
            _stopTime,
            SharedPreferencesHelper.setStopTime
        ))
    );
},

It generates a Flutter screen/widget that looks like this:

How to use the Flutter CupertinoDatePicker in “time picker” mode

Summary

In summary, if you ever want to use the Flutter CupertinoDatePicker in “time picker” mode, I hope this example code is helpful.

A Flutter function to convert a TimeOfDay to a String (formatted)

If you ever need a Dart/Flutter method to format a TimeOfDay variable — i.e., convert a TimeOfDay to a String — I can confirm that this method works:

String formatTimeOfDay(TimeOfDay tod) {
    final now = new DateTime.now();
    final dt = DateTime(now.year, now.month, now.day, tod.hour, tod.minute);
    final format = DateFormat.jm();  //"6:00 AM"
    return format.format(dt);
}

An example of a Flutter RadioListTile in a ListView

Here’s a little example of a Flutter time preferences widget, something I’ll be using in the new version of my Just Be app. Probably most important thing about this source code is that it shows an example of how to use the Flutter RadioListTile:

import 'package:flutter/material.dart';

class TimeValue {
    final int _key;
    final String _value;
    TimeValue(this._key, this._value);
}

class TimePreferencesWidget extends StatefulWidget {
    @override
    TimePreferencesWidgetState createState() => TimePreferencesWidgetState();
}

class TimePreferencesWidgetState extends State<TimePreferencesWidget> {
    int _currentTimeValue = 1;

    final _buttonOptions = [
        TimeValue(30,  "30 minutes"),
        TimeValue(60,  "1 hour"),
        TimeValue(120, "2 hours"),
        TimeValue(240, "4 hours"),
        TimeValue(480, "8 hours"),
        TimeValue(720, "12 hours"),
    ];

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text("Time Preferences"),
            ),
            body: ListView(
                padding: EdgeInsets.all(8.0),
                children: _buttonOptions.map((timeValue) => RadioListTile(
                    groupValue: _currentTimeValue,
                    title: Text(timeValue._value),
                    value: timeValue._key,
                    onChanged: (val) {
                        setState(() {
                            debugPrint('VAL = $val');
                            _currentTimeValue = val;
                        });
                    },
                )).toList(),
            ),
        );
    }
}

I initially wanted to create _buttonOptions as a Map, but I ended up creating the TimeValue class to get what I wanted. (I’m still new to Dart, and I couldn’t find a good way to convert _buttonOptions.map from a Map to a List, which is required for the children parameter, so I went with the approach shown.)

Here’s an image of what this code creates:

An example of a Flutter RadioListTile in a ListView

In summary, if you wanted to see an example of a Flutter RadioListTile inside a ListView, I hope this example is helpful.