Flutter LocalNotification Plugin, Showing notification every 2 hours - dart

How do I change this _repeatNotification() method, to repeat every 2 hours?
Future _repeatNotification() async {
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'repeating channel id',
'repeating channel name',
'repeating description');
var iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.periodicallyShow(0, 'repeating title',
'repeating body', RepeatInterval.EveryMinute, platformChannelSpecifics);
}

Referring to: https://pub.dartlang.org/documentation/flutter_local_notifications/latest/flutter_local_notifications/FlutterLocalNotificationsPlugin/periodicallyShow.html
This package only offers 4 enums for periodically showing notification.
What you can do is to edit it's source code.
Here: https://github.com/MaikuB/flutter_local_notifications/blob/master/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java#L266
change 60000 * 60 to 60000 * 60 * 2
Remember to keep the backup of your original package.

Related

Assert all the items emitted by a Stream in order until it is canceled in Dart?

Is there any convenient way to assert all the items emitted by a Stream in order until it is canceled?
If I use:
expectLater(
stream,
emitsInOrder(<String>[
'item1',
'item2',
]),
);
and the Stream emits ['item1', 'item2', 'item3'] , the test won't fail.
The only way I've found so far is the following:
var count = 0;
final expected = ['item1', 'item2', 'item3'];
stream.listen(
expectAsync1(
(final result) {
expect(result, expected[count++]);
},
count: expected.length,
),
);
But it is a bit verbose and not very easy to read. Is there a simpler/more elegant way?
You can collect the items into a list, using toList, then compare it to your own expectation list:
await expectLater(stream.toList(), completion(expected));
This does not handle the case where the stream doesn't close at all (but then, nothing does, you just have to wait for a timeout).
It doesn't catch errors until all events have been emitted, the emitsInOrder approach is better for that. Not shorter, though.
emitsDone can be used if the Stream is closed at some point.
E.g:
test('Test', () async {
final controller = StreamController<String>();
final stream = controller.stream;
final matcher = expectLater(
stream,
emitsInOrder(<dynamic>[
'Item1',
'Item2',
emitsDone,
]),
);
controller
..add('Item1')
..add('Item2')
..add('Item3')
..close();
await matcher;
await controller.close();
});
The test fails with error:
Expected: should do the following in order:
• emit an event that 'Item1'
• emit an event that 'Item2'
• be done
Actual: <Instance of '_ControllerStream<String>'>
Which: emitted • Item1
• Item2
• Item3
x Stream closed.
which didn't be done
As #Irn suggest, a more compact alternative for Streams that complete at some point is using toList:
test('Test', () async {
final controller = StreamController<String>();
final stream = controller.stream;
final matcher = expectLater(stream.toList(), completion(<String>['Item1', 'Item2']));
controller
..add('Item1')
..add('Item2')
..add('Item3')
..close();
await matcher;
await controller.close();
});
If the Stream is never closed, you can add a timeout and check the items that have been emitted in that period:
test('Test3', () async {
final controller = StreamController<String>();
final stream = controller.stream.timeout(const Duration(milliseconds: 200));
final matcher = expectLater(
stream,
emitsInOrder(<dynamic>[
'Item1',
'Item2',
]),
);
controller
..add('Item1')
..add('Item2');
await matcher;
await controller.close();
});

Alarm clock or timing notification in Flutter

Hello i'm some new with flutter and i need to do an alarm or a timing notification.I need some like AlarmManager in Android Studio.
I'm taking the hour from my server so i need the alarm or notification runs with that hour. I'll be so grateful if someone can help me thanks.
You can try using flutter_local_notifications for configuring a timer and notification in Flutter.
Here's a code snippet that sends out an hourly notification.
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
// hourly notification schedule config, set to either `hours: 1` or `minutes: 60`
var scheduledNotificationDateTime =
DateTime.now().add(Duration(minutes: 60));
Future<void> _showNotificationHourly() async {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'your other channel id',
'your other channel name',
'your other channel description',),
);
const IOSNotificationDetails iOSPlatformChannelSpecifics =
IOSNotificationDetails();
const MacOSNotificationDetails macOSPlatformChannelSpecifics =
MacOSNotificationDetails();
const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
macOS: macOSPlatformChannelSpecifics);
// https://pub.dev/documentation/flutter_local_notifications/latest/#scheduling-a-notification
await flutterLocalNotificationsPlugin.zonedSchedule(
0,
'scheduled title',
'scheduled body',
scheduledNotificationDateTime,
platformChannelSpecifics);
}

Flutter: How to get upload / download progress for http requests

I am writing an app that uploads an image to a server, and instead of just showing a spinner, I'd love to be able to get progress on the status of that upload.
Additionally, I want to do this without using Multipart form data. This is the code I'm currently using - but it appears to be stalling out with a broken pipe, and I have zero feedback as to whether data is being sent to the server:
Future<String> _uploadFile(File assetFile) async {
final url = <removed>;
final stream = await assetFile.openRead();
int length = assetFile.lengthSync();
final client = new HttpClient();
final request = await client.postUrl(Uri.parse(url));
request.headers.add(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
request.contentLength = length;
await request.addStream(stream);
final response = await request.close();
// response prociessing.
}
Is it possible to send large data as a stream without reading it into memory, and can I get progress on that upload with current dart / flutter APIs?
Screenshot (Null Safe):
This solution
Downloads an image from server.
Shows downloading progress.
After download, the image is saved to device storage.
Code:
import 'package:http/http.dart' as http;
class _MyPageState extends State<MyPage> {
int _total = 0, _received = 0;
late http.StreamedResponse _response;
File? _image;
final List<int> _bytes = [];
Future<void> _downloadImage() async {
_response = await http.Client()
.send(http.Request('GET', Uri.parse('https://upload.wikimedia.org/wikipedia/commons/f/ff/Pizigani_1367_Chart_10MB.jpg')));
_total = _response.contentLength ?? 0;
_response.stream.listen((value) {
setState(() {
_bytes.addAll(value);
_received += value.length;
});
}).onDone(() async {
final file = File('${(await getApplicationDocumentsDirectory()).path}/image.png');
await file.writeAsBytes(_bytes);
setState(() {
_image = file;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
label: Text('${_received ~/ 1024}/${_total ~/ 1024} KB'),
icon: Icon(Icons.file_download),
onPressed: _downloadImage,
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: SizedBox.fromSize(
size: Size(400, 300),
child: _image == null ? Placeholder() : Image.file(_image!, fit: BoxFit.fill),
),
),
),
);
}
}
The way that you are already using Stream means that you are not reading the whole file into memory. It's being read in as, probably, 64k chunks.
You could intercept the stream between the producer (File) and consumer (HttpClient) with a StreamTransformer, like this:
int byteCount = 0;
Stream<List<int>> stream2 = stream.transform(
new StreamTransformer.fromHandlers(
handleData: (data, sink) {
byteCount += data.length;
print(byteCount);
sink.add(data);
},
handleError: (error, stack, sink) {},
handleDone: (sink) {
sink.close();
},
),
);
....
await request.addStream(stream2);
You should see byteCount incrementing in 64k chunks.
Try dio library. The onSendProgress callback would be helpful.
example:
response = await dio.post(
"http://www.example.com",
data: data,
onSendProgress: (int sent, int total) {
print("$sent $total");
},
);
Reference: https://github.com/flutterchina/dio/issues/103
Update:
A day after posting this I realized that this is not actually measuring the upload progress, but only the progress of reading the bytes from the local JSON payload, which is almost instantaneous. If/when I figure out how to actually measure the upload progress, I'll update this answer.
Original Answer:
This works for me, without using Multipart:
import 'dart:convert';
import 'package:http/http.dart' as http;
// ...
final jsonPayload = {'base64File': 'abc123', 'something': 'else'};
// We are using a StreamedRequest so we can track the upload progress
final streamedRequest = http.StreamedRequest("POST", apiUri);
streamedRequest.headers['content-type'] = 'application/json';
// Length transferred (to calculate upload progress)
var transferredLength = 0;
// Upload progress (from 0.0 to 1.0)
var uploadProgress = 0.0;
// The stringified JSON payload
var stringEncodedPayload = jsonEncode(jsonPayload);
// Total length (to calculate upload progress)
var totalLength = stringEncodedPayload.length;
// Create a stream of the payload string
Stream.value(stringEncodedPayload)
// Transform the string-stream to a byte stream (List<int>)
.transform(utf8.encoder)
// Start reading the stream in chunks, submitting them to the streamedRequest for upload
.listen((chunk) {
transferredLength += chunk.length;
uploadProgress = transferredLength / totalLength;
print("Chunk: ${chunk.length}, transferred: $transferredLength, progress: $uploadProgress");
streamedRequest.sink.add(chunk);
}, onDone: () {
print("Done. Total: $totalLength, transferred: $transferredLength, progress: $uploadProgress");
streamedRequest.sink.close();
});
final result = await client.send(streamedRequest).then(http.Response.fromStream);
print("----------->");
print(result.statusCode);
print(result.body);
print("<-----------");
The output:
flutter: Chunk: 1024, transferred: 1024, progress: 0.0008807503580198599
flutter: Chunk: 1024, transferred: 2048, progress: 0.0017615007160397197
flutter: Chunk: 1024, transferred: 3072, progress: 0.0026422510740595796
...
flutter: Chunk: 1024, transferred: 1159168, progress: 0.9970094052784814
flutter: Chunk: 1024, transferred: 1160192, progress: 0.9978901556365013
flutter: Chunk: 1024, transferred: 1161216, progress: 0.9987709059945211
flutter: Chunk: 1024, transferred: 1162240, progress: 0.9996516563525409
flutter: Chunk: 405, transferred: 1162645, progress: 1.0
flutter: Done. Total: 1162645, transferred: 1162645, progress: 1.0

Push Notifications using Firebase/Google Cloud Functions

I am trying to send a notification when a number is written to _random. I am able to get the device token, and the cloud function works perfectly. However, I do not receive the notification on the simulator. I am using the notification token that is pushed to Firebase to test with. If anybody can help, it will be highly appreciated.
https://i.stack.imgur.com/OB94c.png
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
//Initial function call:
exports.makeRandomFigures = functions.https.onRequest((req, res) => {
    //create database ref
    var rootRef = admin.database().ref();
    var doc_count_temp = 0;
    var keys = [];
    var random_num = 0;
    //get document count
    rootRef.once('value', (snapshot) => {
        doc_count_temp = snapshot.numChildren();
        //real number of member. if delete _timeStamp then minus 2 not 3!
        var doc_count = doc_count_temp - 3;
        //get num array previous generated
        var xRef = rootRef.child("_usedFigures");
        xRef.once('value', function(snap) {
            snap.forEach(function(item) {
                var itemVal = item.val();
                keys.push(itemVal);
            });
            //get non-duplicated random number
            var is_equal = true;
            while (is_equal) {
                random_num = Math.floor((Math.random() * doc_count) + 1);
                is_equal = keys.includes(random_num);
            }
            //insert new random vaule to _usedFigures collection
            rootRef.child('_usedFigures').push(random_num);
            rootRef.child('_random').set(random_num);
        });
    });
    //send back response
    res.redirect(200);
});
exports.sendFigureNotification = functions.database.ref('_random').onWrite(event => {
const payload = {
notification: {
title: 'Title',
body: `Test`, //use _random to get figure at index key
badge: '1',
sound: 'default'
}
};
const options = {
priority: "high",
timeToLive: 60 * 60 * 24, //24 hours
content_available: true
};
const token = "cge0F9rUTLo:APA91bGNF3xXI-5uxrdj8BYqRPkxUPA5x9IQALtm3VEFJAdV2WQrQufNkzIclT5B671mBcvR6IDMbgSKyL7iG2jAuxRM3qR3MXhkNp1_utlXhCpE2VZqTw6Yw3d4iMMvHl1B-Cvik6NY";
console.log('Sending notifications');
return admin.messaging().sendToDevice(token, payload, options);
});
You can't get push notifications on the simulator.
To try some alternative ways check this link :
How can I test Apple Push Notification Service without an iPhone?

How to use setInterval/setTimeout in Dart SDK 0.4+

I realised that in current Dart SDK version 0.4.1.0_r19425 methods like setTimeout, setInterval, clearTimeout, clearInterval aren't part of Window class any more and they all moved to WorkerContext.
Is there any documentation on how to use them now? Do I need to create a new instance of WorkerContext every time I want to use them?
In addition to Timer mentioned by Chris, there is a Future-based API:
var future = new Future.delayed(const Duration(milliseconds: 10), doStuffCallback);
There is not yet direct support for cancelling a Future callback, but this works pretty well:
var future = new Future.delayed(const Duration(milliseconds: 10));
var subscription = future.asStream().listen(doStuffCallback);
// ...
subscription.cancel();
Hopefully, there will soon be a Stream version of Timer.repeating as well.
You can use:
1) SetInterval
_timer = new Timer.periodic(const Duration(seconds: 2), functionBack);
Where: `functionBack(Timer timer) {
print('again');
}
2) SetTimeOut
_timer = Timer(Duration(seconds: 5), () => print('done'));
Where _time is type Time
From this post on the group (Feb 14th 2013).
// Old Version
window.setTimeout(() { doStuff(); }, 0);
// New Version
import 'dart:async';
Timer.run(doStuffCallback);
And another example (copied from the same post)
// Old version:
var id = window.setTimeout(doStuffCallback, 10);
.... some time later....
window.clearTimeout(id);
id = window.setInterval(doStuffCallback, 1000);
window.clearInterval(id);
// New version:
var timer = new Timer(const Duration(milliseconds: 10), doStuffCallback);
... some time later ---
timer.cancel();
timer = new Timer.repeating(const Duration(seconds: 1), doStuffCallback);
timer.cancel();
Specifically, they are now part of the Timer class in the dart:async library (rather than WorkerContext, which seems to be IndexedDb specific). API docs here

Resources