adding group message notifications

This commit is contained in:
erinn 2021-06-16 16:03:39 -07:00
parent f08062c0fb
commit ed621e7795
3 changed files with 88 additions and 111 deletions

View File

@ -2,7 +2,6 @@ package im.cwtch.flwtch
import android.app.* import android.app.*
import android.content.Context import android.content.Context
import android.content.Context.ACTIVITY_SERVICE
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Color import android.graphics.Color
@ -24,7 +23,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
NotificationManager NotificationManager
private var notificationID: MutableMap<String, Int> = mutableMapOf() private var notificationID: MutableMap<String, Int> = mutableMapOf()
private var notificationIDnext: Int = 1; private var notificationIDnext: Int = 1
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
val method = inputData.getString(KEY_METHOD) val method = inputData.getString(KEY_METHOD)
@ -32,7 +31,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
val args = inputData.getString(KEY_ARGS) val args = inputData.getString(KEY_ARGS)
?: return Result.failure() ?: return Result.failure()
// Mark the Worker as important // Mark the Worker as important
val progress = "Trying to do a Flwtch"//todo:translate val progress = "Cwtch is keeping Tor running in the background"//todo:translate
setForeground(createForegroundInfo(progress)) setForeground(createForegroundInfo(progress))
return handleCwtch(method, args) return handleCwtch(method, args)
} }
@ -45,8 +44,8 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
return notificationID[k] ?: -1 return notificationID[k] ?: -1
} }
private suspend fun handleCwtch(method: String, args: String): Result { private fun handleCwtch(method: String, args: String): Result {
val a = JSONObject(args); val a = JSONObject(args)
when (method) { when (method) {
"Start" -> { "Start" -> {
Log.i("FlwtchWorker.kt", "handleAppInfo Start") Log.i("FlwtchWorker.kt", "handleAppInfo Start")
@ -54,12 +53,13 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
val torPath = (a.get("torPath") as? String) ?: "tor" val torPath = (a.get("torPath") as? String) ?: "tor"
Log.i("FlwtchWorker.kt", "appDir: '$appDir' torPath: '$torPath'") Log.i("FlwtchWorker.kt", "appDir: '$appDir' torPath: '$torPath'")
if (Cwtch.startCwtch(appDir, torPath) != 0.toByte()) return Result.failure() //todo: maybe change this back to toByte after lcg gets merged? not sure why it got changed
if (Cwtch.startCwtch(appDir, torPath) != 0.toLong()) return Result.failure()
// infinite coroutine :) // infinite coroutine :)
while(true) { while(true) {
val evt = MainActivity.AppbusEvent(Cwtch.getAppBusEvent()) val evt = MainActivity.AppbusEvent(Cwtch.getAppBusEvent())
if (evt.EventType == "NewMessageFromPeer") { if (evt.EventType == "NewMessageFromPeer" || evt.EventType == "NewMessageFromGroup") {
val data = JSONObject(evt.Data) val data = JSONObject(evt.Data)
val channelId = val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -75,7 +75,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
val fh = applicationContext.assets.open(key) val fh = applicationContext.assets.open(key)
val clickIntent = Intent(applicationContext, MainActivity::class.java).also { intent -> val clickIntent = Intent(applicationContext, MainActivity::class.java).also { intent ->
intent.setAction(Intent.ACTION_RUN) intent.action = Intent.ACTION_RUN
intent.putExtra("EventType", "NotificationClicked") intent.putExtra("EventType", "NotificationClicked")
intent.putExtra("ProfileOnion", data.getString("ProfileOnion")) intent.putExtra("ProfileOnion", data.getString("ProfileOnion"))
intent.putExtra("RemotePeer", data.getString("RemotePeer")) intent.putExtra("RemotePeer", data.getString("RemotePeer"))
@ -83,7 +83,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
val newNotification = NotificationCompat.Builder(applicationContext, channelId) val newNotification = NotificationCompat.Builder(applicationContext, channelId)
.setContentTitle(data.getString("Nick")) .setContentTitle(data.getString("Nick"))
.setContentText("New message") .setContentText("New message")//todo: translate
.setLargeIcon(BitmapFactory.decodeStream(fh)) .setLargeIcon(BitmapFactory.decodeStream(fh))
.setSmallIcon(R.mipmap.knott) .setSmallIcon(R.mipmap.knott)
.setContentIntent(PendingIntent.getActivity(applicationContext, 1, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT)) .setContentIntent(PendingIntent.getActivity(applicationContext, 1, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT))
@ -93,7 +93,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
} }
Intent().also { intent -> Intent().also { intent ->
intent.setAction("im.cwtch.flwtch.broadcast.SERVICE_EVENT_BUS") intent.action = "im.cwtch.flwtch.broadcast.SERVICE_EVENT_BUS"
intent.putExtra("EventType", evt.EventType) intent.putExtra("EventType", evt.EventType)
intent.putExtra("Data", evt.Data) intent.putExtra("Data", evt.Data)
intent.putExtra("EventID", evt.EventID) intent.putExtra("EventID", evt.EventID)
@ -105,123 +105,124 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
Cwtch.reconnectCwtchForeground() Cwtch.reconnectCwtchForeground()
} }
"SelectProfile" -> { "SelectProfile" -> {
val onion = (a.get("profile") as? String) ?: ""; //val onion = (a.get("profile") as? String) ?: ""
Cwtch.selectProfile(onion) //todo: maybe remove or readd after lcg merge? not sure why
//Cwtch.selectProfile(onion)
} }
"CreateProfile" -> { "CreateProfile" -> {
val nick = (a.get("nick") as? String) ?: ""; val nick = (a.get("nick") as? String) ?: ""
val pass = (a.get("pass") as? String) ?: ""; val pass = (a.get("pass") as? String) ?: ""
Cwtch.createProfile(nick, pass) Cwtch.createProfile(nick, pass)
} }
"LoadProfiles" -> { "LoadProfiles" -> {
val pass = (a.get("pass") as? String) ?: ""; val pass = (a.get("pass") as? String) ?: ""
Cwtch.loadProfiles(pass) Cwtch.loadProfiles(pass)
} }
"GetProfiles" -> Result.success(Data.Builder().putString("result", Cwtch.getProfiles()).build()) "GetProfiles" -> Result.success(Data.Builder().putString("result", Cwtch.getProfiles()).build())
// "ACNEvents" -> result.success(Cwtch.acnEvents()) // "ACNEvents" -> result.success(Cwtch.acnEvents())
"ContactEvents" -> Result.success(Data.Builder().putString("result", Cwtch.contactEvents()).build()) "ContactEvents" -> Result.success(Data.Builder().putString("result", Cwtch.contactEvents()).build())
"NumMessages" -> { "NumMessages" -> {
val profile = (a.get("profile") as? String) ?: ""; val profile = (a.get("profile") as? String) ?: ""
val handle = (a.get("contact") as? String) ?: ""; val handle = (a.get("contact") as? String) ?: ""
return Result.success(Data.Builder().putLong("result", Cwtch.numMessages(profile, handle)).build()) return Result.success(Data.Builder().putLong("result", Cwtch.numMessages(profile, handle)).build())
} }
"GetMessage" -> { "GetMessage" -> {
val profile = (a.get("profile") as? String) ?: ""; val profile = (a.get("profile") as? String) ?: ""
val handle = (a.get("contact") as? String) ?: ""; val handle = (a.get("contact") as? String) ?: ""
val indexI = a.getInt("index") ?: 0; val indexI = a.getInt("index")
Log.i("FlwtchWorker.kt", "indexI = " + indexI) Log.i("FlwtchWorker.kt", "indexI = $indexI")
return Result.success(Data.Builder().putString("result", Cwtch.getMessage(profile, handle, indexI.toLong())).build()) return Result.success(Data.Builder().putString("result", Cwtch.getMessage(profile, handle, indexI.toLong())).build())
} }
"GetMessages" -> { "GetMessages" -> {
val profile = (a.get("profile") as? String) ?: ""; val profile = (a.get("profile") as? String) ?: ""
val handle = (a.get("contact") as? String) ?: ""; val handle = (a.get("contact") as? String) ?: ""
val start = (a.get("start") as? Long) ?: 0; val start = (a.get("start") as? Long) ?: 0
val end = (a.get("end") as? Long) ?: 0; val end = (a.get("end") as? Long) ?: 0
return Result.success(Data.Builder().putString("result", Cwtch.getMessages(profile, handle, start, end)).build()) return Result.success(Data.Builder().putString("result", Cwtch.getMessages(profile, handle, start, end)).build())
} }
"UpdateMessageFlags" -> { "UpdateMessageFlags" -> {
val profile = (a.get("profile") as? String) ?: ""; val profile = (a.get("profile") as? String) ?: ""
val handle = (a.get("contact") as? String) ?: ""; val handle = (a.get("contact") as? String) ?: ""
val midx = (a.get("midx") as? Long) ?: 0; val midx = (a.get("midx") as? Long) ?: 0
val flags = (a.get("flags") as? Long) ?: 0; val flags = (a.get("flags") as? Long) ?: 0
Cwtch.updateMessageFlags(profile, handle, midx, flags); Cwtch.updateMessageFlags(profile, handle, midx, flags)
} }
"AcceptContact" -> { "AcceptContact" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val handle = (a.get("handle") as? String) ?: ""; val handle = (a.get("handle") as? String) ?: ""
Cwtch.acceptContact(profile, handle); Cwtch.acceptContact(profile, handle)
} }
"BlockContact" -> { "BlockContact" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val handle = (a.get("handle") as? String) ?: ""; val handle = (a.get("handle") as? String) ?: ""
Cwtch.blockContact(profile, handle); Cwtch.blockContact(profile, handle)
} }
"DebugResetContact" -> { "DebugResetContact" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val handle = (a.get("handle") as? String) ?: ""; val handle = (a.get("handle") as? String) ?: ""
Cwtch.debugResetContact(profile, handle); Cwtch.debugResetContact(profile, handle)
} }
"SendMessage" -> { "SendMessage" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val handle = (a.get("handle") as? String) ?: ""; val handle = (a.get("handle") as? String) ?: ""
val message = (a.get("message") as? String) ?: ""; val message = (a.get("message") as? String) ?: ""
Cwtch.sendMessage(profile, handle, message); Cwtch.sendMessage(profile, handle, message)
} }
"SendInvitation" -> { "SendInvitation" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val handle = (a.get("handle") as? String) ?: ""; val handle = (a.get("handle") as? String) ?: ""
val target = (a.get("target") as? String) ?: ""; val target = (a.get("target") as? String) ?: ""
Cwtch.sendInvitation(profile, handle, target); Cwtch.sendInvitation(profile, handle, target)
} }
"SendProfileEvent" -> { "SendProfileEvent" -> {
val onion = (a.get("onion") as? String) ?: ""; val onion = (a.get("onion") as? String) ?: ""
val jsonEvent = (a.get("jsonEvent") as? String) ?: ""; val jsonEvent = (a.get("jsonEvent") as? String) ?: ""
Cwtch.sendProfileEvent(onion, jsonEvent); Cwtch.sendProfileEvent(onion, jsonEvent)
} }
"SendAppEvent" -> { "SendAppEvent" -> {
val jsonEvent = (a.get("jsonEvent") as? String) ?: ""; val jsonEvent = (a.get("jsonEvent") as? String) ?: ""
Cwtch.sendAppEvent(jsonEvent); Cwtch.sendAppEvent(jsonEvent)
} }
"ResetTor" -> { "ResetTor" -> {
Cwtch.resetTor(); Cwtch.resetTor()
} }
"ImportBundle" -> { "ImportBundle" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val bundle = (a.get("bundle") as? String) ?: ""; val bundle = (a.get("bundle") as? String) ?: ""
Cwtch.importBundle(profile, bundle); Cwtch.importBundle(profile, bundle)
} }
"SetGroupAttribute" -> { "SetGroupAttribute" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val groupHandle = (a.get("groupHandle") as? String) ?: ""; val groupHandle = (a.get("groupHandle") as? String) ?: ""
val key = (a.get("key") as? String) ?: ""; val key = (a.get("key") as? String) ?: ""
val value = (a.get("value") as? String) ?: ""; val value = (a.get("value") as? String) ?: ""
Cwtch.setGroupAttribute(profile, groupHandle, key, value); Cwtch.setGroupAttribute(profile, groupHandle, key, value)
} }
"CreateGroup" -> { "CreateGroup" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val server = (a.get("server") as? String) ?: ""; val server = (a.get("server") as? String) ?: ""
val groupName = (a.get("groupname") as? String) ?: ""; val groupName = (a.get("groupname") as? String) ?: ""
Cwtch.createGroup(profile, server, groupName); Cwtch.createGroup(profile, server, groupName)
} }
"DeleteProfile" -> { "DeleteProfile" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val groupHandle = (a.get("pass") as? String) ?: ""; val groupHandle = (a.get("pass") as? String) ?: ""
Cwtch.deleteProfile(profile, groupHandle); Cwtch.deleteProfile(profile, groupHandle)
} }
"LeaveConversation" -> { "LeaveConversation" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val contactHandle = (a.get("contactHandle") as? String) ?: ""; val contactHandle = (a.get("contactHandle") as? String) ?: ""
Cwtch.leaveConversation(profile, contactHandle); Cwtch.leaveConversation(profile, contactHandle)
} }
"LeaveGroup" -> { "LeaveGroup" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val groupHandle = (a.get("groupHandle") as? String) ?: ""; val groupHandle = (a.get("groupHandle") as? String) ?: ""
Cwtch.leaveGroup(profile, groupHandle); Cwtch.leaveGroup(profile, groupHandle)
} }
"RejectInvite" -> { "RejectInvite" -> {
val profile = (a.get("ProfileOnion") as? String) ?: ""; val profile = (a.get("ProfileOnion") as? String) ?: ""
val groupHandle = (a.get("groupHandle") as? String) ?: ""; val groupHandle = (a.get("groupHandle") as? String) ?: ""
Cwtch.rejectInvite(profile, groupHandle); Cwtch.rejectInvite(profile, groupHandle)
} }
else -> return Result.failure() else -> return Result.failure()
} }
@ -233,20 +234,11 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
private fun createForegroundInfo(progress: String): ForegroundInfo { private fun createForegroundInfo(progress: String): ForegroundInfo {
val id = "flwtch" val id = "flwtch"
val title = "Flwtch" val title = "Flwtch"
val cancel = "Nevermind"//todo: translate val cancel = "Shut down"//todo: translate
// This PendingIntent can be used to cancel the worker // This PendingIntent can be used to cancel the worker
val intent = WorkManager.getInstance(applicationContext) val intent = WorkManager.getInstance(applicationContext)
.createCancelPendingIntent(getId()) .createCancelPendingIntent(getId())
val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(id, id)
} else {
// If earlier version channel ID is not used
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
""
}
val notification = NotificationCompat.Builder(applicationContext, id) val notification = NotificationCompat.Builder(applicationContext, id)
.setContentTitle(title) .setContentTitle(title)
.setTicker(title) .setTicker(title)
@ -261,18 +253,6 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
return ForegroundInfo(101, notification) return ForegroundInfo(101, notification)
} }
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(channelId: String, channelName: String): String{
val chan = NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_NONE)
chan.lightColor = Color.MAGENTA
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
notificationManager.createNotificationChannel(chan)
return channelId
}
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
private fun createMessageNotificationChannel(channelId: String, channelName: String): String{ private fun createMessageNotificationChannel(channelId: String, channelName: String): String{
val chan = NotificationChannel(channelId, val chan = NotificationChannel(channelId,
@ -287,10 +267,4 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
const val KEY_METHOD = "KEY_METHOD" const val KEY_METHOD = "KEY_METHOD"
const val KEY_ARGS = "KEY_ARGS" const val KEY_ARGS = "KEY_ARGS"
} }
class AppbusEvent(json: String) : JSONObject(json) {
val EventType = this.optString("EventType")
val EventID = this.optString("EventID")
val Data = this.optString("Data")
}
} }

View File

@ -11,6 +11,7 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import android.view.Window
import android.widget.Toast import android.widget.Toast
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
@ -74,6 +75,8 @@ class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine) super.configureFlutterEngine(flutterEngine)
// Note: this methods are invoked on the main thread. // Note: this methods are invoked on the main thread.
//note to self: ask someone if this does anything ^ea
requestWindowFeature(Window.FEATURE_NO_TITLE)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_APP_INFO).setMethodCallHandler { call, result -> handleAppInfo(call, result) } MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_APP_INFO).setMethodCallHandler { call, result -> handleAppInfo(call, result) }
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_CWTCH).setMethodCallHandler { call, result -> handleCwtch(call, result) } MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_CWTCH).setMethodCallHandler { call, result -> handleCwtch(call, result) }
methodChan = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_NOTIF_CLICK) methodChan = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_NOTIF_CLICK)

View File

@ -193,12 +193,12 @@ class _MessageViewState extends State<MessageView> {
), ),
ElevatedButton( ElevatedButton(
child: Text(AppLocalizations.of(bcontext)!.inviteBtn, semanticsLabel: AppLocalizations.of(bcontext)!.inviteBtn), child: Text(AppLocalizations.of(bcontext)!.inviteBtn, semanticsLabel: AppLocalizations.of(bcontext)!.inviteBtn),
onPressed: this.selectedContact == "" onPressed: () {
? null if (this.selectedContact != "") {
: () { this._sendInvitation();
this._sendInvitation(); }
Navigator.pop(bcontext); Navigator.pop(bcontext);
}, },
), ),
], ],
)), )),