Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,24 @@ fun SettingsScreen(
}
}

item {
SwitchSettingItem(
title = stringResource(R.string.download_stats),
description = stringResource(R.string.download_statistics_summary),
checked = settings.dlStatsEnabled,
onCheckedChange = viewModel::setDownloadStatisticsEnabled,
)
}

item {
SwitchSettingItem(
title = stringResource(R.string.reproducibility_logs),
description = stringResource(R.string.reproducibility_logs_summary),
checked = settings.rbLogsEnabled,
onCheckedChange = viewModel::setReproducibilityLogsEnabled,
)
}

item { SettingHeader(title = stringResource(R.string.install_types)) }

item {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.looker.droidify.BuildConfig
import com.looker.droidify.R
import com.looker.droidify.data.PrivacyRepository
import com.looker.droidify.data.StringHandler
import com.looker.droidify.database.Database
import com.looker.droidify.database.RepositoryExporter
Expand Down Expand Up @@ -45,6 +46,7 @@ import kotlinx.coroutines.launch
@HiltViewModel
class SettingsViewModel @Inject constructor(
private val settingsRepository: SettingsRepository,
private val privacyRepository: PrivacyRepository,
private val repositoryExporter: RepositoryExporter,
private val customButtonRepository: CustomButtonRepository,
private val handler: StringHandler,
Expand Down Expand Up @@ -188,6 +190,24 @@ class SettingsViewModel @Inject constructor(
}
}

fun setDownloadStatisticsEnabled(enabled: Boolean) {
viewModelScope.launch {
settingsRepository.setDownloadStatisticsEnabled(enabled)
if (!enabled) {
privacyRepository.clearDownloadStats()
}
}
}

fun setReproducibilityLogsEnabled(enabled: Boolean) {
viewModelScope.launch {
settingsRepository.setRBLogsEnabled(enabled)
if (!enabled) {
privacyRepository.clearRbLogs()
}
}
}

fun setProxyType(proxyType: ProxyType) {
viewModelScope.launch {
settingsRepository.setProxyType(proxyType)
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/kotlin/com/looker/droidify/data/PrivacyRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,14 @@ class PrivacyRepository(
suspend fun save(downloadStats: List<DownloadStats>) {
downloadStatsDao.insert(downloadStats)
}

suspend fun clearDownloadStats() {
downloadStatsDao.deleteAll()
settingsRepo.clearDownloadStatsLastModified()
}

suspend fun clearRbLogs() {
rbDao.deleteAll()
settingsRepo.clearRbLogLastModified()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@ interface DownloadStatsDao {

@Insert(onConflict = REPLACE)
suspend fun insert(stats: List<DownloadStats>)

@Query("DELETE FROM download_stats")
suspend fun deleteAll()
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ interface RBLogDao {

@Query("SELECT * FROM rblog WHERE packageName = :packageName")
fun getFlow(packageName: String): Flow<List<RBLogEntity>>

@Query("DELETE FROM rblog")
suspend fun deleteAll()
}
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,24 @@ class PreferenceSettingsRepository(
override suspend fun setDeleteApkOnInstall(enable: Boolean) =
DELETE_APK_ON_INSTALL.update(enable)

override suspend fun setDownloadStatisticsEnabled(enabled: Boolean) =
DOWNLOAD_STATISTICS_ENABLED.update(enabled)

override suspend fun clearDownloadStatsLastModified() {
dataStore.edit { pref ->
pref.remove(LAST_MODIFIED_DS)
}
}

override suspend fun setRBLogsEnabled(enabled: Boolean) =
REPRODUCIBILITY_LOGS_ENABLED.update(enabled)

override suspend fun clearRbLogLastModified() {
dataStore.edit { pref ->
pref.remove(LAST_RB_FETCH)
}
}

private fun mapSettings(preferences: Preferences): Settings {
val installerType =
InstallerType.valueOf(preferences[INSTALLER_TYPE] ?: InstallerType.Default.name)
Expand Down Expand Up @@ -228,6 +246,8 @@ class PreferenceSettingsRepository(
val enabledRepoIds =
preferences[ENABLED_REPO_IDS]?.mapNotNull { it.toIntOrNull() }?.toSet() ?: emptySet()
val deleteApkOnInstall = preferences[DELETE_APK_ON_INSTALL] ?: false
val downloadStatisticsEnabled = preferences[DOWNLOAD_STATISTICS_ENABLED] ?: true
val reproducibilityLogsEnabled = preferences[REPRODUCIBILITY_LOGS_ENABLED] ?: true

return Settings(
language = language,
Expand All @@ -251,6 +271,8 @@ class PreferenceSettingsRepository(
homeScreenSwiping = homeScreenSwiping,
enabledRepoIds = enabledRepoIds,
deleteApkOnInstall = deleteApkOnInstall,
dlStatsEnabled = downloadStatisticsEnabled,
rbLogsEnabled = reproducibilityLogsEnabled,
)
}

Expand All @@ -277,6 +299,8 @@ class PreferenceSettingsRepository(
val FAVOURITE_APPS = stringSetPreferencesKey("key_favourite_apps")
val HOME_SCREEN_SWIPING = booleanPreferencesKey("key_home_swiping")
val DELETE_APK_ON_INSTALL = booleanPreferencesKey("key_delete_apk_on_install")
val DOWNLOAD_STATISTICS_ENABLED = booleanPreferencesKey("key_download_statistics_enabled")
val REPRODUCIBILITY_LOGS_ENABLED = booleanPreferencesKey("key_reproducibility_logs_enabled")
val LEGACY_INSTALLER_COMPONENT_CLASS =
stringPreferencesKey("key_legacy_installer_component_class")
val LEGACY_INSTALLER_COMPONENT_ACTIVITY =
Expand Down Expand Up @@ -338,6 +362,8 @@ class PreferenceSettingsRepository(
set(HOME_SCREEN_SWIPING, settings.homeScreenSwiping)
set(ENABLED_REPO_IDS, settings.enabledRepoIds.map { it.toString() }.toSet())
set(DELETE_APK_ON_INSTALL, settings.deleteApkOnInstall)
set(DOWNLOAD_STATISTICS_ENABLED, settings.dlStatsEnabled)
set(REPRODUCIBILITY_LOGS_ENABLED, settings.rbLogsEnabled)
return this.toPreferences()
}
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/kotlin/com/looker/droidify/datastore/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ data class Settings(
val homeScreenSwiping: Boolean = true,
val enabledRepoIds: Set<Int> = emptySet(),
val deleteApkOnInstall: Boolean = false,
val dlStatsEnabled: Boolean = true,
val rbLogsEnabled: Boolean = true,
)

@OptIn(ExperimentalSerializationApi::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ interface SettingsRepository {
suspend fun isRepoEnabled(repoId: Int): Boolean

suspend fun setDeleteApkOnInstall(enable: Boolean)

suspend fun setDownloadStatisticsEnabled(enabled: Boolean)

suspend fun clearDownloadStatsLastModified()

suspend fun setRBLogsEnabled(enabled: Boolean)

suspend fun clearRbLogLastModified()
}

inline fun <T> SettingsRepository.get(crossinline block: suspend Settings.() -> T): Flow<T> {
Expand Down
62 changes: 29 additions & 33 deletions app/src/main/kotlin/com/looker/droidify/service/SyncService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.fragment.app.Fragment
import com.looker.droidify.BuildConfig
import com.looker.droidify.R
import com.looker.droidify.database.Database
import com.looker.droidify.datastore.Settings
import com.looker.droidify.datastore.SettingsRepository
import com.looker.droidify.index.RepositoryUpdater
import com.looker.droidify.model.ProductItem
Expand Down Expand Up @@ -51,6 +52,7 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
Expand Down Expand Up @@ -129,7 +131,7 @@ class SyncService : ConnectionService<SyncService.Binder>() {
val state: SharedFlow<State>
get() = syncState.asSharedFlow()

private fun sync(ids: List<Long>, request: SyncRequest) {
private fun sync(ids: List<Long>, request: SyncRequest, settings: Settings) {
val cancelledTask =
cancelCurrentTask { request == SyncRequest.FORCE && it.task?.repositoryId in ids }
cancelTasks { !it.manual && it.repositoryId in ids }
Expand All @@ -139,7 +141,7 @@ class SyncService : ConnectionService<SyncService.Binder>() {
it !in currentIds &&
it != currentTask?.task?.repositoryId
}.map { Task(it, manual) }
handleNextTask(cancelledTask?.hasUpdates == true)
handleNextTask(cancelledTask?.hasUpdates == true, settings)
if (request != SyncRequest.AUTO && started == Started.AUTO) {
started = Started.MANUAL
startServiceCompat()
Expand All @@ -149,19 +151,21 @@ class SyncService : ConnectionService<SyncService.Binder>() {
}

fun sync(request: SyncRequest) {
RBLogWorker.fetchRBLogs(applicationContext)
DownloadStatsWorker.fetchDownloadStats(applicationContext)
val settings = runBlocking { settingsRepository.getInitial() }
if (settings.rbLogsEnabled) RBLogWorker.fetchRBLogs(applicationContext)
if (settings.dlStatsEnabled) DownloadStatsWorker.fetchDownloadStats(applicationContext)

val ids = Database.RepositoryAdapter.getAll()
.filter { it.enabled }
.map { it.id }

sync(ids, request)
sync(ids, request, settings)
}

fun sync(repository: Repository) {
val settings = runBlocking { settingsRepository.getInitial() }
if (repository.enabled) {
sync(listOf(repository.id), SyncRequest.FORCE)
sync(listOf(repository.id), SyncRequest.FORCE, settings)
}
}

Expand All @@ -180,19 +184,20 @@ class SyncService : ConnectionService<SyncService.Binder>() {

fun setEnabled(repository: Repository, enabled: Boolean): Boolean {
Database.RepositoryAdapter.put(repository.enable(enabled))
val settings = runBlocking { settingsRepository.getInitial() }
if (enabled) {
val isRepoInTasks = repository.id != currentTask?.task?.repositoryId &&
!tasks.any { it.repositoryId == repository.id }
if (isRepoInTasks) {
tasks += Task(repository.id, true)
handleNextTask(false)
handleNextTask(false, settings)
}
} else {
cancelTasks { it.repositoryId == repository.id }
val cancelledTask = cancelCurrentTask {
it.task?.repositoryId == repository.id
}
handleNextTask(cancelledTask?.hasUpdates == true)
handleNextTask(cancelledTask?.hasUpdates == true, settings)
}
return true
}
Expand All @@ -211,9 +216,10 @@ class SyncService : ConnectionService<SyncService.Binder>() {
}

fun cancelAuto(): Boolean {
val settings = runBlocking { settingsRepository.getInitial() }
val removed = cancelTasks { !it.manual }
val currentTask = cancelCurrentTask { it.task?.manual == false }
handleNextTask(currentTask?.hasUpdates == true)
handleNextTask(currentTask?.hasUpdates == true, settings)
return removed || currentTask != null
}
}
Expand Down Expand Up @@ -258,10 +264,11 @@ class SyncService : ConnectionService<SyncService.Binder>() {
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val settings = runBlocking { settingsRepository.getInitial() }
if (intent?.action == ACTION_CANCEL) {
tasks.clear()
val cancelledTask = cancelCurrentTask { it.task != null }
handleNextTask(cancelledTask?.hasUpdates == true)
handleNextTask(cancelledTask?.hasUpdates == true, settings)
stopSelf()
} else {
startForeground(
Expand Down Expand Up @@ -460,24 +467,19 @@ class SyncService : ConnectionService<SyncService.Binder>() {
stateNotificationBuilder.setWhen(System.currentTimeMillis())
}

private fun handleNextTask(isIndexModified: Boolean) {
private fun handleNextTask(isIndexModified: Boolean, settings: Settings) {
if (currentTask != null) return
if (tasks.isEmpty()) {
if (started != Started.NO) {
lifecycleScope.launch {
val setting = settingsRepository.getInitial()
handleUpdates(
notifyUpdates = setting.notifyUpdate,
autoUpdate = setting.autoUpdate,
skipSignature = setting.ignoreSignature,
)
handleUpdates(settings)
}
}
return
}
val task = tasks.removeAt(0)
val repository = Database.RepositoryAdapter.get(task.repositoryId)
if (repository == null || !repository.enabled) handleNextTask(isIndexModified)
if (repository == null || !repository.enabled) handleNextTask(isIndexModified, settings)
val lastStarted = started
val newStarted = if (task.manual || lastStarted == Started.MANUAL) {
Started.MANUAL
Expand All @@ -492,13 +494,11 @@ class SyncService : ConnectionService<SyncService.Binder>() {
val initialState = State.Connecting(repository!!.name)
publishForegroundState(true, initialState)
lifecycleScope.launch {
val unstableUpdates =
settingsRepository.getInitial().unstableUpdate
val downloadJob = downloadFile(
task = task,
repository = repository,
isIndexModified = isIndexModified,
unstableUpdates = unstableUpdates,
settings = settings
)
currentTask = CurrentTask(task, downloadJob, isIndexModified, initialState)
}
Expand All @@ -508,14 +508,14 @@ class SyncService : ConnectionService<SyncService.Binder>() {
task: Task,
repository: Repository,
isIndexModified: Boolean,
unstableUpdates: Boolean,
settings: Settings,
): CoroutinesJob = launch(Dispatchers.Default) {
var isNewlyModified = isIndexModified
try {
val response = RepositoryUpdater.update(
this@SyncService,
repository,
unstableUpdates,
settings.unstableUpdate,
) { stage, progress, total ->
launch {
syncState.emit(
Expand All @@ -542,28 +542,24 @@ class SyncService : ConnectionService<SyncService.Binder>() {
} finally {
withContext(NonCancellable) {
lock.withLock { currentTask = null }
handleNextTask(isNewlyModified)
handleNextTask(isNewlyModified, settings)
}
}
}

suspend fun handleUpdates(
notifyUpdates: Boolean,
autoUpdate: Boolean,
skipSignature: Boolean,
) {
suspend fun handleUpdates(settings: Settings) {
try {
val blocked = updateNotificationBlockerFragment?.get()?.isAdded == true
val updates = Database.ProductAdapter.getUpdates(skipSignature)
val updates = Database.ProductAdapter.getUpdates(settings.ignoreSignature)

if (!blocked && updates.isNotEmpty()) {
if (notifyUpdates) {
if (settings.notifyUpdate) {
notificationManager?.notify(
Constants.NOTIFICATION_ID_UPDATES,
updatesAvailableNotification(this, updates),
)
}
if (autoUpdate) {
if (settings.autoUpdate) {
autoUpdating = true
autoUpdateStartedFor = updates.map { it.packageName }
updateAllAppsInternal(updates)
Expand All @@ -577,7 +573,7 @@ class SyncService : ConnectionService<SyncService.Binder>() {
} finally {
withContext(NonCancellable) {
lock.withLock { currentTask = null }
handleNextTask(false)
handleNextTask(false, settings)
}
}
}
Expand Down
Loading