mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-26 03:16:02 +03:00
Profile Screen / Add show device list trust screen
This commit is contained in:
parent
665c577747
commit
08ae0b485a
13 changed files with 418 additions and 28 deletions
|
@ -18,6 +18,7 @@ package im.vector.matrix.rx
|
||||||
|
|
||||||
import androidx.paging.PagedList
|
import androidx.paging.PagedList
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||||
import im.vector.matrix.android.api.session.group.GroupSummaryQueryParams
|
import im.vector.matrix.android.api.session.group.GroupSummaryQueryParams
|
||||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||||
import im.vector.matrix.android.api.session.pushers.Pusher
|
import im.vector.matrix.android.api.session.pushers.Pusher
|
||||||
|
@ -103,6 +104,11 @@ class RxSession(private val session: Session) {
|
||||||
fun liveUserCryptoDevices(userId: String): Observable<List<CryptoDeviceInfo>> {
|
fun liveUserCryptoDevices(userId: String): Observable<List<CryptoDeviceInfo>> {
|
||||||
return session.getLiveCryptoDeviceInfo(userId).asObservable()
|
return session.getLiveCryptoDeviceInfo(userId).asObservable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun liveCrossSigningInfo(userId: String): Observable<Optional<MXCrossSigningInfo>> {
|
||||||
|
return session.getCrossSigningService().getLiveCrossSigningKeys(userId).asObservable()
|
||||||
|
.startWith(session.getCrossSigningService().getUserCrossSigningKeys(userId).toOptional())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Session.rx(): RxSession {
|
fun Session.rx(): RxSession {
|
||||||
|
|
|
@ -52,6 +52,7 @@ import im.vector.riotx.features.reactions.EmojiReactionPickerActivity
|
||||||
import im.vector.riotx.features.reactions.widget.ReactionButton
|
import im.vector.riotx.features.reactions.widget.ReactionButton
|
||||||
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
|
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
|
||||||
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity
|
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity
|
||||||
|
import im.vector.riotx.features.roommemberprofile.devices.DeviceListBottomSheet
|
||||||
import im.vector.riotx.features.settings.VectorSettingsActivity
|
import im.vector.riotx.features.settings.VectorSettingsActivity
|
||||||
import im.vector.riotx.features.settings.devices.DeviceVerificationInfoBottomSheet
|
import im.vector.riotx.features.settings.devices.DeviceVerificationInfoBottomSheet
|
||||||
import im.vector.riotx.features.share.IncomingShareActivity
|
import im.vector.riotx.features.share.IncomingShareActivity
|
||||||
|
@ -148,6 +149,8 @@ interface ScreenComponent {
|
||||||
|
|
||||||
fun inject(deviceVerificationInfoBottomSheet: DeviceVerificationInfoBottomSheet)
|
fun inject(deviceVerificationInfoBottomSheet: DeviceVerificationInfoBottomSheet)
|
||||||
|
|
||||||
|
fun inject(deviceListBottomSheet: DeviceListBottomSheet)
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(vectorComponent: VectorComponent,
|
fun create(vectorComponent: VectorComponent,
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 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.riotx.core.ui.list
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.riotx.core.extensions.setTextOrHide
|
||||||
|
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||||
|
import im.vector.riotx.features.themes.ThemeUtils
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic list item.
|
||||||
|
* Displays an item with a title, and optional description.
|
||||||
|
* Can display an accessory on the right, that can be an image or an indeterminate progress.
|
||||||
|
* If provided with an action, will display a button at the bottom of the list item.
|
||||||
|
*/
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_generic_with_value)
|
||||||
|
abstract class GenericItemWithValue : VectorEpoxyModel<GenericItemWithValue.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var title: String? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var value: CharSequence? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
@ColorInt
|
||||||
|
var valueColorInt: Int? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
@DrawableRes
|
||||||
|
var titleIconResourceId: Int = -1
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var itemClickAction: View.OnClickListener? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
holder.titleText.setTextOrHide(title)
|
||||||
|
|
||||||
|
if (titleIconResourceId != -1) {
|
||||||
|
holder.titleIcon.setImageResource(titleIconResourceId)
|
||||||
|
holder.titleIcon.isVisible = true
|
||||||
|
} else {
|
||||||
|
holder.titleIcon.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
holder.valueText.setTextOrHide(value)
|
||||||
|
|
||||||
|
if (valueColorInt != null) {
|
||||||
|
holder.valueText.setTextColor(valueColorInt!!)
|
||||||
|
} else {
|
||||||
|
holder.valueText.setTextColor(ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_primary))
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.view.setOnClickListener(itemClickAction?.let { DebouncedClickListener(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val titleIcon by bind<ImageView>(R.id.itemGenericWithValueTitleIcon)
|
||||||
|
val titleText by bind<TextView>(R.id.itemGenericWithValueLabelText)
|
||||||
|
val valueText by bind<TextView>(R.id.itemGenericWithValueValueText)
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,9 +75,9 @@ class RoomMemberProfileController @Inject constructor(
|
||||||
buildProfileSection(stringProvider.getString(R.string.room_profile_section_security))
|
buildProfileSection(stringProvider.getString(R.string.room_profile_section_security))
|
||||||
|
|
||||||
if (state.isRoomEncrypted) {
|
if (state.isRoomEncrypted) {
|
||||||
if (state.userMXCrossSigningInfo != null) {
|
if (state.userMXCrossSigningInfo.invoke() != null) {
|
||||||
// Cross signing is enabled for this user
|
// Cross signing is enabled for this user
|
||||||
if (state.userMXCrossSigningInfo.isTrusted) {
|
if (state.userMXCrossSigningInfo.invoke()?.isTrusted() == true) {
|
||||||
//User is trusted
|
//User is trusted
|
||||||
val icon = if (state.allDevicesAreTrusted.invoke() == true) R.drawable.ic_shield_trusted
|
val icon = if (state.allDevicesAreTrusted.invoke() == true) R.drawable.ic_shield_trusted
|
||||||
else R.drawable.ic_shield_warning
|
else R.drawable.ic_shield_warning
|
||||||
|
@ -126,14 +126,6 @@ class RoomMemberProfileController @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// buildProfileAction(
|
|
||||||
// id = "learn_more",
|
|
||||||
// title = stringProvider.getString(R.string.room_profile_section_security_learn_more),
|
|
||||||
// dividerColor = dividerColor,
|
|
||||||
// editable = false,
|
|
||||||
// divider = false,
|
|
||||||
// subtitle = stringProvider.getString(R.string.room_profile_not_encrypted_subtitle)
|
|
||||||
// )
|
|
||||||
genericFooterItem {
|
genericFooterItem {
|
||||||
id("verify_footer_not_encrypted")
|
id("verify_footer_not_encrypted")
|
||||||
text(stringProvider.getString(R.string.room_profile_not_encrypted_subtitle))
|
text(stringProvider.getString(R.string.room_profile_not_encrypted_subtitle))
|
||||||
|
|
|
@ -38,6 +38,7 @@ import im.vector.riotx.core.platform.StateView
|
||||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
|
import im.vector.riotx.features.roommemberprofile.devices.DeviceListBottomSheet
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
||||||
import kotlinx.android.synthetic.main.view_stub_room_member_profile_header.*
|
import kotlinx.android.synthetic.main.view_stub_room_member_profile_header.*
|
||||||
|
@ -175,8 +176,8 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
override fun onShowDeviceList() {
|
override fun onShowDeviceList() = withState(viewModel) {
|
||||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
DeviceListBottomSheet.newInstance(it.userId).show(parentFragmentManager, "DEV_LIST")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onShowDeviceListNoCrossSigning() {
|
override fun onShowDeviceListNoCrossSigning() {
|
||||||
|
|
|
@ -76,16 +76,6 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
||||||
return fragment.viewModelFactory.create(state)
|
return fragment.viewModelFactory.create(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initialState(viewModelContext: ViewModelContext): RoomMemberProfileViewState? {
|
|
||||||
val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
|
|
||||||
val args = viewModelContext.args<RoomMemberProfileArgs>()
|
|
||||||
|
|
||||||
return RoomMemberProfileViewState(
|
|
||||||
userId = args.userId,
|
|
||||||
roomId = args.roomId,
|
|
||||||
userMXCrossSigningInfo = session.getCrossSigningService().getUserCrossSigningKeys(args.userId)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _viewEvents = PublishDataSource<RoomMemberProfileViewEvents>()
|
private val _viewEvents = PublishDataSource<RoomMemberProfileViewEvents>()
|
||||||
|
@ -126,6 +116,14 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
||||||
.execute {
|
.execute {
|
||||||
copy(allDevicesAreTrusted = it)
|
copy(allDevicesAreTrusted = it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session.rx().liveCrossSigningInfo(initialState.userId)
|
||||||
|
.map {
|
||||||
|
it.getOrNull()
|
||||||
|
}
|
||||||
|
.execute {
|
||||||
|
copy(userMXCrossSigningInfo = it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +150,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
||||||
private fun prepareVerification(action: RoomMemberProfileAction.VerifyUser) = withState { state ->
|
private fun prepareVerification(action: RoomMemberProfileAction.VerifyUser) = withState { state ->
|
||||||
// Sanity
|
// Sanity
|
||||||
if (state.isRoomEncrypted) {
|
if (state.isRoomEncrypted) {
|
||||||
if (!state.isMine && state.userMXCrossSigningInfo?.isTrusted == false) {
|
if (!state.isMine && state.userMXCrossSigningInfo.invoke()?.isTrusted() == false) {
|
||||||
// ok, let's find or create the DM room
|
// ok, let's find or create the DM room
|
||||||
_actionResultLiveData.postValue(
|
_actionResultLiveData.postValue(
|
||||||
LiveEvent(Success(action.copy(userId = state.userId)))
|
LiveEvent(Success(action.copy(userId = state.userId)))
|
||||||
|
|
|
@ -35,9 +35,9 @@ data class RoomMemberProfileViewState(
|
||||||
val powerLevelsContent: Async<PowerLevelsContent> = Uninitialized,
|
val powerLevelsContent: Async<PowerLevelsContent> = Uninitialized,
|
||||||
val userPowerLevelString: Async<String> = Uninitialized,
|
val userPowerLevelString: Async<String> = Uninitialized,
|
||||||
val userMatrixItem: Async<MatrixItem> = Uninitialized,
|
val userMatrixItem: Async<MatrixItem> = Uninitialized,
|
||||||
val userMXCrossSigningInfo: MXCrossSigningInfo? = null,
|
val userMXCrossSigningInfo: Async<MXCrossSigningInfo?> = Uninitialized,
|
||||||
val allDevicesAreTrusted: Async<Boolean> = Uninitialized
|
val allDevicesAreTrusted: Async<Boolean> = Uninitialized
|
||||||
) : MvRxState {
|
) : MvRxState {
|
||||||
|
|
||||||
//constructor(args: RoomMemberProfileArgs) : this(roomId = args.roomId, userId = args.userId)
|
constructor(args: RoomMemberProfileArgs) : this(roomId = args.roomId, userId = args.userId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 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.riotx.features.roommemberprofile.devices
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import butterknife.BindView
|
||||||
|
import com.airbnb.mvrx.MvRx
|
||||||
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.di.ScreenComponent
|
||||||
|
import im.vector.riotx.core.extensions.cleanup
|
||||||
|
import im.vector.riotx.core.extensions.configureWith
|
||||||
|
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
|
import im.vector.riotx.core.utils.DimensionConverter
|
||||||
|
import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DeviceListBottomSheet : VectorBaseBottomSheetDialogFragment(), DeviceListEpoxyController.InteractionListener {
|
||||||
|
|
||||||
|
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
|
||||||
|
|
||||||
|
private val viewModel: DeviceListBottomSheetViewModel by fragmentViewModel(DeviceListBottomSheetViewModel::class)
|
||||||
|
|
||||||
|
@Inject lateinit var viewModelFactory: DeviceListBottomSheetViewModel.Factory
|
||||||
|
|
||||||
|
@Inject lateinit var dimensionConverter: DimensionConverter
|
||||||
|
|
||||||
|
@BindView(R.id.bottomSheetRecyclerView)
|
||||||
|
lateinit var recyclerView: RecyclerView
|
||||||
|
|
||||||
|
override fun injectWith(injector: ScreenComponent) {
|
||||||
|
injector.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject lateinit var epoxyController: DeviceListEpoxyController
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
recyclerView.setPadding(0, dimensionConverter.dpToPx(16 ),0, dimensionConverter.dpToPx(16 ))
|
||||||
|
recyclerView.configureWith(
|
||||||
|
epoxyController,
|
||||||
|
showDivider = false,
|
||||||
|
hasFixedSize = false)
|
||||||
|
epoxyController.interactionListener = this
|
||||||
|
bottomSheetTitle.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
recyclerView.cleanup()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate() = withState(viewModel) {
|
||||||
|
epoxyController.setData(it)
|
||||||
|
super.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeviceSelected(device: CryptoDeviceInfo) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance(userId: String): DeviceListBottomSheet {
|
||||||
|
val args = Bundle()
|
||||||
|
args.putString(MvRx.KEY_ARG, userId)
|
||||||
|
return DeviceListBottomSheet().apply { arguments = args }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package im.vector.riotx.features.roommemberprofile.devices
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
|
import com.squareup.inject.assisted.Assisted
|
||||||
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
|
||||||
|
import im.vector.matrix.rx.rx
|
||||||
|
import im.vector.riotx.core.platform.EmptyAction
|
||||||
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
|
|
||||||
|
data class DeviceListViewState(
|
||||||
|
val cryptoDevices: Async<List<CryptoDeviceInfo>> = Loading()
|
||||||
|
) : MvRxState
|
||||||
|
|
||||||
|
class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted private val initialState: DeviceListViewState,
|
||||||
|
@Assisted private val userId: String,
|
||||||
|
private val stringProvider: StringProvider,
|
||||||
|
private val session: Session) : VectorViewModel<DeviceListViewState, EmptyAction>(initialState) {
|
||||||
|
|
||||||
|
@AssistedInject.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: DeviceListViewState, userId: String): DeviceListBottomSheetViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
session.rx().liveUserCryptoDevices(userId)
|
||||||
|
.execute {
|
||||||
|
copy(cryptoDevices = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(action: EmptyAction) {}
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<DeviceListBottomSheetViewModel, DeviceListViewState> {
|
||||||
|
@JvmStatic
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: DeviceListViewState): DeviceListBottomSheetViewModel? {
|
||||||
|
val fragment: DeviceListBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
|
||||||
|
val userId = viewModelContext.args<String>()
|
||||||
|
return fragment.viewModelFactory.create(state, userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
package im.vector.riotx.features.roommemberprofile.devices
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import com.airbnb.mvrx.Fail
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.epoxy.errorWithRetryItem
|
||||||
|
import im.vector.riotx.core.epoxy.loadingItem
|
||||||
|
import im.vector.riotx.core.resources.ColorProvider
|
||||||
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
|
import im.vector.riotx.core.resources.UserPreferencesProvider
|
||||||
|
import im.vector.riotx.core.ui.list.GenericItem
|
||||||
|
import im.vector.riotx.core.ui.list.genericFooterItem
|
||||||
|
import im.vector.riotx.core.ui.list.genericItem
|
||||||
|
import im.vector.riotx.core.ui.list.genericItemWithValue
|
||||||
|
import im.vector.riotx.features.settings.VectorPreferences
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DeviceListEpoxyController @Inject constructor(private val stringProvider: StringProvider,
|
||||||
|
private val colorProvider: ColorProvider,
|
||||||
|
private val vectorPreferences: VectorPreferences)
|
||||||
|
: TypedEpoxyController<DeviceListViewState>() {
|
||||||
|
|
||||||
|
interface InteractionListener {
|
||||||
|
fun onDeviceSelected(device: CryptoDeviceInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
var interactionListener: InteractionListener? = null
|
||||||
|
|
||||||
|
override fun buildModels(data: DeviceListViewState?) {
|
||||||
|
if (data == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
when (data.cryptoDevices) {
|
||||||
|
Uninitialized -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
is Loading -> {
|
||||||
|
loadingItem {
|
||||||
|
id("loading")
|
||||||
|
loadingText(stringProvider.getString(R.string.loading))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Success -> {
|
||||||
|
|
||||||
|
val deviceList = data.cryptoDevices.invoke()
|
||||||
|
|
||||||
|
// Build top header
|
||||||
|
val allGreen = deviceList.fold(true, { prev, device ->
|
||||||
|
prev && device.isVerified
|
||||||
|
})
|
||||||
|
|
||||||
|
genericItem {
|
||||||
|
id("title")
|
||||||
|
style(GenericItem.STYLE.BIG_TEXT)
|
||||||
|
titleIconResourceId(if (allGreen) R.drawable.ic_shield_trusted else R.drawable.ic_shield_warning)
|
||||||
|
title(stringProvider.getString(R.string.verification_profile_verified))
|
||||||
|
description(stringProvider.getString(R.string.verification_conclusion_ok_notice))
|
||||||
|
}
|
||||||
|
|
||||||
|
genericItem {
|
||||||
|
id("sessions")
|
||||||
|
style(GenericItem.STYLE.BIG_TEXT)
|
||||||
|
title(stringProvider.getString(R.string.room_member_profile_sessions_section_title))
|
||||||
|
|
||||||
|
}
|
||||||
|
if (deviceList.isEmpty()) {
|
||||||
|
// Can this really happen?
|
||||||
|
genericFooterItem {
|
||||||
|
id("empty")
|
||||||
|
text(stringProvider.getString(R.string.search_no_results))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Build list of device with status
|
||||||
|
deviceList.forEach { device ->
|
||||||
|
genericItemWithValue {
|
||||||
|
id(device.deviceId)
|
||||||
|
titleIconResourceId(if (device.isVerified) R.drawable.ic_shield_trusted else R.drawable.ic_shield_warning)
|
||||||
|
title(
|
||||||
|
buildString {
|
||||||
|
append(device.displayName() ?: device.deviceId)
|
||||||
|
apply {
|
||||||
|
if (vectorPreferences.developerMode()) {
|
||||||
|
append("\n")
|
||||||
|
append(device.deviceId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
value(
|
||||||
|
stringProvider.getString(
|
||||||
|
if (device.isVerified) R.string.trusted else R.string.not_trusted
|
||||||
|
)
|
||||||
|
)
|
||||||
|
valueColorInt(
|
||||||
|
colorProvider.getColor(
|
||||||
|
if (device.isVerified) R.color.riotx_positive_accent else R.color.riotx_destructive_accent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Fail -> {
|
||||||
|
errorWithRetryItem {
|
||||||
|
id("error")
|
||||||
|
text(stringProvider.getString(R.string.room_member_profile_failed_to_get_devices))
|
||||||
|
listener {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import im.vector.riotx.core.epoxy.dividerItem
|
||||||
import im.vector.riotx.core.epoxy.loadingItem
|
import im.vector.riotx.core.epoxy.loadingItem
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
import im.vector.riotx.core.resources.ColorProvider
|
||||||
import im.vector.riotx.core.resources.StringProvider
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
|
import im.vector.riotx.core.resources.UserPreferencesProvider
|
||||||
import im.vector.riotx.core.ui.list.GenericItem
|
import im.vector.riotx.core.ui.list.GenericItem
|
||||||
import im.vector.riotx.core.ui.list.genericItem
|
import im.vector.riotx.core.ui.list.genericItem
|
||||||
import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||||
|
@ -30,8 +31,7 @@ import javax.inject.Inject
|
||||||
|
|
||||||
class DeviceVerificationInfoEpoxyController @Inject constructor(private val stringProvider: StringProvider,
|
class DeviceVerificationInfoEpoxyController @Inject constructor(private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider,
|
private val colorProvider: ColorProvider,
|
||||||
private val session: Session,
|
private val session: Session)
|
||||||
private val avatarRender: AvatarRenderer)
|
|
||||||
: TypedEpoxyController<DeviceVerificationInfoBottomSheetViewState>() {
|
: TypedEpoxyController<DeviceVerificationInfoBottomSheetViewState>() {
|
||||||
|
|
||||||
var callback: Callback? = null
|
var callback: Callback? = null
|
||||||
|
|
44
vector/src/main/res/layout/item_generic_with_value.xml
Normal file
44
vector/src/main/res/layout/item_generic_with_value.xml
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:paddingStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:paddingEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:minHeight="40dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/itemGenericWithValueTitleIcon"
|
||||||
|
android:layout_width="20sp"
|
||||||
|
android:layout_height="20sp"
|
||||||
|
android:src="@drawable/ic_shield_trusted"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemGenericWithValueLabelText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
tools:text="Label" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemGenericWithValueValueText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="0dp"
|
||||||
|
tools:textColor="@color/riotx_positive_accent"
|
||||||
|
tools:text="Value" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -124,4 +124,9 @@
|
||||||
<string name="verification_profile_verified">Verified</string>
|
<string name="verification_profile_verified">Verified</string>
|
||||||
<string name="verification_profile_warning">Warning</string>
|
<string name="verification_profile_warning">Warning</string>
|
||||||
|
|
||||||
|
<string name="room_member_profile_failed_to_get_devices">Failed to get devices</string>
|
||||||
|
<string name="room_member_profile_sessions_section_title">Sessions</string>
|
||||||
|
<string name="trusted">Trusted</string>
|
||||||
|
<string name="not_trusted">Not Trusted</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue