Code review fixes.
This commit is contained in:
parent
2763ebdd5a
commit
81cc8ab98b
@ -1 +0,0 @@
|
|||||||
[Devices Management] Refactor some code to improve testability
|
|
@ -3265,6 +3265,32 @@
|
|||||||
<string name="device_manager_session_title">Session</string>
|
<string name="device_manager_session_title">Session</string>
|
||||||
<!-- Examples: Last activity Yesterday at 6PM, Last activity Aug 31 at 5:47PM -->
|
<!-- Examples: Last activity Yesterday at 6PM, Last activity Aug 31 at 5:47PM -->
|
||||||
<string name="device_manager_session_last_activity">Last activity %1$s</string>
|
<string name="device_manager_session_last_activity">Last activity %1$s</string>
|
||||||
|
<string name="device_manager_filter_bottom_sheet_title">Filter</string>
|
||||||
|
<string name="device_manager_filter_option_all_sessions">All sessions</string>
|
||||||
|
<string name="device_manager_filter_option_verified">Verified</string>
|
||||||
|
<string name="device_manager_filter_option_verified_description">Ready for secure messaging</string>
|
||||||
|
<string name="device_manager_filter_option_unverified">Unverified</string>
|
||||||
|
<string name="device_manager_filter_option_unverified_description">Not ready for secure messaging</string>
|
||||||
|
<string name="device_manager_filter_option_inactive">Inactive</string>
|
||||||
|
<plurals name="device_manager_filter_option_inactive_description">
|
||||||
|
<item quantity="one">Inactive for %1$d day or longer</item>
|
||||||
|
<item quantity="other">Inactive for %1$d days or longer</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="a11y_device_manager_filter">Filter</string>
|
||||||
|
<string name="device_manager_other_sessions_recommendation_title_verified">Verified</string>
|
||||||
|
<string name="device_manager_other_sessions_recommendation_description_verified">For best security, sign out from any session that you don’t recognize or use anymore.</string>
|
||||||
|
<string name="device_manager_other_sessions_recommendation_title_unverified">Unverified</string>
|
||||||
|
<string name="device_manager_other_sessions_recommendation_description_unverified">Verify your sessions for enhanced secure messaging or sign out from those you don’t recognize or use anymore.</string>
|
||||||
|
<string name="device_manager_other_sessions_recommendation_title_inactive">Inactive</string>
|
||||||
|
<plurals name="device_manager_other_sessions_recommendation_description_inactive">
|
||||||
|
<item quantity="one">Consider signing out from old sessions (%1$d day or more) you don’t use anymore.</item>
|
||||||
|
<item quantity="other">Consider signing out from old sessions (%1$d days or more) you don’t use anymore.</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="device_manager_other_sessions_no_verified_sessions_found">No verified sessions found.</string>
|
||||||
|
<string name="device_manager_other_sessions_no_unverified_sessions_found">No unverified sessions found.</string>
|
||||||
|
<string name="device_manager_other_sessions_no_inactive_sessions_found">No inactive sessions found.</string>
|
||||||
|
<string name="device_manager_other_sessions_clear_filter">Clear Filter</string>
|
||||||
|
|
||||||
<!-- Note to translators: %s will be replaces with selected space name -->
|
<!-- 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>
|
<string name="home_empty_space_no_rooms_title">%s\nis looking a little empty.</string>
|
||||||
<!-- Note to translators: for RTL languages, Spaces will be at the bottom left. Please translate "bottom-left" instead of "bottom-right". Thanks!-->
|
<!-- Note to translators: for RTL languages, Spaces will be at the bottom left. Please translate "bottom-left" instead of "bottom-right". Thanks!-->
|
||||||
@ -3286,31 +3312,4 @@
|
|||||||
<string name="onboarding_new_app_layout_feedback_message">Tap top right to see the option to feedback.</string>
|
<string name="onboarding_new_app_layout_feedback_message">Tap top right to see the option to feedback.</string>
|
||||||
<string name="onboarding_new_app_layout_button_try">Try it out</string>
|
<string name="onboarding_new_app_layout_button_try">Try it out</string>
|
||||||
|
|
||||||
<string name="device_manager_filter_bottom_sheet_title">Filter</string>
|
|
||||||
<string name="device_manager_filter_option_all_sessions">All session</string>
|
|
||||||
<string name="device_manager_filter_option_verified">Verified</string>
|
|
||||||
<string name="device_manager_filter_option_verified_description">Ready for secure messaging</string>
|
|
||||||
<string name="device_manager_filter_option_unverified">Unverified</string>
|
|
||||||
<string name="device_manager_filter_option_unverified_description">Not ready for secure messaging</string>
|
|
||||||
<string name="device_manager_filter_option_inactive">Inactive</string>
|
|
||||||
<plurals name="device_manager_filter_option_inactive_description">
|
|
||||||
<item quantity="one">Inactive for %1$d day or longer</item>
|
|
||||||
<item quantity="other">Inactive for %1$d days or longer</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="device_manager_other_sessions_title">Other sessions</string>
|
|
||||||
<string name="a11y_device_manager_filter">Filter</string>
|
|
||||||
<string name="device_manager_other_sessions_recommendation_title_verified">Verified</string>
|
|
||||||
<string name="device_manager_other_sessions_recommendation_description_verified">For best security, sign out from any session that you don’t recognize or use anymore.</string>
|
|
||||||
<string name="device_manager_other_sessions_recommendation_title_unverified">Unverified</string>
|
|
||||||
<string name="device_manager_other_sessions_recommendation_description_unverified">Verify your sessions for enhanced secure messaging or sign out from those you don’t recognize or use anymore.</string>
|
|
||||||
<string name="device_manager_other_sessions_recommendation_title_inactive">Inactive</string>
|
|
||||||
<plurals name="device_manager_other_sessions_recommendation_description_inactive">
|
|
||||||
<item quantity="one">Consider signing out from old sessions (%1$d day or more) you don’t use anymore.</item>
|
|
||||||
<item quantity="other">Consider signing out from old sessions (%1$d days or more) you don’t use anymore.</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="device_manager_other_sessions_no_verified_sessions_found">No verified sessions found.</string>
|
|
||||||
<string name="device_manager_other_sessions_no_unverified_sessions_found">No unverified sessions found.</string>
|
|
||||||
<string name="device_manager_other_sessions_no_inactive_sessions_found">No inactive sessions found.</string>
|
|
||||||
<string name="device_manager_other_sessions_clear_filter">Clear Filter</string>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -88,6 +88,7 @@ import im.vector.app.features.settings.account.deactivation.DeactivateAccountVie
|
|||||||
import im.vector.app.features.settings.crosssigning.CrossSigningSettingsViewModel
|
import im.vector.app.features.settings.crosssigning.CrossSigningSettingsViewModel
|
||||||
import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheetViewModel
|
import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheetViewModel
|
||||||
import im.vector.app.features.settings.devices.DevicesViewModel
|
import im.vector.app.features.settings.devices.DevicesViewModel
|
||||||
|
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.overview.SessionOverviewViewModel
|
||||||
import im.vector.app.features.settings.devtools.AccountDataViewModel
|
import im.vector.app.features.settings.devtools.AccountDataViewModel
|
||||||
import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailViewModel
|
import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailViewModel
|
||||||
@ -641,4 +642,9 @@ interface MavericksViewModelModule {
|
|||||||
@IntoMap
|
@IntoMap
|
||||||
@MavericksViewModelKey(SessionOverviewViewModel::class)
|
@MavericksViewModelKey(SessionOverviewViewModel::class)
|
||||||
fun sessionOverviewViewModelFactory(factory: SessionOverviewViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
fun sessionOverviewViewModelFactory(factory: SessionOverviewViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@MavericksViewModelKey(OtherSessionsViewModel::class)
|
||||||
|
fun otherSessionsViewModelFactory(factory: OtherSessionsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,8 @@
|
|||||||
package im.vector.app.features.settings.devices.v2
|
package im.vector.app.features.settings.devices.v2
|
||||||
|
|
||||||
import im.vector.app.core.platform.VectorViewModelAction
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||||
|
|
||||||
sealed class DevicesAction : VectorViewModelAction {
|
sealed class DevicesAction : VectorViewModelAction {
|
||||||
data class MarkAsManuallyVerified(val cryptoDeviceInfo: CryptoDeviceInfo) : DevicesAction()
|
data class MarkAsManuallyVerified(val cryptoDeviceInfo: CryptoDeviceInfo) : DevicesAction()
|
||||||
data class FilterDevices(val filterType: DeviceManagerFilterType) : DevicesAction()
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
|||||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.utils.PublishDataSource
|
import im.vector.app.core.utils.PublishDataSource
|
||||||
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
import im.vector.lib.core.utils.flow.throttleFirst
|
import im.vector.lib.core.utils.flow.throttleFirst
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@ -94,7 +95,10 @@ class DevicesViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun observeDevices() {
|
private fun observeDevices() {
|
||||||
getDeviceFullInfoListUseCase.execute()
|
getDeviceFullInfoListUseCase.execute(
|
||||||
|
filterType = DeviceManagerFilterType.ALL_SESSIONS,
|
||||||
|
excludeCurrentDevice = false
|
||||||
|
)
|
||||||
.execute { async ->
|
.execute { async ->
|
||||||
if (async is Success) {
|
if (async is Success) {
|
||||||
val deviceFullInfoList = async.invoke()
|
val deviceFullInfoList = async.invoke()
|
||||||
@ -144,19 +148,9 @@ class DevicesViewModel @AssistedInject constructor(
|
|||||||
override fun handle(action: DevicesAction) {
|
override fun handle(action: DevicesAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is DevicesAction.MarkAsManuallyVerified -> handleMarkAsManuallyVerifiedAction()
|
is DevicesAction.MarkAsManuallyVerified -> handleMarkAsManuallyVerifiedAction()
|
||||||
is DevicesAction.FilterDevices -> handleFilterDevices(action)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleFilterDevices(action: DevicesAction.FilterDevices) {
|
|
||||||
setState {
|
|
||||||
copy(
|
|
||||||
currentFilter = action.filterType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
queryRefreshDevicesList()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleMarkAsManuallyVerifiedAction() {
|
private fun handleMarkAsManuallyVerifiedAction() {
|
||||||
// TODO implement when needed
|
// TODO implement when needed
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,6 @@ package im.vector.app.features.settings.devices.v2
|
|||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MavericksState
|
import com.airbnb.mvrx.MavericksState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
|
||||||
|
|
||||||
data class DevicesViewState(
|
data class DevicesViewState(
|
||||||
val currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo = CurrentSessionCrossSigningInfo(),
|
val currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo = CurrentSessionCrossSigningInfo(),
|
||||||
@ -28,17 +26,4 @@ data class DevicesViewState(
|
|||||||
val unverifiedSessionsCount: Int = 0,
|
val unverifiedSessionsCount: Int = 0,
|
||||||
val inactiveSessionsCount: Int = 0,
|
val inactiveSessionsCount: Int = 0,
|
||||||
val isLoading: Boolean = false,
|
val isLoading: Boolean = false,
|
||||||
val currentFilter: DeviceManagerFilterType = DeviceManagerFilterType.ALL_SESSIONS,
|
) : MavericksState
|
||||||
) : MavericksState {
|
|
||||||
|
|
||||||
fun List<DeviceFullInfo>?.filteredDevices(): List<DeviceFullInfo>? {
|
|
||||||
return this?.filter {
|
|
||||||
when (currentFilter) {
|
|
||||||
DeviceManagerFilterType.ALL_SESSIONS -> true
|
|
||||||
DeviceManagerFilterType.VERIFIED -> it.cryptoDeviceInfo?.isVerified.orFalse()
|
|
||||||
DeviceManagerFilterType.UNVERIFIED -> !it.cryptoDeviceInfo?.isVerified.orFalse()
|
|
||||||
DeviceManagerFilterType.INACTIVE -> it.isInactive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
package im.vector.app.features.settings.devices.v2
|
package im.vector.app.features.settings.devices.v2
|
||||||
|
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
|
import im.vector.app.features.settings.devices.v2.filter.FilterDevicesUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
@ -32,16 +34,23 @@ class GetDeviceFullInfoListUseCase @Inject constructor(
|
|||||||
private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase,
|
private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase,
|
||||||
private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase,
|
private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase,
|
||||||
private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase,
|
private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase,
|
||||||
|
private val filterDevicesUseCase: FilterDevicesUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun execute(): Flow<List<DeviceFullInfo>> {
|
fun execute(filterType: DeviceManagerFilterType, excludeCurrentDevice: Boolean = false): Flow<List<DeviceFullInfo>> {
|
||||||
return activeSessionHolder.getSafeActiveSession()?.let { session ->
|
return activeSessionHolder.getSafeActiveSession()?.let { session ->
|
||||||
val deviceFullInfoFlow = combine(
|
val deviceFullInfoFlow = combine(
|
||||||
getCurrentSessionCrossSigningInfoUseCase.execute(),
|
getCurrentSessionCrossSigningInfoUseCase.execute(),
|
||||||
session.flow().liveUserCryptoDevices(session.myUserId),
|
session.flow().liveUserCryptoDevices(session.myUserId),
|
||||||
session.flow().liveMyDevicesInfo()
|
session.flow().liveMyDevicesInfo()
|
||||||
) { currentSessionCrossSigningInfo, cryptoList, infoList ->
|
) { currentSessionCrossSigningInfo, cryptoList, infoList ->
|
||||||
convertToDeviceFullInfoList(currentSessionCrossSigningInfo, cryptoList, infoList)
|
val deviceFullInfoList = convertToDeviceFullInfoList(currentSessionCrossSigningInfo, cryptoList, infoList)
|
||||||
|
val excludedDeviceIds = if (excludeCurrentDevice) {
|
||||||
|
listOf(currentSessionCrossSigningInfo.deviceId)
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
filterDevicesUseCase.execute(deviceFullInfoList, filterType, excludedDeviceIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceFullInfoFlow.distinctUntilChanged()
|
deviceFullInfoFlow.distinctUntilChanged()
|
||||||
|
@ -50,7 +50,7 @@ class DeviceManagerFilterBottomSheet : VectorBaseBottomSheetDialogFragment<Botto
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initFilterRadioGroup() {
|
private fun initFilterRadioGroup() {
|
||||||
views.filterOptionInactiveRadioButtonDescription.text = resources.getQuantityString(
|
views.filterOptionInactiveTextView.text = resources.getQuantityString(
|
||||||
R.plurals.device_manager_filter_option_inactive_description,
|
R.plurals.device_manager_filter_option_inactive_description,
|
||||||
SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
|
SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
|
||||||
SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS
|
SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS
|
||||||
@ -64,6 +64,16 @@ class DeviceManagerFilterBottomSheet : VectorBaseBottomSheetDialogFragment<Botto
|
|||||||
}
|
}
|
||||||
views.filterOptionsRadioGroup.check(radioButtonId)
|
views.filterOptionsRadioGroup.check(radioButtonId)
|
||||||
|
|
||||||
|
views.filterOptionVerifiedTextView.debouncedClicks {
|
||||||
|
views.filterOptionsRadioGroup.check(R.id.filterOptionVerifiedRadioButton)
|
||||||
|
}
|
||||||
|
views.filterOptionUnverifiedTextView.debouncedClicks {
|
||||||
|
views.filterOptionsRadioGroup.check(R.id.filterOptionUnverifiedRadioButton)
|
||||||
|
}
|
||||||
|
views.filterOptionInactiveTextView.debouncedClicks {
|
||||||
|
views.filterOptionsRadioGroup.check(R.id.filterOptionInactiveRadioButton)
|
||||||
|
}
|
||||||
|
|
||||||
views.filterOptionsRadioGroup.setOnCheckedChangeListener { _, checkedId ->
|
views.filterOptionsRadioGroup.setOnCheckedChangeListener { _, checkedId ->
|
||||||
onFilterTypeChanged(checkedId)
|
onFilterTypeChanged(checkedId)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.filter
|
||||||
|
|
||||||
|
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||||
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class FilterDevicesUseCase @Inject constructor() {
|
||||||
|
|
||||||
|
fun execute(
|
||||||
|
devices: List<DeviceFullInfo>,
|
||||||
|
filterType: DeviceManagerFilterType,
|
||||||
|
excludedDeviceIds: List<String> = emptyList(),
|
||||||
|
): List<DeviceFullInfo> {
|
||||||
|
return devices
|
||||||
|
.filter {
|
||||||
|
when (filterType) {
|
||||||
|
DeviceManagerFilterType.ALL_SESSIONS -> true
|
||||||
|
DeviceManagerFilterType.VERIFIED -> it.cryptoDeviceInfo?.isVerified.orFalse()
|
||||||
|
DeviceManagerFilterType.UNVERIFIED -> !it.cryptoDeviceInfo?.isVerified.orFalse()
|
||||||
|
DeviceManagerFilterType.INACTIVE -> it.isInactive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter { it.deviceInfo.deviceId !in excludedDeviceIds }
|
||||||
|
}
|
||||||
|
}
|
@ -20,9 +20,12 @@ import android.content.Context
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.airbnb.epoxy.OnModelBuildFinishedListener
|
||||||
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.epoxy.LayoutManagerStateRestorer
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.databinding.ViewOtherSessionsBinding
|
import im.vector.app.databinding.ViewOtherSessionsBinding
|
||||||
@ -44,18 +47,32 @@ class OtherSessionsView @JvmOverloads constructor(
|
|||||||
@Inject lateinit var otherSessionsController: OtherSessionsController
|
@Inject lateinit var otherSessionsController: OtherSessionsController
|
||||||
|
|
||||||
private val views: ViewOtherSessionsBinding
|
private val views: ViewOtherSessionsBinding
|
||||||
private val recyclerViewDataObserver: RecyclerView.AdapterDataObserver
|
private lateinit var recyclerViewDataObserver: RecyclerView.AdapterDataObserver
|
||||||
|
private lateinit var stateRestorer: LayoutManagerStateRestorer
|
||||||
|
private var modelBuildListener: OnModelBuildFinishedListener? = null
|
||||||
|
|
||||||
var callback: Callback? = null
|
var callback: Callback? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
inflate(context, R.layout.view_other_sessions, this)
|
inflate(context, R.layout.view_other_sessions, this)
|
||||||
views = ViewOtherSessionsBinding.bind(this)
|
views = ViewOtherSessionsBinding.bind(this)
|
||||||
|
|
||||||
otherSessionsController.callback = this
|
configureOtherSessionsRecyclerView()
|
||||||
|
|
||||||
views.otherSessionsViewAllButton.setOnClickListener {
|
views.otherSessionsViewAllButton.setOnClickListener {
|
||||||
callback?.onViewAllOtherSessionsClicked()
|
callback?.onViewAllOtherSessionsClicked()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun configureOtherSessionsRecyclerView() {
|
||||||
|
views.otherSessionsRecyclerView.configureWith(otherSessionsController, hasFixedSize = false)
|
||||||
|
|
||||||
|
val layoutManager = LinearLayoutManager(context)
|
||||||
|
stateRestorer = LayoutManagerStateRestorer(layoutManager)
|
||||||
|
views.otherSessionsRecyclerView.layoutManager = layoutManager
|
||||||
|
layoutManager.recycleChildrenOnDetach = true
|
||||||
|
modelBuildListener = OnModelBuildFinishedListener { it.dispatchTo(stateRestorer) }
|
||||||
|
otherSessionsController.addModelBuildListener(modelBuildListener)
|
||||||
|
|
||||||
recyclerViewDataObserver = object : RecyclerView.AdapterDataObserver() {
|
recyclerViewDataObserver = object : RecyclerView.AdapterDataObserver() {
|
||||||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||||
@ -64,10 +81,11 @@ class OtherSessionsView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
otherSessionsController.adapter.registerAdapterDataObserver(recyclerViewDataObserver)
|
otherSessionsController.adapter.registerAdapterDataObserver(recyclerViewDataObserver)
|
||||||
|
|
||||||
|
otherSessionsController.callback = this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render(devices: List<DeviceFullInfo>, totalNumberOfDevices: Int, showViewAll: Boolean) {
|
fun render(devices: List<DeviceFullInfo>, totalNumberOfDevices: Int, showViewAll: Boolean) {
|
||||||
views.otherSessionsRecyclerView.configureWith(otherSessionsController, hasFixedSize = true)
|
|
||||||
if (showViewAll) {
|
if (showViewAll) {
|
||||||
views.otherSessionsViewAllButton.isVisible = true
|
views.otherSessionsViewAllButton.isVisible = true
|
||||||
views.otherSessionsViewAllButton.text = context.getString(R.string.device_manager_other_sessions_view_all, totalNumberOfDevices)
|
views.otherSessionsViewAllButton.text = context.getString(R.string.device_manager_other_sessions_view_all, totalNumberOfDevices)
|
||||||
@ -78,6 +96,8 @@ class OtherSessionsView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
override fun onDetachedFromWindow() {
|
||||||
|
otherSessionsController.removeModelBuildListener(modelBuildListener)
|
||||||
|
modelBuildListener = null
|
||||||
otherSessionsController.callback = null
|
otherSessionsController.callback = null
|
||||||
otherSessionsController.adapter.unregisterAdapterDataObserver(recyclerViewDataObserver)
|
otherSessionsController.adapter.unregisterAdapterDataObserver(recyclerViewDataObserver)
|
||||||
views.otherSessionsRecyclerView.cleanup()
|
views.otherSessionsRecyclerView.cleanup()
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.othersessions
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
|
|
||||||
|
sealed class OtherSessionsAction : VectorViewModelAction {
|
||||||
|
data class FilterDevices(val filterType: DeviceManagerFilterType) : OtherSessionsAction()
|
||||||
|
}
|
@ -32,9 +32,6 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.databinding.FragmentOtherSessionsBinding
|
import im.vector.app.databinding.FragmentOtherSessionsBinding
|
||||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||||
import im.vector.app.features.settings.devices.v2.DevicesAction
|
|
||||||
import im.vector.app.features.settings.devices.v2.DevicesViewModel
|
|
||||||
import im.vector.app.features.settings.devices.v2.VectorSettingsDevicesViewNavigator
|
|
||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterBottomSheet
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterBottomSheet
|
||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
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.OtherSessionsView
|
||||||
@ -48,9 +45,11 @@ class OtherSessionsFragment :
|
|||||||
VectorBaseBottomSheetDialogFragment.ResultListener,
|
VectorBaseBottomSheetDialogFragment.ResultListener,
|
||||||
OtherSessionsView.Callback {
|
OtherSessionsView.Callback {
|
||||||
|
|
||||||
private val viewModel: DevicesViewModel by fragmentViewModel()
|
private val viewModel: OtherSessionsViewModel by fragmentViewModel()
|
||||||
|
|
||||||
@Inject lateinit var colorProvider: ColorProvider
|
@Inject lateinit var colorProvider: ColorProvider
|
||||||
@Inject lateinit var viewNavigator: VectorSettingsDevicesViewNavigator
|
|
||||||
|
@Inject lateinit var viewNavigator: OtherSessionsViewNavigator
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentOtherSessionsBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentOtherSessionsBinding {
|
||||||
return FragmentOtherSessionsBinding.inflate(layoutInflater, container, false)
|
return FragmentOtherSessionsBinding.inflate(layoutInflater, container, false)
|
||||||
@ -59,9 +58,19 @@ class OtherSessionsFragment :
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setupToolbar(views.otherSessionsToolbar).allowBack()
|
setupToolbar(views.otherSessionsToolbar).allowBack()
|
||||||
|
observeViewEvents()
|
||||||
initFilterView()
|
initFilterView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeViewEvents() {
|
||||||
|
viewModel.observeViewEvents {
|
||||||
|
when (it) {
|
||||||
|
is OtherSessionsViewEvents.Loading -> showLoading(it.message)
|
||||||
|
is OtherSessionsViewEvents.Failure -> showFailure(it.throwable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun initFilterView() {
|
private fun initFilterView() {
|
||||||
views.otherSessionsFilterFrameLayout.debouncedClicks {
|
views.otherSessionsFilterFrameLayout.debouncedClicks {
|
||||||
withState(viewModel) { state ->
|
withState(viewModel) { state ->
|
||||||
@ -72,7 +81,7 @@ class OtherSessionsFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
views.otherSessionsClearFilterButton.debouncedClicks {
|
views.otherSessionsClearFilterButton.debouncedClicks {
|
||||||
viewModel.handle(DevicesAction.FilterDevices(DeviceManagerFilterType.ALL_SESSIONS))
|
viewModel.handle(OtherSessionsAction.FilterDevices(DeviceManagerFilterType.ALL_SESSIONS))
|
||||||
}
|
}
|
||||||
|
|
||||||
views.deviceListOtherSessions.callback = this
|
views.deviceListOtherSessions.callback = this
|
||||||
@ -80,18 +89,13 @@ class OtherSessionsFragment :
|
|||||||
|
|
||||||
override fun onBottomSheetResult(resultCode: Int, data: Any?) {
|
override fun onBottomSheetResult(resultCode: Int, data: Any?) {
|
||||||
if (resultCode == RESULT_OK && data != null && data is DeviceManagerFilterType) {
|
if (resultCode == RESULT_OK && data != null && data is DeviceManagerFilterType) {
|
||||||
viewModel.handle(DevicesAction.FilterDevices(data))
|
viewModel.handle(OtherSessionsAction.FilterDevices(data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
if (state.devices is Success) {
|
if (state.devices is Success) {
|
||||||
with(state) {
|
renderDevices(state.devices(), state.currentFilter)
|
||||||
val devices = state.devices()
|
|
||||||
?.filter { it.deviceInfo.deviceId != state.currentSessionCrossSigningInfo.deviceId }
|
|
||||||
?.filteredDevices()
|
|
||||||
renderDevices(devices, state.currentFilter)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import im.vector.app.core.extensions.setTextWithColoredPart
|
|||||||
import im.vector.app.databinding.ViewOtherSessionSecurityRecommendationBinding
|
import im.vector.app.databinding.ViewOtherSessionSecurityRecommendationBinding
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class OtherSessionsSecurityRecommendationView @JvmOverloads constructor(
|
class OtherSessionsSecurityRecommendationView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0
|
defStyleAttr: Int = 0
|
||||||
@ -84,13 +84,14 @@ class OtherSessionsSecurityRecommendationView @JvmOverloads constructor(
|
|||||||
|
|
||||||
private fun setDescription(description: String?) {
|
private fun setDescription(description: String?) {
|
||||||
val learnMore = context.getString(R.string.action_learn_more)
|
val learnMore = context.getString(R.string.action_learn_more)
|
||||||
val stringBuilder = StringBuilder()
|
val formattedDescription = buildString {
|
||||||
stringBuilder.append(description)
|
append(description)
|
||||||
stringBuilder.append(" ")
|
append(" ")
|
||||||
stringBuilder.append(learnMore)
|
append(learnMore)
|
||||||
|
}
|
||||||
|
|
||||||
views.recommendationDescriptionTextView.setTextWithColoredPart(
|
views.recommendationDescriptionTextView.setTextWithColoredPart(
|
||||||
fullText = stringBuilder.toString(),
|
fullText = formattedDescription,
|
||||||
coloredPart = learnMore,
|
coloredPart = learnMore,
|
||||||
underline = false
|
underline = false
|
||||||
) {
|
) {
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.othersessions
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewEvents
|
||||||
|
|
||||||
|
sealed class OtherSessionsViewEvents : VectorViewEvents {
|
||||||
|
data class Loading(val message: CharSequence? = null) : OtherSessionsViewEvents()
|
||||||
|
data class Failure(val throwable: Throwable) : OtherSessionsViewEvents()
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* 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.othersessions
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
|
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||||
|
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
|
import im.vector.app.core.utils.PublishDataSource
|
||||||
|
import im.vector.app.features.settings.devices.v2.GetDeviceFullInfoListUseCase
|
||||||
|
import im.vector.app.features.settings.devices.v2.RefreshDevicesUseCase
|
||||||
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
|
import im.vector.lib.core.utils.flow.throttleFirst
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
|
class OtherSessionsViewModel @AssistedInject constructor(
|
||||||
|
@Assisted initialState: OtherSessionsViewState,
|
||||||
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
|
private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase,
|
||||||
|
private val refreshDevicesUseCase: RefreshDevicesUseCase,
|
||||||
|
) : VectorViewModel<OtherSessionsViewState, OtherSessionsAction, OtherSessionsViewEvents>(initialState), VerificationService.Listener {
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory : MavericksAssistedViewModelFactory<OtherSessionsViewModel, OtherSessionsViewState> {
|
||||||
|
override fun create(initialState: OtherSessionsViewState): OtherSessionsViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MavericksViewModelFactory<OtherSessionsViewModel, OtherSessionsViewState> by hiltMavericksViewModelFactory()
|
||||||
|
|
||||||
|
private var observeDevicesJob: Job? = null
|
||||||
|
|
||||||
|
private val refreshSource = PublishDataSource<Unit>()
|
||||||
|
private val refreshThrottleDelayMs = 4.seconds.inWholeMilliseconds
|
||||||
|
|
||||||
|
init {
|
||||||
|
observeDevices(initialState.currentFilter)
|
||||||
|
addVerificationListener()
|
||||||
|
observeRefreshSource()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
removeVerificationListener()
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeDevices(currentFilter: DeviceManagerFilterType) {
|
||||||
|
observeDevicesJob?.cancel()
|
||||||
|
observeDevicesJob = getDeviceFullInfoListUseCase.execute(
|
||||||
|
filterType = currentFilter,
|
||||||
|
excludeCurrentDevice = true
|
||||||
|
)
|
||||||
|
.execute { async ->
|
||||||
|
if (async is Success) {
|
||||||
|
copy(
|
||||||
|
devices = async,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
copy(
|
||||||
|
devices = async
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addVerificationListener() {
|
||||||
|
activeSessionHolder.getSafeActiveSession()
|
||||||
|
?.cryptoService()
|
||||||
|
?.verificationService()
|
||||||
|
?.addListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeVerificationListener() {
|
||||||
|
activeSessionHolder.getSafeActiveSession()
|
||||||
|
?.cryptoService()
|
||||||
|
?.verificationService()
|
||||||
|
?.removeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeRefreshSource() {
|
||||||
|
refreshSource.stream()
|
||||||
|
.throttleFirst(refreshThrottleDelayMs)
|
||||||
|
.onEach { refreshDevicesUseCase.execute() }
|
||||||
|
.launchIn(viewModelScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transactionUpdated(tx: VerificationTransaction) {
|
||||||
|
if (tx.state == VerificationTxState.Verified) {
|
||||||
|
queryRefreshDevicesList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun queryRefreshDevicesList() {
|
||||||
|
refreshSource.post(Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(action: OtherSessionsAction) {
|
||||||
|
when (action) {
|
||||||
|
is OtherSessionsAction.FilterDevices -> handleFilterDevices(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleFilterDevices(action: OtherSessionsAction.FilterDevices) {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
currentFilter = action.filterType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
observeDevices(action.filterType)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.othersessions
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class OtherSessionsViewNavigator @Inject constructor() {
|
||||||
|
|
||||||
|
fun navigateToSessionOverview(context: Context, deviceId: String) {
|
||||||
|
context.startActivity(SessionOverviewActivity.newIntent(context, deviceId))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.othersessions
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.MavericksState
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||||
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
|
|
||||||
|
data class OtherSessionsViewState(
|
||||||
|
val devices: Async<List<DeviceFullInfo>> = Uninitialized,
|
||||||
|
val currentFilter: DeviceManagerFilterType = DeviceManagerFilterType.ALL_SESSIONS,
|
||||||
|
) : MavericksState
|
@ -47,6 +47,7 @@
|
|||||||
android:text="@string/device_manager_filter_option_verified" />
|
android:text="@string/device_manager_filter_option_verified" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/filterOptionVerifiedTextView"
|
||||||
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -63,6 +64,7 @@
|
|||||||
android:text="@string/device_manager_filter_option_unverified" />
|
android:text="@string/device_manager_filter_option_unverified" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/filterOptionUnverifiedTextView"
|
||||||
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -79,7 +81,7 @@
|
|||||||
android:text="@string/device_manager_filter_option_inactive" />
|
android:text="@string/device_manager_filter_option_inactive" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/filterOptionInactiveRadioButtonDescription"
|
android:id="@+id/filterOptionInactiveTextView"
|
||||||
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:navigationIcon="@drawable/ic_back_24dp"
|
app:navigationIcon="@drawable/ic_back_24dp"
|
||||||
app:title="@string/device_manager_other_sessions_title">
|
app:title="@string/settings_sessions_other_title">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/otherSessionsFilterFrameLayout"
|
android:id="@+id/otherSessionsFilterFrameLayout"
|
||||||
|
Loading…
Reference in New Issue
Block a user