Improved performance when multiple FS changes occur in a fraction of a second
Between update there is a minimum of 0.5s even if there have been multiple file updates
This commit is contained in:
parent
41ff6a57b8
commit
afc7d9df8e
3 changed files with 50 additions and 18 deletions
|
@ -87,7 +87,7 @@ class DiffManager @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun prepareTreeParser(repository: Repository, commit: RevCommit): AbstractTreeIterator? {
|
||||
fun prepareTreeParser(repository: Repository, commit: RevCommit): AbstractTreeIterator {
|
||||
// from the commit we can build the tree which allows us to construct the TreeParser
|
||||
RevWalk(repository).use { walk ->
|
||||
val tree: RevTree = walk.parseTree(commit.tree.id)
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
package app.git
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import java.io.IOException
|
||||
import java.nio.file.*
|
||||
import java.nio.file.StandardWatchEventKinds.*
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val MIN_TIME_IN_MS_BETWEEN_REFRESHES = 500L
|
||||
|
||||
class FileChangesWatcher @Inject constructor() {
|
||||
suspend fun watchDirectoryPath(pathStr: String, ignoredDirsPath: List<String>) = flow {
|
||||
private var lastNotify = 0L
|
||||
private var asyncJob: Job? = null
|
||||
|
||||
private val _changesNotifier = MutableSharedFlow<Long>()
|
||||
val changesNotifier: SharedFlow<Long> = _changesNotifier
|
||||
|
||||
suspend fun watchDirectoryPath(pathStr: String, ignoredDirsPath: List<String>) = withContext(Dispatchers.IO) {
|
||||
println(ignoredDirsPath)
|
||||
|
||||
val watchService = FileSystems.getDefault().newWatchService()
|
||||
|
||||
val path = Paths.get(pathStr)
|
||||
|
@ -40,10 +49,33 @@ class FileChangesWatcher @Inject constructor() {
|
|||
|
||||
var key: WatchKey
|
||||
while (watchService.take().also { key = it } != null) {
|
||||
this.emit(Unit)
|
||||
key.pollEvents()
|
||||
|
||||
println("Polled events")
|
||||
|
||||
asyncJob?.cancel()
|
||||
|
||||
// Sometimes external apps can run filesystem multiple operations in a fraction of a second.
|
||||
// To prevent excessive updates, we add a slight delay between updates emission to prevent slowing down
|
||||
// the app by constantly running "git status".
|
||||
val currentTimeMillis = System.currentTimeMillis()
|
||||
val diffTime = currentTimeMillis - lastNotify
|
||||
|
||||
if (diffTime > MIN_TIME_IN_MS_BETWEEN_REFRESHES) {
|
||||
_changesNotifier.emit(currentTimeMillis)
|
||||
println("Sync emit with diff time $diffTime")
|
||||
} else {
|
||||
asyncJob = async {
|
||||
delay(MIN_TIME_IN_MS_BETWEEN_REFRESHES)
|
||||
println("Async emit")
|
||||
if (isActive)
|
||||
_changesNotifier.emit(currentTimeMillis)
|
||||
}
|
||||
}
|
||||
|
||||
lastNotify = currentTimeMillis
|
||||
|
||||
key.reset()
|
||||
}
|
||||
}.flowOn(Dispatchers.IO)
|
||||
|
||||
}
|
||||
}
|
|
@ -7,13 +7,10 @@ import app.credentials.CredentialsStateManager
|
|||
import app.git.*
|
||||
import app.newErrorNow
|
||||
import app.ui.SelectedItem
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.lib.ObjectId
|
||||
import org.eclipse.jgit.lib.Repository
|
||||
|
@ -148,15 +145,18 @@ class TabViewModel @Inject constructor(
|
|||
private suspend fun watchRepositoryChanges(git: Git) = tabState.managerScope.launch(Dispatchers.IO) {
|
||||
val ignored = git.status().call().ignoredNotInIndex.toList()
|
||||
|
||||
launch {
|
||||
fileChangesWatcher.changesNotifier.collect {
|
||||
if (!tabState.operationRunning) { // Only update if there isn't any process running
|
||||
println("Changes detected, loading status")
|
||||
checkUncommitedChanges()
|
||||
}
|
||||
}
|
||||
}
|
||||
fileChangesWatcher.watchDirectoryPath(
|
||||
pathStr = git.repository.directory.parent,
|
||||
ignoredDirsPath = ignored,
|
||||
).collect {
|
||||
if (!tabState.operationRunning) { // Only update if there isn't any process running
|
||||
println("Changes detected, loading status")
|
||||
checkUncommitedChanges()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun checkUncommitedChanges(fullUpdateLog: Boolean = false) = tabState.runOperation(
|
||||
|
|
Loading…
Reference in a new issue