mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-24 02:39:55 +01:00
Provide retry UX for tier restore network failures.
This commit is contained in:
committed by
Greyson Parrelli
parent
9b527f7c6c
commit
eb44dd4318
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.contactsupport
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import org.signal.core.ui.compose.Dialogs
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.SignalPreview
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.SupportEmailUtil
|
||||
|
||||
interface ContactSupportCallbacks {
|
||||
fun submitWithDebuglog()
|
||||
fun submitWithoutDebuglog()
|
||||
fun cancel()
|
||||
|
||||
object Empty : ContactSupportCallbacks {
|
||||
override fun submitWithDebuglog() = Unit
|
||||
override fun submitWithoutDebuglog() = Unit
|
||||
override fun cancel() = Unit
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Three-option contact support dialog.
|
||||
*/
|
||||
@Composable
|
||||
fun ContactSupportDialog(
|
||||
showInProgress: Boolean,
|
||||
callbacks: ContactSupportCallbacks
|
||||
) {
|
||||
if (showInProgress) {
|
||||
Dialogs.IndeterminateProgressDialog()
|
||||
} else {
|
||||
Dialogs.AdvancedAlertDialog(
|
||||
title = stringResource(R.string.ContactSupportDialog_submit_debug_log),
|
||||
body = stringResource(R.string.ContactSupportDialog_your_debug_logs),
|
||||
positive = stringResource(R.string.ContactSupportDialog_submit_with_debug),
|
||||
onPositive = { callbacks.submitWithDebuglog() },
|
||||
neutral = stringResource(R.string.ContactSupportDialog_submit_without_debug),
|
||||
onNeutral = { callbacks.submitWithoutDebuglog() },
|
||||
negative = stringResource(android.R.string.cancel),
|
||||
onNegative = { callbacks.cancel() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in conjunction with [ContactSupportDialog] and [ContactSupportViewModel] to trigger
|
||||
* sending an email when ready.
|
||||
*/
|
||||
@Composable
|
||||
fun SendSupportEmailEffect(
|
||||
contactSupportState: ContactSupportViewModel.ContactSupportState,
|
||||
@StringRes subjectRes: Int,
|
||||
@StringRes filterRes: Int,
|
||||
hide: () -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(contactSupportState.sendEmail) {
|
||||
if (contactSupportState.sendEmail) {
|
||||
val subject = context.getString(subjectRes)
|
||||
val prefix = if (contactSupportState.debugLogUrl != null) {
|
||||
"\n${context.getString(R.string.HelpFragment__debug_log)} ${contactSupportState.debugLogUrl}\n\n"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
val body = SupportEmailUtil.generateSupportEmailBody(context, filterRes, prefix, null)
|
||||
CommunicationActions.openEmail(context, SupportEmailUtil.getSupportEmailAddress(context), subject, body)
|
||||
hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun ContactSupportDialogPreview() {
|
||||
Previews.Preview {
|
||||
ContactSupportDialog(
|
||||
false,
|
||||
ContactSupportCallbacks.Empty
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.contactsupport
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.signal.core.util.orNull
|
||||
import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogRepository
|
||||
|
||||
/**
|
||||
* Intended to be used to drive [ContactSupportDialog].
|
||||
*/
|
||||
class ContactSupportViewModel : ViewModel(), ContactSupportCallbacks {
|
||||
private val submitDebugLogRepository: SubmitDebugLogRepository = SubmitDebugLogRepository()
|
||||
|
||||
private val store: MutableStateFlow<ContactSupportState> = MutableStateFlow(ContactSupportState())
|
||||
|
||||
val state: StateFlow<ContactSupportState> = store.asStateFlow()
|
||||
|
||||
fun showContactSupport() {
|
||||
store.update { it.copy(show = true) }
|
||||
}
|
||||
|
||||
fun hideContactSupport() {
|
||||
store.update { ContactSupportState() }
|
||||
}
|
||||
|
||||
fun contactSupport(includeLogs: Boolean) {
|
||||
viewModelScope.launch {
|
||||
if (includeLogs) {
|
||||
store.update { it.copy(showAsProgress = true) }
|
||||
submitDebugLogRepository.buildAndSubmitLog { result ->
|
||||
store.update { ContactSupportState(sendEmail = true, debugLogUrl = result.orNull()) }
|
||||
}
|
||||
} else {
|
||||
store.update { ContactSupportState(sendEmail = true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun submitWithDebuglog() {
|
||||
contactSupport(true)
|
||||
}
|
||||
|
||||
override fun submitWithoutDebuglog() {
|
||||
contactSupport(false)
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
hideContactSupport()
|
||||
}
|
||||
|
||||
data class ContactSupportState(
|
||||
val show: Boolean = false,
|
||||
val showAsProgress: Boolean = false,
|
||||
val sendEmail: Boolean = false,
|
||||
val debugLogUrl: String? = null
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user