diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index 5eaec2c84b..c33185ba26 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -3267,6 +3267,12 @@
Last activity %1$s
Session details
Application, device, and activity information.
+ Session
+ Session name
+ Session ID
+ Last activity
+ Device
+ IP address
%s\nis looking a little empty.
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/CheckIfSectionDeviceIsVisibleUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/CheckIfSectionDeviceIsVisibleUseCase.kt
new file mode 100644
index 0000000000..0bfcc371c5
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/CheckIfSectionDeviceIsVisibleUseCase.kt
@@ -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.details
+
+import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
+import javax.inject.Inject
+
+// TODO add unit tests
+class CheckIfSectionDeviceIsVisibleUseCase @Inject constructor() {
+
+ fun execute(deviceInfo: DeviceInfo): Boolean {
+ return deviceInfo.lastSeenIp?.isNotEmpty().orFalse()
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/CheckIfSectionSessionIsVisibleUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/CheckIfSectionSessionIsVisibleUseCase.kt
new file mode 100644
index 0000000000..b07d3b7ebf
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/CheckIfSectionSessionIsVisibleUseCase.kt
@@ -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 org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
+import javax.inject.Inject
+
+// TODO add unit tests
+class CheckIfSectionSessionIsVisibleUseCase @Inject constructor() {
+
+ fun execute(deviceInfo: DeviceInfo): Boolean {
+ return deviceInfo.displayName?.isNotEmpty().orFalse() ||
+ deviceInfo.deviceId?.isNotEmpty().orFalse() ||
+ (deviceInfo.lastSeenTs ?: 0) > 0
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsContentItem.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsContentItem.kt
index 5c3a46475d..e0f433af35 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsContentItem.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsContentItem.kt
@@ -25,7 +25,7 @@ import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
@EpoxyModelClass
-abstract class SessionDetailsContentItem : VectorEpoxyModel(R.layout.item_session_details_header) {
+abstract class SessionDetailsContentItem : VectorEpoxyModel(R.layout.item_session_details_content) {
@EpoxyAttribute
var title: String? = null
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsController.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsController.kt
new file mode 100644
index 0000000000..5a55ef55ef
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsController.kt
@@ -0,0 +1,109 @@
+/*
+ * 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 androidx.annotation.StringRes
+import com.airbnb.epoxy.TypedEpoxyController
+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 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 stringProvider: StringProvider,
+ private val dateFormatter: VectorDateFormatter,
+) : TypedEpoxyController() {
+
+ var callback: Callback? = null
+
+ interface Callback {
+ fun onItemLongClicked(content: String)
+ }
+
+ override fun buildModels(data: DeviceInfo?) {
+ data?.let { info ->
+ if (hasSectionSession(data)) {
+ buildSectionSession(info)
+ }
+
+ if (hasSectionDevice(data)) {
+ // TODO add a marginTop of 48dp if the session section is visible
+ buildSectionDevice(info)
+ }
+ }
+ }
+
+ private fun buildHeaderItem(@StringRes titleResId: Int) {
+ val host = this
+ sessionDetailsHeaderItem {
+ id(titleResId)
+ title(host.stringProvider.getString(titleResId))
+ }
+ }
+
+ private fun buildContentItem(@StringRes titleResId: Int, value: String) {
+ val host = this
+ sessionDetailsContentItem {
+ id(titleResId)
+ title(host.stringProvider.getString(titleResId))
+ description(value)
+ }
+ }
+
+ private fun hasSectionSession(data: DeviceInfo): Boolean {
+ return checkIfSectionSessionIsVisibleUseCase.execute(data)
+ }
+
+ private fun buildSectionSession(data: DeviceInfo) {
+ val sessionName = data.displayName
+ val sessionId = data.deviceId
+ val sessionLastSeenTs = data.lastSeenTs
+
+ buildHeaderItem(R.string.device_manager_session_details_section_session_title)
+
+ // TODO hide divider on the last visible item
+ sessionName?.let {
+ buildContentItem(R.string.device_manager_session_details_session_name, it)
+ }
+ sessionId?.let {
+ buildContentItem(R.string.device_manager_session_details_session_id, it)
+ }
+ sessionLastSeenTs?.let {
+ val formattedDate = dateFormatter.format(it, DateFormatKind.MESSAGE_DETAIL)
+ buildContentItem(R.string.device_manager_session_details_session_last_activity, formattedDate)
+ }
+ }
+
+ private fun hasSectionDevice(data: DeviceInfo): Boolean {
+ return checkIfSectionDeviceIsVisibleUseCase.execute(data)
+ }
+
+ private fun buildSectionDevice(data: DeviceInfo) {
+ val lastSeenIp = data.lastSeenIp
+
+ buildHeaderItem(R.string.device_manager_session_details_section_device_title)
+
+ // TODO hide divider on the last visible item
+ lastSeenIp?.let {
+ buildContentItem(R.string.device_manager_session_details_device_ip_address, it)
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsFragment.kt
index 278f9eec7a..bf0037b0e8 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/details/SessionDetailsFragment.kt
@@ -21,11 +21,19 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.isGone
+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.R
+import im.vector.app.core.extensions.cleanup
+import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentSessionDetailsBinding
+import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
+import javax.inject.Inject
/**
* Display the details info about a Session.
@@ -34,6 +42,8 @@ import im.vector.app.databinding.FragmentSessionDetailsBinding
class SessionDetailsFragment :
VectorBaseFragment() {
+ @Inject lateinit var sessionDetailsController: SessionDetailsController
+
private val viewModel: SessionDetailsViewModel by fragmentViewModel()
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSessionDetailsBinding {
@@ -43,6 +53,7 @@ class SessionDetailsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initToolbar()
+ initSessionDetails()
}
private fun initToolbar() {
@@ -51,14 +62,33 @@ class SessionDetailsFragment :
?.setTitle(R.string.device_manager_session_details_title)
}
- /*override fun invalidate() = withState(viewModel) { state ->
+ private fun initSessionDetails() {
+ views.sessionDetails.configureWith(sessionDetailsController)
+ }
+
+ override fun onDestroyView() {
+ cleanUpSessionDetails()
+ super.onDestroyView()
+ }
+
+ private fun cleanUpSessionDetails() {
+ views.sessionDetails.cleanup()
+ }
+
+ override fun invalidate() = withState(viewModel) { state ->
if (state.deviceInfo is Success) {
renderSessionDetails(state.deviceInfo.invoke())
} else {
- hideSessionInfo()
+ hideSessionDetails()
}
}
private fun renderSessionDetails(deviceInfo: DeviceInfo) {
- }*/
+ views.sessionDetails.isVisible = true
+ sessionDetailsController.setData(deviceInfo)
+ }
+
+ private fun hideSessionDetails() {
+ views.sessionDetails.isGone = true
+ }
}
diff --git a/vector/src/main/res/layout/fragment_session_details.xml b/vector/src/main/res/layout/fragment_session_details.xml
index 1354408486..de0ce27798 100644
--- a/vector/src/main/res/layout/fragment_session_details.xml
+++ b/vector/src/main/res/layout/fragment_session_details.xml
@@ -1,6 +1,21 @@
+
+