mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 09:25:49 +03:00
Add Rooms to space
This commit is contained in:
parent
5a84456f1f
commit
8146d8ab1e
35 changed files with 1244 additions and 16 deletions
|
@ -19,4 +19,5 @@ package org.matrix.android.sdk.api.query
|
||||||
sealed class ActiveSpaceFilter {
|
sealed class ActiveSpaceFilter {
|
||||||
object None : ActiveSpaceFilter()
|
object None : ActiveSpaceFilter()
|
||||||
data class ActiveSpace(val currentSpaceId: String?) : ActiveSpaceFilter()
|
data class ActiveSpace(val currentSpaceId: String?) : ActiveSpaceFilter()
|
||||||
|
data class ExcludeSpace(val spaceId: String) : ActiveSpaceFilter()
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,13 +178,15 @@ interface RoomService {
|
||||||
* TODO Doc
|
* TODO Doc
|
||||||
*/
|
*/
|
||||||
fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
|
fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
|
||||||
pagedListConfig: PagedList.Config = defaultPagedListConfig): LiveData<PagedList<RoomSummary>>
|
pagedListConfig: PagedList.Config = defaultPagedListConfig,
|
||||||
|
sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData<PagedList<RoomSummary>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Doc
|
* TODO Doc
|
||||||
*/
|
*/
|
||||||
fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
|
fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
|
||||||
pagedListConfig: PagedList.Config = defaultPagedListConfig): UpdatableLivePageResult
|
pagedListConfig: PagedList.Config = defaultPagedListConfig,
|
||||||
|
sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): UpdatableLivePageResult
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Doc
|
* TODO Doc
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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.api.session.room
|
||||||
|
|
||||||
|
enum class RoomSortOrder {
|
||||||
|
NAME,
|
||||||
|
ACTIVITY,
|
||||||
|
NONE
|
||||||
|
}
|
|
@ -57,7 +57,8 @@ data class RoomSummary constructor(
|
||||||
val hasFailedSending: Boolean = false,
|
val hasFailedSending: Boolean = false,
|
||||||
val roomType: String? = null,
|
val roomType: String? = null,
|
||||||
val spaceParents: List<SpaceParentInfo>? = null,
|
val spaceParents: List<SpaceParentInfo>? = null,
|
||||||
val children: List<SpaceChildInfo>? = null
|
val children: List<SpaceChildInfo>? = null,
|
||||||
|
val flattenParentIds: List<String> = emptyList()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val isVersioned: Boolean
|
val isVersioned: Boolean
|
||||||
|
|
|
@ -89,7 +89,8 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
|
||||||
viaServers = it.viaServers.toList(),
|
viaServers = it.viaServers.toList(),
|
||||||
parentRoomId = roomSummaryEntity.roomId
|
parentRoomId = roomSummaryEntity.roomId
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
|
flattenParentIds = roomSummaryEntity.flattenParentIds?.split("|") ?: emptyList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.zhuinden.monarchy.Monarchy
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.room.Room
|
import org.matrix.android.sdk.api.session.room.Room
|
||||||
import org.matrix.android.sdk.api.session.room.RoomService
|
import org.matrix.android.sdk.api.session.room.RoomService
|
||||||
|
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||||
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
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.UpdatableLivePageResult
|
||||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
|
@ -91,14 +92,14 @@ internal class DefaultRoomService @Inject constructor(
|
||||||
return roomSummaryDataSource.getRoomSummariesLive(queryParams)
|
return roomSummaryDataSource.getRoomSummariesLive(queryParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, pagedListConfig: PagedList.Config)
|
override fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, pagedListConfig: PagedList.Config, sortOrder: RoomSortOrder)
|
||||||
: LiveData<PagedList<RoomSummary>> {
|
: LiveData<PagedList<RoomSummary>> {
|
||||||
return roomSummaryDataSource.getSortedPagedRoomSummariesLive(queryParams, pagedListConfig)
|
return roomSummaryDataSource.getSortedPagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, pagedListConfig: PagedList.Config)
|
override fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, pagedListConfig: PagedList.Config, sortOrder: RoomSortOrder)
|
||||||
: UpdatableLivePageResult {
|
: UpdatableLivePageResult {
|
||||||
return roomSummaryDataSource.getUpdatablePagedRoomSummariesLive(queryParams, pagedListConfig)
|
return roomSummaryDataSource.getUpdatablePagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNotificationCountForRooms(queryParams: RoomSummaryQueryParams): RoomAggregateNotificationCount {
|
override fun getNotificationCountForRooms(queryParams: RoomSummaryQueryParams): RoomAggregateNotificationCount {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import io.realm.Sort
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||||
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||||
|
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||||
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
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.UpdatableLivePageResult
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
@ -162,10 +163,22 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSortedPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
|
fun getSortedPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
|
||||||
pagedListConfig: PagedList.Config): LiveData<PagedList<RoomSummary>> {
|
pagedListConfig: PagedList.Config,
|
||||||
|
sortOrder: RoomSortOrder): LiveData<PagedList<RoomSummary>> {
|
||||||
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
|
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
|
||||||
roomSummariesQuery(realm, queryParams)
|
roomSummariesQuery(realm, queryParams)
|
||||||
.sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
|
.apply {
|
||||||
|
when (sortOrder) {
|
||||||
|
RoomSortOrder.NAME -> {
|
||||||
|
sort(RoomSummaryEntityFields.DISPLAY_NAME, Sort.ASCENDING)
|
||||||
|
}
|
||||||
|
RoomSortOrder.ACTIVITY -> {
|
||||||
|
sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
|
||||||
|
}
|
||||||
|
RoomSortOrder.NONE -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val dataSourceFactory = realmDataSourceFactory.map {
|
val dataSourceFactory = realmDataSourceFactory.map {
|
||||||
roomSummaryMapper.map(it)
|
roomSummaryMapper.map(it)
|
||||||
|
@ -177,10 +190,22 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUpdatablePagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
|
fun getUpdatablePagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
|
||||||
pagedListConfig: PagedList.Config): UpdatableLivePageResult {
|
pagedListConfig: PagedList.Config,
|
||||||
|
sortOrder: RoomSortOrder): UpdatableLivePageResult {
|
||||||
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
|
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
|
||||||
roomSummariesQuery(realm, queryParams)
|
roomSummariesQuery(realm, queryParams)
|
||||||
.sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
|
.apply {
|
||||||
|
when (sortOrder) {
|
||||||
|
RoomSortOrder.NAME -> {
|
||||||
|
sort(RoomSummaryEntityFields.DISPLAY_NAME, Sort.ASCENDING)
|
||||||
|
}
|
||||||
|
RoomSortOrder.ACTIVITY -> {
|
||||||
|
sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
|
||||||
|
}
|
||||||
|
RoomSortOrder.NONE -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val dataSourceFactory = realmDataSourceFactory.map {
|
val dataSourceFactory = realmDataSourceFactory.map {
|
||||||
roomSummaryMapper.map(it)
|
roomSummaryMapper.map(it)
|
||||||
|
@ -197,7 +222,18 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
|
||||||
override fun updateQuery(builder: (RoomSummaryQueryParams) -> RoomSummaryQueryParams) {
|
override fun updateQuery(builder: (RoomSummaryQueryParams) -> RoomSummaryQueryParams) {
|
||||||
realmDataSourceFactory.updateQuery {
|
realmDataSourceFactory.updateQuery {
|
||||||
roomSummariesQuery(it, builder.invoke(queryParams))
|
roomSummariesQuery(it, builder.invoke(queryParams))
|
||||||
.sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
|
.apply {
|
||||||
|
when (sortOrder) {
|
||||||
|
RoomSortOrder.NAME -> {
|
||||||
|
sort(RoomSummaryEntityFields.DISPLAY_NAME, Sort.ASCENDING)
|
||||||
|
}
|
||||||
|
RoomSortOrder.ACTIVITY -> {
|
||||||
|
sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
|
||||||
|
}
|
||||||
|
RoomSortOrder.NONE -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,6 +308,9 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
|
||||||
query.contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.activeSpaceId.currentSpaceId)
|
query.contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.activeSpaceId.currentSpaceId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is ActiveSpaceFilter.ExcludeSpace -> {
|
||||||
|
query.not().contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.activeSpaceId.spaceId)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// nop
|
// nop
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,8 @@ internal class DefaultSpaceService @Inject constructor(
|
||||||
avatarUrl = spaceDesc?.avatarUrl ?: "",
|
avatarUrl = spaceDesc?.avatarUrl ?: "",
|
||||||
encryptionEventTs = null,
|
encryptionEventTs = null,
|
||||||
typingUsers = emptyList(),
|
typingUsers = emptyList(),
|
||||||
isEncrypted = false
|
isEncrypted = false,
|
||||||
|
flattenParentIds = emptyList()
|
||||||
),
|
),
|
||||||
second = response.rooms
|
second = response.rooms
|
||||||
?.filter { it.roomId != spaceId }
|
?.filter { it.roomId != spaceId }
|
||||||
|
|
|
@ -161,7 +161,7 @@ Formatter\.formatShortFileSize===1
|
||||||
# android\.text\.TextUtils
|
# android\.text\.TextUtils
|
||||||
|
|
||||||
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
|
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
|
||||||
enum class===98
|
enum class===99
|
||||||
|
|
||||||
### Do not import temporary legacy classes
|
### Do not import temporary legacy classes
|
||||||
import org.matrix.android.sdk.internal.legacy.riot===3
|
import org.matrix.android.sdk.internal.legacy.riot===3
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"message": "William Shakespeare (bapt. 26 April 1564 – 23 April 1616) was an English poet, playwright and actor, widely regarded as the greatest writer in the English language and the world's greatest dramatist. He is often called England's national poet and the \"Bard of Avon\". His extant works, including collaborations, consist of approximately 39 plays, 154 sonnets, two long narrative poems, and a few other verses, some of uncertain authorship. His plays have been translated into every major living language and are performed more often than those of any other playwright.\n\nShakespeare was born and raised in Stratford-upon-Avon, Warwickshire. At the age of 18, he married Anne Hathaway, with whom he had three children: Susanna and twins Hamnet and Judith. Sometime between 1585 and 1592, he began a successful career in London as an actor, writer, and part-owner of a playing company called the Lord Chamberlain's Men, later known as the King's Men. At age 49 (around 1613), he appears to have retired to Stratford, where he died three years later. Few records of Shakespeare's private life survive; this has stimulated considerable speculation about such matters as his physical appearance, his sexuality, his religious beliefs, and whether the works attributed to him were written by others. Such theories are often criticised for failing to adequately note that few records survive of most commoners of the period.\n\nShakespeare produced most of his known works between 1589 and 1613. His early plays were primarily comedies and histories and are regarded as some of the best work produced in these genres. Until about 1608, he wrote mainly tragedies, among them Hamlet, Othello, King Lear, and Macbeth, all considered to be among the finest works in the English language. In the last phase of his life, he wrote tragicomedies (also known as romances) and collaborated with other playwrights.\n\nMany of Shakespeare's plays were published in editions of varying quality and accuracy in his lifetime. However, in 1623, two fellow actors and friends of Shakespeare's, John Heminges and Henry Condell, published a more definitive text known as the First Folio, a posthumous collected edition of Shakespeare's dramatic works that included all but two of his plays. The volume was prefaced with a poem by Ben Jonson, in which Jonson presciently hails Shakespeare in a now-famous quote as \"not of an age, but for all time\".\n\nThroughout the 20th and 21st centuries, Shakespeare's works have been continually adapted and rediscovered by new movements in scholarship and performance. His plays remain popular and are studied, performed, and reinterpreted through various cultural and political contexts around the world.",
|
"message": "William Shakespeare (bapt. 26 April 1564 – 23 April 1616) was an English poet, playwright and actor, widely regarded as the greatest writer in the English language and the world's greatest dramatist. He is often called England's national poet and the \"Bard of Avon\". His extant works, including collaborations, consist of approximately 39 plays, 154 sonnets, two long narrative poems, and a few other verses, some of uncertain authorship. His plays have been translated into every major living language and are performed more often than those of any other playwright.\n\nShakespeare was born and raised in Stratford-upon-Avon, Warwickshire. At the age of 18, he married Anne Hathaway, with whom he had three children: Susanna and twins Hamnet and Judith. Sometime between 1585 and 1592, he began a successful career in London as an actor, writer, and part-owner of a playing company called the Lord Chamberlain's Men, later known as the King's Men. At age 49 (around 1613), he appears to have retired to Stratford, where he died three years later. Few records of Shakespeare's private life survive; this has stimulated considerable speculation about such matters as his physical appearance, his sexuality, his religious beliefs, and whether the works attributed to him were written by others. Such theories are often criticised for failing to adequately note that few records survive of most commoners of the period.\n\nShakespeare produced most of his known works between 1589 and 1613. His early plays were primarily comedies and histories and are regarded as some of the best work produced in these genres. Until about 1608, he wrote mainly tragedies, among them Hamlet, Othello, King Lear, and Macbeth, all considered to be among the finest works in the English language. In the last phase of his life, he wrote tragicomedies (also known as romances) and collaborated with other playwrights.\n\nMany of Shakespeare's plays were published in editions of varying quality and accuracy in his lifetime. However, in 1623, two fellow actors and friends of Shakespeare's, John Heminges and Henry Condell, published a more definitive text known as the First Folio, a posthumous collected edition of Shakespeare's dramatic works that included all but two of his plays. The volume was prefaced with a poem by Ben Jonson, in which Jonson presciently hails Shakespeare in a now-famous quote as \"not of an age, but for all time\".\n\nThroughout the 20th and 21st centuries, Shakespeare's works have been continually adapted and rediscovered by new movements in scholarship and performance. His plays remain popular and are studied, performed, and reinterpreted through various cultural and political contexts around the world.",
|
||||||
"roomName": "Matrix HQ",
|
"roomName": "Matrix HQ",
|
||||||
"roomAlias": "#matrix:matrix.org",
|
"roomAlias": "#matrix:matrix.org",
|
||||||
|
"spaceName": "Runner's world",
|
||||||
"roomTopic": "Welcome to Matrix HQ! Here is the rest of the room topic, with a https://www.example.org url and a phone number: 0102030405 which should not be clickable."
|
"roomTopic": "Welcome to Matrix HQ! Here is the rest of the room topic, with a https://www.example.org url and a phone number: 0102030405 which should not be clickable."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -14,6 +15,7 @@
|
||||||
"message": "Hello!",
|
"message": "Hello!",
|
||||||
"roomName": "Room name very loooooooong with some details",
|
"roomName": "Room name very loooooooong with some details",
|
||||||
"roomAlias": "#matrix:matrix.org",
|
"roomAlias": "#matrix:matrix.org",
|
||||||
|
"spaceName": "Matrix Org",
|
||||||
"roomTopic": "Room topic very loooooooong with some details"
|
"roomTopic": "Room topic very loooooooong with some details"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -22,6 +24,7 @@
|
||||||
"message": "How are you?",
|
"message": "How are you?",
|
||||||
"roomName": "Room name very loooooooong with some details",
|
"roomName": "Room name very loooooooong with some details",
|
||||||
"roomAlias": "#matrix:matrix.org",
|
"roomAlias": "#matrix:matrix.org",
|
||||||
|
"spaceName": "Rennes",
|
||||||
"roomTopic": "Room topic very loooooooong with some details"
|
"roomTopic": "Room topic very loooooooong with some details"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -30,6 +33,7 @@
|
||||||
"message": "Great weather today!",
|
"message": "Great weather today!",
|
||||||
"roomName": "Room name very loooooooong with some details",
|
"roomName": "Room name very loooooooong with some details",
|
||||||
"roomAlias": "#matrix:matrix.org",
|
"roomAlias": "#matrix:matrix.org",
|
||||||
|
"spaceName": "Est London",
|
||||||
"roomTopic": "Room topic very loooooooong with some details"
|
"roomTopic": "Room topic very loooooooong with some details"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -38,6 +42,7 @@
|
||||||
"message": "Let's do a picnic",
|
"message": "Let's do a picnic",
|
||||||
"roomName": "Room name very loooooooong with some details",
|
"roomName": "Room name very loooooooong with some details",
|
||||||
"roomAlias": "#matrix:matrix.org",
|
"roomAlias": "#matrix:matrix.org",
|
||||||
|
"spaceName": "Element HQ",
|
||||||
"roomTopic": "Room topic very loooooooong with some details"
|
"roomTopic": "Room topic very loooooooong with some details"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -46,6 +51,7 @@
|
||||||
"message": "Yes, great idea",
|
"message": "Yes, great idea",
|
||||||
"roomName": "Room name very loooooooong with some details",
|
"roomName": "Room name very loooooooong with some details",
|
||||||
"roomAlias": "#matrix:matrix.org",
|
"roomAlias": "#matrix:matrix.org",
|
||||||
|
"spaceName": "My Company",
|
||||||
"roomTopic": "Room topic very loooooooong with some details"
|
"roomTopic": "Room topic very loooooooong with some details"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -275,6 +275,7 @@
|
||||||
<activity android:name=".features.spaces.SpacePreviewActivity" />
|
<activity android:name=".features.spaces.SpacePreviewActivity" />
|
||||||
<activity android:name=".features.spaces.SpaceExploreActivity" />
|
<activity android:name=".features.spaces.SpaceExploreActivity" />
|
||||||
<activity android:name=".features.spaces.SpaceCreationActivity" />
|
<activity android:name=".features.spaces.SpaceCreationActivity" />
|
||||||
|
<activity android:name=".features.spaces.manage.SpaceManageActivity" />
|
||||||
<!-- Services -->
|
<!-- Services -->
|
||||||
|
|
||||||
<service
|
<service
|
||||||
|
|
|
@ -125,6 +125,7 @@ import im.vector.app.features.spaces.create.ChooseSpaceTypeFragment
|
||||||
import im.vector.app.features.spaces.create.CreateSpaceDefaultRoomsFragment
|
import im.vector.app.features.spaces.create.CreateSpaceDefaultRoomsFragment
|
||||||
import im.vector.app.features.spaces.create.CreateSpaceDetailsFragment
|
import im.vector.app.features.spaces.create.CreateSpaceDetailsFragment
|
||||||
import im.vector.app.features.spaces.explore.SpaceDirectoryFragment
|
import im.vector.app.features.spaces.explore.SpaceDirectoryFragment
|
||||||
|
import im.vector.app.features.spaces.manage.SpaceAddRoomFragment
|
||||||
import im.vector.app.features.spaces.preview.SpacePreviewFragment
|
import im.vector.app.features.spaces.preview.SpacePreviewFragment
|
||||||
import im.vector.app.features.terms.ReviewTermsFragment
|
import im.vector.app.features.terms.ReviewTermsFragment
|
||||||
import im.vector.app.features.usercode.ShowUserCodeFragment
|
import im.vector.app.features.usercode.ShowUserCodeFragment
|
||||||
|
@ -678,4 +679,9 @@ interface FragmentModule {
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FragmentKey(ChoosePrivateSpaceTypeFragment::class)
|
@FragmentKey(ChoosePrivateSpaceTypeFragment::class)
|
||||||
fun bindChoosePrivateSpaceTypeFragment(fragment: ChoosePrivateSpaceTypeFragment): Fragment
|
fun bindChoosePrivateSpaceTypeFragment(fragment: ChoosePrivateSpaceTypeFragment): Fragment
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FragmentKey(SpaceAddRoomFragment::class)
|
||||||
|
fun bindSpaceAddRoomFragment(fragment: SpaceAddRoomFragment): Fragment
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ import im.vector.app.features.spaces.ShareSpaceBottomSheet
|
||||||
import im.vector.app.features.spaces.SpaceCreationActivity
|
import im.vector.app.features.spaces.SpaceCreationActivity
|
||||||
import im.vector.app.features.spaces.SpaceExploreActivity
|
import im.vector.app.features.spaces.SpaceExploreActivity
|
||||||
import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
|
import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
|
||||||
|
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
||||||
import im.vector.app.features.terms.ReviewTermsActivity
|
import im.vector.app.features.terms.ReviewTermsActivity
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
import im.vector.app.features.usercode.UserCodeActivity
|
import im.vector.app.features.usercode.UserCodeActivity
|
||||||
|
@ -158,6 +159,7 @@ interface ScreenComponent {
|
||||||
fun inject(activity: RoomDevToolActivity)
|
fun inject(activity: RoomDevToolActivity)
|
||||||
fun inject(activity: SpaceCreationActivity)
|
fun inject(activity: SpaceCreationActivity)
|
||||||
fun inject(activity: SpaceExploreActivity)
|
fun inject(activity: SpaceExploreActivity)
|
||||||
|
fun inject(activity: SpaceManageActivity)
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* BottomSheets
|
* BottomSheets
|
||||||
|
|
|
@ -35,10 +35,12 @@ import im.vector.app.features.navigation.Navigator
|
||||||
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
|
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
|
||||||
import im.vector.app.features.roomprofile.RoomProfileActivity
|
import im.vector.app.features.roomprofile.RoomProfileActivity
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -91,7 +93,9 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
|
||||||
.subscribe { powerLevelContent ->
|
.subscribe { powerLevelContent ->
|
||||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelContent)
|
val powerLevelsHelper = PowerLevelsHelper(powerLevelContent)
|
||||||
val canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId)
|
val canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId)
|
||||||
|
val canAddChild = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_SPACE_CHILD)
|
||||||
views.invitePeople.isVisible = canInvite
|
views.invitePeople.isVisible = canInvite
|
||||||
|
views.addRooms.isVisible = canAddChild
|
||||||
}.disposeOnDestroyView()
|
}.disposeOnDestroyView()
|
||||||
|
|
||||||
views.invitePeople.views.bottomSheetActionClickableZone.debouncedClicks {
|
views.invitePeople.views.bottomSheetActionClickableZone.debouncedClicks {
|
||||||
|
@ -112,6 +116,10 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
|
||||||
startActivity(SpaceExploreActivity.newIntent(requireContext(), spaceArgs.spaceId))
|
startActivity(SpaceExploreActivity.newIntent(requireContext(), spaceArgs.spaceId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
views.addRooms.views.bottomSheetActionClickableZone.debouncedClicks {
|
||||||
|
startActivity(SpaceManageActivity.newIntent(requireContext(), spaceArgs.spaceId))
|
||||||
|
}
|
||||||
|
|
||||||
views.leaveSpace.views.bottomSheetActionClickableZone.debouncedClicks {
|
views.leaveSpace.views.bottomSheetActionClickableZone.debouncedClicks {
|
||||||
AlertDialog.Builder(requireContext())
|
AlertDialog.Builder(requireContext())
|
||||||
.setMessage(getString(R.string.space_leave_prompt_msg))
|
.setMessage(getString(R.string.space_leave_prompt_msg))
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import com.airbnb.epoxy.EpoxyModel
|
||||||
|
import com.airbnb.epoxy.paging.PagedListEpoxyController
|
||||||
|
import im.vector.app.core.utils.DebouncedClickListener
|
||||||
|
import im.vector.app.core.utils.createUIHandler
|
||||||
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||||
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AddRoomListController @Inject constructor(
|
||||||
|
private val avatarRenderer: AvatarRenderer
|
||||||
|
) : PagedListEpoxyController<RoomSummary>(
|
||||||
|
// Important it must match the PageList builder notify Looper
|
||||||
|
modelBuildingHandler = createUIHandler(),
|
||||||
|
|
||||||
|
itemDiffCallback = object : DiffUtil.ItemCallback<RoomSummary>() {
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItem: RoomSummary, newItem: RoomSummary): Boolean {
|
||||||
|
return oldItem.roomId == newItem.roomId
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: RoomSummary, newItem: RoomSummary): Boolean {
|
||||||
|
// for this use case we can test less things
|
||||||
|
return oldItem.displayName == newItem.displayName
|
||||||
|
&& oldItem.avatarUrl == newItem.avatarUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun onItemSelected(roomSummary: RoomSummary)
|
||||||
|
}
|
||||||
|
|
||||||
|
var listener: Listener? = null
|
||||||
|
var ignoreRooms: List<String>? = null
|
||||||
|
|
||||||
|
var selectedItems: Map<String, Boolean> = emptyMap()
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
// mmm annoying but can't just force for a given model
|
||||||
|
requestForcedModelBuild()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addModels(models: List<EpoxyModel<*>>) {
|
||||||
|
if (ignoreRooms == null) {
|
||||||
|
super.addModels(models)
|
||||||
|
} else {
|
||||||
|
super.addModels(
|
||||||
|
models.filter {
|
||||||
|
it !is RoomSelectionItem || !ignoreRooms!!.contains(it.matrixItem.id)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildItemModel(currentPosition: Int, item: RoomSummary?): EpoxyModel<*> {
|
||||||
|
if (item == null) return RoomSelectionPlaceHolderItem_().apply { id(currentPosition) }
|
||||||
|
return RoomSelectionItem_().apply {
|
||||||
|
id(item.roomId)
|
||||||
|
matrixItem(item.toMatrixItem())
|
||||||
|
avatarRenderer(this@AddRoomListController.avatarRenderer)
|
||||||
|
space(item.roomType == RoomType.SPACE)
|
||||||
|
selected(selectedItems[item.roomId] ?: false)
|
||||||
|
itemClickListener(DebouncedClickListener({
|
||||||
|
listener?.onItemSelected(item)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
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.features.home.AvatarRenderer
|
||||||
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_room_to_add_in_space)
|
||||||
|
abstract class RoomSelectionItem : VectorEpoxyModel<RoomSelectionItem.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
||||||
|
@EpoxyAttribute lateinit var matrixItem: MatrixItem
|
||||||
|
@EpoxyAttribute var space: Boolean = false
|
||||||
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemClickListener: View.OnClickListener? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
if (space) {
|
||||||
|
avatarRenderer.renderSpace(matrixItem, holder.avatarImageView)
|
||||||
|
} else {
|
||||||
|
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
||||||
|
}
|
||||||
|
holder.titleText.text = matrixItem.getBestName()
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
holder.checkboxImage.setImageDrawable(ContextCompat.getDrawable(holder.view.context, R.drawable.ic_checkbox_on))
|
||||||
|
holder.checkboxImage.contentDescription = holder.view.context.getString(R.string.a11y_checked)
|
||||||
|
} else {
|
||||||
|
holder.checkboxImage.setImageDrawable(ContextCompat.getDrawable(holder.view.context, R.drawable.ic_checkbox_off))
|
||||||
|
holder.checkboxImage.contentDescription = holder.view.context.getString(R.string.a11y_unchecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.view.setOnClickListener {
|
||||||
|
itemClickListener?.onClick(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val avatarImageView by bind<ImageView>(R.id.itemAddRoomRoomAvatar)
|
||||||
|
val titleText by bind<TextView>(R.id.itemAddRoomRoomNameText)
|
||||||
|
val checkboxImage by bind<ImageView>(R.id.itemAddRoomRoomCheckBox)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_room_to_add_in_space_placeholder)
|
||||||
|
abstract class RoomSelectionPlaceHolderItem : VectorEpoxyModel<RoomSelectionPlaceHolderItem.Holder>() {
|
||||||
|
class Holder : VectorEpoxyHolder()
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
|
sealed class SpaceAddRoomActions : VectorViewModelAction {
|
||||||
|
data class UpdateFilter(val filter: String) : SpaceAddRoomActions()
|
||||||
|
data class ToggleSelection(val roomSummary: RoomSummary) : SpaceAddRoomActions()
|
||||||
|
object Save : SpaceAddRoomActions()
|
||||||
|
// object HandleBack : SpaceAddRoomActions()
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.activityViewModel
|
||||||
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import com.jakewharton.rxbinding3.appcompat.queryTextChanges
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.extensions.cleanup
|
||||||
|
import im.vector.app.core.extensions.configureWith
|
||||||
|
import im.vector.app.core.platform.OnBackPressed
|
||||||
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentSpaceAddRoomsBinding
|
||||||
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SpaceAddRoomFragment @Inject constructor(
|
||||||
|
private val epoxyController: AddRoomListController,
|
||||||
|
private val viewModelFactory: SpaceAddRoomsViewModel.Factory
|
||||||
|
) : VectorBaseFragment<FragmentSpaceAddRoomsBinding>(),
|
||||||
|
OnBackPressed, AddRoomListController.Listener, SpaceAddRoomsViewModel.Factory {
|
||||||
|
|
||||||
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) =
|
||||||
|
FragmentSpaceAddRoomsBinding.inflate(layoutInflater, container, false)
|
||||||
|
|
||||||
|
private val viewModel by fragmentViewModel(SpaceAddRoomsViewModel::class)
|
||||||
|
|
||||||
|
private val sharedViewModel: SpaceManageSharedViewModel by activityViewModel()
|
||||||
|
|
||||||
|
override fun create(initialState: SpaceAddRoomsState): SpaceAddRoomsViewModel =
|
||||||
|
viewModelFactory.create(initialState)
|
||||||
|
|
||||||
|
override fun getMenuRes(): Int = R.menu.menu_space_add_room
|
||||||
|
|
||||||
|
private var saveNeeded = false
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
vectorBaseActivity.setSupportActionBar(views.addRoomToSpaceToolbar)
|
||||||
|
|
||||||
|
vectorBaseActivity.supportActionBar?.let {
|
||||||
|
it.setDisplayShowHomeEnabled(true)
|
||||||
|
it.setDisplayHomeAsUpEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
||||||
|
setupRecyclerView()
|
||||||
|
|
||||||
|
views.publicRoomsFilter.queryTextChanges()
|
||||||
|
.debounce(100, TimeUnit.MILLISECONDS)
|
||||||
|
.subscribeBy {
|
||||||
|
viewModel.handle(SpaceAddRoomActions.UpdateFilter(it.toString()))
|
||||||
|
}
|
||||||
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
|
viewModel.selectionListLiveData.observe(viewLifecycleOwner) {
|
||||||
|
epoxyController.selectedItems = it
|
||||||
|
saveNeeded = it.values.any { it }
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.selectSubscribe(this, SpaceAddRoomsState::spaceName) {
|
||||||
|
views.appBarSpaceInfo.text = it
|
||||||
|
}.disposeOnDestroyView()
|
||||||
|
|
||||||
|
viewModel.selectSubscribe(this, SpaceAddRoomsState::ignoreRooms) {
|
||||||
|
epoxyController.ignoreRooms = it
|
||||||
|
}.disposeOnDestroyView()
|
||||||
|
|
||||||
|
viewModel.selectSubscribe(this, SpaceAddRoomsState::isSaving) {
|
||||||
|
if (it is Loading) {
|
||||||
|
sharedViewModel.handle(SpaceManagedSharedAction.ShowLoading)
|
||||||
|
} else {
|
||||||
|
sharedViewModel.handle(SpaceManagedSharedAction.HideLoading)
|
||||||
|
}
|
||||||
|
}.disposeOnDestroyView()
|
||||||
|
|
||||||
|
// views.createNewRoom.debouncedClicks {
|
||||||
|
// sharedActionViewModel.post(RoomDirectorySharedAction.CreateRoom)
|
||||||
|
// }
|
||||||
|
|
||||||
|
viewModel.observeViewEvents {
|
||||||
|
when (it) {
|
||||||
|
SpaceAddRoomsViewEvents.WarnUnsavedChanged -> {
|
||||||
|
AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle(R.string.dialog_title_warning)
|
||||||
|
.setMessage(R.string.warning_unsaved_change)
|
||||||
|
.setPositiveButton(R.string.warning_unsaved_change_discard) { _, _ ->
|
||||||
|
sharedViewModel.handle(SpaceManagedSharedAction.HandleBack)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
SpaceAddRoomsViewEvents.SaveFailed -> {
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
}
|
||||||
|
SpaceAddRoomsViewEvents.SavedDone -> {
|
||||||
|
sharedViewModel.handle(SpaceManagedSharedAction.HandleBack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate() = withState(viewModel) {
|
||||||
|
super.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
|
super.onPrepareOptionsMenu(menu)
|
||||||
|
menu.findItem(R.id.spaceAddRoomSaveItem).isVisible = saveNeeded
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (item.itemId == R.id.spaceAddRoomSaveItem) {
|
||||||
|
viewModel.handle(SpaceAddRoomActions.Save)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
views.roomList.cleanup()
|
||||||
|
epoxyController.listener = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupRecyclerView() {
|
||||||
|
views.roomList.configureWith(epoxyController, showDivider = true)
|
||||||
|
epoxyController.listener = this
|
||||||
|
viewModel.updatableLivePageResult.livePagedList.observe(viewLifecycleOwner) {
|
||||||
|
epoxyController.submitList(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed(toolbarButton: Boolean): Boolean {
|
||||||
|
if (viewModel.canGoBack()) {
|
||||||
|
sharedViewModel.handle(SpaceManagedSharedAction.HandleBack)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemSelected(roomSummary: RoomSummary) {
|
||||||
|
viewModel.handle(SpaceAddRoomActions.ToggleSelection(roomSummary))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
|
||||||
|
data class SpaceAddRoomsState(
|
||||||
|
// The current filter
|
||||||
|
val spaceId: String = "",
|
||||||
|
val currentFilter: String = "",
|
||||||
|
val spaceName: String = "",
|
||||||
|
val ignoreRooms: List<String> = emptyList(),
|
||||||
|
val isSaving: Async<List<String>> = Uninitialized
|
||||||
|
// val selectionList: Map<String, Boolean> = emptyMap()
|
||||||
|
) : MvRxState {
|
||||||
|
constructor(args: SpaceManageArgs) : this(
|
||||||
|
spaceId = args.spaceId
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewEvents
|
||||||
|
|
||||||
|
sealed class SpaceAddRoomsViewEvents : VectorViewEvents {
|
||||||
|
object WarnUnsavedChanged : SpaceAddRoomsViewEvents()
|
||||||
|
object SavedDone : SpaceAddRoomsViewEvents()
|
||||||
|
object SaveFailed : SpaceAddRoomsViewEvents()
|
||||||
|
}
|
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.paging.PagedList
|
||||||
|
import com.airbnb.mvrx.ActivityViewModelContext
|
||||||
|
import com.airbnb.mvrx.Fail
|
||||||
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||||
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
|
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||||
|
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.roomSummaryQueryParams
|
||||||
|
|
||||||
|
class AddRoomError(val errorList: Map<String, Throwable>) : Throwable()
|
||||||
|
|
||||||
|
class SpaceAddRoomsViewModel @AssistedInject constructor(
|
||||||
|
@Assisted val initialState: SpaceAddRoomsState,
|
||||||
|
private val session: Session
|
||||||
|
) : VectorViewModel<SpaceAddRoomsState, SpaceAddRoomActions, SpaceAddRoomsViewEvents>(initialState) {
|
||||||
|
|
||||||
|
val updatableLivePageResult: UpdatableLivePageResult by lazy {
|
||||||
|
session.getFilteredPagedRoomSummariesLive(
|
||||||
|
roomSummaryQueryParams {
|
||||||
|
this.memberships = listOf(Membership.JOIN)
|
||||||
|
this.excludeType = null
|
||||||
|
this.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||||
|
this.activeSpaceId = ActiveSpaceFilter.ExcludeSpace(initialState.spaceId)
|
||||||
|
this.displayName = QueryStringValue.Contains(initialState.currentFilter, QueryStringValue.Case.INSENSITIVE)
|
||||||
|
},
|
||||||
|
pagedListConfig = PagedList.Config.Builder()
|
||||||
|
.setPageSize(10)
|
||||||
|
.setInitialLoadSizeHint(20)
|
||||||
|
.setEnablePlaceholders(true)
|
||||||
|
.setPrefetchDistance(10)
|
||||||
|
.build(),
|
||||||
|
sortOrder = RoomSortOrder.NAME
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val selectionList = mutableMapOf<String, Boolean>()
|
||||||
|
val selectionListLiveData = MutableLiveData<Map<String, Boolean>>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
val spaceSummary = session.getRoomSummary(initialState.spaceId)
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
spaceName = spaceSummary?.displayName ?: "",
|
||||||
|
ignoreRooms = (spaceSummary?.flattenParentIds ?: emptyList()) + listOf(initialState.spaceId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: SpaceAddRoomsState): SpaceAddRoomsViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<SpaceAddRoomsViewModel, SpaceAddRoomsState> {
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: SpaceAddRoomsState): SpaceAddRoomsViewModel? {
|
||||||
|
val factory = when (viewModelContext) {
|
||||||
|
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
|
||||||
|
is ActivityViewModelContext -> viewModelContext.activity as? Factory
|
||||||
|
}
|
||||||
|
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun canGoBack(): Boolean {
|
||||||
|
val needToSave = selectionList.values.any { it }
|
||||||
|
if (needToSave) {
|
||||||
|
_viewEvents.post(SpaceAddRoomsViewEvents.WarnUnsavedChanged)
|
||||||
|
}
|
||||||
|
return !needToSave
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(action: SpaceAddRoomActions) {
|
||||||
|
when (action) {
|
||||||
|
is SpaceAddRoomActions.UpdateFilter -> {
|
||||||
|
updatableLivePageResult.updateQuery {
|
||||||
|
it.copy(
|
||||||
|
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.INSENSITIVE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
currentFilter = action.filter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is SpaceAddRoomActions.ToggleSelection -> {
|
||||||
|
selectionList[action.roomSummary.roomId] = (selectionList[action.roomSummary.roomId] ?: false).not()
|
||||||
|
selectionListLiveData.postValue(selectionList.toMap())
|
||||||
|
}
|
||||||
|
SpaceAddRoomActions.Save -> {
|
||||||
|
doAddSelectedRooms()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doAddSelectedRooms() {
|
||||||
|
val childrenToAdd = selectionList.filter { it.value }.keys
|
||||||
|
if (childrenToAdd.isEmpty()) return // should not happen
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
isSaving = Loading()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
viewModelScope.launch {
|
||||||
|
val errors = mutableMapOf<String, Throwable>()
|
||||||
|
val completed = mutableListOf<String>()
|
||||||
|
childrenToAdd.forEach { roomId ->
|
||||||
|
try {
|
||||||
|
session.spaceService().getSpace(initialState.spaceId)!!.addChildren(
|
||||||
|
roomId = roomId,
|
||||||
|
viaServers = listOf(session.sessionParams.homeServerHost ?: ""),
|
||||||
|
order = null
|
||||||
|
)
|
||||||
|
completed.add(roomId)
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
errors[roomId] = failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errors.isEmpty()) {
|
||||||
|
// success
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
isSaving = Success(childrenToAdd.toList())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
completed.forEach {
|
||||||
|
selectionList.remove(it)
|
||||||
|
}
|
||||||
|
_viewEvents.post(SpaceAddRoomsViewEvents.SavedDone)
|
||||||
|
}
|
||||||
|
} else if (errors.size < childrenToAdd.size) {
|
||||||
|
// partial success
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
isSaving = Success(completed)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
completed.forEach {
|
||||||
|
selectionList.remove(it)
|
||||||
|
}
|
||||||
|
_viewEvents.post(SpaceAddRoomsViewEvents.SavedDone)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
isSaving = Fail(AddRoomError(errors))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_viewEvents.post(SpaceAddRoomsViewEvents.SaveFailed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.airbnb.mvrx.MvRx
|
||||||
|
import com.airbnb.mvrx.viewModel
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.di.ScreenComponent
|
||||||
|
import im.vector.app.core.extensions.commitTransaction
|
||||||
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.app.databinding.ActivitySimpleBinding
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class SpaceManageArgs(
|
||||||
|
val spaceId: String
|
||||||
|
) : Parcelable
|
||||||
|
|
||||||
|
class SpaceManageActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceManageSharedViewModel.Factory {
|
||||||
|
|
||||||
|
@Inject lateinit var sharedViewModelFactory: SpaceManageSharedViewModel.Factory
|
||||||
|
|
||||||
|
override fun injectWith(injector: ScreenComponent) {
|
||||||
|
injector.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBinding(): ActivitySimpleBinding = ActivitySimpleBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
override fun getTitleRes(): Int = R.string.space_add_existing_rooms
|
||||||
|
|
||||||
|
val sharedViewModel: SpaceManageSharedViewModel by viewModel()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
if (isFirstCreation()) {
|
||||||
|
val simpleName = SpaceAddRoomFragment::class.java.simpleName
|
||||||
|
val args = intent?.getParcelableExtra<SpaceManageArgs>(MvRx.KEY_ARG)
|
||||||
|
if (supportFragmentManager.findFragmentByTag(simpleName) == null) {
|
||||||
|
supportFragmentManager.commitTransaction {
|
||||||
|
replace(R.id.simpleFragmentContainer,
|
||||||
|
SpaceAddRoomFragment::class.java,
|
||||||
|
Bundle().apply { this.putParcelable(MvRx.KEY_ARG, args) },
|
||||||
|
simpleName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedViewModel.observeViewEvents {
|
||||||
|
when (it) {
|
||||||
|
SpaceManagedSharedViewEvents.Finish -> {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
SpaceManagedSharedViewEvents.HideLoading -> {
|
||||||
|
views.simpleActivityWaitingView.isVisible = false
|
||||||
|
}
|
||||||
|
SpaceManagedSharedViewEvents.ShowLoading -> {
|
||||||
|
views.simpleActivityWaitingView.isVisible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newIntent(context: Context, spaceId: String): Intent {
|
||||||
|
return Intent(context, SpaceManageActivity::class.java).apply {
|
||||||
|
putExtra(MvRx.KEY_ARG, SpaceManageArgs(spaceId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun create(initialState: SpaceManageViewState) = sharedViewModelFactory.create(initialState)
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.ActivityViewModelContext
|
||||||
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
|
||||||
|
class SpaceManageSharedViewModel @AssistedInject constructor(
|
||||||
|
@Assisted initialState: SpaceManageViewState,
|
||||||
|
private val session: Session
|
||||||
|
) : VectorViewModel<SpaceManageViewState, SpaceManagedSharedAction, SpaceManagedSharedViewEvents>(initialState) {
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: SpaceManageViewState): SpaceManageSharedViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<SpaceManageSharedViewModel, SpaceManageViewState> {
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: SpaceManageViewState): SpaceManageSharedViewModel? {
|
||||||
|
val factory = when (viewModelContext) {
|
||||||
|
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
|
||||||
|
is ActivityViewModelContext -> viewModelContext.activity as? Factory
|
||||||
|
}
|
||||||
|
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(action: SpaceManagedSharedAction) {
|
||||||
|
when (action) {
|
||||||
|
SpaceManagedSharedAction.HandleBack -> {
|
||||||
|
// for now finish
|
||||||
|
_viewEvents.post(SpaceManagedSharedViewEvents.Finish)
|
||||||
|
}
|
||||||
|
SpaceManagedSharedAction.HideLoading -> _viewEvents.post(SpaceManagedSharedViewEvents.HideLoading)
|
||||||
|
SpaceManagedSharedAction.ShowLoading -> _viewEvents.post(SpaceManagedSharedViewEvents.ShowLoading)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
|
||||||
|
data class SpaceManageViewState(
|
||||||
|
val spaceId: String = ""
|
||||||
|
) : MvRxState {
|
||||||
|
constructor(args: SpaceManageArgs) : this(
|
||||||
|
spaceId = args.spaceId
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
|
||||||
|
sealed class SpaceManagedSharedAction : VectorViewModelAction {
|
||||||
|
object HandleBack : SpaceManagedSharedAction()
|
||||||
|
object ShowLoading: SpaceManagedSharedAction()
|
||||||
|
object HideLoading: SpaceManagedSharedAction()
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.manage
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewEvents
|
||||||
|
|
||||||
|
sealed class SpaceManagedSharedViewEvents : VectorViewEvents {
|
||||||
|
object Finish : SpaceManagedSharedViewEvents()
|
||||||
|
object ShowLoading: SpaceManagedSharedViewEvents()
|
||||||
|
object HideLoading: SpaceManagedSharedViewEvents()
|
||||||
|
}
|
11
vector/src/main/res/drawable/ic_checkbox_off.xml
Normal file
11
vector/src/main/res/drawable/ic_checkbox_off.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<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="M4,0.75L12,0.75A3.25,3.25 0,0 1,15.25 4L15.25,12A3.25,3.25 0,0 1,12 15.25L4,15.25A3.25,3.25 0,0 1,0.75 12L0.75,4A3.25,3.25 0,0 1,4 0.75z"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#8D99A5"/>
|
||||||
|
</vector>
|
18
vector/src/main/res/drawable/ic_checkbox_on.xml
Normal file
18
vector/src/main/res/drawable/ic_checkbox_on.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<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="M4,0.75L12,0.75A3.25,3.25 0,0 1,15.25 4L15.25,12A3.25,3.25 0,0 1,12 15.25L4,15.25A3.25,3.25 0,0 1,0.75 12L0.75,4A3.25,3.25 0,0 1,4 0.75z"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:fillColor="#03B381"
|
||||||
|
android:strokeColor="#03B381"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12,5.5L6.5,11L4,8.5"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#ffffff"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
|
@ -111,6 +111,18 @@
|
||||||
app:titleTextColor="?attr/riotx_text_primary"
|
app:titleTextColor="?attr/riotx_text_primary"
|
||||||
tools:actionDescription="" />
|
tools:actionDescription="" />
|
||||||
|
|
||||||
|
|
||||||
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
|
android:id="@+id/addRooms"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:actionTitle="@string/space_add_child_title"
|
||||||
|
app:leftIcon="@drawable/ic_add_black"
|
||||||
|
app:tint="?attr/riotx_text_primary"
|
||||||
|
app:titleTextColor="?attr/riotx_text_primary"
|
||||||
|
tools:actionDescription="" />
|
||||||
|
|
||||||
|
|
||||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||||
android:id="@+id/leaveSpace"
|
android:id="@+id/leaveSpace"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
103
vector/src/main/res/layout/fragment_space_add_rooms.xml
Normal file
103
vector/src/main/res/layout/fragment_space_add_rooms.xml
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout 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/coordinatorLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/roomList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?riotx_header_panel_background"
|
||||||
|
android:overScrollMode="always"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
tools:listitem="@layout/item_room_to_add_in_space" />
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
style="@style/VectorAppBarLayoutStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:elevation="4dp">
|
||||||
|
|
||||||
|
<!-- minHeight="0dp" is important to collapse on scroll -->
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/addRoomToSpaceToolbar"
|
||||||
|
style="@style/VectorToolbarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:elevation="4dp"
|
||||||
|
android:minHeight="0dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap|enterAlways">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical|start"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/appBarTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start|center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@string/space_add_existing_rooms"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/appBarSpaceInfo"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start|center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?riotx_text_secondary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="@sample/matrix.json/data/spaceName" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SearchView
|
||||||
|
android:id="@+id/publicRoomsFilter"
|
||||||
|
style="@style/VectorSearchView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/addRoomToSpaceToolbar"
|
||||||
|
app:queryHint="@string/search_hint_room_name" />
|
||||||
|
|
||||||
|
<!-- <com.google.android.material.button.MaterialButton-->
|
||||||
|
<!-- android:id="@+id/createNewRoom"-->
|
||||||
|
<!-- style="@style/VectorButtonStyleText"-->
|
||||||
|
<!-- android:layout_width="wrap_content"-->
|
||||||
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
<!-- android:layout_marginStart="16dp"-->
|
||||||
|
<!-- android:layout_marginTop="8dp"-->
|
||||||
|
<!-- android:layout_marginBottom="8dp"-->
|
||||||
|
<!-- android:minHeight="@dimen/layout_touch_size"-->
|
||||||
|
<!-- android:text="@string/create_new_room"-->
|
||||||
|
<!-- app:icon="@drawable/ic_plus_circle"-->
|
||||||
|
<!-- app:iconPadding="13dp"-->
|
||||||
|
<!-- app:iconTint="@color/riotx_accent"-->
|
||||||
|
<!-- app:layout_constraintStart_toStartOf="parent"-->
|
||||||
|
<!-- app:layout_constraintTop_toBottomOf="@+id/addRoomToSpaceToolbar" />-->
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
56
vector/src/main/res/layout/item_room_to_add_in_space.xml
Normal file
56
vector/src/main/res/layout/item_room_to_add_in_space.xml
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout 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/itemPublicRoomLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?riotx_background"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:minHeight="50dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/itemAddRoomRoomAvatar"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:contentDescription="@string/avatar"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemAddRoomRoomNameText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="17dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/itemAddRoomRoomCheckBox"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/itemAddRoomRoomAvatar"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
tools:text="@sample/matrix.json/data/roomName" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/itemAddRoomRoomCheckBox"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:contentDescription="@string/a11y_checked"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/itemAddRoomRoomNameText"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@drawable/ic_checkbox_on" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout 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/itemPublicRoomLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?riotx_background"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:minHeight="50dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/itemAddRoomRoomAvatar"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/header_panel_round_background"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/itemAddRoomRoomNameText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="16sp"
|
||||||
|
android:layout_marginStart="17dp"
|
||||||
|
android:layout_marginEnd="40dp"
|
||||||
|
android:background="@drawable/rounded_rect_shape_8"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/itemAddRoomRoomAvatar"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
tools:text="@sample/matrix.json/data/roomName" />
|
||||||
|
|
||||||
|
<!-- <ImageView-->
|
||||||
|
<!-- android:id="@+id/itemAddRoomRoomCheckBox"-->
|
||||||
|
<!-- android:layout_width="20dp"-->
|
||||||
|
<!-- android:layout_height="20dp"-->
|
||||||
|
<!-- android:layout_marginEnd="16dp"-->
|
||||||
|
<!-- android:importantForAccessibility="no"-->
|
||||||
|
<!-- android:src="@drawable/ic_checkbox_off"-->
|
||||||
|
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||||
|
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||||
|
<!-- app:layout_constraintStart_toEndOf="@id/itemAddRoomRoomNameText"-->
|
||||||
|
<!-- app:layout_constraintTop_toTopOf="parent" />-->
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
9
vector/src/main/res/menu/menu_space_add_room.xml
Normal file
9
vector/src/main/res/menu/menu_space_add_room.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/spaceAddRoomSaveItem"
|
||||||
|
android:title="@string/save"
|
||||||
|
app:iconTint="?attr/colorAccent"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
</menu>
|
|
@ -2193,6 +2193,8 @@
|
||||||
<string name="room_directory_search_hint">Name or ID (#example:matrix.org)</string>
|
<string name="room_directory_search_hint">Name or ID (#example:matrix.org)</string>
|
||||||
<string name="user_directory_search_hint">Search by name or ID</string>
|
<string name="user_directory_search_hint">Search by name or ID</string>
|
||||||
|
|
||||||
|
<string name="search_hint_room_name">Search Name</string>
|
||||||
|
|
||||||
<string name="labs_swipe_to_reply_in_timeline">Enable swipe to reply in timeline</string>
|
<string name="labs_swipe_to_reply_in_timeline">Enable swipe to reply in timeline</string>
|
||||||
<string name="labs_show_unread_notifications_as_tab">Add a dedicated tab for unread notifications on main screen.</string>
|
<string name="labs_show_unread_notifications_as_tab">Add a dedicated tab for unread notifications on main screen.</string>
|
||||||
|
|
||||||
|
@ -3329,6 +3331,10 @@
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
<string name="space_explore_activity_title">Explore rooms</string>
|
<string name="space_explore_activity_title">Explore rooms</string>
|
||||||
|
<string name="space_add_child_title">Add rooms</string>
|
||||||
<string name="leave_space">Leave Space</string>
|
<string name="leave_space">Leave Space</string>
|
||||||
<string name="space_leave_prompt_msg">Are you sure you want to leave the space?</string>
|
<string name="space_leave_prompt_msg">Are you sure you want to leave the space?</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="space_add_existing_rooms">Add existing rooms and space</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue