test push notification

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
This commit is contained in:
sowjanyakch 2025-03-28 15:54:24 +01:00
parent c97fbcc2ce
commit 99b61f5331
No known key found for this signature in database
GPG Key ID: F7AA2A8B65B50220
10 changed files with 305 additions and 26 deletions

View File

@ -17,6 +17,7 @@ import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
import com.nextcloud.talk.models.json.participants.TalkBan
import com.nextcloud.talk.models.json.participants.TalkBanOverall
import com.nextcloud.talk.models.json.testNotification.TestNotificationOverall
import com.nextcloud.talk.models.json.userAbsence.UserAbsenceOverall
import okhttp3.MultipartBody
import okhttp3.RequestBody
@ -238,6 +239,12 @@ interface NcApiCoroutines {
@Url url: String
): UserAbsenceOverall
@POST
suspend fun testPushNotifications(
@Header("Authorization") authorization: String,
@Url url: String
): TestNotificationOverall
@GET
suspend fun getContextOfChatMessage(
@Header("Authorization") authorization: String,

View File

@ -16,6 +16,7 @@ import com.nextcloud.talk.conversationcreation.ConversationCreationViewModel
import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel
import com.nextcloud.talk.conversationinfoedit.viewmodel.ConversationInfoEditViewModel
import com.nextcloud.talk.conversationlist.viewmodels.ConversationsListViewModel
import com.nextcloud.talk.diagnose.DiagnoseViewModel
import com.nextcloud.talk.invitation.viewmodels.InvitationsViewModel
import com.nextcloud.talk.messagesearch.MessageSearchViewModel
import com.nextcloud.talk.openconversations.viewmodels.OpenConversationsViewModel
@ -148,4 +149,9 @@ abstract class ViewModelModule {
@IntoMap
@ViewModelKey(ConversationCreationViewModel::class)
abstract fun conversationCreationViewModel(viewModel: ConversationCreationViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(DiagnoseViewModel::class)
abstract fun diagnoseViewModel(viewModel: DiagnoseViewModel): ViewModel
}

View File

@ -10,6 +10,7 @@ import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Build.MANUFACTURER
import android.os.Build.MODEL
@ -27,6 +28,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.ViewModelProvider
import androidx.core.net.toUri
import autodagger.AutoInjector
import com.nextcloud.talk.BuildConfig
@ -35,8 +37,8 @@ import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
import com.nextcloud.talk.components.SetupSystemBars
import com.nextcloud.talk.components.StandardAppBar
import com.nextcloud.talk.components.SetupSystemBars
import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.BrandingUtils
import com.nextcloud.talk.utils.ClosedInterfaceImpl
@ -56,6 +58,9 @@ class DiagnoseActivity : BaseActivity() {
@Inject
lateinit var arbitraryStorageManager: ArbitraryStorageManager
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
@Inject
lateinit var ncApi: NcApi
@ -78,6 +83,10 @@ class DiagnoseActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
val diagnoseViewModel = ViewModelProvider(
this,
viewModelFactory
)[DiagnoseViewModel::class.java]
val colorScheme = viewThemeUtils.getColorScheme(this)
@ -113,7 +122,7 @@ class DiagnoseActivity : BaseActivity() {
.background(backgroundColor)
.fillMaxSize()
) {
DiagnoseContentComposable(diagnoseDataState)
DiagnoseContentComposable(diagnoseDataState, diagnoseViewModel)
}
}
)
@ -132,6 +141,7 @@ class DiagnoseActivity : BaseActivity() {
setupMetaValues()
setupPhoneValues()
setupAppValues()
testPushNotification()
setupAccountValues()
diagnoseDataState.value = diagnoseData.toList()
@ -187,6 +197,10 @@ class DiagnoseActivity : BaseActivity() {
).show()
}
private fun testPushNotification() {
addHeadline(context.resources.getString(R.string.nc_test_push_button))
}
private fun setupMetaValues() {
addHeadline(context.resources.getString(R.string.nc_diagnose_meta_category_title))
addDiagnosisEntry(

View File

@ -7,28 +7,53 @@
package com.nextcloud.talk.diagnose
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.nextcloud.talk.R
@Composable
fun DiagnoseContentComposable(data: State<List<DiagnoseActivity.DiagnoseElement>>) {
fun DiagnoseContentComposable(
data: State<List<DiagnoseActivity.DiagnoseElement>>,
diagnoseViewModel: DiagnoseViewModel
) {
val context = LocalContext.current
val message = diagnoseViewModel.notificationMessage
val isLoading = diagnoseViewModel.isLoading
val showDialog = diagnoseViewModel.showDialog
Column(
modifier = Modifier
.fillMaxSize()
@ -37,13 +62,33 @@ fun DiagnoseContentComposable(data: State<List<DiagnoseActivity.DiagnoseElement>
) {
data.value.forEach { element ->
when (element) {
is DiagnoseActivity.DiagnoseElement.DiagnoseHeadline -> Text(
modifier = Modifier.padding(vertical = 16.dp),
is DiagnoseActivity.DiagnoseElement.DiagnoseHeadline -> {
if (element.headline == "Test push notifications") {
Text(
text = element.headline,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp)
.clickable { diagnoseViewModel.fetchTestPushResult() },
color = MaterialTheme.colorScheme.secondary,
fontSize = LocalDensity.current.run {
dimensionResource(R.dimen.headline_text_size).toPx().toSp()
},
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Start
)
} else {
Text(
modifier = Modifier.fillMaxWidth().padding(vertical = 16.dp),
text = element.headline,
color = MaterialTheme.colorScheme.primary,
fontSize = LocalDensity.current.run { dimensionResource(R.dimen.headline_text_size).toPx().toSp() },
fontSize = LocalDensity.current.run {
dimensionResource(R.dimen.headline_text_size).toPx().toSp()
},
fontWeight = FontWeight.Bold
)
}
}
is DiagnoseActivity.DiagnoseElement.DiagnoseEntry -> {
Text(
@ -59,19 +104,89 @@ fun DiagnoseContentComposable(data: State<List<DiagnoseActivity.DiagnoseElement>
}
}
}
if (isLoading.value) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
}
@Preview(showBackground = true)
@Composable
fun DiagnoseContentPreview() {
val state = remember {
mutableStateOf(
listOf(
DiagnoseActivity.DiagnoseElement.DiagnoseHeadline("Headline"),
DiagnoseActivity.DiagnoseElement.DiagnoseEntry("Key", "Value")
if (showDialog.value) {
Dialog(
onDismissRequest = { diagnoseViewModel.dismissDialog() },
properties = DialogProperties(
dismissOnClickOutside = true,
usePlatformDefaultWidth = false
)
) {
if (showDialog.value) {
Dialog(
onDismissRequest = { diagnoseViewModel.dismissDialog() },
properties = DialogProperties(
dismissOnClickOutside = true,
usePlatformDefaultWidth = false
)
) {
Surface(
shape = MaterialTheme.shapes.medium,
tonalElevation = 8.dp,
modifier = Modifier
.wrapContentSize()
.padding(16.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Push Test Result", style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(12.dp))
Box(
modifier = Modifier
.fillMaxWidth()
.weight(1f, fill = false)
.verticalScroll(rememberScrollState())
) {
Text(message.value)
}
DiagnoseContentComposable(state)
Spacer(modifier = Modifier.height(16.dp))
Row(
horizontalArrangement = Arrangement.SpaceEvenly,
modifier = Modifier.fillMaxWidth()
) {
TextButton(onClick = { diagnoseViewModel.dismissDialog() }) {
Text("Cancel")
}
Spacer(modifier = Modifier.width(8.dp))
TextButton(onClick = {
val clipboard =
context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("PushMessage", message.value)
clipboard.setPrimaryClip(clip)
Toast.makeText(context, "Message copied to clipboard", Toast.LENGTH_SHORT)
.show()
diagnoseViewModel.dismissDialog()
}) {
Text("Copy")
}
}
}
}
}
}
}
}
}
}
// @Preview(showBackground = true)
// @Composable
// fun DiagnoseContentPreview() {
// val state = remember {
// mutableStateOf(
// listOf(
// DiagnoseActivity.DiagnoseElement.DiagnoseHeadline("Headline"),
// DiagnoseActivity.DiagnoseElement.DiagnoseEntry("Key", "Value")
// )
// )
// }
// DiagnoseContentComposable(state)
// }

View File

@ -0,0 +1,59 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Your Name <your@email.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.diagnose
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.nextcloud.talk.api.NcApiCoroutines
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
import kotlinx.coroutines.launch
import javax.inject.Inject
class DiagnoseViewModel @Inject constructor(
private val ncApiCoroutines: NcApiCoroutines,
private val currentUserProvider: CurrentUserProviderNew
) : ViewModel() {
private val _currentUser = currentUserProvider.currentUser.blockingGet()
val currentUser: User = _currentUser
val credentials = ApiUtils.getCredentials(_currentUser.username, _currentUser.token) ?: ""
private val _notificationMessage = mutableStateOf("")
val notificationMessage = _notificationMessage
private val _isLoading = mutableStateOf(false)
val isLoading = _isLoading
private val _showDialog = mutableStateOf(false)
val showDialog = _showDialog
fun fetchTestPushResult() {
viewModelScope.launch {
try {
_isLoading.value = true
val response = ncApiCoroutines.testPushNotifications(
credentials,
ApiUtils
.getUrlForTestPushNotifications(_currentUser.baseUrl ?: "")
)
_notificationMessage.value = response.ocs?.data?.message ?: "Error while fetching test push message"
} catch (e: Exception) {
_notificationMessage.value = "Exception: ${e.localizedMessage}"
} finally {
_isLoading.value = false
_showDialog.value = true
}
}
}
fun dismissDialog() {
_showDialog.value = false
}
}

View File

@ -0,0 +1,24 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Your Name <your@email.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.models.json.testNotification
import android.os.Parcelable
import com.bluelinelabs.logansquare.annotation.JsonField
import com.bluelinelabs.logansquare.annotation.JsonObject
import kotlinx.parcelize.Parcelize
@Parcelize
@JsonObject
data class TestNotificationData(
@JsonField(name = ["message"])
var message: String
) : Parcelable {
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
constructor() :
this("")
}

View File

@ -0,0 +1,26 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Your Name <your@email.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.models.json.testNotification
import android.os.Parcelable
import com.bluelinelabs.logansquare.annotation.JsonField
import com.bluelinelabs.logansquare.annotation.JsonObject
import com.nextcloud.talk.models.json.generic.GenericMeta
import kotlinx.parcelize.Parcelize
@Parcelize
@JsonObject
data class TestNotificationOCS(
@JsonField(name = ["meta"])
var meta: GenericMeta?,
@JsonField(name = ["data"])
var data: TestNotificationData?
) : Parcelable {
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
constructor() : this(null, null)
}

View File

@ -0,0 +1,23 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Your Name <your@email.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.models.json.testNotification
import android.os.Parcelable
import com.bluelinelabs.logansquare.annotation.JsonField
import com.bluelinelabs.logansquare.annotation.JsonObject
import kotlinx.parcelize.Parcelize
@Parcelize
@JsonObject
data class TestNotificationOverall(
@JsonField(name = ["ocs"])
var ocs: TestNotificationOCS?
) : Parcelable {
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
constructor() : this(null)
}

View File

@ -273,6 +273,10 @@ object ApiUtils {
return getUrlForApi(version, baseUrl) + "/signaling"
}
fun getUrlForTestPushNotifications(baseUrl: String): String {
return "$baseUrl$OCS_API_VERSION/apps/notifications/api/v3/test/self"
}
@JvmStatic
fun getUrlForSignalingBackend(version: Int, baseUrl: String?): String {
return getUrlForSignaling(version, baseUrl) + "/backend"

View File

@ -228,6 +228,7 @@ How to translate with transifex:
<string name="send_email">Send email</string>
<string name="create_issue">Create issue</string>
<string name="nc_diagnose_flavor" translatable="false">Build flavor</string>
<string name="nc_test_push_button">"Test push notifications</string>
<!-- Conversation menu -->
<string name="nc_leave">Leave conversation</string>