Compare commits
61 Commits
develop
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
|
df25dfc284 | ||
|
2ec468ba27 | ||
|
484afac10b | ||
|
d70d110454 | ||
|
7437b71b24 | ||
|
6da990d4a5 | ||
|
2d32d0da54 | ||
|
f54da187ca | ||
|
a961ed7de7 | ||
|
df0415748f | ||
|
43d23e195f | ||
|
626c6933a3 | ||
|
60adecedd6 | ||
|
7f41aa313e | ||
|
c7efb2cec9 | ||
|
10ceb56321 | ||
|
3a156cf8c8 | ||
|
9618c76dbd | ||
|
456b6881d7 | ||
|
94e6e1b0d8 | ||
|
a6564b6466 | ||
|
c72ba8d651 | ||
|
a158d9866d | ||
|
89db0645a5 | ||
|
f5851a0bf8 | ||
|
39e892dc08 | ||
|
0faeada1c6 | ||
|
f3720d2dce | ||
|
1bca6f83ee | ||
|
4fe455c47b | ||
|
65d5473661 | ||
|
e533b9f33d | ||
|
947cd8fceb | ||
|
a0baf77438 | ||
|
fee96b45bc | ||
|
20a72e640b | ||
|
952e3102d8 | ||
|
19fcb6faf1 | ||
|
89f69a1062 | ||
|
4ee5b90f82 | ||
|
051adad0ed | ||
|
2d2f8f5479 | ||
|
9fc189efce | ||
|
b6ab0bdc53 | ||
|
15c89f918e | ||
|
b46794d4df | ||
|
c9b32fec44 | ||
|
47493fcfa1 | ||
|
f70a24d257 | ||
|
a355b625e9 | ||
|
7cc79fef0f | ||
|
7e415e82b0 | ||
|
962e9abc6b | ||
|
4784717b0c | ||
|
b280358077 | ||
|
33475602f8 | ||
|
87ad35dca6 | ||
|
70cded2733 | ||
|
9e53e6cc8f | ||
|
a3367d4075 | ||
|
0250f61d10 |
1802
.editorconfig
1802
.editorconfig
File diff suppressed because it is too large
Load Diff
@ -104,7 +104,7 @@ allprojects {
|
|||||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||||
// Warnings are potential errors, so stop ignoring them
|
// Warnings are potential errors, so stop ignoring them
|
||||||
// You can override by passing `-PallWarningsAsErrors=false` in the command line
|
// You can override by passing `-PallWarningsAsErrors=false` in the command line
|
||||||
kotlinOptions.allWarningsAsErrors = project.getProperties().getOrDefault("allWarningsAsErrors", "true").toBoolean()
|
// kotlinOptions.allWarningsAsErrors = project.getProperties().getOrDefault("allWarningsAsErrors", "true").toBoolean()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix "Java heap space" issue
|
// Fix "Java heap space" issue
|
||||||
|
1
changelog.d/5860.feature
Normal file
1
changelog.d/5860.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Adds space or user id as a subtitle under rooms in search
|
6
library/ui-styles/src/main/res/values-night/bools.xml
Normal file
6
library/ui-styles/src/main/res/values-night/bools.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<bool name="isDarkMode">true</bool>
|
||||||
|
|
||||||
|
</resources>
|
6
library/ui-styles/src/main/res/values-night/colors.xml
Normal file
6
library/ui-styles/src/main/res/values-night/colors.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<color name="modal_background_color">@color/element_system_dark</color>
|
||||||
|
|
||||||
|
</resources>
|
@ -3,5 +3,6 @@
|
|||||||
|
|
||||||
<!-- Created to detect what has to be implemented (especially in the settings) -->
|
<!-- Created to detect what has to be implemented (especially in the settings) -->
|
||||||
<bool name="false_not_implemented">false</bool>
|
<bool name="false_not_implemented">false</bool>
|
||||||
|
<bool name="isDarkMode">false</bool>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
<color name="android_status_bar_background_dark">@color/element_background_dark</color>
|
<color name="android_status_bar_background_dark">@color/element_background_dark</color>
|
||||||
<color name="android_navigation_bar_background_dark">@color/element_system_dark</color>
|
<color name="android_navigation_bar_background_dark">@color/element_system_dark</color>
|
||||||
|
|
||||||
|
<color name="modal_background_color">#FFFFFF</color>
|
||||||
|
|
||||||
<!-- Used for toolbar background -->
|
<!-- Used for toolbar background -->
|
||||||
<attr name="vctr_toolbar_background" format="color" />
|
<attr name="vctr_toolbar_background" format="color" />
|
||||||
|
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="SpaceListModalImageShapeOverlay">
|
||||||
|
<item name="cornerFamily">rounded</item>
|
||||||
|
<item name="cornerSize">8dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
@ -17,6 +17,10 @@
|
|||||||
<item name="android:textAppearance">@style/TextAppearance.Vector.Title.Medium</item>
|
<item name="android:textAppearance">@style/TextAppearance.Vector.Title.Medium</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.Vector.TextView.Title.Bold">
|
||||||
|
<item name="android:textAppearance">@style/TextAppearance.Vector.Title.Bold</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="Widget.Vector.TextView.HeadlineMedium">
|
<style name="Widget.Vector.TextView.HeadlineMedium">
|
||||||
<item name="android:textAppearance">@style/TextAppearance.Vector.Headline.Medium</item>
|
<item name="android:textAppearance">@style/TextAppearance.Vector.Headline.Medium</item>
|
||||||
</style>
|
</style>
|
||||||
@ -48,4 +52,4 @@
|
|||||||
<item name="lineHeight">16sp</item>
|
<item name="lineHeight">16sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -24,6 +24,11 @@
|
|||||||
<item name="android:fontFamily">sans-serif-medium</item>
|
<item name="android:fontFamily">sans-serif-medium</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.Vector.Title.Bold">
|
||||||
|
<item name="fontFamily">sans-serif-black</item>
|
||||||
|
<item name="android:fontFamily">sans-serif-black</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.Vector.Headline.Medium" parent="TextAppearance.MaterialComponents.Headline1">
|
<style name="TextAppearance.Vector.Headline.Medium" parent="TextAppearance.MaterialComponents.Headline1">
|
||||||
<item name="fontFamily">sans-serif-medium</item>
|
<item name="fontFamily">sans-serif-medium</item>
|
||||||
<item name="android:fontFamily">sans-serif-medium</item>
|
<item name="android:fontFamily">sans-serif-medium</item>
|
||||||
|
@ -43,7 +43,6 @@ internal class RoomChildRelationInfo(
|
|||||||
data class SpaceChildInfo(
|
data class SpaceChildInfo(
|
||||||
val roomId: String,
|
val roomId: String,
|
||||||
val order: String?,
|
val order: String?,
|
||||||
// val autoJoin: Boolean,
|
|
||||||
val viaServers: List<String>
|
val viaServers: List<String>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -60,18 +59,13 @@ internal class RoomChildRelationInfo(
|
|||||||
fun getDirectChildrenDescriptions(): List<SpaceChildInfo> {
|
fun getDirectChildrenDescriptions(): List<SpaceChildInfo> {
|
||||||
return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_CHILD)
|
return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_CHILD)
|
||||||
.findAll()
|
.findAll()
|
||||||
// .also {
|
|
||||||
// Timber.v("## Space: Found ${it.count()} m.space.child state events for $roomId")
|
|
||||||
// }
|
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
ContentMapper.map(it.root?.content).toModel<SpaceChildContent>()?.let { scc ->
|
ContentMapper.map(it.root?.content).toModel<SpaceChildContent>()?.let { scc ->
|
||||||
// Timber.v("## Space child desc state event $scc")
|
|
||||||
// Children where via is not present are ignored.
|
// Children where via is not present are ignored.
|
||||||
scc.via?.let { via ->
|
scc.via?.let { via ->
|
||||||
SpaceChildInfo(
|
SpaceChildInfo(
|
||||||
roomId = it.stateKey,
|
roomId = it.stateKey,
|
||||||
order = scc.validOrder(),
|
order = scc.validOrder(),
|
||||||
// autoJoin = scc.autoJoin ?: false,
|
|
||||||
viaServers = via
|
viaServers = via
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -83,17 +77,13 @@ internal class RoomChildRelationInfo(
|
|||||||
fun getParentDescriptions(): List<SpaceParentInfo> {
|
fun getParentDescriptions(): List<SpaceParentInfo> {
|
||||||
return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_PARENT)
|
return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_PARENT)
|
||||||
.findAll()
|
.findAll()
|
||||||
// .also {
|
|
||||||
// Timber.v("## Space: Found ${it.count()} m.space.parent state events for $roomId")
|
|
||||||
// }
|
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
ContentMapper.map(it.root?.content).toModel<SpaceParentContent>()?.let { scc ->
|
ContentMapper.map(it.root?.content).toModel<SpaceParentContent>()?.let { spaceParentContent ->
|
||||||
// Timber.v("## Space parent desc state event $scc")
|
|
||||||
// Parent where via is not present are ignored.
|
// Parent where via is not present are ignored.
|
||||||
scc.via?.let { via ->
|
spaceParentContent.via?.let { via ->
|
||||||
SpaceParentInfo(
|
SpaceParentInfo(
|
||||||
roomId = it.stateKey,
|
roomId = it.stateKey,
|
||||||
canonical = scc.canonical ?: false,
|
canonical = spaceParentContent.canonical ?: false,
|
||||||
viaServers = via,
|
viaServers = via,
|
||||||
stateEventSender = it.root?.sender ?: ""
|
stateEventSender = it.root?.sender ?: ""
|
||||||
)
|
)
|
||||||
|
@ -36,6 +36,7 @@ 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
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
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.session.room.model.RoomType
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.SpaceParentInfo
|
||||||
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.spaceSummaryQueryParams
|
import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||||
@ -193,6 +194,18 @@ internal class RoomSummaryDataSource @Inject constructor(
|
|||||||
}
|
}
|
||||||
val dataSourceFactory = realmDataSourceFactory.map {
|
val dataSourceFactory = realmDataSourceFactory.map {
|
||||||
roomSummaryMapper.map(it)
|
roomSummaryMapper.map(it)
|
||||||
|
}.map { roomSummary ->
|
||||||
|
val parents = roomSummary.flattenParentIds.mapNotNull { parentId ->
|
||||||
|
getRoomSummary(parentId)?.let { parentSummary ->
|
||||||
|
SpaceParentInfo(
|
||||||
|
parentId = parentSummary.flattenParentIds.firstOrNull(),
|
||||||
|
roomSummary = parentSummary,
|
||||||
|
canonical = true,
|
||||||
|
viaServers = emptyList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
roomSummary.copy(spaceParents = parents)
|
||||||
}
|
}
|
||||||
|
|
||||||
val boundaries = MutableLiveData(ResultBoundaries())
|
val boundaries = MutableLiveData(ResultBoundaries())
|
||||||
|
@ -18,7 +18,7 @@ ext.versionMinor = 4
|
|||||||
// Note: even values are reserved for regular release, odd values for hotfix release.
|
// Note: even values are reserved for regular release, odd values for hotfix release.
|
||||||
// When creating a hotfix, you should decrease the value, since the current value
|
// When creating a hotfix, you should decrease the value, since the current value
|
||||||
// is the value for the next regular release.
|
// is the value for the next regular release.
|
||||||
ext.versionPatch = 16
|
ext.versionPatch = 17
|
||||||
|
|
||||||
static def getGitTimestamp() {
|
static def getGitTimestamp() {
|
||||||
def cmd = 'git show -s --format=%ct'
|
def cmd = 'git show -s --format=%ct'
|
||||||
@ -262,7 +262,7 @@ android {
|
|||||||
|
|
||||||
dimension "store"
|
dimension "store"
|
||||||
isDefault = true
|
isDefault = true
|
||||||
versionName "${versionMajor}.${versionMinor}.${versionPatch}${getGplayVersionSuffix()}"
|
versionName "${versionMajor}.${versionMinor}.${versionPatch}-experiment-spaceSwitching"
|
||||||
|
|
||||||
resValue "bool", "isGplay", "true"
|
resValue "bool", "isGplay", "true"
|
||||||
buildConfigField "boolean", "ALLOW_FCM_USE", "true"
|
buildConfigField "boolean", "ALLOW_FCM_USE", "true"
|
||||||
@ -273,7 +273,7 @@ android {
|
|||||||
fdroid {
|
fdroid {
|
||||||
dimension "store"
|
dimension "store"
|
||||||
|
|
||||||
versionName "${versionMajor}.${versionMinor}.${versionPatch}${getFdroidVersionSuffix()}"
|
versionName "${versionMajor}.${versionMinor}.${versionPatch}-experiment-spaceSwitching"
|
||||||
|
|
||||||
resValue "bool", "isGplay", "false"
|
resValue "bool", "isGplay", "false"
|
||||||
buildConfigField "boolean", "ALLOW_FCM_USE", "false"
|
buildConfigField "boolean", "ALLOW_FCM_USE", "false"
|
||||||
|
25
vector/src/main/java/im/vector/app/SessionVariables.kt
Normal file
25
vector/src/main/java/im/vector/app/SessionVariables.kt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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
|
||||||
|
|
||||||
|
class SessionVariables {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
var optionsMenuShouldShow = true
|
||||||
|
}
|
||||||
|
}
|
@ -46,6 +46,7 @@ import androidx.viewbinding.ViewBinding
|
|||||||
import com.airbnb.mvrx.MavericksView
|
import com.airbnb.mvrx.MavericksView
|
||||||
import com.bumptech.glide.util.Util
|
import com.bumptech.glide.util.Util
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
import com.google.android.material.color.MaterialColors
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.hilt.android.EntryPointAccessors
|
import dagger.hilt.android.EntryPointAccessors
|
||||||
@ -238,6 +239,14 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
|||||||
|
|
||||||
initUiAndData()
|
initUiAndData()
|
||||||
|
|
||||||
|
try {
|
||||||
|
val toolbarBackground = MaterialColors.getColor(views.root, R.attr.vctr_toolbar_background)
|
||||||
|
window.statusBarColor = toolbarBackground
|
||||||
|
window.navigationBarColor = toolbarBackground
|
||||||
|
} catch (e: Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
val titleRes = getTitleRes()
|
val titleRes = getTitleRes()
|
||||||
if (titleRes != -1) {
|
if (titleRes != -1) {
|
||||||
supportActionBar?.let {
|
supportActionBar?.let {
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.analytics.experiment
|
||||||
|
|
||||||
|
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||||
|
|
||||||
|
data class ExperimentInteraction(
|
||||||
|
/**
|
||||||
|
* The unique name of this element.
|
||||||
|
*/
|
||||||
|
val name: Name,
|
||||||
|
|
||||||
|
val extra: Map<String, Any> = emptyMap()
|
||||||
|
) : VectorAnalyticsEvent {
|
||||||
|
|
||||||
|
enum class Name {
|
||||||
|
SpaceSwitchHeader,
|
||||||
|
SpaceSwitchHeaderAdd,
|
||||||
|
SpaceSwitchHeaderCreate,
|
||||||
|
SpacePanelSwitchSpace
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName() = "Interaction"
|
||||||
|
|
||||||
|
override fun getProperties(): Map<String, Any>? {
|
||||||
|
return mutableMapOf<String, Any>().apply {
|
||||||
|
put("name", name.name)
|
||||||
|
putAll(extra)
|
||||||
|
}.takeIf { it.isNotEmpty() }
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.app.features.home
|
package im.vector.app.features.home
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@ -73,6 +74,15 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
fun render(matrixItem: MatrixItem, context: Context, imageView: ImageView) {
|
||||||
|
render(
|
||||||
|
GlideApp.with(context),
|
||||||
|
matrixItem,
|
||||||
|
DrawableImageViewTarget(imageView)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// fun renderSpace(matrixItem: MatrixItem, imageView: ImageView) {
|
// fun renderSpace(matrixItem: MatrixItem, imageView: ImageView) {
|
||||||
// renderSpace(
|
// renderSpace(
|
||||||
// matrixItem,
|
// matrixItem,
|
||||||
|
@ -37,6 +37,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.AppStateHandler
|
import im.vector.app.AppStateHandler
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.SessionVariables
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.extensions.hideKeyboard
|
import im.vector.app.core.extensions.hideKeyboard
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
@ -190,7 +191,7 @@ class HomeActivity :
|
|||||||
views.drawerLayout.addDrawerListener(drawerListener)
|
views.drawerLayout.addDrawerListener(drawerListener)
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
replaceFragment(views.homeDetailFragmentContainer, HomeDetailFragment::class.java)
|
replaceFragment(views.homeDetailFragmentContainer, HomeDetailFragment::class.java)
|
||||||
replaceFragment(views.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
|
// replaceFragment(views.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedActionViewModel
|
sharedActionViewModel
|
||||||
@ -243,7 +244,7 @@ class HomeActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun openGroup(shouldClearFragment: Boolean) {
|
private fun openGroup(shouldClearFragment: Boolean) {
|
||||||
views.drawerLayout.closeDrawer(GravityCompat.START)
|
// views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
|
|
||||||
// When switching from space to group or group to space, we need to reload the fragment
|
// When switching from space to group or group to space, we need to reload the fragment
|
||||||
if (shouldClearFragment) {
|
if (shouldClearFragment) {
|
||||||
@ -270,7 +271,7 @@ class HomeActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun closeGroup() {
|
private fun closeGroup() {
|
||||||
views.drawerLayout.openDrawer(GravityCompat.START)
|
// views.drawerLayout.openDrawer(GravityCompat.START)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleShowAnalyticsOptIn() {
|
private fun handleShowAnalyticsOptIn() {
|
||||||
@ -520,11 +521,15 @@ class HomeActivity :
|
|||||||
override fun getMenuRes() = R.menu.home
|
override fun getMenuRes() = R.menu.home
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||||
menu.findItem(R.id.menu_home_init_sync_legacy).isVisible = vectorPreferences.developerMode()
|
menu.findItem(R.id.menu_home_init_sync_legacy)?.isVisible = vectorPreferences.developerMode()
|
||||||
menu.findItem(R.id.menu_home_init_sync_optimized).isVisible = vectorPreferences.developerMode()
|
menu.findItem(R.id.menu_home_init_sync_optimized)?.isVisible = vectorPreferences.developerMode()
|
||||||
return super.onPrepareOptionsMenu(menu)
|
return super.onPrepareOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
return if (SessionVariables.optionsMenuShouldShow) super.onCreateOptionsMenu(menu) else false
|
||||||
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.menu_home_suggestion -> {
|
R.id.menu_home_suggestion -> {
|
||||||
|
@ -19,11 +19,14 @@ package im.vector.app.features.home
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.DecelerateInterpolator
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.airbnb.mvrx.activityViewModel
|
import com.airbnb.mvrx.activityViewModel
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
@ -31,6 +34,7 @@ import com.google.android.material.badge.BadgeDrawable
|
|||||||
import im.vector.app.AppStateHandler
|
import im.vector.app.AppStateHandler
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.RoomGroupingMethod
|
import im.vector.app.RoomGroupingMethod
|
||||||
|
import im.vector.app.SessionVariables
|
||||||
import im.vector.app.core.extensions.commitTransaction
|
import im.vector.app.core.extensions.commitTransaction
|
||||||
import im.vector.app.core.extensions.toMvRxBundle
|
import im.vector.app.core.extensions.toMvRxBundle
|
||||||
import im.vector.app.core.platform.OnBackPressed
|
import im.vector.app.core.platform.OnBackPressed
|
||||||
@ -41,6 +45,7 @@ import im.vector.app.core.ui.views.CurrentCallsView
|
|||||||
import im.vector.app.core.ui.views.CurrentCallsViewPresenter
|
import im.vector.app.core.ui.views.CurrentCallsViewPresenter
|
||||||
import im.vector.app.core.ui.views.KeysBackupBanner
|
import im.vector.app.core.ui.views.KeysBackupBanner
|
||||||
import im.vector.app.databinding.FragmentHomeDetailBinding
|
import im.vector.app.databinding.FragmentHomeDetailBinding
|
||||||
|
import im.vector.app.features.analytics.experiment.ExperimentInteraction
|
||||||
import im.vector.app.features.call.SharedKnownCallsViewModel
|
import im.vector.app.features.call.SharedKnownCallsViewModel
|
||||||
import im.vector.app.features.call.VectorCallActivity
|
import im.vector.app.features.call.VectorCallActivity
|
||||||
import im.vector.app.features.call.dialpad.DialPadFragment
|
import im.vector.app.features.call.dialpad.DialPadFragment
|
||||||
@ -53,12 +58,18 @@ import im.vector.app.features.popup.VerificationVectorAlert
|
|||||||
import im.vector.app.features.settings.VectorLocale
|
import im.vector.app.features.settings.VectorLocale
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS
|
import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS
|
||||||
|
import im.vector.app.features.spaces.SpaceExploreActivity
|
||||||
|
import im.vector.app.features.spaces.manage.ManageType
|
||||||
|
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
||||||
|
import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import im.vector.app.features.workers.signout.BannerState
|
import im.vector.app.features.workers.signout.BannerState
|
||||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class HomeDetailFragment @Inject constructor(
|
class HomeDetailFragment @Inject constructor(
|
||||||
@ -81,6 +92,8 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||||
private lateinit var sharedCallActionViewModel: SharedKnownCallsViewModel
|
private lateinit var sharedCallActionViewModel: SharedKnownCallsViewModel
|
||||||
|
|
||||||
|
private var isInSpace = false
|
||||||
|
|
||||||
private var hasUnreadRooms = false
|
private var hasUnreadRooms = false
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value != field) {
|
if (value != field) {
|
||||||
@ -97,16 +110,39 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
viewModel.handle(HomeDetailAction.MarkAllRoomsRead)
|
viewModel.handle(HomeDetailAction.MarkAllRoomsRead)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
R.id.menu_explore_rooms -> {
|
||||||
|
sharedActionViewModel.space.value?.let { startActivity(SpaceExploreActivity.newIntent(requireContext(), it.roomId)) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.menu_invite_people -> {
|
||||||
|
activity?.let { activity ->
|
||||||
|
sharedActionViewModel.space.value?.let { ShareSpaceBottomSheet.show(activity.supportFragmentManager, it.roomId) }
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.menu_add_rooms -> {
|
||||||
|
sharedActionViewModel.space.value?.let { startActivity(SpaceManageActivity.newIntent(requireActivity(), it.roomId, ManageType.AddRooms)) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
if (SessionVariables.optionsMenuShouldShow) super.onCreateOptionsMenu(menu, inflater) else Unit
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
withState(viewModel) { state ->
|
withState(viewModel) { state ->
|
||||||
val isRoomList = state.currentTab is HomeTab.RoomList
|
val isRoomList = state.currentTab is HomeTab.RoomList
|
||||||
menu.findItem(R.id.menu_home_mark_all_as_read).isVisible = isRoomList && hasUnreadRooms
|
menu.findItem(R.id.menu_home_mark_all_as_read)?.isVisible = isRoomList && hasUnreadRooms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menu.findItem(R.id.menu_explore_rooms)?.isVisible = isInSpace
|
||||||
|
menu.findItem(R.id.menu_invite_people)?.isVisible = isInSpace
|
||||||
|
menu.findItem(R.id.menu_add_rooms)?.isVisible = isInSpace
|
||||||
|
|
||||||
super.onPrepareOptionsMenu(menu)
|
super.onPrepareOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,8 +168,13 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
|
|
||||||
viewModel.onEach(HomeDetailViewState::roomGroupingMethod) { roomGroupingMethod ->
|
viewModel.onEach(HomeDetailViewState::roomGroupingMethod) { roomGroupingMethod ->
|
||||||
when (roomGroupingMethod) {
|
when (roomGroupingMethod) {
|
||||||
is RoomGroupingMethod.ByLegacyGroup -> onGroupChange(roomGroupingMethod.groupSummary)
|
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||||
is RoomGroupingMethod.BySpace -> onSpaceChange(roomGroupingMethod.spaceSummary)
|
onGroupChange(roomGroupingMethod.groupSummary)
|
||||||
|
}
|
||||||
|
is RoomGroupingMethod.BySpace -> {
|
||||||
|
onSpaceChange(roomGroupingMethod.spaceSummary)
|
||||||
|
sharedActionViewModel.space.value = roomGroupingMethod.spaceSummary
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,12 +182,40 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
updateUIForTab(currentTab)
|
updateUIForTab(currentTab)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.onEach(HomeDetailViewState::showDialPadTab) { showDialPadTab ->
|
views.allChatsLayout.setOnClickListener {
|
||||||
updateTabVisibilitySafely(R.id.bottom_action_dial_pad, showDialPadTab)
|
toggleModalVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
views.groupToolbarNavigateUp.setOnClickListener {
|
views.backButtonLayout.setOnClickListener {
|
||||||
navigateUpOneSpace()
|
navigateUpOneSpace()
|
||||||
|
// val currentSpace = sharedActionViewModel.space.value
|
||||||
|
// val directParent = currentSpace?.spaceParents?.firstOrNull()
|
||||||
|
// viewModel.handleSelectSpace(directParent?.roomSummary)
|
||||||
|
// sharedActionViewModel.space.value = directParent?.roomSummary
|
||||||
|
// sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup(false))
|
||||||
|
// onSpaceChange(directParent?.roomSummary)
|
||||||
|
}
|
||||||
|
|
||||||
|
views.dimView.setOnClickListener {
|
||||||
|
hideModal()
|
||||||
|
views.toolbarChevron.animate()
|
||||||
|
.rotation(0F)
|
||||||
|
.setDuration(300)
|
||||||
|
.setInterpolator(DecelerateInterpolator())
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
views.dimViewBottom.setOnClickListener {
|
||||||
|
hideModal()
|
||||||
|
views.toolbarChevron.animate()
|
||||||
|
.rotation(0F)
|
||||||
|
.setDuration(300)
|
||||||
|
.setInterpolator(DecelerateInterpolator())
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.onEach(HomeDetailViewState::showDialPadTab) { showDialPadTab ->
|
||||||
|
updateTabVisibilitySafely(R.id.bottom_action_dial_pad, showDialPadTab)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.observeViewEvents { viewEvent ->
|
viewModel.observeViewEvents { viewEvent ->
|
||||||
@ -189,6 +258,57 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
currentCallsViewPresenter.updateCall(callManager.getCurrentCall(), callManager.getCalls())
|
currentCallsViewPresenter.updateCall(callManager.getCurrentCall(), callManager.getCalls())
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observeSharedActions()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeSharedActions() = lifecycleScope.launch {
|
||||||
|
sharedActionViewModel.stream().collect { action ->
|
||||||
|
when (action) {
|
||||||
|
is HomeActivitySharedAction.OpenGroup -> hideModal()
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleModalVisibility() {
|
||||||
|
if (views.spaceModalFragment.isVisible) {
|
||||||
|
hideModal()
|
||||||
|
views.toolbarChevron.animate()
|
||||||
|
.rotation(0F)
|
||||||
|
.setDuration(300)
|
||||||
|
.setInterpolator(DecelerateInterpolator())
|
||||||
|
.start()
|
||||||
|
} else {
|
||||||
|
val extraProperties = if (getCurrentSpace() != null) {
|
||||||
|
mapOf("isSubspace" to true)
|
||||||
|
} else {
|
||||||
|
mapOf("isSubspace" to false)
|
||||||
|
}
|
||||||
|
analyticsTracker.capture(ExperimentInteraction(ExperimentInteraction.Name.SpaceSwitchHeader, extraProperties))
|
||||||
|
showModal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showModal() {
|
||||||
|
SessionVariables.optionsMenuShouldShow = false
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
views.spaceModalFragment.isVisible = true
|
||||||
|
views.dimView.isVisible = true
|
||||||
|
views.dimViewBottom.isVisible = true
|
||||||
|
views.toolbarChevron.animate()
|
||||||
|
.rotation(90F)
|
||||||
|
.setDuration(300)
|
||||||
|
.setInterpolator(DecelerateInterpolator())
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideModal() {
|
||||||
|
SessionVariables.optionsMenuShouldShow = true
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
views.spaceModalFragment.isVisible = false
|
||||||
|
views.dimView.isVisible = false
|
||||||
|
views.dimViewBottom.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateUpOneSpace() {
|
private fun navigateUpOneSpace() {
|
||||||
@ -283,24 +403,45 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onGroupChange(groupSummary: GroupSummary?) {
|
private fun onGroupChange(groupSummary: GroupSummary?) {
|
||||||
|
hideModal()
|
||||||
if (groupSummary == null) {
|
if (groupSummary == null) {
|
||||||
|
views.backButtonLayout.isVisible = false
|
||||||
views.groupToolbarSpaceTitleView.isVisible = false
|
views.groupToolbarSpaceTitleView.isVisible = false
|
||||||
|
views.groupToolbarSpaceTitleView.text = getString(R.string.all_chats)
|
||||||
|
views.groupToolbarTitleView.text = getString(R.string.all_chats)
|
||||||
} else {
|
} else {
|
||||||
|
views.backButtonLayout.isVisible = true
|
||||||
views.groupToolbarSpaceTitleView.isVisible = true
|
views.groupToolbarSpaceTitleView.isVisible = true
|
||||||
views.groupToolbarSpaceTitleView.text = groupSummary.displayName
|
views.groupToolbarSpaceTitleView.text = groupSummary.displayName
|
||||||
|
views.groupToolbarTitleView.text = groupSummary.displayName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onSpaceChange(spaceSummary: RoomSummary?) {
|
private fun onSpaceChange(spaceSummary: RoomSummary?) {
|
||||||
|
hideModal()
|
||||||
|
views.backButtonText.text = getString(R.string.all_chats)
|
||||||
|
views.toolbarChevron.rotation = 0F
|
||||||
if (spaceSummary == null) {
|
if (spaceSummary == null) {
|
||||||
|
isInSpace = false
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
views.backButtonLayout.isVisible = false
|
||||||
views.groupToolbarSpaceTitleView.isVisible = false
|
views.groupToolbarSpaceTitleView.isVisible = false
|
||||||
views.groupToolbarAvatarImageView.isVisible = true
|
views.groupToolbarSpaceTitleView.text = getString(R.string.all_chats)
|
||||||
views.groupToolbarNavigateUp.isVisible = false
|
views.groupToolbarTitleView.text = getString(R.string.all_chats)
|
||||||
|
views.spaceAvatar.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
|
isInSpace = true
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
views.backButtonLayout.isVisible = true
|
||||||
views.groupToolbarSpaceTitleView.isVisible = true
|
views.groupToolbarSpaceTitleView.isVisible = true
|
||||||
views.groupToolbarSpaceTitleView.text = spaceSummary.displayName
|
views.groupToolbarSpaceTitleView.text = spaceSummary.displayName
|
||||||
views.groupToolbarAvatarImageView.isVisible = false
|
views.groupToolbarTitleView.text = spaceSummary.displayName
|
||||||
views.groupToolbarNavigateUp.isVisible = true
|
views.spaceAvatar.isVisible = true
|
||||||
|
avatarRenderer.render(spaceSummary.toMatrixItem(), requireContext(), views.spaceAvatar)
|
||||||
|
|
||||||
|
spaceSummary.spaceParents?.firstOrNull()?.let { directParent ->
|
||||||
|
views.backButtonText.text = directParent.roomSummary?.name ?: getString(R.string.all_chats)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,20 +470,20 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
sharedActionViewModel.post(HomeActivitySharedAction.OpenDrawer)
|
sharedActionViewModel.post(HomeActivitySharedAction.OpenDrawer)
|
||||||
}
|
}
|
||||||
|
|
||||||
views.homeToolbarContent.debouncedClicks {
|
// views.homeToolbarContent.debouncedClicks {
|
||||||
withState(viewModel) {
|
// withState(viewModel) {
|
||||||
when (it.roomGroupingMethod) {
|
// when (it.roomGroupingMethod) {
|
||||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
// is RoomGroupingMethod.ByLegacyGroup -> {
|
||||||
// do nothing
|
// // do nothing
|
||||||
}
|
// }
|
||||||
is RoomGroupingMethod.BySpace -> {
|
// is RoomGroupingMethod.BySpace -> {
|
||||||
it.roomGroupingMethod.spaceSummary?.let { spaceSummary ->
|
// it.roomGroupingMethod.spaceSummary?.let { spaceSummary ->
|
||||||
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(spaceSummary.roomId))
|
// sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(spaceSummary.roomId))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupBottomNavigationView() {
|
private fun setupBottomNavigationView() {
|
||||||
@ -361,7 +502,6 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
|
|
||||||
private fun updateUIForTab(tab: HomeTab) {
|
private fun updateUIForTab(tab: HomeTab) {
|
||||||
views.bottomNavigationView.menu.findItem(tab.toMenuId()).isChecked = true
|
views.bottomNavigationView.menu.findItem(tab.toMenuId()).isChecked = true
|
||||||
views.groupToolbarTitleView.setText(tab.titleRes)
|
|
||||||
updateSelectedFragment(tab)
|
updateSelectedFragment(tab)
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
@ -375,7 +515,9 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
childFragmentManager.fragments
|
childFragmentManager.fragments
|
||||||
.filter { it != fragmentToShow }
|
.filter { it != fragmentToShow }
|
||||||
.forEach {
|
.forEach {
|
||||||
detach(it)
|
if (it.id != R.id.space_modal_fragment) {
|
||||||
|
detach(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (fragmentToShow == null) {
|
if (fragmentToShow == null) {
|
||||||
when (tab) {
|
when (tab) {
|
||||||
|
@ -29,6 +29,10 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
|
|||||||
import im.vector.app.core.extensions.singletonEntryPoint
|
import im.vector.app.core.extensions.singletonEntryPoint
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.features.VectorOverrides
|
import im.vector.app.features.VectorOverrides
|
||||||
|
import im.vector.app.features.analytics.AnalyticsTracker
|
||||||
|
import im.vector.app.features.analytics.extensions.toAnalyticsViewRoom
|
||||||
|
import im.vector.app.features.analytics.plan.Interaction
|
||||||
|
import im.vector.app.features.analytics.plan.ViewRoom
|
||||||
import im.vector.app.features.call.dialpad.DialPadLookup
|
import im.vector.app.features.call.dialpad.DialPadLookup
|
||||||
import im.vector.app.features.call.lookup.CallProtocolsChecker
|
import im.vector.app.features.call.lookup.CallProtocolsChecker
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
@ -36,7 +40,10 @@ import im.vector.app.features.createdirect.DirectRoomHelper
|
|||||||
import im.vector.app.features.invite.AutoAcceptInvites
|
import im.vector.app.features.invite.AutoAcceptInvites
|
||||||
import im.vector.app.features.invite.showInvites
|
import im.vector.app.features.invite.showInvites
|
||||||
import im.vector.app.features.settings.VectorDataStore
|
import im.vector.app.features.settings.VectorDataStore
|
||||||
|
import im.vector.app.features.spaces.SpaceListAction
|
||||||
|
import im.vector.app.features.spaces.SpaceListViewEvents
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
|
import im.vector.app.space
|
||||||
import im.vector.lib.core.utils.flow.throttleFirst
|
import im.vector.lib.core.utils.flow.throttleFirst
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
@ -52,6 +59,7 @@ import org.matrix.android.sdk.api.session.crypto.NewSessionListener
|
|||||||
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
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.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.roomSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
import org.matrix.android.sdk.flow.flow
|
import org.matrix.android.sdk.flow.flow
|
||||||
@ -70,7 +78,8 @@ class HomeDetailViewModel @AssistedInject constructor(
|
|||||||
private val directRoomHelper: DirectRoomHelper,
|
private val directRoomHelper: DirectRoomHelper,
|
||||||
private val appStateHandler: AppStateHandler,
|
private val appStateHandler: AppStateHandler,
|
||||||
private val autoAcceptInvites: AutoAcceptInvites,
|
private val autoAcceptInvites: AutoAcceptInvites,
|
||||||
private val vectorOverrides: VectorOverrides
|
private val vectorOverrides: VectorOverrides,
|
||||||
|
private val analyticsTracker: AnalyticsTracker
|
||||||
) : VectorViewModel<HomeDetailViewState, HomeDetailAction, HomeDetailViewEvents>(initialState),
|
) : VectorViewModel<HomeDetailViewState, HomeDetailAction, HomeDetailViewEvents>(initialState),
|
||||||
CallProtocolsChecker.Listener {
|
CallProtocolsChecker.Listener {
|
||||||
|
|
||||||
@ -215,8 +224,26 @@ class HomeDetailViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun handleSelectSpace(space: RoomSummary?) {
|
||||||
|
appStateHandler.setCurrentSpace(space?.roomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun trackSpaceSwitch(){
|
||||||
|
when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||||
|
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||||
|
// TODO!!
|
||||||
|
}
|
||||||
|
is RoomGroupingMethod.BySpace -> {
|
||||||
|
groupingMethod.spaceSummary.toAnalyticsViewRoom(null, groupingMethod).let {
|
||||||
|
analyticsTracker.capture(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun observeRoomSummaries() {
|
private fun observeRoomSummaries() {
|
||||||
appStateHandler.selectedRoomGroupingFlow.distinctUntilChanged().flatMapLatest {
|
appStateHandler.selectedRoomGroupingFlow.distinctUntilChanged().flatMapLatest {
|
||||||
|
trackSpaceSwitch()
|
||||||
// we use it as a trigger to all changes in room, but do not really load
|
// we use it as a trigger to all changes in room, but do not really load
|
||||||
// the actual models
|
// the actual models
|
||||||
session.roomService().getPagedRoomSummariesLive(
|
session.roomService().getPagedRoomSummariesLive(
|
||||||
|
@ -16,8 +16,13 @@
|
|||||||
|
|
||||||
package im.vector.app.features.home
|
package im.vector.app.features.home
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import im.vector.app.core.platform.VectorSharedActionViewModel
|
import im.vector.app.core.platform.VectorSharedActionViewModel
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class HomeSharedActionViewModel @Inject constructor(val session: Session) : VectorSharedActionViewModel<HomeActivitySharedAction>()
|
class HomeSharedActionViewModel @Inject constructor(val session: Session) : VectorSharedActionViewModel<HomeActivitySharedAction>() {
|
||||||
|
|
||||||
|
val space = MutableLiveData<RoomSummary?>()
|
||||||
|
}
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.home
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.ListItemInviteBinding
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
|
||||||
|
class InvitesAdapter(
|
||||||
|
private val avatarRenderer: AvatarRenderer,
|
||||||
|
private val inviteUserTask: ((String) -> String?)?,
|
||||||
|
private val onInviteClicked: ((RoomSummary) -> Unit)?,
|
||||||
|
) : RecyclerView.Adapter<InvitesAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
private val invites = mutableListOf<RoomSummary>()
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
val view = ListItemInviteBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return ViewHolder(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(invites[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = invites.size
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun updateList(invites: List<RoomSummary>) {
|
||||||
|
this.invites.clear()
|
||||||
|
this.invites.addAll(invites)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ViewHolder(private val binding: ListItemInviteBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
fun bind(invite: RoomSummary) {
|
||||||
|
avatarRenderer.render(invite.toMatrixItem(), binding.avatar)
|
||||||
|
binding.name.text = invite.name
|
||||||
|
binding.root.setOnClickListener { onInviteClicked?.invoke(invite) }
|
||||||
|
|
||||||
|
invite.inviterId?.let {
|
||||||
|
val inviterName = inviteUserTask?.invoke(it)
|
||||||
|
if (inviterName != null) {
|
||||||
|
binding.invitedBy.text = binding.root.context.getString(R.string.invited_by, inviterName)
|
||||||
|
} else {
|
||||||
|
binding.invitedBy.text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.home
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import im.vector.app.databinding.BottomSheetInvitesBinding
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
|
class InvitesBottomSheet(
|
||||||
|
private val invites: List<RoomSummary>,
|
||||||
|
private val avatarRenderer: AvatarRenderer,
|
||||||
|
private val inviteUserTask: ((String) -> String?)?,
|
||||||
|
private val onInviteClicked: ((RoomSummary) -> Unit)?
|
||||||
|
) : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: BottomSheetInvitesBinding
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
binding = BottomSheetInvitesBinding.inflate(inflater)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
setupInvitesList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupInvitesList() {
|
||||||
|
val adapter = InvitesAdapter(avatarRenderer, inviteUserTask) {
|
||||||
|
dismiss()
|
||||||
|
onInviteClicked?.invoke(it)
|
||||||
|
}
|
||||||
|
val layoutManager = LinearLayoutManager(context)
|
||||||
|
binding.invitesList.adapter = adapter
|
||||||
|
binding.invitesList.layoutManager = layoutManager
|
||||||
|
adapter.updateList(invites)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "InvitesBottomSheet"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.home
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import im.vector.app.databinding.ItemModalSpaceBinding
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
|
||||||
|
class SpaceListAdapter(
|
||||||
|
private val spaces: MutableList<RoomSummary>,
|
||||||
|
private val avatarRenderer: AvatarRenderer,
|
||||||
|
) : RecyclerView.Adapter<SpaceListAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
private var onItemClickListener: ((RoomSummary) -> Unit)? = null
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
val itemView = ItemModalSpaceBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return ViewHolder(itemView)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(spaces[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = spaces.size
|
||||||
|
|
||||||
|
fun replaceList(spaces: List<RoomSummary>) {
|
||||||
|
this.spaces.clear()
|
||||||
|
this.spaces.addAll(spaces)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOnSpaceClickListener(onClick: (space: RoomSummary) -> Unit) {
|
||||||
|
this.onItemClickListener = onClick
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ViewHolder(private val binding: ItemModalSpaceBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
fun bind(space: RoomSummary) {
|
||||||
|
avatarRenderer.render(space.toMatrixItem(), binding.avatar)
|
||||||
|
binding.name.text = space.name
|
||||||
|
binding.root.setOnClickListener { onItemClickListener?.invoke(space) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.home
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.allViews
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentSpaceListModalBinding
|
||||||
|
import im.vector.app.features.analytics.experiment.ExperimentInteraction
|
||||||
|
import im.vector.app.features.analytics.plan.Interaction
|
||||||
|
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
import im.vector.app.features.spaces.SpaceListAction
|
||||||
|
import im.vector.app.features.spaces.SpaceListViewModel
|
||||||
|
import im.vector.app.features.spaces.manage.ManageType
|
||||||
|
import im.vector.app.features.spaces.manage.SpaceManageActivity
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class SpaceListModalFragment : VectorBaseFragment<FragmentSpaceListModalBinding>() {
|
||||||
|
|
||||||
|
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var avatarRenderer: AvatarRenderer
|
||||||
|
|
||||||
|
private lateinit var binding: FragmentSpaceListModalBinding
|
||||||
|
|
||||||
|
private val viewModel: SpaceListViewModel by fragmentViewModel()
|
||||||
|
|
||||||
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSpaceListModalBinding {
|
||||||
|
binding = FragmentSpaceListModalBinding.inflate(inflater)
|
||||||
|
return binding
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||||
|
setupRecyclerView()
|
||||||
|
setupTopBar()
|
||||||
|
setupAddSpace()
|
||||||
|
setupInvites()
|
||||||
|
observeSpaceChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupRecyclerView() {
|
||||||
|
binding.roomList.layoutManager = LinearLayoutManager(context)
|
||||||
|
binding.roomList.adapter = SpaceListAdapter(mutableListOf(), avatarRenderer).apply {
|
||||||
|
setOnSpaceClickListener { spaceSummary ->
|
||||||
|
viewModel.handle(SpaceListAction.SelectSpace(spaceSummary))
|
||||||
|
sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupTopBar() {
|
||||||
|
if (!binding.roomList.canScrollVertically(-1)) {
|
||||||
|
binding.headerBottomShadow.isVisible = false
|
||||||
|
binding.addSpaceTopShadow.isVisible = false
|
||||||
|
binding.addSpaceTopDivider.isVisible = true
|
||||||
|
} else {
|
||||||
|
binding.headerBottomShadow.isVisible = true
|
||||||
|
binding.addSpaceTopShadow.isVisible = true
|
||||||
|
binding.addSpaceTopDivider.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupAddSpace() {
|
||||||
|
binding.addSpaceLayout.setOnClickListener {
|
||||||
|
val currentSpace = sharedActionViewModel.space.value
|
||||||
|
if (currentSpace != null) {
|
||||||
|
analyticsTracker.capture(ExperimentInteraction(ExperimentInteraction.Name.SpaceSwitchHeaderAdd))
|
||||||
|
startActivity(SpaceManageActivity.newIntent(requireActivity(), currentSpace.roomId, ManageType.AddRoomsOnlySpaces))
|
||||||
|
} else {
|
||||||
|
analyticsTracker.capture(ExperimentInteraction(ExperimentInteraction.Name.SpaceSwitchHeaderCreate))
|
||||||
|
sharedActionViewModel.post(HomeActivitySharedAction.AddSpace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupInvites() {
|
||||||
|
binding.invitesGroup.referencedIds.map { binding.root.findViewById<View>(it) }.forEach {
|
||||||
|
it.setOnClickListener {
|
||||||
|
withState(viewModel) { state ->
|
||||||
|
val invitesBottomSheet = InvitesBottomSheet(state.inviteSpaces.orEmpty(), avatarRenderer, state.inviteUserTask) { invite ->
|
||||||
|
sharedActionViewModel.post(HomeActivitySharedAction.OpenSpaceInvite(invite.roomId))
|
||||||
|
}
|
||||||
|
invitesBottomSheet.show(requireActivity().supportFragmentManager, InvitesBottomSheet.TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeSpaceChange() = sharedActionViewModel.space.observe(viewLifecycleOwner) {
|
||||||
|
viewModel.setSpace(it)
|
||||||
|
binding.headerText.isVisible = it == null
|
||||||
|
binding.headerTextLayout.isVisible = binding.headerText.isVisible || binding.invitesGroup.isVisible
|
||||||
|
binding.addSpaceText.setText(if (it == null) R.string.create_space else R.string.add_space)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate() {
|
||||||
|
withState(viewModel) { state ->
|
||||||
|
state.rootSpacesOrdered?.let {
|
||||||
|
(binding.roomList.adapter as SpaceListAdapter).replaceList(it)
|
||||||
|
binding.noSpacesYetGroup.isVisible = it.isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.invitesGroup.isVisible = state.inviteCount > 0
|
||||||
|
binding.headerTextLayout.isVisible = binding.headerText.isVisible || binding.invitesGroup.isVisible
|
||||||
|
binding.counterBadge.render(UnreadCounterBadgeView.State(state.inviteCount, true))
|
||||||
|
setupTopBar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -68,7 +68,7 @@ abstract class CollapsableTypedEpoxyController<T> :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun buildModels() {
|
override fun buildModels() {
|
||||||
check(isBuildingModels()) {
|
check(isBuildingModels) {
|
||||||
("You cannot call `buildModels` directly. Call `setData` instead to trigger a model " +
|
("You cannot call `buildModels` directly. Call `setData` instead to trigger a model " +
|
||||||
"refresh with new data.")
|
"refresh with new data.")
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.isVisible = true
|
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.isVisible = true
|
||||||
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = true
|
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = true
|
||||||
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.isVisible = true
|
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.isVisible = true
|
||||||
else -> Unit // No button in this mode
|
RoomListDisplayMode.FILTERED -> Unit // No button in this mode
|
||||||
}
|
}
|
||||||
|
|
||||||
views.createChatRoomButton.debouncedClicks {
|
views.createChatRoomButton.debouncedClicks {
|
||||||
@ -237,7 +237,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.hide()
|
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.hide()
|
||||||
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.hide()
|
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.hide()
|
||||||
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.hide()
|
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.hide()
|
||||||
else -> Unit
|
RoomListDisplayMode.FILTERED -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,7 +294,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
val contentAdapter =
|
val contentAdapter =
|
||||||
when {
|
when {
|
||||||
section.livePages != null -> {
|
section.livePages != null -> {
|
||||||
pagedControllerFactory.createRoomSummaryPagedController()
|
pagedControllerFactory.createRoomSummaryPagedController(roomListParams.displayMode)
|
||||||
.also { controller ->
|
.also { controller ->
|
||||||
section.livePages.observe(viewLifecycleOwner) { pl ->
|
section.livePages.observe(viewLifecycleOwner) { pl ->
|
||||||
controller.submitList(pl)
|
controller.submitList(pl)
|
||||||
@ -316,7 +316,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
section.isExpanded.observe(viewLifecycleOwner) { _ ->
|
section.isExpanded.observe(viewLifecycleOwner) {
|
||||||
refreshCollapseStates()
|
refreshCollapseStates()
|
||||||
}
|
}
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
@ -337,14 +337,14 @@ class RoomListFragment @Inject constructor(
|
|||||||
checkEmptyState()
|
checkEmptyState()
|
||||||
}
|
}
|
||||||
observeItemCount(section, sectionAdapter)
|
observeItemCount(section, sectionAdapter)
|
||||||
section.isExpanded.observe(viewLifecycleOwner) { _ ->
|
section.isExpanded.observe(viewLifecycleOwner) {
|
||||||
refreshCollapseStates()
|
refreshCollapseStates()
|
||||||
}
|
}
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
pagedControllerFactory.createRoomSummaryListController()
|
pagedControllerFactory.createRoomSummaryListController(roomListParams.displayMode)
|
||||||
.also { controller ->
|
.also { controller ->
|
||||||
section.liveList?.observe(viewLifecycleOwner) { list ->
|
section.liveList?.observe(viewLifecycleOwner) { list ->
|
||||||
controller.setData(list)
|
controller.setData(list)
|
||||||
@ -366,7 +366,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
section.isExpanded.observe(viewLifecycleOwner) { _ ->
|
section.isExpanded.observe(viewLifecycleOwner) {
|
||||||
refreshCollapseStates()
|
refreshCollapseStates()
|
||||||
}
|
}
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
@ -402,7 +402,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.show()
|
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.show()
|
||||||
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.show()
|
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.show()
|
||||||
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.show()
|
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.show()
|
||||||
else -> Unit
|
RoomListDisplayMode.FILTERED -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -498,7 +498,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
isBigImage = true,
|
isBigImage = true,
|
||||||
message = getString(R.string.room_list_rooms_empty_body)
|
message = getString(R.string.room_list_rooms_empty_body)
|
||||||
)
|
)
|
||||||
else ->
|
RoomListDisplayMode.FILTERED ->
|
||||||
// Always display the content in this mode, because if the footer
|
// Always display the content in this mode, because if the footer
|
||||||
StateView.State.Content
|
StateView.State.Content
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import im.vector.app.core.ui.views.PresenceStateImageView
|
|||||||
import im.vector.app.core.ui.views.ShieldImageView
|
import im.vector.app.core.ui.views.ShieldImageView
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
|
import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
@ -45,48 +46,102 @@ import org.matrix.android.sdk.api.util.MatrixItem
|
|||||||
@EpoxyModelClass(layout = R.layout.item_room)
|
@EpoxyModelClass(layout = R.layout.item_room)
|
||||||
abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
||||||
|
|
||||||
@EpoxyAttribute lateinit var typingMessage: String
|
@EpoxyAttribute
|
||||||
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
lateinit var typingMessage: String
|
||||||
@EpoxyAttribute lateinit var matrixItem: MatrixItem
|
|
||||||
|
|
||||||
@EpoxyAttribute lateinit var lastFormattedEvent: EpoxyCharSequence
|
@EpoxyAttribute
|
||||||
@EpoxyAttribute lateinit var lastEventTime: String
|
lateinit var avatarRenderer: AvatarRenderer
|
||||||
@EpoxyAttribute var encryptionTrustLevel: RoomEncryptionTrustLevel? = null
|
|
||||||
@EpoxyAttribute var userPresence: UserPresence? = null
|
@EpoxyAttribute
|
||||||
@EpoxyAttribute var showPresence: Boolean = false
|
lateinit var matrixItem: MatrixItem
|
||||||
@EpoxyAttribute var izPublic: Boolean = false
|
|
||||||
@EpoxyAttribute var unreadNotificationCount: Int = 0
|
@EpoxyAttribute
|
||||||
@EpoxyAttribute var hasUnreadMessage: Boolean = false
|
var displayMode: RoomListDisplayMode = RoomListDisplayMode.PEOPLE
|
||||||
@EpoxyAttribute var hasDraft: Boolean = false
|
|
||||||
@EpoxyAttribute var showHighlighted: Boolean = false
|
@EpoxyAttribute
|
||||||
@EpoxyAttribute var hasFailedSending: Boolean = false
|
lateinit var subtitle: String
|
||||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemLongClickListener: View.OnLongClickListener? = null
|
|
||||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var itemClickListener: ClickListener? = null
|
@EpoxyAttribute
|
||||||
@EpoxyAttribute var showSelected: Boolean = false
|
lateinit var lastFormattedEvent: EpoxyCharSequence
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
lateinit var lastEventTime: String
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var encryptionTrustLevel: RoomEncryptionTrustLevel? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var userPresence: UserPresence? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var showPresence: Boolean = false
|
||||||
|
|
||||||
|
@EpoxyAttribute @JvmField
|
||||||
|
var isPublic: Boolean = false
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var unreadNotificationCount: Int = 0
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var hasUnreadMessage: Boolean = false
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var hasDraft: Boolean = false
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var showHighlighted: Boolean = false
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var hasFailedSending: Boolean = false
|
||||||
|
|
||||||
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
||||||
|
var itemLongClickListener: View.OnLongClickListener? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
||||||
|
var itemClickListener: ClickListener? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var showSelected: Boolean = false
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
super.bind(holder)
|
super.bind(holder)
|
||||||
|
|
||||||
|
renderDisplayMode(holder)
|
||||||
holder.rootView.onClick(itemClickListener)
|
holder.rootView.onClick(itemClickListener)
|
||||||
holder.rootView.setOnLongClickListener {
|
holder.rootView.setOnLongClickListener {
|
||||||
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||||
itemLongClickListener?.onLongClick(it) ?: false
|
itemLongClickListener?.onLongClick(it) ?: false
|
||||||
}
|
}
|
||||||
holder.titleView.text = matrixItem.getBestName()
|
holder.titleView.text = matrixItem.getBestName()
|
||||||
holder.lastEventTimeView.text = lastEventTime
|
|
||||||
holder.lastEventView.text = lastFormattedEvent.charSequence
|
|
||||||
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
|
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
|
||||||
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
|
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
|
||||||
holder.draftView.isVisible = hasDraft
|
holder.draftView.isVisible = hasDraft
|
||||||
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
||||||
holder.roomAvatarDecorationImageView.render(encryptionTrustLevel)
|
holder.roomAvatarDecorationImageView.render(encryptionTrustLevel)
|
||||||
holder.roomAvatarPublicDecorationImageView.isVisible = izPublic
|
holder.roomAvatarPublicDecorationImageView.isVisible = isPublic
|
||||||
holder.roomAvatarFailSendingImageView.isVisible = hasFailedSending
|
holder.roomAvatarFailSendingImageView.isVisible = hasFailedSending
|
||||||
renderSelection(holder, showSelected)
|
renderSelection(holder, showSelected)
|
||||||
holder.typingView.setTextOrHide(typingMessage)
|
|
||||||
holder.lastEventView.isInvisible = holder.typingView.isVisible
|
|
||||||
holder.roomAvatarPresenceImageView.render(showPresence, userPresence)
|
holder.roomAvatarPresenceImageView.render(showPresence, userPresence)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun renderDisplayMode(holder: Holder) = when (displayMode) {
|
||||||
|
RoomListDisplayMode.ROOMS,
|
||||||
|
RoomListDisplayMode.PEOPLE,
|
||||||
|
RoomListDisplayMode.NOTIFICATIONS -> renderForDefaultDisplayMode(holder)
|
||||||
|
RoomListDisplayMode.FILTERED -> renderForFilteredDisplayMode(holder)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderForDefaultDisplayMode(holder: Holder) {
|
||||||
|
holder.subtitleView.text = lastFormattedEvent.charSequence
|
||||||
|
holder.lastEventTimeView.text = lastEventTime
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderForFilteredDisplayMode(holder: Holder) {
|
||||||
|
holder.subtitleView.text = subtitle
|
||||||
|
holder.typingView.setTextOrHide(typingMessage)
|
||||||
|
holder.subtitleView.isInvisible = holder.typingView.isVisible
|
||||||
|
}
|
||||||
|
|
||||||
override fun unbind(holder: Holder) {
|
override fun unbind(holder: Holder) {
|
||||||
holder.rootView.setOnClickListener(null)
|
holder.rootView.setOnClickListener(null)
|
||||||
holder.rootView.setOnLongClickListener(null)
|
holder.rootView.setOnLongClickListener(null)
|
||||||
@ -110,7 +165,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
|||||||
val titleView by bind<TextView>(R.id.roomNameView)
|
val titleView by bind<TextView>(R.id.roomNameView)
|
||||||
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView)
|
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView)
|
||||||
val unreadIndentIndicator by bind<View>(R.id.roomUnreadIndicator)
|
val unreadIndentIndicator by bind<View>(R.id.roomUnreadIndicator)
|
||||||
val lastEventView by bind<TextView>(R.id.roomLastEventView)
|
val subtitleView by bind<TextView>(R.id.subtitleView)
|
||||||
val typingView by bind<TextView>(R.id.roomTypingView)
|
val typingView by bind<TextView>(R.id.roomTypingView)
|
||||||
val draftView by bind<ImageView>(R.id.roomDraftBadge)
|
val draftView by bind<ImageView>(R.id.roomDraftBadge)
|
||||||
val lastEventTimeView by bind<TextView>(R.id.roomLastEventTimeView)
|
val lastEventTimeView by bind<TextView>(R.id.roomLastEventTimeView)
|
||||||
|
@ -26,6 +26,7 @@ import im.vector.app.core.epoxy.VectorEpoxyModel
|
|||||||
import im.vector.app.core.error.ErrorFormatter
|
import im.vector.app.core.error.ErrorFormatter
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
|
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
|
||||||
import im.vector.app.features.home.room.typing.TypingHelper
|
import im.vector.app.features.home.room.typing.TypingHelper
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
@ -46,13 +47,16 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
|||||||
fun create(roomSummary: RoomSummary,
|
fun create(roomSummary: RoomSummary,
|
||||||
roomChangeMembershipStates: Map<String, ChangeMembershipState>,
|
roomChangeMembershipStates: Map<String, ChangeMembershipState>,
|
||||||
selectedRoomIds: Set<String>,
|
selectedRoomIds: Set<String>,
|
||||||
|
displayMode: RoomListDisplayMode,
|
||||||
listener: RoomListListener?): VectorEpoxyModel<*> {
|
listener: RoomListListener?): VectorEpoxyModel<*> {
|
||||||
return when (roomSummary.membership) {
|
return when (roomSummary.membership) {
|
||||||
Membership.INVITE -> {
|
Membership.INVITE -> {
|
||||||
val changeMembershipState = roomChangeMembershipStates[roomSummary.roomId] ?: ChangeMembershipState.Unknown
|
val changeMembershipState = roomChangeMembershipStates[roomSummary.roomId] ?: ChangeMembershipState.Unknown
|
||||||
createInvitationItem(roomSummary, changeMembershipState, listener)
|
createInvitationItem(roomSummary, changeMembershipState, listener)
|
||||||
}
|
}
|
||||||
else -> createRoomItem(roomSummary, selectedRoomIds, listener?.let { it::onRoomClicked }, listener?.let { it::onRoomLongClicked })
|
else -> createRoomItem(
|
||||||
|
roomSummary, selectedRoomIds, displayMode, listener?.let { it::onRoomClicked }, listener?.let { it::onRoomLongClicked }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,9 +109,11 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
|||||||
fun createRoomItem(
|
fun createRoomItem(
|
||||||
roomSummary: RoomSummary,
|
roomSummary: RoomSummary,
|
||||||
selectedRoomIds: Set<String>,
|
selectedRoomIds: Set<String>,
|
||||||
|
displayMode: RoomListDisplayMode,
|
||||||
onClick: ((RoomSummary) -> Unit)?,
|
onClick: ((RoomSummary) -> Unit)?,
|
||||||
onLongClick: ((RoomSummary) -> Boolean)?
|
onLongClick: ((RoomSummary) -> Boolean)?
|
||||||
): VectorEpoxyModel<*> {
|
): VectorEpoxyModel<*> {
|
||||||
|
val subtitle = getSearchResultSubtitle(roomSummary)
|
||||||
val unreadCount = roomSummary.notificationCount
|
val unreadCount = roomSummary.notificationCount
|
||||||
val showHighlighted = roomSummary.highlightCount > 0
|
val showHighlighted = roomSummary.highlightCount > 0
|
||||||
val showSelected = selectedRoomIds.contains(roomSummary.roomId)
|
val showSelected = selectedRoomIds.contains(roomSummary.roomId)
|
||||||
@ -118,13 +124,16 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
|||||||
latestFormattedEvent = displayableEventFormatter.format(latestEvent, roomSummary.isDirect, roomSummary.isDirect.not())
|
latestFormattedEvent = displayableEventFormatter.format(latestEvent, roomSummary.isDirect, roomSummary.isDirect.not())
|
||||||
latestEventTime = dateFormatter.format(latestEvent.root.originServerTs, DateFormatKind.ROOM_LIST)
|
latestEventTime = dateFormatter.format(latestEvent.root.originServerTs, DateFormatKind.ROOM_LIST)
|
||||||
}
|
}
|
||||||
|
|
||||||
val typingMessage = typingHelper.getTypingMessage(roomSummary.typingUsers)
|
val typingMessage = typingHelper.getTypingMessage(roomSummary.typingUsers)
|
||||||
return RoomSummaryItem_()
|
return RoomSummaryItem_()
|
||||||
.id(roomSummary.roomId)
|
.id(roomSummary.roomId)
|
||||||
.avatarRenderer(avatarRenderer)
|
.avatarRenderer(avatarRenderer)
|
||||||
// We do not display shield in the room list anymore
|
// We do not display shield in the room list anymore
|
||||||
// .encryptionTrustLevel(roomSummary.roomEncryptionTrustLevel)
|
// .encryptionTrustLevel(roomSummary.roomEncryptionTrustLevel)
|
||||||
.izPublic(roomSummary.isPublic)
|
.displayMode(displayMode)
|
||||||
|
.subtitle(subtitle)
|
||||||
|
.isPublic(roomSummary.isPublic)
|
||||||
.showPresence(roomSummary.isDirect)
|
.showPresence(roomSummary.isDirect)
|
||||||
.userPresence(roomSummary.directUserPresence)
|
.userPresence(roomSummary.directUserPresence)
|
||||||
.matrixItem(roomSummary.toMatrixItem())
|
.matrixItem(roomSummary.toMatrixItem())
|
||||||
@ -142,4 +151,12 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
|||||||
}
|
}
|
||||||
.itemClickListener { onClick?.invoke(roomSummary) }
|
.itemClickListener { onClick?.invoke(roomSummary) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getSearchResultSubtitle(roomSummary: RoomSummary): String {
|
||||||
|
val userId = roomSummary.directUserId
|
||||||
|
val spaceName = roomSummary.spaceParents?.firstOrNull()?.roomSummary?.name
|
||||||
|
val canonicalAlias = roomSummary.canonicalAlias
|
||||||
|
|
||||||
|
return (userId ?: spaceName ?: canonicalAlias).orEmpty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,17 +16,19 @@
|
|||||||
|
|
||||||
package im.vector.app.features.home.room.list
|
package im.vector.app.features.home.room.list
|
||||||
|
|
||||||
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
class RoomSummaryListController(
|
class RoomSummaryListController(
|
||||||
private val roomSummaryItemFactory: RoomSummaryItemFactory
|
private val roomSummaryItemFactory: RoomSummaryItemFactory,
|
||||||
|
private val displayMode: RoomListDisplayMode
|
||||||
) : CollapsableTypedEpoxyController<List<RoomSummary>>() {
|
) : CollapsableTypedEpoxyController<List<RoomSummary>>() {
|
||||||
|
|
||||||
var listener: RoomListListener? = null
|
var listener: RoomListListener? = null
|
||||||
|
|
||||||
override fun buildModels(data: List<RoomSummary>?) {
|
override fun buildModels(data: List<RoomSummary>?) {
|
||||||
data?.forEach {
|
data?.forEach {
|
||||||
add(roomSummaryItemFactory.create(it, emptyMap(), emptySet(), listener))
|
add(roomSummaryItemFactory.create(it, emptyMap(), emptySet(), displayMode, listener))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,13 @@ package im.vector.app.features.home.room.list
|
|||||||
import com.airbnb.epoxy.EpoxyModel
|
import com.airbnb.epoxy.EpoxyModel
|
||||||
import com.airbnb.epoxy.paging.PagedListEpoxyController
|
import com.airbnb.epoxy.paging.PagedListEpoxyController
|
||||||
import im.vector.app.core.utils.createUIHandler
|
import im.vector.app.core.utils.createUIHandler
|
||||||
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
class RoomSummaryPagedController(
|
class RoomSummaryPagedController(
|
||||||
private val roomSummaryItemFactory: RoomSummaryItemFactory
|
private val roomSummaryItemFactory: RoomSummaryItemFactory,
|
||||||
|
private val displayMode: RoomListDisplayMode
|
||||||
) : PagedListEpoxyController<RoomSummary>(
|
) : PagedListEpoxyController<RoomSummary>(
|
||||||
// Important it must match the PageList builder notify Looper
|
// Important it must match the PageList builder notify Looper
|
||||||
modelBuildingHandler = createUIHandler()
|
modelBuildingHandler = createUIHandler()
|
||||||
@ -57,6 +59,6 @@ class RoomSummaryPagedController(
|
|||||||
override fun buildItemModel(currentPosition: Int, item: RoomSummary?): EpoxyModel<*> {
|
override fun buildItemModel(currentPosition: Int, item: RoomSummary?): EpoxyModel<*> {
|
||||||
// for place holder if enabled
|
// for place holder if enabled
|
||||||
item ?: return RoomSummaryItemPlaceHolder_().apply { id(currentPosition) }
|
item ?: return RoomSummaryItemPlaceHolder_().apply { id(currentPosition) }
|
||||||
return roomSummaryItemFactory.create(item, roomChangeMembershipStates.orEmpty(), emptySet(), listener)
|
return roomSummaryItemFactory.create(item, roomChangeMembershipStates.orEmpty(), emptySet(), displayMode, listener)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,18 +16,19 @@
|
|||||||
|
|
||||||
package im.vector.app.features.home.room.list
|
package im.vector.app.features.home.room.list
|
||||||
|
|
||||||
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class RoomSummaryPagedControllerFactory @Inject constructor(
|
class RoomSummaryPagedControllerFactory @Inject constructor(
|
||||||
private val roomSummaryItemFactory: RoomSummaryItemFactory
|
private val roomSummaryItemFactory: RoomSummaryItemFactory
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun createRoomSummaryPagedController(): RoomSummaryPagedController {
|
fun createRoomSummaryPagedController(displayMode: RoomListDisplayMode): RoomSummaryPagedController {
|
||||||
return RoomSummaryPagedController(roomSummaryItemFactory)
|
return RoomSummaryPagedController(roomSummaryItemFactory, displayMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createRoomSummaryListController(): RoomSummaryListController {
|
fun createRoomSummaryListController(displayMode: RoomListDisplayMode): RoomSummaryListController {
|
||||||
return RoomSummaryListController(roomSummaryItemFactory)
|
return RoomSummaryListController(roomSummaryItemFactory, displayMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createSuggestedRoomListController(): SuggestedRoomListController {
|
fun createSuggestedRoomListController(): SuggestedRoomListController {
|
||||||
|
@ -22,6 +22,7 @@ import im.vector.app.R
|
|||||||
import im.vector.app.core.epoxy.loadingItem
|
import im.vector.app.core.epoxy.loadingItem
|
||||||
import im.vector.app.core.epoxy.noResultItem
|
import im.vector.app.core.epoxy.noResultItem
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
import im.vector.app.features.home.room.list.RoomSummaryItemFactory
|
import im.vector.app.features.home.room.list.RoomSummaryItemFactory
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -53,7 +54,13 @@ class IncomingShareController @Inject constructor(private val roomSummaryItemFac
|
|||||||
} else {
|
} else {
|
||||||
roomSummaries.forEach { roomSummary ->
|
roomSummaries.forEach { roomSummary ->
|
||||||
roomSummaryItemFactory
|
roomSummaryItemFactory
|
||||||
.createRoomItem(roomSummary, data.selectedRoomIds, callback?.let { it::onRoomClicked }, callback?.let { it::onRoomLongClicked })
|
.createRoomItem(
|
||||||
|
roomSummary,
|
||||||
|
data.selectedRoomIds,
|
||||||
|
RoomListDisplayMode.FILTERED,
|
||||||
|
callback?.let { it::onRoomClicked },
|
||||||
|
callback?.let { it::onRoomLongClicked }
|
||||||
|
)
|
||||||
.addTo(this)
|
.addTo(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,19 +76,16 @@ class SpaceListFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDragReleased(model: SpaceSummaryItem?, itemView: View?) {
|
override fun onDragReleased(model: SpaceSummaryItem?, itemView: View?) {
|
||||||
// Timber.v("VAL: onModelMoved from $fromPositionM to $toPositionM ${model?.matrixItem?.getBestName()}")
|
|
||||||
if (toPositionM == null || fromPositionM == null) return
|
if (toPositionM == null || fromPositionM == null) return
|
||||||
val movingSpace = model?.matrixItem?.id ?: return
|
val movingSpace = model?.matrixItem?.id ?: return
|
||||||
viewModel.handle(SpaceListAction.MoveSpace(movingSpace, toPositionM!! - fromPositionM!!))
|
viewModel.handle(SpaceListAction.MoveSpace(movingSpace, toPositionM!! - fromPositionM!!))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clearView(model: SpaceSummaryItem?, itemView: View?) {
|
override fun clearView(model: SpaceSummaryItem?, itemView: View?) {
|
||||||
// Timber.v("VAL: clearView ${model?.matrixItem?.getBestName()}")
|
|
||||||
itemView?.elevation = initialElevation ?: 0f
|
itemView?.elevation = initialElevation ?: 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onModelMoved(fromPosition: Int, toPosition: Int, modelBeingMoved: SpaceSummaryItem?, itemView: View?) {
|
override fun onModelMoved(fromPosition: Int, toPosition: Int, modelBeingMoved: SpaceSummaryItem?, itemView: View?) {
|
||||||
// Timber.v("VAL: onModelMoved incremental from $fromPosition to $toPosition ${modelBeingMoved?.matrixItem?.getBestName()}")
|
|
||||||
if (fromPositionM == null) {
|
if (fromPositionM == null) {
|
||||||
fromPositionM = fromPosition
|
fromPositionM = fromPosition
|
||||||
}
|
}
|
||||||
@ -97,7 +94,6 @@ class SpaceListFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isDragEnabledForModel(model: SpaceSummaryItem?): Boolean {
|
override fun isDragEnabledForModel(model: SpaceSummaryItem?): Boolean {
|
||||||
// Timber.v("VAL: isDragEnabledForModel ${model?.matrixItem?.getBestName()}")
|
|
||||||
return model?.canDrag == true
|
return model?.canDrag == true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package im.vector.app.features.spaces
|
package im.vector.app.features.spaces
|
||||||
|
|
||||||
import androidx.lifecycle.asFlow
|
import androidx.lifecycle.asFlow
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.Loading
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
@ -29,7 +30,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
|||||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.features.analytics.AnalyticsTracker
|
import im.vector.app.features.analytics.AnalyticsTracker
|
||||||
import im.vector.app.features.analytics.plan.Interaction
|
import im.vector.app.features.analytics.experiment.ExperimentInteraction
|
||||||
import im.vector.app.features.invite.AutoAcceptInvites
|
import im.vector.app.features.invite.AutoAcceptInvites
|
||||||
import im.vector.app.features.session.coroutineScope
|
import im.vector.app.features.session.coroutineScope
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
@ -50,10 +51,12 @@ import org.matrix.android.sdk.api.session.Session
|
|||||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.getRoom
|
import org.matrix.android.sdk.api.session.getRoom
|
||||||
|
import org.matrix.android.sdk.api.session.getUser
|
||||||
import org.matrix.android.sdk.api.session.group.groupSummaryQueryParams
|
import org.matrix.android.sdk.api.session.group.groupSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||||
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
|
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
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.roomSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams
|
import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||||
@ -71,6 +74,8 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
|
|||||||
private val analyticsTracker: AnalyticsTracker
|
private val analyticsTracker: AnalyticsTracker
|
||||||
) : VectorViewModel<SpaceListViewState, SpaceListAction, SpaceListViewEvents>(initialState) {
|
) : VectorViewModel<SpaceListViewState, SpaceListAction, SpaceListViewEvents>(initialState) {
|
||||||
|
|
||||||
|
private var currentSpace: RoomSummary? = null
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
interface Factory : MavericksAssistedViewModelFactory<SpaceListViewModel, SpaceListViewState> {
|
interface Factory : MavericksAssistedViewModelFactory<SpaceListViewModel, SpaceListViewState> {
|
||||||
override fun create(initialState: SpaceListViewState): SpaceListViewModel
|
override fun create(initialState: SpaceListViewState): SpaceListViewModel
|
||||||
@ -138,7 +143,7 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
|
|||||||
)
|
)
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
homeAggregateCount = counts
|
homeAggregateCount = counts,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,14 +234,13 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
|
|||||||
|
|
||||||
private fun handleSelectSpace(action: SpaceListAction.SelectSpace) = withState { state ->
|
private fun handleSelectSpace(action: SpaceListAction.SelectSpace) = withState { state ->
|
||||||
val groupingMethod = state.selectedGroupingMethod
|
val groupingMethod = state.selectedGroupingMethod
|
||||||
|
val isAtSpace = groupingMethod.space() != null
|
||||||
if (groupingMethod is RoomGroupingMethod.ByLegacyGroup || groupingMethod.space()?.roomId != action.spaceSummary?.roomId) {
|
if (groupingMethod is RoomGroupingMethod.ByLegacyGroup || groupingMethod.space()?.roomId != action.spaceSummary?.roomId) {
|
||||||
analyticsTracker.capture(Interaction(null, null, Interaction.Name.SpacePanelSwitchSpace))
|
|
||||||
setState { copy(selectedGroupingMethod = RoomGroupingMethod.BySpace(action.spaceSummary)) }
|
setState { copy(selectedGroupingMethod = RoomGroupingMethod.BySpace(action.spaceSummary)) }
|
||||||
appStateHandler.setCurrentSpace(action.spaceSummary?.roomId)
|
appStateHandler.setCurrentSpace(action.spaceSummary?.roomId)
|
||||||
_viewEvents.post(SpaceListViewEvents.OpenSpace(groupingMethod is RoomGroupingMethod.ByLegacyGroup))
|
_viewEvents.post(SpaceListViewEvents.OpenSpace(groupingMethod is RoomGroupingMethod.ByLegacyGroup))
|
||||||
} else {
|
|
||||||
analyticsTracker.capture(Interaction(null, null, Interaction.Name.SpacePanelSelectedSpace))
|
|
||||||
}
|
}
|
||||||
|
analyticsTracker.capture(ExperimentInteraction(ExperimentInteraction.Name.SpacePanelSwitchSpace, mapOf("isSubspace" to isAtSpace)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSelectGroup(action: SpaceListAction.SelectLegacyGroup) = withState { state ->
|
private fun handleSelectGroup(action: SpaceListAction.SelectLegacyGroup) = withState { state ->
|
||||||
@ -273,36 +277,43 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
|
|||||||
_viewEvents.post(SpaceListViewEvents.AddSpace)
|
_viewEvents.post(SpaceListViewEvents.AddSpace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var asyncSpaceList: Async<List<RoomSummary>>? = null
|
||||||
|
|
||||||
private fun observeSpaceSummaries() {
|
private fun observeSpaceSummaries() {
|
||||||
val params = spaceSummaryQueryParams {
|
val params = spaceSummaryQueryParams {
|
||||||
memberships = listOf(Membership.JOIN, Membership.INVITE)
|
memberships = listOf(Membership.JOIN, Membership.INVITE)
|
||||||
displayName = QueryStringValue.IsNotEmpty
|
displayName = QueryStringValue.IsNotEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
combine(
|
combine(session.flow().liveSpaceSummaries(params),
|
||||||
session.flow()
|
|
||||||
.liveSpaceSummaries(params),
|
|
||||||
session.accountDataService()
|
session.accountDataService()
|
||||||
.getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER))
|
.getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER))
|
||||||
.asFlow()
|
.asFlow()
|
||||||
) { spaces, _ ->
|
) { spaces, _ -> spaces }.execute { async ->
|
||||||
spaces
|
asyncSpaceList = async
|
||||||
|
val currentSpaceChildren = currentSpace?.let { space -> async.invoke()?.filter { it.flattenParentIds.contains(space.roomId) } }
|
||||||
|
val rootSpaces = async.invoke().orEmpty().filter { it.flattenParentIds.isEmpty() }
|
||||||
|
val displaySpaces = (currentSpaceChildren ?: rootSpaces).filter { it.inviterId == null }
|
||||||
|
val inviteSpaces = (currentSpaceChildren ?: rootSpaces).filter { it.inviterId != null }
|
||||||
|
val inviteUserTask: (String) -> String? = {
|
||||||
|
session.getUser(it)?.displayName
|
||||||
|
}
|
||||||
|
val orders = displaySpaces.associate {
|
||||||
|
it.roomId to session.getRoom(it.roomId)
|
||||||
|
?.roomAccountDataService()
|
||||||
|
?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)
|
||||||
|
?.content.toModel<SpaceOrderContent>()
|
||||||
|
?.safeOrder()
|
||||||
|
}
|
||||||
|
copy(
|
||||||
|
asyncSpaces = async,
|
||||||
|
rootSpacesOrdered = displaySpaces.sortedWith(TopLevelSpaceComparator(orders)),
|
||||||
|
inviteSpaces = inviteSpaces.sortedWith(TopLevelSpaceComparator(orders)),
|
||||||
|
inviteCount = inviteSpaces.size,
|
||||||
|
inviteUserTask = inviteUserTask,
|
||||||
|
spaceOrderInfo = orders
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.execute { async ->
|
|
||||||
val rootSpaces = async.invoke().orEmpty().filter { it.flattenParentIds.isEmpty() }
|
|
||||||
val orders = rootSpaces.associate {
|
|
||||||
it.roomId to session.getRoom(it.roomId)
|
|
||||||
?.roomAccountDataService()
|
|
||||||
?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)
|
|
||||||
?.content.toModel<SpaceOrderContent>()
|
|
||||||
?.safeOrder()
|
|
||||||
}
|
|
||||||
copy(
|
|
||||||
asyncSpaces = async,
|
|
||||||
rootSpacesOrdered = rootSpaces.sortedWith(TopLevelSpaceComparator(orders)),
|
|
||||||
spaceOrderInfo = orders
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear local echos on update
|
// clear local echos on update
|
||||||
session.accountDataService()
|
session.accountDataService()
|
||||||
@ -314,4 +325,36 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun emitSpaceViewState() = asyncSpaceList?.let { async ->
|
||||||
|
val currentSpaceChildren = currentSpace?.let { space -> asyncSpaceList?.invoke()?.filter { it.flattenParentIds.contains(space.roomId) } }
|
||||||
|
val rootSpaces = asyncSpaceList?.invoke().orEmpty().filter { it.flattenParentIds.isEmpty() }
|
||||||
|
val displaySpaces = (currentSpaceChildren ?: rootSpaces).filter { it.inviterId == null }
|
||||||
|
val inviteSpaces = (currentSpaceChildren ?: rootSpaces).filter { it.inviterId != null }
|
||||||
|
val inviteUserTask: (String) -> String? = {
|
||||||
|
session.getUser(it)?.displayName
|
||||||
|
}
|
||||||
|
val orders = displaySpaces.associate {
|
||||||
|
it.roomId to session.getRoom(it.roomId)
|
||||||
|
?.roomAccountDataService()
|
||||||
|
?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)
|
||||||
|
?.content.toModel<SpaceOrderContent>()
|
||||||
|
?.safeOrder()
|
||||||
|
}
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncSpaces = async,
|
||||||
|
rootSpacesOrdered = displaySpaces.sortedWith(TopLevelSpaceComparator(orders)),
|
||||||
|
inviteSpaces = inviteSpaces.sortedWith(TopLevelSpaceComparator(orders)),
|
||||||
|
inviteCount = inviteSpaces.size,
|
||||||
|
inviteUserTask = inviteUserTask,
|
||||||
|
spaceOrderInfo = orders
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSpace(space: RoomSummary?) {
|
||||||
|
this.currentSpace = space
|
||||||
|
emitSpaceViewState()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,12 @@ data class SpaceListViewState(
|
|||||||
val asyncSpaces: Async<List<RoomSummary>> = Uninitialized,
|
val asyncSpaces: Async<List<RoomSummary>> = Uninitialized,
|
||||||
val selectedGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
|
val selectedGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
|
||||||
val rootSpacesOrdered: List<RoomSummary>? = null,
|
val rootSpacesOrdered: List<RoomSummary>? = null,
|
||||||
|
val inviteSpaces: List<RoomSummary>? = null,
|
||||||
val spaceOrderInfo: Map<String, String?>? = null,
|
val spaceOrderInfo: Map<String, String?>? = null,
|
||||||
val spaceOrderLocalEchos: Map<String, String?>? = null,
|
val spaceOrderLocalEchos: Map<String, String?>? = null,
|
||||||
val legacyGroups: List<GroupSummary>? = null,
|
val legacyGroups: List<GroupSummary>? = null,
|
||||||
val expandedStates: Map<String, Boolean> = emptyMap(),
|
val expandedStates: Map<String, Boolean> = emptyMap(),
|
||||||
|
val inviteCount: Int = 0,
|
||||||
|
val inviteUserTask: ((String) -> String?)? = null,
|
||||||
val homeAggregateCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0)
|
val homeAggregateCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0)
|
||||||
) : MavericksState
|
) : MavericksState
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.airbnb.epoxy.EpoxyController
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
|
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.genericHeaderItem
|
||||||
|
import im.vector.app.features.grouplist.groupSummaryItem
|
||||||
|
import im.vector.app.features.grouplist.homeSpaceSummaryItem
|
||||||
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
import im.vector.app.group
|
||||||
|
import im.vector.app.space
|
||||||
|
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
|
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.toMatrixItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SpaceModalController @Inject constructor(
|
||||||
|
private val avatarRenderer: AvatarRenderer,
|
||||||
|
// private val colorProvider: ColorProvider,
|
||||||
|
// private val stringProvider: StringProvider
|
||||||
|
) : EpoxyController() {
|
||||||
|
|
||||||
|
var callback: Callback? = null
|
||||||
|
private var viewState: SpaceListViewState? = null
|
||||||
|
|
||||||
|
fun update(viewState: SpaceListViewState) {
|
||||||
|
this.viewState = viewState
|
||||||
|
requestModelBuild()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildModels() {
|
||||||
|
viewState?.apply {
|
||||||
|
buildGroupModels(selectedGroupingMethod, rootSpacesOrdered, expandedStates)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildGroupModels(selected: RoomGroupingMethod,
|
||||||
|
rootSpaces: List<RoomSummary>?,
|
||||||
|
expandedStates: Map<String, Boolean>) {
|
||||||
|
val host = this
|
||||||
|
|
||||||
|
rootSpaces?.forEach { spaceSummary ->
|
||||||
|
val isSelected = selected is RoomGroupingMethod.BySpace && spaceSummary.roomId == selected.space()?.roomId
|
||||||
|
val expanded = expandedStates[spaceSummary.roomId] == true
|
||||||
|
|
||||||
|
spaceSummaryItem {
|
||||||
|
avatarRenderer(host.avatarRenderer)
|
||||||
|
id(spaceSummary.roomId)
|
||||||
|
expanded(expanded)
|
||||||
|
matrixItem(spaceSummary.toMatrixItem())
|
||||||
|
selected(isSelected)
|
||||||
|
canDrag(true)
|
||||||
|
listener { host.callback?.onSpaceSelected(spaceSummary) }
|
||||||
|
countState(
|
||||||
|
UnreadCounterBadgeView.State(
|
||||||
|
spaceSummary.notificationCount,
|
||||||
|
spaceSummary.highlightCount > 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onSpaceSelected(spaceSummary: RoomSummary?)
|
||||||
|
}
|
||||||
|
}
|
12
vector/src/main/res/drawable/bg_modal_ripple_grey.xml
Normal file
12
vector/src/main/res/drawable/bg_modal_ripple_grey.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:color="?attr/vctr_content_secondary">
|
||||||
|
|
||||||
|
<item android:drawable="@color/modal_background_color"/>
|
||||||
|
|
||||||
|
<!--this creates the mask with the ripple effect-->
|
||||||
|
<item
|
||||||
|
android:id="@+id/mask"
|
||||||
|
android:drawable="?attr/vctr_toolbar_background" />
|
||||||
|
|
||||||
|
</ripple>
|
7
vector/src/main/res/drawable/bg_space_modal.xml
Normal file
7
vector/src/main/res/drawable/bg_space_modal.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="?attr/vctr_toolbar_background"/>
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="12dp"
|
||||||
|
android:bottomRightRadius="12dp" />
|
||||||
|
</shape>
|
10
vector/src/main/res/drawable/ic_plus.xml
Normal file
10
vector/src/main/res/drawable/ic_plus.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12.7822,4.2963C12.7822,3.8641 12.4318,3.5137 11.9996,3.5137C11.5673,3.5137 11.217,3.8641 11.217,4.2963V11.2173L4.2963,11.2173C3.8641,11.2173 3.5137,11.5676 3.5137,11.9999C3.5137,12.4321 3.8641,12.7825 4.2963,12.7825H11.217V19.7038C11.217,20.136 11.5673,20.4864 11.9996,20.4864C12.4318,20.4864 12.7822,20.136 12.7822,19.7038V12.7825H19.7038C20.136,12.7825 20.4864,12.4321 20.4864,11.9999C20.4864,11.5676 20.136,11.2173 19.7038,11.2173L12.7822,11.2173V4.2963Z"
|
||||||
|
android:fillColor="#17191C"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
</vector>
|
10
vector/src/main/res/drawable/ripple_grey.xml
Normal file
10
vector/src/main/res/drawable/ripple_grey.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:color="?attr/vctr_content_secondary">
|
||||||
|
|
||||||
|
<!--this creates the mask with the ripple effect-->
|
||||||
|
<item
|
||||||
|
android:id="@+id/mask"
|
||||||
|
android:drawable="?attr/vctr_toolbar_background" />
|
||||||
|
|
||||||
|
</ripple>
|
7
vector/src/main/res/drawable/top_shadow.xml
Normal file
7
vector/src/main/res/drawable/top_shadow.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<gradient
|
||||||
|
android:startColor="#10000000"
|
||||||
|
android:endColor="@android:color/transparent"
|
||||||
|
android:angle="90" />
|
||||||
|
</shape>
|
@ -22,10 +22,4 @@
|
|||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
</androidx.drawerlayout.widget.DrawerLayout>
|
||||||
android:id="@+id/homeDrawerFragmentContainer"
|
|
||||||
android:layout_width="@dimen/navigation_drawer_max_width"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="start" />
|
|
||||||
|
|
||||||
</androidx.drawerlayout.widget.DrawerLayout>
|
|
||||||
|
32
vector/src/main/res/layout/bottom_sheet_invites.xml
Normal file
32
vector/src/main/res/layout/bottom_sheet_invites.xml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="360dp"
|
||||||
|
android:background="?attr/vctr_toolbar_background"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/invites_header"
|
||||||
|
style="@style/Widget.Vector.TextView.Title.Medium"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/space_invites"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/invites_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/invites_header"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
tools:listitem="@layout/list_item_invite"
|
||||||
|
tools:itemCount="3"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -9,6 +9,7 @@
|
|||||||
android:id="@+id/appBarLayout"
|
android:id="@+id/appBarLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
app:elevation="0dp"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<im.vector.app.core.ui.views.CurrentCallsView
|
<im.vector.app.core.ui.views.CurrentCallsView
|
||||||
@ -18,19 +19,64 @@
|
|||||||
android:minHeight="48dp"
|
android:minHeight="48dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintTop_toBottomOf="@id/homeKeysBackupBanner"
|
app:layout_constraintTop_toBottomOf="@id/homeKeysBackupBanner"
|
||||||
tools:visibility="visible" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/groupToolbar"
|
android:id="@+id/groupToolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:baselineAligned="false"
|
android:baselineAligned="false"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="start"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
tools:ignore="UselessParent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textAppearance="@style/TextAppearance.Vector.Widget.ActionBarTitle"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/groupToolbarSpaceTitleView"
|
||||||
|
style="@style/TextAppearance.Vector.Widget.ActionBarSubTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="@tools:sample/lorem/random"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/homeToolbarContent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/groupToolbarAvatarImageView"
|
android:id="@+id/groupToolbarAvatarImageView"
|
||||||
@ -39,6 +85,7 @@
|
|||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:contentDescription="@string/a11y_open_drawer"
|
android:contentDescription="@string/a11y_open_drawer"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
@ -74,58 +121,83 @@
|
|||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<ImageView
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/groupToolbarNavigateUp"
|
android:id="@+id/back_button_layout"
|
||||||
android:layout_width="28dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="28dp"
|
|
||||||
android:src="@drawable/ic_arrow_back"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:contentDescription="@string/a11y_navigate_up_space"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:tint="?vctr_content_secondary"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:ignore="MissingPrefix" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/homeToolbarContent"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:gravity="start"
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingStart="8dp"
|
<ImageView
|
||||||
android:paddingEnd="8dp">
|
android:id="@+id/back_button_chevron"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_back_24dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:tint="?attr/vctr_message_text_color" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/back_button_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/chats"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:textColor="@color/palette_element_green"
|
||||||
|
android:textSize="17sp"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/back_button_chevron"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:id="@+id/all_chats_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/back_button_layout">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/space_avatar"
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:shapeAppearanceOverlay="@style/SpaceListModalImageShapeOverlay"
|
||||||
|
tools:background="#42A5F5"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/groupToolbarTitleView"
|
android:id="@+id/groupToolbarTitleView"
|
||||||
android:layout_width="match_parent"
|
style="@style/Widget.Vector.TextView.Title.Bold"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:gravity="start"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textAppearance="@style/TextAppearance.Vector.Widget.ActionBarTitle"
|
|
||||||
android:textColor="?vctr_content_primary"
|
|
||||||
android:textStyle="bold"
|
|
||||||
tools:text="@tools:sample/lorem/random" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/groupToolbarSpaceTitleView"
|
|
||||||
style="@style/TextAppearance.Vector.Widget.ActionBarSubTitle"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:ellipsize="end"
|
android:layout_gravity="center_vertical"
|
||||||
android:gravity="start"
|
android:layout_marginStart="4dp"
|
||||||
android:maxLines="1"
|
android:text="@string/all_chats"
|
||||||
android:textColor="?vctr_content_primary"
|
android:textSize="22sp" />
|
||||||
android:visibility="gone"
|
|
||||||
tools:text="@tools:sample/lorem/random"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
<ImageView
|
||||||
|
android:id="@+id/toolbar_chevron"
|
||||||
|
android:layout_width="12dp"
|
||||||
|
android:layout_height="12dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_arrow_right"
|
||||||
|
app:tint="@color/palette_element_green"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</com.google.android.material.appbar.MaterialToolbar>
|
</com.google.android.material.appbar.MaterialToolbar>
|
||||||
|
|
||||||
@ -149,12 +221,14 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
||||||
tools:visibility="visible" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/roomListContainer"
|
android:id="@+id/roomListContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
android:visibility="visible"
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomNavigationView"
|
app:layout_constraintBottom_toTopOf="@id/bottomNavigationView"
|
||||||
app:layout_constraintTop_toBottomOf="@id/homeKeysBackupBanner" />
|
app:layout_constraintTop_toBottomOf="@id/homeKeysBackupBanner" />
|
||||||
|
|
||||||
@ -165,6 +239,46 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:menu="@menu/home_bottom_navigation" />
|
app:menu="@menu/home_bottom_navigation"
|
||||||
|
app:labelVisibilityMode="labeled" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/dim_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:alpha="0.5"
|
||||||
|
android:background="#000"
|
||||||
|
android:elevation="0dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/bottomNavigationView"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/dim_view_bottom"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:alpha="0.5"
|
||||||
|
android:background="#000"
|
||||||
|
android:elevation="10dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/bottomNavigationView"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/bottomNavigationView" />
|
||||||
|
|
||||||
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
android:id="@+id/space_modal_fragment"
|
||||||
|
android:name="im.vector.app.features.home.SpaceListModalFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/bottom_guideline"
|
||||||
|
android:elevation="0dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline
|
||||||
|
android:id="@+id/bottom_guideline"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintGuide_percent="0.75" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
188
vector/src/main/res/layout/fragment_space_list_modal.xml
Normal file
188
vector/src/main/res/layout/fragment_space_list_modal.xml
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
<?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:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/bg_space_modal">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/header_text_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:background="?attr/vctr_toolbar_background"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/header_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textColor="?attr/vctr_content_tertiary"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="@string/choose_a_space"
|
||||||
|
android:textAllCaps="true" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Group
|
||||||
|
android:id="@+id/invites_group"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:constraint_referenced_ids="invites_text, counter_badge"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/invites_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textColor="?attr/vctr_content_tertiary"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@string/invites"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/counter_badge" />
|
||||||
|
|
||||||
|
<im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
android:id="@+id/counter_badge"
|
||||||
|
style="@style/Widget.Vector.TextView.Micro"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:minWidth="16dp"
|
||||||
|
android:minHeight="16dp"
|
||||||
|
android:paddingStart="4dp"
|
||||||
|
android:paddingEnd="4dp"
|
||||||
|
android:textColor="?colorOnError"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/invites_text"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/invites_text"
|
||||||
|
tools:background="@drawable/bg_unread_highlight"
|
||||||
|
tools:text="147" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/room_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/header_text_layout"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/add_space_layout"
|
||||||
|
tools:itemCount="3"
|
||||||
|
tools:layout_editor_absoluteX="-99dp"
|
||||||
|
tools:listitem="@layout/item_modal_space"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/header_bottom_shadow"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:background="@drawable/top_shadow"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:rotation="180"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/header_text_layout" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Group
|
||||||
|
android:id="@+id/no_spaces_yet_group"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:constraint_referenced_ids="no_spaces_yet_text, no_spaces_yet_message" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/no_spaces_yet_text"
|
||||||
|
style="@style/Widget.Vector.TextView.Title.Medium"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/no_spaces_yet"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/header_text_layout"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/no_spaces_yet_message"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/no_spaces_yet_message"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:text="@string/no_spaces_yet_message"
|
||||||
|
android:textColor="?attr/vctr_content_tertiary"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/no_spaces_yet_text"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/add_space_layout"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/add_space_top_shadow"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:background="@drawable/top_shadow"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/add_space_layout" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/add_space_top_divider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?attr/vctr_content_quinary"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/add_space_layout" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/add_space_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_modal_ripple_grey"
|
||||||
|
android:elevation="3dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/add_space_icon_background"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:background="#4D8D97A5"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:shapeAppearanceOverlay="@style/SpaceListModalImageShapeOverlay" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_plus"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/add_space_icon_background"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/add_space_icon_background"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/add_space_icon_background"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/add_space_icon_background"
|
||||||
|
app:tint="?attr/vctr_spoiler_background_color" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/add_space_text"
|
||||||
|
style="@style/Widget.Vector.TextView.Body.Medium"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="@string/add_space"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textColor="?attr/vctr_message_text_color"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/add_space_icon_background"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/add_space_icon_background"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/add_space_icon_background" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/add_space_icon_background" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -36,13 +36,13 @@
|
|||||||
android:textColor="?vctr_content_primary"
|
android:textColor="?vctr_content_primary"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@id/groupBottomSeparator"
|
app:layout_constraintBottom_toTopOf="@id/groupBottomSeparator"
|
||||||
app:layout_constraintEnd_toStartOf="@id/groupAvatarChevron"
|
app:layout_constraintEnd_toStartOf="@id/chevron"
|
||||||
app:layout_constraintStart_toEndOf="@id/groupAvatarImageView"
|
app:layout_constraintStart_toEndOf="@id/groupAvatarImageView"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/groupAvatarChevron"
|
android:id="@+id/chevron"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="21dp"
|
android:layout_marginEnd="21dp"
|
||||||
|
65
vector/src/main/res/layout/item_modal_space.xml
Normal file
65
vector/src/main/res/layout/item_modal_space.xml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?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:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/ripple_grey"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="12dp">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/avatar"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:shapeAppearanceOverlay="@style/SpaceListModalImageShapeOverlay"
|
||||||
|
tools:background="#42A5F5" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name"
|
||||||
|
style="@style/Widget.Vector.TextView.Body.Medium"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:textSize="17sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/avatar"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/avatar"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/avatar"
|
||||||
|
tools:text="Space name" />
|
||||||
|
|
||||||
|
<im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
android:id="@+id/counter_badge"
|
||||||
|
style="@style/Widget.Vector.TextView.Micro"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:minWidth="16dp"
|
||||||
|
android:minHeight="16dp"
|
||||||
|
android:paddingStart="4dp"
|
||||||
|
android:paddingEnd="4dp"
|
||||||
|
android:textColor="?colorOnError"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/chevron"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
tools:background="@drawable/bg_unread_highlight"
|
||||||
|
tools:text="147"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/chevron"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_arrow_right"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:tint="?vctr_content_primary"
|
||||||
|
tools:ignore="MissingPrefix" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -183,7 +183,7 @@
|
|||||||
tools:text="@tools:sample/date/hhmm" />
|
tools:text="@tools:sample/date/hhmm" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/roomLastEventView"
|
android:id="@+id/subtitleView"
|
||||||
style="@style/Widget.Vector.TextView.Body"
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -213,7 +213,8 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="@id/roomNameView"
|
app:layout_constraintStart_toStartOf="@id/roomNameView"
|
||||||
app:layout_constraintTop_toBottomOf="@id/roomNameView"
|
app:layout_constraintTop_toBottomOf="@id/roomNameView"
|
||||||
tools:text="Alice is typing…" />
|
tools:text="Alice is typing…"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<!-- Margin bottom does not work, so I use space -->
|
<!-- Margin bottom does not work, so I use space -->
|
||||||
<Space
|
<Space
|
||||||
@ -221,7 +222,7 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="7dp"
|
android:layout_height="7dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/roomLastEventView"
|
app:layout_constraintTop_toBottomOf="@id/subtitleView"
|
||||||
tools:layout_marginStart="120dp" />
|
tools:layout_marginStart="120dp" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
<androidx.constraintlayout.widget.Barrier
|
||||||
|
@ -120,12 +120,12 @@
|
|||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:src="@drawable/ic_more_vertical"
|
android:src="@drawable/ic_more_vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/groupAvatarChevron"
|
app:layout_constraintEnd_toStartOf="@id/chevron"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:tint="?vctr_content_secondary" />
|
app:tint="?vctr_content_secondary" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/groupAvatarChevron"
|
android:id="@+id/chevron"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="21dp"
|
android:layout_marginEnd="21dp"
|
||||||
|
@ -101,12 +101,12 @@
|
|||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:src="@drawable/ic_more_vertical"
|
android:src="@drawable/ic_more_vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/groupAvatarChevron"
|
app:layout_constraintEnd_toStartOf="@id/chevron"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:tint="?vctr_content_secondary" />
|
app:tint="?vctr_content_secondary" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/groupAvatarChevron"
|
android:id="@+id/chevron"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="21dp"
|
android:layout_marginEnd="21dp"
|
||||||
|
45
vector/src/main/res/layout/list_item_invite.xml
Normal file
45
vector/src/main/res/layout/list_item_invite.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:background="@drawable/ripple_grey"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/avatar"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@sample/space_avatars"
|
||||||
|
android:layout_marginStart="16dp" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
style="@style/Widget.Vector.TextView.Body.Medium"
|
||||||
|
android:id="@+id/name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/avatar"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/invited_by"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/avatar"
|
||||||
|
app:layout_constraintVertical_chainStyle="spread_inside"
|
||||||
|
tools:text="Element Corp."/>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
|
android:id="@+id/invited_by"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="?attr/vctr_content_secondary"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/name"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/avatar"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/name"
|
||||||
|
tools:text="Invited by John from Cornwall"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -7,26 +7,31 @@
|
|||||||
android:id="@+id/menu_home_setting"
|
android:id="@+id/menu_home_setting"
|
||||||
android:icon="@drawable/ic_settings_x"
|
android:icon="@drawable/ic_settings_x"
|
||||||
android:title="@string/settings"
|
android:title="@string/settings"
|
||||||
|
android:orderInCategory="100"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_home_suggestion"
|
android:id="@+id/menu_home_suggestion"
|
||||||
android:icon="@drawable/ic_material_bug_report"
|
android:icon="@drawable/ic_material_bug_report"
|
||||||
|
android:orderInCategory="110"
|
||||||
android:title="@string/send_suggestion" />
|
android:title="@string/send_suggestion" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_home_report_bug"
|
android:id="@+id/menu_home_report_bug"
|
||||||
android:icon="@drawable/ic_material_bug_report"
|
android:icon="@drawable/ic_material_bug_report"
|
||||||
|
android:orderInCategory="120"
|
||||||
android:title="@string/send_bug_report" />
|
android:title="@string/send_bug_report" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_home_init_sync_legacy"
|
android:id="@+id/menu_home_init_sync_legacy"
|
||||||
android:title="Do a legacy init sync"
|
android:title="Do a legacy init sync"
|
||||||
|
android:orderInCategory="130"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_home_init_sync_optimized"
|
android:id="@+id/menu_home_init_sync_optimized"
|
||||||
android:title="Do an optimized init sync"
|
android:title="Do an optimized init sync"
|
||||||
|
android:orderInCategory="140"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
|
@ -1,9 +1,29 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_home_mark_all_as_read"
|
android:id="@+id/menu_home_mark_all_as_read"
|
||||||
android:icon="@drawable/ic_material_done"
|
android:icon="@drawable/ic_material_done"
|
||||||
|
android:orderInCategory="50"
|
||||||
android:title="@string/action_mark_all_as_read" />
|
android:title="@string/action_mark_all_as_read" />
|
||||||
|
|
||||||
</menu>
|
<item
|
||||||
|
android:id="@+id/menu_explore_rooms"
|
||||||
|
android:title="@string/space_explore_activity_title"
|
||||||
|
android:orderInCategory="10"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_invite_people"
|
||||||
|
android:title="@string/invite_people_menu"
|
||||||
|
android:orderInCategory="20"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_add_rooms"
|
||||||
|
android:title="@string/space_add_child_title"
|
||||||
|
android:orderInCategory="30"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
</menu>
|
||||||
|
@ -620,8 +620,6 @@
|
|||||||
<string name="room_participants_leave_prompt_msg">Are you sure you want to leave the room?</string>
|
<string name="room_participants_leave_prompt_msg">Are you sure you want to leave the room?</string>
|
||||||
<string name="room_participants_leave_private_warning">This room is not public. You will not be able to rejoin without an invite.</string>
|
<string name="room_participants_leave_private_warning">This room is not public. You will not be able to rejoin without an invite.</string>
|
||||||
|
|
||||||
<string name="room_participants_header_direct_chats">Direct Messages</string>
|
|
||||||
|
|
||||||
<string name="room_participants_action_invite">Invite</string>
|
<string name="room_participants_action_invite">Invite</string>
|
||||||
<string name="room_participants_action_cancel_invite">Cancel invite</string>
|
<string name="room_participants_action_cancel_invite">Cancel invite</string>
|
||||||
<string name="room_participants_action_ban">Ban</string>
|
<string name="room_participants_action_ban">Ban</string>
|
||||||
@ -897,7 +895,6 @@
|
|||||||
|
|
||||||
<string name="settings_messages_containing_display_name">My display name</string>
|
<string name="settings_messages_containing_display_name">My display name</string>
|
||||||
<string name="settings_messages_containing_username">My username</string>
|
<string name="settings_messages_containing_username">My username</string>
|
||||||
<string name="settings_messages_direct_messages">Direct messages</string>
|
|
||||||
<string name="settings_encrypted_direct_messages">Encrypted direct messages</string>
|
<string name="settings_encrypted_direct_messages">Encrypted direct messages</string>
|
||||||
<string name="settings_group_messages">Group messages</string>
|
<string name="settings_group_messages">Group messages</string>
|
||||||
<string name="settings_encrypted_group_messages">Encrypted group messages</string>
|
<string name="settings_encrypted_group_messages">Encrypted group messages</string>
|
||||||
@ -1607,7 +1604,6 @@
|
|||||||
<string name="room_preview_not_found">This room is not accessible at this time.\nTry again later, or ask a room admin to check if you have access.</string>
|
<string name="room_preview_not_found">This room is not accessible at this time.\nTry again later, or ask a room admin to check if you have access.</string>
|
||||||
<string name="room_preview_no_preview_join">"This room can't be previewed. Do you want to join it?"</string>
|
<string name="room_preview_no_preview_join">"This room can't be previewed. Do you want to join it?"</string>
|
||||||
<string name="fab_menu_create_room">"Rooms"</string>
|
<string name="fab_menu_create_room">"Rooms"</string>
|
||||||
<string name="fab_menu_create_chat">"Direct Messages"</string>
|
|
||||||
|
|
||||||
<!-- Create room screen -->
|
<!-- Create room screen -->
|
||||||
<string name="create_room_action_create">"CREATE"</string>
|
<string name="create_room_action_create">"CREATE"</string>
|
||||||
@ -1680,7 +1676,11 @@
|
|||||||
<string name="settings_labs_show_hidden_events_in_timeline">Show hidden events in timeline</string>
|
<string name="settings_labs_show_hidden_events_in_timeline">Show hidden events in timeline</string>
|
||||||
<string name="settings_labs_show_complete_history_in_encrypted_room">"Show complete history in encrypted rooms"</string>
|
<string name="settings_labs_show_complete_history_in_encrypted_room">"Show complete history in encrypted rooms"</string>
|
||||||
|
|
||||||
<string name="bottom_action_people_x">Direct Messages</string>
|
<string name="fab_menu_create_chat">"Direct Messages"</string>
|
||||||
|
<string name="room_participants_header_direct_chats">Direct Messages</string>
|
||||||
|
|
||||||
|
<string name="bottom_action_people_x">People</string>
|
||||||
|
<string name="settings_messages_direct_messages">Direct messages</string>
|
||||||
|
|
||||||
<string name="send_file_step_idle">Waiting…</string>
|
<string name="send_file_step_idle">Waiting…</string>
|
||||||
<string name="send_file_step_encrypting_thumbnail">Encrypting thumbnail…</string>
|
<string name="send_file_step_encrypting_thumbnail">Encrypting thumbnail…</string>
|
||||||
@ -3042,4 +3042,13 @@
|
|||||||
<!-- Screen sharing -->
|
<!-- Screen sharing -->
|
||||||
<string name="screen_sharing_notification_title">${app_name} Screen Sharing</string>
|
<string name="screen_sharing_notification_title">${app_name} Screen Sharing</string>
|
||||||
<string name="screen_sharing_notification_description">Screen sharing is in progress</string>
|
<string name="screen_sharing_notification_description">Screen sharing is in progress</string>
|
||||||
|
<string name="all_chats">All Chats</string>
|
||||||
|
<string name="choose_a_space">Spaces</string>
|
||||||
|
<string name="invites">Invites</string>
|
||||||
|
<string name="chats">Chats</string>
|
||||||
|
<string name="no_spaces_yet">No spaces yet</string>
|
||||||
|
<string name="no_spaces_yet_message">Add spaces to group your chats</string>
|
||||||
|
<string name="no_subspaces_yet">No subspaces yet</string>
|
||||||
|
<string name="no_subspaces_yet_message">Add subspaces to group your chats</string>
|
||||||
|
<string name="space_invites">Space Invites</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user