Rendering Application section into session details

This commit is contained in:
Maxime NATUREL 2022-10-05 17:49:57 +02:00
parent acd05a0233
commit 9f9f6e14be
7 changed files with 100 additions and 31 deletions

View file

@ -3309,6 +3309,10 @@
<string name="device_manager_session_details_session_name">Session name</string>
<string name="device_manager_session_details_session_id">Session ID</string>
<string name="device_manager_session_details_session_last_activity">Last activity</string>
<string name="device_manager_session_details_application">Application</string>
<string name="device_manager_session_details_application_name">Name</string>
<string name="device_manager_session_details_application_version">Version</string>
<string name="device_manager_session_details_application_url">URL</string>
<string name="device_manager_session_details_device_ip_address">IP address</string>
<string name="device_manager_session_rename">Rename session</string>
<string name="device_manager_session_rename_edit_hint">Session name</string>

View file

@ -0,0 +1,31 @@
/*
* 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.details
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
import org.matrix.android.sdk.api.extensions.orFalse
import javax.inject.Inject
class CheckIfSectionApplicationIsVisibleUseCase @Inject constructor() {
// TODO add unit tests
fun execute(matrixClientInfoContent: MatrixClientInfoContent?): Boolean {
return matrixClientInfoContent?.name?.isNotEmpty().orFalse() ||
matrixClientInfoContent?.version?.isNotEmpty().orFalse() ||
matrixClientInfoContent?.url?.isNotEmpty().orFalse()
}
}

View file

@ -23,17 +23,20 @@ import im.vector.app.R
import im.vector.app.core.date.DateFormatKind
import im.vector.app.core.date.VectorDateFormatter
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
import im.vector.app.core.utils.DimensionConverter
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
import javax.inject.Inject
class SessionDetailsController @Inject constructor(
private val checkIfSectionSessionIsVisibleUseCase: CheckIfSectionSessionIsVisibleUseCase,
private val checkIfSectionDeviceIsVisibleUseCase: CheckIfSectionDeviceIsVisibleUseCase,
private val checkIfSectionApplicationIsVisibleUseCase: CheckIfSectionApplicationIsVisibleUseCase,
private val stringProvider: StringProvider,
private val dateFormatter: VectorDateFormatter,
private val dimensionConverter: DimensionConverter,
) : TypedEpoxyController<DeviceInfo>() {
) : TypedEpoxyController<DeviceFullInfo>() {
var callback: Callback? = null
@ -41,15 +44,22 @@ class SessionDetailsController @Inject constructor(
fun onItemLongClicked(content: String)
}
override fun buildModels(data: DeviceInfo?) {
data?.let { info ->
val hasSectionSession = hasSectionSession(data)
override fun buildModels(data: DeviceFullInfo?) {
data?.let { fullInfo ->
val deviceInfo = fullInfo.deviceInfo
val matrixClientInfo = fullInfo.matrixClientInfo
val hasSectionSession = hasSectionSession(deviceInfo)
if (hasSectionSession) {
buildSectionSession(info)
buildSectionSession(deviceInfo)
}
if (hasSectionDevice(data)) {
buildSectionDevice(info, addExtraTopMargin = hasSectionSession)
val hasApplicationSection = hasSectionApplication(matrixClientInfo)
if (hasApplicationSection && matrixClientInfo != null) {
buildSectionApplication(matrixClientInfo, addExtraTopMargin = hasSectionSession)
}
if (hasSectionDevice(deviceInfo)) {
buildSectionDevice(deviceInfo, addExtraTopMargin = hasSectionSession || hasApplicationSection)
}
}
}
@ -83,39 +93,64 @@ class SessionDetailsController @Inject constructor(
}
private fun buildSectionSession(data: DeviceInfo) {
val sessionName = data.displayName
val sessionId = data.deviceId
val sessionLastSeenTs = data.lastSeenTs
val sessionName = data.displayName.orEmpty()
val sessionId = data.deviceId.orEmpty()
val sessionLastSeenTs = data.lastSeenTs ?: -1
buildHeaderItem(R.string.device_manager_session_title)
sessionName?.let {
val hasDivider = sessionId != null || sessionLastSeenTs != null
buildContentItem(R.string.device_manager_session_details_session_name, it, hasDivider)
if (sessionName.isNotEmpty()) {
val hasDivider = sessionId.isNotEmpty() || sessionLastSeenTs > 0
buildContentItem(R.string.device_manager_session_details_session_name, sessionName, hasDivider)
}
sessionId?.let {
val hasDivider = sessionLastSeenTs != null
buildContentItem(R.string.device_manager_session_details_session_id, it, hasDivider)
if (sessionId.isNotEmpty()) {
val hasDivider = sessionLastSeenTs > 0
buildContentItem(R.string.device_manager_session_details_session_id, sessionId, hasDivider)
}
sessionLastSeenTs?.let {
val formattedDate = dateFormatter.format(it, DateFormatKind.MESSAGE_DETAIL)
if (sessionLastSeenTs > 0) {
val formattedDate = dateFormatter.format(sessionLastSeenTs, DateFormatKind.MESSAGE_DETAIL)
val hasDivider = false
buildContentItem(R.string.device_manager_session_details_session_last_activity, formattedDate, hasDivider)
}
}
private fun hasSectionApplication(matrixClientInfoContent: MatrixClientInfoContent?): Boolean {
return checkIfSectionApplicationIsVisibleUseCase.execute(matrixClientInfoContent)
}
private fun buildSectionApplication(matrixClientInfoContent: MatrixClientInfoContent, addExtraTopMargin: Boolean) {
val name = matrixClientInfoContent.name.orEmpty()
val version = matrixClientInfoContent.version.orEmpty()
val url = matrixClientInfoContent.url.orEmpty()
buildHeaderItem(R.string.device_manager_session_details_application, addExtraTopMargin)
if (name.isNotEmpty()) {
val hasDivider = version.isNotEmpty() || url.isNotEmpty()
buildContentItem(R.string.device_manager_session_details_application_name, name, hasDivider)
}
if (version.isNotEmpty()) {
val hasDivider = url.isNotEmpty()
buildContentItem(R.string.device_manager_session_details_application_version, version, hasDivider)
}
if (url.isNotEmpty()) {
val hasDivider = false
buildContentItem(R.string.device_manager_session_details_application_url, url, hasDivider)
}
}
private fun hasSectionDevice(data: DeviceInfo): Boolean {
return checkIfSectionDeviceIsVisibleUseCase.execute(data)
}
private fun buildSectionDevice(data: DeviceInfo, addExtraTopMargin: Boolean) {
val lastSeenIp = data.lastSeenIp
val lastSeenIp = data.lastSeenIp.orEmpty()
buildHeaderItem(R.string.device_manager_device_title, addExtraTopMargin)
lastSeenIp?.let {
if (lastSeenIp.isNotEmpty()) {
val hasDivider = false
buildContentItem(R.string.device_manager_session_details_device_ip_address, it, hasDivider)
buildContentItem(R.string.device_manager_session_details_device_ip_address, lastSeenIp, hasDivider)
}
}
}

View file

@ -33,6 +33,7 @@ import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.platform.showOptimizedSnackbar
import im.vector.app.databinding.FragmentSessionDetailsBinding
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
import javax.inject.Inject
@ -92,16 +93,16 @@ class SessionDetailsFragment :
}
override fun invalidate() = withState(viewModel) { state ->
if (state.deviceInfo is Success) {
renderSessionDetails(state.deviceInfo.invoke())
if (state.deviceFullInfo is Success) {
renderSessionDetails(state.deviceFullInfo.invoke())
} else {
hideSessionDetails()
}
}
private fun renderSessionDetails(deviceInfo: DeviceInfo) {
private fun renderSessionDetails(deviceFullInfo: DeviceFullInfo) {
views.sessionDetails.isVisible = true
sessionDetailsController.setData(deviceInfo)
sessionDetailsController.setData(deviceFullInfo)
}
private fun hideSessionDetails() {

View file

@ -48,7 +48,7 @@ class SessionDetailsViewModel @AssistedInject constructor(
private fun observeSessionInfo(deviceId: String) {
getDeviceFullInfoUseCase.execute(deviceId)
.onEach { setState { copy(deviceInfo = Success(it.deviceInfo)) } }
.onEach { setState { copy(deviceFullInfo = Success(it)) } }
.launchIn(viewModelScope)
}

View file

@ -19,11 +19,11 @@ package im.vector.app.features.settings.devices.v2.details
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.Uninitialized
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
data class SessionDetailsViewState(
val deviceId: String,
val deviceInfo: Async<DeviceInfo> = Uninitialized,
val deviceFullInfo: Async<DeviceFullInfo> = Uninitialized,
) : MavericksState {
constructor(args: SessionDetailsArgs) : this(
deviceId = args.deviceId

View file

@ -57,12 +57,10 @@ class SessionDetailsViewModelTest {
fun `given the viewModel has been initialized then viewState is updated with session info`() {
// Given
val deviceFullInfo = mockk<DeviceFullInfo>()
val deviceInfo = mockk<DeviceInfo>()
every { deviceFullInfo.deviceInfo } returns deviceInfo
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo)
val expectedState = SessionDetailsViewState(
deviceId = A_SESSION_ID,
deviceInfo = Success(deviceInfo)
deviceFullInfo = Success(deviceFullInfo)
)
// When