Skip to content

Sketch removing notification when message read #864

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
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: 2 additions & 1 deletion .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 118 additions & 0 deletions android/app/src/main/kotlin/com/zulip/flutter/Notifications.g.kt
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,65 @@ data class MessagingStyle (
)
}
}

/**
* Corresponds to `android.app.Notification`.
*
* See: https://developer.android.com/reference/kotlin/android/app/Notification
*
* Generated class from Pigeon that represents data sent in messages.
*/
data class Notification (
val group: String? = null,
val extras: Map<String?, Any?>

) {
companion object {
@Suppress("LocalVariableName")
fun fromList(__pigeon_list: List<Any?>): Notification {
val group = __pigeon_list[0] as String?
val extras = __pigeon_list[1] as Map<String?, Any?>
return Notification(group, extras)
}
}
fun toList(): List<Any?> {
return listOf(
group,
extras,
)
}
}

/**
* Corresponds to `android.service.notification.StatusBarNotification`.
*
* See: https://developer.android.com/reference/kotlin/android/service/notification/StatusBarNotification
*
* Generated class from Pigeon that represents data sent in messages.
*/
data class StatusBarNotification (
val id: Long,
val notification: Notification,
val tag: String? = null

) {
companion object {
@Suppress("LocalVariableName")
fun fromList(__pigeon_list: List<Any?>): StatusBarNotification {
val id = __pigeon_list[0].let { num -> if (num is Int) num.toLong() else num as Long }
val notification = __pigeon_list[1] as Notification
val tag = __pigeon_list[2] as String?
return StatusBarNotification(id, notification, tag)
}
}
fun toList(): List<Any?> {
return listOf(
id,
notification,
tag,
)
}
}
private object NotificationsPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) {
Expand Down Expand Up @@ -289,6 +348,16 @@ private object NotificationsPigeonCodec : StandardMessageCodec() {
MessagingStyle.fromList(it)
}
}
135.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
Notification.fromList(it)
}
}
136.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
StatusBarNotification.fromList(it)
}
}
else -> super.readValueOfType(type, buffer)
}
}
Expand Down Expand Up @@ -318,6 +387,14 @@ private object NotificationsPigeonCodec : StandardMessageCodec() {
stream.write(134)
writeValue(stream, value.toList())
}
is Notification -> {
stream.write(135)
writeValue(stream, value.toList())
}
is StatusBarNotification -> {
stream.write(136)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
Expand Down Expand Up @@ -351,6 +428,7 @@ interface AndroidNotificationHostApi {
* https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder
*/
fun notify(tag: String?, id: Long, autoCancel: Boolean?, channelId: String, color: Long?, contentIntent: PendingIntent?, contentText: String?, contentTitle: String?, extras: Map<String?, String?>?, groupKey: String?, inboxStyle: InboxStyle?, isGroupSummary: Boolean?, messagingStyle: MessagingStyle?, number: Long?, smallIconResourceName: String?)
fun getActiveNotifications(): List<StatusBarNotification>
/**
* Wraps `androidx.core.app.NotificationManagerCompat.getActiveNotifications`,
* combined with `androidx.core.app.NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification`.
Expand All @@ -365,6 +443,12 @@ interface AndroidNotificationHostApi {
* https://developer.android.com/reference/kotlin/androidx/core/app/NotificationCompat.MessagingStyle#extractMessagingStyleFromNotification(android.app.Notification)
*/
fun getActiveNotificationMessagingStyleByTag(tag: String): MessagingStyle?
/**
* Corresponds to `android.app.NotificationManager.cancel`.
*
* See: https://developer.android.com/reference/kotlin/android/app/NotificationManager.html#cancel
*/
fun cancel(tag: String?, id: Long)

companion object {
/** The codec used by AndroidNotificationHostApi. */
Expand Down Expand Up @@ -425,6 +509,21 @@ interface AndroidNotificationHostApi {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.zulip.AndroidNotificationHostApi.getActiveNotifications$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
listOf(api.getActiveNotifications())
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.zulip.AndroidNotificationHostApi.getActiveNotificationMessagingStyleByTag$separatedMessageChannelSuffix", codec)
if (api != null) {
Expand All @@ -442,6 +541,25 @@ interface AndroidNotificationHostApi {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.zulip.AndroidNotificationHostApi.cancel$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val tagArg = args[0] as String?
val idArg = args[1].let { num -> if (num is Int) num.toLong() else num as Long }
val wrapped: List<Any?> = try {
api.cancel(tagArg, idArg)
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
27 changes: 27 additions & 0 deletions android/app/src/main/kotlin/com/zulip/flutter/ZulipPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.zulip.flutter

import android.annotation.SuppressLint
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.os.Bundle
Expand All @@ -14,6 +15,13 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin

private const val TAG = "ZulipPlugin"

private fun Bundle.stringsMap(): Map<String, CharSequence?> {
return keySet().associateWith {
try { get(it) as CharSequence? }
catch (e: Throwable) { null }
}
}

fun toAndroidPerson(person: Person): androidx.core.app.Person {
return androidx.core.app.Person.Builder().apply {
person.iconBitmap?.let { setIcon(IconCompat.createWithData(it, 0, it.size)) }
Expand Down Expand Up @@ -121,6 +129,20 @@ private class AndroidNotificationHost(val context: Context)
NotificationManagerCompat.from(context).notify(tag, id.toInt(), notification)
}

override fun getActiveNotifications(): List<StatusBarNotification> {
val notificationManager = context.getSystemService(NotificationManager::class.java)!!
return notificationManager.activeNotifications.map {
StatusBarNotification(
id = it.id.toLong(),
tag = it.tag,
notification = Notification(
group = it.notification.group,
extras = it.notification.extras.stringsMap() as Map<String?, Any?>,
)
)
}
}

override fun getActiveNotificationMessagingStyleByTag(tag: String): MessagingStyle? {
val activeNotification = NotificationManagerCompat.from(context)
.activeNotifications
Expand All @@ -143,6 +165,11 @@ private class AndroidNotificationHost(val context: Context)
}
return null
}

override fun cancel(tag: String?, id: Long) {
val notificationManager = context.getSystemService(NotificationManager::class.java)!!
notificationManager.cancel(tag, id.toInt())
}
}

/** A Flutter plugin for the Zulip app's ad-hoc needs. */
Expand Down
125 changes: 125 additions & 0 deletions lib/host/android_notifications.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,69 @@ class MessagingStyle {
}
}

/// Corresponds to `android.app.Notification`.
///
/// See: https://developer.android.com/reference/kotlin/android/app/Notification
class Notification {
Notification({
this.group,
required this.extras,
});

String? group;

Map<String?, Object?> extras;

Object encode() {
return <Object?>[
group,
extras,
];
}

static Notification decode(Object result) {
result as List<Object?>;
return Notification(
group: result[0] as String?,
extras: (result[1] as Map<Object?, Object?>?)!.cast<String?, Object?>(),
);
}
}

/// Corresponds to `android.service.notification.StatusBarNotification`.
///
/// See: https://developer.android.com/reference/kotlin/android/service/notification/StatusBarNotification
class StatusBarNotification {
StatusBarNotification({
required this.id,
required this.notification,
this.tag,
});

int id;

Notification notification;

String? tag;

Object encode() {
return <Object?>[
id,
notification,
tag,
];
}

static StatusBarNotification decode(Object result) {
result as List<Object?>;
return StatusBarNotification(
id: result[0]! as int,
notification: result[1]! as Notification,
tag: result[2] as String?,
);
}
}


class _PigeonCodec extends StandardMessageCodec {
const _PigeonCodec();
Expand All @@ -263,6 +326,12 @@ class _PigeonCodec extends StandardMessageCodec {
} else if (value is MessagingStyle) {
buffer.putUint8(134);
writeValue(buffer, value.encode());
} else if (value is Notification) {
buffer.putUint8(135);
writeValue(buffer, value.encode());
} else if (value is StatusBarNotification) {
buffer.putUint8(136);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
Expand All @@ -283,6 +352,10 @@ class _PigeonCodec extends StandardMessageCodec {
return MessagingStyleMessage.decode(readValue(buffer)!);
case 134:
return MessagingStyle.decode(readValue(buffer)!);
case 135:
return Notification.decode(readValue(buffer)!);
case 136:
return StatusBarNotification.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
Expand Down Expand Up @@ -366,6 +439,33 @@ class AndroidNotificationHostApi {
}
}

Future<List<StatusBarNotification?>> getActiveNotifications() async {
final String __pigeon_channelName = 'dev.flutter.pigeon.zulip.AndroidNotificationHostApi.getActiveNotifications$__pigeon_messageChannelSuffix';
final BasicMessageChannel<Object?> __pigeon_channel = BasicMessageChannel<Object?>(
__pigeon_channelName,
pigeonChannelCodec,
binaryMessenger: __pigeon_binaryMessenger,
);
final List<Object?>? __pigeon_replyList =
await __pigeon_channel.send(null) as List<Object?>?;
if (__pigeon_replyList == null) {
throw _createConnectionError(__pigeon_channelName);
} else if (__pigeon_replyList.length > 1) {
throw PlatformException(
code: __pigeon_replyList[0]! as String,
message: __pigeon_replyList[1] as String?,
details: __pigeon_replyList[2],
);
} else if (__pigeon_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (__pigeon_replyList[0] as List<Object?>?)!.cast<StatusBarNotification?>();
}
}

/// Wraps `androidx.core.app.NotificationManagerCompat.getActiveNotifications`,
/// combined with `androidx.core.app.NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification`.
///
Expand Down Expand Up @@ -398,4 +498,29 @@ class AndroidNotificationHostApi {
return (__pigeon_replyList[0] as MessagingStyle?);
}
}

/// Corresponds to `android.app.NotificationManager.cancel`.
///
/// See: https://developer.android.com/reference/kotlin/android/app/NotificationManager.html#cancel
Future<void> cancel({String? tag, required int id}) async {
final String __pigeon_channelName = 'dev.flutter.pigeon.zulip.AndroidNotificationHostApi.cancel$__pigeon_messageChannelSuffix';
final BasicMessageChannel<Object?> __pigeon_channel = BasicMessageChannel<Object?>(
__pigeon_channelName,
pigeonChannelCodec,
binaryMessenger: __pigeon_binaryMessenger,
);
final List<Object?>? __pigeon_replyList =
await __pigeon_channel.send(<Object?>[tag, id]) as List<Object?>?;
if (__pigeon_replyList == null) {
throw _createConnectionError(__pigeon_channelName);
} else if (__pigeon_replyList.length > 1) {
throw PlatformException(
code: __pigeon_replyList[0]! as String,
message: __pigeon_replyList[1] as String?,
details: __pigeon_replyList[2],
);
} else {
return;
}
}
}
Loading
Loading