Reduce DownloadManager initialization time
This commit is contained in:
1 parent
cf10e2ff6d
commit
779dd1f8fd
2 files changed
+101
-55
No files matched your search
@@ -22,8 +22,11 @@ import androidx.compose.runtime.DisallowComposableCalls
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.core.util.size
|
||||
import arrow.fx.coroutines.parMapNotNull
|
||||
import com.ehviewer.core.data.model.asEntity
|
||||
@@ -72,9 +75,7 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
override val coroutineContext = Dispatchers.IO + Job()
|
||||
|
||||
// All download info list
|
||||
private val allInfoList = runAssertingNotMainThread {
|
||||
(EhDB.getAllDownloadInfo() as MutableList).apply { sortWith(comparator()) }
|
||||
}
|
||||
private val allInfoList = runAssertingNotMainThread { EhDB.getAllDownloadInfo() as MutableList }
|
||||
|
||||
val downloadInfoList: List<DownloadInfo>
|
||||
get() = allInfoList
|
||||
@@ -99,6 +100,21 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
||||
private val sortMutex = Mutex()
|
||||
private val sortMode
|
||||
get() = SortMode.from(Settings.downloadSortMode.value)
|
||||
|
||||
var isInitialized by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
init {
|
||||
launch {
|
||||
val mode = sortMode
|
||||
if (mode != SortMode.Default) sortDownloads(mode)
|
||||
isInitialized = true
|
||||
}
|
||||
}
|
||||
|
||||
fun containLabel(label: String?): Boolean {
|
||||
if (label == null) {
|
||||
return false
|
||||
@@ -184,7 +200,9 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
info.label = label
|
||||
info.state = DownloadInfo.STATE_WAIT
|
||||
// Add to all download list and map
|
||||
allInfoList.insertWith(info, comparator())
|
||||
sortMutex.withLock {
|
||||
allInfoList.insertWith(info, sortMode.comparator())
|
||||
}
|
||||
mAllInfoMap[galleryInfo.gid] = info
|
||||
|
||||
// Add to wait list
|
||||
@@ -241,10 +259,12 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
}.collectAsState(transform(info)).value
|
||||
|
||||
suspend fun startAllDownload() {
|
||||
val updateList = allInfoList.filter {
|
||||
when (it.state) {
|
||||
DownloadInfo.STATE_NONE, DownloadInfo.STATE_FAILED -> true
|
||||
else -> false
|
||||
val updateList = sortMutex.withLock {
|
||||
allInfoList.filter {
|
||||
when (it.state) {
|
||||
DownloadInfo.STATE_NONE, DownloadInfo.STATE_FAILED -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updateList.isNotEmpty()) {
|
||||
@@ -258,8 +278,8 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun addDownload(downloadInfoList: List<DownloadInfo>) {
|
||||
val comparator = comparator()
|
||||
suspend fun addDownload(downloadInfoList: List<DownloadInfo>) = sortMutex.withLock {
|
||||
val comparator = sortMode.comparator()
|
||||
downloadInfoList.forEach { info ->
|
||||
if (containDownloadInfo(info.gid)) return@forEach
|
||||
|
||||
@@ -293,7 +313,9 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
info.state = DownloadInfo.STATE_NONE
|
||||
|
||||
// Add to all download list and map
|
||||
allInfoList.insertWith(info, comparator())
|
||||
sortMutex.withLock {
|
||||
allInfoList.insertWith(info, sortMode.comparator())
|
||||
}
|
||||
mAllInfoMap[galleryInfo.gid] = info
|
||||
|
||||
// Save to
|
||||
@@ -352,7 +374,9 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
EhDB.removeDownloadInfo(info)
|
||||
|
||||
// Remove all list and map
|
||||
allInfoList.remove(info)
|
||||
sortMutex.withLock {
|
||||
allInfoList.remove(info)
|
||||
}
|
||||
mAllInfoMap.remove(info.gid)
|
||||
|
||||
// Update listener
|
||||
@@ -375,7 +399,9 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
mAllInfoMap.remove(gid)
|
||||
}
|
||||
EhDB.removeDownloadInfo(list)
|
||||
allInfoList.removeAll(list.toSet())
|
||||
sortMutex.withLock {
|
||||
allInfoList.removeAll(list.toSet())
|
||||
}
|
||||
|
||||
// Update listener
|
||||
list.forEach { mutableNotifyFlow.emit(it) }
|
||||
@@ -384,7 +410,7 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
ensureDownload()
|
||||
}
|
||||
|
||||
fun sortDownloads(mode: SortMode) {
|
||||
suspend fun sortDownloads(mode: SortMode) = sortMutex.withLock {
|
||||
allInfoList.sortWith(mode.comparator())
|
||||
}
|
||||
|
||||
@@ -503,9 +529,11 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
val new = exist.copy(label = to)
|
||||
labelList.add(index, new)
|
||||
EhDB.updateDownloadLabel(new)
|
||||
allInfoList.forEach {
|
||||
if (it.label == from) {
|
||||
it.label = to
|
||||
sortMutex.withLock {
|
||||
allInfoList.forEach {
|
||||
if (it.label == from) {
|
||||
it.label = to
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -521,21 +549,25 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
}
|
||||
removeAt(index)
|
||||
}
|
||||
allInfoList.forEach {
|
||||
if (it.label == label) {
|
||||
it.label = null
|
||||
sortMutex.withLock {
|
||||
allInfoList.forEach {
|
||||
if (it.label == label) {
|
||||
it.label = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun readMetadataFromLocal() {
|
||||
val list = allInfoList.mapNotNull {
|
||||
val updateGallery = it.pages == 0 || it.simpleTags == null
|
||||
val updateArtist = it.artistInfoList.isEmpty()
|
||||
if (updateGallery || updateArtist) {
|
||||
Triple(it, updateGallery, updateArtist)
|
||||
} else {
|
||||
null
|
||||
val list = sortMutex.withLock {
|
||||
allInfoList.mapNotNull {
|
||||
val updateGallery = it.pages == 0 || it.simpleTags == null
|
||||
val updateArtist = it.artistInfoList.isEmpty()
|
||||
if (updateGallery || updateArtist) {
|
||||
Triple(it, updateGallery, updateArtist)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}.parMapNotNull(concurrency = 5) { (info, updateGallery, updateArtist) ->
|
||||
info.downloadDir?.run {
|
||||
@@ -785,8 +817,6 @@ object DownloadManager : OnSpiderListener, CoroutineScope {
|
||||
}
|
||||
|
||||
private const val TAG = "DownloadManager"
|
||||
|
||||
private fun comparator() = SortMode.from(Settings.downloadSortMode.value).comparator()
|
||||
}
|
||||
|
||||
var downloadLocation: Path
|
||||
|
||||
@@ -5,8 +5,10 @@ import android.view.ViewConfiguration
|
||||
import androidx.compose.animation.AnimatedVisibilityScope
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -43,6 +45,7 @@ import androidx.compose.material.icons.filled.Reorder
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.Shuffle
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularWavyProgressIndicator
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -93,7 +96,6 @@ import com.ehviewer.core.ui.component.LocalSideSheetState
|
||||
import com.ehviewer.core.ui.component.ProvideSideSheetContent
|
||||
import com.ehviewer.core.ui.icons.EhIcons
|
||||
import com.ehviewer.core.ui.icons.big.Download
|
||||
import com.ehviewer.core.ui.util.Await
|
||||
import com.ehviewer.core.ui.util.HapticFeedbackType
|
||||
import com.ehviewer.core.ui.util.asyncState
|
||||
import com.ehviewer.core.ui.util.ifTrueThen
|
||||
@@ -113,7 +115,6 @@ import com.hippo.ehviewer.asMutableState
|
||||
import com.hippo.ehviewer.client.EhTagDatabase
|
||||
import com.hippo.ehviewer.collectAsState
|
||||
import com.hippo.ehviewer.download.DownloadManager
|
||||
import com.hippo.ehviewer.download.DownloadManager.downloadInfoList
|
||||
import com.hippo.ehviewer.download.DownloadService
|
||||
import com.hippo.ehviewer.download.DownloadsFilterMode
|
||||
import com.hippo.ehviewer.download.SortMode
|
||||
@@ -148,6 +149,7 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
|
||||
val filterMode by Settings.downloadFilterMode.collectAsState { DownloadsFilterMode.from(it) }
|
||||
var filterState by rememberSerializable { mutableStateOf(DownloadsFilterState(filterMode, Settings.recentDownloadLabel.value)) }
|
||||
var invalidateKey by rememberSaveable { mutableStateOf(false) }
|
||||
var isLoading by rememberSaveable { mutableStateOf(true) }
|
||||
var searchBarExpanded by rememberSaveable { mutableStateOf(false) }
|
||||
var searchBarOffsetY by remember { mutableIntStateOf(0) }
|
||||
val animateItems by Settings.animateItems.collectAsState()
|
||||
@@ -183,10 +185,19 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
|
||||
},
|
||||
)
|
||||
val hint = stringResource(R.string.search_bar_hint, title)
|
||||
val list = remember(filterState, invalidateKey) {
|
||||
downloadInfoList.filterTo(mutableStateListOf()) { info ->
|
||||
filterState.take(info)
|
||||
val list = if (DownloadManager.isInitialized) {
|
||||
remember(filterState, invalidateKey) {
|
||||
DownloadManager.downloadInfoList.filterTo(mutableStateListOf()) { info ->
|
||||
filterState.take(info)
|
||||
}.also {
|
||||
launch {
|
||||
delay(200)
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
remember { mutableStateListOf() }
|
||||
}
|
||||
|
||||
val newLabel = stringResource(R.string.new_label_title)
|
||||
@@ -632,24 +643,26 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
|
||||
}
|
||||
}
|
||||
|
||||
Await({ delay(200) }) {
|
||||
if (list.isEmpty()) {
|
||||
Column(
|
||||
modifier = Modifier.padding(realPadding).fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = EhIcons.Big.Default.Download,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(16.dp),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = R.string.no_download_info),
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
)
|
||||
}
|
||||
if (isLoading) {
|
||||
Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface), contentAlignment = Alignment.Center) {
|
||||
CircularWavyProgressIndicator()
|
||||
}
|
||||
} else if (list.isEmpty()) {
|
||||
Column(
|
||||
modifier = Modifier.padding(realPadding).fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = EhIcons.Big.Default.Download,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(16.dp),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = R.string.no_download_info),
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -689,9 +702,12 @@ fun AnimatedVisibilityScope.DownloadsScreen(navigator: DestinationsNavigator) =
|
||||
oldMode.groupByDownloadLabel,
|
||||
)
|
||||
val mode = SortMode.All[selected].copy(groupByDownloadLabel = checked)
|
||||
DownloadManager.sortDownloads(mode)
|
||||
sortMode = mode.flag
|
||||
invalidateKey = !invalidateKey
|
||||
if (mode != oldMode) {
|
||||
sortMode = mode.flag
|
||||
isLoading = true
|
||||
DownloadManager.sortDownloads(mode)
|
||||
invalidateKey = !invalidateKey
|
||||
}
|
||||
}
|
||||
onClick(Icons.Default.FilterList) {
|
||||
val downloadStates = contextOf<Context>().resources.getStringArray(com.hippo.ehviewer.R.array.download_state).toList()
|
||||
|
||||
Reference in new issue
Block a user