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

Droid 3622 add counters to space chat widget (#2449)

This commit is contained in:
Evgenii Kozlov 2025-05-23 19:01:21 +02:00 committed by GitHub
parent 5fe1d8489d
commit 622b4ea27c
Signed by: github
GPG key ID: B5690EEEBB952194
15 changed files with 249 additions and 103 deletions

View file

@ -47,6 +47,7 @@ import com.anytypeio.anytype.domain.base.onSuccess
import com.anytypeio.anytype.domain.bin.EmptyBin
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
import com.anytypeio.anytype.domain.block.interactor.Move
import com.anytypeio.anytype.domain.chats.ChatPreviewContainer
import com.anytypeio.anytype.domain.collections.AddObjectToCollection
import com.anytypeio.anytype.domain.dashboard.interactor.SetObjectListIsFavorite
import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewObject
@ -122,6 +123,7 @@ import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction
import com.anytypeio.anytype.presentation.widgets.LinkWidgetContainer
import com.anytypeio.anytype.presentation.widgets.ListWidgetContainer
import com.anytypeio.anytype.presentation.widgets.SpaceBinWidgetContainer
import com.anytypeio.anytype.presentation.widgets.SpaceChatWidgetContainer
import com.anytypeio.anytype.presentation.widgets.SpaceWidgetContainer
import com.anytypeio.anytype.presentation.widgets.TreePath
import com.anytypeio.anytype.presentation.widgets.TreeWidgetBranchStateHolder
@ -233,7 +235,8 @@ class HomeScreenViewModel(
private val getSpaceInviteLink: GetSpaceInviteLink,
private val deleteSpace: DeleteSpace,
private val spaceMembers: ActiveSpaceMemberSubscriptionContainer,
private val setAsFavourite: SetObjectListIsFavorite
private val setAsFavourite: SetObjectListIsFavorite,
private val chatPreviews: ChatPreviewContainer
) : NavigationViewModel<HomeScreenViewModel.Navigation>(),
Reducer<ObjectView, Payload>,
WidgetActiveViewStateHolder by widgetActiveViewStateHolder,
@ -507,6 +510,10 @@ class HomeScreenViewModel(
widgets.forceChatPosition().filter { widget -> widget.hasValidLayout() }.map { widget ->
when (widget) {
is Widget.Chat -> SpaceChatWidgetContainer(
widget = widget,
container = chatPreviews
)
is Widget.Link -> LinkWidgetContainer(
widget = widget,
fieldParser = fieldParser
@ -1192,7 +1199,7 @@ class HomeScreenViewModel(
)
)
}
WidgetView.SpaceChat.id -> {
BundledWidgetSourceIds.CHAT -> {
proceedWithSpaceChatWidgetHeaderClick()
}
else -> {
@ -1315,6 +1322,7 @@ class HomeScreenViewModel(
}
// All-objects widget has link appearance.
is Widget.AllObjects -> Command.ChangeWidgetType.TYPE_LINK
is Widget.Chat -> Command.ChangeWidgetType.TYPE_LINK
}
// TODO move to a separate reducer inject into this VM's constructor
@ -2690,7 +2698,8 @@ class HomeScreenViewModel(
private val getSpaceInviteLink: GetSpaceInviteLink,
private val deleteSpace: DeleteSpace,
private val activeSpaceMemberSubscriptionContainer: ActiveSpaceMemberSubscriptionContainer,
private val setObjectListIsFavorite: SetObjectListIsFavorite
private val setObjectListIsFavorite: SetObjectListIsFavorite,
private val chatPreviews: ChatPreviewContainer
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T = HomeScreenViewModel(
@ -2748,7 +2757,8 @@ class HomeScreenViewModel(
getSpaceInviteLink = getSpaceInviteLink,
deleteSpace = this@Factory.deleteSpace,
spaceMembers = activeSpaceMemberSubscriptionContainer,
setAsFavourite = setObjectListIsFavorite
setAsFavourite = setObjectListIsFavorite,
chatPreviews = chatPreviews
) as T
}

View file

@ -93,7 +93,7 @@ class DataViewListWidgetContainer(
)
)
}
is Widget.Link, is Widget.Tree, is Widget.AllObjects -> {
is Widget.Link, is Widget.Tree, is Widget.AllObjects, is Widget.Chat -> {
throw IllegalStateException("Incompatible widget type.")
}
}
@ -150,7 +150,7 @@ class DataViewListWidgetContainer(
)
)
}
is Widget.Tree, is Widget.Link, is Widget.AllObjects -> {
is Widget.Tree, is Widget.Link, is Widget.AllObjects, is Widget.Chat -> {
throw IllegalStateException("Incompatible widget type.")
}
}
@ -181,7 +181,7 @@ class DataViewListWidgetContainer(
limit = when (widget) {
is Widget.List -> widget.limit
is Widget.View -> widget.limit
is Widget.Tree, is Widget.Link, is Widget.AllObjects -> {
is Widget.Tree, is Widget.Link, is Widget.AllObjects, is Widget.Chat -> {
throw IllegalStateException("Incompatible widget type.")
}
}
@ -355,7 +355,7 @@ class DataViewListWidgetContainer(
prettyPrintName = fieldParser.getObjectPluralName(widget.source.obj)
)
)
is Widget.Link, is Widget.Tree, is Widget.AllObjects -> {
is Widget.Link, is Widget.Tree, is Widget.AllObjects, is Widget.Chat -> {
throw IllegalStateException("Incompatible widget type.")
}
}

View file

@ -1,10 +1,42 @@
package com.anytypeio.anytype.presentation.widgets
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.chats.ChatPreviewContainer
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
class SpaceChatWidgetContainer : WidgetContainer {
override val view: Flow<WidgetView> = flowOf(
WidgetView.SpaceChat
)
class SpaceChatWidgetContainer @Inject constructor(
private val widget: Widget,
private val container: ChatPreviewContainer
) : WidgetContainer {
override val view: Flow<WidgetView> = flow {
emitAll(
container
.observePreview(space = SpaceId(widget.config.space))
.map { preview ->
(preview?.state?.unreadMessages?.counter ?: 0) to (preview?.state?.unreadMentions?.counter ?: 0)
}
.distinctUntilChanged()
.map { (unreadMessageCount, unreadMentionCount) ->
WidgetView.SpaceChat(
id = widget.id,
source = widget.source,
unreadMessageCount = unreadMessageCount,
unreadMentionCount = unreadMentionCount
)
}
)
}.catch {
emit(
WidgetView.SpaceChat(
id = widget.id,
source = widget.source
)
)
}
}

View file

@ -72,6 +72,13 @@ sealed class Widget {
override val isAutoCreated: Boolean = false,
) : Widget()
data class Chat(
override val id: Id,
override val source: Source.Bundled.Chat,
override val config: Config,
override val isAutoCreated: Boolean = false,
) : Widget()
sealed class Source {
abstract val id: Id
@ -172,69 +179,32 @@ fun List<Block>.parseWidgets(
is Widget.Source.Default -> source.obj.isValid && source.obj.notDeletedNorArchived
}
if (hasValidSource && !WidgetConfig.excludedTypes.contains(source.type)) {
if (source is Widget.Source.Bundled.AllObjects) {
add(
Widget.AllObjects(
id = w.id,
source = source,
config = config,
isAutoCreated = widgetContent.isAutoAdded
when (source) {
is Widget.Source.Bundled.AllObjects -> {
add(
Widget.AllObjects(
id = w.id,
source = source,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
)
)
} else {
when (widgetContent.layout) {
Block.Content.Widget.Layout.TREE -> {
add(
Widget.Tree(
id = w.id,
source = source,
limit = widgetContent.limit,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
}
is Widget.Source.Bundled.Chat -> {
add(
Widget.Chat(
id = w.id,
source = source,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
}
Block.Content.Widget.Layout.LINK -> {
add(
Widget.Link(
id = w.id,
source = source,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
)
}
Block.Content.Widget.Layout.LIST -> {
add(
Widget.List(
id = w.id,
source = source,
limit = widgetContent.limit,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
)
}
Block.Content.Widget.Layout.COMPACT_LIST -> {
add(
Widget.List(
id = w.id,
source = source,
isCompact = true,
limit = widgetContent.limit,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
)
}
Block.Content.Widget.Layout.VIEW -> {
if (source is Widget.Source.Default) {
)
}
else -> {
when (widgetContent.layout) {
Block.Content.Widget.Layout.TREE -> {
add(
Widget.View(
Widget.Tree(
id = w.id,
source = source,
limit = widgetContent.limit,
@ -243,6 +213,56 @@ fun List<Block>.parseWidgets(
)
)
}
Block.Content.Widget.Layout.LINK -> {
add(
Widget.Link(
id = w.id,
source = source,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
)
}
Block.Content.Widget.Layout.LIST -> {
add(
Widget.List(
id = w.id,
source = source,
limit = widgetContent.limit,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
)
}
Block.Content.Widget.Layout.COMPACT_LIST -> {
add(
Widget.List(
id = w.id,
source = source,
isCompact = true,
limit = widgetContent.limit,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
)
}
Block.Content.Widget.Layout.VIEW -> {
if (source is Widget.Source.Default) {
add(
Widget.View(
id = w.id,
source = source,
limit = widgetContent.limit,
config = config,
isAutoCreated = widgetContent.isAutoAdded
)
)
}
}
}
}
}

View file

@ -174,10 +174,13 @@ sealed class WidgetView {
override val isLoading: Boolean = false
}
data object SpaceChat : WidgetView() {
private const val SPACE_CHAT_WIDGET_ID = "bundled-widget.space-chat"
data class SpaceChat(
override val id: Id,
val source: Widget.Source,
val unreadMessageCount: Int = 0,
val unreadMentionCount: Int = 0
) : WidgetView() {
override val isLoading: Boolean = false
override val id: Id = SPACE_CHAT_WIDGET_ID
}
sealed class SpaceWidget: WidgetView() {
@ -200,7 +203,7 @@ sealed class WidgetView {
}
}
object EmptyState : WidgetView() {
data object EmptyState : WidgetView() {
override val id: Id get() = "id.widgets.empty.state"
override val isLoading: Boolean = false
}