1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-3654 Notifications | Notification alert (#2392)

This commit is contained in:
Konstantin Ivanov 2025-05-20 14:55:28 +02:00 committed by GitHub
parent be265520d4
commit 83e6981c81
Signed by: github
GPG key ID: B5690EEEBB952194
12 changed files with 485 additions and 10 deletions

View file

@ -4,7 +4,6 @@ import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Command
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.LinkPreview
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys
import com.anytypeio.anytype.core_models.ObjectWrapper
@ -42,6 +41,7 @@ import com.anytypeio.anytype.presentation.confgs.ChatConfig
import com.anytypeio.anytype.presentation.home.OpenObjectNavigation
import com.anytypeio.anytype.presentation.home.navigation
import com.anytypeio.anytype.presentation.mapper.objectIcon
import com.anytypeio.anytype.presentation.notifications.NotificationPermissionManager
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.objects.SpaceMemberIconView
import com.anytypeio.anytype.presentation.search.GlobalSearchItemView
@ -61,7 +61,6 @@ import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
@ -83,7 +82,8 @@ class ChatViewModel @Inject constructor(
private val copyFileToCacheDirectory: CopyFileToCacheDirectory,
private val exitToVaultDelegate: ExitToVaultDelegate,
private val getLinkPreview: GetLinkPreview,
private val createObjectFromUrl: CreateObjectFromUrl
private val createObjectFromUrl: CreateObjectFromUrl,
private val notificationPermissionManager: NotificationPermissionManager
) : BaseViewModel(), ExitToVaultDelegate by exitToVaultDelegate {
private val visibleRangeUpdates = MutableSharedFlow<Pair<Id, Id>>(
@ -100,6 +100,7 @@ class ChatViewModel @Inject constructor(
val navigation = MutableSharedFlow<OpenObjectNavigation>()
val chatBoxMode = MutableStateFlow<ChatBoxMode>(ChatBoxMode.Default())
val mentionPanelState = MutableStateFlow<MentionPanelState>(MentionPanelState.Hidden)
val showNotificationPermissionDialog = MutableStateFlow(false)
private val dateFormatter = SimpleDateFormat("d MMMM YYYY")
@ -955,6 +956,33 @@ class ChatViewModel @Inject constructor(
}
}
fun checkNotificationPermissionDialogState() {
val shouldShow = notificationPermissionManager.shouldShowPermissionDialog()
Timber.d("shouldShowNotificationPermissionDialog: $shouldShow")
if (shouldShow) {
showNotificationPermissionDialog.value = true
}
}
fun onNotificationPermissionRequested() {
notificationPermissionManager.onPermissionRequested()
}
fun onNotificationPermissionGranted() {
showNotificationPermissionDialog.value = false
notificationPermissionManager.onPermissionGranted()
}
fun onNotificationPermissionDenied() {
showNotificationPermissionDialog.value = false
notificationPermissionManager.onPermissionDenied()
}
fun onNotificationPermissionDismissed() {
showNotificationPermissionDialog.value = false
notificationPermissionManager.onPermissionDismissed()
}
private fun isMentionTriggered(text: String, selectionStart: Int): Boolean {
if (selectionStart <= 0 || selectionStart > text.length) return false
val previousChar = text[selectionStart - 1]

View file

@ -18,6 +18,7 @@ import com.anytypeio.anytype.domain.`object`.OpenObject
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
import com.anytypeio.anytype.domain.objects.CreateObjectFromUrl
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.presentation.notifications.NotificationPermissionManager
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
import com.anytypeio.anytype.presentation.vault.ExitToVaultDelegate
import javax.inject.Inject
@ -39,7 +40,8 @@ class ChatViewModelFactory @Inject constructor(
private val copyFileToCacheDirectory: CopyFileToCacheDirectory,
private val exitToVaultDelegate: ExitToVaultDelegate,
private val getLinkPreview: GetLinkPreview,
private val createObjectFromUrl: CreateObjectFromUrl
private val createObjectFromUrl: CreateObjectFromUrl,
private val notificationPermissionManager: NotificationPermissionManager
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T = ChatViewModel(
@ -59,6 +61,7 @@ class ChatViewModelFactory @Inject constructor(
copyFileToCacheDirectory = copyFileToCacheDirectory,
exitToVaultDelegate = exitToVaultDelegate,
getLinkPreview = getLinkPreview,
createObjectFromUrl = createObjectFromUrl
createObjectFromUrl = createObjectFromUrl,
notificationPermissionManager = notificationPermissionManager
) as T
}

View file

@ -0,0 +1,94 @@
package com.anytypeio.anytype.feature_chats.ui
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
import com.anytypeio.anytype.core_ui.views.ButtonPrimary
import com.anytypeio.anytype.core_ui.views.ButtonSecondary
import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.HeadlineHeading
import com.anytypeio.anytype.core_ui.views.Title2
import com.anytypeio.anytype.feature_chats.R
@Composable
fun NotificationPermissionContent(
onEnableNotifications: () -> Unit,
onCancelClicked: () -> Unit
) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(color = colorResource(id = R.color.widget_background)),
) {
Image(
modifier = Modifier
.fillMaxWidth()
.height(232.dp),
painter = painterResource(id = R.drawable.push_modal_illustration),
contentDescription = "Push notifications illustration",
contentScale = ContentScale.Crop
)
Spacer(modifier = Modifier.height(20.dp))
Text(
text = stringResource(R.string.notifications_modal_title),
style = HeadlineHeading,
textAlign = TextAlign.Center,
color = colorResource(id = R.color.text_primary),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.notifications_modal_description),
style = Title2,
textAlign = TextAlign.Center,
color = colorResource(id = R.color.text_primary),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
)
Spacer(modifier = Modifier.height(20.dp))
ButtonPrimary(
text = stringResource(R.string.notifications_modal_success_button),
onClick = onEnableNotifications,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
size = ButtonSize.Large,
)
Spacer(modifier = Modifier.height(10.dp))
ButtonSecondary(
text = stringResource(id = R.string.notifications_modal_cancel_button),
onClick = onCancelClicked,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
size = ButtonSize.Large
)
Spacer(modifier = Modifier.height(16.dp))
}
}
@DefaultPreviews
@Composable
fun NotificationPermissionRequestDialogPreview() {
NotificationPermissionContent(
onEnableNotifications = {},
onCancelClicked = {}
)
}