@@ -59,7 +59,12 @@ import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
5959import androidx.appcompat.app.AlertDialog
6060import androidx.appcompat.view.ContextThemeWrapper
6161import androidx.cardview.widget.CardView
62+ import androidx.compose.material3.MaterialTheme
63+ import androidx.compose.runtime.getValue
6264import androidx.compose.runtime.mutableStateOf
65+ import androidx.compose.runtime.setValue
66+ import androidx.compose.ui.platform.ComposeView
67+ import androidx.coordinatorlayout.widget.CoordinatorLayout
6368import androidx.core.content.FileProvider
6469import androidx.core.content.PermissionChecker
6570import androidx.core.content.PermissionChecker.PERMISSION_GRANTED
@@ -241,6 +246,7 @@ import java.util.Locale
241246import java.util.concurrent.ExecutionException
242247import javax.inject.Inject
243248import kotlin.math.roundToInt
249+ import androidx.core.content.ContextCompat
244250
245251@Suppress(" TooManyFunctions" )
246252@AutoInjector(NextcloudTalkApplication ::class )
@@ -285,6 +291,9 @@ class ChatActivity :
285291
286292 private var chatMenu: Menu ? = null
287293
294+ private var overflowMenuHostView: ComposeView ? = null
295+ private var isThreadMenuExpanded by mutableStateOf(false )
296+
288297 private val startSelectContactForResult = registerForActivityResult(
289298 ActivityResultContracts
290299 .StartActivityForResult ()
@@ -1276,26 +1285,6 @@ class ChatActivity :
12761285 }
12771286 }
12781287
1279- this .lifecycleScope.launch {
1280- chatViewModel.threadCreationState.collect { uiState ->
1281- when (uiState) {
1282- ChatViewModel .ThreadCreationUiState .None -> {
1283- }
1284-
1285- is ChatViewModel .ThreadCreationUiState .Error -> {
1286- Log .e(TAG , " Error when creating thread" , uiState.exception)
1287- Snackbar .make(binding.root, R .string.nc_common_error_sorry, Snackbar .LENGTH_LONG ).show()
1288- }
1289-
1290- is ChatViewModel .ThreadCreationUiState .Success -> {
1291- uiState.thread?.first?.threadId?.let {
1292- openThread(it)
1293- }
1294- }
1295- }
1296- }
1297- }
1298-
12991288 this .lifecycleScope.launch {
13001289 chatViewModel.threadRetrieveState.collect { uiState ->
13011290 when (uiState) {
@@ -1309,6 +1298,7 @@ class ChatActivity :
13091298
13101299 is ChatViewModel .ThreadRetrieveUiState .Success -> {
13111300 conversationThreadInfo = uiState.thread
1301+ invalidateOptionsMenu()
13121302 }
13131303 }
13141304 }
@@ -3301,10 +3291,24 @@ class ChatActivity :
33013291 menu.removeItem(R .id.conversation_video_call)
33023292 menu.removeItem(R .id.conversation_voice_call)
33033293 }
3294+
3295+ handleThreadNotificationIcon(menu.findItem(R .id.thread_notifications))
33043296 }
33053297 return true
33063298 }
33073299
3300+ private fun handleThreadNotificationIcon (threadNotificationItem : MenuItem ) {
3301+ threadNotificationItem.isVisible = isChatThread() &&
3302+ hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures .THREADS )
3303+
3304+ val threadNotificationIcon = when (conversationThreadInfo?.attendee?.notificationLevel) {
3305+ 1 -> R .drawable.outline_notifications_active_24
3306+ 3 -> R .drawable.ic_baseline_notifications_off_24
3307+ else -> R .drawable.baseline_notifications_24
3308+ }
3309+ threadNotificationItem.icon = ContextCompat .getDrawable(context, threadNotificationIcon)
3310+ }
3311+
33083312 override fun onOptionsItemSelected (item : MenuItem ): Boolean =
33093313 when (item.itemId) {
33103314 R .id.conversation_video_call -> {
@@ -3334,7 +3338,7 @@ class ChatActivity :
33343338
33353339 R .id.conversation_event -> {
33363340 val anchorView = findViewById<View >(R .id.conversation_event)
3337- showPopupWindow (anchorView)
3341+ showConversationEventMenu (anchorView)
33383342 true
33393343 }
33403344
@@ -3343,11 +3347,96 @@ class ChatActivity :
33433347 true
33443348 }
33453349
3350+ R .id.thread_notifications -> {
3351+ showThreadNotificationMenu()
3352+ true
3353+ }
3354+
33463355 else -> super .onOptionsItemSelected(item)
33473356 }
33483357
3358+ @Suppress(" Detekt.LongMethod" )
3359+ private fun showThreadNotificationMenu () {
3360+ fun setThreadNotificationLevel (level : Int ) {
3361+ val threadNotificationUrl = ApiUtils .getUrlForThreadNotificationLevel(
3362+ version = 1 ,
3363+ baseUrl = conversationUser!! .baseUrl,
3364+ token = roomToken,
3365+ threadId = conversationThreadId!! .toInt()
3366+ )
3367+ chatViewModel.setThreadNotificationLevel(credentials!! , threadNotificationUrl, level)
3368+ }
3369+
3370+ if (overflowMenuHostView == null ) {
3371+ val threadNotificationsAnchor: View ? = findViewById(R .id.thread_notifications)
3372+
3373+ val colorScheme = viewThemeUtils.getColorScheme(this )
3374+
3375+ overflowMenuHostView = ComposeView (this ).apply {
3376+ setContent {
3377+ MaterialTheme (
3378+ colorScheme = colorScheme
3379+ ) {
3380+ val items = listOf (
3381+ MenuItemData (
3382+ title = context.resources.getString(R .string.notifications_default),
3383+ subtitle = context.resources.getString(
3384+ R .string.notifications_default_description
3385+ ),
3386+ icon = R .drawable.baseline_notifications_24,
3387+ onClick = {
3388+ setThreadNotificationLevel(0 )
3389+ }
3390+ ),
3391+ MenuItemData (
3392+ title = context.resources.getString(R .string.notification_all_messages),
3393+ subtitle = null ,
3394+ icon = R .drawable.outline_notifications_active_24,
3395+ onClick = {
3396+ setThreadNotificationLevel(1 )
3397+ }
3398+ ),
3399+ MenuItemData (
3400+ title = context.resources.getString(R .string.notification_mention_only),
3401+ subtitle = null ,
3402+ icon = R .drawable.baseline_notifications_24,
3403+ onClick = {
3404+ setThreadNotificationLevel(2 )
3405+ }
3406+ ),
3407+ MenuItemData (
3408+ title = context.resources.getString(R .string.notification_off),
3409+ subtitle = null ,
3410+ icon = R .drawable.ic_baseline_notifications_off_24,
3411+ onClick = {
3412+ setThreadNotificationLevel(3 )
3413+ }
3414+ )
3415+ )
3416+
3417+ OverflowMenu (
3418+ anchor = threadNotificationsAnchor,
3419+ expanded = isThreadMenuExpanded,
3420+ items = items,
3421+ onDismiss = { isThreadMenuExpanded = false }
3422+ )
3423+ }
3424+ }
3425+ }
3426+
3427+ addContentView(
3428+ overflowMenuHostView,
3429+ CoordinatorLayout .LayoutParams (
3430+ CoordinatorLayout .LayoutParams .MATCH_PARENT ,
3431+ CoordinatorLayout .LayoutParams .MATCH_PARENT
3432+ )
3433+ )
3434+ }
3435+ isThreadMenuExpanded = true
3436+ }
3437+
33493438 @SuppressLint(" InflateParams" )
3350- private fun showPopupWindow (anchorView : View ) {
3439+ private fun showConversationEventMenu (anchorView : View ) {
33513440 val popupView = layoutInflater.inflate(R .layout.item_event_schedule, null )
33523441
33533442 val subtitleTextView = popupView.findViewById<TextView >(R .id.meetingTime)
@@ -4354,18 +4443,6 @@ class ChatActivity :
43544443 startActivity(chatIntent)
43554444 }
43564445
4357- fun createThread (chatMessage : ChatMessage ) {
4358- chatViewModel.createThread(
4359- credentials = conversationUser!! .getCredentials(),
4360- url = ApiUtils .getUrlForThread(
4361- version = chatApiVersion,
4362- baseUrl = conversationUser!! .baseUrl!! ,
4363- token = roomToken,
4364- threadId = chatMessage.jsonMessageId
4365- )
4366- )
4367- }
4368-
43694446 fun openThreadsOverview () {
43704447 val bundle = Bundle ()
43714448 bundle.putString(KEY_ROOM_TOKEN , roomToken)
0 commit comments