Merge pull request #2367 from vector-im/feature/bma/sanity_test

Feature/bma/sanity test
This commit is contained in:
Benoit Marty 2020-11-20 13:56:49 +01:00 committed by GitHub
commit 41f46d0810
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 744 additions and 353 deletions

View file

@ -31,6 +31,9 @@ SDK API changes ⚠️:
Build 🧱:
-
Test:
- Add `allScreensTest` to cover all screens of the app
Other changes:
- Upgrade Realm dependency to 10.0.0
@ -1044,5 +1047,8 @@ SDK API changes ⚠️:
Build 🧱:
-
Test:
-
Other changes:
-

View file

@ -1679,27 +1679,24 @@ internal class RealmCryptoStore @Inject constructor(
// Only keep one week history
realm.where<IncomingGossipingRequestEntity>()
.lessThan(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, prevWeekTs)
.findAll().let {
Timber.i("## Crypto Clean up ${it.size} IncomingGossipingRequestEntity")
it.deleteAllFromRealm()
}
.findAll()
.also { Timber.i("## Crypto Clean up ${it.size} IncomingGossipingRequestEntity") }
.deleteAllFromRealm()
// Clean the cancelled ones?
realm.where<OutgoingGossipingRequestEntity>()
.equalTo(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, OutgoingGossipingRequestState.CANCELLED.name)
.equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
.findAll().let {
Timber.i("## Crypto Clean up ${it.size} OutgoingGossipingRequestEntity")
it.deleteAllFromRealm()
}
.findAll()
.also { Timber.i("## Crypto Clean up ${it.size} OutgoingGossipingRequestEntity") }
.deleteAllFromRealm()
// Only keep one week history
realm.where<GossipingEventEntity>()
.lessThan(GossipingEventEntityFields.AGE_LOCAL_TS, prevWeekTs)
.findAll().let {
Timber.i("## Crypto Clean up ${it.size} GossipingEventEntityFields")
it.deleteAllFromRealm()
}
.findAll()
.also { Timber.i("## Crypto Clean up ${it.size} GossipingEventEntityFields") }
.deleteAllFromRealm()
// Can we do something for WithHeldSessionEntity?
}

View file

@ -461,6 +461,10 @@ dependencies {
androidTestImplementation "androidx.arch.core:core-testing:$arch_version"
// Plant Timber tree for test
androidTestImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
// "The one who serves a great Espresso"
androidTestImplementation('com.schibsted.spain:barista:3.7.0') {
exclude group: 'org.jetbrains.kotlin'
}
}
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Gplay")) {

View file

@ -67,7 +67,7 @@ class RegistrationTest {
.perform(click())
// Enter local synapse
onView((withId(R.id.loginServerUrlFormHomeServerUrl)))
onView(withId(R.id.loginServerUrlFormHomeServerUrl))
.perform(typeText(homeServerUrl))
// Click on continue
@ -87,7 +87,7 @@ class RegistrationTest {
.check(matches(isDisplayed()))
// Ensure user id
onView((withId(R.id.loginField)))
onView(withId(R.id.loginField))
.perform(typeText(userId))
// Ensure login button not yet enabled
@ -95,7 +95,7 @@ class RegistrationTest {
.check(matches(not(isEnabled())))
// Ensure password
onView((withId(R.id.passwordField)))
onView(withId(R.id.passwordField))
.perform(closeSoftKeyboard(), typeText(password))
// Submit

View file

@ -79,7 +79,7 @@ class SecurityBootstrapTest : VerificationTestBase() {
fun testBasicBootstrap() {
val userId: String = existingSession!!.myUserId
doLogin(homeServerUrl, userId, password)
uiTestBase.login(userId = userId, password = password, homeServerUrl = homeServerUrl)
// Thread.sleep(6000)
withIdlingResource(activityIdlingResource(HomeActivity::class.java)) {

View file

@ -18,15 +18,11 @@ package im.vector.app
import android.net.Uri
import androidx.lifecycle.Observer
import androidx.test.espresso.Espresso
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.matcher.ViewMatchers
import im.vector.app.ui.UiTestBase
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.hamcrest.CoreMatchers
import org.junit.Assert
import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.MatrixCallback
@ -43,108 +39,12 @@ abstract class VerificationTestBase {
val password = "password"
val homeServerUrl: String = "http://10.0.2.2:8080"
fun doLogin(homeServerUrl: String, userId: String, password: String) {
Espresso.onView(ViewMatchers.withId(R.id.loginSplashSubmit))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
.check(ViewAssertions.matches(ViewMatchers.withText(R.string.login_splash_submit)))
protected val uiTestBase = UiTestBase()
Espresso.onView(ViewMatchers.withId(R.id.loginSplashSubmit))
.perform(ViewActions.click())
Espresso.onView(ViewMatchers.withId(R.id.loginServerTitle))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
.check(ViewAssertions.matches(ViewMatchers.withText(R.string.login_server_title)))
// Chose custom server
Espresso.onView(ViewMatchers.withId(R.id.loginServerChoiceOther))
.perform(ViewActions.click())
// Enter local synapse
Espresso.onView((ViewMatchers.withId(R.id.loginServerUrlFormHomeServerUrl)))
.perform(ViewActions.typeText(homeServerUrl))
Espresso.onView(ViewMatchers.withId(R.id.loginServerUrlFormSubmit))
.check(ViewAssertions.matches(ViewMatchers.isEnabled()))
.perform(ViewActions.closeSoftKeyboard(), ViewActions.click())
// Click on the signin button
Espresso.onView(ViewMatchers.withId(R.id.loginSignupSigninSignIn))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
.perform(ViewActions.click())
// Ensure password flow supported
Espresso.onView(ViewMatchers.withId(R.id.loginField))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
Espresso.onView(ViewMatchers.withId(R.id.passwordField))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
Espresso.onView((ViewMatchers.withId(R.id.loginField)))
.perform(ViewActions.typeText(userId))
Espresso.onView(ViewMatchers.withId(R.id.loginSubmit))
.check(ViewAssertions.matches(CoreMatchers.not(ViewMatchers.isEnabled())))
Espresso.onView((ViewMatchers.withId(R.id.passwordField)))
.perform(ViewActions.closeSoftKeyboard(), ViewActions.typeText(password))
Espresso.onView(ViewMatchers.withId(R.id.loginSubmit))
.check(ViewAssertions.matches(ViewMatchers.isEnabled()))
.perform(ViewActions.closeSoftKeyboard(), ViewActions.click())
}
private fun createAccount(userId: String = "UiAutoTest", password: String = "password", homeServerUrl: String = "http://10.0.2.2:8080") {
Espresso.onView(ViewMatchers.withId(R.id.loginSplashSubmit))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
.check(ViewAssertions.matches(ViewMatchers.withText(R.string.login_splash_submit)))
Espresso.onView(ViewMatchers.withId(R.id.loginSplashSubmit))
.perform(ViewActions.click())
Espresso.onView(ViewMatchers.withId(R.id.loginServerTitle))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
.check(ViewAssertions.matches(ViewMatchers.withText(R.string.login_server_title)))
// Chose custom server
Espresso.onView(ViewMatchers.withId(R.id.loginServerChoiceOther))
.perform(ViewActions.click())
// Enter local synapse
Espresso.onView((ViewMatchers.withId(R.id.loginServerUrlFormHomeServerUrl)))
.perform(ViewActions.typeText(homeServerUrl))
Espresso.onView(ViewMatchers.withId(R.id.loginServerUrlFormSubmit))
.check(ViewAssertions.matches(ViewMatchers.isEnabled()))
.perform(ViewActions.closeSoftKeyboard(), ViewActions.click())
// Click on the signup button
Espresso.onView(ViewMatchers.withId(R.id.loginSignupSigninSubmit))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
.perform(ViewActions.click())
// Ensure password flow supported
Espresso.onView(ViewMatchers.withId(R.id.loginField))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
Espresso.onView(ViewMatchers.withId(R.id.passwordField))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
Espresso.onView((ViewMatchers.withId(R.id.loginField)))
.perform(ViewActions.typeText(userId))
Espresso.onView(ViewMatchers.withId(R.id.loginSubmit))
.check(ViewAssertions.matches(CoreMatchers.not(ViewMatchers.isEnabled())))
Espresso.onView((ViewMatchers.withId(R.id.passwordField)))
.perform(ViewActions.typeText(password))
Espresso.onView(ViewMatchers.withId(R.id.loginSubmit))
.check(ViewAssertions.matches(ViewMatchers.isEnabled()))
.perform(ViewActions.closeSoftKeyboard(), ViewActions.click())
Espresso.onView(ViewMatchers.withId(R.id.homeDrawerFragmentContainer))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
}
fun createAccountAndSync(matrix: Matrix, userName: String,
password: String,
withInitialSync: Boolean): Session {
fun createAccountAndSync(matrix: Matrix,
userName: String,
password: String,
withInitialSync: Boolean): Session {
val hs = createHomeServerConfig()
doSync<LoginFlowResult> {
@ -174,7 +74,7 @@ abstract class VerificationTestBase {
return session
}
fun createHomeServerConfig(): HomeServerConnectionConfig {
private fun createHomeServerConfig(): HomeServerConnectionConfig {
return HomeServerConnectionConfig.Builder()
.withHomeServerUri(Uri.parse(homeServerUrl))
.build()
@ -200,7 +100,7 @@ abstract class VerificationTestBase {
return result!!
}
fun syncSession(session: Session) {
private fun syncSession(session: Session) {
val lock = CountDownLatch(1)
GlobalScope.launch(Dispatchers.Main) { session.open() }

View file

@ -78,7 +78,7 @@ class VerifySessionInteractiveTest : VerificationTestBase() {
fun checkVerifyPopup() {
val userId: String = existingSession!!.myUserId
doLogin(homeServerUrl, userId, password)
uiTestBase.login(userId = userId, password = password, homeServerUrl = homeServerUrl)
// Thread.sleep(6000)
withIdlingResource(activityIdlingResource(HomeActivity::class.java)) {
@ -215,10 +215,10 @@ class VerifySessionInteractiveTest : VerificationTestBase() {
}
fun signout() {
onView((withId(R.id.groupToolbarAvatarImageView)))
onView(withId(R.id.groupToolbarAvatarImageView))
.perform(click())
onView((withId(R.id.homeDrawerHeaderSettingsView)))
onView(withId(R.id.homeDrawerHeaderSettingsView))
.perform(click())
onView(withText("General"))

View file

@ -88,7 +88,7 @@ class VerifySessionPassphraseTest : VerificationTestBase() {
fun checkVerifyWithPassphrase() {
val userId: String = existingSession!!.myUserId
doLogin(homeServerUrl, userId, password)
uiTestBase.login(userId = userId, password = password, homeServerUrl = homeServerUrl)
// Thread.sleep(6000)
withIdlingResource(activityIdlingResource(HomeActivity::class.java)) {
@ -137,10 +137,10 @@ class VerifySessionPassphraseTest : VerificationTestBase() {
onView(withId(R.id.ssss__root)).check(matches(isDisplayed()))
}
onView((withId(R.id.ssss_passphrase_enter_edittext)))
onView(withId(R.id.ssss_passphrase_enter_edittext))
.perform(typeText(passphrase))
onView((withId(R.id.ssss_passphrase_submit)))
onView(withId(R.id.ssss_passphrase_submit))
.perform(click())
System.out.println("*** passphrase 1")

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2020 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.espresso.tools
import android.widget.Switch
import androidx.annotation.StringRes
import androidx.preference.Preference
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.Espresso.onData
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
import androidx.test.espresso.matcher.PreferenceMatchers.withKey
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.withClassName
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import im.vector.app.R
import org.hamcrest.Matchers.`is`
import org.hamcrest.Matchers.allOf
import org.hamcrest.Matchers.instanceOf
fun clickOnPreference(@StringRes textResId: Int) {
onView(withId(R.id.recycler_view))
.perform(actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(textResId)), click()))
}
fun clickOnSwitchPreference(preferenceKey: String) {
onData(allOf(`is`(instanceOf(Preference::class.java)), withKey(preferenceKey)))
.onChildView(withClassName(`is`(Switch::class.java.name))).perform(click())
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 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.espresso.tools
import android.app.Activity
import im.vector.app.activityIdlingResource
import im.vector.app.withIdlingResource
inline fun <reified T : Activity> waitUntilActivityVisible(noinline block: (() -> Unit)) {
withIdlingResource(activityIdlingResource(T::class.java), block)
}

View file

@ -0,0 +1,460 @@
/*
* Copyright (c) 2020 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.ui
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.Espresso.pressBack
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import androidx.test.espresso.action.ViewActions.longClick
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.schibsted.spain.barista.assertion.BaristaListAssertions.assertListItemCount
import com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertDisplayed
import com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickBack
import com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickOn
import com.schibsted.spain.barista.interaction.BaristaClickInteractions.longClickOn
import com.schibsted.spain.barista.interaction.BaristaDialogInteractions.clickDialogNegativeButton
import com.schibsted.spain.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton
import com.schibsted.spain.barista.interaction.BaristaEditTextInteractions.writeTo
import com.schibsted.spain.barista.interaction.BaristaListInteractions.clickListItem
import com.schibsted.spain.barista.interaction.BaristaListInteractions.clickListItemChild
import com.schibsted.spain.barista.interaction.BaristaMenuClickInteractions.clickMenu
import com.schibsted.spain.barista.interaction.BaristaMenuClickInteractions.openMenu
import im.vector.app.EspressoHelper
import im.vector.app.R
import im.vector.app.SleepViewAction
import im.vector.app.activityIdlingResource
import im.vector.app.espresso.tools.clickOnPreference
import im.vector.app.espresso.tools.waitUntilActivityVisible
import im.vector.app.features.MainActivity
import im.vector.app.features.createdirect.CreateDirectRoomActivity
import im.vector.app.features.home.HomeActivity
import im.vector.app.features.home.room.detail.RoomDetailActivity
import im.vector.app.features.login.LoginActivity
import im.vector.app.features.roomdirectory.RoomDirectoryActivity
import im.vector.app.initialSyncIdlingResource
import im.vector.app.waitForView
import im.vector.app.withIdlingResource
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.lang.Thread.sleep
import java.util.UUID
/**
* This test aim to open every possible screen of the application
*/
@RunWith(AndroidJUnit4::class)
@LargeTest
class UiAllScreensSanityTest {
@get:Rule
val activityRule = ActivityScenarioRule(MainActivity::class.java)
private val uiTestBase = UiTestBase()
// Last passing: 2020-11-09
@Test
fun allScreensTest() {
// Create an account
val userId = "UiTest_" + UUID.randomUUID().toString()
uiTestBase.createAccount(userId = userId)
withIdlingResource(activityIdlingResource(HomeActivity::class.java)) {
assertDisplayed(R.id.roomListContainer)
closeSoftKeyboard()
}
val activity = EspressoHelper.getCurrentActivity()!!
val uiSession = (activity as HomeActivity).activeSessionHolder.getActiveSession()
withIdlingResource(initialSyncIdlingResource(uiSession)) {
assertDisplayed(R.id.roomListContainer)
}
assertDisplayed(R.id.bottomNavigationView)
// Settings
navigateToSettings()
// Create DM
clickOn(R.id.bottom_action_people)
createDm()
// Create Room
// First navigate to the other tab
clickOn(R.id.bottom_action_rooms)
createRoom()
assertDisplayed(R.id.bottomNavigationView)
// Long click on the room
onView(withId(R.id.roomListView))
.perform(
actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.room_displayname_empty_room)),
longClick()
)
)
pressBack()
uiTestBase.signout()
// We have sent a message in a e2e room, accept to loose it
clickOn(R.id.exitAnywayButton)
// Dark pattern
clickDialogNegativeButton()
// Login again on the same account
waitUntilActivityVisible<LoginActivity> {
assertDisplayed(R.id.loginSplashLogo)
}
uiTestBase.login(userId)
ignoreVerification()
uiTestBase.signout()
clickDialogPositiveButton()
// TODO Deactivate account instead of logout?
}
private fun ignoreVerification() {
Thread.sleep(6000)
val activity = EspressoHelper.getCurrentActivity()!!
val popup = activity.findViewById<View>(com.tapadoo.alerter.R.id.llAlertBackground)
activity.runOnUiThread {
popup.performClick()
}
assertDisplayed(R.id.bottomSheetFragmentContainer)
onView(ViewMatchers.isRoot()).perform(SleepViewAction.sleep(2000))
clickOn(R.string.skip)
assertDisplayed(R.string.are_you_sure)
clickOn(R.string.skip)
}
private fun createRoom() {
clickOn(R.id.createGroupRoomButton)
waitUntilActivityVisible<RoomDirectoryActivity> {
assertDisplayed(R.id.publicRoomsList)
}
clickOn(R.string.create_new_room)
// Create
assertListItemCount(R.id.createRoomForm, 10)
clickListItemChild(R.id.createRoomForm, 9, R.id.form_submit_button)
waitUntilActivityVisible<RoomDetailActivity> {
assertDisplayed(R.id.roomDetailContainer)
}
clickOn(R.id.attachmentButton)
clickBack()
// Send a message
writeTo(R.id.composerEditText, "Hello world!")
clickOn(R.id.sendButton)
navigateToRoomSettings()
// Long click on the message
longClickOnMessageTest()
// Menu
openMenu()
pressBack()
clickMenu(R.id.voice_call)
pressBack()
clickMenu(R.id.video_call)
pressBack()
pressBack()
}
private fun longClickOnMessageTest() {
// Test quick reaction
longClickOnMessage()
// Add quick reaction
clickOn("👍")
sleep(1000)
// Open reactions
longClickOn("👍")
pressBack()
// Test add reaction
longClickOnMessage()
clickOn(R.string.message_add_reaction)
// Filter
// TODO clickMenu(R.id.search)
clickListItem(R.id.emojiRecyclerView, 4)
// Test Edit mode
longClickOnMessage()
clickOn(R.string.edit)
// TODO Cancel action
writeTo(R.id.composerEditText, "Hello universe!")
clickOn(R.id.sendButton)
// Open edit history
longClickOnMessage("Hello universe! (edited)")
clickOn(R.string.message_view_edit_history)
pressBack()
}
private fun longClickOnMessage(text: String = "Hello world!") {
onView(withId(R.id.timelineRecyclerView))
.perform(
actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(text)),
longClick()
)
)
}
private fun navigateToRoomSettings() {
clickOn(R.id.roomToolbarTitleView)
assertDisplayed(R.id.roomProfileAvatarView)
// Room settings
clickListItem(R.id.matrixProfileRecyclerView, 3)
pressBack()
// Notifications
clickListItem(R.id.matrixProfileRecyclerView, 5)
pressBack()
assertDisplayed(R.id.roomProfileAvatarView)
// People
clickListItem(R.id.matrixProfileRecyclerView, 7)
assertDisplayed(R.id.inviteUsersButton)
navigateToRoomPeople()
// Fab
navigateToInvite()
pressBack()
pressBack()
assertDisplayed(R.id.roomProfileAvatarView)
// Uploads
clickListItem(R.id.matrixProfileRecyclerView, 9)
// File tab
clickOn(R.string.uploads_files_title)
pressBack()
assertDisplayed(R.id.roomProfileAvatarView)
// Leave
clickListItem(R.id.matrixProfileRecyclerView, 13)
clickDialogNegativeButton()
// Menu share
// clickMenu(R.id.roomProfileShareAction)
// pressBack()
pressBack()
}
private fun navigateToInvite() {
assertDisplayed(R.id.inviteUsersButton)
clickOn(R.id.inviteUsersButton)
closeSoftKeyboard()
pressBack()
}
private fun navigateToRoomPeople() {
// Open first user
clickListItem(R.id.roomSettingsRecyclerView, 1)
assertDisplayed(R.id.memberProfilePowerLevelView)
// Verification
clickListItem(R.id.matrixProfileRecyclerView, 1)
clickBack()
// Role
clickListItem(R.id.matrixProfileRecyclerView, 3)
clickDialogNegativeButton()
clickBack()
}
private fun createDm() {
clickOn(R.id.createChatRoomButton)
withIdlingResource(activityIdlingResource(CreateDirectRoomActivity::class.java)) {
assertDisplayed(R.id.addByMatrixId)
}
closeSoftKeyboard()
pressBack()
pressBack()
}
private fun navigateToSettings() {
clickOn(R.id.groupToolbarAvatarImageView)
clickOn(R.id.homeDrawerHeaderSettingsView)
clickOn(R.string.settings_general_title)
navigateToSettingsGeneral()
pressBack()
clickOn(R.string.settings_notifications)
navigateToSettingsNotifications()
pressBack()
clickOn(R.string.settings_preferences)
navigateToSettingsPreferences()
pressBack()
clickOn(R.string.preference_voice_and_video)
pressBack()
clickOn(R.string.settings_ignored_users)
pressBack()
clickOn(R.string.settings_security_and_privacy)
navigateToSettingsSecurity()
pressBack()
clickOn(R.string.room_settings_labs_pref_title)
pressBack()
clickOn(R.string.settings_advanced_settings)
navigateToSettingsAdvanced()
pressBack()
clickOn(R.string.preference_root_help_about)
navigateToSettingsHelp()
pressBack()
pressBack()
}
private fun navigateToSettingsHelp() {
/*
clickOn(R.string.settings_app_info_link_title)
Cannot go back...
pressBack()
clickOn(R.string.settings_copyright)
pressBack()
clickOn(R.string.settings_app_term_conditions)
pressBack()
clickOn(R.string.settings_privacy_policy)
pressBack()
*/
clickOn(R.string.settings_third_party_notices)
clickDialogPositiveButton()
}
private fun navigateToSettingsAdvanced() {
clickOnPreference(R.string.settings_notifications_targets)
pressBack()
clickOnPreference(R.string.settings_push_rules)
pressBack()
/* TODO P2 test developer screens
// Enable developer mode
clickOnSwitchPreference("SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY")
clickOnPreference(R.string.settings_account_data)
clickOn("m.push_rules")
pressBack()
pressBack()
clickOnPreference(R.string.settings_key_requests)
pressBack()
// Disable developer mode
clickOnSwitchPreference("SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY")
*/
}
private fun navigateToSettingsSecurity() {
clickOnPreference(R.string.settings_active_sessions_show_all)
pressBack()
clickOnPreference(R.string.encryption_message_recovery)
// TODO go deeper here
pressBack()
/* Cannot exit
clickOnPreference(R.string.encryption_export_e2e_room_keys)
pressBack()
*/
}
private fun navigateToSettingsPreferences() {
clickOn(R.string.settings_interface_language)
onView(isRoot())
.perform(waitForView(withText("Dansk (Danmark)")))
pressBack()
clickOn(R.string.settings_theme)
clickDialogNegativeButton()
clickOn(R.string.font_size)
clickDialogNegativeButton()
}
private fun navigateToSettingsNotifications() {
clickOn(R.string.settings_notification_advanced)
pressBack()
/*
clickOn(R.string.settings_noisy_notifications_preferences)
TODO Cannot go back
pressBack()
clickOn(R.string.settings_silent_notifications_preferences)
pressBack()
clickOn(R.string.settings_call_notifications_preferences)
pressBack()
*/
clickOnPreference(R.string.settings_notification_troubleshoot)
pressBack()
}
private fun navigateToSettingsGeneral() {
clickOn(R.string.settings_profile_picture)
clickDialogPositiveButton()
clickOn(R.string.settings_display_name)
clickDialogNegativeButton()
clickOn(R.string.settings_password)
clickDialogNegativeButton()
clickOn(R.string.settings_emails_and_phone_numbers_title)
pressBack()
clickOn(R.string.settings_discovery_manage)
clickOn(R.string.add_identity_server)
pressBack()
pressBack()
// Identity server
clickOnPreference(R.string.settings_identity_server)
pressBack()
// Deactivate account
clickOnPreference(R.string.settings_deactivate_my_account)
pressBack()
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2020 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.ui
import androidx.test.espresso.Espresso.closeSoftKeyboard
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.espresso.matcher.ViewMatchers.withId
import com.schibsted.spain.barista.assertion.BaristaEnabledAssertions.assertDisabled
import com.schibsted.spain.barista.assertion.BaristaEnabledAssertions.assertEnabled
import com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertDisplayed
import com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickOn
import com.schibsted.spain.barista.interaction.BaristaEditTextInteractions.writeTo
import im.vector.app.R
import im.vector.app.espresso.tools.waitUntilActivityVisible
import im.vector.app.features.home.HomeActivity
import im.vector.app.waitForView
class UiTestBase {
fun createAccount(userId: String, password: String = "password", homeServerUrl: String = "http://10.0.2.2:8080") {
initSession(true, userId, password, homeServerUrl)
}
fun login(userId: String, password: String = "password", homeServerUrl: String = "http://10.0.2.2:8080") {
initSession(false, userId, password, homeServerUrl)
}
private fun initSession(createAccount: Boolean,
userId: String,
password: String,
homeServerUrl: String) {
assertDisplayed(R.id.loginSplashSubmit, R.string.login_splash_submit)
clickOn(R.id.loginSplashSubmit)
assertDisplayed(R.id.loginServerTitle, R.string.login_server_title)
// Chose custom server
clickOn(R.id.loginServerChoiceOther)
// Enter local synapse
writeTo(R.id.loginServerUrlFormHomeServerUrl, homeServerUrl)
assertEnabled(R.id.loginServerUrlFormSubmit)
closeSoftKeyboard()
clickOn(R.id.loginServerUrlFormSubmit)
onView(isRoot()).perform(waitForView(withId(R.id.loginSignupSigninSubmit)))
if (createAccount) {
// Click on the signup button
assertDisplayed(R.id.loginSignupSigninSubmit)
clickOn(R.id.loginSignupSigninSubmit)
} else {
// Click on the signin button
assertDisplayed(R.id.loginSignupSigninSignIn)
clickOn(R.id.loginSignupSigninSignIn)
}
// Ensure password flow supported
assertDisplayed(R.id.loginField)
assertDisplayed(R.id.passwordField)
writeTo(R.id.loginField, userId)
assertDisabled(R.id.loginSubmit)
writeTo(R.id.passwordField, password)
assertEnabled(R.id.loginSubmit)
closeSoftKeyboard()
clickOn(R.id.loginSubmit)
// Wait
waitUntilActivityVisible<HomeActivity> {
assertDisplayed(R.id.homeDetailFragmentContainer)
}
}
fun signout() {
clickOn(R.id.groupToolbarAvatarImageView)
clickOn(R.id.homeDrawerHeaderSignoutView)
}
}

View file

@ -30,12 +30,12 @@ class DebugSasEmojiActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_generic_recycler)
val controller = SasEmojiController()
recyclerView.configureWith(controller)
genericRecyclerView.configureWith(controller)
controller.setData(SasState(getAllVerificationEmojis()))
}
override fun onDestroy() {
recyclerView.cleanup()
genericRecyclerView.cleanup()
super.onDestroy()
}
}

View file

@ -28,7 +28,7 @@ import im.vector.app.features.settings.VectorSettingsUrls
// Increase this value to show again the disclaimer dialog after an upgrade of the application
private const val CURRENT_DISCLAIMER_VALUE = 2
private const val SHARED_PREF_KEY = "LAST_DISCLAIMER_VERSION_VALUE"
const val SHARED_PREF_KEY = "LAST_DISCLAIMER_VERSION_VALUE"
fun showDisclaimerDialog(activity: Activity) {
val sharedPrefs = DefaultSharedPreferences.getInstance(activity)

View file

@ -55,7 +55,7 @@ class DiscoverySettingsFragment @Inject constructor(
sharedViewModel = activityViewModelProvider.get(DiscoverySharedViewModel::class.java)
controller.listener = this
recyclerView.configureWith(controller)
genericRecyclerView.configureWith(controller)
sharedViewModel.navigateEvent.observeEvent(this) {
when (it) {
@ -74,7 +74,7 @@ class DiscoverySettingsFragment @Inject constructor(
}
override fun onDestroyView() {
recyclerView.cleanup()
genericRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}

View file

@ -22,6 +22,6 @@ import org.matrix.android.sdk.api.util.MatrixItem
sealed class HomeActivityViewEvents : VectorViewEvents {
data class AskPasswordToInitCrossSigning(val userItem: MatrixItem.UserItem?) : HomeActivityViewEvents()
data class OnNewSession(val userItem: MatrixItem.UserItem?, val waitForIncomingRequest: Boolean = true) : HomeActivityViewEvents()
data class OnCrossSignedInvalidated(val userItem: MatrixItem.UserItem?) : HomeActivityViewEvents()
data class OnCrossSignedInvalidated(val userItem: MatrixItem.UserItem) : HomeActivityViewEvents()
object PromptToEnableSessionPush : HomeActivityViewEvents()
}

View file

@ -78,29 +78,30 @@ class HomeActivityViewModel @AssistedInject constructor(
}
private fun observeCrossSigningReset() {
val safeActiveSession = activeSessionHolder.getSafeActiveSession()
val crossSigningService = safeActiveSession
?.cryptoService()
?.crossSigningService()
onceTrusted = crossSigningService
?.allPrivateKeysKnown() ?: false
val safeActiveSession = activeSessionHolder.getSafeActiveSession() ?: return
onceTrusted = safeActiveSession
.cryptoService()
.crossSigningService().allPrivateKeysKnown()
safeActiveSession
?.rx()
?.liveCrossSigningInfo(safeActiveSession.myUserId)
?.subscribe {
.rx()
.liveCrossSigningInfo(safeActiveSession.myUserId)
.subscribe {
val isVerified = it.getOrNull()?.isTrusted() ?: false
if (!isVerified && onceTrusted) {
// cross signing keys have been reset
// Tigger a popup to re-verify
_viewEvents.post(
HomeActivityViewEvents.OnCrossSignedInvalidated(
safeActiveSession.getUser(safeActiveSession.myUserId)?.toMatrixItem()
)
)
// Note: user can be null in case of logout
safeActiveSession.getUser(safeActiveSession.myUserId)
?.toMatrixItem()
?.let { user ->
_viewEvents.post(HomeActivityViewEvents.OnCrossSignedInvalidated(user))
}
}
onceTrusted = isVerified
}?.disposeOnClear()
}
.disposeOnClear()
}
private fun observeInitialSync() {

View file

@ -543,7 +543,7 @@ class RoomDetailFragment @Inject constructor(
modelBuildListener = null
autoCompleter.clear()
debouncer.cancelAll()
recyclerView.cleanup()
timelineRecyclerView.cleanup()
super.onDestroyView()
}
@ -570,7 +570,7 @@ class RoomDetailFragment @Inject constructor(
jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager(
jumpToBottomView,
debouncer,
recyclerView,
timelineRecyclerView,
layoutManager
)
}
@ -593,7 +593,7 @@ class RoomDetailFragment @Inject constructor(
if (scrollPosition == null) {
scrollOnHighlightedEventCallback.scheduleScrollTo(action.eventId)
} else {
recyclerView.stopScroll()
timelineRecyclerView.stopScroll()
layoutManager.scrollToPosition(scrollPosition)
}
}
@ -1004,14 +1004,14 @@ class RoomDetailFragment @Inject constructor(
timelineEventController.callback = this
timelineEventController.timeline = roomDetailViewModel.timeline
recyclerView.trackItemsVisibilityChange()
timelineRecyclerView.trackItemsVisibilityChange()
layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
scrollOnNewMessageCallback = ScrollOnNewMessageCallback(layoutManager, timelineEventController)
scrollOnHighlightedEventCallback = ScrollOnHighlightedEventCallback(recyclerView, layoutManager, timelineEventController)
recyclerView.layoutManager = layoutManager
recyclerView.itemAnimator = null
recyclerView.setHasFixedSize(true)
scrollOnHighlightedEventCallback = ScrollOnHighlightedEventCallback(timelineRecyclerView, layoutManager, timelineEventController)
timelineRecyclerView.layoutManager = layoutManager
timelineRecyclerView.itemAnimator = null
timelineRecyclerView.setHasFixedSize(true)
modelBuildListener = OnModelBuildFinishedListener {
it.dispatchTo(stateRestorer)
it.dispatchTo(scrollOnNewMessageCallback)
@ -1020,7 +1020,7 @@ class RoomDetailFragment @Inject constructor(
jumpToBottomViewVisibilityManager.maybeShowJumpToBottomViewVisibilityWithDelay()
}
timelineEventController.addModelBuildListener(modelBuildListener)
recyclerView.adapter = timelineEventController.adapter
timelineRecyclerView.adapter = timelineEventController.adapter
if (vectorPreferences.swipeToReplyIsEnabled()) {
val quickReplyHandler = object : RoomMessageTouchHelperCallback.QuickReplayHandler {
@ -1050,9 +1050,9 @@ class RoomDetailFragment @Inject constructor(
}
val swipeCallback = RoomMessageTouchHelperCallback(requireContext(), R.drawable.ic_reply, quickReplyHandler)
val touchHelper = ItemTouchHelper(swipeCallback)
touchHelper.attachToRecyclerView(recyclerView)
touchHelper.attachToRecyclerView(timelineRecyclerView)
}
recyclerView.addGlidePreloader(
timelineRecyclerView.addGlidePreloader(
epoxyController = timelineEventController,
requestManager = GlideApp.with(this),
preloader = glidePreloader { requestManager, epoxyModel: MessageImageVideoItem, _ ->

View file

@ -46,7 +46,7 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
private var weakCurrentActivity: WeakReference<Activity>? = null
private var currentAlerter: VectorAlert? = null
private val alertFiFo = ArrayList<VectorAlert>()
private val alertFiFo = mutableListOf<VectorAlert>()
fun postVectorAlert(alert: VectorAlert) {
synchronized(alertFiFo) {

View file

@ -41,12 +41,12 @@ class EmojiSearchResultFragment @Inject constructor(
super.onViewCreated(view, savedInstanceState)
sharedViewModel = activityViewModelProvider.get(EmojiChooserViewModel::class.java)
epoxyController.listener = this
recyclerView.configureWith(epoxyController, showDivider = true)
genericRecyclerView.configureWith(epoxyController, showDivider = true)
}
override fun onDestroyView() {
epoxyController.listener = null
recyclerView.cleanup()
genericRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -56,7 +56,7 @@ class RoomBannedMemberListFragment @Inject constructor(
roomMemberListController.callback = this
setupToolbar(roomSettingsToolbar)
setupSearchView()
recyclerView.configureWith(roomMemberListController, hasFixedSize = true)
roomSettingsRecyclerView.configureWith(roomMemberListController, hasFixedSize = true)
viewModel.observeViewEvents {
when (it) {
@ -83,7 +83,7 @@ class RoomBannedMemberListFragment @Inject constructor(
}
override fun onDestroyView() {
recyclerView.cleanup()
roomSettingsRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -57,7 +57,7 @@ class RoomMemberListFragment @Inject constructor(
setupToolbar(roomSettingsToolbar)
setupSearchView()
setupInviteUsersButton()
recyclerView.configureWith(roomMemberListController, hasFixedSize = true)
roomSettingsRecyclerView.configureWith(roomMemberListController, hasFixedSize = true)
}
private fun setupInviteUsersButton() {
@ -65,7 +65,7 @@ class RoomMemberListFragment @Inject constructor(
navigator.openInviteUsersToRoom(requireContext(), roomProfileArgs.roomId)
}
// Hide FAB when list is scrolling
recyclerView.addOnScrollListener(
roomSettingsRecyclerView.addOnScrollListener(
object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
when (newState) {
@ -99,7 +99,7 @@ class RoomMemberListFragment @Inject constructor(
}
override fun onDestroyView() {
recyclerView.cleanup()
roomSettingsRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -72,7 +72,7 @@ class RoomSettingsFragment @Inject constructor(
super.onViewCreated(view, savedInstanceState)
controller.callback = this
setupToolbar(roomSettingsToolbar)
recyclerView.configureWith(controller, hasFixedSize = true)
roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true)
waiting_view_status_text.setText(R.string.please_wait)
waiting_view_status_text.isVisible = true
@ -93,7 +93,8 @@ class RoomSettingsFragment @Inject constructor(
}
override fun onDestroyView() {
recyclerView.cleanup()
controller.callback = null
roomSettingsRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -24,6 +24,7 @@ import com.squareup.seismic.ShakeDetector
import im.vector.app.BuildConfig
import im.vector.app.R
import im.vector.app.core.di.DefaultSharedPreferences
import im.vector.app.features.disclaimer.SHARED_PREF_KEY
import im.vector.app.features.homeserver.ServerUrlsRepository
import im.vector.app.features.themes.ThemeUtils
import org.matrix.android.sdk.api.extensions.tryOrNull
@ -248,6 +249,9 @@ class VectorPreferences @Inject constructor(private val context: Context) {
// theme
keysToKeep.add(ThemeUtils.APPLICATION_THEME_KEY)
// Disclaimer dialog
keysToKeep.add(SHARED_PREF_KEY)
// get all the existing keys
val keys = defaultPrefs.all.keys

View file

@ -68,12 +68,12 @@ class CrossSigningSettingsFragment @Inject constructor(
}
private fun setupRecyclerView() {
recyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
genericRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
controller.interactionListener = this
}
override fun onDestroyView() {
recyclerView.cleanup()
genericRecyclerView.cleanup()
controller.interactionListener = null
super.onDestroyView()
}

View file

@ -61,7 +61,7 @@ class VectorSettingsDevicesFragment @Inject constructor(
waiting_view_status_text.setText(R.string.please_wait)
waiting_view_status_text.isVisible = true
devicesController.callback = this
recyclerView.configureWith(devicesController, showDivider = true)
genericRecyclerView.configureWith(devicesController, showDivider = true)
viewModel.observeViewEvents {
when (it) {
is DevicesViewEvents.Loading -> showLoading(it.message)
@ -97,7 +97,7 @@ class VectorSettingsDevicesFragment @Inject constructor(
override fun onDestroyView() {
devicesController.callback = null
recyclerView.cleanup()
genericRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -57,13 +57,13 @@ class AccountDataFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.configureWith(epoxyController, showDivider = true)
genericRecyclerView.configureWith(epoxyController, showDivider = true)
epoxyController.interactionListener = this
}
override fun onDestroyView() {
super.onDestroyView()
recyclerView.cleanup()
genericRecyclerView.cleanup()
epoxyController.interactionListener = null
}

View file

@ -50,13 +50,13 @@ class GossipingEventsPaperTrailFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.configureWith(epoxyController, showDivider = true)
genericRecyclerView.configureWith(epoxyController, showDivider = true)
epoxyController.interactionListener = this
}
override fun onDestroyView() {
super.onDestroyView()
recyclerView.cleanup()
genericRecyclerView.cleanup()
epoxyController.interactionListener = null
}

View file

@ -45,11 +45,11 @@ class IncomingKeyRequestListFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.configureWith(epoxyController, showDivider = true)
genericRecyclerView.configureWith(epoxyController, showDivider = true)
}
override fun onDestroyView() {
super.onDestroyView()
recyclerView.cleanup()
genericRecyclerView.cleanup()
}
}

View file

@ -41,13 +41,13 @@ class OutgoingKeyRequestListFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.configureWith(epoxyController, showDivider = true)
genericRecyclerView.configureWith(epoxyController, showDivider = true)
// epoxyController.interactionListener = this
}
override fun onDestroyView() {
super.onDestroyView()
recyclerView.cleanup()
genericRecyclerView.cleanup()
// epoxyController.interactionListener = null
}
}

View file

@ -49,7 +49,7 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
waiting_view_status_text.setText(R.string.please_wait)
waiting_view_status_text.isVisible = true
ignoredUsersController.callback = this
recyclerView.configureWith(ignoredUsersController)
genericRecyclerView.configureWith(ignoredUsersController)
viewModel.observeViewEvents {
when (it) {
is IgnoredUsersViewEvents.Loading -> showLoading(it.message)
@ -60,7 +60,7 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
override fun onDestroyView() {
ignoredUsersController.callback = null
recyclerView.cleanup()
genericRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -59,11 +59,11 @@ class PushGatewaysFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.configureWith(epoxyController, showDivider = true)
genericRecyclerView.configureWith(epoxyController, showDivider = true)
}
override fun onDestroyView() {
recyclerView.cleanup()
genericRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -43,11 +43,11 @@ class PushRulesFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.configureWith(epoxyController, showDivider = true)
genericRecyclerView.configureWith(epoxyController, showDivider = true)
}
override fun onDestroyView() {
recyclerView.cleanup()
genericRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -54,7 +54,7 @@ class ThreePidsSettingsFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.configureWith(epoxyController)
genericRecyclerView.configureWith(epoxyController)
epoxyController.interactionListener = this
viewModel.observeViewEvents {
@ -73,7 +73,7 @@ class ThreePidsSettingsFragment @Inject constructor(
override fun onDestroyView() {
super.onDestroyView()
recyclerView.cleanup()
genericRecyclerView.cleanup()
epoxyController.interactionListener = null
}

View file

@ -70,12 +70,12 @@ class SoftLogoutFragment @Inject constructor(
}
private fun setupRecyclerView() {
recyclerView.configureWith(softLogoutController)
genericRecyclerView.configureWith(softLogoutController)
softLogoutController.listener = this
}
override fun onDestroyView() {
recyclerView.cleanup()
genericRecyclerView.cleanup()
softLogoutController.listener = null
super.onDestroyView()
}
@ -121,7 +121,7 @@ class SoftLogoutFragment @Inject constructor(
}
private fun cleanupUi() {
recyclerView.hideKeyboard()
genericRecyclerView.hideKeyboard()
}
override fun forgetPasswordClicked() {

View file

@ -82,7 +82,7 @@ class KnownUsersFragment @Inject constructor(
override fun onDestroyView() {
knownUsersController.callback = null
recyclerView.cleanup()
knownUsersRecyclerView.cleanup()
super.onDestroyView()
}
@ -124,7 +124,7 @@ class KnownUsersFragment @Inject constructor(
private fun setupRecyclerView() {
knownUsersController.callback = this
// Don't activate animation as we might have way to much item animation when filtering
recyclerView.configureWith(knownUsersController, disableItemAnimation = true)
knownUsersRecyclerView.configureWith(knownUsersController, disableItemAnimation = true)
}
private fun setupFilterView() {

View file

@ -28,7 +28,6 @@ import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.setupAsSearch
import im.vector.app.core.extensions.showKeyboard
import im.vector.app.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_create_direct_room_directory_users.recyclerView
import kotlinx.android.synthetic.main.fragment_user_directory.*
import org.matrix.android.sdk.api.session.user.model.User
import javax.inject.Inject
@ -51,14 +50,14 @@ class UserDirectoryFragment @Inject constructor(
}
override fun onDestroyView() {
recyclerView.cleanup()
userDirectoryRecyclerView.cleanup()
directRoomController.callback = null
super.onDestroyView()
}
private fun setupRecyclerView() {
directRoomController.callback = this
recyclerView.configureWith(directRoomController)
userDirectoryRecyclerView.configureWith(directRoomController)
}
private fun setupSearchByMatrixIdView() {

View file

@ -1,143 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/createDirectRoomToolbar"
style="@style/VectorToolbarStyle"
android:layout_width="0dp"
android:layout_height="?actionBarSize"
android:elevation="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/createDirectRoomClose"
android:layout_width="@dimen/layout_touch_size"
android:layout_height="@dimen/layout_touch_size"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:scaleType="center"
android:src="@drawable/ic_x_18dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/createDirectRoomTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/fab_menu_create_chat"
android:textColor="?riotx_text_primary"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/createDirectRoomClose"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.Toolbar>
<im.vector.app.core.platform.MaxHeightScrollView
android:id="@+id/chipGroupScrollView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginTop="8dp"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/createDirectRoomToolbar"
app:maxHeight="64dp">
<com.google.android.material.chip.ChipGroup
android:id="@+id/chipGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:lineSpacing="2dp" />
</im.vector.app.core.platform.MaxHeightScrollView>
<EditText
android:id="@+id/createDirectRoomFilter"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
android:background="@null"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:hint="@string/direct_room_filter_hint"
android:importantForAutofill="no"
android:inputType="text"
android:maxHeight="80dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/chipGroupScrollView" />
<View
android:id="@+id/createDirectRoomFilterDivider"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="?attr/vctr_list_divider_color"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/createDirectRoomFilter" />
<com.google.android.material.button.MaterialButton
android:id="@+id/addByMatrixId"
style="@style/VectorButtonStyleText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:minHeight="@dimen/layout_touch_size"
android:text="@string/add_by_matrix_id"
android:visibility="visible"
app:icon="@drawable/ic_plus_circle"
app:iconPadding="13dp"
app:iconTint="@color/riotx_accent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/createDirectRoomFilterDivider" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:fastScrollEnabled="true"
android:overScrollMode="always"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/addByMatrixId"
tools:listitem="@layout/item_create_direct_room_user" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -90,7 +90,7 @@
app:layout_constraintTop_toBottomOf="@+id/createDirectRoomSearchByIdContainer" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:id="@+id/createDirectRoomRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"

View file

@ -7,7 +7,7 @@
android:background="?riotx_background">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:id="@+id/genericRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:itemSpacing="1dp"

View file

@ -105,7 +105,7 @@
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_height="wrap_content"
android:background="?riotx_background"
app:itemIconSize="20dp"
app:itemIconTint="@color/bottom_navigation_icon_tint_selector"

View file

@ -156,7 +156,7 @@
app:layout_constraintTop_toBottomOf="@id/addByMatrixId" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:id="@+id/knownUsersRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:fastScrollEnabled="true"

View file

@ -82,7 +82,7 @@
</androidx.appcompat.widget.Toolbar>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/recyclerViewBarrier"
android:id="@+id/timelineRecyclerViewBarrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="top"
@ -113,11 +113,11 @@
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:id="@+id/timelineRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="always"
app:layout_constraintBottom_toTopOf="@+id/recyclerViewBarrier"
app:layout_constraintBottom_toTopOf="@+id/timelineRecyclerViewBarrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/activeConferenceView"

View file

@ -11,7 +11,8 @@
android:id="@+id/roomListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="always" />
android:overScrollMode="always"
tools:listitem="@layout/item_room" />
<im.vector.app.features.home.room.list.widget.FabMenuView
android:id="@+id/createChatFabMenu"

View file

@ -62,7 +62,7 @@
app:layout_constraintTop_toBottomOf="@+id/roomSettingsToolbar">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:id="@+id/roomSettingsRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="always"

View file

@ -90,7 +90,7 @@
app:layout_constraintTop_toBottomOf="@+id/userDirectorySearchByIdContainer" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:id="@+id/userDirectoryRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"