Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ void initState() {
* `notificationTitle`: The title to display in the notification.
* `notificationText`: The text to display in the notification.
* `notificationIcon`: The icon to display in the notification. Go to [this page](./documentation/customize_notification_icon.md) to customize.
* `notificationProgress`: The progress bar to display in the notification. Use `NotificationProgress.none()` to hide an existing progress bar.
* `notificationButtons`: The buttons to display in the notification. (can add 0~3 buttons)
* `notificationInitialRoute`: Initial route to be used when the app is launched via a notification. Works the same as the `launchApp` utility.
* `callback`: A top-level function that calls the setTaskHandler function.
Expand All @@ -387,6 +388,7 @@ Future<ServiceRequestResult> _startService() async {
notificationTitle: 'Foreground Service is running',
notificationText: 'Tap to return to the app',
notificationIcon: null,
notificationProgress: const NotificationProgress(max: 100, progress: 0),
notificationButtons: [
const NotificationButton(id: 'btn_hello', text: 'hello'),
],
Expand Down Expand Up @@ -443,6 +445,7 @@ class FirstTaskHandler extends TaskHandler {
FlutterForegroundTask.updateService(
notificationTitle: 'Hello FirstTaskHandler :)',
notificationText: timestamp.toString(),
notificationProgress: NotificationProgress(max: 100, progress: _count),
);

// Send data to main isolate.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ object PreferencesKey {
const val NOTIFICATION_CONTENT_TITLE = "notificationContentTitle"
const val NOTIFICATION_CONTENT_TEXT = "notificationContentText"
const val NOTIFICATION_CONTENT_ICON = "icon"
const val NOTIFICATION_CONTENT_PROGRESS = "progress"
const val NOTIFICATION_CONTENT_BUTTONS = "buttons"
const val NOTIFICATION_INITIAL_ROUTE = "initialRoute"

Expand All @@ -57,4 +58,4 @@ object PreferencesKey {

// task data
const val CALLBACK_HANDLE = "callbackHandle"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ data class NotificationContent(
val title: String,
val text: String,
val icon: NotificationIcon?,
val progress: NotificationProgress?,
val buttons: List<NotificationButton>,
val initialRoute: String?
) {
Expand All @@ -26,6 +27,12 @@ data class NotificationContent(
icon = NotificationIcon.fromJsonString(iconJsonString)
}

val progressJsonString = prefs.getString(PrefsKey.NOTIFICATION_CONTENT_PROGRESS, null)
var progress: NotificationProgress? = null
if (progressJsonString != null) {
progress = NotificationProgress.fromJsonString(progressJsonString)
}

val buttonsJsonString = prefs.getString(PrefsKey.NOTIFICATION_CONTENT_BUTTONS, null)
val buttons: MutableList<NotificationButton> = mutableListOf()
if (buttonsJsonString != null) {
Expand All @@ -42,6 +49,7 @@ data class NotificationContent(
title = title,
text = text,
icon = icon,
progress = progress,
buttons = buttons,
initialRoute = initialRoute
)
Expand All @@ -60,6 +68,12 @@ data class NotificationContent(
iconJsonString = JSONObject(iconJson).toString()
}

val progressJson = map?.get(PrefsKey.NOTIFICATION_CONTENT_PROGRESS) as? Map<*, *>
var progressJsonString: String? = null
if (progressJson != null) {
progressJsonString = JSONObject(progressJson).toString()
}

val buttonsJson = map?.get(PrefsKey.NOTIFICATION_CONTENT_BUTTONS) as? List<*>
var buttonsJsonString: String? = null
if (buttonsJson != null) {
Expand All @@ -72,6 +86,7 @@ data class NotificationContent(
putString(PrefsKey.NOTIFICATION_CONTENT_TITLE, title)
putString(PrefsKey.NOTIFICATION_CONTENT_TEXT, text)
putString(PrefsKey.NOTIFICATION_CONTENT_ICON, iconJsonString)
putString(PrefsKey.NOTIFICATION_CONTENT_PROGRESS, progressJsonString)
putString(PrefsKey.NOTIFICATION_CONTENT_BUTTONS, buttonsJsonString)
putString(PrefsKey.NOTIFICATION_INITIAL_ROUTE, initialRoute)
commit()
Expand All @@ -91,6 +106,12 @@ data class NotificationContent(
iconJsonString = JSONObject(iconJson).toString()
}

val progressJson = map?.get(PrefsKey.NOTIFICATION_CONTENT_PROGRESS) as? Map<*, *>
var progressJsonString: String? = null
if (progressJson != null) {
progressJsonString = JSONObject(progressJson).toString()
}

val buttonsJson = map?.get(PrefsKey.NOTIFICATION_CONTENT_BUTTONS) as? List<*>
var buttonsJsonString: String? = null
if (buttonsJson != null) {
Expand All @@ -103,6 +124,7 @@ data class NotificationContent(
title?.let { putString(PrefsKey.NOTIFICATION_CONTENT_TITLE, it) }
text?.let { putString(PrefsKey.NOTIFICATION_CONTENT_TEXT, it) }
iconJsonString?.let { putString(PrefsKey.NOTIFICATION_CONTENT_ICON, it) }
progressJsonString?.let { putString(PrefsKey.NOTIFICATION_CONTENT_PROGRESS, it) }
buttonsJsonString?.let { putString(PrefsKey.NOTIFICATION_CONTENT_BUTTONS, it) }
initialRoute?.let { putString(PrefsKey.NOTIFICATION_INITIAL_ROUTE, it) }
commit()
Expand All @@ -119,4 +141,4 @@ data class NotificationContent(
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.pravera.flutter_foreground_task.models

import org.json.JSONObject

data class NotificationProgress(
val max: Int,
val progress: Int,
val indeterminate: Boolean,
val show: Boolean
) {
companion object {
fun fromJsonString(jsonString: String): NotificationProgress {
val jsonObj = JSONObject(jsonString)
val max = jsonObj.optInt("max", 0)
val progress = jsonObj.optInt("progress", 0)
val indeterminate = jsonObj.optBoolean("indeterminate", false)
val show = jsonObj.optBoolean("show", max > 0 || indeterminate)

return NotificationProgress(
max = max.coerceAtLeast(0),
progress = progress.coerceIn(0, max.coerceAtLeast(0)),
indeterminate = indeterminate,
show = show
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,13 @@ class ForegroundService : Service() {
builder.setContentTitle(notificationContent.title)
builder.setContentText(notificationContent.text)
builder.style = Notification.BigTextStyle()
notificationContent.progress?.let { progress ->
if (progress.show) {
builder.setProgress(progress.max, progress.progress, progress.indeterminate)
} else {
builder.setProgress(0, 0, false)
}
}
builder.setVisibility(notificationOptions.visibility)
builder.setOnlyAlertOnce(notificationOptions.onlyAlertOnce)
if (iconBackgroundColor != null) {
Expand Down Expand Up @@ -389,6 +396,13 @@ class ForegroundService : Service() {
builder.setContentTitle(notificationContent.title)
builder.setContentText(notificationContent.text)
builder.setStyle(NotificationCompat.BigTextStyle().bigText(notificationContent.text))
notificationContent.progress?.let { progress ->
if (progress.show) {
builder.setProgress(progress.max, progress.progress, progress.indeterminate)
} else {
builder.setProgress(0, 0, false)
}
}
builder.setVisibility(notificationOptions.visibility)
builder.setOnlyAlertOnce(notificationOptions.onlyAlertOnce)
if (iconBackgroundColor != null) {
Expand Down Expand Up @@ -613,4 +627,4 @@ class ForegroundService : Service() {

return actions
}
}
}
5 changes: 5 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ class MyTaskHandler extends TaskHandler {

void _incrementCount() {
_count++;
final int progress = _count % 10;

// Update notification content.
FlutterForegroundTask.updateService(
notificationTitle: 'Hello MyTaskHandler :)',
notificationText: 'count: $_count',
notificationProgress: progress == 0
? const NotificationProgress.none()
: NotificationProgress(max: 10, progress: progress),
);

// Send data to main isolate.
Expand Down Expand Up @@ -176,6 +180,7 @@ class _ExamplePageState extends State<ExamplePage> {
notificationTitle: 'Foreground Service is running',
notificationText: 'Tap to return to the app',
notificationIcon: null,
notificationProgress: const NotificationProgress(max: 10, progress: 0),
notificationButtons: [
const NotificationButton(id: 'btn_hello', text: 'hello'),
],
Expand Down
5 changes: 3 additions & 2 deletions lib/errors/service_already_started_exception.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class ServiceAlreadyStartedException implements Exception {
ServiceAlreadyStartedException(
[this.message = 'The service has already started.']);
ServiceAlreadyStartedException([
this.message = 'The service has already started.',
]);

final String message;

Expand Down
7 changes: 4 additions & 3 deletions lib/errors/service_not_initialized_exception.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
class ServiceNotInitializedException implements Exception {
ServiceNotInitializedException(
[this.message =
'Not initialized. Please call this function after calling the init function.']);
ServiceNotInitializedException([
this.message =
'Not initialized. Please call this function after calling the init function.',
]);

final String message;

Expand Down
7 changes: 4 additions & 3 deletions lib/errors/service_timeout_exception.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
class ServiceTimeoutException implements Exception {
ServiceTimeoutException(
[this.message =
'The service request timed out. (ref: https://developer.android.com/guide/components/services#StartingAService)']);
ServiceTimeoutException([
this.message =
'The service request timed out. (ref: https://developer.android.com/guide/components/services#StartingAService)',
]);

final String message;

Expand Down
6 changes: 6 additions & 0 deletions lib/flutter_foreground_task.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'models/notification_button.dart';
import 'models/notification_icon.dart';
import 'models/notification_options.dart';
import 'models/notification_permission.dart';
import 'models/notification_progress.dart';
import 'models/service_request_result.dart';
import 'task_handler.dart';
import 'utils/utility.dart';
Expand All @@ -33,6 +34,7 @@ export 'models/notification_icon.dart';
export 'models/notification_options.dart';
export 'models/notification_permission.dart';
export 'models/notification_priority.dart';
export 'models/notification_progress.dart';
export 'models/notification_visibility.dart';
export 'models/service_request_result.dart';
export 'ui/with_foreground_task.dart';
Expand Down Expand Up @@ -102,6 +104,7 @@ class FlutterForegroundTask {
required String notificationTitle,
required String notificationText,
NotificationIcon? notificationIcon,
NotificationProgress? notificationProgress,
List<NotificationButton>? notificationButtons,
String? notificationInitialRoute,
Function? callback,
Expand All @@ -124,6 +127,7 @@ class FlutterForegroundTask {
notificationTitle: notificationTitle,
notificationText: notificationText,
notificationIcon: notificationIcon,
notificationProgress: notificationProgress,
notificationButtons: notificationButtons,
notificationInitialRoute: notificationInitialRoute,
callback: callback,
Expand Down Expand Up @@ -160,6 +164,7 @@ class FlutterForegroundTask {
String? notificationTitle,
String? notificationText,
NotificationIcon? notificationIcon,
NotificationProgress? notificationProgress,
List<NotificationButton>? notificationButtons,
String? notificationInitialRoute,
Function? callback,
Expand All @@ -174,6 +179,7 @@ class FlutterForegroundTask {
notificationText: notificationText,
notificationTitle: notificationTitle,
notificationIcon: notificationIcon,
notificationProgress: notificationProgress,
notificationButtons: notificationButtons,
notificationInitialRoute: notificationInitialRoute,
callback: callback,
Expand Down
30 changes: 20 additions & 10 deletions lib/flutter_foreground_task_method_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ import 'models/notification_button.dart';
import 'models/notification_icon.dart';
import 'models/notification_options.dart';
import 'models/notification_permission.dart';
import 'models/notification_progress.dart';
import 'models/service_options.dart';
import 'task_handler.dart';

/// An implementation of [FlutterForegroundTaskPlatform] that uses method channels.
class MethodChannelFlutterForegroundTask extends FlutterForegroundTaskPlatform {
@visibleForTesting
final MethodChannel mMDChannel =
const MethodChannel('flutter_foreground_task/methods');
final MethodChannel mMDChannel = const MethodChannel(
'flutter_foreground_task/methods',
);

@visibleForTesting
final MethodChannel mBGChannel =
const MethodChannel('flutter_foreground_task/background');
final MethodChannel mBGChannel = const MethodChannel(
'flutter_foreground_task/background',
);

@visibleForTesting
Platform platform = const LocalPlatform();
Expand All @@ -42,6 +45,7 @@ class MethodChannelFlutterForegroundTask extends FlutterForegroundTaskPlatform {
required String notificationTitle,
required String notificationText,
NotificationIcon? notificationIcon,
NotificationProgress? notificationProgress,
List<NotificationButton>? notificationButtons,
String? notificationInitialRoute,
Function? callback,
Expand All @@ -55,6 +59,7 @@ class MethodChannelFlutterForegroundTask extends FlutterForegroundTaskPlatform {
notificationContentTitle: notificationTitle,
notificationContentText: notificationText,
notificationIcon: notificationIcon,
notificationProgress: notificationProgress,
notificationButtons: notificationButtons,
notificationInitialRoute: notificationInitialRoute,
callback: callback,
Expand All @@ -74,6 +79,7 @@ class MethodChannelFlutterForegroundTask extends FlutterForegroundTaskPlatform {
String? notificationTitle,
String? notificationText,
NotificationIcon? notificationIcon,
NotificationProgress? notificationProgress,
List<NotificationButton>? notificationButtons,
String? notificationInitialRoute,
Function? callback,
Expand All @@ -83,6 +89,7 @@ class MethodChannelFlutterForegroundTask extends FlutterForegroundTaskPlatform {
notificationContentTitle: notificationTitle,
notificationContentText: notificationText,
notificationIcon: notificationIcon,
notificationProgress: notificationProgress,
notificationButtons: notificationButtons,
notificationInitialRoute: notificationInitialRoute,
callback: callback,
Expand Down Expand Up @@ -214,8 +221,9 @@ class MethodChannelFlutterForegroundTask extends FlutterForegroundTaskPlatform {
@override
Future<bool> openIgnoreBatteryOptimizationSettings() async {
if (platform.isAndroid) {
return await mMDChannel
.invokeMethod('openIgnoreBatteryOptimizationSettings');
return await mMDChannel.invokeMethod(
'openIgnoreBatteryOptimizationSettings',
);
}
return true;
}
Expand Down Expand Up @@ -246,15 +254,17 @@ class MethodChannelFlutterForegroundTask extends FlutterForegroundTaskPlatform {

@override
Future<NotificationPermission> checkNotificationPermission() async {
final int result =
await mMDChannel.invokeMethod('checkNotificationPermission');
final int result = await mMDChannel.invokeMethod(
'checkNotificationPermission',
);
return NotificationPermission.fromIndex(result);
}

@override
Future<NotificationPermission> requestNotificationPermission() async {
final int result =
await mMDChannel.invokeMethod('requestNotificationPermission');
final int result = await mMDChannel.invokeMethod(
'requestNotificationPermission',
);
return NotificationPermission.fromIndex(result);
}

Expand Down
Loading