Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latest page progress indicator #678

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/kotlin/com/machiav3lli/fdroid/NeoActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,6 @@ class NeoActivity : AppCompatActivity() {
}

val viewModelsModule = module {
viewModel { MainVM(get()) }
viewModel { MainVM(get(), get()) }
viewModel { PrefsVM(get()) }
}
271 changes: 144 additions & 127 deletions src/main/kotlin/com/machiav3lli/fdroid/pages/LatestPage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package com.machiav3lli.fdroid.pages

import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SheetValue
Expand Down Expand Up @@ -56,6 +58,7 @@ fun LatestPage(viewModel: MainVM) {
val neoActivity = context as NeoActivity
val scope = rememberCoroutineScope()

val sync by viewModel.sync.collectAsState(false)
val installedList by viewModel.installed.collectAsState(emptyMap())
val secondaryList by viewModel.newProdsLatest.collectAsState(emptyList())
val primaryList by viewModel.updatedProdsLatest.collectAsState(emptyList())
Expand Down Expand Up @@ -135,153 +138,167 @@ fun LatestPage(viewModel: MainVM) {
}
}
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
if (!Preferences[Preferences.Key.HideNewApps]) item {
Row(
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(id = R.string.new_applications),
modifier = Modifier.weight(1f),
)
}
}
if (!Preferences[Preferences.Key.HideNewApps]) item {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
if (Preferences[Preferences.Key.AltNewApps]) {
ProductsHorizontalRecycler(
if (sync) {
LoadingWidget()
} else {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
if (!Preferences[Preferences.Key.HideNewApps]) item {
Row(
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(id = R.string.new_applications),
modifier = Modifier.weight(1f),
productsList = secondaryList,
repositories = repositoriesMap,
) { item ->
neoActivity.navigateProduct(item.packageName)
}
} else {
ProductsCarousel(
modifier = Modifier.weight(1f),
productsList = secondaryList,
repositories = repositoriesMap,
favorites = favorites,
onFavouriteClick = {
viewModel.setFavorite(
it.packageName,
!favorites.contains(it.packageName)
)
},
onActionClick = { item, action ->
val installed = installedList[item.packageName]
val installFun = { MainApplication.wm.install(item) }
)
}
}
if (!Preferences[Preferences.Key.HideNewApps]) item {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
if (Preferences[Preferences.Key.AltNewApps]) {
ProductsHorizontalRecycler(
modifier = Modifier.weight(1f),
productsList = secondaryList,
repositories = repositoriesMap,
) { item ->
neoActivity.navigateProduct(item.packageName)
}
} else {
ProductsCarousel(
modifier = Modifier.weight(1f),
productsList = secondaryList,
repositories = repositoriesMap,
favorites = favorites,
onFavouriteClick = {
viewModel.setFavorite(
it.packageName,
!favorites.contains(it.packageName)
)
},
onActionClick = { item, action ->
val installed = installedList[item.packageName]
val installFun = { MainApplication.wm.install(item) }

when (action) {
is ActionState.Install -> {
if (Preferences[Preferences.Key.DownloadShowDialog]) {
dialogKey.value =
DialogKey.Download(item.name, installFun)
openDialog.value = true
} else installFun()
}
when (action) {
is ActionState.Install -> {
if (Preferences[Preferences.Key.DownloadShowDialog]) {
dialogKey.value =
DialogKey.Download(item.name, installFun)
openDialog.value = true
} else installFun()
}

is ActionState.Launch -> installed?.let {
context.onLaunchClick(
it,
neoActivity.supportFragmentManager
)
}
is ActionState.Launch -> installed?.let {
context.onLaunchClick(
it,
neoActivity.supportFragmentManager
)
}

else -> {}
}
},
onUserClick = { item ->
neoActivity.navigateProduct(item.packageName)
},
)
else -> {}
}
},
onUserClick = { item ->
neoActivity.navigateProduct(item.packageName)
},
)
}
}
}
}
item {
Row(
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(id = R.string.recently_updated),
modifier = Modifier.weight(1f),
)
SortFilterChip(notModified = notModifiedSortFilter) {
scope.launch {
scaffoldState.bottomSheetState.expand()
item {
Row(
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(id = R.string.recently_updated),
modifier = Modifier.weight(1f),
)
SortFilterChip(notModified = notModifiedSortFilter) {
scope.launch {
scaffoldState.bottomSheetState.expand()
}
}
}
}
}
items(
items = primaryList,
key = { it.packageName },
) { item ->
ProductsListItem(
item = item,
repo = repositoriesMap[item.repositoryId],
isFavorite = favorites.contains(item.packageName),
onUserClick = {
neoActivity.navigateProduct(it.packageName)
},
onFavouriteClick = {
viewModel.setFavorite(
it.packageName,
!favorites.contains(it.packageName)
)
},
installed = installedList[item.packageName],
onActionClick = {
val installed = installedList[it.packageName]
val action = { MainApplication.wm.install(it) }
if (installed != null && installed.launcherActivities.isNotEmpty())
context.onLaunchClick(
installed,
neoActivity.supportFragmentManager
items(
items = primaryList,
key = { it.packageName },
) { item ->
ProductsListItem(
item = item,
repo = repositoriesMap[item.repositoryId],
isFavorite = favorites.contains(item.packageName),
onUserClick = {
neoActivity.navigateProduct(it.packageName)
},
onFavouriteClick = {
viewModel.setFavorite(
it.packageName,
!favorites.contains(it.packageName)
)
else if (Preferences[Preferences.Key.DownloadShowDialog]) {
dialogKey.value = DialogKey.Download(it.name, action)
openDialog.value = true
} else action()
}
)
},
installed = installedList[item.packageName],
onActionClick = {
val installed = installedList[it.packageName]
val action = { MainApplication.wm.install(it) }
if (installed != null && installed.launcherActivities.isNotEmpty())
context.onLaunchClick(
installed,
neoActivity.supportFragmentManager
)
else if (Preferences[Preferences.Key.DownloadShowDialog]) {
dialogKey.value = DialogKey.Download(it.name, action)
openDialog.value = true
} else action()
}
)
}
}
}
}

if (openDialog.value) {
BaseDialog(openDialogCustom = openDialog) {
when (dialogKey.value) {
is DialogKey.Download -> KeyDialogUI(
key = dialogKey.value,
openDialog = openDialog,
primaryAction = {
if (Preferences[Preferences.Key.ActionLockDialog] != Preferences.ActionLock.None)
neoActivity.launchLockPrompt {
if (openDialog.value) {
BaseDialog(openDialogCustom = openDialog) {
when (dialogKey.value) {
is DialogKey.Download -> KeyDialogUI(
key = dialogKey.value,
openDialog = openDialog,
primaryAction = {
if (Preferences[Preferences.Key.ActionLockDialog] != Preferences.ActionLock.None)
neoActivity.launchLockPrompt {
(dialogKey.value as DialogKey.Download).action()
openDialog.value = false
}
else {
(dialogKey.value as DialogKey.Download).action()
openDialog.value = false
}
else {
(dialogKey.value as DialogKey.Download).action()
},
onDismiss = {
dialogKey.value = null
openDialog.value = false
}
},
onDismiss = {
dialogKey.value = null
openDialog.value = false
}
)
)

else -> {}
else -> {}
}
}
}
}
}

@Composable
private fun LoadingWidget() {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize()
) {
CircularProgressIndicator()
}
}
13 changes: 13 additions & 0 deletions src/main/kotlin/com/machiav3lli/fdroid/service/WorkerManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,11 @@ import com.machiav3lli.fdroid.utility.updateProgress
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
Expand Down Expand Up @@ -106,6 +108,16 @@ class WorkerManager(appContext: Context) : KoinComponent {
}
}

val repositorySyncWorkersFlow: Flow<List<WorkInfo>> get() {
return workManager.getWorkInfosByTagFlow(SyncWorker::class.qualifiedName.orEmpty())
.map { syncWorkerList ->
syncWorkerList.filter { workInfo ->
val task = SyncWorker.getTask(workInfo.progress)
task.repositoryId != NON_EXISTENT_REPOSITORY_ID
}
}
}

fun release(): WorkerManager? {
context.unregisterReceiver(actionReceiver)
return null
Expand Down Expand Up @@ -245,6 +257,7 @@ class WorkerManager(appContext: Context) : KoinComponent {
}

companion object {
private const val NON_EXISTENT_REPOSITORY_ID = -1L
private val syncsRunning = SnapshotStateMap<Long, SyncState?>()
private val downloadsRunning = SnapshotStateMap<String, DownloadState>()

Expand Down
13 changes: 12 additions & 1 deletion src/main/kotlin/com/machiav3lli/fdroid/viewmodels/MainVM.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.machiav3lli.fdroid.entity.Page
import com.machiav3lli.fdroid.entity.ProductItem
import com.machiav3lli.fdroid.entity.Request
import com.machiav3lli.fdroid.entity.Source
import com.machiav3lli.fdroid.service.WorkerManager
import com.machiav3lli.fdroid.utility.matchSearchQuery
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
Expand All @@ -37,7 +38,10 @@ import kotlinx.coroutines.withContext
ExperimentalCoroutinesApi::class,
FlowPreview::class,
)
open class MainVM(val db: DatabaseX) : ViewModel() {
open class MainVM(
private val workerManager: WorkerManager,
val db: DatabaseX
) : ViewModel() {
private val cc = Dispatchers.IO
private val ioScope = viewModelScope.plus(Dispatchers.IO)

Expand Down Expand Up @@ -69,6 +73,13 @@ open class MainVM(val db: DatabaseX) : ViewModel() {
Source.NONE -> Request.None
}

val sync: Flow<Boolean> = combine(
db.getProductDao().queryFlowList(Request.Updated),
workerManager.repositorySyncWorkersFlow
) { productList, workerList ->
productList.isEmpty() && workerList.isNotEmpty()
}

val repositories = db.getRepositoryDao().getAllFlow().distinctUntilChanged()

val categories = db.getCategoryDao().getAllNamesFlow().distinctUntilChanged()
Expand Down