mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2397 Multiplayer | Enhancement | Basic layouts and event handling for multiplayer flow notifications (#1090)
This commit is contained in:
parent
bf1d5a269d
commit
baafe2028e
13 changed files with 457 additions and 36 deletions
|
@ -16,8 +16,7 @@ class DefaultFeatureToggles @Inject constructor(
|
|||
override val isLogFromGoProcess =
|
||||
BuildConfig.LOG_FROM_MW_LIBRARY && buildProvider.isDebug()
|
||||
|
||||
override val isLogMiddlewareInteraction =
|
||||
BuildConfig.LOG_MW_INTERACTION && buildProvider.isDebug()
|
||||
override val isLogMiddlewareInteraction = BuildConfig.LOG_MW_INTERACTION && buildProvider.isDebug()
|
||||
|
||||
override val excludeThreadStatusLogging: Boolean = true
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ data class Notification(
|
|||
|
||||
sealed class NotificationPayload {
|
||||
data class GalleryImport(
|
||||
val processId: String,
|
||||
val processId: Id,
|
||||
val errorCode: ImportErrorCode,
|
||||
val spaceId: SpaceId,
|
||||
val name: String
|
||||
|
@ -35,6 +35,15 @@ sealed class NotificationPayload {
|
|||
|
||||
data class RequestToJoin(
|
||||
val spaceId: SpaceId,
|
||||
val spaceName: String,
|
||||
val identity: Id,
|
||||
val identityName: String,
|
||||
val identityIcon: String
|
||||
) : NotificationPayload()
|
||||
|
||||
data class RequestToLeave(
|
||||
val spaceId: SpaceId,
|
||||
val spaceName: String,
|
||||
val identity: String,
|
||||
val identityName: String,
|
||||
val identityIcon: String
|
||||
|
@ -42,29 +51,27 @@ sealed class NotificationPayload {
|
|||
|
||||
data class ParticipantRequestApproved(
|
||||
val spaceId: SpaceId,
|
||||
val spaceName: String,
|
||||
val permissions: SpaceMemberPermissions
|
||||
) : NotificationPayload()
|
||||
|
||||
data class RequestToLeave(
|
||||
|
||||
data class ParticipantRemove(
|
||||
val spaceId: SpaceId,
|
||||
val spaceName: String,
|
||||
val identity: String,
|
||||
val identityName: String,
|
||||
val identityIcon: String
|
||||
) : NotificationPayload()
|
||||
|
||||
data class ParticipantRemove(
|
||||
val identity: String,
|
||||
val identityName: String,
|
||||
val identityIcon: String,
|
||||
val spaceId: SpaceId
|
||||
) : NotificationPayload()
|
||||
|
||||
data class ParticipantRequestDecline(
|
||||
val spaceId: SpaceId
|
||||
val spaceId: SpaceId,
|
||||
val spaceName: String
|
||||
) : NotificationPayload()
|
||||
|
||||
data class ParticipantPermissionsChange(
|
||||
val spaceId: SpaceId,
|
||||
val spaceName: String,
|
||||
val permissions: SpaceMemberPermissions
|
||||
) : NotificationPayload()
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
package com.anytypeio.anytype.core_ui.notifications
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Regular
|
||||
|
||||
@Composable
|
||||
fun MemberRequestApprovedNotification(
|
||||
spaceName: String,
|
||||
isReadOnly: Boolean
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = colorResource(id = R.color.background_primary),
|
||||
)
|
||||
.padding(horizontal = 20.dp, vertical = 16.dp)
|
||||
) {
|
||||
val placeholder = stringResource(id = R.string.untitled)
|
||||
val msg = if (isReadOnly)
|
||||
stringResource(
|
||||
id = R.string.multiplayer_notification_member_request_approved_with_read_only_rights,
|
||||
spaceName.ifEmpty { placeholder }
|
||||
)
|
||||
else
|
||||
stringResource(
|
||||
id = R.string.multiplayer_notification_member_request_approved_with_read_only_rights,
|
||||
spaceName.ifEmpty { placeholder }
|
||||
)
|
||||
Text(
|
||||
text = msg,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Caption1Regular,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MemberSpaceRemovedNotification() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = colorResource(id = R.color.background_primary),)
|
||||
.padding(horizontal = 20.dp, vertical = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.multiplayer_notification_member_removed_from_space),
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Caption1Regular,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun MemberRequestApprovedWithAccessRightsNotificationPreview() {
|
||||
MemberRequestApprovedNotification(
|
||||
spaceName = "Art historians",
|
||||
isReadOnly = true
|
||||
)
|
||||
}
|
|
@ -1,32 +1,46 @@
|
|||
package com.anytypeio.anytype.core_ui.notifications
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.*
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.BAD_INPUT
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.FILE_LOAD_ERROR
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.IMPORT_IS_CANCELED
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.INSUFFICIENT_PERMISSIONS
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.INTERNAL_ERROR
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.LIMIT_OF_ROWS_OR_RELATIONS_EXCEEDED
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.NO_OBJECTS_TO_IMPORT
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.NULL
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode.UNKNOWN_ERROR
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.foundation.AlertConfig
|
||||
import com.anytypeio.anytype.core_ui.foundation.AlertIcon
|
||||
import com.anytypeio.anytype.core_ui.foundation.GRADIENT_TYPE_GREEN
|
||||
import com.anytypeio.anytype.core_ui.foundation.GRADIENT_TYPE_RED
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyCalloutRegular
|
||||
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.Caption1Regular
|
||||
import com.anytypeio.anytype.core_ui.views.HeadlineSubheading
|
||||
import com.anytypeio.anytype.presentation.notifications.NotificationsScreenState
|
||||
|
||||
|
@ -66,7 +80,29 @@ fun NotificationsScreen(
|
|||
onButtonClick = onErrorButtonClick
|
||||
)
|
||||
}
|
||||
|
||||
is NotificationsScreenState.Multiplayer.RequestToJoin -> {
|
||||
OwnerUserRequestToJoin(
|
||||
name = state.identityName,
|
||||
spaceName = state.spaceName,
|
||||
onManageClicked = {}
|
||||
)
|
||||
}
|
||||
is NotificationsScreenState.Multiplayer.RequestToLeave -> {
|
||||
OwnerUserRequestToLeave(
|
||||
name = state.name,
|
||||
spaceName = state.spaceName,
|
||||
onManageClicked = {}
|
||||
)
|
||||
}
|
||||
is NotificationsScreenState.Multiplayer.MemberRequestApproved -> {
|
||||
MemberRequestApprovedNotification(
|
||||
spaceName = state.spaceName,
|
||||
isReadOnly = state.isReadOnly
|
||||
)
|
||||
}
|
||||
is NotificationsScreenState.Multiplayer.MemberSpaceRemove -> {
|
||||
MemberSpaceRemovedNotification()
|
||||
}
|
||||
NotificationsScreenState.Hidden -> {}
|
||||
}
|
||||
}
|
||||
|
@ -204,4 +240,64 @@ fun NotificationsScreenPreviewError() {
|
|||
onActionButtonClick = {},
|
||||
onErrorButtonClick = {}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UserJoinedSpaceWithAccessRightsNotification(
|
||||
name: String,
|
||||
spaceName: String,
|
||||
onManageClicked: () -> Unit,
|
||||
isReadOnly: Boolean
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = colorResource(id = R.color.background_notification_primary),
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
)
|
||||
.padding(horizontal = 20.dp, vertical = 16.dp)
|
||||
.noRippleClickable { onManageClicked() }
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.background(
|
||||
color = Color.Red,
|
||||
shape = CircleShape
|
||||
)
|
||||
)
|
||||
val placeholder = stringResource(id = R.string.untitled)
|
||||
val msg = if (isReadOnly)
|
||||
stringResource(
|
||||
id = R.string.multiplayer_notification_member_joined_space_with_read_only_rights,
|
||||
name.ifEmpty { placeholder },
|
||||
spaceName.ifEmpty { placeholder }
|
||||
)
|
||||
else
|
||||
stringResource(
|
||||
id = R.string.multiplayer_notification_member_joined_space_with_read_only_rights,
|
||||
name.ifEmpty { placeholder },
|
||||
spaceName.ifEmpty { placeholder }
|
||||
)
|
||||
Text(
|
||||
text = msg,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart)
|
||||
.padding(start = 44.dp),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Caption1Regular
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun UserJoinedSpaceWithAccessRightsNotificationPreview() {
|
||||
UserJoinedSpaceWithAccessRightsNotification(
|
||||
name = "Carl Einstein",
|
||||
spaceName = "Art historians",
|
||||
isReadOnly = true,
|
||||
onManageClicked = {}
|
||||
)
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
package com.anytypeio.anytype.core_ui.notifications
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Medium
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Regular
|
||||
|
||||
@Composable
|
||||
fun OwnerUserRequestToJoin(
|
||||
name: String,
|
||||
spaceName: String,
|
||||
onManageClicked: () -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = colorResource(id = R.color.background_primary)
|
||||
)
|
||||
.padding(horizontal = 20.dp, vertical = 16.dp)
|
||||
.noRippleClickable { onManageClicked() },
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.background(
|
||||
color = Color.Red,
|
||||
shape = CircleShape
|
||||
)
|
||||
)
|
||||
val placeholder = stringResource(id = R.string.untitled)
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.multiplayer_notification_member_user_sends_join_request,
|
||||
name.ifEmpty { placeholder },
|
||||
spaceName.ifEmpty { placeholder }
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(start = 12.dp)
|
||||
.weight(1f),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Caption1Regular
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = R.string.multiplayer_notification_view_request),
|
||||
modifier = Modifier
|
||||
.padding(start = 12.dp),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = Caption1Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OwnerUserRequestToLeave(
|
||||
name: String,
|
||||
spaceName: String,
|
||||
onManageClicked: () -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = colorResource(id = R.color.background_primary)
|
||||
)
|
||||
.padding(horizontal = 20.dp, vertical = 16.dp)
|
||||
.noRippleClickable { onManageClicked() },
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.background(
|
||||
color = Color.Red,
|
||||
shape = CircleShape
|
||||
)
|
||||
)
|
||||
val placeholder = stringResource(id = R.string.untitled)
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.multiplayer_notification_member_user_sends_leave_request,
|
||||
name.ifEmpty { placeholder },
|
||||
spaceName.ifEmpty { placeholder }
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(start = 12.dp)
|
||||
.weight(1f),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Caption1Regular
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = R.string.multiplayer_notification_view_request),
|
||||
modifier = Modifier
|
||||
.padding(start = 12.dp),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = Caption1Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun OwnerUserRequestToJoinPreview() {
|
||||
OwnerUserRequestToJoin(
|
||||
name = "Carl Einstein",
|
||||
spaceName = "Art historians",
|
||||
onManageClicked = {}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun OwnerUserRequestToLeavePreview() {
|
||||
OwnerUserRequestToLeave(
|
||||
name = "Aby Warburg",
|
||||
spaceName = "Art historians",
|
||||
onManageClicked = {}
|
||||
)
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
<color name="text_button_label">#000000</color>
|
||||
|
||||
<color name="background_primary">#000000</color>
|
||||
<color name="background_notification_primary">#FFFFFF</color>
|
||||
<color name="background_secondary">#1F1E1D</color>
|
||||
<color name="background_highlighted">#24DAD7CA</color>
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@
|
|||
<color name="text_button_label">#FFFFFF</color>
|
||||
|
||||
<color name="background_primary">#FFFFFF</color>
|
||||
<color name="background_notification_primary">#000000</color>
|
||||
<color name="background_secondary">#FFFFFF</color>
|
||||
<color name="background_highlighted">#144F4F4F</color>
|
||||
|
||||
|
|
|
@ -1354,6 +1354,15 @@
|
|||
<string name="multiplayer_error_space_deleted">Space deleted</string>
|
||||
<string name="multiplayer_error_space_not_found">Space not found</string>
|
||||
<string name="multiplayer_read_only_access_error">Read-only access. Contact space owner for changes.</string>
|
||||
<string name="multiplayer_notification_member_user_sends_join_request"><b>%1$s</b> requested to join the <b>%2$s</b> space.</string>
|
||||
<string name="multiplayer_notification_member_user_sends_leave_request"><b>%1$s</b> requested to leave the <b>%2$s</b> space.</string>
|
||||
<string name="multiplayer_notification_new_join_request">New join request</string>
|
||||
<string name="multiplayer_notification_member_joined_space_with_read_only_rights"><b>%1$s</b> joined <b>%2$s</b> space with read-only access rights</string>
|
||||
<string name="multiplayer_notification_member_joined_space_with_editor_only_rights"><b>%1$s</b> joined <b>%2$s</b> space with edit access rights</string>
|
||||
<string name="multiplayer_notification_member_request_approved_with_read_only_rights">Your request to join the %1$s space has been approved with read-only access rights. The space will be available on your device soon.</string>
|
||||
<string name="multiplayer_notification_member_request_approved_with_edit_rights">Your request to join the %1$s space has been approved with edit access rights. The space will be available on your device soon.</string>
|
||||
<string name="multiplayer_notification_member_removed_from_space">You have been removed from the space, or the space was deleted by the owner.</string>
|
||||
<string name="multiplayer_notification_view_request">View</string>
|
||||
|
||||
<!--endregion-->
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.anytypeio.anytype.data.auth.event.NotificationsRemoteChannel
|
|||
import com.anytypeio.anytype.middleware.EventProxy
|
||||
import com.anytypeio.anytype.middleware.mappers.toCoreModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
|
||||
class NotificationsMiddlewareChannel(
|
||||
|
@ -33,6 +34,6 @@ class NotificationsMiddlewareChannel(
|
|||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}.filter { events -> events.isNotEmpty() }
|
||||
}
|
||||
}
|
|
@ -23,7 +23,6 @@ import com.anytypeio.anytype.core_models.DVViewerCardSize
|
|||
import com.anytypeio.anytype.core_models.DVViewerRelation
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_models.Process
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode
|
||||
import com.anytypeio.anytype.core_models.ManifestInfo
|
||||
|
@ -38,6 +37,7 @@ import com.anytypeio.anytype.core_models.ObjectType
|
|||
import com.anytypeio.anytype.core_models.ObjectTypeIds
|
||||
import com.anytypeio.anytype.core_models.ObjectView
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.Process
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.core_models.RelationFormat
|
||||
import com.anytypeio.anytype.core_models.RelationLink
|
||||
|
@ -909,12 +909,14 @@ fun MNotification.toCoreModel(): Notification {
|
|||
participantPermissionsChange != null -> {
|
||||
NotificationPayload.ParticipantPermissionsChange(
|
||||
spaceId = SpaceId(participantPermissionsChange!!.spaceId),
|
||||
spaceName = participantPermissionsChange!!.spaceName,
|
||||
permissions = participantPermissionsChange!!.permissions.toCore()
|
||||
)
|
||||
}
|
||||
requestToJoin != null -> {
|
||||
NotificationPayload.RequestToJoin(
|
||||
spaceId = SpaceId(requestToJoin!!.spaceId),
|
||||
spaceName = requestToJoin!!.spaceName,
|
||||
identity = requestToJoin!!.identity,
|
||||
identityName = requestToJoin!!.identityName,
|
||||
identityIcon = requestToJoin!!.identityIcon
|
||||
|
@ -923,6 +925,7 @@ fun MNotification.toCoreModel(): Notification {
|
|||
requestToLeave != null -> {
|
||||
NotificationPayload.RequestToLeave(
|
||||
spaceId = SpaceId(requestToLeave!!.spaceId),
|
||||
spaceName = requestToLeave!!.spaceName,
|
||||
identity = requestToLeave!!.identity,
|
||||
identityName = requestToLeave!!.identityName,
|
||||
identityIcon = requestToLeave!!.identityIcon
|
||||
|
@ -931,7 +934,8 @@ fun MNotification.toCoreModel(): Notification {
|
|||
participantRequestApproved != null -> {
|
||||
NotificationPayload.ParticipantRequestApproved(
|
||||
spaceId = SpaceId(participantRequestApproved!!.spaceId),
|
||||
permissions = participantRequestApproved!!.permissions.toCore()
|
||||
permissions = participantRequestApproved!!.permissions.toCore(),
|
||||
spaceName = participantRequestApproved!!.spaceName
|
||||
)
|
||||
}
|
||||
participantRemove != null -> {
|
||||
|
@ -939,12 +943,14 @@ fun MNotification.toCoreModel(): Notification {
|
|||
identity = participantRemove!!.identity,
|
||||
identityName = participantRemove!!.identityName,
|
||||
identityIcon = participantRemove!!.identityIcon,
|
||||
spaceId = SpaceId(participantRemove!!.spaceId)
|
||||
spaceId = SpaceId(participantRemove!!.spaceId),
|
||||
spaceName = participantRemove!!.spaceName
|
||||
)
|
||||
}
|
||||
participantRequestDecline != null -> {
|
||||
NotificationPayload.ParticipantRequestDecline(
|
||||
spaceId = SpaceId(participantRequestDecline!!.spaceId)
|
||||
spaceId = SpaceId(participantRequestDecline!!.spaceId),
|
||||
spaceName = participantRequestDecline!!.spaceName
|
||||
)
|
||||
}
|
||||
galleryImport != null -> {
|
||||
|
|
|
@ -96,13 +96,31 @@ class MainViewModel(
|
|||
}
|
||||
|
||||
private suspend fun handleNotification(event: Notification.Event) {
|
||||
val payload = event.notification?.payload
|
||||
if (payload is NotificationPayload.GalleryImport) {
|
||||
delay(DELAY_BEFORE_SHOWING_NOTIFICATION_SCREEN)
|
||||
commands.emit(Command.Notifications)
|
||||
} else {
|
||||
viewModelScope.launch {
|
||||
toasts.emit(payload.toString())
|
||||
when (val payload = event.notification?.payload) {
|
||||
is NotificationPayload.GalleryImport -> {
|
||||
delay(DELAY_BEFORE_SHOWING_NOTIFICATION_SCREEN)
|
||||
commands.emit(Command.Notifications)
|
||||
}
|
||||
is NotificationPayload.RequestToJoin -> {
|
||||
delay(DELAY_BEFORE_SHOWING_NOTIFICATION_SCREEN)
|
||||
commands.emit(Command.Notifications)
|
||||
}
|
||||
is NotificationPayload.RequestToLeave -> {
|
||||
delay(DELAY_BEFORE_SHOWING_NOTIFICATION_SCREEN)
|
||||
commands.emit(Command.Notifications)
|
||||
}
|
||||
is NotificationPayload.ParticipantRequestApproved -> {
|
||||
delay(DELAY_BEFORE_SHOWING_NOTIFICATION_SCREEN)
|
||||
commands.emit(Command.Notifications)
|
||||
}
|
||||
is NotificationPayload.ParticipantRemove -> {
|
||||
delay(DELAY_BEFORE_SHOWING_NOTIFICATION_SCREEN)
|
||||
commands.emit(Command.Notifications)
|
||||
}
|
||||
else -> {
|
||||
viewModelScope.launch {
|
||||
toasts.emit(payload.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.anytypeio.anytype.core_models.Notification
|
|||
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.workspace.NotificationsChannel
|
||||
import com.anytypeio.anytype.presentation.BuildConfig
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
@ -13,6 +14,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
interface NotificationsProvider {
|
||||
val events: StateFlow<List<Notification.Event>>
|
||||
|
@ -30,6 +32,9 @@ interface NotificationsProvider {
|
|||
init {
|
||||
scope.launch(dispatchers.io) {
|
||||
observe().collect { events ->
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.d("New notifications: $events")
|
||||
}
|
||||
_events.value = events
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.analytics.base.EventsDictionary
|
||||
import com.anytypeio.anytype.analytics.base.sendEvent
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ImportErrorCode
|
||||
import com.anytypeio.anytype.core_models.Notification
|
||||
import com.anytypeio.anytype.core_models.NotificationPayload
|
||||
|
@ -38,17 +39,51 @@ class NotificationsViewModel(
|
|||
|
||||
private fun handleNotification(event: Notification.Event) {
|
||||
val payload = event.notification?.payload
|
||||
if (payload is NotificationPayload.GalleryImport) {
|
||||
if (payload.errorCode != ImportErrorCode.NULL) {
|
||||
state.value = NotificationsScreenState.GalleryInstalledError(
|
||||
errorCode = payload.errorCode
|
||||
when (payload) {
|
||||
is NotificationPayload.GalleryImport -> {
|
||||
if (payload.errorCode != ImportErrorCode.NULL) {
|
||||
state.value = NotificationsScreenState.GalleryInstalledError(
|
||||
errorCode = payload.errorCode
|
||||
)
|
||||
} else {
|
||||
state.value = NotificationsScreenState.GalleryInstalled(
|
||||
spaceId = payload.spaceId,
|
||||
galleryName = payload.name
|
||||
)
|
||||
}
|
||||
}
|
||||
is NotificationPayload.RequestToJoin -> {
|
||||
state.value = NotificationsScreenState.Multiplayer.RequestToJoin(
|
||||
space = payload.spaceId,
|
||||
spaceName = payload.spaceName,
|
||||
identity = payload.identity,
|
||||
identityName = payload.identityName
|
||||
)
|
||||
} else {
|
||||
state.value = NotificationsScreenState.GalleryInstalled(
|
||||
spaceId = payload.spaceId,
|
||||
galleryName = payload.name
|
||||
}
|
||||
is NotificationPayload.RequestToLeave -> {
|
||||
state.value = NotificationsScreenState.Multiplayer.RequestToLeave(
|
||||
space = payload.spaceId,
|
||||
spaceName = payload.spaceName,
|
||||
identity = payload.identity,
|
||||
name = payload.identityName
|
||||
)
|
||||
}
|
||||
is NotificationPayload.ParticipantRequestApproved -> {
|
||||
state.value = NotificationsScreenState.Multiplayer.MemberRequestApproved(
|
||||
space = payload.spaceId,
|
||||
spaceName = payload.spaceName,
|
||||
isReadOnly = !payload.permissions.isOwnerOrEditor()
|
||||
)
|
||||
}
|
||||
is NotificationPayload.ParticipantRemove -> {
|
||||
state.value = NotificationsScreenState.Multiplayer.MemberSpaceRemove(
|
||||
spaceName = payload.spaceName,
|
||||
identityName = payload.identityName
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Timber.w("Ignored notification: $payload")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,7 +115,7 @@ class NotificationsViewModel(
|
|||
}
|
||||
|
||||
sealed class Command {
|
||||
object Dismiss : Command()
|
||||
data object Dismiss : Command()
|
||||
data class NavigateToSpace(val spaceId: SpaceId) : Command()
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +123,7 @@ class NotificationsViewModel(
|
|||
|
||||
|
||||
sealed class NotificationsScreenState {
|
||||
object Hidden : NotificationsScreenState()
|
||||
data object Hidden : NotificationsScreenState()
|
||||
data class GalleryInstalled(
|
||||
val spaceId: SpaceId,
|
||||
val galleryName: String
|
||||
|
@ -96,4 +131,31 @@ sealed class NotificationsScreenState {
|
|||
data class GalleryInstalledError(
|
||||
val errorCode: ImportErrorCode
|
||||
) : NotificationsScreenState()
|
||||
sealed class Multiplayer : NotificationsScreenState() {
|
||||
// Owner
|
||||
data class RequestToJoin(
|
||||
val space: SpaceId,
|
||||
val spaceName: String,
|
||||
val identity: Id,
|
||||
val identityName: String
|
||||
) : Multiplayer()
|
||||
// Owner
|
||||
data class RequestToLeave(
|
||||
val space: SpaceId,
|
||||
val spaceName: String,
|
||||
val identity: Id,
|
||||
val name: String
|
||||
) : Multiplayer()
|
||||
// Member
|
||||
data class MemberRequestApproved(
|
||||
val space: SpaceId,
|
||||
val spaceName: String,
|
||||
val isReadOnly: Boolean
|
||||
) : Multiplayer()
|
||||
// Member
|
||||
data class MemberSpaceRemove(
|
||||
val spaceName: String,
|
||||
val identityName: String
|
||||
) : Multiplayer()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue