- Only enabled on Conversations deemed important
- Enabled ChatActivity to be resizable and embedded in Android Manifest

Signed-off-by: Julius Linus <julius.linus@nextcloud.com>
This commit is contained in:
Julius Linus 2023-10-19 10:52:09 -05:00 committed by rapterjet2004
parent 151613c045
commit f522beb57d
3 changed files with 94 additions and 22 deletions

View File

@ -115,7 +115,8 @@
<activity <activity
android:name=".activities.MainActivity" android:name=".activities.MainActivity"
android:exported="true" android:exported="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize"
>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
@ -217,7 +218,10 @@
<activity <activity
android:name=".chat.ChatActivity" android:name=".chat.ChatActivity"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme"
android:allowEmbedded="true"
android:resizeableActivity="true"
/>
<activity <activity
android:name=".openconversations.ListOpenConversationsActivity" android:name=".openconversations.ListOpenConversationsActivity"

View File

@ -1288,7 +1288,7 @@ class ConversationInfoActivity :
binding.notificationSettingsView.notificationSettingsImportantConversation.setOnClickListener { binding.notificationSettingsView.notificationSettingsImportantConversation.setOnClickListener {
val isChecked = binding.notificationSettingsView.importantConversationSwitch.isChecked val isChecked = binding.notificationSettingsView.importantConversationSwitch.isChecked
binding.notificationSettingsView.importantConversationSwitch.isChecked = !isChecked binding.notificationSettingsView.importantConversationSwitch.isChecked = !isChecked
module.saveBoolean("important_conversation_switch", !isChecked) module.saveBoolean(IMPORTANT_CONVERSATION_KEY, !isChecked)
} }
binding.notificationSettingsView.notificationSettingsCallNotifications.setOnClickListener { binding.notificationSettingsView.notificationSettingsCallNotifications.setOnClickListener {
val isChecked = binding.notificationSettingsView.callNotificationsSwitch.isChecked val isChecked = binding.notificationSettingsView.callNotificationsSwitch.isChecked
@ -1303,7 +1303,7 @@ class ConversationInfoActivity :
} }
binding.notificationSettingsView.importantConversationSwitch.isChecked = module binding.notificationSettingsView.importantConversationSwitch.isChecked = module
.getBoolean("important_conversation_switch", false) .getBoolean(IMPORTANT_CONVERSATION_KEY, false)
binding.notificationSettingsView.callNotificationsSwitch.isChecked = module binding.notificationSettingsView.callNotificationsSwitch.isChecked = module
.getBoolean("call_notifications_switch", true) .getBoolean("call_notifications_switch", true)
@ -1317,6 +1317,7 @@ class ConversationInfoActivity :
private const val LOW_EMPHASIS_OPACITY: Float = 0.38f 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_NOT_REQUIRED_FOR_CONVERSATION: Int = 0
private const val RECORDING_CONSENT_REQUIRED_FOR_CONVERSATION: Int = 1 private const val RECORDING_CONSENT_REQUIRED_FOR_CONVERSATION: Int = 1
const val IMPORTANT_CONVERSATION_KEY = "important_conversation_switch"
} }
/** /**

View File

@ -43,12 +43,18 @@ import android.text.TextUtils
import android.util.Base64 import android.util.Base64
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.BubbleMetadata
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.Person import androidx.core.app.Person
import androidx.core.app.RemoteInput import androidx.core.app.RemoteInput
import androidx.core.content.ContextCompat 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.core.graphics.drawable.toBitmap
import androidx.emoji2.text.EmojiCompat import androidx.emoji2.text.EmojiCompat
import androidx.work.Data import androidx.work.Data
@ -65,6 +71,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
import com.nextcloud.talk.callnotification.CallNotificationActivity import com.nextcloud.talk.callnotification.CallNotificationActivity
import com.nextcloud.talk.conversationinfo.ConversationInfoActivity
import com.nextcloud.talk.models.SignatureVerification import com.nextcloud.talk.models.SignatureVerification
import com.nextcloud.talk.models.json.chat.ChatUtils.Companion.getParsedMessage import com.nextcloud.talk.models.json.chat.ChatUtils.Companion.getParsedMessage
import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.conversations.RoomOverall
@ -77,6 +84,7 @@ import com.nextcloud.talk.receivers.DirectReplyReceiver
import com.nextcloud.talk.receivers.DismissRecordingAvailableReceiver import com.nextcloud.talk.receivers.DismissRecordingAvailableReceiver
import com.nextcloud.talk.receivers.MarkAsReadReceiver import com.nextcloud.talk.receivers.MarkAsReadReceiver
import com.nextcloud.talk.receivers.ShareRecordingToChatReceiver import com.nextcloud.talk.receivers.ShareRecordingToChatReceiver
import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldPlaySound import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldPlaySound
import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.NotificationUtils
@ -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_SHARE_RECORDING_TO_CHAT_URL
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID
import com.nextcloud.talk.utils.preferences.AppPreferences import com.nextcloud.talk.utils.preferences.AppPreferences
import com.nextcloud.talk.utils.preferences.preferencestorage.DatabaseStorageModule
import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.Observer import io.reactivex.Observer
@ -134,6 +143,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
@Inject @Inject
var retrofit: Retrofit? = null var retrofit: Retrofit? = null
@Inject
lateinit var userManager: UserManager
@JvmField @JvmField
@Inject @Inject
var okHttpClient: OkHttpClient? = null var okHttpClient: OkHttpClient? = null
@ -174,6 +186,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
} }
} else if (isSpreedNotification()) { } else if (isSpreedNotification()) {
Log.d(TAG, "pushMessage.type: " + pushMessage.type) 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) { when (pushMessage.type) {
TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING, TYPE_REMINDER -> handleNonCallPushMessage() TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING, TYPE_REMINDER -> handleNonCallPushMessage()
TYPE_CALL -> handleCallPushMessage() TYPE_CALL -> handleCallPushMessage()
@ -319,6 +334,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
override fun onNext(notificationOverall: NotificationOverall) { override fun onNext(notificationOverall: NotificationOverall) {
val ncNotification = notificationOverall.ocs!!.notification val ncNotification = notificationOverall.ocs!!.notification
Log.d(TAG, "Notification is: $ncNotification")
if (ncNotification != null) { if (ncNotification != null) {
enrichPushMessageByNcNotificationData(ncNotification) enrichPushMessageByNcNotificationData(ncNotification)
showNotification(intent, ncNotification) showNotification(intent, ncNotification)
@ -436,10 +452,10 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
val autoCancelOnClick = TYPE_RECORDING != pushMessage.type val autoCancelOnClick = TYPE_RECORDING != pushMessage.type
val notificationBuilder = NotificationCompat.Builder(context!!, "1") val notificationBuilder = NotificationCompat.Builder(context!!, "4")
.setPriority(NotificationCompat.PRIORITY_HIGH) .setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(category) .setCategory(category)
.setLargeIcon(getLargeIcon()) // .setLargeIcon(getLargeIcon())
.setSmallIcon(R.drawable.ic_logo) .setSmallIcon(R.drawable.ic_logo)
.setContentTitle(contentTitle) .setContentTitle(contentTitle)
.setContentText(contentText) .setContentText(contentText)
@ -495,6 +511,12 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
prepareChatNotification(notificationBuilder, activeStatusBarNotification, systemNotificationId) prepareChatNotification(notificationBuilder, activeStatusBarNotification, systemNotificationId)
addReplyAction(notificationBuilder, systemNotificationId) addReplyAction(notificationBuilder, systemNotificationId)
addMarkAsReadAction(notificationBuilder, systemNotificationId) addMarkAsReadAction(notificationBuilder, systemNotificationId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
TYPE_REMINDER !=
pushMessage.type
) {
setBubble(notificationBuilder)
}
} }
if (TYPE_RECORDING == pushMessage.type && ncNotification != null) { if (TYPE_RECORDING == pushMessage.type && ncNotification != null) {
@ -556,23 +578,13 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
val person = Person.Builder() val person = Person.Builder()
.setKey(signatureVerification.user!!.id.toString() + "@" + notificationUser.id) .setKey(signatureVerification.user!!.id.toString() + "@" + notificationUser.id)
.setName(EmojiCompat.get().process(notificationUser.name!!)) .setName(EmojiCompat.get().process(notificationUser.name!!))
.setBot("bot" == userType) .setImportant(true)
.setBot(true)
notificationBuilder.setOnlyAlertOnce(true) notificationBuilder.setOnlyAlertOnce(true)
person.setIcon(getAvatarIcon())
if ("user" == userType || "guest" == userType) { val personBuilt = person.build()
val baseUrl = signatureVerification.user!!.baseUrl notificationBuilder.setStyle(getStyle(personBuilt, style))
val avatarUrl = if ("user" == userType) { notificationBuilder.addPerson(personBuilt)
ApiUtils.getUrlForAvatar(
baseUrl,
notificationUser.id,
false
)
} else {
ApiUtils.getUrlForGuestAvatar(baseUrl, notificationUser.name, false)
}
person.setIcon(loadAvatarSync(avatarUrl, context!!))
}
notificationBuilder.setStyle(getStyle(person.build(), style))
} }
private fun buildIntentForAction(cls: Class<*>, systemNotificationId: Int, messageId: Int): PendingIntent { private fun buildIntentForAction(cls: Class<*>, systemNotificationId: Int, messageId: Int): PendingIntent {
@ -619,6 +631,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) { private fun addReplyAction(notificationBuilder: NotificationCompat.Builder, systemNotificationId: Int) {
val replyLabel = context!!.resources.getString(R.string.nc_reply) val replyLabel = context!!.resources.getString(R.string.nc_reply)
val remoteInput = RemoteInput.Builder(NotificationUtils.KEY_DIRECT_REPLY) val remoteInput = RemoteInput.Builder(NotificationUtils.KEY_DIRECT_REPLY)
@ -994,5 +1060,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
private const val TIMER_COUNT = 12 private const val TIMER_COUNT = 12
private const val TIMER_DELAY: Long = 5 private const val TIMER_DELAY: Long = 5
private const val GET_ROOM_RETRY_COUNT: Long = 3 private const val GET_ROOM_RETRY_COUNT: Long = 3
private const val DESIRED_SIZE = 600
} }
} }