Skip to content

Commit

Permalink
Bubbles
Browse files Browse the repository at this point in the history
- Only enabled on Conversations deemed important
- Enabled ChatActivity to be resizable and embedded in Android Manifest
  • Loading branch information
rapterjet2004 committed Nov 6, 2023
1 parent cf38174 commit 5e7fef4
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 22 deletions.
12 changes: 10 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@
<activity
android:name=".activities.MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize"
android:allowEmbedded="true"
android:resizeableActivity="true"
android:documentLaunchMode="always"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
Expand Down Expand Up @@ -217,7 +221,11 @@

<activity
android:name=".chat.ChatActivity"
android:theme="@style/AppTheme" />
android:theme="@style/AppTheme"
android:allowEmbedded="true"
android:resizeableActivity="true"
android:documentLaunchMode="always"
/>

<activity
android:name=".openconversations.ListOpenConversationsActivity"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ class ConversationInfoActivity :
binding.notificationSettingsView.notificationSettingsImportantConversation.setOnClickListener {
val isChecked = binding.notificationSettingsView.importantConversationSwitch.isChecked
binding.notificationSettingsView.importantConversationSwitch.isChecked = !isChecked
module.saveBoolean("important_conversation_switch", !isChecked)
module.saveBoolean(IMPORTANT_CONVERSATION_KEY, !isChecked)
}
binding.notificationSettingsView.notificationSettingsCallNotifications.setOnClickListener {
val isChecked = binding.notificationSettingsView.callNotificationsSwitch.isChecked
Expand All @@ -1303,7 +1303,7 @@ class ConversationInfoActivity :
}

binding.notificationSettingsView.importantConversationSwitch.isChecked = module
.getBoolean("important_conversation_switch", false)
.getBoolean(IMPORTANT_CONVERSATION_KEY, false)

binding.notificationSettingsView.callNotificationsSwitch.isChecked = module
.getBoolean("call_notifications_switch", true)
Expand All @@ -1317,6 +1317,7 @@ class ConversationInfoActivity :
private const val LOW_EMPHASIS_OPACITY: Float = 0.38f
private const val RECORDING_CONSENT_NOT_REQUIRED_FOR_CONVERSATION: Int = 0
private const val RECORDING_CONSENT_REQUIRED_FOR_CONVERSATION: Int = 1
const val IMPORTANT_CONVERSATION_KEY = "important_conversation_switch"
}

/**
Expand Down
104 changes: 86 additions & 18 deletions app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,18 @@ import android.text.TextUtils
import android.util.Base64
import android.util.Log
import android.view.View
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.BubbleMetadata
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.Person
import androidx.core.app.RemoteInput
import androidx.core.content.ContextCompat
import androidx.core.content.LocusIdCompat
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.emoji2.text.EmojiCompat
import androidx.work.Data
Expand All @@ -65,6 +71,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
import com.nextcloud.talk.callnotification.CallNotificationActivity
import com.nextcloud.talk.conversationinfo.ConversationInfoActivity
import com.nextcloud.talk.models.SignatureVerification
import com.nextcloud.talk.models.json.chat.ChatUtils.Companion.getParsedMessage
import com.nextcloud.talk.models.json.conversations.RoomOverall
Expand All @@ -77,6 +84,7 @@ import com.nextcloud.talk.receivers.DirectReplyReceiver
import com.nextcloud.talk.receivers.DismissRecordingAvailableReceiver
import com.nextcloud.talk.receivers.MarkAsReadReceiver
import com.nextcloud.talk.receivers.ShareRecordingToChatReceiver
import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldPlaySound
import com.nextcloud.talk.utils.NotificationUtils
Expand All @@ -99,6 +107,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARE_RECORDING_TO_CHAT_URL
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID
import com.nextcloud.talk.utils.preferences.AppPreferences
import com.nextcloud.talk.utils.preferences.preferencestorage.DatabaseStorageModule
import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder
import io.reactivex.Observable
import io.reactivex.Observer
Expand Down Expand Up @@ -134,6 +143,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
@Inject
var retrofit: Retrofit? = null

@Inject
lateinit var userManager: UserManager

@JvmField
@Inject
var okHttpClient: OkHttpClient? = null
Expand Down Expand Up @@ -174,6 +186,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
}
} else if (isSpreedNotification()) {
Log.d(TAG, "pushMessage.type: " + pushMessage.type)
val currentUser = userManager.currentUser.blockingGet()
val module = DatabaseStorageModule(currentUser, pushMessage.id)
importantConversation = module.getBoolean(ConversationInfoActivity.IMPORTANT_CONVERSATION_KEY, false)
when (pushMessage.type) {
TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING, TYPE_REMINDER -> handleNonCallPushMessage()
TYPE_CALL -> handleCallPushMessage()
Expand Down Expand Up @@ -319,6 +334,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor

override fun onNext(notificationOverall: NotificationOverall) {
val ncNotification = notificationOverall.ocs!!.notification
Log.d(TAG, "Notification is: $ncNotification")
if (ncNotification != null) {
enrichPushMessageByNcNotificationData(ncNotification)
showNotification(intent, ncNotification)
Expand Down Expand Up @@ -436,10 +452,10 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor

val autoCancelOnClick = TYPE_RECORDING != pushMessage.type

val notificationBuilder = NotificationCompat.Builder(context!!, "1")
val notificationBuilder = NotificationCompat.Builder(context!!, "4")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(category)
.setLargeIcon(getLargeIcon())
// .setLargeIcon(getLargeIcon())
.setSmallIcon(R.drawable.ic_logo)
.setContentTitle(contentTitle)
.setContentText(contentText)
Expand Down Expand Up @@ -495,6 +511,13 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
prepareChatNotification(notificationBuilder, activeStatusBarNotification, systemNotificationId)
addReplyAction(notificationBuilder, systemNotificationId)
addMarkAsReadAction(notificationBuilder, systemNotificationId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
importantConversation &&
TYPE_REMINDER !=
pushMessage.type
) {
setBubble(notificationBuilder)
}
}

if (TYPE_RECORDING == pushMessage.type && ncNotification != null) {
Expand Down Expand Up @@ -556,23 +579,13 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
val person = Person.Builder()
.setKey(signatureVerification.user!!.id.toString() + "@" + notificationUser.id)
.setName(EmojiCompat.get().process(notificationUser.name!!))
.setBot("bot" == userType)
.setImportant(true)
.setBot(true)
notificationBuilder.setOnlyAlertOnce(true)

if ("user" == userType || "guest" == userType) {
val baseUrl = signatureVerification.user!!.baseUrl
val avatarUrl = if ("user" == userType) {
ApiUtils.getUrlForAvatar(
baseUrl,
notificationUser.id,
false
)
} else {
ApiUtils.getUrlForGuestAvatar(baseUrl, notificationUser.name, false)
}
person.setIcon(loadAvatarSync(avatarUrl, context!!))
}
notificationBuilder.setStyle(getStyle(person.build(), style))
person.setIcon(getAvatarIcon())
val personBuilt = person.build()
notificationBuilder.setStyle(getStyle(personBuilt, style))
notificationBuilder.addPerson(personBuilt)
}

private fun buildIntentForAction(cls: Class<*>, systemNotificationId: Int, messageId: Int): PendingIntent {
Expand Down Expand Up @@ -619,6 +632,60 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
}
}

@RequiresApi(Build.VERSION_CODES.R)
private fun setBubble(notificationBuilder: NotificationCompat.Builder) {
val intent = getIntentToOpenConversation()!!

val shortcutId = pushMessage.notificationUser!!.id!!
val shortcuts = ShortcutManagerCompat.getDynamicShortcuts(context!!)
val index = shortcuts.firstOrNull {
it.id == shortcutId
}

if (index == null) {
val shortCutInfo = ShortcutInfoCompat.Builder(context!!, shortcutId)
.setCategories(setOf(Notification.CATEGORY_MESSAGE))
.setIntent(Intent(Intent.ACTION_DEFAULT))
.setLongLived(true)
.setShortLabel(pushMessage.notificationUser!!.name!!)
.build()
ShortcutManagerCompat.pushDynamicShortcut(context!!, shortCutInfo)
}

val bubbleData =
BubbleMetadata.Builder(intent, getAvatarIcon())
.setDesiredHeight(DESIRED_SIZE)
.setIntent(intent)

bubbleData.setIcon(getAvatarIcon())

notificationBuilder
.setBubbleMetadata(bubbleData.build())
.setShortcutId(shortcutId)
.setLocusId(LocusIdCompat(shortcutId))
}

private fun getAvatarIcon(): IconCompat {
val notificationUser = pushMessage.notificationUser
val userType = notificationUser!!.type
var result: IconCompat? = null
if ("user" == userType || "guest" == userType) {
val baseUrl = signatureVerification.user!!.baseUrl
val avatarUrl = if ("user" == userType) {
ApiUtils.getUrlForAvatar(
baseUrl,
notificationUser.type,
false
)
} else {
ApiUtils.getUrlForGuestAvatar(baseUrl, notificationUser.name, false)
}
result = loadAvatarSync(avatarUrl, context!!)
}

return result ?: IconCompat.createWithResource(context!!, R.drawable.account_circle_96dp)
}

private fun addReplyAction(notificationBuilder: NotificationCompat.Builder, systemNotificationId: Int) {
val replyLabel = context!!.resources.getString(R.string.nc_reply)
val remoteInput = RemoteInput.Builder(NotificationUtils.KEY_DIRECT_REPLY)
Expand Down Expand Up @@ -994,5 +1061,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
private const val TIMER_COUNT = 12
private const val TIMER_DELAY: Long = 5
private const val GET_ROOM_RETRY_COUNT: Long = 3
private const val DESIRED_SIZE = 600
}
}

0 comments on commit 5e7fef4

Please sign in to comment.