Merge pull request #3312 from vector-im/feature/bca/spaces_polish
Spaces various fixes and polish
This commit is contained in:
commit
56d0699bc7
|
@ -33,7 +33,7 @@ interface Space {
|
|||
fun spaceSummary(): RoomSummary?
|
||||
|
||||
suspend fun addChildren(roomId: String,
|
||||
viaServers: List<String>,
|
||||
viaServers: List<String>?,
|
||||
order: String?,
|
||||
autoJoin: Boolean = false,
|
||||
suggested: Boolean? = false)
|
||||
|
|
|
@ -18,19 +18,13 @@ package org.matrix.android.sdk.internal.session.permalinks
|
|||
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkService.Companion.MATRIX_TO_URL_BASE
|
||||
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.room.RoomGetter
|
||||
import java.net.URLEncoder
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
internal class PermalinkFactory @Inject constructor(
|
||||
@UserId
|
||||
private val userId: String,
|
||||
// Use a provider to fix circular Dagger dependency
|
||||
private val roomGetterProvider: Provider<RoomGetter>
|
||||
private val viaParameterFinder: ViaParameterFinder
|
||||
) {
|
||||
|
||||
fun createPermalink(event: Event): String? {
|
||||
|
@ -50,12 +44,12 @@ internal class PermalinkFactory @Inject constructor(
|
|||
return if (roomId.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
MATRIX_TO_URL_BASE + escape(roomId) + computeViaParams(userId, roomId)
|
||||
MATRIX_TO_URL_BASE + escape(roomId) + viaParameterFinder.computeViaParams(userId, roomId)
|
||||
}
|
||||
}
|
||||
|
||||
fun createPermalink(roomId: String, eventId: String): String {
|
||||
return MATRIX_TO_URL_BASE + escape(roomId) + "/" + escape(eventId) + computeViaParams(userId, roomId)
|
||||
return MATRIX_TO_URL_BASE + escape(roomId) + "/" + escape(eventId) + viaParameterFinder.computeViaParams(userId, roomId)
|
||||
}
|
||||
|
||||
fun getLinkedId(url: String): String? {
|
||||
|
@ -66,25 +60,6 @@ internal class PermalinkFactory @Inject constructor(
|
|||
} else null
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the via parameters.
|
||||
* Take up to 3 homeserver domains, taking the most representative one regarding room members and including the
|
||||
* current user one.
|
||||
*/
|
||||
private fun computeViaParams(userId: String, roomId: String): String {
|
||||
val userHomeserver = userId.substringAfter(":")
|
||||
return getUserIdsOfJoinedMembers(roomId)
|
||||
.map { it.substringAfter(":") }
|
||||
.groupBy { it }
|
||||
.mapValues { it.value.size }
|
||||
.toMutableMap()
|
||||
// Ensure the user homeserver will be included
|
||||
.apply { this[userHomeserver] = Int.MAX_VALUE }
|
||||
.let { map -> map.keys.sortedByDescending { map[it] } }
|
||||
.take(3)
|
||||
.joinToString(prefix = "?via=", separator = "&via=") { URLEncoder.encode(it, "utf-8") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape '/' in id, because it is used as a separator
|
||||
*
|
||||
|
@ -104,15 +79,4 @@ internal class PermalinkFactory @Inject constructor(
|
|||
private fun unescape(id: String): String {
|
||||
return id.replace("%2F", "/")
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of userIds of joined members of a room
|
||||
*/
|
||||
private fun getUserIdsOfJoinedMembers(roomId: String): Set<String> {
|
||||
return roomGetterProvider.get().getRoom(roomId)
|
||||
?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
|
||||
?.map { it.userId }
|
||||
.orEmpty()
|
||||
.toSet()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.permalinks
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.room.RoomGetter
|
||||
import java.net.URLEncoder
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
internal class ViaParameterFinder @Inject constructor(
|
||||
@UserId private val userId: String,
|
||||
private val roomGetterProvider: Provider<RoomGetter>
|
||||
) {
|
||||
|
||||
fun computeViaParams(roomId: String, max: Int): List<String> {
|
||||
return computeViaParams(userId, roomId, max)
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the via parameters.
|
||||
* Take up to 3 homeserver domains, taking the most representative one regarding room members and including the
|
||||
* current user one.
|
||||
*/
|
||||
fun computeViaParams(userId: String, roomId: String): String {
|
||||
return computeViaParams(userId, roomId, 3)
|
||||
.joinToString(prefix = "?via=", separator = "&via=") { URLEncoder.encode(it, "utf-8") }
|
||||
}
|
||||
|
||||
fun computeViaParams(userId: String, roomId: String, max: Int): List<String> {
|
||||
val userHomeserver = userId.substringAfter(":")
|
||||
return getUserIdsOfJoinedMembers(roomId)
|
||||
.map { it.substringAfter(":") }
|
||||
.groupBy { it }
|
||||
.mapValues { it.value.size }
|
||||
.toMutableMap()
|
||||
// Ensure the user homeserver will be included
|
||||
.apply { this[userHomeserver] = Int.MAX_VALUE }
|
||||
.let { map -> map.keys.sortedByDescending { map[it] } }
|
||||
.take(max)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of userIds of joined members of a room
|
||||
*/
|
||||
private fun getUserIdsOfJoinedMembers(roomId: String): Set<String> {
|
||||
return roomGetterProvider.get().getRoom(roomId)
|
||||
?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
|
||||
?.map { it.userId }
|
||||
.orEmpty()
|
||||
.toSet()
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.search.SearchResult
|
|||
import org.matrix.android.sdk.api.session.space.Space
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
|
||||
import org.matrix.android.sdk.internal.session.room.state.SendStateTask
|
||||
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
|
||||
import org.matrix.android.sdk.internal.session.search.SearchTask
|
||||
|
@ -66,6 +67,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
|||
private val roomMembersService: MembershipService,
|
||||
private val roomPushRuleService: RoomPushRuleService,
|
||||
private val sendStateTask: SendStateTask,
|
||||
private val viaParameterFinder: ViaParameterFinder,
|
||||
private val searchTask: SearchTask) :
|
||||
Room,
|
||||
TimelineService by timelineService,
|
||||
|
@ -154,6 +156,6 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
|||
|
||||
override fun asSpace(): Space? {
|
||||
if (roomSummary()?.roomType != RoomType.SPACE) return null
|
||||
return DefaultSpace(this, roomSummaryDataSource)
|
||||
return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.room
|
|||
import org.matrix.android.sdk.api.session.crypto.CryptoService
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
|
||||
import org.matrix.android.sdk.internal.session.room.alias.DefaultAliasService
|
||||
import org.matrix.android.sdk.internal.session.room.call.DefaultRoomCallService
|
||||
import org.matrix.android.sdk.internal.session.room.draft.DefaultDraftService
|
||||
|
@ -60,6 +61,7 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService:
|
|||
private val membershipServiceFactory: DefaultMembershipService.Factory,
|
||||
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory,
|
||||
private val sendStateTask: SendStateTask,
|
||||
private val viaParameterFinder: ViaParameterFinder,
|
||||
private val searchTask: SearchTask) :
|
||||
RoomFactory {
|
||||
|
||||
|
@ -83,7 +85,8 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService:
|
|||
roomMembersService = membershipServiceFactory.create(roomId),
|
||||
roomPushRuleService = roomPushRuleServiceFactory.create(roomId),
|
||||
sendStateTask = sendStateTask,
|
||||
searchTask = searchTask
|
||||
searchTask = searchTask,
|
||||
viaParameterFinder = viaParameterFinder
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -364,6 +364,8 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||
realm.where(RoomSummaryEntity::class.java)
|
||||
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, listOf(Membership.JOIN))
|
||||
.notEqualTo(RoomSummaryEntityFields.ROOM_TYPE, RoomType.SPACE)
|
||||
// also we do not count DM in here, because home space will already show them
|
||||
.equalTo(RoomSummaryEntityFields.IS_DIRECT, false)
|
||||
.contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, space.roomId)
|
||||
.findAll().forEach {
|
||||
highlightCount += it.highlightCount
|
||||
|
|
|
@ -24,11 +24,13 @@ import org.matrix.android.sdk.api.session.room.Room
|
|||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.space.Space
|
||||
import org.matrix.android.sdk.api.session.space.model.SpaceChildContent
|
||||
import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
|
||||
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
|
||||
|
||||
internal class DefaultSpace(
|
||||
private val room: Room,
|
||||
private val spaceSummaryDataSource: RoomSummaryDataSource
|
||||
private val spaceSummaryDataSource: RoomSummaryDataSource,
|
||||
private val viaParameterFinder: ViaParameterFinder
|
||||
) : Space {
|
||||
|
||||
override fun asRoom(): Room {
|
||||
|
@ -46,15 +48,17 @@ internal class DefaultSpace(
|
|||
}
|
||||
|
||||
override suspend fun addChildren(roomId: String,
|
||||
viaServers: List<String>,
|
||||
viaServers: List<String>?,
|
||||
order: String?,
|
||||
autoJoin: Boolean,
|
||||
suggested: Boolean?) {
|
||||
// Find best via
|
||||
|
||||
room.sendStateEvent(
|
||||
eventType = EventType.STATE_SPACE_CHILD,
|
||||
stateKey = roomId,
|
||||
body = SpaceChildContent(
|
||||
via = viaServers,
|
||||
via = viaServers ?: viaParameterFinder.computeViaParams(roomId, 3),
|
||||
autoJoin = autoJoin,
|
||||
order = order,
|
||||
suggested = suggested
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package im.vector.app.core.ui.list
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.Gravity
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.ImageViewCompat
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
|
||||
/**
|
||||
* A generic list item with a rounded corner background and an optional icon
|
||||
*/
|
||||
@EpoxyModelClass(layout = R.layout.item_generic_pill_footer)
|
||||
abstract class GenericPillItem : VectorEpoxyModel<GenericPillItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var text: CharSequence? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var style: ItemStyle = ItemStyle.NORMAL_TEXT
|
||||
|
||||
@EpoxyAttribute
|
||||
var itemClickAction: GenericItem.Action? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var centered: Boolean = false
|
||||
|
||||
@EpoxyAttribute
|
||||
@DrawableRes
|
||||
var imageRes: Int? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var tintIcon: Boolean = true
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
holder.textView.setTextOrHide(text)
|
||||
holder.textView.typeface = style.toTypeFace()
|
||||
holder.textView.textSize = style.toTextSize()
|
||||
holder.textView.gravity = if (centered) Gravity.CENTER_HORIZONTAL else Gravity.START
|
||||
|
||||
if (imageRes != null) {
|
||||
holder.imageView.setImageResource(imageRes!!)
|
||||
holder.imageView.isVisible = true
|
||||
} else {
|
||||
holder.imageView.isVisible = false
|
||||
}
|
||||
if (tintIcon) {
|
||||
val iconTintColor = ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_secondary)
|
||||
ImageViewCompat.setImageTintList(holder.imageView, ColorStateList.valueOf(iconTintColor))
|
||||
} else {
|
||||
ImageViewCompat.setImageTintList(holder.imageView, null)
|
||||
}
|
||||
|
||||
holder.view.setOnClickListener {
|
||||
itemClickAction?.perform?.run()
|
||||
}
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val imageView by bind<ImageView>(R.id.itemGenericPillImage)
|
||||
val textView by bind<TextView>(R.id.itemGenericPillText)
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
package im.vector.app.features.grouplist
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
|
@ -35,8 +36,9 @@ import im.vector.app.features.themes.ThemeUtils
|
|||
abstract class HomeSpaceSummaryItem : VectorEpoxyModel<HomeSpaceSummaryItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute var selected: Boolean = false
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: (() -> Unit)? = null
|
||||
@EpoxyAttribute var countState : UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
||||
@EpoxyAttribute var showSeparator: Boolean = false
|
||||
|
||||
override fun getViewType(): Int {
|
||||
// mm.. it's reusing the same layout for basic space item
|
||||
|
@ -56,6 +58,7 @@ abstract class HomeSpaceSummaryItem : VectorEpoxyModel<HomeSpaceSummaryItem.Hold
|
|||
holder.leaveView.isVisible = false
|
||||
|
||||
holder.counterBadgeView.render(countState)
|
||||
holder.bottomSeparator.isVisible = showSeparator
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
|
@ -64,5 +67,6 @@ abstract class HomeSpaceSummaryItem : VectorEpoxyModel<HomeSpaceSummaryItem.Hold
|
|||
val rootView by bind<CheckableConstraintLayout>(R.id.itemGroupLayout)
|
||||
val leaveView by bind<ImageView>(R.id.groupTmpLeave)
|
||||
val counterBadgeView by bind<UnreadCounterBadgeView>(R.id.groupCounterBadge)
|
||||
val bottomSeparator by bind<View>(R.id.groupBottomSeparator)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||
setState {
|
||||
copy(
|
||||
notificationCountCatchup = dmRooms.totalCount + otherRooms.totalCount + roomsInvite + dmInvites,
|
||||
notificationHighlightCatchup = dmRooms.isHighlight || otherRooms.isHighlight,
|
||||
notificationHighlightCatchup = dmRooms.isHighlight || otherRooms.isHighlight || (dmInvites + roomsInvite) > 0,
|
||||
notificationCountPeople = dmRooms.totalCount + dmInvites,
|
||||
notificationHighlightPeople = dmRooms.isHighlight || dmInvites > 0,
|
||||
notificationCountRooms = otherRooms.totalCount + roomsInvite,
|
||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.app.RoomGroupingMethod
|
|||
import im.vector.app.core.platform.EmptyAction
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||
|
@ -52,6 +53,7 @@ data class CountInfo(
|
|||
|
||||
class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initialState: UnreadMessagesState,
|
||||
session: Session,
|
||||
private val vectorPreferences: VectorPreferences,
|
||||
appStateHandler: AppStateHandler)
|
||||
: VectorViewModel<UnreadMessagesState, EmptyAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
|
@ -126,12 +128,24 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
|
|||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
val selectedSpace = appStateHandler.safeActiveSpaceId()
|
||||
val counts = session.getNotificationCountForRooms(
|
||||
|
||||
val inviteCount = session.getRoomSummaries(roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.INVITE)
|
||||
}).size
|
||||
|
||||
val totalCount = session.getNotificationCountForRooms(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
|
||||
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null).takeIf {
|
||||
vectorPreferences.labsSpacesOnlyOrphansInHome()
|
||||
} ?: ActiveSpaceFilter.None
|
||||
}
|
||||
)
|
||||
|
||||
val counts = RoomAggregateNotificationCount(
|
||||
totalCount.notificationCount + inviteCount,
|
||||
totalCount.highlightCount + inviteCount
|
||||
)
|
||||
val rootCounts = session.spaceService().getRootSpaceSummaries()
|
||||
.filter {
|
||||
// filter out current selection
|
||||
|
|
|
@ -832,7 +832,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
session.spaceService().getSpace(spaceId)
|
||||
?.addChildren(
|
||||
state.roomId,
|
||||
listOf(session.sessionParams.homeServerHost ?: ""),
|
||||
null,
|
||||
null,
|
||||
true
|
||||
)
|
||||
|
@ -849,7 +849,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
session.spaceService().getSpace(slashCommandResult.spaceId)
|
||||
?.addChildren(
|
||||
room.roomId,
|
||||
listOf(session.sessionParams.homeServerHost ?: ""),
|
||||
null,
|
||||
null,
|
||||
false
|
||||
)
|
||||
|
|
|
@ -69,12 +69,12 @@ class RoomListViewModel @Inject constructor(
|
|||
* Filter the rooms if they are part of the current space (children and grand children).
|
||||
* If current space is null, will return orphan rooms only
|
||||
*/
|
||||
NORMAL,
|
||||
ORPHANS_IF_SPACE_NULL,
|
||||
/**
|
||||
* Special case when we don't want to discriminate rooms when current space is null.
|
||||
* In this case return all.
|
||||
*/
|
||||
NOT_IF_ALL,
|
||||
ALL_IF_SPACE_NULL,
|
||||
/** Do not filter based on space*/
|
||||
NONE
|
||||
}
|
||||
|
@ -131,7 +131,8 @@ class RoomListViewModel @Inject constructor(
|
|||
},
|
||||
{
|
||||
updatableQuery = it
|
||||
}
|
||||
},
|
||||
vectorPreferences.labsSpacesOnlyOrphansInHome()
|
||||
).buildSections(initialState.displayMode)
|
||||
} else {
|
||||
GroupRoomListSectionBuilder(
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.matrix.android.sdk.api.session.Session
|
|||
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||
import org.matrix.android.sdk.rx.asObservable
|
||||
|
||||
class SpaceRoomListSectionBuilder(
|
||||
|
@ -50,7 +51,8 @@ class SpaceRoomListSectionBuilder(
|
|||
val viewModelScope: CoroutineScope,
|
||||
private val suggestedRoomJoiningState: LiveData<Map<String, Async<Unit>>>,
|
||||
val onDisposable: (Disposable) -> Unit,
|
||||
val onUdpatable: (UpdatableLivePageResult) -> Unit
|
||||
val onUdpatable: (UpdatableLivePageResult) -> Unit,
|
||||
val onlyOrphansInHome: Boolean = false
|
||||
) : RoomListSectionBuilder {
|
||||
|
||||
val pagedListConfig = PagedList.Config.Builder()
|
||||
|
@ -87,22 +89,31 @@ class SpaceRoomListSectionBuilder(
|
|||
}
|
||||
RoomListDisplayMode.NOTIFICATIONS -> {
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.invitations_header,
|
||||
true,
|
||||
RoomListViewModel.SpaceFilterStrategy.NORMAL
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
},
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ALL
|
||||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_rooms,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.NORMAL
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.bottom_action_rooms,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS
|
||||
|
@ -126,10 +137,12 @@ class SpaceRoomListSectionBuilder(
|
|||
|
||||
private fun buildRoomsSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) {
|
||||
addSection(
|
||||
sections, activeSpaceAwareQueries,
|
||||
R.string.invitations_header,
|
||||
true,
|
||||
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
|
@ -140,7 +153,7 @@ class SpaceRoomListSectionBuilder(
|
|||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
|
@ -148,11 +161,15 @@ class SpaceRoomListSectionBuilder(
|
|||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_rooms,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.NORMAL
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.bottom_action_rooms,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
|
@ -160,11 +177,15 @@ class SpaceRoomListSectionBuilder(
|
|||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.low_priority_header,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.NORMAL
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.low_priority_header,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
|
@ -172,11 +193,15 @@ class SpaceRoomListSectionBuilder(
|
|||
}
|
||||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.system_alerts_header,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.NORMAL
|
||||
sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.system_alerts_header,
|
||||
notifyOfLocalEcho = false,
|
||||
spaceFilterStrategy = if (onlyOrphansInHome) {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
|
||||
} else {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
}
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
|
@ -228,11 +253,12 @@ class SpaceRoomListSectionBuilder(
|
|||
}
|
||||
|
||||
private fun buildDmSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) {
|
||||
addSection(sections,
|
||||
activeSpaceAwareQueries,
|
||||
R.string.invitations_header,
|
||||
true,
|
||||
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL
|
||||
addSection(sections = sections,
|
||||
activeSpaceUpdaters = activeSpaceAwareQueries,
|
||||
nameRes = R.string.invitations_header,
|
||||
notifyOfLocalEcho = true,
|
||||
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
|
||||
countRoomAsNotif = true
|
||||
) {
|
||||
it.memberships = listOf(Membership.INVITE)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
|
@ -242,7 +268,7 @@ class SpaceRoomListSectionBuilder(
|
|||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_favourites,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
|
@ -253,7 +279,7 @@ class SpaceRoomListSectionBuilder(
|
|||
activeSpaceAwareQueries,
|
||||
R.string.bottom_action_people_x,
|
||||
false,
|
||||
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
|
||||
) {
|
||||
it.memberships = listOf(Membership.JOIN)
|
||||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
|
@ -266,6 +292,7 @@ class SpaceRoomListSectionBuilder(
|
|||
@StringRes nameRes: Int,
|
||||
notifyOfLocalEcho: Boolean = false,
|
||||
spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE,
|
||||
countRoomAsNotif: Boolean = false,
|
||||
query: (RoomSummaryQueryParams.Builder) -> Unit) {
|
||||
withQueryParams(
|
||||
{ query.invoke(it) },
|
||||
|
@ -277,7 +304,7 @@ class SpaceRoomListSectionBuilder(
|
|||
pagedListConfig
|
||||
).also {
|
||||
when (spaceFilterStrategy) {
|
||||
RoomListViewModel.SpaceFilterStrategy.NORMAL -> {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> {
|
||||
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
|
||||
override fun updateForSpaceId(roomId: String?) {
|
||||
it.updateQuery {
|
||||
|
@ -288,7 +315,7 @@ class SpaceRoomListSectionBuilder(
|
|||
}
|
||||
})
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL -> {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL -> {
|
||||
activeSpaceUpdaters.add(object : RoomListViewModel.ActiveSpaceQueryUpdater {
|
||||
override fun updateForSpaceId(roomId: String?) {
|
||||
if (roomId != null) {
|
||||
|
@ -307,7 +334,7 @@ class SpaceRoomListSectionBuilder(
|
|||
}
|
||||
})
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.NONE -> {
|
||||
RoomListViewModel.SpaceFilterStrategy.NONE -> {
|
||||
// we ignore current space for this one
|
||||
}
|
||||
}
|
||||
|
@ -320,9 +347,15 @@ class SpaceRoomListSectionBuilder(
|
|||
.subscribe {
|
||||
sections.find { it.sectionName == name }
|
||||
?.notificationCount
|
||||
?.postValue(session.getNotificationCountForRooms(
|
||||
roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId())
|
||||
))
|
||||
?.postValue(
|
||||
if (countRoomAsNotif) {
|
||||
RoomAggregateNotificationCount(it.size, it.size)
|
||||
} else {
|
||||
session.getNotificationCountForRooms(
|
||||
roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId())
|
||||
)
|
||||
}
|
||||
)
|
||||
}.also {
|
||||
onDisposable.invoke(it)
|
||||
}
|
||||
|
@ -349,14 +382,16 @@ class SpaceRoomListSectionBuilder(
|
|||
|
||||
internal fun RoomSummaryQueryParams.process(spaceFilter: RoomListViewModel.SpaceFilterStrategy, currentSpace: String?): RoomSummaryQueryParams {
|
||||
return when (spaceFilter) {
|
||||
RoomListViewModel.SpaceFilterStrategy.NORMAL -> {
|
||||
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> {
|
||||
copy(
|
||||
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(currentSpace)
|
||||
)
|
||||
}
|
||||
RoomListViewModel.SpaceFilterStrategy.NOT_IF_ALL -> {
|
||||
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL -> {
|
||||
if (currentSpace == null) {
|
||||
this
|
||||
copy(
|
||||
activeSpaceFilter = ActiveSpaceFilter.None
|
||||
)
|
||||
} else {
|
||||
copy(
|
||||
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(currentSpace)
|
||||
|
|
|
@ -236,10 +236,9 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init
|
|||
if (initialState.parentSpaceId != null) {
|
||||
// add it as a child
|
||||
try {
|
||||
val via = session.sessionParams.homeServerHost?.let { listOf(it) }.orEmpty()
|
||||
session.spaceService()
|
||||
.getSpace(initialState.parentSpaceId)
|
||||
?.addChildren(roomId, viaServers = via, order = null)
|
||||
?.addChildren(roomId, viaServers = null, order = null)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.w(failure, "Failed to add as a child")
|
||||
}
|
||||
|
|
|
@ -151,6 +151,7 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
|||
|
||||
const val SETTINGS_LABS_ALLOW_EXTENDED_LOGS = "SETTINGS_LABS_ALLOW_EXTENDED_LOGS"
|
||||
const val SETTINGS_LABS_USE_RESTRICTED_JOIN_RULE = "SETTINGS_LABS_USE_RESTRICTED_JOIN_RULE"
|
||||
const val SETTINGS_LABS_SPACES_HOME_AS_ORPHAN = "SETTINGS_LABS_SPACES_HOME_AS_ORPHAN"
|
||||
|
||||
private const val SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY = "SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY"
|
||||
private const val SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY = "SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
||||
|
@ -956,6 +957,10 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
|||
return defaultPrefs.getBoolean(SETTINGS_LABS_USE_RESTRICTED_JOIN_RULE, false)
|
||||
}
|
||||
|
||||
fun labsSpacesOnlyOrphansInHome(): Boolean {
|
||||
return defaultPrefs.getBoolean(SETTINGS_LABS_SPACES_HOME_AS_ORPHAN, false)
|
||||
}
|
||||
|
||||
/*
|
||||
* Photo / video picker
|
||||
*/
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
package im.vector.app.features.settings
|
||||
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.preference.VectorSwitchPreference
|
||||
import im.vector.app.features.MainActivity
|
||||
import im.vector.app.features.MainActivityArgs
|
||||
import javax.inject.Inject
|
||||
|
||||
class VectorSettingsLabsFragment @Inject constructor(
|
||||
|
@ -27,6 +30,11 @@ class VectorSettingsLabsFragment @Inject constructor(
|
|||
override val preferenceXmlRes = R.xml.vector_settings_labs
|
||||
|
||||
override fun bindPref() {
|
||||
// Nothing to do
|
||||
findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_LABS_SPACES_HOME_AS_ORPHAN)!!.let { pref ->
|
||||
pref.setOnPreferenceChangeListener { _, _ ->
|
||||
MainActivity.restartApp(requireActivity(), MainActivityArgs(clearCache = false))
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ import im.vector.app.space
|
|||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -43,6 +43,8 @@ class SpaceSummaryController @Inject constructor(
|
|||
var callback: Callback? = null
|
||||
private var viewState: SpaceListViewState? = null
|
||||
|
||||
private val subSpaceComparator: Comparator<SpaceChildInfo> = compareBy<SpaceChildInfo> { it.order }.thenBy { it.childRoomId }
|
||||
|
||||
init {
|
||||
requestModelBuild()
|
||||
}
|
||||
|
@ -132,13 +134,13 @@ class SpaceSummaryController @Inject constructor(
|
|||
}
|
||||
|
||||
rootSpaces
|
||||
?.sortedBy { it.displayName }
|
||||
?.sortedBy { it.roomId }
|
||||
?.forEach { groupSummary ->
|
||||
val isSelected = selected is RoomGroupingMethod.BySpace && groupSummary.roomId == selected.space()?.roomId
|
||||
// does it have children?
|
||||
val subSpaces = groupSummary.spaceChildren?.filter { childInfo ->
|
||||
summaries?.indexOfFirst { it.roomId == childInfo.childRoomId } != -1
|
||||
}
|
||||
}?.sortedWith(subSpaceComparator)
|
||||
val hasChildren = (subSpaces?.size ?: 0) > 0
|
||||
val expanded = expandedStates[groupSummary.roomId] == true
|
||||
|
||||
|
@ -163,24 +165,7 @@ class SpaceSummaryController @Inject constructor(
|
|||
if (hasChildren && expanded) {
|
||||
// it's expanded
|
||||
subSpaces?.forEach { child ->
|
||||
summaries?.firstOrNull { it.roomId == child.childRoomId }?.let { childSum ->
|
||||
val isChildSelected = selected is RoomGroupingMethod.BySpace && childSum.roomId == selected.space()?.roomId
|
||||
spaceSummaryItem {
|
||||
avatarRenderer(avatarRenderer)
|
||||
id(child.childRoomId)
|
||||
hasChildren(false)
|
||||
selected(isChildSelected)
|
||||
matrixItem(MatrixItem.RoomItem(child.childRoomId, child.name, child.avatarUrl))
|
||||
listener { callback?.onSpaceSelected(childSum) }
|
||||
indent(1)
|
||||
countState(
|
||||
UnreadCounterBadgeView.State(
|
||||
groupSummary.notificationCount,
|
||||
groupSummary.highlightCount > 0
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
buildSubSpace(summaries, expandedStates, selected, child, 1, 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +176,45 @@ class SpaceSummaryController @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun buildSubSpace(summaries: List<RoomSummary>?,
|
||||
expandedStates: Map<String, Boolean>,
|
||||
selected: RoomGroupingMethod,
|
||||
info: SpaceChildInfo, currentDepth: Int, maxDepth: Int) {
|
||||
if (currentDepth >= maxDepth) return
|
||||
val childSummary = summaries?.firstOrNull { it.roomId == info.childRoomId } ?: return
|
||||
// does it have children?
|
||||
val subSpaces = childSummary.spaceChildren?.filter { childInfo ->
|
||||
summaries.indexOfFirst { it.roomId == childInfo.childRoomId } != -1
|
||||
}?.sortedWith(subSpaceComparator)
|
||||
val expanded = expandedStates[childSummary.roomId] == true
|
||||
val isSelected = selected is RoomGroupingMethod.BySpace && childSummary.roomId == selected.space()?.roomId
|
||||
|
||||
subSpaceSummaryItem {
|
||||
avatarRenderer(avatarRenderer)
|
||||
id(childSummary.roomId)
|
||||
hasChildren(!subSpaces.isNullOrEmpty())
|
||||
selected(isSelected)
|
||||
expanded(expanded)
|
||||
onMore { callback?.onSpaceSettings(childSummary) }
|
||||
matrixItem(childSummary.toMatrixItem())
|
||||
listener { callback?.onSpaceSelected(childSummary) }
|
||||
toggleExpand { callback?.onToggleExpand(childSummary) }
|
||||
indent(currentDepth)
|
||||
countState(
|
||||
UnreadCounterBadgeView.State(
|
||||
childSummary.notificationCount,
|
||||
childSummary.highlightCount > 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (expanded) {
|
||||
subSpaces?.forEach {
|
||||
buildSubSpace(summaries, expandedStates, selected, it, currentDepth + 1, maxDepth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onSpaceSelected(spaceSummary: RoomSummary?)
|
||||
fun onSpaceInviteSelected(spaceSummary: RoomSummary)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.spaces
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.Space
|
||||
import android.widget.TextView
|
||||
|
@ -37,17 +38,18 @@ import org.matrix.android.sdk.api.util.MatrixItem
|
|||
@EpoxyModelClass(layout = R.layout.item_space)
|
||||
abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute lateinit var matrixItem: MatrixItem
|
||||
@EpoxyAttribute var selected: Boolean = false
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
@EpoxyAttribute var onMore: (() -> Unit)? = null
|
||||
@EpoxyAttribute var toggleExpand: (() -> Unit)? = null
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: (() -> Unit)? = null
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var onMore: (() -> Unit)? = null
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var toggleExpand: (() -> Unit)? = null
|
||||
@EpoxyAttribute var expanded: Boolean = false
|
||||
@EpoxyAttribute var hasChildren: Boolean = false
|
||||
@EpoxyAttribute var indent: Int = 0
|
||||
@EpoxyAttribute var countState : UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
||||
@EpoxyAttribute var description: String? = null
|
||||
@EpoxyAttribute var showSeparator: Boolean = false
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
@ -83,6 +85,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
|
|||
}
|
||||
|
||||
holder.indentSpace.isVisible = indent > 0
|
||||
holder.separator.isVisible = showSeparator
|
||||
|
||||
avatarRenderer.renderSpace(matrixItem, holder.avatarImageView)
|
||||
holder.counterBadgeView.render(countState)
|
||||
|
@ -102,5 +105,6 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
|
|||
val collapseIndicator by bind<ImageView>(R.id.groupChildrenCollapse)
|
||||
val indentSpace by bind<Space>(R.id.indent)
|
||||
val counterBadgeView by bind<UnreadCounterBadgeView>(R.id.groupCounterBadge)
|
||||
val separator by bind<View>(R.id.groupBottomSeparator)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,7 @@ import dagger.assisted.AssistedInject
|
|||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.ui.UiStateRepository
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.group
|
||||
import im.vector.app.space
|
||||
import io.reactivex.Observable
|
||||
|
@ -45,6 +44,7 @@ import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
|||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.rx.asObservable
|
||||
|
@ -54,8 +54,7 @@ import java.util.concurrent.TimeUnit
|
|||
class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: SpaceListViewState,
|
||||
private val appStateHandler: AppStateHandler,
|
||||
private val session: Session,
|
||||
private val stringProvider: StringProvider,
|
||||
private val uiStateRepository: UiStateRepository
|
||||
private val vectorPreferences: VectorPreferences
|
||||
) : VectorViewModel<SpaceListViewState, SpaceListAction, SpaceListViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
|
@ -108,21 +107,34 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||
}
|
||||
}.disposeOnClear()
|
||||
|
||||
// XXX there should be a way to refactor this and share it
|
||||
session.getPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
|
||||
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null).takeIf {
|
||||
vectorPreferences.labsSpacesOnlyOrphansInHome()
|
||||
} ?: ActiveSpaceFilter.None
|
||||
}, sortOrder = RoomSortOrder.NONE
|
||||
).asObservable()
|
||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe {
|
||||
val counts = session.getNotificationCountForRooms(
|
||||
val inviteCount = session.getRoomSummaries(roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.INVITE)
|
||||
}).size
|
||||
|
||||
val totalCount = session.getNotificationCountForRooms(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
|
||||
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null).takeIf {
|
||||
vectorPreferences.labsSpacesOnlyOrphansInHome()
|
||||
} ?: ActiveSpaceFilter.None
|
||||
}
|
||||
)
|
||||
val counts = RoomAggregateNotificationCount(
|
||||
totalCount.notificationCount + inviteCount,
|
||||
totalCount.highlightCount + inviteCount
|
||||
)
|
||||
setState {
|
||||
copy(
|
||||
homeAggregateCount = counts
|
||||
|
@ -217,7 +229,7 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||
.rx()
|
||||
.liveUser(session.myUserId)
|
||||
.map {
|
||||
it.getOrNull()
|
||||
it.getOrNull()
|
||||
},
|
||||
session
|
||||
.rx()
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.spaces
|
||||
|
||||
import android.widget.ImageView
|
||||
import android.widget.Space
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.app.core.platform.CheckableConstraintLayout
|
||||
import im.vector.app.core.utils.DebouncedClickListener
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_sub_space)
|
||||
abstract class SubSpaceSummaryItem : VectorEpoxyModel<SubSpaceSummaryItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute lateinit var matrixItem: MatrixItem
|
||||
@EpoxyAttribute var selected: Boolean = false
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: (() -> Unit)? = null
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var onMore: (() -> Unit)? = null
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var toggleExpand: (() -> Unit)? = null
|
||||
@EpoxyAttribute var expanded: Boolean = false
|
||||
@EpoxyAttribute var hasChildren: Boolean = false
|
||||
@EpoxyAttribute var indent: Int = 0
|
||||
@EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||
holder.groupNameView.text = matrixItem.displayName
|
||||
holder.rootView.isChecked = selected
|
||||
if (onMore != null) {
|
||||
holder.moreView.isVisible = true
|
||||
holder.moreView.setOnClickListener(
|
||||
DebouncedClickListener({ _ ->
|
||||
onMore?.invoke()
|
||||
})
|
||||
)
|
||||
} else {
|
||||
holder.moreView.isVisible = false
|
||||
}
|
||||
|
||||
holder.collapseIndicator.setImageDrawable(
|
||||
ContextCompat.getDrawable(holder.view.context,
|
||||
if (expanded) R.drawable.ic_expand_less else R.drawable.ic_expand_more
|
||||
)
|
||||
)
|
||||
holder.collapseIndicator.setOnClickListener(
|
||||
DebouncedClickListener({ _ ->
|
||||
toggleExpand?.invoke()
|
||||
})
|
||||
)
|
||||
|
||||
holder.collapseIndicator.isVisible = hasChildren
|
||||
|
||||
holder.indentSpace.isVisible = indent > 0
|
||||
holder.indentSpace.updateLayoutParams {
|
||||
width = indent * 30
|
||||
}
|
||||
|
||||
avatarRenderer.renderSpace(matrixItem, holder.avatarImageView)
|
||||
holder.counterBadgeView.render(countState)
|
||||
}
|
||||
|
||||
override fun unbind(holder: Holder) {
|
||||
avatarRenderer.clear(holder.avatarImageView)
|
||||
super.unbind(holder)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
||||
val groupNameView by bind<TextView>(R.id.groupNameView)
|
||||
val rootView by bind<CheckableConstraintLayout>(R.id.itemGroupLayout)
|
||||
val moreView by bind<ImageView>(R.id.groupTmpLeave)
|
||||
val collapseIndicator by bind<ImageView>(R.id.groupChildrenCollapse)
|
||||
val indentSpace by bind<Space>(R.id.indent)
|
||||
val counterBadgeView by bind<UnreadCounterBadgeView>(R.id.groupCounterBadge)
|
||||
}
|
||||
}
|
|
@ -18,13 +18,21 @@ package im.vector.app.features.spaces.explore
|
|||
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.errorWithRetryItem
|
||||
import im.vector.app.core.epoxy.loadingItem
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.ui.list.genericFooterItem
|
||||
import im.vector.app.core.ui.list.genericPillItem
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.list.spaceChildInfoItem
|
||||
import me.gujun.android.span.span
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.failure.MatrixError.Companion.M_UNRECOGNIZED
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
@ -32,13 +40,16 @@ import javax.inject.Inject
|
|||
|
||||
class SpaceDirectoryController @Inject constructor(
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val stringProvider: StringProvider
|
||||
private val stringProvider: StringProvider,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val errorFormatter: ErrorFormatter
|
||||
) : TypedEpoxyController<SpaceDirectoryState>() {
|
||||
|
||||
interface InteractionListener {
|
||||
fun onButtonClick(spaceChildInfo: SpaceChildInfo)
|
||||
fun onSpaceChildClick(spaceChildInfo: SpaceChildInfo)
|
||||
fun onRoomClick(spaceChildInfo: SpaceChildInfo)
|
||||
fun retry()
|
||||
}
|
||||
|
||||
var listener: InteractionListener? = null
|
||||
|
@ -50,6 +61,33 @@ class SpaceDirectoryController @Inject constructor(
|
|||
loadingItem {
|
||||
id("loading")
|
||||
}
|
||||
} else if (results is Fail) {
|
||||
val failure = results.error
|
||||
if (failure is Failure.ServerError && failure.error.code == M_UNRECOGNIZED) {
|
||||
genericPillItem {
|
||||
id("HS no Support")
|
||||
imageRes(R.drawable.error)
|
||||
tintIcon(false)
|
||||
text(
|
||||
span {
|
||||
span(stringProvider.getString(R.string.spaces_no_server_support_title)) {
|
||||
textStyle = "bold"
|
||||
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_primary)
|
||||
}
|
||||
+"\n\n"
|
||||
span(stringProvider.getString(R.string.spaces_no_server_support_description)) {
|
||||
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
errorWithRetryItem {
|
||||
id("api_err")
|
||||
text(errorFormatter.toHumanReadable(failure))
|
||||
listener { listener?.retry() }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val flattenChildInfo = results?.invoke()
|
||||
?.filter {
|
||||
|
|
|
@ -94,6 +94,9 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||
return true
|
||||
}
|
||||
|
||||
override fun retry() {
|
||||
viewModel.handle(SpaceDirectoryViewAction.Retry)
|
||||
}
|
||||
// override fun navigateToRoom(roomId: String) {
|
||||
// viewModel.handle(SpaceDirectoryViewAction.NavigateToRoom(roomId))
|
||||
// }
|
||||
|
|
|
@ -25,4 +25,5 @@ sealed class SpaceDirectoryViewAction : VectorViewModelAction {
|
|||
data class ShowDetails(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction()
|
||||
data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewAction()
|
||||
object HandleBack : SpaceDirectoryViewAction()
|
||||
object Retry : SpaceDirectoryViewAction()
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ import org.matrix.android.sdk.rx.rx
|
|||
import timber.log.Timber
|
||||
|
||||
class SpaceDirectoryViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: SpaceDirectoryState,
|
||||
@Assisted val initialState: SpaceDirectoryState,
|
||||
private val session: Session
|
||||
) : VectorViewModel<SpaceDirectoryState, SpaceDirectoryViewAction, SpaceDirectoryViewEvents>(initialState) {
|
||||
|
||||
|
@ -63,11 +63,21 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
val spaceSum = session.getRoomSummary(initialState.spaceId)
|
||||
setState {
|
||||
copy(
|
||||
childList = spaceSum?.spaceChildren ?: emptyList(),
|
||||
spaceSummaryApiResult = Loading()
|
||||
childList = spaceSum?.spaceChildren ?: emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
refreshFromApi()
|
||||
observeJoinedRooms()
|
||||
observeMembershipChanges()
|
||||
}
|
||||
|
||||
private fun refreshFromApi() {
|
||||
setState {
|
||||
copy(
|
||||
spaceSummaryApiResult = Loading()
|
||||
)
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val query = session.spaceService().querySpaceChildren(initialState.spaceId)
|
||||
|
@ -84,8 +94,6 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
observeJoinedRooms()
|
||||
observeMembershipChanges()
|
||||
}
|
||||
|
||||
private fun observeJoinedRooms() {
|
||||
|
@ -139,13 +147,16 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
is SpaceDirectoryViewAction.NavigateToRoom -> {
|
||||
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToRoom(action.roomId))
|
||||
}
|
||||
is SpaceDirectoryViewAction.ShowDetails -> {
|
||||
is SpaceDirectoryViewAction.ShowDetails -> {
|
||||
// This is temporary for now to at least display something for the space beta
|
||||
// It's not ideal as it's doing some peeking that is not needed.
|
||||
session.permalinkService().createRoomPermalink(action.spaceChildInfo.childRoomId)?.let {
|
||||
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToMxToBottomSheet(it))
|
||||
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToMxToBottomSheet(it))
|
||||
}
|
||||
}
|
||||
SpaceDirectoryViewAction.Retry -> {
|
||||
refreshFromApi()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ package im.vector.app.features.spaces.manage
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.airbnb.epoxy.EpoxyModel
|
||||
import com.airbnb.epoxy.paging.PagedListEpoxyController
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.ui.list.GenericPillItem_
|
||||
import im.vector.app.core.utils.DebouncedClickListener
|
||||
import im.vector.app.core.utils.createUIHandler
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
|
@ -56,6 +58,8 @@ class AddRoomListController @Inject constructor(
|
|||
var listener: Listener? = null
|
||||
var ignoreRooms: List<String>? = null
|
||||
|
||||
var subHeaderText: CharSequence? = null
|
||||
|
||||
var initialLoadOccurred = false
|
||||
|
||||
fun boundaryChange(boundary: ResultBoundaries) {
|
||||
|
@ -100,6 +104,15 @@ class AddRoomListController @Inject constructor(
|
|||
expanded(true)
|
||||
}
|
||||
)
|
||||
if (subHeaderText != null) {
|
||||
add(
|
||||
GenericPillItem_().apply {
|
||||
id("sub_header")
|
||||
text(subHeaderText)
|
||||
imageRes(R.drawable.ic_info)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
super.addModels(filteredModel)
|
||||
if (!initialLoadOccurred) {
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
|
||||
package im.vector.app.features.spaces.manage
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
|
@ -26,12 +23,8 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.airbnb.epoxy.EpoxyViewHolder
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -41,7 +34,6 @@ import im.vector.app.core.extensions.cleanup
|
|||
import im.vector.app.core.platform.OnBackPressed
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentSpaceAddRoomsBinding
|
||||
import im.vector.app.features.home.room.list.RoomCategoryItem_
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -88,6 +80,7 @@ class SpaceAddRoomFragment @Inject constructor(
|
|||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
spaceEpoxyController.subHeaderText = getString(R.string.spaces_feeling_experimental_subspace)
|
||||
viewModel.selectionListLiveData.observe(viewLifecycleOwner) {
|
||||
spaceEpoxyController.selectedItems = it
|
||||
roomEpoxyController.selectedItems = it
|
||||
|
@ -183,36 +176,6 @@ class SpaceAddRoomFragment @Inject constructor(
|
|||
}
|
||||
|
||||
views.roomList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
views.roomList.addItemDecoration(
|
||||
|
||||
object : DividerItemDecoration(context, VERTICAL) {
|
||||
val decorationDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.divider_horizontal)
|
||||
|
||||
override fun getDrawable(): Drawable? {
|
||||
return decorationDrawable
|
||||
}
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
val position = parent.getChildAdapterPosition(view)
|
||||
val vh = parent.findViewHolderForAdapterPosition(position)
|
||||
val nextIsSectionOrFinal = parent.findViewHolderForAdapterPosition(position + 1)?.let {
|
||||
(it as? EpoxyViewHolder)?.model is RoomCategoryItem_
|
||||
} ?: true
|
||||
if (vh == null
|
||||
|| (vh as? EpoxyViewHolder)?.model is RoomCategoryItem_
|
||||
|| nextIsSectionOrFinal
|
||||
) {
|
||||
outRect.setEmpty()
|
||||
} else {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
||||
super.onDraw(c, parent, state)
|
||||
}
|
||||
}
|
||||
)
|
||||
views.roomList.setHasFixedSize(true)
|
||||
|
||||
concatAdapter.addAdapter(roomEpoxyController.adapter)
|
||||
|
|
|
@ -174,7 +174,7 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
|
|||
try {
|
||||
session.spaceService().getSpace(initialState.spaceId)!!.addChildren(
|
||||
roomId = roomId,
|
||||
viaServers = listOf(session.sessionParams.homeServerHost ?: ""),
|
||||
viaServers = null,
|
||||
order = null
|
||||
)
|
||||
completed.add(roomId)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M14.6666,7.9999C14.6666,11.6818 11.6818,14.6666 7.9999,14.6666C4.318,14.6666 1.3333,11.6818 1.3333,7.9999C1.3333,4.318 4.318,1.3333 7.9999,1.3333C11.6818,1.3333 14.6666,4.318 14.6666,7.9999ZM6.3333,7.9999C6.3333,8.4353 6.6115,8.8057 6.9999,8.943V10.9999C6.9999,11.5522 7.4476,11.9999 7.9999,11.9999H8.9999C9.5522,11.9999 9.9999,11.5522 9.9999,10.9999C9.9999,10.4476 9.5522,9.9999 8.9999,9.9999V7.9999C8.9999,7.4476 8.5522,6.9999 7.9999,6.9999H7.3333C6.781,6.9999 6.3333,7.4476 6.3333,7.9999ZM7.9999,6.6666C8.5522,6.6666 8.9999,6.2189 8.9999,5.6666C8.9999,5.1143 8.5522,4.6666 7.9999,4.6666C7.4476,4.6666 6.9999,5.1143 6.9999,5.6666C6.9999,6.2189 7.4476,6.6666 7.9999,6.6666Z"
|
||||
android:fillColor="#737D8C"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
|
@ -10,7 +10,7 @@
|
|||
android:id="@+id/roomList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?riotx_header_panel_background"
|
||||
android:background="?riotx_background"
|
||||
android:overScrollMode="always"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:listitem="@layout/item_room_to_add_in_space" />
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:background="@drawable/rounded_rect_shape_8"
|
||||
android:backgroundTint="?riotx_reaction_background_off"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/itemGenericPillImage"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_info"
|
||||
app:tint="?riotx_text_secondary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemGenericPillText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:gravity="start"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,132 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<im.vector.app.core.platform.CheckableConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/itemGroupLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/bg_space_item"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
|
||||
<Space
|
||||
android:id="@+id/indent"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupAvatarImageView"
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="26dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:contentDescription="@string/avatar"
|
||||
android:duplicateParentState="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/indent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||
android:id="@+id/groupCounterBadge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:gravity="center"
|
||||
android:minWidth="16dp"
|
||||
android:minHeight="16dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="10sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintCircle="@+id/groupAvatarImageView"
|
||||
app:layout_constraintCircleAngle="45"
|
||||
app:layout_constraintCircleRadius="14dp"
|
||||
tools:background="@drawable/bg_unread_highlight"
|
||||
tools:text="147"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/groupNameView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/groupChildrenCollapse"
|
||||
app:layout_constraintStart_toEndOf="@+id/groupAvatarImageView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupChildrenCollapse"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_expand_less_white"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/groupTmpLeave"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?riotx_text_primary"
|
||||
tools:ignore="MissingPrefix"
|
||||
tools:src="@drawable/ic_expand_more_white"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupTmpLeave"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:importantForAccessibility="no"
|
||||
android:padding="4dp"
|
||||
android:src="@drawable/ic_more_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/groupAvatarChevron"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?riotx_text_secondary" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupAvatarChevron"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="21dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_arrow_right"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/groupBottomSeparator"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?riotx_text_primary"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
<!-- <View-->
|
||||
<!-- android:id="@+id/groupBottomSeparator"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="1dp"-->
|
||||
<!-- android:background="?riotx_header_panel_border_mobile"-->
|
||||
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||
<!-- app:layout_constraintStart_toStartOf="parent" />-->
|
||||
|
||||
</im.vector.app.core.platform.CheckableConstraintLayout>
|
|
@ -3362,4 +3362,10 @@
|
|||
<string name="space_mark_as_suggested">Mark as suggested</string>
|
||||
<string name="space_mark_as_not_suggested">Mark as not suggested</string>
|
||||
<string name="space_manage_rooms_and_spaces">Manage rooms and spaces</string>
|
||||
|
||||
|
||||
<string name="labs_space_show_orphan_in_home">Experimental Space - Only show orphans in Home</string>
|
||||
<string name="spaces_feeling_experimental_subspace">Feeling experimental?\nYou can add existing spaces to a space.</string>
|
||||
<string name="spaces_no_server_support_title">It looks like your homeserver does not support Spaces yet</string>
|
||||
<string name="spaces_no_server_support_description">Please contact your homserver admin for further information</string>
|
||||
</resources>
|
||||
|
|
|
@ -52,4 +52,9 @@
|
|||
android:summary="@string/labs_use_restricted_join_rule_desc"/>
|
||||
<!--</im.vector.app.core.preference.VectorPreferenceCategory>-->
|
||||
|
||||
<im.vector.app.core.preference.VectorSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="SETTINGS_LABS_SPACES_HOME_AS_ORPHAN"
|
||||
android:title="@string/labs_space_show_orphan_in_home"/>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in New Issue