Skip to content

Commit 75c5879

Browse files
authored
Merge pull request #5345 from nextcloud/feature/3074/improveThreads5
Feature/3074/improve threads5
2 parents 7caccdd + 6c44d6e commit 75c5879

14 files changed

Lines changed: 322 additions & 62 deletions

File tree

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ configurations.configureEach {
186186

187187
dependencies {
188188
implementation "androidx.room:room-testing-android:${roomVersion}"
189+
implementation 'androidx.compose.foundation:foundation-layout:1.9.0'
189190
spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.14.0'
190191
spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.14'
191192
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.8")

app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,17 @@ interface NcApiCoroutines {
289289
@DELETE
290290
suspend fun unbindRoom(@Header("Authorization") authorization: String, @Url url: String): GenericOverall
291291

292-
@POST
293-
suspend fun createThread(@Header("Authorization") authorization: String, @Url url: String): ThreadOverall
294-
295292
@GET
296293
suspend fun getThreads(@Header("Authorization") authorization: String, @Url url: String): ThreadsOverall
297294

298295
@GET
299296
suspend fun getThread(@Header("Authorization") authorization: String, @Url url: String): ThreadOverall
297+
298+
@FormUrlEncoded
299+
@POST
300+
suspend fun setThreadNotificationLevel(
301+
@Header("Authorization") authorization: String,
302+
@Url url: String,
303+
@Field("level") level: Int
304+
): ThreadOverall
300305
}

app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

Lines changed: 111 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
5959
import androidx.appcompat.app.AlertDialog
6060
import androidx.appcompat.view.ContextThemeWrapper
6161
import androidx.cardview.widget.CardView
62+
import androidx.compose.material3.MaterialTheme
63+
import androidx.compose.runtime.getValue
6264
import androidx.compose.runtime.mutableStateOf
65+
import androidx.compose.runtime.setValue
66+
import androidx.compose.ui.platform.ComposeView
67+
import androidx.coordinatorlayout.widget.CoordinatorLayout
6368
import androidx.core.content.FileProvider
6469
import androidx.core.content.PermissionChecker
6570
import androidx.core.content.PermissionChecker.PERMISSION_GRANTED
@@ -241,6 +246,7 @@ import java.util.Locale
241246
import java.util.concurrent.ExecutionException
242247
import javax.inject.Inject
243248
import 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

Comments
 (0)