mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 01:15:54 +03:00
create encrypted DM for user invite by email (#8172)
Co-authored-by: jonnyandrew <jonny.andrew@protonmail.com>
This commit is contained in:
parent
29f2bf25fc
commit
94675b9f85
18 changed files with 113 additions and 149 deletions
1
changelog.d/6912.misc
Normal file
1
changelog.d/6912.misc
Normal file
|
@ -0,0 +1 @@
|
|||
Direct Message: Manage encrypted DM in case of invite by email
|
|
@ -1817,6 +1817,7 @@
|
|||
<string name="add_by_qr_code">Add by QR code</string>
|
||||
<string name="qr_code">QR code</string>
|
||||
<string name="creating_direct_room">"Creating room…"</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">You can only invite one email at a time</string>
|
||||
<string name="direct_room_user_list_known_title">Known Users</string>
|
||||
<string name="direct_room_user_list_suggestions_title">Suggestions</string>
|
||||
|
||||
|
@ -2561,6 +2562,8 @@
|
|||
<string name="encryption_enabled_tile_description">Messages in this room are end-to-end encrypted. Learn more & verify users in their profile.</string>
|
||||
<string name="direct_room_encryption_enabled_tile_description">Messages in this chat are end-to-end encrypted.</string>
|
||||
<string name="direct_room_encryption_enabled_tile_description_future">Messages in this chat will be end-to-end encrypted.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">Waiting for users to join ${app_name}</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Once invited users have joined ${app_name}, you will be able to chat and the room will be end-to-end encrypted</string>
|
||||
<string name="encryption_not_enabled">Encryption not enabled</string>
|
||||
<string name="encryption_misconfigured">Encryption is misconfigured</string>
|
||||
<string name="encryption_unknown_algorithm_tile_description">The encryption used by this room is not supported</string>
|
||||
|
|
|
@ -190,10 +190,8 @@ internal class CreateRoomBodyBuilder @Inject constructor(
|
|||
private suspend fun canEnableEncryption(params: CreateRoomParams): Boolean {
|
||||
return params.enableEncryptionIfInvitedUsersSupportIt &&
|
||||
// Parity with web, enable if users have encryption ready devices
|
||||
// for now remove checks on cross signing and 3pid invites
|
||||
// for now remove checks on cross signing
|
||||
// && crossSigningService.isCrossSigningVerified()
|
||||
params.invite3pids.isEmpty() &&
|
||||
params.invitedUserIds.isNotEmpty() &&
|
||||
params.invitedUserIds.let { userIds ->
|
||||
val keys = deviceListManager.downloadKeys(userIds, forceDownload = false)
|
||||
|
||||
|
|
|
@ -115,8 +115,13 @@ internal class RoomDisplayNameResolver @Inject constructor(
|
|||
val leftMembersNames = roomMembers.queryLeftRoomMembersEvent()
|
||||
.findAll()
|
||||
.map { displayNameResolver.getBestName(it.toMatrixItem()) }
|
||||
val directUserId = roomSummary?.directUserId
|
||||
if (!directUserId.isNullOrBlank() && leftMembersNames.isEmpty()) {
|
||||
directUserId
|
||||
} else {
|
||||
roomDisplayNameFallbackProvider.getNameForEmptyRoom(roomSummary?.isDirect.orFalse(), leftMembersNames)
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
roomDisplayNameFallbackProvider.getNameFor1member(
|
||||
resolveRoomMemberName(otherMembersSubset[0], roomMembers)
|
||||
|
|
|
@ -57,7 +57,6 @@ import im.vector.app.features.home.room.list.RoomListViewModel
|
|||
import im.vector.app.features.home.room.list.home.HomeRoomListViewModel
|
||||
import im.vector.app.features.home.room.list.home.invites.InvitesViewModel
|
||||
import im.vector.app.features.home.room.list.home.release.ReleaseNotesViewModel
|
||||
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
|
||||
import im.vector.app.features.invite.InviteUsersToRoomViewModel
|
||||
import im.vector.app.features.location.LocationSharingViewModel
|
||||
import im.vector.app.features.location.live.map.LiveLocationMapViewModel
|
||||
|
@ -500,11 +499,6 @@ interface MavericksViewModelModule {
|
|||
@MavericksViewModelKey(StartAppViewModel::class)
|
||||
fun startAppViewModelFactory(factory: StartAppViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@MavericksViewModelKey(HomeServerCapabilitiesViewModel::class)
|
||||
fun homeServerCapabilitiesViewModelFactory(factory: HomeServerCapabilitiesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@MavericksViewModelKey(InviteUsersToRoomViewModel::class)
|
||||
|
|
|
@ -93,6 +93,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
|||
title = getString(R.string.fab_menu_create_chat),
|
||||
menuResId = R.menu.vector_create_direct_room,
|
||||
submitMenuItemId = R.id.action_create_direct_room,
|
||||
single3pidSelection = true,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
val result = runCatchingToAsync {
|
||||
if (vectorPreferences.isDeferredDmEnabled()) {
|
||||
if (vectorPreferences.isDeferredDmEnabled() && roomParams.invite3pids.isEmpty()) {
|
||||
session.roomService().createLocalRoom(roomParams)
|
||||
} else {
|
||||
analyticsTracker.capture(CreatedRoom(isDM = roomParams.isDirect.orFalse()))
|
||||
|
|
|
@ -1176,6 +1176,10 @@ class TimelineFragment :
|
|||
views.hideComposerViews()
|
||||
views.notificationAreaView.render(NotificationAreaView.State.Tombstone(mainState.tombstoneEvent))
|
||||
}
|
||||
|
||||
if (summary.isDirect && summary.isEncrypted && summary.joinedMembersCount == 1 && summary.invitedMembersCount == 0) {
|
||||
views.hideComposerViews()
|
||||
}
|
||||
} else if (summary?.membership == Membership.INVITE && inviter != null) {
|
||||
views.hideComposerViews()
|
||||
lazyLoadedViews.inviteView(true)?.apply {
|
||||
|
|
|
@ -56,22 +56,37 @@ class EncryptionItemFactory @Inject constructor(
|
|||
val description: String
|
||||
val shield: StatusTileTimelineItem.ShieldUIState
|
||||
if (isSafeAlgorithm) {
|
||||
val isDirect = session.getRoomSummary(event.root.roomId.orEmpty())?.isDirect.orFalse()
|
||||
title = stringProvider.getString(R.string.encryption_enabled)
|
||||
description = stringProvider.getString(
|
||||
when {
|
||||
isDirect && RoomLocalEcho.isLocalEchoId(event.root.roomId.orEmpty()) -> {
|
||||
R.string.direct_room_encryption_enabled_tile_description_future
|
||||
}
|
||||
val roomSummary = session.getRoomSummary(event.root.roomId.orEmpty())
|
||||
val isDirect = roomSummary?.isDirect.orFalse()
|
||||
val (resTitle, resDescription, resShield) = when {
|
||||
isDirect -> {
|
||||
R.string.direct_room_encryption_enabled_tile_description
|
||||
val isWaitingUser = roomSummary?.isEncrypted.orFalse() && roomSummary?.joinedMembersCount == 1 && roomSummary.invitedMembersCount == 0
|
||||
when {
|
||||
RoomLocalEcho.isLocalEchoId(event.root.roomId.orEmpty()) -> Triple(
|
||||
R.string.encryption_enabled,
|
||||
R.string.direct_room_encryption_enabled_tile_description_future,
|
||||
StatusTileTimelineItem.ShieldUIState.BLACK
|
||||
)
|
||||
isWaitingUser -> Triple(
|
||||
R.string.direct_room_encryption_enabled_waiting_users,
|
||||
R.string.direct_room_encryption_enabled_waiting_users_tile_description,
|
||||
StatusTileTimelineItem.ShieldUIState.WAITING
|
||||
)
|
||||
else -> Triple(
|
||||
R.string.encryption_enabled,
|
||||
R.string.direct_room_encryption_enabled_tile_description,
|
||||
StatusTileTimelineItem.ShieldUIState.BLACK
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
R.string.encryption_enabled_tile_description
|
||||
Triple(R.string.encryption_enabled, R.string.encryption_enabled_tile_description, StatusTileTimelineItem.ShieldUIState.BLACK)
|
||||
}
|
||||
}
|
||||
)
|
||||
shield = StatusTileTimelineItem.ShieldUIState.BLACK
|
||||
|
||||
title = stringProvider.getString(resTitle)
|
||||
description = stringProvider.getString(resDescription)
|
||||
shield = resShield
|
||||
} else {
|
||||
title = stringProvider.getString(R.string.encryption_misconfigured)
|
||||
description = stringProvider.getString(R.string.encryption_unknown_algorithm_tile_description)
|
||||
|
|
|
@ -40,6 +40,7 @@ import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
|||
import im.vector.app.features.home.room.detail.timeline.tools.linkify
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
import me.gujun.android.span.span
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
|
@ -127,26 +128,38 @@ abstract class MergedRoomCreationItem : BasedMergedItem<MergedRoomCreationItem.H
|
|||
}
|
||||
|
||||
private fun renderE2ESecureTile(holder: Holder) {
|
||||
val resources = holder.expandView.resources
|
||||
val description = when {
|
||||
val (title, description, drawable) = when {
|
||||
isDirectRoom -> {
|
||||
if (attributes.isLocalRoom) {
|
||||
resources.getString(R.string.direct_room_encryption_enabled_tile_description_future)
|
||||
} else {
|
||||
resources.getString(R.string.direct_room_encryption_enabled_tile_description)
|
||||
val isWaitingUser = roomSummary?.isEncrypted.orFalse() && roomSummary?.joinedMembersCount == 1 && roomSummary?.invitedMembersCount == 0
|
||||
when {
|
||||
attributes.isLocalRoom -> Triple(
|
||||
R.string.encryption_enabled,
|
||||
R.string.direct_room_encryption_enabled_tile_description_future,
|
||||
R.drawable.ic_shield_black
|
||||
)
|
||||
isWaitingUser -> Triple(
|
||||
R.string.direct_room_encryption_enabled_waiting_users,
|
||||
R.string.direct_room_encryption_enabled_waiting_users_tile_description,
|
||||
R.drawable.ic_room_profile_member_list
|
||||
)
|
||||
else -> Triple(
|
||||
R.string.encryption_enabled,
|
||||
R.string.direct_room_encryption_enabled_tile_description,
|
||||
R.drawable.ic_shield_black
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
resources.getString(R.string.encryption_enabled_tile_description)
|
||||
Triple(R.string.encryption_enabled, R.string.encryption_enabled_tile_description, R.drawable.ic_shield_black)
|
||||
}
|
||||
}
|
||||
|
||||
holder.e2eTitleTextView.text = holder.expandView.resources.getString(R.string.encryption_enabled)
|
||||
holder.e2eTitleTextView.text = holder.expandView.resources.getString(title)
|
||||
holder.e2eTitleTextView.setCompoundDrawablesWithIntrinsicBounds(
|
||||
ContextCompat.getDrawable(holder.view.context, R.drawable.ic_shield_black),
|
||||
ContextCompat.getDrawable(holder.view.context, drawable),
|
||||
null, null, null
|
||||
)
|
||||
holder.e2eTitleDescriptionView.text = description
|
||||
holder.e2eTitleDescriptionView.text = holder.expandView.resources.getString(description)
|
||||
holder.e2eTitleDescriptionView.textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ abstract class StatusTileTimelineItem : AbsBaseMessageItem<StatusTileTimelineIte
|
|||
ShieldUIState.GREEN -> R.drawable.ic_shield_trusted
|
||||
ShieldUIState.BLACK -> R.drawable.ic_shield_black
|
||||
ShieldUIState.RED -> R.drawable.ic_shield_warning
|
||||
ShieldUIState.WAITING -> R.drawable.ic_room_profile_member_list
|
||||
ShieldUIState.ERROR -> R.drawable.ic_warning_badge
|
||||
}
|
||||
|
||||
|
@ -101,6 +102,7 @@ abstract class StatusTileTimelineItem : AbsBaseMessageItem<StatusTileTimelineIte
|
|||
BLACK,
|
||||
RED,
|
||||
GREEN,
|
||||
WAITING,
|
||||
ERROR
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 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.app.features.homeserver
|
||||
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.EntryPoints
|
||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.SingletonEntryPoint
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.EmptyAction
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.raw.wellknown.getElementWellknown
|
||||
import im.vector.app.features.raw.wellknown.isE2EByDefault
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.raw.RawService
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
|
||||
class HomeServerCapabilitiesViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: HomeServerCapabilitiesViewState,
|
||||
private val session: Session,
|
||||
private val rawService: RawService
|
||||
) : VectorViewModel<HomeServerCapabilitiesViewState, EmptyAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MavericksAssistedViewModelFactory<HomeServerCapabilitiesViewModel, HomeServerCapabilitiesViewState> {
|
||||
override fun create(initialState: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel
|
||||
}
|
||||
|
||||
companion object : MavericksViewModelFactory<HomeServerCapabilitiesViewModel, HomeServerCapabilitiesViewState> by hiltMavericksViewModelFactory() {
|
||||
|
||||
override fun initialState(viewModelContext: ViewModelContext): HomeServerCapabilitiesViewState {
|
||||
val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getSafeActiveSession()
|
||||
return HomeServerCapabilitiesViewState(
|
||||
capabilities = session?.homeServerCapabilitiesService()?.getHomeServerCapabilities() ?: HomeServerCapabilities()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
|
||||
initAdminE2eByDefault()
|
||||
}
|
||||
|
||||
private fun initAdminE2eByDefault() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val adminE2EByDefault = tryOrNull {
|
||||
rawService.getElementWellknown(session.sessionParams)
|
||||
?.isE2EByDefault()
|
||||
?: true
|
||||
} ?: true
|
||||
|
||||
setState {
|
||||
copy(
|
||||
isE2EByDefault = adminE2EByDefault
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(action: EmptyAction) {}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 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.app.features.homeserver
|
||||
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
|
||||
data class HomeServerCapabilitiesViewState(
|
||||
val capabilities: HomeServerCapabilities = HomeServerCapabilities(),
|
||||
val isE2EByDefault: Boolean = true
|
||||
) : MavericksState
|
|
@ -25,6 +25,7 @@ import im.vector.app.R
|
|||
import im.vector.app.core.epoxy.errorWithRetryItem
|
||||
import im.vector.app.core.epoxy.loadingItem
|
||||
import im.vector.app.core.epoxy.noResultItem
|
||||
import im.vector.app.core.epoxy.profiles.notifications.textHeaderItem
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
|
@ -61,6 +62,13 @@ class UserListController @Inject constructor(
|
|||
val currentState = state ?: return
|
||||
val host = this
|
||||
|
||||
if (currentState.isE2EByDefault && currentState.single3pidSelection && currentState.pendingSelections.isNotEmpty()) {
|
||||
textHeaderItem {
|
||||
id("userListNotificationHeader")
|
||||
textRes(R.string.direct_room_user_list_only_invite_one_email)
|
||||
}
|
||||
}
|
||||
|
||||
// Build generic items
|
||||
if (currentState.searchTerm.isBlank()) {
|
||||
if (currentState.showInviteActions()) {
|
||||
|
|
|
@ -27,7 +27,6 @@ import androidx.core.view.isVisible
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.chip.Chip
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
@ -42,7 +41,6 @@ import im.vector.app.core.utils.DimensionConverter
|
|||
import im.vector.app.core.utils.showIdentityServerConsentDialog
|
||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
import im.vector.app.databinding.FragmentUserListBinding
|
||||
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -63,7 +61,6 @@ class UserListFragment :
|
|||
|
||||
private val args: UserListFragmentArgs by args()
|
||||
private val viewModel: UserListViewModel by activityViewModel()
|
||||
private val homeServerCapabilitiesViewModel: HomeServerCapabilitiesViewModel by fragmentViewModel()
|
||||
private lateinit var sharedActionViewModel: UserListSharedActionViewModel
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentUserListBinding {
|
||||
|
@ -86,7 +83,7 @@ class UserListFragment :
|
|||
setupRecyclerView()
|
||||
setupSearchView()
|
||||
|
||||
homeServerCapabilitiesViewModel.onEach {
|
||||
viewModel.onEach {
|
||||
views.userListE2EbyDefaultDisabled.isVisible = !it.isE2EByDefault
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ data class UserListFragmentArgs(
|
|||
val submitMenuItemId: Int,
|
||||
val excludedUserIds: Set<String>? = null,
|
||||
val singleSelection: Boolean = false,
|
||||
val single3pidSelection: Boolean = false,
|
||||
val showInviteActions: Boolean = true,
|
||||
val showContactBookAction: Boolean = true,
|
||||
val showToolbar: Boolean = true
|
||||
|
|
|
@ -31,6 +31,9 @@ import im.vector.app.core.extensions.toggle
|
|||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.discovery.fetchIdentityServerWithTerms
|
||||
import im.vector.app.features.raw.wellknown.getElementWellknown
|
||||
import im.vector.app.features.raw.wellknown.isE2EByDefault
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
@ -41,6 +44,7 @@ import kotlinx.coroutines.flow.sample
|
|||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.MatrixPatterns
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.raw.RawService
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
|
||||
import org.matrix.android.sdk.api.session.identity.IdentityServiceListener
|
||||
|
@ -57,6 +61,7 @@ data class ThreePidUser(
|
|||
class UserListViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: UserListViewState,
|
||||
private val stringProvider: StringProvider,
|
||||
private val rawService: RawService,
|
||||
private val session: Session
|
||||
) : VectorViewModel<UserListViewState, UserListAction, UserListViewEvents>(initialState) {
|
||||
|
||||
|
@ -84,6 +89,7 @@ class UserListViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
init {
|
||||
initAdminE2eByDefault()
|
||||
observeUsers()
|
||||
setState {
|
||||
copy(
|
||||
|
@ -93,6 +99,22 @@ class UserListViewModel @AssistedInject constructor(
|
|||
session.identityService().addListener(identityServerListener)
|
||||
}
|
||||
|
||||
private fun initAdminE2eByDefault() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val adminE2EByDefault = tryOrNull {
|
||||
rawService.getElementWellknown(session.sessionParams)
|
||||
?.isE2EByDefault()
|
||||
?: true
|
||||
} ?: true
|
||||
|
||||
setState {
|
||||
copy(
|
||||
isE2EByDefault = adminE2EByDefault
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanISURL(url: String?): String? {
|
||||
return url?.removePrefix("https://")
|
||||
}
|
||||
|
@ -258,9 +280,14 @@ class UserListViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun handleSelectUser(action: UserListAction.AddPendingSelection) = withState { state ->
|
||||
val canSelectUser = !state.isE2EByDefault || state.pendingSelections.isEmpty() || !state.single3pidSelection ||
|
||||
(action.pendingSelection is PendingSelection.UserPendingSelection &&
|
||||
state.pendingSelections.last() is PendingSelection.UserPendingSelection)
|
||||
if (canSelectUser) {
|
||||
val selections = state.pendingSelections.toggle(action.pendingSelection, singleElement = state.singleSelection)
|
||||
setState { copy(pendingSelections = selections) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRemoveSelectedUser(action: UserListAction.RemovePendingSelection) = withState { state ->
|
||||
val selections = state.pendingSelections.minus(action.pendingSelection)
|
||||
|
|
|
@ -32,6 +32,8 @@ data class UserListViewState(
|
|||
val pendingSelections: Set<PendingSelection> = emptySet(),
|
||||
val searchTerm: String = "",
|
||||
val singleSelection: Boolean,
|
||||
val single3pidSelection: Boolean,
|
||||
val isE2EByDefault: Boolean = false,
|
||||
val configuredIdentityServer: String? = null,
|
||||
private val showInviteActions: Boolean,
|
||||
val showContactBookAction: Boolean
|
||||
|
@ -40,6 +42,7 @@ data class UserListViewState(
|
|||
constructor(args: UserListFragmentArgs) : this(
|
||||
excludedUserIds = args.excludedUserIds,
|
||||
singleSelection = args.singleSelection,
|
||||
single3pidSelection = args.single3pidSelection,
|
||||
showInviteActions = args.showInviteActions,
|
||||
showContactBookAction = args.showContactBookAction
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue