Adding last seen details + fix observation of wrong deviceId in ViewModel
This commit is contained in:
parent
d12bb09273
commit
1ad585e154
@ -3256,6 +3256,7 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="device_manager_current_session_title">Current Session</string>
|
<string name="device_manager_current_session_title">Current Session</string>
|
||||||
<string name="device_manager_session_title">Session</string>
|
<string name="device_manager_session_title">Session</string>
|
||||||
|
<string name="device_manager_session_last_activity">Last activity %1$s</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>
|
||||||
|
@ -31,6 +31,7 @@ import com.airbnb.mvrx.fragmentViewModel
|
|||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
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.date.VectorDateFormatter
|
||||||
import im.vector.app.core.dialogs.ManuallyVerifyDialog
|
import im.vector.app.core.dialogs.ManuallyVerifyDialog
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.FragmentSettingsDevicesBinding
|
import im.vector.app.databinding.FragmentSettingsDevicesBinding
|
||||||
@ -55,6 +56,8 @@ class VectorSettingsDevicesFragment :
|
|||||||
|
|
||||||
@Inject lateinit var viewNavigator: VectorSettingsDevicesViewNavigator
|
@Inject lateinit var viewNavigator: VectorSettingsDevicesViewNavigator
|
||||||
|
|
||||||
|
@Inject lateinit var dateFormatter: VectorDateFormatter
|
||||||
|
|
||||||
private val viewModel: DevicesViewModel by fragmentViewModel()
|
private val viewModel: DevicesViewModel by fragmentViewModel()
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSettingsDevicesBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSettingsDevicesBinding {
|
||||||
@ -214,7 +217,7 @@ class VectorSettingsDevicesFragment :
|
|||||||
isCurrentSession = true,
|
isCurrentSession = true,
|
||||||
deviceFullInfo = it
|
deviceFullInfo = it
|
||||||
)
|
)
|
||||||
views.deviceListCurrentSession.render(viewState)
|
views.deviceListCurrentSession.render(viewState, dateFormatter)
|
||||||
views.deviceListCurrentSession.debouncedClicks {
|
views.deviceListCurrentSession.debouncedClicks {
|
||||||
currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) }
|
currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) }
|
||||||
}
|
}
|
||||||
@ -226,10 +229,10 @@ class VectorSettingsDevicesFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToSessionOverview(sessionId: String) {
|
private fun navigateToSessionOverview(deviceId: String) {
|
||||||
viewNavigator.navigateToSessionOverview(
|
viewNavigator.navigateToSessionOverview(
|
||||||
context = requireActivity(),
|
context = requireActivity(),
|
||||||
sessionId = sessionId
|
deviceId = deviceId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class VectorSettingsDevicesViewNavigator @Inject constructor() {
|
class VectorSettingsDevicesViewNavigator @Inject constructor() {
|
||||||
|
|
||||||
fun navigateToSessionOverview(context: Context, sessionId: String) {
|
fun navigateToSessionOverview(context: Context, deviceId: String) {
|
||||||
context.startActivity(SessionOverviewActivity.newIntent(context, sessionId))
|
context.startActivity(SessionOverviewActivity.newIntent(context, deviceId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,15 @@ package im.vector.app.features.settings.devices.v2.list
|
|||||||
import android.content.Context
|
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.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.date.DateFormatKind
|
||||||
|
import im.vector.app.core.date.VectorDateFormatter
|
||||||
import im.vector.app.core.extensions.setTextWithColoredPart
|
import im.vector.app.core.extensions.setTextWithColoredPart
|
||||||
import im.vector.app.databinding.ViewSessionInfoBinding
|
import im.vector.app.databinding.ViewSessionInfoBinding
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
|
|
||||||
class SessionInfoView @JvmOverloads constructor(
|
class SessionInfoView @JvmOverloads constructor(
|
||||||
@ -43,13 +47,14 @@ class SessionInfoView @JvmOverloads constructor(
|
|||||||
|
|
||||||
val viewDetailsButton = views.sessionInfoViewDetailsButton
|
val viewDetailsButton = views.sessionInfoViewDetailsButton
|
||||||
|
|
||||||
fun render(sessionInfoViewState: SessionInfoViewState) {
|
fun render(sessionInfoViewState: SessionInfoViewState, dateFormatter: VectorDateFormatter) {
|
||||||
renderDeviceInfo(sessionInfoViewState.deviceFullInfo.deviceInfo.displayName.orEmpty())
|
renderDeviceInfo(sessionInfoViewState.deviceFullInfo.deviceInfo.displayName.orEmpty())
|
||||||
renderVerificationStatus(
|
renderVerificationStatus(
|
||||||
sessionInfoViewState.deviceFullInfo.trustLevelForShield,
|
sessionInfoViewState.deviceFullInfo.trustLevelForShield,
|
||||||
sessionInfoViewState.isCurrentSession,
|
sessionInfoViewState.isCurrentSession,
|
||||||
sessionInfoViewState.hasLearnMoreLink
|
sessionInfoViewState.isLearnMoreLinkVisible
|
||||||
)
|
)
|
||||||
|
renderDeviceLastSeenDetails(sessionInfoViewState.deviceFullInfo.deviceInfo, dateFormatter, sessionInfoViewState.isLastSeenDetailsVisible)
|
||||||
renderDetailsButton(sessionInfoViewState.isDetailsButtonVisible)
|
renderDetailsButton(sessionInfoViewState.isDetailsButtonVisible)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +122,33 @@ class SessionInfoView @JvmOverloads constructor(
|
|||||||
views.sessionInfoNameTextView.text = sessionName
|
views.sessionInfoNameTextView.text = sessionName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun renderDeviceLastSeenDetails(
|
||||||
|
deviceInfo: DeviceInfo,
|
||||||
|
dateFormatter: VectorDateFormatter,
|
||||||
|
isLastSeenDetailsVisible: Boolean,
|
||||||
|
) {
|
||||||
|
deviceInfo.lastSeenTs
|
||||||
|
?.takeIf { isLastSeenDetailsVisible }
|
||||||
|
?.let { timestamp ->
|
||||||
|
views.sessionInfoLastActivityTextView.isVisible = true
|
||||||
|
val formattedTs = dateFormatter.format(timestamp, DateFormatKind.DEFAULT_DATE_AND_TIME)
|
||||||
|
views.sessionInfoLastActivityTextView.text = context.getString(R.string.device_manager_session_last_activity, formattedTs)
|
||||||
|
}
|
||||||
|
?: run {
|
||||||
|
views.sessionInfoLastActivityTextView.isGone = true
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceInfo.lastSeenIp
|
||||||
|
?.takeIf { isLastSeenDetailsVisible }
|
||||||
|
?.let { ipAddress ->
|
||||||
|
views.sessionInfoLastIPAddressTextView.isVisible = true
|
||||||
|
views.sessionInfoLastIPAddressTextView.text = ipAddress
|
||||||
|
}
|
||||||
|
?: run {
|
||||||
|
views.sessionInfoLastIPAddressTextView.isGone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun renderDetailsButton(isDetailsButtonVisible: Boolean) {
|
private fun renderDetailsButton(isDetailsButtonVisible: Boolean) {
|
||||||
views.sessionInfoViewDetailsButton.isVisible = isDetailsButtonVisible
|
views.sessionInfoViewDetailsButton.isVisible = isDetailsButtonVisible
|
||||||
}
|
}
|
||||||
|
@ -22,5 +22,6 @@ data class SessionInfoViewState(
|
|||||||
val isCurrentSession: Boolean,
|
val isCurrentSession: Boolean,
|
||||||
val deviceFullInfo: DeviceFullInfo,
|
val deviceFullInfo: DeviceFullInfo,
|
||||||
val isDetailsButtonVisible: Boolean = true,
|
val isDetailsButtonVisible: Boolean = true,
|
||||||
val hasLearnMoreLink: Boolean = false
|
val isLearnMoreLinkVisible: Boolean = false,
|
||||||
|
val isLastSeenDetailsVisible: Boolean = false,
|
||||||
)
|
)
|
||||||
|
@ -43,9 +43,9 @@ class SessionOverviewActivity : SimpleFragmentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newIntent(context: Context, sessionId: String): Intent {
|
fun newIntent(context: Context, deviceId: String): Intent {
|
||||||
return Intent(context, SessionOverviewActivity::class.java).apply {
|
return Intent(context, SessionOverviewActivity::class.java).apply {
|
||||||
putExtra(Mavericks.KEY_ARG, SessionOverviewArgs(sessionId))
|
putExtra(Mavericks.KEY_ARG, SessionOverviewArgs(deviceId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,5 +21,5 @@ import kotlinx.parcelize.Parcelize
|
|||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class SessionOverviewArgs(
|
data class SessionOverviewArgs(
|
||||||
val sessionId: String
|
val deviceId: String
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
@ -29,10 +29,12 @@ import com.airbnb.mvrx.fragmentViewModel
|
|||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
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.date.VectorDateFormatter
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.FragmentSessionOverviewBinding
|
import im.vector.app.databinding.FragmentSessionOverviewBinding
|
||||||
import im.vector.app.features.settings.devices.DeviceFullInfo
|
import im.vector.app.features.settings.devices.DeviceFullInfo
|
||||||
import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
|
import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the overview info about a Session.
|
* Display the overview info about a Session.
|
||||||
@ -41,6 +43,8 @@ import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
|
|||||||
class SessionOverviewFragment :
|
class SessionOverviewFragment :
|
||||||
VectorBaseFragment<FragmentSessionOverviewBinding>() {
|
VectorBaseFragment<FragmentSessionOverviewBinding>() {
|
||||||
|
|
||||||
|
@Inject lateinit var dateFormatter: VectorDateFormatter
|
||||||
|
|
||||||
private val viewModel: SessionOverviewViewModel by fragmentViewModel()
|
private val viewModel: SessionOverviewViewModel by fragmentViewModel()
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSessionOverviewBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSessionOverviewBinding {
|
||||||
@ -89,9 +93,10 @@ class SessionOverviewFragment :
|
|||||||
isCurrentSession = isCurrentSession,
|
isCurrentSession = isCurrentSession,
|
||||||
deviceFullInfo = deviceFullInfo,
|
deviceFullInfo = deviceFullInfo,
|
||||||
isDetailsButtonVisible = false,
|
isDetailsButtonVisible = false,
|
||||||
hasLearnMoreLink = true
|
isLearnMoreLinkVisible = true,
|
||||||
|
isLastSeenDetailsVisible = true,
|
||||||
)
|
)
|
||||||
views.sessionOverviewInfo.render(viewState)
|
views.sessionOverviewInfo.render(viewState, dateFormatter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideSessionInfo() {
|
private fun hideSessionInfo() {
|
||||||
|
@ -46,10 +46,10 @@ class SessionOverviewViewModel @AssistedInject constructor(
|
|||||||
init {
|
init {
|
||||||
val currentDeviceId = session.sessionParams.deviceId.orEmpty()
|
val currentDeviceId = session.sessionParams.deviceId.orEmpty()
|
||||||
setState {
|
setState {
|
||||||
copy(isCurrentSession = sessionId.isNotEmpty() && sessionId == currentDeviceId)
|
copy(isCurrentSession = deviceId.isNotEmpty() && deviceId == currentDeviceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
observeSessionInfo(currentDeviceId)
|
observeSessionInfo(initialState.deviceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeSessionInfo(deviceId: String) {
|
private fun observeSessionInfo(deviceId: String) {
|
||||||
|
@ -22,11 +22,11 @@ import com.airbnb.mvrx.Uninitialized
|
|||||||
import im.vector.app.features.settings.devices.DeviceFullInfo
|
import im.vector.app.features.settings.devices.DeviceFullInfo
|
||||||
|
|
||||||
data class SessionOverviewViewState(
|
data class SessionOverviewViewState(
|
||||||
val sessionId: String,
|
val deviceId: String,
|
||||||
val isCurrentSession: Boolean = false,
|
val isCurrentSession: Boolean = false,
|
||||||
val deviceInfo: Async<DeviceFullInfo> = Uninitialized,
|
val deviceInfo: Async<DeviceFullInfo> = Uninitialized,
|
||||||
) : MavericksState {
|
) : MavericksState {
|
||||||
constructor(args: SessionOverviewArgs) : this(
|
constructor(args: SessionOverviewArgs) : this(
|
||||||
sessionId = args.sessionId
|
deviceId = args.deviceId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,35 @@
|
|||||||
app:layout_constraintTop_toBottomOf="@id/sessionInfoVerificationStatusContainer"
|
app:layout_constraintTop_toBottomOf="@id/sessionInfoVerificationStatusContainer"
|
||||||
tools:text="@string/device_manager_verification_status_detail_current_session_verified" />
|
tools:text="@string/device_manager_verification_status_detail_current_session_verified" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sessionInfoLastActivityTextView"
|
||||||
|
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="32dp"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/sessionInfoVerificationStatusDetailTextView"
|
||||||
|
tools:text="Last activity Fri 14:59" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sessionInfoLastIPAddressTextView"
|
||||||
|
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="32dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/sessionInfoLastActivityTextView"
|
||||||
|
tools:text="81.235.41.100 (United Kingdom)" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/sessionInfoVerifySessionButton"
|
android:id="@+id/sessionInfoVerifySessionButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -81,7 +110,7 @@
|
|||||||
android:text="@string/device_manager_verify_session"
|
android:text="@string/device_manager_verify_session"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/sessionInfoVerificationStatusDetailTextView" />
|
app:layout_constraintTop_toBottomOf="@id/sessionInfoLastIPAddressTextView" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/sessionInfoViewDetailsButton"
|
android:id="@+id/sessionInfoViewDetailsButton"
|
||||||
|
@ -39,7 +39,7 @@ class SessionOverviewViewModelTest {
|
|||||||
val mvRxTestRule = MvRxTestRule(testDispatcher = UnconfinedTestDispatcher())
|
val mvRxTestRule = MvRxTestRule(testDispatcher = UnconfinedTestDispatcher())
|
||||||
|
|
||||||
private val args = SessionOverviewArgs(
|
private val args = SessionOverviewArgs(
|
||||||
sessionId = A_SESSION_ID
|
deviceId = A_SESSION_ID
|
||||||
)
|
)
|
||||||
private val fakeSession = FakeSession()
|
private val fakeSession = FakeSession()
|
||||||
private val getDeviceFullInfoUseCase = mockk<GetDeviceFullInfoUseCase>()
|
private val getDeviceFullInfoUseCase = mockk<GetDeviceFullInfoUseCase>()
|
||||||
@ -56,7 +56,7 @@ class SessionOverviewViewModelTest {
|
|||||||
val deviceFullInfo = mockk<DeviceFullInfo>()
|
val deviceFullInfo = mockk<DeviceFullInfo>()
|
||||||
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(Optional(deviceFullInfo))
|
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(Optional(deviceFullInfo))
|
||||||
val expectedState = SessionOverviewViewState(
|
val expectedState = SessionOverviewViewState(
|
||||||
sessionId = A_SESSION_ID,
|
deviceId = A_SESSION_ID,
|
||||||
isCurrentSession = true,
|
isCurrentSession = true,
|
||||||
deviceInfo = Success(deviceFullInfo)
|
deviceInfo = Success(deviceFullInfo)
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user