Create a ViewState for HomeActivity

And disable the popup - WIP
This commit is contained in:
Benoit Marty 2020-06-09 12:21:02 +02:00 committed by Valere
parent 1365240f69
commit 48a30a7b82
6 changed files with 164 additions and 54 deletions

View file

@ -20,10 +20,13 @@ import androidx.lifecycle.LiveData
interface InitialSyncProgressService {
fun getInitialSyncProgressStatus() : LiveData<Status?>
fun getInitialSyncProgressStatus(): LiveData<Status>
data class Status(
sealed class Status {
object Idle : Status()
data class Progressing(
@StringRes val statusText: Int,
val percentProgress: Int = 0
)
) : Status()
}
}

View file

@ -25,11 +25,11 @@ import javax.inject.Inject
@SessionScope
class DefaultInitialSyncProgressService @Inject constructor() : InitialSyncProgressService {
private var status = MutableLiveData<InitialSyncProgressService.Status>()
private val status = MutableLiveData<InitialSyncProgressService.Status>()
private var rootTask: TaskInfo? = null
override fun getInitialSyncProgressStatus(): LiveData<InitialSyncProgressService.Status?> {
override fun getInitialSyncProgressStatus(): LiveData<InitialSyncProgressService.Status> {
return status
}
@ -63,13 +63,13 @@ class DefaultInitialSyncProgressService @Inject constructor() : InitialSyncProgr
parent?.setProgress(endedTask.offset + (endedTask.totalProgress * endedTask.parentWeight).toInt())
}
if (endedTask?.parent == null) {
status.postValue(null)
status.postValue(InitialSyncProgressService.Status.Idle)
}
}
fun endAll() {
rootTask = null
status.postValue(null)
status.postValue(InitialSyncProgressService.Status.Idle)
}
private inner class TaskInfo(@StringRes var nameRes: Int,
@ -102,9 +102,7 @@ class DefaultInitialSyncProgressService @Inject constructor() : InitialSyncProgr
it.setProgress(offset + parentProgress)
} ?: run {
Timber.v("--- ${leaf().nameRes}: $currentProgress")
status.postValue(
InitialSyncProgressService.Status(leaf().nameRes, currentProgress)
)
status.postValue(InitialSyncProgressService.Status.Progressing(leaf().nameRes, currentProgress))
}
}
}

View file

@ -19,20 +19,16 @@ package im.vector.riotx.features.home
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.view.MenuItem
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.core.view.GravityCompat
import androidx.core.view.isVisible
import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.Observer
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.viewModel
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.api.session.InitialSyncProgressService
import im.vector.riotx.R
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.di.ScreenComponent
@ -46,21 +42,28 @@ import im.vector.riotx.features.crypto.recover.BootstrapBottomSheet
import im.vector.riotx.features.disclaimer.showDisclaimerDialog
import im.vector.riotx.features.notifications.NotificationDrawerManager
import im.vector.riotx.features.popup.PopupAlertManager
import im.vector.riotx.features.popup.VerificationVectorAlert
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.riotx.features.settings.VectorPreferences
import im.vector.riotx.features.workers.signout.SignOutViewModel
import im.vector.riotx.push.fcm.FcmHelper
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.activity_home.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import timber.log.Timber
import javax.inject.Inject
@Parcelize
data class HomeActivityArgs(
val clearNotification: Boolean,
val accountCreation: Boolean
) : Parcelable
class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory {
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
private val homeActivityViewModel: HomeActivityViewModel by viewModel()
@Inject lateinit var viewModelFactory: HomeActivityViewModel.Factory
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
@Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler
@ -114,21 +117,33 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
}
.disposeOnDestroy()
if (intent.getBooleanExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION, false)) {
val args = intent.getParcelableExtra<HomeActivityArgs>(MvRx.KEY_ARG)
if (args?.clearNotification == true) {
notificationDrawerManager.clearAllEvents()
intent.removeExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION)
}
if (intent.getBooleanExtra(EXTRA_ACCOUNT_CREATION, false)) {
sharedActionViewModel.post(HomeActivitySharedAction.PromptForSecurityBootstrap)
homeActivityViewModel.isAccountCreation = true
intent.removeExtra(EXTRA_ACCOUNT_CREATION)
}
activeSessionHolder.getSafeActiveSession()?.getInitialSyncProgressStatus()?.observe(this, Observer { status ->
if (status == null) {
waiting_view.isVisible = false
homeActivityViewModel.subscribe(this) { renderState(it) }
/*
// TODO Remove
// Ask again if the app is relaunched
if (!homeActivityViewModel.hasDisplayedCompleteSecurityPrompt
&& activeSessionHolder.getSafeActiveSession()?.hasAlreadySynced() == true) {
promptCompleteSecurityIfNeeded()
} else {
}
*/
shortcutsHandler.observeRoomsAndBuildShortcuts()
.disposeOnDestroy()
}
private fun renderState(state: HomeActivityViewState) {
when (val status = state.initialSyncProgressServiceStatus) {
is InitialSyncProgressService.Status.Idle -> {
waiting_view.isVisible = false
}
is InitialSyncProgressService.Status.Progressing -> {
homeActivityViewModel.hasDisplayedCompleteSecurityPrompt = false
Timber.v("${getString(status.statusText)} ${status.percentProgress}")
waiting_view.setOnClickListener {
@ -146,18 +161,11 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
}
waiting_view.isVisible = true
}
})
// Ask again if the app is relaunched
if (!homeActivityViewModel.hasDisplayedCompleteSecurityPrompt
&& activeSessionHolder.getSafeActiveSession()?.hasAlreadySynced() == true) {
promptCompleteSecurityIfNeeded()
}
shortcutsHandler.observeRoomsAndBuildShortcuts()
.disposeOnDestroy()
}.exhaustive
}
/*
// TODO Remove
private fun promptCompleteSecurityIfNeeded() {
val session = activeSessionHolder.getSafeActiveSession() ?: return
if (!session.hasAlreadySynced()) return
@ -172,7 +180,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
}
})
}
*/
// TODO Remove
/*
private fun alertCompleteSecurity(session: Session) {
val myCrossSigningKeys = session.cryptoService().crossSigningService()
.getMyCrossSigningKeys()
@ -204,7 +215,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
}
}
}
*/
/*
// TODO Remove
private fun promptSecurityEvent(session: Session, titleRes: Int, descRes: Int, action: ((VectorBaseActivity) -> Unit)) {
homeActivityViewModel.hasDisplayedCompleteSecurityPrompt = true
popupAlertManager.postVectorAlert(
@ -225,12 +239,12 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
}
)
}
*/
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent?.hasExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION) == true) {
if (intent?.getParcelableExtra<HomeActivityArgs>(MvRx.KEY_ARG)?.clearNotification == true) {
notificationDrawerManager.clearAllEvents()
intent.removeExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION)
}
}
@ -293,14 +307,15 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
}
companion object {
private const val EXTRA_CLEAR_EXISTING_NOTIFICATION = "EXTRA_CLEAR_EXISTING_NOTIFICATION"
private const val EXTRA_ACCOUNT_CREATION = "EXTRA_ACCOUNT_CREATION"
fun newIntent(context: Context, clearNotification: Boolean = false, accountCreation: Boolean = false): Intent {
val args = HomeActivityArgs(
clearNotification = clearNotification,
accountCreation = accountCreation
)
return Intent(context, HomeActivity::class.java)
.apply {
putExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION, clearNotification)
putExtra(EXTRA_ACCOUNT_CREATION, accountCreation)
putExtra(MvRx.KEY_ARG, args)
}
}
}

View file

@ -25,5 +25,6 @@ sealed class HomeActivitySharedAction : VectorSharedAction {
object OpenDrawer : HomeActivitySharedAction()
object CloseDrawer : HomeActivitySharedAction()
object OpenGroup : HomeActivitySharedAction()
// TODO Remove?
object PromptForSecurityBootstrap : HomeActivitySharedAction()
}

View file

@ -16,18 +16,87 @@
package im.vector.riotx.features.home
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRx
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.internal.crypto.model.rest.UserPasswordAuth
import im.vector.matrix.rx.asObservable
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.features.login.ReAuthHelper
import timber.log.Timber
data class EmptyState(
val dummy: Boolean = false
) : MvRxState
class HomeActivityViewModel @AssistedInject constructor(
@Assisted initialState: HomeActivityViewState,
@Assisted private val args: HomeActivityArgs,
private val activeSessionHolder: ActiveSessionHolder,
private val reAuthHelper: ReAuthHelper
) : VectorViewModel<HomeActivityViewState, EmptyAction, EmptyViewEvents>(initialState) {
class HomeActivityViewModel : VectorViewModel<EmptyState, EmptyAction, EmptyViewEvents>(EmptyState()) {
@AssistedInject.Factory
interface Factory {
fun create(initialState: HomeActivityViewState, args: HomeActivityArgs): HomeActivityViewModel
}
companion object : MvRxViewModelFactory<HomeActivityViewModel, HomeActivityViewState> {
@JvmStatic
override fun create(viewModelContext: ViewModelContext, state: HomeActivityViewState): HomeActivityViewModel? {
val activity: HomeActivity = viewModelContext.activity()
val args: HomeActivityArgs? = activity.intent.getParcelableExtra(MvRx.KEY_ARG)
return args?.let { activity.viewModelFactory.create(state, it) }
}
}
// TODO Remove?
var hasDisplayedCompleteSecurityPrompt: Boolean = false
var isAccountCreation: Boolean = false
init {
observeInitialSync()
mayBeInitializeCrossSigning()
}
private fun observeInitialSync() {
val session = activeSessionHolder.getSafeActiveSession() ?: return
session.getInitialSyncProgressStatus()
.asObservable()
.subscribe { status ->
setState {
copy(
initialSyncProgressServiceStatus = status
)
}
}
.disposeOnClear()
}
private fun mayBeInitializeCrossSigning() {
if (args.accountCreation) {
val password = reAuthHelper.data ?: return Unit.also {
Timber.w("No password to init cross signing")
}
val session = activeSessionHolder.getSafeActiveSession() ?: return Unit.also {
Timber.w("No session to init cross signing")
}
// We do not use the viewModel context because we do not want to cancel this action
Timber.d("Initialize cross signing")
session.cryptoService().crossSigningService().initializeCrossSigning(
authParams = UserPasswordAuth(
session = null,
user = session.myUserId,
password = password
)
)
// TODO Download keys?
}
}
override fun handle(action: EmptyAction) {
// NA

View file

@ -0,0 +1,24 @@
/*
* 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.riotx.features.home
import com.airbnb.mvrx.MvRxState
import im.vector.matrix.android.api.session.InitialSyncProgressService
data class HomeActivityViewState(
val initialSyncProgressServiceStatus: InitialSyncProgressService.Status = InitialSyncProgressService.Status.Idle
) : MvRxState