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.AddParticipantOverall
import com.nextcloud.talk.models.json.participants.TalkBan import com.nextcloud.talk.models.json.participants.TalkBan
import com.nextcloud.talk.models.json.participants.TalkBanOverall 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 com.nextcloud.talk.models.json.userAbsence.UserAbsenceOverall
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.RequestBody import okhttp3.RequestBody
@ -238,6 +239,12 @@ interface NcApiCoroutines {
@Url url: String @Url url: String
): UserAbsenceOverall ): UserAbsenceOverall
@POST
suspend fun testPushNotifications(
@Header("Authorization") authorization: String,
@Url url: String
): TestNotificationOverall
@GET @GET
suspend fun getContextOfChatMessage( suspend fun getContextOfChatMessage(
@Header("Authorization") authorization: String, @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.conversationinfo.viewmodel.ConversationInfoViewModel
import com.nextcloud.talk.conversationinfoedit.viewmodel.ConversationInfoEditViewModel import com.nextcloud.talk.conversationinfoedit.viewmodel.ConversationInfoEditViewModel
import com.nextcloud.talk.conversationlist.viewmodels.ConversationsListViewModel import com.nextcloud.talk.conversationlist.viewmodels.ConversationsListViewModel
import com.nextcloud.talk.diagnose.DiagnoseViewModel
import com.nextcloud.talk.invitation.viewmodels.InvitationsViewModel import com.nextcloud.talk.invitation.viewmodels.InvitationsViewModel
import com.nextcloud.talk.messagesearch.MessageSearchViewModel import com.nextcloud.talk.messagesearch.MessageSearchViewModel
import com.nextcloud.talk.openconversations.viewmodels.OpenConversationsViewModel import com.nextcloud.talk.openconversations.viewmodels.OpenConversationsViewModel
@ -148,4 +149,9 @@ abstract class ViewModelModule {
@IntoMap @IntoMap
@ViewModelKey(ConversationCreationViewModel::class) @ViewModelKey(ConversationCreationViewModel::class)
abstract fun conversationCreationViewModel(viewModel: ConversationCreationViewModel): ViewModel 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.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Build.MANUFACTURER import android.os.Build.MANUFACTURER
import android.os.Build.MODEL import android.os.Build.MODEL
@ -27,6 +28,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.ViewModelProvider
import androidx.core.net.toUri import androidx.core.net.toUri
import autodagger.AutoInjector import autodagger.AutoInjector
import com.nextcloud.talk.BuildConfig 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.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
import com.nextcloud.talk.components.SetupSystemBars
import com.nextcloud.talk.components.StandardAppBar import com.nextcloud.talk.components.StandardAppBar
import com.nextcloud.talk.components.SetupSystemBars
import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.BrandingUtils import com.nextcloud.talk.utils.BrandingUtils
import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.ClosedInterfaceImpl
@ -56,6 +58,9 @@ class DiagnoseActivity : BaseActivity() {
@Inject @Inject
lateinit var arbitraryStorageManager: ArbitraryStorageManager lateinit var arbitraryStorageManager: ArbitraryStorageManager
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
@Inject @Inject
lateinit var ncApi: NcApi lateinit var ncApi: NcApi
@ -78,6 +83,10 @@ class DiagnoseActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
val diagnoseViewModel = ViewModelProvider(
this,
viewModelFactory
)[DiagnoseViewModel::class.java]
val colorScheme = viewThemeUtils.getColorScheme(this) val colorScheme = viewThemeUtils.getColorScheme(this)
@ -113,7 +122,7 @@ class DiagnoseActivity : BaseActivity() {
.background(backgroundColor) .background(backgroundColor)
.fillMaxSize() .fillMaxSize()
) { ) {
DiagnoseContentComposable(diagnoseDataState) DiagnoseContentComposable(diagnoseDataState, diagnoseViewModel)
} }
} }
) )
@ -132,6 +141,7 @@ class DiagnoseActivity : BaseActivity() {
setupMetaValues() setupMetaValues()
setupPhoneValues() setupPhoneValues()
setupAppValues() setupAppValues()
testPushNotification()
setupAccountValues() setupAccountValues()
diagnoseDataState.value = diagnoseData.toList() diagnoseDataState.value = diagnoseData.toList()
@ -187,6 +197,10 @@ class DiagnoseActivity : BaseActivity() {
).show() ).show()
} }
private fun testPushNotification() {
addHeadline(context.resources.getString(R.string.nc_test_push_button))
}
private fun setupMetaValues() { private fun setupMetaValues() {
addHeadline(context.resources.getString(R.string.nc_diagnose_meta_category_title)) addHeadline(context.resources.getString(R.string.nc_diagnose_meta_category_title))
addDiagnosisEntry( addDiagnosisEntry(

View File

@ -7,28 +7,53 @@
package com.nextcloud.talk.diagnose 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.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize 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.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Alignment
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.text.font.FontWeight 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.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.nextcloud.talk.R import com.nextcloud.talk.R
@Composable @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( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -37,13 +62,33 @@ fun DiagnoseContentComposable(data: State<List<DiagnoseActivity.DiagnoseElement>
) { ) {
data.value.forEach { element -> data.value.forEach { element ->
when (element) { when (element) {
is DiagnoseActivity.DiagnoseElement.DiagnoseHeadline -> Text( is DiagnoseActivity.DiagnoseElement.DiagnoseHeadline -> {
modifier = Modifier.padding(vertical = 16.dp), if (element.headline == "Test push notifications") {
text = element.headline, Text(
color = MaterialTheme.colorScheme.primary, text = element.headline,
fontSize = LocalDensity.current.run { dimensionResource(R.dimen.headline_text_size).toPx().toSp() }, modifier = Modifier
fontWeight = FontWeight.Bold .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()
},
fontWeight = FontWeight.Bold
)
}
}
is DiagnoseActivity.DiagnoseElement.DiagnoseEntry -> { is DiagnoseActivity.DiagnoseElement.DiagnoseEntry -> {
Text( Text(
@ -59,19 +104,89 @@ fun DiagnoseContentComposable(data: State<List<DiagnoseActivity.DiagnoseElement>
} }
} }
} }
if (isLoading.value) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
}
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)
}
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) // @Preview(showBackground = true)
@Composable // @Composable
fun DiagnoseContentPreview() { // fun DiagnoseContentPreview() {
val state = remember { // val state = remember {
mutableStateOf( // mutableStateOf(
listOf( // listOf(
DiagnoseActivity.DiagnoseElement.DiagnoseHeadline("Headline"), // DiagnoseActivity.DiagnoseElement.DiagnoseHeadline("Headline"),
DiagnoseActivity.DiagnoseElement.DiagnoseEntry("Key", "Value") // DiagnoseActivity.DiagnoseElement.DiagnoseEntry("Key", "Value")
) // )
) // )
} // }
DiagnoseContentComposable(state) // 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" return getUrlForApi(version, baseUrl) + "/signaling"
} }
fun getUrlForTestPushNotifications(baseUrl: String): String {
return "$baseUrl$OCS_API_VERSION/apps/notifications/api/v3/test/self"
}
@JvmStatic @JvmStatic
fun getUrlForSignalingBackend(version: Int, baseUrl: String?): String { fun getUrlForSignalingBackend(version: Int, baseUrl: String?): String {
return getUrlForSignaling(version, baseUrl) + "/backend" 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="send_email">Send email</string>
<string name="create_issue">Create issue</string> <string name="create_issue">Create issue</string>
<string name="nc_diagnose_flavor" translatable="false">Build flavor</string> <string name="nc_diagnose_flavor" translatable="false">Build flavor</string>
<string name="nc_test_push_button">"Test push notifications</string>
<!-- Conversation menu --> <!-- Conversation menu -->
<string name="nc_leave">Leave conversation</string> <string name="nc_leave">Leave conversation</string>