Merge pull request #7110 from vector-im/feature/mna/devices-learn-more-bottom-sheet

[Device Management] Learn more bottom sheets (PSG-715)
This commit is contained in:
Maxime NATUREL 2022-10-03 17:39:41 +02:00 committed by GitHub
commit 07a2e3254a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 334 additions and 37 deletions

1
changelog.d/7100.wip Normal file
View file

@ -0,0 +1 @@
[Device Management] Learn more bottom sheets

View file

@ -406,6 +406,7 @@
<string name="action_reset">Reset</string>
<string name="action_learn_more">Learn more</string>
<string name="action_next">Next</string>
<string name="action_got_it">Got it</string>
<string name="copied_to_clipboard">Copied to clipboard</string>
@ -2366,9 +2367,6 @@
<string name="settings_active_sessions_manage">Manage Sessions</string>
<string name="settings_active_sessions_signout_device">Sign out of this session</string>
<string name="settings_sessions_list">Sessions</string>
<string name="device_manager_sessions_other_title">Other sessions</string>
<string name="device_manager_sessions_other_description">For best security, verify your sessions and sign out from any session that you dont recognize or use anymore.</string>
<string name="settings_server_name">Server name</string>
<string name="settings_server_version">Server version</string>
<string name="settings_server_upload_size_title">Server file upload limit</string>
@ -3229,6 +3227,8 @@
<!-- Device Manager -->
<string name="device_manager_settings_active_sessions_show_all">Show All Sessions (V2, WIP)</string>
<string name="device_manager_sessions_other_title">Other sessions</string>
<string name="device_manager_sessions_other_description">For best security, verify your sessions and sign out from any session that you dont recognize or use anymore.</string>
<string name="a11y_device_manager_device_type_mobile">Mobile</string>
<string name="a11y_device_manager_device_type_web">Web</string>
<string name="a11y_device_manager_device_type_desktop">Desktop</string>
@ -3302,6 +3302,14 @@
<string name="device_manager_session_rename_edit_hint">Session name</string>
<string name="device_manager_session_rename_description">Custom session names can help you recognize your devices more easily.</string>
<string name="device_manager_session_rename_warning">Please be aware that session names are also visible to people you communicate with.</string>
<string name="device_manager_learn_more_sessions_inactive_title">Inactive sessions</string>
<string name="device_manager_learn_more_sessions_inactive">Inactive sessions are sessions you have not used in some time, but they continue to receive encryption keys.\n\nRemoving inactive sessions improves security and performance, and makes it easier for you to identify if a new session is suspicious.</string>
<string name="device_manager_learn_more_sessions_unverified_title">Unverified sessions</string>
<string name="device_manager_learn_more_sessions_unverified">Unverified sessions are sessions that have logged in with your credentials but not been cross-verified.\n\nYou should make especially certain that you recognise these sessions as they could represent an unauthorised use of your account.</string>
<string name="device_manager_learn_more_sessions_verified_title">Verified sessions</string>
<string name="device_manager_learn_more_sessions_verified">Verified sessions have logged in with your credentials and then been verified, either using your secure passphrase or by cross-verifying.\n\nThis means they hold encryption keys for your previous messages, and confirm to other users you are communicating with that these sessions are really you.</string>
<string name="device_manager_learn_more_session_rename_title">Renaming sessions</string>
<string name="device_manager_learn_more_session_rename">Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.</string>
<!-- Note to translators: %s will be replaces with selected space name -->
<string name="home_empty_space_no_rooms_title">%s\nis looking a little empty.</string>

View file

@ -4,6 +4,7 @@
<declare-styleable name="SessionsListHeaderView">
<attr name="sessionsListHeaderTitle" format="string" />
<attr name="sessionsListHeaderDescription" format="string" />
<attr name="sessionsListHeaderHasLearnMoreLink" format="boolean" />
</declare-styleable>
</resources>

View file

@ -89,6 +89,7 @@ import im.vector.app.features.settings.crosssigning.CrossSigningSettingsViewMode
import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheetViewModel
import im.vector.app.features.settings.devices.DevicesViewModel
import im.vector.app.features.settings.devices.v2.details.SessionDetailsViewModel
import im.vector.app.features.settings.devices.v2.more.SessionLearnMoreViewModel
import im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsViewModel
import im.vector.app.features.settings.devices.v2.overview.SessionOverviewViewModel
import im.vector.app.features.settings.devices.v2.rename.RenameSessionViewModel
@ -659,4 +660,9 @@ interface MavericksViewModelModule {
@IntoMap
@MavericksViewModelKey(RenameSessionViewModel::class)
fun renameSessionViewModelFactory(factory: RenameSessionViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
@Binds
@IntoMap
@MavericksViewModelKey(SessionLearnMoreViewModel::class)
fun sessionLearnMoreViewModelFactory(factory: SessionLearnMoreViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
}

View file

@ -21,7 +21,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import com.airbnb.mvrx.Success
@ -82,7 +81,6 @@ class VectorSettingsDevicesFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initLearnMoreButtons()
initWaitingView()
initOtherSessionsView()
initSecurityRecommendationsView()
@ -155,12 +153,6 @@ class VectorSettingsDevicesFragment :
super.onDestroyView()
}
private fun initLearnMoreButtons() {
views.deviceListHeaderOtherSessions.onLearnMoreClickListener = {
Toast.makeText(context, "Learn more other", Toast.LENGTH_LONG).show()
}
}
private fun cleanUpLearnMoreButtonsListeners() {
views.deviceListHeaderOtherSessions.onLearnMoreClickListener = null
}

View file

@ -65,14 +65,23 @@ class SessionsListHeaderView @JvmOverloads constructor(
return
}
val hasLearnMoreLink = typedArray.getBoolean(R.styleable.SessionsListHeaderView_sessionsListHeaderHasLearnMoreLink, true)
if (hasLearnMoreLink) {
setDescriptionWithLearnMore(description)
} else {
binding.sessionsListHeaderDescription.text = description
}
binding.sessionsListHeaderDescription.isVisible = true
}
private fun setDescriptionWithLearnMore(description: String) {
val learnMore = context.getString(R.string.action_learn_more)
val fullDescription = buildString {
append(description)
append(" ")
append(learnMore)
}
binding.sessionsListHeaderDescription.isVisible = true
binding.sessionsListHeaderDescription.setTextWithColoredPart(
fullText = fullDescription,
coloredPart = learnMore,

View file

@ -0,0 +1,75 @@
/*
* 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.settings.devices.v2.more
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.FragmentManager
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.databinding.BottomSheetSessionLearnMoreBinding
import kotlinx.parcelize.Parcelize
@AndroidEntryPoint
class SessionLearnMoreBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSessionLearnMoreBinding>() {
@Parcelize
data class Args(
val title: String,
val description: String,
) : Parcelable
private val viewModel: SessionLearnMoreViewModel by fragmentViewModel()
override val showExpanded = true
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetSessionLearnMoreBinding {
return BottomSheetSessionLearnMoreBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initCloseButton()
}
private fun initCloseButton() {
views.bottomSheetSessionLearnMoreCloseButton.debouncedClicks {
dismiss()
}
}
override fun invalidate() = withState(viewModel) { viewState ->
super.invalidate()
views.bottomSheetSessionLearnMoreTitle.text = viewState.title
views.bottomSheetSessionLearnMoreDescription.text = viewState.description
}
companion object {
fun show(fragmentManager: FragmentManager, args: Args) {
val bottomSheet = SessionLearnMoreBottomSheet()
bottomSheet.isCancelable = true
bottomSheet.setArguments(args)
bottomSheet.show(fragmentManager, "SessionLearnMoreBottomSheet")
}
}
}

View file

@ -0,0 +1,43 @@
/*
* 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.settings.devices.v2.more
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
class SessionLearnMoreViewModel @AssistedInject constructor(
@Assisted initialState: SessionLearnMoreViewState,
) : VectorViewModel<SessionLearnMoreViewState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedFactory
interface Factory : MavericksAssistedViewModelFactory<SessionLearnMoreViewModel, SessionLearnMoreViewState> {
override fun create(initialState: SessionLearnMoreViewState): SessionLearnMoreViewModel
}
companion object : MavericksViewModelFactory<SessionLearnMoreViewModel, SessionLearnMoreViewState> by hiltMavericksViewModelFactory()
override fun handle(action: EmptyAction) {
// do nothing
}
}

View file

@ -0,0 +1,29 @@
/*
* 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.settings.devices.v2.more
import com.airbnb.mvrx.MavericksState
data class SessionLearnMoreViewState(
val title: String,
val description: String,
) : MavericksState {
constructor(args: SessionLearnMoreBottomSheet.Args) : this(
title = args.title,
description = args.description,
)
}

View file

@ -20,6 +20,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.core.view.isVisible
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.args
@ -37,6 +38,7 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterBott
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
import im.vector.app.features.settings.devices.v2.list.OtherSessionsView
import im.vector.app.features.settings.devices.v2.list.SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS
import im.vector.app.features.settings.devices.v2.more.SessionLearnMoreBottomSheet
import im.vector.app.features.themes.ThemeUtils
import javax.inject.Inject
@ -121,6 +123,7 @@ class OtherSessionsFragment :
)
)
views.otherSessionsNotFoundTextView.text = getString(R.string.device_manager_other_sessions_no_verified_sessions_found)
updateSecurityLearnMoreButton(R.string.device_manager_learn_more_sessions_verified_title, R.string.device_manager_learn_more_sessions_verified)
}
DeviceManagerFilterType.UNVERIFIED -> {
views.otherSessionsSecurityRecommendationView.render(
@ -132,6 +135,10 @@ class OtherSessionsFragment :
)
)
views.otherSessionsNotFoundTextView.text = getString(R.string.device_manager_other_sessions_no_unverified_sessions_found)
updateSecurityLearnMoreButton(
R.string.device_manager_learn_more_sessions_unverified_title,
R.string.device_manager_learn_more_sessions_unverified
)
}
DeviceManagerFilterType.INACTIVE -> {
views.otherSessionsSecurityRecommendationView.render(
@ -147,8 +154,10 @@ class OtherSessionsFragment :
)
)
views.otherSessionsNotFoundTextView.text = getString(R.string.device_manager_other_sessions_no_inactive_sessions_found)
updateSecurityLearnMoreButton(R.string.device_manager_learn_more_sessions_inactive_title, R.string.device_manager_learn_more_sessions_inactive)
}
DeviceManagerFilterType.ALL_SESSIONS -> { /* NOOP. View is not visible */
}
DeviceManagerFilterType.ALL_SESSIONS -> { /* NOOP. View is not visible */ }
}
if (devices.isNullOrEmpty()) {
@ -161,6 +170,26 @@ class OtherSessionsFragment :
}
}
private fun updateSecurityLearnMoreButton(
@StringRes titleResId: Int,
@StringRes descriptionResId: Int,
) {
views.otherSessionsSecurityRecommendationView.onLearnMoreClickListener = {
showLearnMoreInfo(titleResId, getString(descriptionResId))
}
}
private fun showLearnMoreInfo(
@StringRes titleResId: Int,
description: String,
) {
val args = SessionLearnMoreBottomSheet.Args(
title = getString(titleResId),
description = description,
)
SessionLearnMoreBottomSheet.show(childFragmentManager, args)
}
override fun onOtherSessionClicked(deviceId: String) {
viewNavigator.navigateToSessionOverview(
context = requireActivity(),

View file

@ -41,9 +41,11 @@ import im.vector.app.databinding.FragmentSessionOverviewBinding
import im.vector.app.features.auth.ReAuthActivity
import im.vector.app.features.crypto.recover.SetupMode
import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
import im.vector.app.features.settings.devices.v2.more.SessionLearnMoreBottomSheet
import im.vector.app.features.workers.signout.SignOutUiWorker
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
import javax.inject.Inject
/**
@ -204,6 +206,9 @@ class SessionOverviewFragment :
isLastSeenDetailsVisible = true,
)
views.sessionOverviewInfo.render(infoViewState, dateFormatter, drawableProvider, colorProvider)
views.sessionOverviewInfo.onLearnMoreClickListener = {
showLearnMoreInfoVerificationStatus(deviceInfo.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted)
}
} else {
views.sessionOverviewInfo.isVisible = false
}
@ -249,4 +254,22 @@ class SessionOverviewFragment :
reAuthActivityResultLauncher.launch(intent)
}
}
private fun showLearnMoreInfoVerificationStatus(isVerified: Boolean) {
val titleResId = if (isVerified) {
R.string.device_manager_verification_status_verified
} else {
R.string.device_manager_verification_status_unverified
}
val descriptionResId = if (isVerified) {
R.string.device_manager_learn_more_sessions_verified
} else {
R.string.device_manager_learn_more_sessions_unverified
}
val args = SessionLearnMoreBottomSheet.Args(
title = getString(titleResId),
description = getString(descriptionResId),
)
SessionLearnMoreBottomSheet.show(childFragmentManager, args)
}
}

View file

@ -24,9 +24,11 @@ import androidx.core.widget.doOnTextChanged
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.showKeyboard
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentSessionRenameBinding
import im.vector.app.features.settings.devices.v2.more.SessionLearnMoreBottomSheet
import javax.inject.Inject
/**
@ -51,6 +53,7 @@ class RenameSessionFragment :
initEditText()
initSaveButton()
initWithLastEditedName()
initInfoView()
}
private fun initToolbar() {
@ -75,6 +78,20 @@ class RenameSessionFragment :
viewModel.handle(RenameSessionAction.InitWithLastEditedName)
}
private fun initInfoView() {
views.renameSessionInfo.onLearnMoreClickListener = {
showLearnMoreInfo()
}
}
private fun showLearnMoreInfo() {
val args = SessionLearnMoreBottomSheet.Args(
title = getString(R.string.device_manager_learn_more_session_rename_title),
description = getString(R.string.device_manager_learn_more_session_rename),
)
SessionLearnMoreBottomSheet.show(childFragmentManager, args)
}
private fun observeViewEvents() {
viewModel.observeViewEvents {
when (it) {

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorSurface"
android:paddingHorizontal="24dp"
android:paddingTop="8dp"
android:paddingBottom="16dp">
<View
android:id="@+id/bottomSheetSessionLearnMoreHandle"
android:layout_width="36dp"
android:layout_height="6dp"
android:background="@drawable/ic_bottom_sheet_handle"
app:layout_constraintBottom_toTopOf="@id/bottomSheetSessionLearnMoreTitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/bottomSheetSessionLearnMoreTitle"
style="@style/TextAppearance.Vector.Subtitle.Medium.DevicesManagement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintBottom_toTopOf="@id/bottomSheetSessionLearnMoreDescription"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bottomSheetSessionLearnMoreHandle"
tools:text="Verified sessions" />
<TextView
android:id="@+id/bottomSheetSessionLearnMoreDescription"
style="@style/TextAppearance.Vector.Body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toTopOf="@id/bottomSheetSessionLearnMoreCloseButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bottomSheetSessionLearnMoreTitle"
tools:text="Further context on verified sessions. What do those mean, and how do they differ from unverified ones." />
<Button
android:id="@+id/bottomSheetSessionLearnMoreCloseButton"
style="@style/Widget.Vector.Button.CallToAction"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_marginTop="24dp"
android:text="@string/action_got_it"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bottomSheetSessionLearnMoreDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -53,11 +53,12 @@
android:id="@+id/deviceListHeaderOtherSessions"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:sessionsListHeaderDescription="@string/device_manager_sessions_other_description"
app:sessionsListHeaderTitle=""
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
app:layout_constraintTop_toBottomOf="@id/appBarLayout"
app:sessionsListHeaderDescription="@string/device_manager_sessions_other_description"
app:sessionsListHeaderHasLearnMoreLink="false"
app:sessionsListHeaderTitle="" />
<im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsSecurityRecommendationView
android:id="@+id/otherSessionsSecurityRecommendationView"

View file

@ -60,6 +60,7 @@
app:layout_constraintTop_toBottomOf="@id/renameSessionInputLayout" />
<im.vector.app.features.settings.devices.v2.SessionWarningInfoView
android:id="@+id/renameSessionInfo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/layout_horizontal_margin"
@ -68,6 +69,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/renameSessionDescription"
app:sessionsWarningInfoDescription="@string/device_manager_session_rename_warning"
app:sessionsWarningInfoHasLearnMore="false" />
app:sessionsWarningInfoHasLearnMore="true" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -12,11 +12,12 @@
android:id="@+id/deviceListHeaderSectionSecurityRecommendations"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:sessionsListHeaderDescription="@string/device_manager_header_section_security_recommendations_description"
app:sessionsListHeaderTitle="@string/device_manager_header_section_security_recommendations_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
app:sessionsListHeaderDescription="@string/device_manager_header_section_security_recommendations_description"
app:sessionsListHeaderHasLearnMoreLink="false"
app:sessionsListHeaderTitle="@string/device_manager_header_section_security_recommendations_title" />
<im.vector.app.features.settings.devices.v2.list.SecurityRecommendationView
android:id="@+id/deviceListUnverifiedSessionsRecommendation"
@ -24,13 +25,13 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="16dp"
app:recommendationTitle="@string/device_manager_unverified_sessions_title"
app:recommendationDescription="@string/device_manager_unverified_sessions_description"
app:recommendationImageResource="@drawable/ic_shield_warning_no_border"
app:recommendationImageBackgroundTint="@color/shield_color_warning_background"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/deviceListHeaderSectionSecurityRecommendations"/>
app:layout_constraintTop_toBottomOf="@id/deviceListHeaderSectionSecurityRecommendations"
app:recommendationDescription="@string/device_manager_unverified_sessions_description"
app:recommendationImageBackgroundTint="@color/shield_color_warning_background"
app:recommendationImageResource="@drawable/ic_shield_warning_no_border"
app:recommendationTitle="@string/device_manager_unverified_sessions_title" />
<im.vector.app.features.settings.devices.v2.list.SecurityRecommendationView
android:id="@+id/deviceListInactiveSessionsRecommendation"
@ -38,13 +39,13 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="16dp"
app:recommendationTitle="@string/device_manager_inactive_sessions_title"
app:recommendationDescription="@plurals/device_manager_inactive_sessions_description"
app:recommendationImageResource="@drawable/ic_inactive_sessions"
app:recommendationImageBackgroundTint="?vctr_system"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/deviceListUnverifiedSessionsRecommendation"/>
app:layout_constraintTop_toBottomOf="@id/deviceListUnverifiedSessionsRecommendation"
app:recommendationDescription="@plurals/device_manager_inactive_sessions_description"
app:recommendationImageBackgroundTint="?vctr_system"
app:recommendationImageResource="@drawable/ic_inactive_sessions"
app:recommendationTitle="@string/device_manager_inactive_sessions_title" />
<View
android:id="@+id/deviceListSecurityRecommendationsDivider"
@ -60,11 +61,12 @@
android:id="@+id/deviceListHeaderCurrentSession"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:sessionsListHeaderDescription=""
app:sessionsListHeaderTitle="@string/device_manager_current_session_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/deviceListSecurityRecommendationsDivider" />
app:layout_constraintTop_toBottomOf="@id/deviceListSecurityRecommendationsDivider"
app:sessionsListHeaderDescription=""
app:sessionsListHeaderHasLearnMoreLink="false"
app:sessionsListHeaderTitle="@string/device_manager_current_session_title" />
<im.vector.app.features.settings.devices.v2.list.SessionInfoView
android:id="@+id/deviceListCurrentSession"
@ -90,11 +92,12 @@
android:id="@+id/deviceListHeaderOtherSessions"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:sessionsListHeaderDescription="@string/device_manager_sessions_other_description"
app:sessionsListHeaderTitle="@string/device_manager_sessions_other_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/deviceListDividerCurrentSession" />
app:layout_constraintTop_toBottomOf="@id/deviceListDividerCurrentSession"
app:sessionsListHeaderDescription="@string/device_manager_sessions_other_description"
app:sessionsListHeaderHasLearnMoreLink="false"
app:sessionsListHeaderTitle="@string/device_manager_sessions_other_title" />
<im.vector.app.features.settings.devices.v2.list.OtherSessionsView
android:id="@+id/deviceListOtherSessions"