diff --git a/app/schemas/com.keylesspalace.tusky.db.AppDatabase/25.json b/app/schemas/com.keylesspalace.tusky.db.AppDatabase/25.json
index eb29ed08..ce58a97a 100644
--- a/app/schemas/com.keylesspalace.tusky.db.AppDatabase/25.json
+++ b/app/schemas/com.keylesspalace.tusky.db.AppDatabase/25.json
@@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 25,
- "identityHash": "7ab8482b8d5dcb97c4c8932f578879f2",
+ "identityHash": "ce7a96213f9e12e00a6ec21f3efaf547",
"entities": [
{
"tableName": "TootEntity",
@@ -92,7 +92,7 @@
},
{
"tableName": "AccountEntity",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `notificationsEmojiReactions` INTEGER NOT NULL, `notificationsChatMessages` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `alwaysOpenSpoiler` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL, `notificationsFilter` TEXT NOT NULL, `defaultFormattingSyntax` TEXT NOT NULL)",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsStreamingEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `notificationsEmojiReactions` INTEGER NOT NULL, `notificationsChatMessages` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `alwaysOpenSpoiler` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL, `notificationsFilter` TEXT NOT NULL, `defaultFormattingSyntax` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
@@ -148,6 +148,12 @@
"affinity": "INTEGER",
"notNull": true
},
+ {
+ "fieldPath": "notificationsStreamingEnabled",
+ "columnName": "notificationsStreamingEnabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
{
"fieldPath": "notificationsMentioned",
"columnName": "notificationsMentioned",
@@ -879,7 +885,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
- "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7ab8482b8d5dcb97c4c8932f578879f2')"
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ce7a96213f9e12e00a6ec21f3efaf547')"
]
}
}
\ No newline at end of file
diff --git a/app/src/husky/res/values/strings.xml b/app/src/husky/res/values/strings.xml
index 56ad4784..c913f461 100644
--- a/app/src/husky/res/values/strings.xml
+++ b/app/src/husky/res/values/strings.xml
@@ -43,6 +43,9 @@
Attachment
Link
+
+ Live notifications
+ Running live notifications for:
Post visibility
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 77aaa040..217fde72 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -168,6 +168,8 @@
+
+
> {
- override fun onFailure(call: Call>, t: Throwable) {
-
- }
-
- override fun onResponse(call: Call>, response: Response>) {
- val notifications = response.body()
- val newId = account.lastNotificationId
- var newestId = ""
- var isFirstOfBatch = true
- notifications?.reversed()?.forEach { notification ->
- val currentId = notification.id
- if (newestId.isLessThan(currentId)) {
- newestId = currentId
- }
- if (newId.isLessThan(currentId)) {
- NotificationHelper.make(this@MainActivity, notification, account, isFirstOfBatch)
- isFirstOfBatch = false
- }
- }
- account.lastNotificationId = newestId
- accountManager.saveAccount(account)
- }
- })
- } catch (e: IOException) {
- Log.w(TAG, "error receiving notifications", e)
- }
+ if(accountManager.areNotificationsStreamingEnabled()) {
+ NotificationHelper.disablePullNotifications(this)
+ StreamingService.startStreaming(this)
+ } else {
+ StreamingService.stopStreaming(this)
+ NotificationHelper.enablePullNotifications(this)
}
-
- */
- }
-
} else {
+ StreamingService.stopStreaming(this)
NotificationHelper.disablePullNotifications(this)
}
eventHub.events
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java
index 24806409..c1c51ad7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java
+++ b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java
@@ -138,7 +138,7 @@ public class NotificationHelper {
/**
* by setting this as false, it's possible to test legacy notification channels on newer devices
*/
- //public static final boolean NOTIFICATION_USE_CHANNELS = false;
+ // public static final boolean NOTIFICATION_USE_CHANNELS = false;
public static final boolean NOTIFICATION_USE_CHANNELS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
/**
@@ -518,7 +518,7 @@ public class NotificationHelper {
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS, TimeUnit.MILLISECONDS
)
.addTag(NOTIFICATION_PULL_TAG)
- //.setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
+ .setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
.build();
workManager.enqueue(workRequest);
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationWorker.kt b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationWorker.kt
index 7a38e8d1..8ee2c896 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationWorker.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationWorker.kt
@@ -46,8 +46,7 @@ class NotificationWorker(
val notificationsResponse = mastodonApi.notificationsWithAuth(
String.format("Bearer %s", account.accessToken),
account.domain, true,
- setOf(Notification.Type.CHAT_MESSAGE.presentation)
- ).execute()
+ Notification.Type.asStringList).execute()
val notifications = notificationsResponse.body()
if (notificationsResponse.isSuccessful && notifications != null) {
onNotificationsReceived(account, notifications)
diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AccountEntity.kt b/app/src/main/java/com/keylesspalace/tusky/db/AccountEntity.kt
index 4b5ed2d8..01cd8ac1 100644
--- a/app/src/main/java/com/keylesspalace/tusky/db/AccountEntity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/db/AccountEntity.kt
@@ -37,6 +37,7 @@ data class AccountEntity(@field:PrimaryKey(autoGenerate = true) var id: Long,
var displayName: String = "",
var profilePictureUrl: String = "",
var notificationsEnabled: Boolean = true,
+ var notificationsStreamingEnabled: Boolean = true,
var notificationsMentioned: Boolean = true,
var notificationsFollowed: Boolean = true,
var notificationsFollowRequested: Boolean = false,
diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt
index 5293bd03..5a72411e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt
@@ -184,6 +184,10 @@ class AccountManager @Inject constructor(db: AppDatabase) {
return accounts.any { it.notificationsEnabled }
}
+ fun areNotificationsStreamingEnabled() : Boolean {
+ return accounts.any { it.notificationsStreamingEnabled }
+ }
+
/**
* Finds an account by its database id
* @param accountId the id of the account
diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java b/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
index 878cac2e..89af2df1 100644
--- a/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
+++ b/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
@@ -372,6 +372,7 @@ public abstract class AppDatabase extends RoomDatabase {
"PRIMARY KEY (`localId`, `messageId`))");
database.execSQL("ALTER TABLE `InstanceEntity` ADD COLUMN `chatLimit` INTEGER");
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `notificationsChatMessages` INTEGER NOT NULL DEFAULT 1");
+ database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `notificationsStreamingEnabled` INTEGER NOT NULL DEFAULT 1");
}
};
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt
index 6d81b2ff..64611d45 100644
--- a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt
@@ -60,9 +60,9 @@ class NetworkModule {
addInterceptor(InstanceSwitchAuthInterceptor(accountManager))
if (BuildConfig.DEBUG) {
addInterceptor(HttpLoggingInterceptor().apply {
- //level = HttpLoggingInterceptor.Level.BASIC
+ level = HttpLoggingInterceptor.Level.BASIC
//level = HttpLoggingInterceptor.Level.HEADERS
- level = HttpLoggingInterceptor.Level.BODY
+ //level = HttpLoggingInterceptor.Level.BODY
})
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt
index 5f649554..a2d6d469 100644
--- a/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt
@@ -19,6 +19,7 @@ import android.content.Context
import com.keylesspalace.tusky.service.SendTootService
import com.keylesspalace.tusky.service.ServiceClient
import com.keylesspalace.tusky.service.ServiceClientImpl
+import com.keylesspalace.tusky.service.StreamingService
import dagger.Module
import dagger.Provides
import dagger.android.ContributesAndroidInjector
@@ -28,6 +29,9 @@ abstract class ServicesModule {
@ContributesAndroidInjector
abstract fun contributesSendTootService(): SendTootService
+ @ContributesAndroidInjector
+ abstract fun contributesStreamingService(): StreamingService
+
@Module
companion object {
@Provides
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Notification.kt b/app/src/main/java/com/keylesspalace/tusky/entity/Notification.kt
index 12e1a374..e057264c 100644
--- a/app/src/main/java/com/keylesspalace/tusky/entity/Notification.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/Notification.kt
@@ -57,6 +57,8 @@ data class Notification(
return UNKNOWN
}
val asList = listOf(MENTION, REBLOG, FAVOURITE, FOLLOW, POLL, EMOJI_REACTION, FOLLOW_REQUEST, CHAT_MESSAGE)
+
+ val asStringList = asList.map { it.presentation }
}
override fun toString(): String {
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/StreamEvent.kt b/app/src/main/java/com/keylesspalace/tusky/entity/StreamEvent.kt
new file mode 100644
index 00000000..ce761ed1
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/StreamEvent.kt
@@ -0,0 +1,20 @@
+package com.keylesspalace.tusky.entity
+
+import com.google.gson.annotations.SerializedName
+
+data class StreamEvent (
+ val event: EventType,
+ val payload: String
+) {
+ enum class EventType {
+ UNKNOWN,
+ @SerializedName("update")
+ UPDATE,
+ @SerializedName("notification")
+ NOTIFICATION,
+ @SerializedName("delete")
+ DELETE,
+ @SerializedName("filters_changed")
+ FILTERS_CHANGED;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt
index d7ec1ed9..7cf54c22 100644
--- a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt
@@ -110,7 +110,7 @@ interface MastodonApi {
@Header("Authorization") auth: String,
@Header(DOMAIN_HEADER) domain: String,
@Query("with_muted") withMuted: Boolean?,
- @Query("include_types[]") includeTypes: Set?
+ @Query("include_types[]") includeTypes: List?
): Call>
@POST("api/v1/notifications/clear")
diff --git a/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt b/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt
index 54969868..d5aa9974 100644
--- a/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt
@@ -52,7 +52,7 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
val senderIdentifier = intent.getStringExtra(NotificationHelper.KEY_SENDER_ACCOUNT_IDENTIFIER)
val senderFullName = intent.getStringExtra(NotificationHelper.KEY_SENDER_ACCOUNT_FULL_NAME)
val citedStatusId = intent.getStringExtra(NotificationHelper.KEY_CITED_STATUS_ID)
- val visibility = intent.getSerializableExtra(NotificationHelper.KEY_VISIBILITY) as Status.Visibility
+ val visibility = intent.getSerializableExtra(NotificationHelper.KEY_VISIBILITY)
val spoiler = intent.getStringExtra(NotificationHelper.KEY_SPOILER)
val mentions = intent.getStringArrayExtra(NotificationHelper.KEY_MENTIONS)
val citedText = intent.getStringExtra(NotificationHelper.KEY_CITED_TEXT)
@@ -93,7 +93,7 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
val composeIntent = ComposeActivity.startIntent(context, ComposeOptions(
inReplyToId = citedStatusId,
- replyVisibility = visibility,
+ replyVisibility = visibility as Status.Visibility,
contentWarning = spoiler,
mentionedUsernames = mentions.toSet(),
replyingStatusAuthor = localAuthorId,
@@ -114,7 +114,7 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
TootToSend(
text,
spoiler,
- visibility.serverString(),
+ (visibility as Status.Visibility).serverString(),
false,
emptyList(),
emptyList(),
diff --git a/app/src/main/java/com/keylesspalace/tusky/service/SendTootService.kt b/app/src/main/java/com/keylesspalace/tusky/service/SendTootService.kt
index 44587454..3991e616 100644
--- a/app/src/main/java/com/keylesspalace/tusky/service/SendTootService.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/service/SendTootService.kt
@@ -8,9 +8,7 @@ import android.content.ClipData
import android.content.ClipDescription
import android.content.Context
import android.content.Intent
-import android.os.Build
-import android.os.IBinder
-import android.os.Parcelable
+import android.os.*
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
diff --git a/app/src/main/java/com/keylesspalace/tusky/service/StreamingService.kt b/app/src/main/java/com/keylesspalace/tusky/service/StreamingService.kt
new file mode 100644
index 00000000..1b7d0676
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/service/StreamingService.kt
@@ -0,0 +1,194 @@
+package com.keylesspalace.tusky.service
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.Handler
+import android.os.IBinder
+import android.os.Message
+import android.util.Log
+import androidx.core.app.NotificationCompat
+import androidx.core.app.ServiceCompat
+import androidx.core.content.ContextCompat
+import com.google.gson.Gson
+import com.keylesspalace.tusky.R
+import com.keylesspalace.tusky.appstore.EventHub
+import com.keylesspalace.tusky.components.notifications.NotificationHelper
+import com.keylesspalace.tusky.db.AccountEntity
+import com.keylesspalace.tusky.db.AccountManager
+import com.keylesspalace.tusky.di.Injectable
+import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.entity.Notification
+import com.keylesspalace.tusky.entity.StreamEvent
+import com.keylesspalace.tusky.network.MastodonApi
+import dagger.android.AndroidInjection
+import okhttp3.*
+import javax.inject.Inject
+
+class StreamingService: Service(), Injectable {
+ @Inject
+ lateinit var api: MastodonApi
+
+ @Inject
+ lateinit var eventHub: EventHub
+
+ @Inject
+ lateinit var accountManager: AccountManager
+
+ @Inject
+ lateinit var gson: Gson
+
+ private val sockets: MutableMap = mutableMapOf()
+
+ private val notificationManager by lazy { getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager }
+
+ override fun onBind(intent: Intent?): IBinder? {
+ return null
+ }
+
+ override fun onCreate() {
+ AndroidInjection.inject(this)
+ super.onCreate()
+ }
+
+ private fun stopStreamingForId(id: Long) {
+ if(id in sockets) {
+ sockets[id]!!.close(1000, null)
+ sockets.remove(id)
+ }
+ }
+
+ private fun stopStreaming() : Int {
+ for(sock in sockets) {
+ sock.value.close(1000, null)
+ }
+ sockets.clear()
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
+ }
+
+ notificationManager.cancel(1337)
+ return START_NOT_STICKY
+ }
+
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ if(intent.hasExtra(KEY_STOP_STREAMING)) {
+ Log.d(TAG, "Stopping stream")
+ return stopStreaming()
+ }
+
+ var description = getString(R.string.streaming_notification_description)
+ val accounts = accountManager.getAllAccountsOrderedByActive()
+ var count = 0
+ for(account in accounts) {
+ stopStreamingForId(account.id)
+
+ if(!account.notificationsStreamingEnabled)
+ continue
+
+ val endpoint = "wss://${account.domain}/api/v1/streaming/?access_token=${account.accessToken}&stream=user:notification"
+
+ val request = Request.Builder().url(endpoint).build()
+ val client = OkHttpClient.Builder().build()
+
+ Log.d(TAG, "Running stream for ${account.fullName}")
+
+ sockets[account.id] = client.newWebSocket(request, StreamingListener(this, gson, account))
+ description += "\n" + account.fullName
+ count++
+ }
+
+ if(count <= 0) {
+ Log.d(TAG, "No accounts. Stopping stream")
+ return stopStreaming()
+ }
+
+ if (NotificationHelper.NOTIFICATION_USE_CHANNELS) {
+ val channel = NotificationChannel(CHANNEL_ID, getString(R.string.streaming_notification_name), NotificationManager.IMPORTANCE_LOW)
+ notificationManager.createNotificationChannel(channel)
+ }
+
+ val builder = NotificationCompat.Builder(this, CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_notify)
+ .setContentTitle(getString(R.string.streaming_notification_name))
+ .setContentText(description)
+ .setOngoing(true)
+ .setColor(ContextCompat.getColor(this, R.color.tusky_blue))
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
+ startForeground(1337, builder.build())
+ } else {
+ notificationManager.notify(1337, builder.build())
+ }
+
+ return START_NOT_STICKY
+ }
+
+ companion object {
+ val CHANNEL_ID = "streaming"
+ val KEY_STOP_STREAMING = "stop_streaming"
+ val TAG = "StreamingService"
+
+ @JvmStatic
+ private fun startForegroundService(ctx: Context, intent: Intent) {
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ ctx.startForegroundService(intent)
+ } else {
+ ctx.startService(intent)
+ }
+ }
+
+ @JvmStatic
+ fun startStreaming(context: Context) {
+ val intent = Intent(context, StreamingService::class.java)
+
+ Log.d(TAG, "Starting notifications streaming service...")
+
+ startForegroundService(context, intent)
+ }
+
+ @JvmStatic
+ fun stopStreaming(context: Context) {
+ val intent = Intent(context, StreamingService::class.java)
+ intent.putExtra(KEY_STOP_STREAMING, 123)
+
+ Log.d(TAG, "Stopping notifications streaming service...")
+
+ startForegroundService(context, intent)
+ }
+ }
+
+ class StreamingListener(val context: Context, val gson: Gson, val account: AccountEntity) : WebSocketListener() {
+
+ override fun onOpen(webSocket: WebSocket, response: Response) {
+ Log.d(TAG, "Stream connected to: ${account.fullName}/user:notification")
+ }
+
+ override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
+ Log.d(TAG, "Stream closed for: ${account.fullName}/user:notification")
+ }
+
+ override fun onMessage(webSocket: WebSocket, text: String) {
+ val event = gson.fromJson(text, StreamEvent::class.java)
+ when(event.event) {
+ StreamEvent.EventType.NOTIFICATION -> {
+ val notification = gson.fromJson(event.payload, Notification::class.java)
+ NotificationHelper.make(context, notification, account, true)
+ }
+ else -> {
+ Log.d(TAG, "Unknown event type: ${event.event.toString()}")
+ }
+ }
+
+
+ super.onMessage(webSocket, text)
+ }
+
+ }
+
+}
\ No newline at end of file