refactor default alerts

This commit is contained in:
2024-07-15 06:02:25 +03:00
parent 654f47bb94
commit eaf609c475
10 changed files with 366 additions and 235 deletions
@@ -3,7 +3,13 @@ package com.meloda.app.fast.designsystem
import android.content.res.Configuration
import android.view.KeyEvent
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.platform.LocalContext
@@ -77,3 +83,21 @@ fun Modifier.handleEnterKey(
action.invoke()
} else false
}
@Composable
fun LazyListState.isScrollingUp(): Boolean {
var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) }
var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) }
return remember(this) {
derivedStateOf {
if (previousIndex != firstVisibleItemIndex) {
previousIndex > firstVisibleItemIndex
} else {
previousScrollOffset >= firstVisibleItemScrollOffset
}.also {
previousIndex = firstVisibleItemIndex
previousScrollOffset = firstVisibleItemScrollOffset
}
}
}.value
}
@@ -37,6 +37,208 @@ import com.meloda.app.fast.common.UiText
import com.meloda.app.fast.common.parseString
import com.meloda.app.fast.designsystem.ImmutableList.Companion.toImmutableList
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MaterialDialog(
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
confirmText: String? = null,
confirmAction: (() -> Unit)? = null,
cancelText: String? = null,
cancelAction: (() -> Unit)? = null,
neutralText: String? = null,
neutralAction: (() -> Unit)? = null,
title: String? = null,
text: String? = null,
itemsSelectionType: ItemsSelectionType = ItemsSelectionType.None,
items: ImmutableList<String> = ImmutableList.empty(),
preSelectedItems: ImmutableList<Int> = ImmutableList.empty(),
onItemClick: ((index: Int) -> Unit)? = null,
properties: DialogProperties = DialogProperties(),
actionInvokeDismiss: ActionInvokeDismiss = ActionInvokeDismiss.IfNoAction,
customContent: (ColumnScope.() -> Unit)? = null
) {
var alertItems by remember {
mutableStateOf(
items.mapIndexed { index, title ->
DialogItem(
title,
preSelectedItems.contains(index)
)
}
)
}
BasicAlertDialog(
onDismissRequest = onDismissRequest,
modifier = modifier,
properties = properties
) {
val scrollState = rememberScrollState()
val canScrollBackward by remember { derivedStateOf { scrollState.value > 0 } }
val canScrollForward by remember { derivedStateOf { scrollState.value < scrollState.maxValue } }
Surface(
modifier = Modifier.fillMaxWidth(),
color = AlertDialogDefaults.containerColor,
shape = AlertDialogDefaults.shape,
tonalElevation = AlertDialogDefaults.TonalElevation
) {
Column(modifier = Modifier.padding(bottom = 10.dp)) {
if (title != null) {
Spacer(modifier = Modifier.height(20.dp))
Row {
Spacer(modifier = Modifier.width(24.dp))
Text(
modifier = Modifier.weight(1f),
text = title,
style = MaterialTheme.typography.headlineSmall
)
Spacer(modifier = Modifier.width(20.dp))
}
}
if (canScrollBackward) {
HorizontalDivider(modifier = Modifier.fillMaxWidth())
}
Column(
modifier = Modifier
.fillMaxWidth()
.weight(1f, fill = false)
.verticalScroll(scrollState)
) {
Spacer(modifier = Modifier.height(8.dp))
if (text != null && title == null) {
Spacer(modifier = Modifier.height(20.dp))
}
if (text != null) {
Row {
Spacer(modifier = Modifier.width(24.dp))
Text(
modifier = Modifier.weight(1f),
text = text,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.width(20.dp))
}
}
Spacer(modifier = Modifier.height(8.dp))
if (alertItems.isNotEmpty()) {
Spacer(modifier = Modifier.height(4.dp))
AlertItems(
selectionType = itemsSelectionType,
items = alertItems,
onItemClick = { index ->
onItemClick?.invoke(index)
if (itemsSelectionType == ItemsSelectionType.None) {
onDismissRequest.invoke()
} else {
val newItems =
alertItems.mapIndexed { itemIndex, item ->
item.copy(isSelected = itemIndex == index)
}
alertItems = newItems
}
},
onItemCheckedChanged = { index ->
val newItems = alertItems.toMutableList()
val oldItem = newItems[index]
newItems[index] =
oldItem.copy(isSelected = !oldItem.isSelected)
alertItems = newItems.toImmutableList()
}
)
Spacer(modifier = Modifier.height(10.dp))
} else {
if (customContent != null) {
Spacer(modifier = Modifier.height(4.dp))
customContent.invoke(this)
Spacer(modifier = Modifier.height(10.dp))
}
}
}
if (canScrollForward) {
HorizontalDivider(modifier = Modifier.fillMaxWidth())
}
Row {
Spacer(modifier = Modifier.width(20.dp))
if (neutralText != null) {
TextButton(
onClick = {
neutralAction?.invoke() ?: kotlin.run {
if (actionInvokeDismiss == ActionInvokeDismiss.IfNoAction) {
onDismissRequest()
}
}
if (actionInvokeDismiss == ActionInvokeDismiss.Always) {
onDismissRequest()
}
}
) {
Text(text = neutralText)
}
}
Spacer(modifier = Modifier.weight(1f))
if (cancelText != null) {
TextButton(
onClick = {
cancelAction?.invoke() ?: kotlin.run {
if (actionInvokeDismiss == ActionInvokeDismiss.IfNoAction) {
onDismissRequest()
}
}
if (actionInvokeDismiss == ActionInvokeDismiss.Always) {
onDismissRequest()
}
}
) {
Text(text = cancelText)
}
}
Spacer(modifier = Modifier.width(2.dp))
if (confirmText != null) {
TextButton(
onClick = {
confirmAction?.invoke() ?: kotlin.run {
if (actionInvokeDismiss == ActionInvokeDismiss.IfNoAction) {
onDismissRequest()
}
}
if (actionInvokeDismiss == ActionInvokeDismiss.Always) {
onDismissRequest()
}
}
) {
Text(text = confirmText)
}
}
Spacer(modifier = Modifier.width(20.dp))
}
}
}
}
}
// TODO: 08.04.2023, Danil Nikolaev: refactor this
@Deprecated("need refactoring")
@OptIn(ExperimentalMaterial3Api::class)
@@ -84,7 +286,7 @@ fun MaterialDialog(
)
}
AlertAnimation(visible = isVisible) {
if (isVisible) {
BasicAlertDialog(
onDismissRequest = onDismissRequest,
properties = properties
@@ -250,21 +452,6 @@ fun MaterialDialog(
}
}
@Composable
fun AlertAnimation(
visible: Boolean,
content: @Composable () -> Unit
) {
if (visible) content()
// AnimatedVisibility(
// visible = visible,
// enter = fadeIn(animationSpec = tween(400)) +
// scaleIn(animationSpec = tween(400)),
// exit = fadeOut(animationSpec = tween(150)),
// content = content
// )
}
@Composable
private fun AlertItems(
selectionType: ItemsSelectionType,
@@ -324,8 +511,14 @@ data class DialogItem(
val isSelected: Boolean
)
sealed interface ItemsSelectionType {
data object Single : ItemsSelectionType
data object Multi : ItemsSelectionType
data object None : ItemsSelectionType
sealed class ActionInvokeDismiss {
data object Never : ActionInvokeDismiss()
data object IfNoAction : ActionInvokeDismiss()
data object Always : ActionInvokeDismiss()
}
sealed class ItemsSelectionType {
data object Single : ItemsSelectionType()
data object Multi : ItemsSelectionType()
data object None : ItemsSelectionType()
}
@@ -259,4 +259,7 @@
<string name="notification_channel_long_polling_service_name">Message update service</string>
<string name="notification_channel_long_polling_service_description">Message update service notifications</string>
<string name="warning_confirmation">Confirmation</string>
<string name="captcha_exit_warning">Are you sure? Captcha process will be cancelled</string>
<string name="validation_exit_warning">Are you sure? Validation process will be cancelled</string>
</resources>
@@ -41,6 +41,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
@@ -50,7 +51,7 @@ import coil.request.ImageRequest
import com.meloda.app.fast.auth.captcha.CaptchaViewModel
import com.meloda.app.fast.auth.captcha.CaptchaViewModelImpl
import com.meloda.app.fast.auth.captcha.model.CaptchaScreenState
import com.meloda.app.fast.common.UiText
import com.meloda.app.fast.designsystem.ActionInvokeDismiss
import com.meloda.app.fast.designsystem.MaterialDialog
import com.meloda.app.fast.designsystem.TextFieldErrorText
import org.koin.androidx.compose.koinViewModel
@@ -89,7 +90,7 @@ fun CaptchaScreen(
onTextFieldDoneAction: () -> Unit = {},
onDoneButtonClicked: () -> Unit = {}
) {
var confirmedExit by rememberSaveable {
var confirmedExit by remember {
mutableStateOf(false)
}
@@ -111,14 +112,13 @@ fun CaptchaScreen(
if (showExitAlert) {
MaterialDialog(
onDismissAction = { showExitAlert = false },
title = UiText.Simple("Confirmation"),
text = UiText.Simple("Are you sure? Captcha process will be cancelled."),
confirmText = UiText.Resource(UiR.string.yes),
confirmAction = {
confirmedExit = true
},
cancelText = UiText.Resource(UiR.string.no)
onDismissRequest = { showExitAlert = false },
title = stringResource(id = UiR.string.warning_confirmation),
text = stringResource(id = UiR.string.captcha_exit_warning),
confirmAction = { confirmedExit = true },
confirmText = stringResource(id = UiR.string.yes),
cancelText = stringResource(id = UiR.string.no),
actionInvokeDismiss = ActionInvokeDismiss.Always
)
}
@@ -38,6 +38,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
@@ -46,7 +47,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.meloda.app.fast.auth.validation.ValidationViewModel
import com.meloda.app.fast.auth.validation.ValidationViewModelImpl
import com.meloda.app.fast.auth.validation.model.ValidationScreenState
import com.meloda.app.fast.common.UiText
import com.meloda.app.fast.designsystem.ActionInvokeDismiss
import com.meloda.app.fast.designsystem.MaterialDialog
import com.meloda.app.fast.designsystem.TextFieldErrorText
import com.meloda.app.fast.designsystem.getString
@@ -96,7 +97,7 @@ fun ValidationScreen(
) {
val focusManager = LocalFocusManager.current
var confirmedExit by rememberSaveable {
var confirmedExit by remember {
mutableStateOf(false)
}
@@ -118,14 +119,13 @@ fun ValidationScreen(
if (showExitAlert) {
MaterialDialog(
onDismissAction = { showExitAlert = false },
title = UiText.Simple("Confirmation"),
text = UiText.Simple("Are you sure? Authorization process will be cancelled."),
confirmText = UiText.Resource(UiR.string.yes),
confirmAction = {
confirmedExit = true
},
cancelText = UiText.Resource(UiR.string.no)
onDismissRequest = { showExitAlert = false },
title = stringResource(id = UiR.string.warning_confirmation),
text = stringResource(id = UiR.string.validation_exit_warning),
confirmAction = { confirmedExit = true },
confirmText = stringResource(id = UiR.string.yes),
cancelText = stringResource(id = UiR.string.no),
actionInvokeDismiss = ActionInvokeDismiss.Always
)
}
@@ -47,8 +47,7 @@ interface ConversationsViewModel {
fun onPaginationConditionsMet()
fun onDeleteDialogDismissed()
fun onDeleteDialogPositiveClick(conversationId: Int)
fun onDeleteDialogPositiveClick()
fun onRefresh()
@@ -56,7 +55,8 @@ interface ConversationsViewModel {
fun onConversationItemLongClick(conversation: UiConversation)
fun onPinDialogDismissed()
fun onPinDialogPositiveClick(conversation: UiConversation)
fun onPinDialogPositiveClick()
fun onOptionClicked(conversation: UiConversation, option: ConversationOption)
fun onErrorConsumed()
@@ -104,9 +104,11 @@ class ConversationsViewModelImpl(
emitShowOptions { old -> old.copy(showDeleteDialog = null) }
}
override fun onDeleteDialogPositiveClick(conversationId: Int) {
override fun onDeleteDialogPositiveClick() {
val conversationId = screenState.value.showOptions.showDeleteDialog ?: return
deleteConversation(conversationId)
hideOptions(conversationId)
onDeleteDialogDismissed()
}
override fun onRefresh() {
@@ -168,9 +170,11 @@ class ConversationsViewModelImpl(
emitShowOptions { old -> old.copy(showPinDialog = null) }
}
override fun onPinDialogPositiveClick(conversation: UiConversation) {
override fun onPinDialogPositiveClick() {
val conversation = screenState.value.showOptions.showPinDialog ?: return
pinConversation(conversation.id, !conversation.isPinned)
hideOptions(conversation.id)
onPinDialogDismissed()
}
override fun onOptionClicked(conversation: UiConversation, option: ConversationOption) {
@@ -222,7 +226,8 @@ class ConversationsViewModelImpl(
private fun loadConversations(
offset: Int = currentOffset.value
) {
conversationsUseCase.getConversations(count = LOAD_COUNT, offset = offset).listenValue { state ->
conversationsUseCase.getConversations(count = LOAD_COUNT, offset = offset)
.listenValue { state ->
state.processState(
error = { error ->
if (error is State.Error.ApiError) {
@@ -21,7 +21,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.MoreVert
@@ -68,7 +67,6 @@ import androidx.core.view.HapticFeedbackConstantsCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil.imageLoader
import coil.request.ImageRequest
import com.meloda.app.fast.common.UiText
import com.meloda.app.fast.conversations.ConversationsViewModel
import com.meloda.app.fast.conversations.ConversationsViewModelImpl
import com.meloda.app.fast.conversations.model.ConversationOption
@@ -79,6 +77,7 @@ import com.meloda.app.fast.designsystem.LocalHazeState
import com.meloda.app.fast.designsystem.LocalTheme
import com.meloda.app.fast.designsystem.MaterialDialog
import com.meloda.app.fast.designsystem.components.FullScreenLoader
import com.meloda.app.fast.designsystem.isScrollingUp
import com.meloda.app.fast.model.BaseError
import com.meloda.app.fast.ui.ErrorView
import dev.chrisbanes.haze.haze
@@ -398,72 +397,30 @@ fun HandleDialogs(
val showOptions = screenState.showOptions
if (showOptions.showDeleteDialog != null) {
val conversationId = showOptions.showDeleteDialog
DeleteDialog(
conversationId = conversationId,
viewModel = viewModel
)
}
showOptions.showPinDialog?.let { conversation ->
PinDialog(
conversation = conversation,
viewModel = viewModel
)
}
}
@Composable
fun DeleteDialog(
conversationId: Int,
viewModel: ConversationsViewModel
) {
MaterialDialog(
title = UiText.Resource(UiR.string.confirm_delete_conversation),
confirmText = UiText.Resource(UiR.string.action_delete),
confirmAction = { viewModel.onDeleteDialogPositiveClick(conversationId) },
cancelText = UiText.Resource(UiR.string.cancel),
onDismissAction = viewModel::onDeleteDialogDismissed
onDismissRequest = viewModel::onDeleteDialogDismissed,
title = stringResource(id = UiR.string.confirm_delete_conversation),
confirmAction = viewModel::onDeleteDialogPositiveClick,
confirmText = stringResource(id = UiR.string.action_delete),
cancelText = stringResource(id = UiR.string.cancel)
)
}
@Composable
fun PinDialog(
conversation: UiConversation,
viewModel: ConversationsViewModel
) {
if (showOptions.showPinDialog != null) {
val conversation = showOptions.showPinDialog
MaterialDialog(
title = UiText.Resource(
if (conversation.isPinned) UiR.string.confirm_unpin_conversation
onDismissRequest = viewModel::onPinDialogDismissed,
title = stringResource(
id = if (conversation.isPinned) UiR.string.confirm_unpin_conversation
else UiR.string.confirm_pin_conversation
),
confirmText = UiText.Resource(
if (conversation.isPinned) UiR.string.action_unpin
confirmAction = viewModel::onPinDialogPositiveClick,
confirmText = stringResource(
id = if (conversation.isPinned) UiR.string.action_unpin
else UiR.string.action_pin
),
confirmAction = {
viewModel.onPinDialogPositiveClick(conversation)
},
cancelText = UiText.Resource(UiR.string.cancel),
onDismissAction = viewModel::onPinDialogDismissed
cancelText = stringResource(id = UiR.string.cancel)
)
}
@Composable
private fun LazyListState.isScrollingUp(): Boolean {
var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) }
var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) }
return remember(this) {
derivedStateOf {
if (previousIndex != firstVisibleItemIndex) {
previousIndex > firstVisibleItemIndex
} else {
previousScrollOffset >= firstVisibleItemScrollOffset
}.also {
previousIndex = firstVisibleItemIndex
previousScrollOffset = firstVisibleItemScrollOffset
}
}
}.value
}
@@ -32,15 +32,10 @@ interface SettingsViewModel {
val isLongPollBackgroundEnabled: StateFlow<Boolean?>
fun onLogOutAlertDismissed()
fun onPerformCrashAlertDismissed()
fun onPerformCrashPositiveButtonClicked()
fun onLogOutAlertPositiveClick()
fun onLongPollingAlertPositiveClicked()
fun onLongPollingAlertDismissed()
fun onPerformCrashAlertDismissed()
fun onPerformCrashPositiveButtonClicked()
fun onSettingsItemClicked(key: String)
fun onSettingsItemLongClicked(key: String)
@@ -68,14 +63,6 @@ class SettingsViewModelImpl(
emitShowOptions { old -> old.copy(showLogOut = false) }
}
override fun onPerformCrashAlertDismissed() {
emitShowOptions { old -> old.copy(showPerformCrash = false) }
}
override fun onPerformCrashPositiveButtonClicked() {
throw Exception("Test exception")
}
override fun onLogOutAlertPositiveClick() {
viewModelScope.launch(Dispatchers.IO) {
accountsRepository.storeAccounts(
@@ -93,18 +80,12 @@ class SettingsViewModelImpl(
}
}
override fun onLongPollingAlertPositiveClicked() {
screenState.setValue { old -> old.copy(isNeedToRequestNotificationPermission = true) }
override fun onPerformCrashAlertDismissed() {
emitShowOptions { old -> old.copy(showPerformCrash = false) }
}
override fun onLongPollingAlertDismissed() {
screenState.setValue { old ->
old.copy(
showOptions = old.showOptions.copy(
showLongPollNotifications = false
)
)
}
override fun onPerformCrashPositiveButtonClicked() {
throw Exception("Test exception")
}
override fun onSettingsItemClicked(key: String) {
@@ -3,14 +3,12 @@ package com.meloda.app.fast.settings.model
data class SettingsShowOptions(
val showLogOut: Boolean,
val showPerformCrash: Boolean,
val showLongPollNotifications: Boolean
) {
companion object {
val EMPTY: SettingsShowOptions = SettingsShowOptions(
showLogOut = false,
showPerformCrash = false,
showLongPollNotifications = false
)
}
}
@@ -34,11 +34,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.LayoutDirection
import androidx.core.content.getSystemService
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.meloda.app.fast.common.UiText
import com.meloda.app.fast.common.UserConfig
import com.meloda.app.fast.datastore.SettingsKeys
import com.meloda.app.fast.datastore.UserSettings
import com.meloda.app.fast.datastore.isUsingDarkMode
import com.meloda.app.fast.designsystem.ActionInvokeDismiss
import com.meloda.app.fast.designsystem.LocalTheme
import com.meloda.app.fast.designsystem.MaterialDialog
import com.meloda.app.fast.settings.HapticType
@@ -118,8 +118,6 @@ fun SettingsRoute(
onLogOutButtonClicked()
},
logoutDismissed = viewModel::onLogOutAlertDismissed,
longPollingPositiveClick = viewModel::onLongPollingAlertPositiveClicked,
longPollingDismissed = viewModel::onLongPollingAlertDismissed,
screenState = screenState
)
}
@@ -273,8 +271,6 @@ fun HandlePopups(
performCrashDismissed: () -> Unit,
logoutPositiveClick: () -> Unit,
logoutDismissed: () -> Unit,
longPollingPositiveClick: () -> Unit,
longPollingDismissed: () -> Unit,
screenState: SettingsScreenState
) {
val showOptions = screenState.showOptions
@@ -290,12 +286,6 @@ fun HandlePopups(
dismiss = logoutDismissed,
show = showOptions.showLogOut
)
LongPollingNotificationsPermission(
positiveClick = longPollingPositiveClick,
dismiss = longPollingDismissed,
show = showOptions.showLongPollNotifications
)
}
@Composable
@@ -306,12 +296,13 @@ fun PerformCrashDialog(
) {
if (show) {
MaterialDialog(
title = UiText.Simple("Perform Crash"),
text = UiText.Simple("App will be crashed. Are you sure?"),
confirmText = UiText.Resource(UiR.string.yes),
onDismissRequest = dismiss,
title = "Perform crash",
text = "App will be crashed. Are you sure?",
confirmAction = positiveClick,
cancelText = UiText.Resource(UiR.string.cancel),
onDismissAction = dismiss
confirmText = stringResource(id = UiR.string.yes),
cancelText = stringResource(id = UiR.string.cancel),
actionInvokeDismiss = ActionInvokeDismiss.Always
)
}
}
@@ -325,41 +316,20 @@ fun LogOutDialog(
if (show) {
val isEasterEgg = UserConfig.userId == SettingsKeys.ID_DMITRY
val title = UiText.Resource(
if (isEasterEgg) UiR.string.easter_egg_log_out_dmitry
MaterialDialog(
onDismissRequest = dismiss,
title = stringResource(
id = if (isEasterEgg) UiR.string.easter_egg_log_out_dmitry
else UiR.string.sign_out_confirm_title
)
val positiveText = UiText.Resource(
if (isEasterEgg) UiR.string.easter_egg_log_out_dmitry
),
text = stringResource(id = UiR.string.sign_out_confirm),
confirmAction = positiveClick,
confirmText = stringResource(
id = if (isEasterEgg) UiR.string.easter_egg_log_out_dmitry
else UiR.string.action_sign_out
)
MaterialDialog(
title = title,
text = UiText.Resource(UiR.string.sign_out_confirm),
confirmText = positiveText,
confirmAction = positiveClick,
cancelText = UiText.Resource(UiR.string.cancel),
onDismissAction = dismiss
)
}
}
@Composable
fun LongPollingNotificationsPermission(
positiveClick: () -> Unit,
dismiss: () -> Unit,
show: Boolean
) {
if (show) {
MaterialDialog(
title = UiText.Resource(UiR.string.warning),
text = UiText.Simple("Long polling in background required notifications permission on Android 13 and up"),
confirmText = UiText.Simple("Grant"),
confirmAction = positiveClick,
cancelText = UiText.Resource(UiR.string.cancel),
onDismissAction = dismiss
),
cancelText = stringResource(id = UiR.string.no),
actionInvokeDismiss = ActionInvokeDismiss.Always
)
}
}