SpaceSummaryController.kt 9.67 KB
Newer Older
Valere's avatar
Valere committed
1
/*
2
 * Copyright (c) 2021 New Vector Ltd
Valere's avatar
Valere committed
3
4
5
6
7
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
Valere's avatar
Valere committed
9
10
11
12
13
14
15
16
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

17
package im.vector.app.features.spaces
Valere's avatar
Valere committed
18

Valere's avatar
Valere committed
19
import android.view.View
Valere's avatar
Valere committed
20
import com.airbnb.epoxy.EpoxyController
21
import im.vector.app.R
22
import im.vector.app.RoomGroupingMethod
Valere's avatar
Valere committed
23
import im.vector.app.core.resources.ColorProvider
Valere's avatar
Valere committed
24
import im.vector.app.core.resources.StringProvider
25
26
import im.vector.app.core.ui.list.genericFooterItem
import im.vector.app.core.ui.list.genericItemHeader
27
import im.vector.app.features.grouplist.groupSummaryItem
28
import im.vector.app.features.grouplist.homeSpaceSummaryItem
Valere's avatar
Valere committed
29
import im.vector.app.features.home.AvatarRenderer
Valere's avatar
Valere committed
30
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
31
32
33
import im.vector.app.group
import im.vector.app.space
import org.matrix.android.sdk.api.session.group.model.GroupSummary
34
import org.matrix.android.sdk.api.session.room.model.Membership
Valere's avatar
Valere committed
35
import org.matrix.android.sdk.api.session.room.model.RoomSummary
36
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
Valere's avatar
Valere committed
37
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
Valere's avatar
Valere committed
38
39
40
41
42
import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject

class SpaceSummaryController @Inject constructor(
        private val avatarRenderer: AvatarRenderer,
Valere's avatar
Valere committed
43
        private val colorProvider: ColorProvider,
Valere's avatar
Valere committed
44
45
46
47
48
        private val stringProvider: StringProvider) : EpoxyController() {

    var callback: Callback? = null
    private var viewState: SpaceListViewState? = null

Valere's avatar
Valere committed
49
50
    private val subSpaceComparator: Comparator<SpaceChildInfo> = compareBy<SpaceChildInfo> { it.order }.thenBy { it.childRoomId }

Valere's avatar
Valere committed
51
52
53
54
55
56
57
58
59
60
61
    init {
        requestModelBuild()
    }

    fun update(viewState: SpaceListViewState) {
        this.viewState = viewState
        requestModelBuild()
    }

    override fun buildModels() {
        val nonNullViewState = viewState ?: return
62
63
        buildGroupModels(
                nonNullViewState.asyncSpaces(),
64
                nonNullViewState.selectedGroupingMethod,
65
                nonNullViewState.rootSpaces,
Valere's avatar
Valere committed
66
67
                nonNullViewState.expandedStates,
                nonNullViewState.homeAggregateCount)
68
69
70
71
72
73
74
75
76
77

        if (!nonNullViewState.legacyGroups.isNullOrEmpty()) {
            genericFooterItem {
                id("legacy_space")
                text(" ")
            }

            genericItemHeader {
                id("legacy_groups")
                text(stringProvider.getString(R.string.groups_header))
Valere's avatar
Valere committed
78
                textColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
            }

            // add home for communities
            nonNullViewState.myMxItem.invoke()?.let { mxItem ->
                groupSummaryItem {
                    avatarRenderer(avatarRenderer)
                    id("all_communities")
                    matrixItem(mxItem.copy(displayName = stringProvider.getString(R.string.group_all_communities)))
                    selected(nonNullViewState.selectedGroupingMethod is RoomGroupingMethod.ByLegacyGroup
                            && nonNullViewState.selectedGroupingMethod.group() == null)
                    listener { callback?.onGroupSelected(null) }
                }
            }

            nonNullViewState.legacyGroups.forEach { groupSummary ->
                groupSummaryItem {
                    avatarRenderer(avatarRenderer)
                    id(groupSummary.groupId)
                    matrixItem(groupSummary.toMatrixItem())
                    selected(nonNullViewState.selectedGroupingMethod is RoomGroupingMethod.ByLegacyGroup
                            && nonNullViewState.selectedGroupingMethod.group()?.groupId == groupSummary.groupId)
                    listener { callback?.onGroupSelected(groupSummary) }
                }
            }
        }
Valere's avatar
Valere committed
104
105
    }

106
    private fun buildGroupModels(summaries: List<RoomSummary>?,
107
                                 selected: RoomGroupingMethod,
108
                                 rootSpaces: List<RoomSummary>?,
Valere's avatar
Valere committed
109
110
                                 expandedStates: Map<String, Boolean>,
                                 homeCount: RoomAggregateNotificationCount) {
Valere's avatar
Valere committed
111
112
113
114
115
116
        spaceBetaHeaderItem {
            id("beta_header")
            clickAction(View.OnClickListener {
                callback?.sendFeedBack()
            })
        }
117

118
119
        // show invites on top

120
121
122
123
124
125
126
127
128
129
        summaries?.filter { it.membership == Membership.INVITE }
                ?.forEach {
                    spaceSummaryItem {
                        avatarRenderer(avatarRenderer)
                        id(it.roomId)
                        matrixItem(it.toMatrixItem())
                        countState(UnreadCounterBadgeView.State(1, true))
                        selected(false)
                        description(stringProvider.getString(R.string.you_are_invited))
                        listener { callback?.onSpaceInviteSelected(it) }
130
                    }
Valere's avatar
Valere committed
131
                }
132

133
134
        homeSpaceSummaryItem {
            id("space_home")
Valere's avatar
Valere committed
135
            selected(selected is RoomGroupingMethod.BySpace && selected.space() == null)
136
137
138
            countState(UnreadCounterBadgeView.State(homeCount.totalCount, homeCount.isHighlight))
            listener { callback?.onSpaceSelected(null) }
        }
139
140

        rootSpaces
Valere's avatar
Valere committed
141
                ?.sortedBy { it.roomId }
142
                ?.forEach { groupSummary ->
143
                    val isSelected = selected is RoomGroupingMethod.BySpace && groupSummary.roomId == selected.space()?.roomId
144
                    // does it have children?
Valere's avatar
Valere committed
145
                    val subSpaces = groupSummary.spaceChildren?.filter { childInfo ->
146
                        summaries?.indexOfFirst { it.roomId == childInfo.childRoomId } != -1
Valere's avatar
Valere committed
147
                    }?.sortedWith(subSpaceComparator)
148
149
150
151
152
153
154
155
156
157
158
159
160
                    val hasChildren = (subSpaces?.size ?: 0) > 0
                    val expanded = expandedStates[groupSummary.roomId] == true

                    spaceSummaryItem {
                        avatarRenderer(avatarRenderer)
                        id(groupSummary.roomId)
                        hasChildren(hasChildren)
                        expanded(expanded)
                        matrixItem(groupSummary.toMatrixItem())
                        selected(isSelected)
                        onMore { callback?.onSpaceSettings(groupSummary) }
                        listener { callback?.onSpaceSelected(groupSummary) }
                        toggleExpand { callback?.onToggleExpand(groupSummary) }
Valere's avatar
Valere committed
161
162
163
164
165
166
                        countState(
                                UnreadCounterBadgeView.State(
                                        groupSummary.notificationCount,
                                        groupSummary.highlightCount > 0
                                )
                        )
167
168
169
170
                    }

                    if (hasChildren && expanded) {
                        // it's expanded
Valere's avatar
Valere committed
171
                        subSpaces?.forEach { child ->
172
                            buildSubSpace(summaries, expandedStates, selected, child, 1, 3)
Valere's avatar
Valere committed
173
                        }
174
175
                    }
                }
Valere's avatar
Valere committed
176

177
        spaceAddItem {
Valere's avatar
Valere committed
178
            id("create")
179
            listener { callback?.onAddSpaceSelected() }
Valere's avatar
Valere committed
180
        }
Valere's avatar
Valere committed
181
182
    }

183
184
185
    private fun buildSubSpace(summaries: List<RoomSummary>?,
                              expandedStates: Map<String, Boolean>,
                              selected: RoomGroupingMethod,
Valere's avatar
Valere committed
186
                              info: SpaceChildInfo, currentDepth: Int, maxDepth: Int) {
187
        if (currentDepth >= maxDepth) return
Valere's avatar
Valere committed
188
        val childSummary = summaries?.firstOrNull { it.roomId == info.childRoomId } ?: return
189
        // does it have children?
Valere's avatar
Valere committed
190
        val subSpaces = childSummary.spaceChildren?.filter { childInfo ->
191
            summaries.indexOfFirst { it.roomId == childInfo.childRoomId } != -1
Valere's avatar
Valere committed
192
        }?.sortedWith(subSpaceComparator)
Valere's avatar
Valere committed
193
194
        val expanded = expandedStates[childSummary.roomId] == true
        val isSelected = selected is RoomGroupingMethod.BySpace && childSummary.roomId == selected.space()?.roomId
195
196
197

        subSpaceSummaryItem {
            avatarRenderer(avatarRenderer)
Valere's avatar
Valere committed
198
            id(childSummary.roomId)
199
200
201
            hasChildren(!subSpaces.isNullOrEmpty())
            selected(isSelected)
            expanded(expanded)
Valere's avatar
Valere committed
202
203
204
205
            onMore { callback?.onSpaceSettings(childSummary) }
            matrixItem(childSummary.toMatrixItem())
            listener { callback?.onSpaceSelected(childSummary) }
            toggleExpand { callback?.onToggleExpand(childSummary) }
206
207
208
            indent(currentDepth)
            countState(
                    UnreadCounterBadgeView.State(
Valere's avatar
Valere committed
209
210
                            childSummary.notificationCount,
                            childSummary.highlightCount > 0
211
212
213
214
215
216
217
218
219
220
221
                    )
            )
        }

        if (expanded) {
            subSpaces?.forEach {
                buildSubSpace(summaries, expandedStates, selected, it, currentDepth + 1, maxDepth)
            }
        }
    }

Valere's avatar
Valere committed
222
    interface Callback {
223
        fun onSpaceSelected(spaceSummary: RoomSummary?)
224
        fun onSpaceInviteSelected(spaceSummary: RoomSummary)
Valere's avatar
Valere committed
225
        fun onSpaceSettings(spaceSummary: RoomSummary)
226
        fun onToggleExpand(spaceSummary: RoomSummary)
Valere's avatar
Valere committed
227
        fun onAddSpaceSelected()
228
        fun onGroupSelected(groupSummary: GroupSummary?)
Valere's avatar
Valere committed
229
        fun sendFeedBack()
Valere's avatar
Valere committed
230
231
    }
}