Compare commits
7 Commits
develop
...
feature/ad
Author | SHA1 | Date |
---|---|---|
Adam Brown | 30d6654745 | |
Adam Brown | eb8931c6da | |
ganfra | ace01876dd | |
ganfra | 05d8f1b355 | |
ganfra | 45e3af9a81 | |
ganfra | 1151dca9c9 | |
ganfra | e21400a940 |
|
@ -32,6 +32,7 @@ buildscript {
|
||||||
classpath 'org.owasp:dependency-check-gradle:7.1.1'
|
classpath 'org.owasp:dependency-check-gradle:7.1.1'
|
||||||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.10"
|
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.10"
|
||||||
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"
|
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"
|
||||||
|
classpath "com.karumi:shot:5.14.1"
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,8 @@ ext.libs = [
|
||||||
'epoxyProcessor' : "com.airbnb.android:epoxy-processor:$epoxy",
|
'epoxyProcessor' : "com.airbnb.android:epoxy-processor:$epoxy",
|
||||||
'epoxyPaging' : "com.airbnb.android:epoxy-paging:$epoxy",
|
'epoxyPaging' : "com.airbnb.android:epoxy-paging:$epoxy",
|
||||||
'mavericks' : "com.airbnb.android:mavericks:$mavericks",
|
'mavericks' : "com.airbnb.android:mavericks:$mavericks",
|
||||||
|
'mavericksMocking' : "com.airbnb.android:mavericks-mocking:$mavericks",
|
||||||
|
'mavericksLauncher' : "com.airbnb.android:mavericks-launcher:$mavericks",
|
||||||
'mavericksTesting' : "com.airbnb.android:mavericks-testing:$mavericks"
|
'mavericksTesting' : "com.airbnb.android:mavericks-testing:$mavericks"
|
||||||
],
|
],
|
||||||
maplibre : [
|
maplibre : [
|
||||||
|
|
|
@ -57,6 +57,7 @@ ext.groups = [
|
||||||
'com.facebook.flipper',
|
'com.facebook.flipper',
|
||||||
'com.facebook.fresco',
|
'com.facebook.fresco',
|
||||||
'com.facebook.infer.annotation',
|
'com.facebook.infer.annotation',
|
||||||
|
'com.facebook.testing.screenshot',
|
||||||
'com.facebook.soloader',
|
'com.facebook.soloader',
|
||||||
'com.facebook.stetho',
|
'com.facebook.stetho',
|
||||||
'com.facebook.yoga',
|
'com.facebook.yoga',
|
||||||
|
@ -97,6 +98,7 @@ ext.groups = [
|
||||||
'com.ibm.icu',
|
'com.ibm.icu',
|
||||||
'com.jakewharton.android.repackaged',
|
'com.jakewharton.android.repackaged',
|
||||||
'com.jakewharton.timber',
|
'com.jakewharton.timber',
|
||||||
|
'com.karumi',
|
||||||
'com.kgurgul.flipper',
|
'com.kgurgul.flipper',
|
||||||
'com.linkedin.dexmaker',
|
'com.linkedin.dexmaker',
|
||||||
'com.mapbox.mapboxsdk',
|
'com.mapbox.mapboxsdk',
|
||||||
|
|
|
@ -37,7 +37,7 @@ import org.matrix.android.sdk.api.util.toOptional
|
||||||
|
|
||||||
typealias ThreadRootEvent = TimelineEvent
|
typealias ThreadRootEvent = TimelineEvent
|
||||||
|
|
||||||
class FlowRoom(private val room: Room) {
|
class FlowRoom(val room: Room) {
|
||||||
|
|
||||||
fun liveRoomSummary(): Flow<Optional<RoomSummary>> {
|
fun liveRoomSummary(): Flow<Optional<RoomSummary>> {
|
||||||
return room.getRoomSummaryLive().asFlow()
|
return room.getRoomSummaryLive().asFlow()
|
||||||
|
|
|
@ -9,6 +9,7 @@ apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'com.likethesalad.stem'
|
apply plugin: 'com.likethesalad.stem'
|
||||||
apply plugin: 'dagger.hilt.android.plugin'
|
apply plugin: 'dagger.hilt.android.plugin'
|
||||||
apply plugin: 'kotlinx-knit'
|
apply plugin: 'kotlinx-knit'
|
||||||
|
apply plugin: 'shot'
|
||||||
|
|
||||||
if (project.hasProperty("coverage")) {
|
if (project.hasProperty("coverage")) {
|
||||||
apply plugin: 'jacoco'
|
apply plugin: 'jacoco'
|
||||||
|
@ -156,7 +157,8 @@ android {
|
||||||
buildConfigField "String", "GIT_BRANCH_NAME", "\"${gitBranchName()}\""
|
buildConfigField "String", "GIT_BRANCH_NAME", "\"${gitBranchName()}\""
|
||||||
buildConfigField "String", "BUILD_NUMBER", "\"${buildNumber}\""
|
buildConfigField "String", "BUILD_NUMBER", "\"${buildNumber}\""
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
// testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
testInstrumentationRunner "com.karumi.shot.ShotTestRunner"
|
||||||
|
|
||||||
// Keep abiFilter for the universalApk
|
// Keep abiFilter for the universalApk
|
||||||
ndk {
|
ndk {
|
||||||
|
@ -424,6 +426,8 @@ dependencies {
|
||||||
kapt libs.airbnb.epoxyProcessor
|
kapt libs.airbnb.epoxyProcessor
|
||||||
implementation libs.airbnb.epoxyPaging
|
implementation libs.airbnb.epoxyPaging
|
||||||
implementation libs.airbnb.mavericks
|
implementation libs.airbnb.mavericks
|
||||||
|
implementation libs.airbnb.mavericksMocking
|
||||||
|
implementation libs.airbnb.mavericksLauncher
|
||||||
|
|
||||||
// Snap Helper https://github.com/rubensousa/GravitySnapHelper
|
// Snap Helper https://github.com/rubensousa/GravitySnapHelper
|
||||||
implementation 'com.github.rubensousa:gravitysnaphelper:2.2.2'
|
implementation 'com.github.rubensousa:gravitysnaphelper:2.2.2'
|
||||||
|
@ -599,5 +603,5 @@ dependencies {
|
||||||
androidTestImplementation libs.mockk.mockkAndroid
|
androidTestImplementation libs.mockk.mockkAndroid
|
||||||
androidTestUtil libs.androidx.orchestrator
|
androidTestUtil libs.androidx.orchestrator
|
||||||
debugImplementation libs.androidx.fragmentTesting
|
debugImplementation libs.androidx.fragmentTesting
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-reflect:1.7.10"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-reflect:1.6.10"
|
||||||
}
|
}
|
||||||
|
|
After Width: | Height: | Size: 178 KiB |
After Width: | Height: | Size: 192 KiB |
After Width: | Height: | Size: 184 KiB |
After Width: | Height: | Size: 260 KiB |
After Width: | Height: | Size: 180 KiB |
After Width: | Height: | Size: 181 KiB |
After Width: | Height: | Size: 178 KiB |
After Width: | Height: | Size: 192 KiB |
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* 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.screenshot
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.test.core.app.ActivityScenario
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.launcher.MavericksLauncherMockActivity
|
||||||
|
import com.airbnb.mvrx.mocking.MockableMavericksView
|
||||||
|
import com.airbnb.mvrx.mocking.getMockVariants
|
||||||
|
import com.airbnb.mvrx.mocking.mockSingleViewModel
|
||||||
|
import com.karumi.shot.ActivityScenarioUtils.waitForActivity
|
||||||
|
import com.karumi.shot.ScreenshotTest
|
||||||
|
import im.vector.app.features.roomprofile.RoomProfileFragment
|
||||||
|
import im.vector.app.features.roomprofile.mocks.mockRoomProfileArgs
|
||||||
|
import im.vector.app.features.roomprofile.mocks.mockRoomProfileViewState
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class MvRxScreenshotTest : ScreenshotTest {
|
||||||
|
|
||||||
|
private val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun defaultRoomProfileFragmentScreenshotTest() {
|
||||||
|
val mock = MockRoomProfileFragment::class.getMock("Default state")
|
||||||
|
|
||||||
|
val scenario = ActivityScenario.launch<MavericksLauncherMockActivity>(
|
||||||
|
MavericksLauncherMockActivity.intent(context, mock)
|
||||||
|
)
|
||||||
|
|
||||||
|
compareScreenshot(scenario.waitForActivity())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun anotherRoomProfileFragmentScreenshotTest() {
|
||||||
|
val mock = MockRoomProfileFragment::class.getMock("my-state")
|
||||||
|
|
||||||
|
val scenario = ActivityScenario.launch<MavericksLauncherMockActivity>(
|
||||||
|
MavericksLauncherMockActivity.intent(context, mock)
|
||||||
|
)
|
||||||
|
|
||||||
|
compareScreenshot(scenario.waitForActivity())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : MockableMavericksView> KClass<T>.getMock(name: String) = getMockVariants(this.java)!!.first { it.mock.name == name }
|
||||||
|
|
||||||
|
class MockRoomProfileFragment : RoomProfileFragment(), MockableMavericksView {
|
||||||
|
|
||||||
|
override fun provideMocks() = mockSingleViewModel(
|
||||||
|
viewModelReference = MockRoomProfileFragment::roomProfileViewModel,
|
||||||
|
defaultState = mockRoomProfileViewState,
|
||||||
|
defaultArgs = mockRoomProfileArgs,
|
||||||
|
) {
|
||||||
|
state("my-state") {
|
||||||
|
val summary = (mockRoomProfileViewState.roomSummary as Success)().copy(
|
||||||
|
displayName = "a wrong name"
|
||||||
|
)
|
||||||
|
mockRoomProfileViewState.copy(
|
||||||
|
roomSummary = Success(summary)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
registerMockPrinter()
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
<activity android:name=".features.debug.features.DebugFeaturesSettingsActivity" />
|
<activity android:name=".features.debug.features.DebugFeaturesSettingsActivity" />
|
||||||
<activity android:name=".features.debug.DebugMenuActivity" />
|
<activity android:name=".features.debug.DebugMenuActivity" />
|
||||||
<activity android:name=".features.debug.leak.DebugMemoryLeaksActivity" />
|
<activity android:name=".features.debug.leak.DebugMemoryLeaksActivity" />
|
||||||
|
<activity android:name=".features.debug.VectorLauncherMockActivity" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
|
android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
|
||||||
|
|
|
@ -24,6 +24,8 @@ import android.os.Build
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.Person
|
import androidx.core.app.Person
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
|
import com.airbnb.mvrx.launcher.MavericksLauncherActivity
|
||||||
|
import com.airbnb.mvrx.launcher.MavericksLauncherMockActivity
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
|
@ -82,6 +84,10 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupViews() {
|
private fun setupViews() {
|
||||||
|
|
||||||
|
views.debugMock.setOnClickListener {
|
||||||
|
MavericksLauncherActivity.show(this)
|
||||||
|
}
|
||||||
views.debugFeatures.setOnClickListener { startActivity(Intent(this, DebugFeaturesSettingsActivity::class.java)) }
|
views.debugFeatures.setOnClickListener { startActivity(Intent(this, DebugFeaturesSettingsActivity::class.java)) }
|
||||||
views.debugPrivateSetting.setOnClickListener { openPrivateSettings() }
|
views.debugPrivateSetting.setOnClickListener { openPrivateSettings() }
|
||||||
views.debugAnalytics.setOnClickListener {
|
views.debugAnalytics.setOnClickListener {
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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.debug
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.airbnb.mvrx.launcher.MavericksLauncherMockActivity
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.app.databinding.ActivityLauncherMockBinding
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class VectorLauncherMockActivity : VectorBaseActivity<ActivityLauncherMockBinding>() {
|
||||||
|
|
||||||
|
override fun getBinding() = ActivityLauncherMockBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
MavericksLauncherMockActivity.showNextMockFromActivity(
|
||||||
|
activity = this,
|
||||||
|
showView = { view ->
|
||||||
|
// Use commit now to catch errors on initialization.
|
||||||
|
setFragment(view as Fragment, commitNow = true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun setFragment(fragment: Fragment, commitNow: Boolean = false) {
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.container, fragment)
|
||||||
|
.setPrimaryNavigationFragment(fragment)
|
||||||
|
.apply {
|
||||||
|
if (commitNow) commitNow() else commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,12 @@
|
||||||
android:padding="@dimen/layout_horizontal_margin"
|
android:padding="@dimen/layout_horizontal_margin"
|
||||||
android:showDividers="middle">
|
android:showDividers="middle">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/debug_mock"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Mocks" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/debug_features"
|
android:id="@+id/debug_features"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
|
@ -37,6 +37,9 @@ import com.airbnb.epoxy.Carousel
|
||||||
import com.airbnb.epoxy.EpoxyAsyncUtil
|
import com.airbnb.epoxy.EpoxyAsyncUtil
|
||||||
import com.airbnb.epoxy.EpoxyController
|
import com.airbnb.epoxy.EpoxyController
|
||||||
import com.airbnb.mvrx.Mavericks
|
import com.airbnb.mvrx.Mavericks
|
||||||
|
import com.airbnb.mvrx.launcher.MavericksLauncherMockActivity
|
||||||
|
import com.airbnb.mvrx.mocking.MavericksMock
|
||||||
|
import com.airbnb.mvrx.mocking.MockableMavericks
|
||||||
import com.facebook.stetho.Stetho
|
import com.facebook.stetho.Stetho
|
||||||
import com.gabrielittner.threetenbp.LazyThreeTen
|
import com.gabrielittner.threetenbp.LazyThreeTen
|
||||||
import com.github.rubensousa.gravitysnaphelper.GravitySnapHelper
|
import com.github.rubensousa.gravitysnaphelper.GravitySnapHelper
|
||||||
|
@ -53,6 +56,7 @@ import im.vector.app.core.resources.BuildMeta
|
||||||
import im.vector.app.features.analytics.VectorAnalytics
|
import im.vector.app.features.analytics.VectorAnalytics
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
import im.vector.app.features.configuration.VectorConfiguration
|
import im.vector.app.features.configuration.VectorConfiguration
|
||||||
|
import im.vector.app.features.debug.VectorLauncherMockActivity
|
||||||
import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog
|
import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog
|
||||||
import im.vector.app.features.invite.InvitesAcceptor
|
import im.vector.app.features.invite.InvitesAcceptor
|
||||||
import im.vector.app.features.lifecycle.VectorActivityLifecycleCallbacks
|
import im.vector.app.features.lifecycle.VectorActivityLifecycleCallbacks
|
||||||
|
@ -146,7 +150,9 @@ class VectorApplication :
|
||||||
}
|
}
|
||||||
logInfo()
|
logInfo()
|
||||||
LazyThreeTen.init(this)
|
LazyThreeTen.init(this)
|
||||||
Mavericks.initialize(debugMode = false)
|
MockableMavericks.initialize(mocksEnabled = buildMeta.isDebug, debugMode = false, applicationContext = applicationContext)
|
||||||
|
MavericksLauncherMockActivity.activityToShowMock = VectorLauncherMockActivity::class
|
||||||
|
//Mavericks.initialize(debugMode = false)
|
||||||
|
|
||||||
configureEpoxy()
|
configureEpoxy()
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,6 @@ import im.vector.app.features.roomdirectory.roompreview.RoomPreviewNoPreviewFrag
|
||||||
import im.vector.app.features.roommemberprofile.RoomMemberProfileFragment
|
import im.vector.app.features.roommemberprofile.RoomMemberProfileFragment
|
||||||
import im.vector.app.features.roommemberprofile.devices.DeviceListFragment
|
import im.vector.app.features.roommemberprofile.devices.DeviceListFragment
|
||||||
import im.vector.app.features.roommemberprofile.devices.DeviceTrustInfoActionFragment
|
import im.vector.app.features.roommemberprofile.devices.DeviceTrustInfoActionFragment
|
||||||
import im.vector.app.features.roomprofile.RoomProfileFragment
|
|
||||||
import im.vector.app.features.roomprofile.alias.RoomAliasFragment
|
import im.vector.app.features.roomprofile.alias.RoomAliasFragment
|
||||||
import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment
|
import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment
|
||||||
import im.vector.app.features.roomprofile.members.RoomMemberListFragment
|
import im.vector.app.features.roomprofile.members.RoomMemberListFragment
|
||||||
|
@ -547,11 +546,6 @@ interface FragmentModule {
|
||||||
@FragmentKey(PublicRoomsFragment::class)
|
@FragmentKey(PublicRoomsFragment::class)
|
||||||
fun bindPublicRoomsFragment(fragment: PublicRoomsFragment): Fragment
|
fun bindPublicRoomsFragment(fragment: PublicRoomsFragment): Fragment
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@FragmentKey(RoomProfileFragment::class)
|
|
||||||
fun bindRoomProfileFragment(fragment: RoomProfileFragment): Fragment
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FragmentKey(RoomMemberListFragment::class)
|
@FragmentKey(RoomMemberListFragment::class)
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.airbnb.mvrx.args
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.animations.AppBarStateChangeListener
|
import im.vector.app.core.animations.AppBarStateChangeListener
|
||||||
import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
|
import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
|
||||||
|
@ -65,21 +66,22 @@ data class RoomProfileArgs(
|
||||||
val roomId: String
|
val roomId: String
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
class RoomProfileFragment @Inject constructor(
|
@AndroidEntryPoint
|
||||||
private val roomProfileController: RoomProfileController,
|
open class RoomProfileFragment :
|
||||||
private val avatarRenderer: AvatarRenderer,
|
|
||||||
private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
|
|
||||||
) :
|
|
||||||
VectorBaseFragment<FragmentMatrixProfileBinding>(),
|
VectorBaseFragment<FragmentMatrixProfileBinding>(),
|
||||||
RoomProfileController.Callback,
|
RoomProfileController.Callback,
|
||||||
VectorMenuProvider {
|
VectorMenuProvider {
|
||||||
|
|
||||||
|
@Inject lateinit var roomProfileController: RoomProfileController
|
||||||
|
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||||
|
@Inject lateinit var roomDetailPendingActionStore: RoomDetailPendingActionStore
|
||||||
|
|
||||||
private lateinit var headerViews: ViewStubRoomProfileHeaderBinding
|
private lateinit var headerViews: ViewStubRoomProfileHeaderBinding
|
||||||
|
|
||||||
private val roomProfileArgs: RoomProfileArgs by args()
|
private val roomProfileArgs: RoomProfileArgs by args()
|
||||||
private lateinit var roomListQuickActionsSharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
private lateinit var roomListQuickActionsSharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
||||||
private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
|
private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
|
||||||
private val roomProfileViewModel: RoomProfileViewModel by fragmentViewModel()
|
val roomProfileViewModel: RoomProfileViewModel by fragmentViewModel()
|
||||||
|
|
||||||
private var appBarStateChangeListener: AppBarStateChangeListener? = null
|
private var appBarStateChangeListener: AppBarStateChangeListener? = null
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
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
|
||||||
|
@ -35,11 +36,13 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
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.room.Room
|
||||||
import org.matrix.android.sdk.api.session.room.getStateEvent
|
import org.matrix.android.sdk.api.session.room.getStateEvent
|
||||||
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
@ -56,7 +59,7 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||||
@Assisted private val initialState: RoomProfileViewState,
|
@Assisted private val initialState: RoomProfileViewState,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val shortcutCreator: ShortcutCreator,
|
private val shortcutCreator: ShortcutCreator,
|
||||||
private val session: Session,
|
sessionHolder: ActiveSessionHolder,
|
||||||
private val analyticsTracker: AnalyticsTracker
|
private val analyticsTracker: AnalyticsTracker
|
||||||
) : VectorViewModel<RoomProfileViewState, RoomProfileAction, RoomProfileViewEvents>(initialState) {
|
) : VectorViewModel<RoomProfileViewState, RoomProfileAction, RoomProfileViewEvents>(initialState) {
|
||||||
|
|
||||||
|
@ -67,23 +70,27 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||||
|
|
||||||
companion object : MavericksViewModelFactory<RoomProfileViewModel, RoomProfileViewState> by hiltMavericksViewModelFactory()
|
companion object : MavericksViewModelFactory<RoomProfileViewModel, RoomProfileViewState> by hiltMavericksViewModelFactory()
|
||||||
|
|
||||||
private val room = session.getRoom(initialState.roomId)!!
|
private val session = sessionHolder.getSafeActiveSession()
|
||||||
|
private val room = session?.getRoom(initialState.roomId)
|
||||||
|
private val myUserId = session?.myUserId ?: ""
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val flowRoom = room.flow()
|
room?.also { room ->
|
||||||
observeRoomSummary(flowRoom)
|
val flowRoom = room.flow()
|
||||||
observeRoomCreateContent(flowRoom)
|
observeRoomSummary(flowRoom)
|
||||||
observeBannedRoomMembers(flowRoom)
|
observeRoomCreateContent(flowRoom)
|
||||||
observePermissions()
|
observeBannedRoomMembers(flowRoom)
|
||||||
observePowerLevels()
|
observePermissions(room)
|
||||||
|
observePowerLevels(room)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observePowerLevels() {
|
private fun observePowerLevels(room: Room) {
|
||||||
val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow()
|
val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow()
|
||||||
powerLevelsContentLive
|
powerLevelsContentLive
|
||||||
.onEach {
|
.onEach {
|
||||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||||
val canUpdateRoomState = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
val canUpdateRoomState = powerLevelsHelper.isUserAllowedToSend(myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
||||||
setState {
|
setState {
|
||||||
copy(canUpdateRoomState = canUpdateRoomState)
|
copy(canUpdateRoomState = canUpdateRoomState)
|
||||||
}
|
}
|
||||||
|
@ -98,10 +105,10 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||||
copy(
|
copy(
|
||||||
roomCreateContent = async,
|
roomCreateContent = async,
|
||||||
// This is a shortcut, we should do the next lines elsewhere, but keep it like that for the moment.
|
// This is a shortcut, we should do the next lines elsewhere, but keep it like that for the moment.
|
||||||
recommendedRoomVersion = room.roomVersionService().getRecommendedVersion(),
|
recommendedRoomVersion = flowRoom.room.roomVersionService().getRecommendedVersion(),
|
||||||
isUsingUnstableRoomVersion = room.roomVersionService().isUsingUnstableRoomVersion(),
|
isUsingUnstableRoomVersion = flowRoom.room.roomVersionService().isUsingUnstableRoomVersion(),
|
||||||
canUpgradeRoom = room.roomVersionService().userMayUpgradeRoom(session.myUserId),
|
canUpgradeRoom = flowRoom.room.roomVersionService().userMayUpgradeRoom(myUserId),
|
||||||
isTombstoned = room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty) != null
|
isTombstoned = flowRoom.room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE, QueryStringValue.IsEmpty) != null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,34 +128,36 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observePermissions() {
|
private fun observePermissions(room: Room) {
|
||||||
PowerLevelsFlowFactory(room)
|
PowerLevelsFlowFactory(room)
|
||||||
.createFlow()
|
.createFlow()
|
||||||
.setOnEach {
|
.setOnEach {
|
||||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||||
val permissions = RoomProfileViewState.ActionPermissions(
|
val permissions = RoomProfileViewState.ActionPermissions(
|
||||||
canEnableEncryption = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
canEnableEncryption = powerLevelsHelper.isUserAllowedToSend(myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
||||||
)
|
)
|
||||||
copy(actionPermissions = permissions)
|
copy(actionPermissions = permissions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(action: RoomProfileAction) {
|
override fun handle(action: RoomProfileAction) {
|
||||||
|
val session = this.session ?: throw IllegalStateException("Action with no active session")
|
||||||
|
val room = this.room ?: throw IllegalStateException("Action with unknown room")
|
||||||
when (action) {
|
when (action) {
|
||||||
is RoomProfileAction.EnableEncryption -> handleEnableEncryption()
|
is RoomProfileAction.EnableEncryption -> handleEnableEncryption(room)
|
||||||
RoomProfileAction.LeaveRoom -> handleLeaveRoom()
|
RoomProfileAction.LeaveRoom -> handleLeaveRoom(session, room)
|
||||||
is RoomProfileAction.ChangeRoomNotificationState -> handleChangeNotificationMode(action)
|
is RoomProfileAction.ChangeRoomNotificationState -> handleChangeNotificationMode(room, action)
|
||||||
is RoomProfileAction.ShareRoomProfile -> handleShareRoomProfile()
|
is RoomProfileAction.ShareRoomProfile -> handleShareRoomProfile(session)
|
||||||
RoomProfileAction.CreateShortcut -> handleCreateShortcut()
|
RoomProfileAction.CreateShortcut -> handleCreateShortcut()
|
||||||
RoomProfileAction.RestoreEncryptionState -> restoreEncryptionState()
|
RoomProfileAction.RestoreEncryptionState -> restoreEncryptionState(session, room)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isPublicRoom(): Boolean {
|
fun isPublicRoom(): Boolean {
|
||||||
return room.stateService().isPublic()
|
return room?.stateService()?.isPublic().orFalse()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEnableEncryption() {
|
private fun handleEnableEncryption(room: Room) {
|
||||||
postLoading(true)
|
postLoading(true)
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
@ -168,15 +177,14 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||||
|
|
||||||
private fun handleCreateShortcut() {
|
private fun handleCreateShortcut() {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
withState { state ->
|
val state = awaitState()
|
||||||
state.roomSummary()
|
state.roomSummary()
|
||||||
?.let { shortcutCreator.create(it) }
|
?.let { shortcutCreator.create(it) }
|
||||||
?.let { _viewEvents.post(RoomProfileViewEvents.OnShortcutReady(it)) }
|
?.let { _viewEvents.post(RoomProfileViewEvents.OnShortcutReady(it)) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleChangeNotificationMode(action: RoomProfileAction.ChangeRoomNotificationState) {
|
private fun handleChangeNotificationMode(room: Room, action: RoomProfileAction.ChangeRoomNotificationState) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
room.roomPushRuleService().setRoomNotificationState(action.notificationState)
|
room.roomPushRuleService().setRoomNotificationState(action.notificationState)
|
||||||
|
@ -186,7 +194,7 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLeaveRoom() {
|
private fun handleLeaveRoom(session: Session, room: Room) {
|
||||||
_viewEvents.post(RoomProfileViewEvents.Loading(stringProvider.getString(R.string.room_profile_leaving_room)))
|
_viewEvents.post(RoomProfileViewEvents.Loading(stringProvider.getString(R.string.room_profile_leaving_room)))
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
|
@ -205,14 +213,14 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleShareRoomProfile() {
|
private fun handleShareRoomProfile(session: Session) {
|
||||||
session.permalinkService().createRoomPermalink(initialState.roomId)
|
session.permalinkService().createRoomPermalink(initialState.roomId)
|
||||||
?.let { permalink ->
|
?.let { permalink ->
|
||||||
_viewEvents.post(RoomProfileViewEvents.ShareRoomProfile(permalink))
|
_viewEvents.post(RoomProfileViewEvents.ShareRoomProfile(permalink))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreEncryptionState() {
|
private fun restoreEncryptionState(session: Session, room: Room) {
|
||||||
_viewEvents.post(RoomProfileViewEvents.Loading())
|
_viewEvents.post(RoomProfileViewEvents.Loading())
|
||||||
session.coroutineScope.launch {
|
session.coroutineScope.launch {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package im.vector.app.features.roomprofile.mocks
|
||||||
|
|
||||||
|
import im.vector.app.features.roomprofile.RoomProfileArgs
|
||||||
|
import kotlin.String
|
||||||
|
|
||||||
|
val mockRoomProfileArgs by lazy { RoomProfileArgs(roomId = "!CWLUCoEWXSFyTCOtfL:matrix.org") }
|
|
@ -0,0 +1,93 @@
|
||||||
|
package im.vector.app.features.roomprofile.mocks
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import im.vector.app.features.roomprofile.RoomProfileViewState
|
||||||
|
import kotlin.Boolean
|
||||||
|
import kotlin.Int
|
||||||
|
import kotlin.Long
|
||||||
|
import kotlin.String
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.UnsignedData
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomEncryptionAlgorithm
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.VersioningState
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.create.Predecessor
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.sender.SenderInfo
|
||||||
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||||
|
|
||||||
|
val mockRoomProfileViewState by lazy {
|
||||||
|
RoomProfileViewState(
|
||||||
|
roomId = "!CWLUCoEWXSFyTCOtfL:matrix.org",
|
||||||
|
roomSummary = Success(
|
||||||
|
value = RoomSummary(
|
||||||
|
roomId = "!CWLUCoEWXSFyTCOtfL:matrix.org",
|
||||||
|
displayName = "A wrong name",
|
||||||
|
name = "Megolm test (E2E Encryption Testfest)",
|
||||||
|
topic = "Test room! Please discuss issues at #e2e:matrix.org. Requires synapse 0.18.0 or later. (0.18.4 for encrypted images); Latest version is recommended.",
|
||||||
|
avatarUrl = "",
|
||||||
|
canonicalAlias = "#megolm:matrix.org",
|
||||||
|
joinRules = RoomJoinRules.PUBLIC,
|
||||||
|
joinedMembersCount = 199,
|
||||||
|
latestPreviewableEvent = TimelineEvent(
|
||||||
|
root = Event(
|
||||||
|
type = "m.room.encrypted",
|
||||||
|
eventId = "\$zo2MIeXtdl9dWNhz1cbY3YT55rlpQLG8XpYBTFN-JXI",
|
||||||
|
content = mutableMapOf(
|
||||||
|
"algorithm" to "m.megolm.v1.aes-sha2",
|
||||||
|
"ciphertext" to "AwgAEoADprWrq3ZJ4BLD/w0+Lx9H/3mXZpnEQdgbF2FoWOPB1fuki6/1w7vikL1Sb6rP5AwMuA4TPJQ14Pl++/TCGCUzRoZE9m8TsYe0nQXKb2VWRDB6u7i1ib27l3epbtQAIOYfKuCg6MnbMmadef9fEA1K4lHl3xxf0SdWF9PQKGq3nf9rhcZwa3AZW+FDepI094NO98bTHmssKJ5YTp1ChStjALy4FwdcfanlD5WWPHbKqij/RIC63FNAspIOUeb3AkBmcAdoUctBrxXml+NpJKKCGKxXvFudeSkiqHMG",
|
||||||
|
"device_id" to "QBOXOIATIX",
|
||||||
|
"sender_key" to "dGWOgnrcFYOdsYAfwvKJQcDr4dwuZ0R743B3ZlGSMWU",
|
||||||
|
"session_id" to "Eg1c1yyhczbhGt2baH4m6qI4TpJxN0Kb59TxZ3JY5lE"
|
||||||
|
),
|
||||||
|
originServerTs = 1661232614808,
|
||||||
|
senderId = "@DatseMultimedia:matrix.org",
|
||||||
|
roomId = "!CWLUCoEWXSFyTCOtfL:matrix.org",
|
||||||
|
unsignedData = UnsignedData(age = 7112957)
|
||||||
|
),
|
||||||
|
localId = 133,
|
||||||
|
eventId = "\$zo2MIeXtdl9dWNhz1cbY3YT55rlpQLG8XpYBTFN-JXI",
|
||||||
|
displayIndex = 11,
|
||||||
|
senderInfo = SenderInfo(
|
||||||
|
userId = "@DatseMultimedia:matrix.org",
|
||||||
|
displayName = "Jigme Datse (they/them)",
|
||||||
|
isUniqueDisplayName = true,
|
||||||
|
avatarUrl = "mxc://matrix.org/aIPbYElyzjKrOWPaWkxbWEqy"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
otherMemberIds = listOf(
|
||||||
|
"@zocker1999:matrix.org",
|
||||||
|
"@denisea:element.io",
|
||||||
|
"@+:jae.fi"
|
||||||
|
),
|
||||||
|
membership = Membership.JOIN,
|
||||||
|
versioningState = VersioningState.NONE,
|
||||||
|
readMarkerId = "\$-wLehwJjk4gGG8igOfp-giNzGQruvlZMI-Vti1YYxHA",
|
||||||
|
isEncrypted = true,
|
||||||
|
encryptionEventTs = 1574382534883,
|
||||||
|
typingUsers = listOf(
|
||||||
|
|
||||||
|
),
|
||||||
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Default,
|
||||||
|
roomEncryptionAlgorithm = RoomEncryptionAlgorithm.Megolm
|
||||||
|
)
|
||||||
|
),
|
||||||
|
roomCreateContent = Success(
|
||||||
|
value = RoomCreateContent(
|
||||||
|
creator = "@abuse:matrix.org",
|
||||||
|
roomVersion = "5",
|
||||||
|
predecessor = Predecessor(roomId = "!UCnwUWwIKhcpaPTHtR:sw1v.org", eventId = "\$1574382534206ivbfT:matrix.org")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
bannedMembership = Success(
|
||||||
|
value = listOf(
|
||||||
|
|
||||||
|
)
|
||||||
|
),
|
||||||
|
actionPermissions = RoomProfileViewState.ActionPermissions(),
|
||||||
|
recommendedRoomVersion = "9"
|
||||||
|
)
|
||||||
|
}
|