This commit is contained in:
Valere 2019-07-04 10:53:46 +02:00
parent a0bd206308
commit 95d83db90c
18 changed files with 373 additions and 113 deletions

View File

@ -0,0 +1,13 @@
package im.vector.matrix.android.api.session

import androidx.lifecycle.LiveData

interface InitialSyncProgressService {

fun getLiveStatus() : LiveData<Status?>

data class Status(
val statusText: Int?,
val percentProgress: Int = 0
)
}

View File

@ -49,7 +49,8 @@ interface Session :
FilterService, FilterService,
FileService, FileService,
PushRuleService, PushRuleService,
PushersService { PushersService,
InitialSyncProgressService {


/** /**
* The params associated to the session * The params associated to the session

View File

@ -0,0 +1,97 @@
package im.vector.matrix.android.internal.session

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import im.vector.matrix.android.api.session.InitialSyncProgressService
import timber.log.Timber
import javax.inject.Inject


@SessionScope
class DefaultInitialSyncProgressService @Inject constructor() : InitialSyncProgressService {

var status = MutableLiveData<InitialSyncProgressService.Status>()

var rootTask: TaskInfo? = null

override fun getLiveStatus(): LiveData<InitialSyncProgressService.Status?> {
return status
}


fun startTask(nameRes: Int, totalProgress: Int, parentWeight: Float = 1f) {
if (rootTask == null) {
rootTask = TaskInfo(nameRes, totalProgress)
} else {
val currentLeaf = rootTask!!.leaf()
val newTask = TaskInfo(nameRes, totalProgress)
newTask.parent = currentLeaf
newTask.offset = currentLeaf.currentProgress
currentLeaf.child = newTask
newTask.parentWeight = parentWeight
}
reportProgress(0)
}

fun reportProgress(progress: Int) {
rootTask?.leaf()?.incrementProgress(progress)
}

fun endTask(nameRes: Int) {
val endedTask = rootTask?.leaf()
if (endedTask?.nameRes == nameRes) {
//close it
val parent = endedTask.parent
parent?.child = null
parent?.incrementProgress(endedTask.offset + (endedTask.totalProgress * endedTask.parentWeight).toInt())
}
if (endedTask?.parent == null) {
this@DefaultInitialSyncProgressService.status.postValue(null)
}
}

fun endAll() {
this@DefaultInitialSyncProgressService.status.postValue(null)
}


inner class TaskInfo(var nameRes: Int,
var totalProgress: Int) {
var parent: TaskInfo? = null
var child: TaskInfo? = null
var parentWeight: Float = 1f
var currentProgress: Int = 0
var offset: Int = 0

fun leaf(): TaskInfo {
var last = this
while (last.child != null) {
last = last.child!!
}
return last
}

fun incrementProgress(progress: Int) {
currentProgress = progress
// val newProgress = Math.min(currentProgress + progress, totalProgress)
parent?.let {
val parentProgress = (currentProgress * parentWeight).toInt()
it.incrementProgress(offset + parentProgress)
}
if (parent == null) {
Timber.e("--- ${leaf().nameRes}: ${currentProgress}")
this@DefaultInitialSyncProgressService.status.postValue(
InitialSyncProgressService.Status(leaf().nameRes, currentProgress)
)
}
}
}

}

public inline fun <T> reportSubtask(reporter: DefaultInitialSyncProgressService?, nameRes: Int, totalProgress: Int, parentWeight: Float = 1f, block: () -> T): T {
reporter?.startTask(nameRes, totalProgress, parentWeight)
return block().also {
reporter?.endTask(nameRes)
}
}

View File

@ -24,6 +24,7 @@ import androidx.work.WorkManager
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.pushrules.PushRuleService import im.vector.matrix.android.api.pushrules.PushRuleService
import im.vector.matrix.android.api.session.InitialSyncProgressService
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.cache.CacheService import im.vector.matrix.android.api.session.cache.CacheService
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
@ -64,7 +65,8 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
private val fileService: FileService, private val fileService: FileService,
private val syncThread: SyncThread, private val syncThread: SyncThread,
private val contentUrlResolver: ContentUrlResolver, private val contentUrlResolver: ContentUrlResolver,
private val contentUploadProgressTracker: ContentUploadStateTracker) private val contentUploadProgressTracker: ContentUploadStateTracker,
private val initialSyncProgressService: InitialSyncProgressService)
: Session, : Session,
RoomService by roomService, RoomService by roomService,
RoomDirectoryService by roomDirectoryService, RoomDirectoryService by roomDirectoryService,
@ -74,9 +76,10 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
CacheService by cacheService, CacheService by cacheService,
SignOutService by signOutService, SignOutService by signOutService,
FilterService by filterService, FilterService by filterService,
FileService by fileService,
PushRuleService by pushRuleService, PushRuleService by pushRuleService,
PushersService by pushersService { PushersService by pushersService,
FileService by fileService,
InitialSyncProgressService by initialSyncProgressService {


private var isOpen = false private var isOpen = false



View File

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session
import dagger.BindsInstance import dagger.BindsInstance
import dagger.Component import dagger.Component
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.session.InitialSyncProgressService
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.crypto.CryptoModule import im.vector.matrix.android.internal.crypto.CryptoModule
import im.vector.matrix.android.internal.di.MatrixComponent import im.vector.matrix.android.internal.di.MatrixComponent

View File

@ -25,6 +25,7 @@ import dagger.multibindings.IntoSet
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.session.InitialSyncProgressService
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.database.configureEncryption import im.vector.matrix.android.internal.database.configureEncryption
@ -132,4 +133,7 @@ internal abstract class SessionModule {
@IntoSet @IntoSet
abstract fun bindUserEntityUpdater(groupSummaryUpdater: UserEntityUpdater): LiveEntityObserver abstract fun bindUserEntityUpdater(groupSummaryUpdater: UserEntityUpdater): LiveEntityObserver


@Binds
abstract fun bindInitialSyncProgressService(initialSyncProgressService: DefaultInitialSyncProgressService): InitialSyncProgressService

} }

View File

@ -26,6 +26,8 @@ import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.session.sync.model.SyncResponse import im.vector.matrix.android.internal.session.sync.model.SyncResponse
import im.vector.matrix.android.internal.session.sync.model.ToDeviceSyncResponse import im.vector.matrix.android.internal.session.sync.model.ToDeviceSyncResponse
import timber.log.Timber import timber.log.Timber
@ -35,8 +37,10 @@ import javax.inject.Inject
internal class CryptoSyncHandler @Inject constructor(private val cryptoManager: CryptoManager, internal class CryptoSyncHandler @Inject constructor(private val cryptoManager: CryptoManager,
private val sasVerificationService: DefaultSasVerificationService) { private val sasVerificationService: DefaultSasVerificationService) {


fun handleToDevice(toDevice: ToDeviceSyncResponse) { fun handleToDevice(toDevice: ToDeviceSyncResponse, initialSyncProgressService: DefaultInitialSyncProgressService? = null) {
toDevice.events?.forEach { event -> val total = toDevice.events?.size ?: 0
toDevice.events?.forEachIndexed { index, event ->
initialSyncProgressService?.reportProgress(((index / total.toFloat()) * 100).toInt())
// Decrypt event if necessary // Decrypt event if necessary
decryptEvent(event, null) decryptEvent(event, null)
if (TextUtils.equals(event.getClearType(), EventType.MESSAGE) if (TextUtils.equals(event.getClearType(), EventType.MESSAGE)

View File

@ -17,10 +17,11 @@
package im.vector.matrix.android.internal.session.sync package im.vector.matrix.android.internal.session.sync


import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.R
import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.internal.database.model.GroupEntity import im.vector.matrix.android.internal.database.model.GroupEntity
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
import im.vector.matrix.android.internal.session.sync.model.GroupsSyncResponse import im.vector.matrix.android.internal.session.sync.model.GroupsSyncResponse
import im.vector.matrix.android.internal.session.sync.model.InvitedGroupSync import im.vector.matrix.android.internal.session.sync.model.InvitedGroupSync
import io.realm.Realm import io.realm.Realm
@ -34,21 +35,48 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc
data class LEFT(val data: Map<String, Any>) : HandlingStrategy() data class LEFT(val data: Map<String, Any>) : HandlingStrategy()
} }


fun handle(roomsSyncResponse: GroupsSyncResponse) { fun handle(roomsSyncResponse: GroupsSyncResponse, reporter: DefaultInitialSyncProgressService? = null) {
monarchy.runTransactionSync { realm -> monarchy.runTransactionSync { realm ->
handleGroupSync(realm, GroupSyncHandler.HandlingStrategy.JOINED(roomsSyncResponse.join)) handleGroupSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), reporter)
handleGroupSync(realm, GroupSyncHandler.HandlingStrategy.INVITED(roomsSyncResponse.invite)) handleGroupSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), reporter)
handleGroupSync(realm, GroupSyncHandler.HandlingStrategy.LEFT(roomsSyncResponse.leave)) handleGroupSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), reporter)
} }
} }


// PRIVATE METHODS ***************************************************************************** // PRIVATE METHODS *****************************************************************************


private fun handleGroupSync(realm: Realm, handlingStrategy: HandlingStrategy) { private fun handleGroupSync(realm: Realm, handlingStrategy: HandlingStrategy, reporter: DefaultInitialSyncProgressService?) {
val groups = when (handlingStrategy) { val groups = when (handlingStrategy) {
is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedGroup(realm, it.key) } is HandlingStrategy.JOINED -> {
is HandlingStrategy.INVITED -> handlingStrategy.data.map { handleInvitedGroup(realm, it.key) } val total = handlingStrategy.data.size
is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftGroup(realm, it.key) } reporter?.startTask(R.string.initial_sync_start_importing_account_groups, total, 0.6f)
var current = 0
handlingStrategy.data.map {
reporter?.reportProgress((current / total.toFloat() * 100).toInt())
current++
handleJoinedGroup(realm, it.key)
}
}
is HandlingStrategy.INVITED -> {
val total = handlingStrategy.data.size
reporter?.startTask(R.string.initial_sync_start_importing_account_groups, total, 0.3f)
var current = 0
handlingStrategy.data.map {
reporter?.reportProgress((current / total.toFloat() * 100).toInt())
current++
handleInvitedGroup(realm, it.key)
}
}
is HandlingStrategy.LEFT -> {
val total = handlingStrategy.data.size
reporter?.startTask(R.string.initial_sync_start_importing_account_groups, total, 0.1f)
var current = 0
handlingStrategy.data.map {
reporter?.reportProgress((current / total.toFloat() * 100).toInt())
current++
handleLeftGroup(realm, it.key)
}
}
} }
realm.insertOrUpdate(groups) realm.insertOrUpdate(groups)
} }

View File

@ -17,6 +17,7 @@
package im.vector.matrix.android.internal.session.sync package im.vector.matrix.android.internal.session.sync


import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.R
import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.events.model.toModel
@ -32,6 +33,7 @@ import im.vector.matrix.android.internal.database.model.RoomEntity
import im.vector.matrix.android.internal.database.query.find import im.vector.matrix.android.internal.database.query.find
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
import im.vector.matrix.android.internal.session.notification.DefaultPushRuleService import im.vector.matrix.android.internal.session.notification.DefaultPushRuleService
import im.vector.matrix.android.internal.session.notification.ProcessEventForPushTask import im.vector.matrix.android.internal.session.notification.ProcessEventForPushTask
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
@ -60,11 +62,11 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
data class LEFT(val data: Map<String, RoomSync>) : HandlingStrategy() data class LEFT(val data: Map<String, RoomSync>) : HandlingStrategy()
} }


fun handle(roomsSyncResponse: RoomsSyncResponse) { fun handle(roomsSyncResponse: RoomsSyncResponse, reporter: DefaultInitialSyncProgressService? = null) {
monarchy.runTransactionSync { realm -> monarchy.runTransactionSync { realm ->
handleRoomSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join)) handleRoomSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), reporter)
handleRoomSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite)) handleRoomSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), reporter)
handleRoomSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave)) handleRoomSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), reporter)
} }


//handle event for bing rule checks //handle event for bing rule checks
@ -87,11 +89,37 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch


// PRIVATE METHODS ***************************************************************************** // PRIVATE METHODS *****************************************************************************


private fun handleRoomSync(realm: Realm, handlingStrategy: HandlingStrategy) { private fun handleRoomSync(realm: Realm, handlingStrategy: HandlingStrategy, reporter: DefaultInitialSyncProgressService?) {

val rooms = when (handlingStrategy) { val rooms = when (handlingStrategy) {
is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) } is HandlingStrategy.JOINED -> {
is HandlingStrategy.INVITED -> handlingStrategy.data.map { handleInvitedRoom(realm, it.key, it.value) } val total = handlingStrategy.data.size
is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftRoom(realm, it.key, it.value) } reporter?.startTask(R.string.initial_sync_start_importing_account_joined_rooms, total, 0.6f)
var current = 0
handlingStrategy.data.map {
reporter?.reportProgress((current / total.toFloat() * 100).toInt())
current++
handleJoinedRoom(realm, it.key, it.value).also {
reporter?.endTask(R.string.initial_sync_start_importing_account_joined_rooms)
}
}

}
is HandlingStrategy.INVITED -> {
val total = handlingStrategy.data.size
reporter?.startTask(R.string.initial_sync_start_importing_account_invited_rooms, total, 0.4f)
var current = 0
handlingStrategy.data.map {
reporter?.reportProgress((current / total.toFloat() * 100).toInt())
current++
handleInvitedRoom(realm, it.key, it.value)
}.also {
reporter?.endTask(R.string.initial_sync_start_importing_account_invited_rooms)
}
}
is HandlingStrategy.LEFT -> {
handlingStrategy.data.map { handleLeftRoom(realm, it.key, it.value) }
}
} }
realm.insertOrUpdate(rooms) realm.insertOrUpdate(rooms)
} }

View File

@ -17,7 +17,10 @@
package im.vector.matrix.android.internal.session.sync package im.vector.matrix.android.internal.session.sync


import arrow.core.Try import arrow.core.Try
import im.vector.matrix.android.R
import im.vector.matrix.android.internal.crypto.CryptoManager import im.vector.matrix.android.internal.crypto.CryptoManager
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
import im.vector.matrix.android.internal.session.reportSubtask
import im.vector.matrix.android.internal.session.sync.model.SyncResponse import im.vector.matrix.android.internal.session.sync.model.SyncResponse
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -27,12 +30,15 @@ internal class SyncResponseHandler @Inject constructor(private val roomSyncHandl
private val userAccountDataSyncHandler: UserAccountDataSyncHandler, private val userAccountDataSyncHandler: UserAccountDataSyncHandler,
private val groupSyncHandler: GroupSyncHandler, private val groupSyncHandler: GroupSyncHandler,
private val cryptoSyncHandler: CryptoSyncHandler, private val cryptoSyncHandler: CryptoSyncHandler,
private val cryptoManager: CryptoManager) { private val cryptoManager: CryptoManager,
private val initialSyncProgressService: DefaultInitialSyncProgressService) {


fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean): Try<SyncResponse> { fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean): Try<SyncResponse> {
return Try { return Try {
Timber.v("Start handling sync")
val isInitialSync = fromToken == null val isInitialSync = fromToken == null
Timber.v("Start handling sync, is InitialSync: ${isInitialSync}")
val reporter = initialSyncProgressService.takeIf { isInitialSync }

if (!cryptoManager.isStarted()) { if (!cryptoManager.isStarted()) {
Timber.v("Should start cryptoManager") Timber.v("Should start cryptoManager")
cryptoManager.start(isInitialSync) cryptoManager.start(isInitialSync)
@ -41,23 +47,36 @@ internal class SyncResponseHandler @Inject constructor(private val roomSyncHandl
// Handle the to device events before the room ones // Handle the to device events before the room ones
// to ensure to decrypt them properly // to ensure to decrypt them properly
Timber.v("Handle toDevice") Timber.v("Handle toDevice")
reportSubtask(reporter, R.string.initial_sync_start_importing_account_crypto, 100, 0.2f) {
if (syncResponse.toDevice != null) { if (syncResponse.toDevice != null) {
cryptoSyncHandler.handleToDevice(syncResponse.toDevice) cryptoSyncHandler.handleToDevice(syncResponse.toDevice, reporter)
}
} }
Timber.v("Handle rooms") Timber.v("Handle rooms")

reportSubtask(reporter, R.string.initial_sync_start_importing_account_rooms, 100, 0.5f) {
if (syncResponse.rooms != null) { if (syncResponse.rooms != null) {
roomSyncHandler.handle(syncResponse.rooms) roomSyncHandler.handle(syncResponse.rooms, reporter)
} }
}

reportSubtask(reporter, R.string.initial_sync_start_importing_account_groups, 100, 0.2f) {
Timber.v("Handle groups") Timber.v("Handle groups")
if (syncResponse.groups != null) { if (syncResponse.groups != null) {
groupSyncHandler.handle(syncResponse.groups) groupSyncHandler.handle(syncResponse.groups, reporter)
} }
}

reportSubtask(reporter, R.string.initial_sync_start_importing_account_data, 100, 0.1f) {
Timber.v("Handle accoundData") Timber.v("Handle accoundData")
if (syncResponse.accountData != null) { if (syncResponse.accountData != null) {
userAccountDataSyncHandler.handle(syncResponse.accountData) userAccountDataSyncHandler.handle(syncResponse.accountData)
} }
}

Timber.v("On sync completed") Timber.v("On sync completed")
cryptoSyncHandler.onSyncCompleted(syncResponse) cryptoSyncHandler.onSyncCompleted(syncResponse)

} }
Timber.v("Finish handling sync in $measure ms") Timber.v("Finish handling sync in $measure ms")
syncResponse syncResponse

View File

@ -19,14 +19,18 @@ package im.vector.matrix.android.internal.session.sync
import arrow.core.Try import arrow.core.Try
import arrow.core.failure import arrow.core.failure
import arrow.core.recoverWith import arrow.core.recoverWith
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.R
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.failure.MatrixError import im.vector.matrix.android.api.failure.MatrixError
import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
import im.vector.matrix.android.internal.session.filter.FilterRepository import im.vector.matrix.android.internal.session.filter.FilterRepository
import im.vector.matrix.android.internal.session.sync.model.SyncResponse import im.vector.matrix.android.internal.session.sync.model.SyncResponse
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.tryTransactionAsync
import javax.inject.Inject import javax.inject.Inject


internal interface SyncTask : Task<SyncTask.Params, Unit> { internal interface SyncTask : Task<SyncTask.Params, Unit> {
@ -40,7 +44,9 @@ internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI,
private val filterRepository: FilterRepository, private val filterRepository: FilterRepository,
private val syncResponseHandler: SyncResponseHandler, private val syncResponseHandler: SyncResponseHandler,
private val sessionParamsStore: SessionParamsStore, private val sessionParamsStore: SessionParamsStore,
private val syncTokenStore: SyncTokenStore private val initialSyncProgressService: DefaultInitialSyncProgressService,
private val syncTokenStore: SyncTokenStore,
private val monarchy: Monarchy
) : SyncTask { ) : SyncTask {




@ -55,6 +61,10 @@ internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI,
requestParams["timeout"] = timeout.toString() requestParams["timeout"] = timeout.toString()
requestParams["filter"] = filterRepository.getFilter() requestParams["filter"] = filterRepository.getFilter()


val isInitialSync = token == null
if (isInitialSync) {
initialSyncProgressService.startTask(R.string.initial_sync_start_importing_account, 100)
}
return executeRequest<SyncResponse> { return executeRequest<SyncResponse> {
apiCall = syncAPI.sync(requestParams) apiCall = syncAPI.sync(requestParams)
}.recoverWith { throwable -> }.recoverWith { throwable ->
@ -67,7 +77,13 @@ internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI,
// Transmit the throwable // Transmit the throwable
throwable.failure() throwable.failure()
}.flatMap { syncResponse -> }.flatMap { syncResponse ->
syncResponseHandler.handleResponse(syncResponse, token, false) syncResponseHandler.handleResponse(syncResponse, token, false).also {
if (isInitialSync) {
monarchy.tryTransactionAsync {
initialSyncProgressService.endAll()
}
}
}
}.map { }.map {
syncTokenStore.saveToken(it.nextBatch) syncTokenStore.saveToken(it.nextBatch)
} }

View File

@ -228,4 +228,13 @@
<!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb -->
<string name="verification_emoji_pin">Pin</string> <string name="verification_emoji_pin">Pin</string>



<string name="initial_sync_start_importing_account">Initial Sync:\nImporting account…</string>
<string name="initial_sync_start_importing_account_crypto">Initial Sync:\nImporting crypto</string>
<string name="initial_sync_start_importing_account_rooms">Initial Sync:\nImporting Rooms</string>
<string name="initial_sync_start_importing_account_joined_rooms">Initial Sync:\nImporting Joined Rooms</string>
<string name="initial_sync_start_importing_account_invited_rooms">Initial Sync:\nImporting Invited Rooms</string>
<string name="initial_sync_start_importing_account_left_rooms">Initial Sync:\nImporting Left Rooms</string>
<string name="initial_sync_start_importing_account_groups">Initial Sync:\nImporting Communities</string>
<string name="initial_sync_start_importing_account_data">Initial Sync:\nImporting Account Data</string>
</resources> </resources>

View File

@ -17,6 +17,7 @@
package im.vector.riotx.features.home package im.vector.riotx.features.home


import android.app.ProgressDialog import android.app.ProgressDialog
import android.app.TimePickerDialog
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@ -24,6 +25,7 @@ import android.view.MenuItem
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.view.GravityCompat import androidx.core.view.GravityCompat
import androidx.core.view.isVisible
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
@ -45,6 +47,8 @@ import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.riotx.features.workers.signout.SignOutViewModel import im.vector.riotx.features.workers.signout.SignOutViewModel
import im.vector.riotx.push.fcm.FcmHelper import im.vector.riotx.push.fcm.FcmHelper
import kotlinx.android.synthetic.main.activity_home.* import kotlinx.android.synthetic.main.activity_home.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject




@ -114,6 +118,25 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
notificationDrawerManager.clearAllEvents() notificationDrawerManager.clearAllEvents()
intent.removeExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION) intent.removeExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION)
} }

activeSessionHolder.getSafeActiveSession()?.getLiveStatus()?.observe(this, Observer {
Timber.e("${it?.statusText?.let { getString(it) }} ${it?.percentProgress}")
if (it == null) {
waiting_view.isVisible = false
} else {
waiting_view_status_horizontal_progress.apply {
isIndeterminate = false
max = 100
progress = it.percentProgress
isVisible = true
}
waiting_view_status_text.apply {
text = it.statusText?.let { res -> getString(res) }
isVisible = true
}
waiting_view.isVisible = true
}
})
} }


override fun onNewIntent(intent: Intent?) { override fun onNewIntent(intent: Intent?) {

View File

@ -30,7 +30,7 @@ import kotlinx.android.synthetic.main.activity_bug_report.*
import timber.log.Timber import timber.log.Timber


/** /**
* Form to send a bug report * Form to send a bug reportSubtask
*/ */
class BugReportActivity : VectorBaseActivity() { class BugReportActivity : VectorBaseActivity() {


@ -56,7 +56,7 @@ class BugReportActivity : VectorBaseActivity() {


forSuggestion = intent.getBooleanExtra("FOR_SUGGESTION", false) forSuggestion = intent.getBooleanExtra("FOR_SUGGESTION", false)


// Default screen is for bug report, so modify it for suggestion // Default screen is for bug reportSubtask, so modify it for suggestion
if (forSuggestion) { if (forSuggestion) {
supportActionBar?.setTitle(R.string.send_suggestion) supportActionBar?.setTitle(R.string.send_suggestion)


@ -101,7 +101,7 @@ class BugReportActivity : VectorBaseActivity() {




/** /**
* Send the bug report * Send the bug reportSubtask
*/ */
private fun sendBugReport() { private fun sendBugReport() {
bug_report_scrollview.alpha = 0.3f bug_report_scrollview.alpha = 0.3f

View File

@ -68,11 +68,11 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
// the http client // the http client
private val mOkHttpClient = OkHttpClient() private val mOkHttpClient = OkHttpClient()


// the pending bug report call // the pending bug reportSubtask call
private var mBugReportCall: Call? = null private var mBugReportCall: Call? = null




// boolean to cancel the bug report // boolean to cancel the bug reportSubtask
private val mIsCancelled = false private val mIsCancelled = false


/** /**
@ -96,16 +96,16 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
private val LOGCAT_CMD_DEBUG = arrayOf("logcat", "-d", "-v", "threadtime", "*:*") private val LOGCAT_CMD_DEBUG = arrayOf("logcat", "-d", "-v", "threadtime", "*:*")


/** /**
* Bug report upload listener * Bug reportSubtask upload listener
*/ */
interface IMXBugReportListener { interface IMXBugReportListener {
/** /**
* The bug report has been cancelled * The bug reportSubtask has been cancelled
*/ */
fun onUploadCancelled() fun onUploadCancelled()


/** /**
* The bug report upload failed. * The bug reportSubtask upload failed.
* *
* @param reason the failure reason * @param reason the failure reason
*/ */
@ -119,13 +119,13 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
fun onProgress(progress: Int) fun onProgress(progress: Int)


/** /**
* The bug report upload succeeded. * The bug reportSubtask upload succeeded.
*/ */
fun onUploadSucceed() fun onUploadSucceed()
} }


/** /**
* Send a bug report. * Send a bug reportSubtask.
* *
* @param context the application context * @param context the application context
* @param forSuggestion true to send a suggestion * @param forSuggestion true to send a suggestion
@ -407,7 +407,7 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
override fun onPostExecute(reason: String?) { override fun onPostExecute(reason: String?) {
mBugReportCall = null mBugReportCall = null


// delete when the bug report has been successfully sent // delete when the bug reportSubtask has been successfully sent
for (file in mBugReportFiles) { for (file in mBugReportFiles) {
file.delete() file.delete()
} }
@ -431,7 +431,7 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
} }


/** /**
* Send a bug report either with email or with Vector. * Send a bug reportSubtask either with email or with Vector.
*/ */
fun openBugReportScreen(activity: Activity, forSuggestion: Boolean = false) { fun openBugReportScreen(activity: Activity, forSuggestion: Boolean = false) {
screenshot = takeScreenshot(activity) screenshot = takeScreenshot(activity)
@ -442,7 +442,7 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
} }


//============================================================================================================== //==============================================================================================================
// crash report management // crash reportSubtask management
//============================================================================================================== //==============================================================================================================


/** /**
@ -472,7 +472,7 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
} }


/** /**
* Save the crash report * Save the crash reportSubtask
* *
* @param context the context * @param context the context
* @param crashDescription teh crash description * @param crashDescription teh crash description

View File

@ -22,66 +22,6 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar" /> app:layout_constraintTop_toBottomOf="@id/toolbar" />


<androidx.constraintlayout.widget.ConstraintLayout <include layout="@layout/merge_overlay_waiting_view"/>
android:id="@+id/waiting_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?vctr_waiting_background_color"
android:visibility="gone"
tools:visibility="visible">

<LinearLayout
android:id="@+id/waiting_view_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/layout_horizontal_margin"
android:background="?attr/colorBackgroundFloating"
android:orientation="vertical"
android:padding="@dimen/layout_horizontal_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="@dimen/dialog_width_ratio">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">

<ProgressBar
android:id="@+id/waiting_view_status_circular_progress"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="6dp"
android:layout_marginRight="6dp" />

<TextView
android:id="@+id/waiting_view_status_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="?riotx_text_secondary"
android:visibility="gone"
tools:text="Waiting status..."
tools:visibility="visible" />

</LinearLayout>

<ProgressBar
android:id="@+id/waiting_view_status_horizontal_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginTop="10dp"
android:visibility="gone"
tools:max="100"
tools:progress="30"
tools:visibility="visible" />

</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>


</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -15,6 +15,8 @@
android:id="@+id/homeDetailFragmentContainer" android:id="@+id/homeDetailFragmentContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />

<include layout="@layout/merge_overlay_waiting_view" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>




@ -24,4 +26,5 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="start" /> android:layout_gravity="start" />



</androidx.drawerlayout.widget.DrawerLayout> </androidx.drawerlayout.widget.DrawerLayout>

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/waiting_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?vctr_waiting_background_color"
android:visibility="gone"
tools:visibility="visible">

<LinearLayout
android:id="@+id/waiting_view_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/layout_horizontal_margin"
android:background="?attr/colorBackgroundFloating"
android:orientation="vertical"
android:padding="@dimen/layout_horizontal_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="@dimen/dialog_width_ratio">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">

<ProgressBar
android:id="@+id/waiting_view_status_circular_progress"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="6dp"
android:layout_marginRight="6dp" />

<TextView
android:id="@+id/waiting_view_status_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="?riotx_text_secondary"
android:visibility="gone"
tools:text="Waiting status..."
tools:visibility="visible" />

</LinearLayout>

<ProgressBar
android:id="@+id/waiting_view_status_horizontal_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginTop="10dp"
android:visibility="gone"
tools:max="100"
tools:progress="30"
tools:visibility="visible" />

</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

</merge>