List devices.

This commit is contained in:
Onuray Sahin 2022-09-08 13:47:07 +03:00
parent 643f99b8e0
commit ab4ebc7f11
8 changed files with 81 additions and 9 deletions

View file

@ -19,6 +19,8 @@ package im.vector.app.features.settings.devices.v2
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MavericksState
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(
val currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo = CurrentSessionCrossSigningInfo(),
@ -26,4 +28,17 @@ data class DevicesViewState(
val unverifiedSessionsCount: Int = 0,
val inactiveSessionsCount: Int = 0,
val isLoading: Boolean = false,
) : MavericksState
val currentFilter: DeviceManagerFilterType = DeviceManagerFilterType.ALL_SESSIONS,
) : 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
}
}
}
}

View file

@ -37,10 +37,11 @@ import im.vector.app.core.resources.DrawableProvider
import im.vector.app.databinding.FragmentSettingsDevicesBinding
import im.vector.app.features.crypto.recover.SetupMode
import im.vector.app.features.crypto.verification.VerificationBottomSheet
import im.vector.app.features.settings.devices.v2.list.NUMBER_OF_OTHER_DEVICES_TO_RENDER
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.list.SecurityRecommendationViewState
import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
import im.vector.app.features.settings.devices.v2.list.OtherSessionsView
import javax.inject.Inject
/**
@ -198,7 +199,7 @@ class VectorSettingsDevicesFragment :
} else {
views.deviceListHeaderOtherSessions.isVisible = true
views.deviceListOtherSessions.isVisible = true
views.deviceListOtherSessions.render(otherDevices)
views.deviceListOtherSessions.render(otherDevices.take(NUMBER_OF_OTHER_DEVICES_TO_RENDER), otherDevices.size)
}
}

View file

@ -50,7 +50,7 @@ class OtherSessionsController @Inject constructor(
text(host.stringProvider.getString(R.string.no_result_placeholder))
}
} else {
data.take(NUMBER_OF_OTHER_DEVICES_TO_RENDER).forEach { device ->
data.forEach { device ->
val dateFormatKind = if (device.isInactive) DateFormatKind.TIMELINE_DAY_DIVIDER else DateFormatKind.DEFAULT_DATE_AND_TIME
val formattedLastActivityDate = host.dateFormatter.format(device.deviceInfo.lastSeenTs, dateFormatKind)
val description = if (device.isInactive) {

View file

@ -55,9 +55,9 @@ class OtherSessionsView @JvmOverloads constructor(
}
}
fun render(devices: List<DeviceFullInfo>) {
fun render(devices: List<DeviceFullInfo>, totalNumberOfDevices: Int) {
views.otherSessionsRecyclerView.configureWith(otherSessionsController, hasFixedSize = true)
views.otherSessionsViewAllButton.text = context.getString(R.string.device_manager_other_sessions_view_all, devices.size)
views.otherSessionsViewAllButton.text = context.getString(R.string.device_manager_other_sessions_view_all, totalNumberOfDevices)
otherSessionsController.setData(devices)
}

View file

@ -54,7 +54,12 @@ class SessionsListHeaderView @JvmOverloads constructor(
private fun setTitle(typedArray: TypedArray) {
val title = typedArray.getString(R.styleable.SessionsListHeaderView_devicesListHeaderTitle)
binding.sessionsListHeaderTitle.text = title
if (title.isNullOrEmpty()) {
binding.sessionsListHeaderTitle.isVisible = false
} else {
binding.sessionsListHeaderTitle.isVisible = true
binding.sessionsListHeaderTitle.text = title
}
}
private fun setDescription(typedArray: TypedArray) {

View file

@ -21,16 +21,25 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isVisible
import com.airbnb.mvrx.Success
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.core.platform.VectorBaseBottomSheetDialogFragment.ResultListener.Companion.RESULT_OK
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentOtherSessionsBinding
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
import im.vector.app.features.settings.devices.v2.DevicesViewModel
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterBottomSheet
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
@AndroidEntryPoint
class OtherSessionsFragment : VectorBaseFragment<FragmentOtherSessionsBinding>(), VectorBaseBottomSheetDialogFragment.ResultListener {
private val viewModel: DevicesViewModel by fragmentViewModel()
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentOtherSessionsBinding {
return FragmentOtherSessionsBinding.inflate(layoutInflater, container, false)
}
@ -54,4 +63,25 @@ class OtherSessionsFragment : VectorBaseFragment<FragmentOtherSessionsBinding>()
Toast.makeText(requireContext(), data.toString(), Toast.LENGTH_LONG).show()
}
}
override fun invalidate() = withState(viewModel) { state ->
if (state.devices is Success) {
with(state) {
val devices = state.devices()
?.filter { it.deviceInfo.deviceId != state.currentSessionCrossSigningInfo.deviceId }
?.filteredDevices()
renderDevices(devices, state.currentFilter)
}
}
}
private fun renderDevices(devices: List<DeviceFullInfo>?, currentFilter: DeviceManagerFilterType) {
views.otherSessionsFilterBadgeImageView.isVisible = currentFilter != DeviceManagerFilterType.ALL_SESSIONS
if (devices.isNullOrEmpty()) {
// TODO. Render empty state
} else {
views.deviceListOtherSessions.render(devices, devices.size)
}
}
}

View file

@ -46,4 +46,25 @@
</com.google.android.material.appbar.AppBarLayout>
<im.vector.app.features.settings.devices.v2.list.SessionsListHeaderView
android:id="@+id/deviceListHeaderOtherSessions"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:devicesListHeaderDescription="@string/settings_sessions_other_description"
app:devicesListHeaderTitle=""
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appBarLayout"/>
<im.vector.app.features.settings.devices.v2.list.OtherSessionsView
android:id="@+id/deviceListOtherSessions"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/deviceListHeaderOtherSessions" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -23,10 +23,10 @@
style="@style/TextAppearance.Vector.Body.DevicesManagement"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/layout_horizontal_margin"
android:layout_marginTop="18.5dp"
android:layout_marginEnd="40dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/sessions_list_header_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/sessions_list_header_title"
tools:text="For best security, verify your sessions and sign out from any session that you dont recognize or use anymore. Learn More." />
</merge>