mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-26 19:36:08 +03:00
Identity: progressing
This commit is contained in:
parent
a75242c79d
commit
3aa6de7cf5
10 changed files with 209 additions and 270 deletions
|
@ -88,7 +88,8 @@ class CommonTestHelper(context: Context) {
|
|||
fun syncSession(session: Session) {
|
||||
val lock = CountDownLatch(1)
|
||||
|
||||
session.open()
|
||||
GlobalScope.launch(Dispatchers.Main) { session.open() }
|
||||
|
||||
session.startSync(true)
|
||||
|
||||
val syncLiveData = runBlocking(Dispatchers.Main) {
|
||||
|
|
|
@ -55,6 +55,7 @@ import im.vector.matrix.android.internal.session.room.timeline.TimelineEventDecr
|
|||
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
||||
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
||||
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -99,6 +100,7 @@ internal class DefaultSession @Inject constructor(
|
|||
private val accountService: Lazy<AccountService>,
|
||||
private val timelineEventDecryptor: TimelineEventDecryptor,
|
||||
private val shieldTrustUpdater: ShieldTrustUpdater,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val defaultIdentityService: DefaultIdentityService)
|
||||
: Session,
|
||||
RoomService by roomService.get(),
|
||||
|
@ -178,7 +180,10 @@ internal class DefaultSession @Inject constructor(
|
|||
isOpen = false
|
||||
eventBus.unregister(this)
|
||||
shieldTrustUpdater.stop()
|
||||
defaultIdentityService.stop()
|
||||
GlobalScope.launch(coroutineDispatchers.main) {
|
||||
// This has to be done on main thread
|
||||
defaultIdentityService.stop()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSyncStateLive(): LiveData<SyncState> {
|
||||
|
|
|
@ -39,9 +39,8 @@ import im.vector.matrix.android.internal.session.identity.db.IdentityServiceStor
|
|||
import im.vector.matrix.android.internal.session.identity.todelete.AccountDataDataSource
|
||||
import im.vector.matrix.android.internal.session.identity.todelete.observeNotNull
|
||||
import im.vector.matrix.android.internal.session.openid.GetOpenIdTokenTask
|
||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.IdentityContent
|
||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.IdentityServerContent
|
||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
|
||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataIdentity
|
||||
import im.vector.matrix.android.internal.session.user.accountdata.UpdateUserAccountDataTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.launchToCallback
|
||||
|
@ -81,16 +80,16 @@ internal class DefaultIdentityService @Inject constructor(
|
|||
accountDataDataSource
|
||||
.getLiveAccountDataEvent(UserAccountData.TYPE_IDENTITY_SERVER)
|
||||
.observeNotNull(lifecycleOwner) {
|
||||
val identityServerContent = it.getOrNull()?.content?.toModel<UserAccountDataIdentity>()
|
||||
val identityServerContent = it.getOrNull()?.content?.toModel<IdentityServerContent>()
|
||||
if (identityServerContent != null) {
|
||||
notifyIdentityServerUrlChange(identityServerContent.content?.baseUrl)
|
||||
notifyIdentityServerUrlChange(identityServerContent.baseUrl)
|
||||
}
|
||||
// TODO Handle the case where the account data is deleted?
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyIdentityServerUrlChange(baseUrl: String?) {
|
||||
// This is maybe not a real change (local echo of account data we are just setting
|
||||
// This is maybe not a real change (local echo of account data we are just setting)
|
||||
if (identityServiceStore.get()?.identityServerUrl == baseUrl) {
|
||||
Timber.d("Local echo of identity server url change")
|
||||
} else {
|
||||
|
@ -169,11 +168,16 @@ internal class DefaultIdentityService @Inject constructor(
|
|||
|
||||
private suspend fun updateAccountData(url: String?) {
|
||||
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.IdentityParams(
|
||||
identityContent = IdentityContent(baseUrl = url)
|
||||
identityContent = IdentityServerContent(baseUrl = url)
|
||||
))
|
||||
}
|
||||
|
||||
override fun lookUp(threePids: List<ThreePid>, callback: MatrixCallback<List<FoundThreePid>>): Cancelable {
|
||||
if (threePids.isEmpty()) {
|
||||
callback.onSuccess(emptyList())
|
||||
return NoOpCancellable
|
||||
}
|
||||
|
||||
return GlobalScope.launchToCallback(coroutineDispatchers.main, callback) {
|
||||
lookUpInternal(true, threePids)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ internal fun IdentityServerEntity.Companion.get(realm: Realm): IdentityServerEnt
|
|||
return realm.where<IdentityServerEntity>().findFirst()
|
||||
}
|
||||
|
||||
internal fun IdentityServerEntity.Companion.getOrCreate(realm: Realm): IdentityServerEntity {
|
||||
private fun IdentityServerEntity.Companion.getOrCreate(realm: Realm): IdentityServerEntity {
|
||||
return get(realm) ?: realm.createObject()
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ internal class RealmIdentityServerStore @Inject constructor(
|
|||
) : IdentityServiceStore {
|
||||
|
||||
override fun get(): IdentityServerEntity? {
|
||||
return Realm.getInstance(realmConfiguration).use {
|
||||
IdentityServerEntity.get(it)
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
IdentityServerEntity.get(realm)?.let { realm.copyFromRealm(it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,12 +20,12 @@ import com.squareup.moshi.Json
|
|||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class UserAccountDataIdentity(
|
||||
internal data class UserAccountDataIdentityServer(
|
||||
@Json(name = "type") override val type: String = TYPE_IDENTITY_SERVER,
|
||||
@Json(name = "content") val content: IdentityContent? = null
|
||||
@Json(name = "content") val content: IdentityServerContent? = null
|
||||
) : UserAccountData()
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class IdentityContent(
|
||||
internal data class IdentityServerContent(
|
||||
@Json(name = "base_url") val baseUrl: String? = null
|
||||
)
|
|
@ -19,7 +19,7 @@ package im.vector.matrix.android.internal.session.user.accountdata
|
|||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.BreadcrumbsContent
|
||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.IdentityContent
|
||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.IdentityServerContent
|
||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
@ -33,7 +33,7 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa
|
|||
}
|
||||
|
||||
data class IdentityParams(override val type: String = UserAccountData.TYPE_IDENTITY_SERVER,
|
||||
private val identityContent: IdentityContent
|
||||
private val identityContent: IdentityServerContent
|
||||
) : Params {
|
||||
|
||||
override fun getData(): Any {
|
||||
|
|
|
@ -18,12 +18,14 @@ package im.vector.riotx.features.discovery
|
|||
import android.view.View
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.resources.ColorProvider
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class DiscoverySettingsController @Inject constructor(
|
||||
|
@ -66,18 +68,18 @@ class DiscoverySettingsController @Inject constructor(
|
|||
}
|
||||
|
||||
when (data.phoneNumbersList) {
|
||||
is Loading -> {
|
||||
is Incomplete -> {
|
||||
settingsLoadingItem {
|
||||
id("phoneLoading")
|
||||
}
|
||||
}
|
||||
is Fail -> {
|
||||
is Fail -> {
|
||||
settingsInfoItem {
|
||||
id("msisdnListError")
|
||||
helperText(data.phoneNumbersList.error.message)
|
||||
}
|
||||
}
|
||||
is Success -> {
|
||||
is Success -> {
|
||||
val phones = data.phoneNumbersList.invoke()
|
||||
if (phones.isEmpty()) {
|
||||
settingsInfoItem {
|
||||
|
@ -86,103 +88,21 @@ class DiscoverySettingsController @Inject constructor(
|
|||
}
|
||||
} else {
|
||||
phones.forEach { piState ->
|
||||
val phoneNumber = PhoneNumberUtil.getInstance()
|
||||
.parse("+${piState.value}", null)
|
||||
val phoneNumber = try {
|
||||
PhoneNumberUtil.getInstance().parse("+${piState.threePid.value}", null)
|
||||
} catch (t: Throwable) {
|
||||
Timber.e(t, "Unable to parse the phone number")
|
||||
null
|
||||
}
|
||||
?.let {
|
||||
PhoneNumberUtil.getInstance().format(it, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL)
|
||||
}
|
||||
|
||||
settingsTextButtonItem {
|
||||
id(piState.value)
|
||||
id(piState.threePid.value)
|
||||
title(phoneNumber)
|
||||
colorProvider(colorProvider)
|
||||
stringProvider(stringProvider)
|
||||
when {
|
||||
piState.isShared is Loading -> buttonIndeterminate(true)
|
||||
piState.isShared is Fail -> {
|
||||
buttonType(SettingsTextButtonItem.ButtonType.NORMAL)
|
||||
buttonStyle(SettingsTextButtonItem.ButtonStyle.DESTRUCTIVE)
|
||||
buttonTitle(stringProvider.getString(R.string.global_retry))
|
||||
infoMessage(piState.isShared.error.message)
|
||||
buttonClickListener(View.OnClickListener {
|
||||
listener?.onTapRetryToRetrieveBindings()
|
||||
})
|
||||
}
|
||||
piState.isShared is Success -> when (piState.isShared()) {
|
||||
PidInfo.SharedState.SHARED,
|
||||
PidInfo.SharedState.NOT_SHARED -> {
|
||||
checked(piState.isShared() == PidInfo.SharedState.SHARED)
|
||||
buttonType(SettingsTextButtonItem.ButtonType.SWITCH)
|
||||
switchChangeListener { _, checked ->
|
||||
if (checked) {
|
||||
listener?.onTapShareMsisdn(piState.value)
|
||||
} else {
|
||||
listener?.onTapRevokeMsisdn(piState.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_BIND,
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND -> {
|
||||
buttonType(SettingsTextButtonItem.ButtonType.NORMAL)
|
||||
buttonTitle("")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
when (piState.isShared()) {
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_BIND,
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND -> {
|
||||
settingsItemText {
|
||||
id("tverif" + piState.value)
|
||||
descriptionText(stringProvider.getString(R.string.settings_text_message_sent, phoneNumber))
|
||||
interactionListener(object : SettingsItemText.Listener {
|
||||
override fun onValidate(code: String) {
|
||||
val bind = piState.isShared() == PidInfo.SharedState.NOT_VERIFIED_FOR_BIND
|
||||
listener?.checkMsisdnVerification(piState.value, code, bind)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildMailSection(data: DiscoverySettingsState) {
|
||||
settingsSectionTitle {
|
||||
id("emails")
|
||||
titleResId(R.string.settings_discovery_emails_title)
|
||||
}
|
||||
when (data.emailList) {
|
||||
is Loading -> {
|
||||
settingsLoadingItem {
|
||||
id("mailLoading")
|
||||
}
|
||||
}
|
||||
is Fail -> {
|
||||
settingsInfoItem {
|
||||
id("mailListError")
|
||||
helperText(data.emailList.error.message)
|
||||
}
|
||||
}
|
||||
is Success -> {
|
||||
val emails = data.emailList.invoke()
|
||||
if (emails.isEmpty()) {
|
||||
settingsInfoItem {
|
||||
id("no_emails")
|
||||
helperText(stringProvider.getString(R.string.settings_discovery_no_mails))
|
||||
}
|
||||
} else {
|
||||
emails.forEach { piState ->
|
||||
settingsTextButtonItem {
|
||||
id(piState.value)
|
||||
title(piState.value)
|
||||
colorProvider(colorProvider)
|
||||
stringProvider(stringProvider)
|
||||
when (piState.isShared) {
|
||||
is Loading -> buttonIndeterminate(true)
|
||||
is Fail -> {
|
||||
|
@ -201,9 +121,95 @@ class DiscoverySettingsController @Inject constructor(
|
|||
buttonType(SettingsTextButtonItem.ButtonType.SWITCH)
|
||||
switchChangeListener { _, checked ->
|
||||
if (checked) {
|
||||
listener?.onTapShareEmail(piState.value)
|
||||
listener?.onTapShareMsisdn(piState.threePid.value)
|
||||
} else {
|
||||
listener?.onTapRevokeEmail(piState.value)
|
||||
listener?.onTapRevokeMsisdn(piState.threePid.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_BIND,
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND -> {
|
||||
buttonType(SettingsTextButtonItem.ButtonType.NORMAL)
|
||||
buttonTitle("")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
when (piState.isShared()) {
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_BIND,
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND -> {
|
||||
settingsItemText {
|
||||
id("tverif" + piState.threePid.value)
|
||||
descriptionText(stringProvider.getString(R.string.settings_text_message_sent, phoneNumber))
|
||||
interactionListener(object : SettingsItemText.Listener {
|
||||
override fun onValidate(code: String) {
|
||||
val bind = piState.isShared() == PidInfo.SharedState.NOT_VERIFIED_FOR_BIND
|
||||
listener?.checkMsisdnVerification(piState.threePid.value, code, bind)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildMailSection(data: DiscoverySettingsState) {
|
||||
settingsSectionTitle {
|
||||
id("emails")
|
||||
titleResId(R.string.settings_discovery_emails_title)
|
||||
}
|
||||
when (data.emailList) {
|
||||
is Incomplete -> {
|
||||
settingsLoadingItem {
|
||||
id("mailLoading")
|
||||
}
|
||||
}
|
||||
is Fail -> {
|
||||
settingsInfoItem {
|
||||
id("mailListError")
|
||||
helperText(data.emailList.error.message)
|
||||
}
|
||||
}
|
||||
is Success -> {
|
||||
val emails = data.emailList.invoke()
|
||||
if (emails.isEmpty()) {
|
||||
settingsInfoItem {
|
||||
id("no_emails")
|
||||
helperText(stringProvider.getString(R.string.settings_discovery_no_mails))
|
||||
}
|
||||
} else {
|
||||
emails.forEach { piState ->
|
||||
settingsTextButtonItem {
|
||||
id(piState.threePid.value)
|
||||
title(piState.threePid.value)
|
||||
colorProvider(colorProvider)
|
||||
stringProvider(stringProvider)
|
||||
when (piState.isShared) {
|
||||
is Loading -> buttonIndeterminate(true)
|
||||
is Fail -> {
|
||||
buttonType(SettingsTextButtonItem.ButtonType.NORMAL)
|
||||
buttonStyle(SettingsTextButtonItem.ButtonStyle.DESTRUCTIVE)
|
||||
buttonTitle(stringProvider.getString(R.string.global_retry))
|
||||
infoMessage(piState.isShared.error.message)
|
||||
buttonClickListener(View.OnClickListener {
|
||||
listener?.onTapRetryToRetrieveBindings()
|
||||
})
|
||||
}
|
||||
is Success -> when (piState.isShared()) {
|
||||
PidInfo.SharedState.SHARED,
|
||||
PidInfo.SharedState.NOT_SHARED -> {
|
||||
checked(piState.isShared() == PidInfo.SharedState.SHARED)
|
||||
buttonType(SettingsTextButtonItem.ButtonType.SWITCH)
|
||||
switchChangeListener { _, checked ->
|
||||
if (checked) {
|
||||
listener?.onTapShareEmail(piState.threePid.value)
|
||||
} else {
|
||||
listener?.onTapRevokeEmail(piState.threePid.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,10 +218,10 @@ class DiscoverySettingsController @Inject constructor(
|
|||
buttonType(SettingsTextButtonItem.ButtonType.NORMAL)
|
||||
buttonTitleId(R.string._continue)
|
||||
infoMessageTintColorId(R.color.vector_info_color)
|
||||
infoMessage(stringProvider.getString(R.string.settings_discovery_confirm_mail, piState.value))
|
||||
infoMessage(stringProvider.getString(R.string.settings_discovery_confirm_mail, piState.threePid.value))
|
||||
buttonClickListener(View.OnClickListener {
|
||||
val bind = piState.isShared() == PidInfo.SharedState.NOT_VERIFIED_FOR_BIND
|
||||
listener?.checkEmailVerification(piState.value, bind)
|
||||
listener?.checkEmailVerification(piState.threePid.value, bind)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,11 +140,7 @@ class DiscoverySettingsFragment @Inject constructor(
|
|||
|
||||
override fun onTapChangeIdentityServer() = withState(viewModel) { state ->
|
||||
//we should prompt if there are bound items with current is
|
||||
val pidList = ArrayList<PidInfo>().apply {
|
||||
state.emailList()?.let { addAll(it) }
|
||||
state.phoneNumbersList()?.let { addAll(it) }
|
||||
}
|
||||
|
||||
val pidList = state.emailList().orEmpty() + state.phoneNumbersList().orEmpty()
|
||||
val hasBoundIds = pidList.any { it.isShared() == PidInfo.SharedState.SHARED }
|
||||
|
||||
if (hasBoundIds) {
|
||||
|
@ -164,11 +160,7 @@ class DiscoverySettingsFragment @Inject constructor(
|
|||
override fun onTapDisconnectIdentityServer() {
|
||||
//we should prompt if there are bound items with current is
|
||||
withState(viewModel) { state ->
|
||||
val pidList = ArrayList<PidInfo>().apply {
|
||||
state.emailList()?.let { addAll(it) }
|
||||
state.phoneNumbersList()?.let { addAll(it) }
|
||||
}
|
||||
|
||||
val pidList = state.emailList().orEmpty() + state.phoneNumbersList().orEmpty()
|
||||
val hasBoundIds = pidList.any { it.isShared() == PidInfo.SharedState.SHARED }
|
||||
|
||||
if (hasBoundIds) {
|
||||
|
|
|
@ -29,17 +29,21 @@ import com.squareup.inject.assisted.Assisted
|
|||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.identity.FoundThreePid
|
||||
import im.vector.matrix.android.api.session.identity.IdentityServiceError
|
||||
import im.vector.matrix.android.api.session.identity.IdentityServiceListener
|
||||
import im.vector.matrix.android.api.session.identity.ThreePid
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotx.core.extensions.exhaustive
|
||||
import im.vector.riotx.core.platform.VectorViewEvents
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||
|
||||
data class PidInfo(
|
||||
val value: String,
|
||||
val isShared: Async<SharedState>,
|
||||
val _3pid: ThreePid? = null
|
||||
// Retrieved from the homeserver
|
||||
val threePid: ThreePid,
|
||||
// Retrieved from IdentityServer, or transient state
|
||||
val isShared: Async<SharedState>
|
||||
) {
|
||||
enum class SharedState {
|
||||
SHARED,
|
||||
|
@ -53,7 +57,7 @@ data class DiscoverySettingsState(
|
|||
val identityServer: Async<String?> = Uninitialized,
|
||||
val emailList: Async<List<PidInfo>> = Uninitialized,
|
||||
val phoneNumbersList: Async<List<PidInfo>> = Uninitialized,
|
||||
// TODO Use ViewEvents
|
||||
// TODO Use ViewEvents?
|
||||
val termsNotSigned: Boolean = false
|
||||
) : MvRxState
|
||||
|
||||
|
@ -100,13 +104,25 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
setState {
|
||||
copy(identityServer = Success(identityServerUrl))
|
||||
}
|
||||
if (currentIS != identityServerUrl) refreshModel()
|
||||
if (currentIS != identityServerUrl) retrieveBinding()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
setState {
|
||||
copy(identityServer = Success(identityService.getCurrentIdentityServer()))
|
||||
}
|
||||
startListenToIdentityManager()
|
||||
refreshModel()
|
||||
observeThreePids()
|
||||
}
|
||||
|
||||
private fun observeThreePids() {
|
||||
session.rx()
|
||||
.liveThreePIds()
|
||||
.subscribe {
|
||||
retrieveBinding(it)
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
|
@ -140,7 +156,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
identityServer = Success(action.url)
|
||||
)
|
||||
}
|
||||
refreshModel()
|
||||
retrieveBinding()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
|
@ -162,12 +178,12 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
|
||||
private fun shareEmail(email: String) = withState { state ->
|
||||
if (state.identityServer() == null) return@withState
|
||||
changeMailState(email, Loading(), null)
|
||||
changeMailState(email, Loading())
|
||||
|
||||
identityService.startBindSession(ThreePid.Email(email), null,
|
||||
object : MatrixCallback<ThreePid> {
|
||||
override fun onSuccess(data: ThreePid) {
|
||||
changeMailState(email, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_BIND), data)
|
||||
changeMailState(email, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_BIND)/* TODO , data*/)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
|
@ -178,30 +194,12 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
})
|
||||
}
|
||||
|
||||
private fun changeMailState(address: String, state: Async<PidInfo.SharedState>, threePid: ThreePid?) {
|
||||
setState {
|
||||
val currentMails = emailList() ?: emptyList()
|
||||
copy(emailList = Success(
|
||||
currentMails.map {
|
||||
if (it.value == address) {
|
||||
it.copy(
|
||||
_3pid = threePid,
|
||||
isShared = state
|
||||
)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
private fun changeMailState(address: String, state: Async<PidInfo.SharedState>) {
|
||||
setState {
|
||||
val currentMails = emailList() ?: emptyList()
|
||||
copy(emailList = Success(
|
||||
currentMails.map {
|
||||
if (it.value == address) {
|
||||
if (it.threePid.value == address) {
|
||||
it.copy(isShared = state)
|
||||
} else {
|
||||
it
|
||||
|
@ -211,16 +209,13 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun changeMsisdnState(address: String, state: Async<PidInfo.SharedState>, threePid: ThreePid?) {
|
||||
private fun changeMsisdnState(address: String, state: Async<PidInfo.SharedState>) {
|
||||
setState {
|
||||
val phones = phoneNumbersList() ?: emptyList()
|
||||
copy(phoneNumbersList = Success(
|
||||
phones.map {
|
||||
if (it.value == address) {
|
||||
it.copy(
|
||||
_3pid = threePid,
|
||||
isShared = state
|
||||
)
|
||||
if (it.threePid.value == address) {
|
||||
it.copy(isShared = state)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
|
@ -245,7 +240,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
override fun onSuccess(data: Pair<Boolean, ThreePid?>) {
|
||||
if (data.first) {
|
||||
// requires mail validation
|
||||
changeMailState(email, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND), data.second)
|
||||
changeMailState(email, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND) /* TODO , data.second */)
|
||||
} else {
|
||||
changeMailState(email, Success(PidInfo.SharedState.NOT_SHARED))
|
||||
}
|
||||
|
@ -271,7 +266,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
identityService.startUnBindSession(ThreePid.Msisdn(msisdn, countryCode), null, object : MatrixCallback<Pair<Boolean, ThreePid?>> {
|
||||
override fun onSuccess(data: Pair<Boolean, ThreePid?>) {
|
||||
if (data.first /*requires mail validation */) {
|
||||
changeMsisdnState(msisdn, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND), data.second)
|
||||
changeMsisdnState(msisdn, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND) /* TODO , data.second */)
|
||||
} else {
|
||||
changeMsisdnState(msisdn, Success(PidInfo.SharedState.NOT_SHARED))
|
||||
}
|
||||
|
@ -297,7 +292,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
|
||||
identityService.startBindSession(ThreePid.Msisdn(msisdn, countryCode), null, object : MatrixCallback<ThreePid> {
|
||||
override fun onSuccess(data: ThreePid) {
|
||||
changeMsisdnState(msisdn, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_BIND), data)
|
||||
changeMsisdnState(msisdn, Success(PidInfo.SharedState.NOT_VERIFIED_FOR_BIND) /* TODO , data */)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
|
@ -308,21 +303,6 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
})
|
||||
}
|
||||
|
||||
private fun changeMsisdnState(msisdn: String, sharedState: Async<PidInfo.SharedState>) {
|
||||
setState {
|
||||
val currentMsisdns = phoneNumbersList()!!
|
||||
copy(phoneNumbersList = Success(
|
||||
currentMsisdns.map {
|
||||
if (it.value == msisdn) {
|
||||
it.copy(isShared = sharedState)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startListenToIdentityManager() {
|
||||
identityService.addListener(identityServerManagerListener)
|
||||
}
|
||||
|
@ -331,115 +311,66 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
identityService.addListener(identityServerManagerListener)
|
||||
}
|
||||
|
||||
private fun refreshModel() = withState { state ->
|
||||
private fun retrieveBinding() {
|
||||
retrieveBinding(session.getThreePids())
|
||||
}
|
||||
|
||||
private fun retrieveBinding(threePids: List<ThreePid>) = withState { state ->
|
||||
if (state.identityServer().isNullOrBlank()) return@withState
|
||||
|
||||
val emails = threePids.filterIsInstance<ThreePid.Email>()
|
||||
val msisdns = threePids.filterIsInstance<ThreePid.Msisdn>()
|
||||
|
||||
setState {
|
||||
copy(
|
||||
emailList = Loading(),
|
||||
phoneNumbersList = Loading()
|
||||
emailList = Success(emails.map { PidInfo(it, Loading()) }),
|
||||
phoneNumbersList = Success(msisdns.map { PidInfo(it, Loading()) })
|
||||
)
|
||||
}
|
||||
|
||||
/* TODO
|
||||
session.refreshThirdPartyIdentifiers(object : MatrixCallback<Unit> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
_errorLiveEvent.postValue(LiveEvent(failure))
|
||||
identityService.lookUp(threePids,
|
||||
object : MatrixCallback<List<FoundThreePid>> {
|
||||
override fun onSuccess(data: List<FoundThreePid>) {
|
||||
setState {
|
||||
copy(
|
||||
emailList = Success(toPidInfoList(emails, data)),
|
||||
phoneNumbersList = Success(toPidInfoList(msisdns, data))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
setState {
|
||||
copy(
|
||||
emailList = Fail(failure),
|
||||
phoneNumbersList = Fail(failure)
|
||||
)
|
||||
}
|
||||
}
|
||||
override fun onFailure(failure: Throwable) {
|
||||
if (failure is IdentityServiceError.TermsNotSignedException) {
|
||||
setState {
|
||||
// TODO Use ViewEvent ?
|
||||
copy(termsNotSigned = true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSuccess(data: Unit) {
|
||||
setState {
|
||||
copy(termsNotSigned = false)
|
||||
}
|
||||
_viewEvents.post(DiscoverySettingsViewEvents.Failure(failure))
|
||||
|
||||
retrieveBinding()
|
||||
}
|
||||
})
|
||||
*/
|
||||
setState {
|
||||
copy(
|
||||
emailList = Success(emails.map { PidInfo(it, Fail(failure)) }),
|
||||
phoneNumbersList = Success(msisdns.map { PidInfo(it, Fail(failure)) })
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun retrieveBinding() {
|
||||
/* TODO
|
||||
val linkedMailsInfo = session.myUser.getlinkedEmails()
|
||||
val knownEmails = linkedMailsInfo.map { it.address }
|
||||
// Note: it will be a list of "email"
|
||||
val knownEmailMedium = linkedMailsInfo.map { it.medium }
|
||||
|
||||
val linkedMsisdnsInfo = session.myUser.getlinkedPhoneNumbers()
|
||||
val knownMsisdns = linkedMsisdnsInfo.map { it.address }
|
||||
// Note: it will be a list of "msisdn"
|
||||
val knownMsisdnMedium = linkedMsisdnsInfo.map { it.medium }
|
||||
|
||||
setState {
|
||||
copy(
|
||||
emailList = Success(knownEmails.map { PidInfo(it, Loading()) }),
|
||||
phoneNumbersList = Success(knownMsisdns.map { PidInfo(it, Loading()) })
|
||||
)
|
||||
}
|
||||
|
||||
identityService.lookup(knownEmails + knownMsisdns,
|
||||
knownEmailMedium + knownMsisdnMedium,
|
||||
object : MatrixCallback<List<FoundThreePid>> {
|
||||
override fun onSuccess(data: List<FoundThreePid>) {
|
||||
setState {
|
||||
copy(
|
||||
emailList = Success(toPidInfoList(knownEmails, data.take(knownEmails.size))),
|
||||
phoneNumbersList = Success(toPidInfoList(knownMsisdns, data.takeLast(knownMsisdns.size)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
if (e is TermsNotSignedException) {
|
||||
setState {
|
||||
// TODO Use ViewEvent
|
||||
copy(termsNotSigned = true)
|
||||
}
|
||||
}
|
||||
onError(e)
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
onError(e)
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
onError(Throwable(e.message))
|
||||
}
|
||||
|
||||
private fun onError(e: Throwable) {
|
||||
_errorLiveEvent.postValue(LiveEvent(e))
|
||||
|
||||
setState {
|
||||
copy(
|
||||
emailList = Success(knownEmails.map { PidInfo(it, Fail(e)) }),
|
||||
phoneNumbersList = Success(knownMsisdns.map { PidInfo(it, Fail(e)) })
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
private fun toPidInfoList(addressList: List<String>, matrixIds: List<String>): List<PidInfo> {
|
||||
return addressList.map {
|
||||
val hasMatrixId = matrixIds[addressList.indexOf(it)].isNotBlank()
|
||||
private fun toPidInfoList(threePids: List<ThreePid>, foundThreePids: List<FoundThreePid>): List<PidInfo> {
|
||||
return threePids.map { threePid ->
|
||||
val hasMatrixId = foundThreePids.any { it.threePid == threePid }
|
||||
PidInfo(
|
||||
value = it,
|
||||
threePid = threePid,
|
||||
isShared = Success(PidInfo.SharedState.SHARED.takeIf { hasMatrixId } ?: PidInfo.SharedState.NOT_SHARED)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun submitMsisdnToken(action: DiscoverySettingsAction.SubmitMsisdnToken) = withState { state ->
|
||||
val pid = state.phoneNumbersList()?.find { it.value == action.msisdn }?._3pid ?: return@withState
|
||||
val pid = state.phoneNumbersList()?.find { it.threePid.value == action.msisdn }?.threePid ?: return@withState
|
||||
|
||||
identityService.submitValidationToken(pid,
|
||||
action.code,
|
||||
|
@ -460,11 +391,11 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
val _3pid = when (action.threePid) {
|
||||
is ThreePid.Email -> {
|
||||
changeMailState(action.threePid.email, Loading())
|
||||
state.emailList()?.find { it.value == action.threePid.email }?._3pid ?: return@withState
|
||||
state.emailList()?.find { it.threePid.value == action.threePid.email }?.threePid ?: return@withState
|
||||
}
|
||||
is ThreePid.Msisdn -> {
|
||||
changeMsisdnState(action.threePid.msisdn, Loading())
|
||||
state.phoneNumbersList()?.find { it.value == action.threePid.msisdn }?._3pid ?: return@withState
|
||||
state.phoneNumbersList()?.find { it.threePid.value == action.threePid.msisdn }?.threePid ?: return@withState
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,8 +403,8 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
override fun onSuccess(data: Unit) {
|
||||
val sharedState = Success(if (action.bind) PidInfo.SharedState.SHARED else PidInfo.SharedState.NOT_SHARED)
|
||||
when (action.threePid) {
|
||||
is ThreePid.Email -> changeMailState(action.threePid.email, sharedState, null)
|
||||
is ThreePid.Msisdn -> changeMsisdnState(action.threePid.msisdn, sharedState, null)
|
||||
is ThreePid.Email -> changeMailState(action.threePid.email, sharedState)
|
||||
is ThreePid.Msisdn -> changeMsisdnState(action.threePid.msisdn, sharedState)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,8 +425,8 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||
private fun refreshPendingEmailBindings() = withState { state ->
|
||||
state.emailList()?.forEach { info ->
|
||||
when (info.isShared()) {
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_BIND -> finalizeBind3pid(DiscoverySettingsAction.FinalizeBind3pid(ThreePid.Email(info.value), true))
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND -> finalizeBind3pid(DiscoverySettingsAction.FinalizeBind3pid(ThreePid.Email(info.value), false))
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_BIND -> finalizeBind3pid(DiscoverySettingsAction.FinalizeBind3pid(info.threePid, true))
|
||||
PidInfo.SharedState.NOT_VERIFIED_FOR_UNBIND -> finalizeBind3pid(DiscoverySettingsAction.FinalizeBind3pid(info.threePid, false))
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue