mirror of
https://github.com/bitfireAT/davx5-ose
synced 2024-07-22 03:01:24 +00:00
Refactor Tasks app detection (and settings update when tasks apps change) (#637)
* Refactoring * Better live handling of (un)installed task apps * Minor changes * SettingsManager: explicitly mark possibility of null LiveData values * Fix tests
This commit is contained in:
parent
cb56132994
commit
06b4cf9477
|
@ -68,7 +68,7 @@ class SettingsManagerTest {
|
|||
// posts value to main thread, InstantTaskExecutorRule is required to execute it instantly
|
||||
settingsManager.putBoolean(SETTING_TEST, true)
|
||||
runBlocking(Dispatchers.Main) { // observeForever can't be run in background thread
|
||||
assertTrue(live.getOrAwaitValue())
|
||||
assertTrue(live.getOrAwaitValue()!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import androidx.hilt.work.HiltWorkerFactory
|
|||
import androidx.work.Configuration
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.syncadapter.AccountsUpdatedListener
|
||||
import at.bitfire.davdroid.syncadapter.SyncUtils
|
||||
import at.bitfire.davdroid.ui.DebugInfoActivity
|
||||
import at.bitfire.davdroid.ui.NotificationUtils
|
||||
import at.bitfire.davdroid.ui.UiUtils
|
||||
|
@ -65,10 +64,8 @@ class App: Application(), Thread.UncaughtExceptionHandler, Configuration.Provide
|
|||
// watch storage because low storage means synchronization is stopped
|
||||
storageLowReceiver.listen()
|
||||
|
||||
// watch installed/removed apps
|
||||
// watch installed/removed tasks apps and update sync settings accordingly
|
||||
TasksWatcher.watch(this)
|
||||
// check whether a tasks app is currently installed
|
||||
SyncUtils.updateTaskSync(this)
|
||||
|
||||
// create/update app shortcuts
|
||||
UiUtils.updateShortcuts(this)
|
||||
|
@ -87,4 +84,4 @@ class App: Application(), Thread.UncaughtExceptionHandler, Configuration.Provide
|
|||
exitProcess(1)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -8,22 +8,39 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import androidx.annotation.MainThread
|
||||
|
||||
abstract class PackageChangedReceiver(
|
||||
val context: Context
|
||||
val context: Context
|
||||
): BroadcastReceiver(), AutoCloseable {
|
||||
|
||||
init {
|
||||
/**
|
||||
* Registers the receiver.
|
||||
*
|
||||
* @param whether [onPackageChanged] shall be called immediately after registering
|
||||
*/
|
||||
fun register(immediateCall: Boolean = false) {
|
||||
val filter = IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply {
|
||||
addAction(Intent.ACTION_PACKAGE_CHANGED)
|
||||
addAction(Intent.ACTION_PACKAGE_REMOVED)
|
||||
addDataScheme("package")
|
||||
}
|
||||
context.registerReceiver(this, filter)
|
||||
|
||||
if (immediateCall)
|
||||
onPackageChanged()
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
context.unregisterReceiver(this)
|
||||
}
|
||||
|
||||
|
||||
@MainThread
|
||||
abstract fun onPackageChanged()
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
onPackageChanged()
|
||||
}
|
||||
|
||||
}
|
|
@ -5,26 +5,55 @@
|
|||
package at.bitfire.davdroid
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import at.bitfire.davdroid.syncadapter.SyncUtils.updateTaskSync
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.resource.TaskUtils
|
||||
import at.bitfire.davdroid.syncadapter.SyncUtils
|
||||
import at.bitfire.ical4android.TaskProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Watches whether a tasks app has been installed or uninstalled and updates
|
||||
* the selected tasks app and task sync settings accordingly.
|
||||
*/
|
||||
class TasksWatcher private constructor(
|
||||
context: Context
|
||||
): PackageChangedReceiver(context) {
|
||||
|
||||
companion object {
|
||||
|
||||
fun watch(context: Context) = TasksWatcher(context)
|
||||
fun watch(context: Context) {
|
||||
TasksWatcher(context).register(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
override fun onPackageChanged() {
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
updateTaskSync(context)
|
||||
if (TaskUtils.currentProvider(context) == null) {
|
||||
/* Currently no usable tasks provider.
|
||||
Iterate through all supported providers and select one, if available. */
|
||||
|
||||
var providerSelected = false
|
||||
for (provider in TaskProvider.ProviderName.entries) {
|
||||
val available = context.packageManager.resolveContentProvider(provider.authority, 0) != null
|
||||
if (available) {
|
||||
Logger.log.info("Selecting new tasks provider: $provider")
|
||||
TaskUtils.selectProvider(context, provider, updateSyncSettings = false)
|
||||
providerSelected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!providerSelected)
|
||||
// no provider available, also clear setting
|
||||
TaskUtils.selectProvider(context, null, updateSyncSettings = false)
|
||||
}
|
||||
|
||||
// update sync settings
|
||||
SyncUtils.updateTaskSync(context)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -16,9 +16,6 @@ import dagger.hilt.EntryPoint
|
|||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object TaskUtils {
|
||||
|
||||
|
@ -28,16 +25,29 @@ object TaskUtils {
|
|||
fun settingsManager(): SettingsManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently selected tasks provider (if it's still available = installed).
|
||||
*
|
||||
* @return the currently selected tasks provider, or null if none is available
|
||||
*/
|
||||
fun currentProvider(context: Context): ProviderName? {
|
||||
val settingsManager = EntryPointAccessors.fromApplication(context, TaskUtilsEntryPoint::class.java).settingsManager()
|
||||
val preferredAuthority = settingsManager.getString(Settings.PREFERRED_TASKS_PROVIDER) ?: return null
|
||||
val preferredAuthority = settingsManager.getString(Settings.SELECTED_TASKS_PROVIDER) ?: return null
|
||||
return preferredAuthorityToProviderName(preferredAuthority, context.packageManager)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently selected tasks provider (if it's still available = installed).
|
||||
*
|
||||
* @return the currently selected tasks provider, or null if none is available
|
||||
*/
|
||||
fun currentProviderLive(context: Context): LiveData<ProviderName?> {
|
||||
val settingsManager = EntryPointAccessors.fromApplication(context, TaskUtilsEntryPoint::class.java).settingsManager()
|
||||
return settingsManager.getStringLive(Settings.PREFERRED_TASKS_PROVIDER).map { preferred ->
|
||||
preferredAuthorityToProviderName(preferred, context.packageManager)
|
||||
return settingsManager.getStringLive(Settings.SELECTED_TASKS_PROVIDER).map { preferred ->
|
||||
if (preferred != null)
|
||||
preferredAuthorityToProviderName(preferred, context.packageManager)
|
||||
else
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,12 +66,12 @@ object TaskUtils {
|
|||
|
||||
fun isAvailable(context: Context) = currentProvider(context) != null
|
||||
|
||||
fun setPreferredProvider(context: Context, providerName: ProviderName) {
|
||||
fun selectProvider(context: Context, providerName: ProviderName?, updateSyncSettings: Boolean = false) {
|
||||
val settingsManager = EntryPointAccessors.fromApplication(context, TaskUtilsEntryPoint::class.java).settingsManager()
|
||||
settingsManager.putString(Settings.PREFERRED_TASKS_PROVIDER, providerName.authority)
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
SyncUtils.updateTaskSync(context)
|
||||
}
|
||||
settingsManager.putString(Settings.SELECTED_TASKS_PROVIDER, providerName?.authority)
|
||||
|
||||
// update sync settings
|
||||
SyncUtils.updateTaskSync(context)
|
||||
}
|
||||
|
||||
}
|
|
@ -39,10 +39,13 @@ object Settings {
|
|||
const val PREFERRED_THEME = "preferred_theme"
|
||||
const val PREFERRED_THEME_DEFAULT = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
|
||||
const val LANGUAGE = "language"
|
||||
const val LANGUAGE_SYSTEM = "language_system"
|
||||
|
||||
const val PREFERRED_TASKS_PROVIDER = "preferred_tasks_provider"
|
||||
/**
|
||||
* Selected tasks app. When at least one tasks app is installed, this setting is set to its authority.
|
||||
* In case of multiple available tasks app, the user can choose one and this setting will reflect the selected one.
|
||||
*
|
||||
* If no tasks app is installed, this setting is not set.
|
||||
*/
|
||||
const val SELECTED_TASKS_PROVIDER = "preferred_tasks_provider"
|
||||
|
||||
/** whether collections are automatically selected for synchronization after their initial detection */
|
||||
const val PRESELECT_COLLECTIONS = "preselect_collections"
|
||||
|
|
|
@ -125,17 +125,17 @@ class SettingsManager internal constructor(
|
|||
|
||||
fun getBooleanOrNull(key: String): Boolean? = getValue(key) { provider -> provider.getBoolean(key) }
|
||||
fun getBoolean(key: String): Boolean = getBooleanOrNull(key) ?: throw NoSuchPropertyException(key)
|
||||
fun getBooleanLive(key: String): LiveData<Boolean> = SettingLiveData { getBooleanOrNull(key) }
|
||||
fun getBooleanLive(key: String): LiveData<Boolean?> = SettingLiveData { getBooleanOrNull(key) }
|
||||
|
||||
fun getIntOrNull(key: String): Int? = getValue(key) { provider -> provider.getInt(key) }
|
||||
fun getInt(key: String): Int = getIntOrNull(key) ?: throw NoSuchPropertyException(key)
|
||||
fun getIntLive(key: String): LiveData<Int> = SettingLiveData { getIntOrNull(key) }
|
||||
fun getIntLive(key: String): LiveData<Int?> = SettingLiveData { getIntOrNull(key) }
|
||||
|
||||
fun getLongOrNull(key: String): Long? = getValue(key) { provider -> provider.getLong(key) }
|
||||
fun getLong(key: String) = getLongOrNull(key) ?: throw NoSuchPropertyException(key)
|
||||
|
||||
fun getString(key: String) = getValue(key) { provider -> provider.getString(key) }
|
||||
fun getStringLive(key: String): LiveData<String> = SettingLiveData { getString(key) }
|
||||
fun getStringLive(key: String): LiveData<String?> = SettingLiveData { getString(key) }
|
||||
|
||||
|
||||
fun isWritable(key: String): Boolean {
|
||||
|
|
|
@ -114,15 +114,17 @@ object SyncUtils {
|
|||
|
||||
// task sync utils
|
||||
|
||||
/**
|
||||
* Sets up sync for the current TaskProvider (and disables sync for unavailable task providers).
|
||||
*
|
||||
* In case of missing permissions, a notification is shown.
|
||||
*/
|
||||
@WorkerThread
|
||||
fun updateTaskSync(context: Context) {
|
||||
val tasksProvider = TaskUtils.currentProvider(context)
|
||||
Logger.log.info("App launched or other package (un)installed; current tasks provider = $tasksProvider")
|
||||
val currentProvider = TaskUtils.currentProvider(context)
|
||||
Logger.log.info("App launched or other package (un)installed; current tasks provider = $currentProvider")
|
||||
|
||||
var permissionsRequired = false // whether additional permissions are required
|
||||
val currentProvider by lazy { // only this provider shall be enabled (null to disable all providers)
|
||||
TaskUtils.currentProvider(context)
|
||||
}
|
||||
|
||||
// check all accounts and (de)activate task provider(s) if a CalDAV service is defined
|
||||
val db = EntryPointAccessors.fromApplication(context, SyncUtilsEntryPoint::class.java).appDatabase()
|
||||
|
|
|
@ -151,7 +151,7 @@ class AppSettingsActivity: AppCompatActivity() {
|
|||
)
|
||||
|
||||
AppSettings_Connection(
|
||||
proxyType = model.settings.getIntLive(Settings.PROXY_TYPE).observeAsState(Settings.PROXY_TYPE_NONE).value,
|
||||
proxyType = model.settings.getIntLive(Settings.PROXY_TYPE).observeAsState().value ?: Settings.PROXY_TYPE_NONE,
|
||||
onProxyTypeUpdated = { model.settings.putInt(Settings.PROXY_TYPE, it) },
|
||||
proxyHostName = model.settings.getStringLive(Settings.PROXY_HOST).observeAsState(null).value,
|
||||
onProxyHostNameUpdated = { model.settings.putString(Settings.PROXY_HOST, it) },
|
||||
|
@ -160,7 +160,7 @@ class AppSettingsActivity: AppCompatActivity() {
|
|||
)
|
||||
|
||||
AppSettings_Security(
|
||||
distrustSystemCerts = model.settings.getBooleanLive(Settings.DISTRUST_SYSTEM_CERTIFICATES).observeAsState(false).value,
|
||||
distrustSystemCerts = model.settings.getBooleanLive(Settings.DISTRUST_SYSTEM_CERTIFICATES).observeAsState().value ?: false,
|
||||
onDistrustSystemCertsUpdated = { model.settings.putBoolean(Settings.DISTRUST_SYSTEM_CERTIFICATES, it) },
|
||||
onResetCertificates = {
|
||||
model.resetCertificates()
|
||||
|
@ -172,7 +172,7 @@ class AppSettingsActivity: AppCompatActivity() {
|
|||
)
|
||||
|
||||
AppSettings_UserInterface(
|
||||
theme = model.settings.getIntLive(Settings.PREFERRED_THEME).observeAsState(Settings.PREFERRED_THEME_DEFAULT).value,
|
||||
theme = model.settings.getIntLive(Settings.PREFERRED_THEME).observeAsState().value ?: Settings.PREFERRED_THEME_DEFAULT,
|
||||
onThemeSelected = {
|
||||
model.settings.putInt(Settings.PREFERRED_THEME, it)
|
||||
UiUtils.updateTheme(context)
|
||||
|
|
|
@ -6,7 +6,6 @@ package at.bitfire.davdroid.ui
|
|||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
|
@ -50,7 +49,6 @@ import at.bitfire.davdroid.util.PermissionUtils
|
|||
import at.bitfire.ical4android.TaskProvider
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import java.util.logging.Level
|
||||
|
||||
class PermissionsActivity: AppCompatActivity() {
|
||||
|
@ -82,13 +80,13 @@ class PermissionsActivity: AppCompatActivity() {
|
|||
val jtxAvailable = MutableLiveData<Boolean>()
|
||||
|
||||
private val tasksWatcher = object: PackageChangedReceiver(app) {
|
||||
@MainThread
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
override fun onPackageChanged() {
|
||||
checkPermissions()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
tasksWatcher.register()
|
||||
checkPermissions()
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
package at.bitfire.davdroid.ui
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.AnyThread
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
@ -45,9 +43,10 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.text.ExperimentalTextApi
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.map
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import at.bitfire.davdroid.BuildConfig
|
||||
import at.bitfire.davdroid.PackageChangedReceiver
|
||||
|
@ -60,6 +59,7 @@ import at.bitfire.davdroid.ui.widget.RadioWithSwitch
|
|||
import at.bitfire.ical4android.TaskProvider
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -80,9 +80,9 @@ class TasksActivity: AppCompatActivity() {
|
|||
|
||||
@HiltViewModel
|
||||
class Model @Inject constructor(
|
||||
application: Application,
|
||||
val context: Application,
|
||||
val settings: SettingsManager
|
||||
) : AndroidViewModel(application), SettingsManager.OnChangeListener {
|
||||
) : ViewModel() {
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -95,83 +95,46 @@ class TasksActivity: AppCompatActivity() {
|
|||
|
||||
}
|
||||
|
||||
val currentProvider = MutableLiveData<TaskProvider.ProviderName>()
|
||||
val openTasksInstalled = MutableLiveData<Boolean>()
|
||||
val openTasksRequested = MutableLiveData<Boolean>()
|
||||
val openTasksSelected = MutableLiveData<Boolean>()
|
||||
val tasksOrgInstalled = MutableLiveData<Boolean>()
|
||||
val tasksOrgRequested = MutableLiveData<Boolean>()
|
||||
val tasksOrgSelected = MutableLiveData<Boolean>()
|
||||
val jtxInstalled = MutableLiveData<Boolean>()
|
||||
val jtxRequested = MutableLiveData<Boolean>()
|
||||
val jtxSelected = MutableLiveData<Boolean>()
|
||||
val dontShow = settings.getBooleanLive(HINT_OPENTASKS_NOT_INSTALLED)
|
||||
fun setDontShow(dontShow: Boolean) {
|
||||
settings.putBoolean(HINT_OPENTASKS_NOT_INSTALLED, !dontShow)
|
||||
}
|
||||
|
||||
private val tasksWatcher = object: PackageChangedReceiver(application) {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
checkInstalled()
|
||||
val currentProvider = TaskUtils.currentProviderLive(context)
|
||||
val jtxSelected = currentProvider.map { it == TaskProvider.ProviderName.JtxBoard }
|
||||
val tasksOrgSelected = currentProvider.map { it == TaskProvider.ProviderName.TasksOrg }
|
||||
val openTasksSelected = currentProvider.map { it == TaskProvider.ProviderName.OpenTasks }
|
||||
|
||||
val jtxInstalled = MutableLiveData<Boolean>()
|
||||
val tasksOrgInstalled = MutableLiveData<Boolean>()
|
||||
val openTasksInstalled = MutableLiveData<Boolean>()
|
||||
|
||||
private val pkgChangedReceiver = object: PackageChangedReceiver(context) {
|
||||
override fun onPackageChanged() {
|
||||
jtxInstalled.postValue(isInstalled(TaskProvider.ProviderName.JtxBoard.packageName))
|
||||
tasksOrgInstalled.postValue(isInstalled(TaskProvider.ProviderName.TasksOrg.packageName))
|
||||
openTasksInstalled.postValue(isInstalled(TaskProvider.ProviderName.OpenTasks.packageName))
|
||||
}
|
||||
}
|
||||
|
||||
val dontShow = MutableLiveData(
|
||||
settings.getBooleanOrNull(HINT_OPENTASKS_NOT_INSTALLED) == false
|
||||
)
|
||||
|
||||
private val dontShowObserver = Observer<Boolean> { value ->
|
||||
if (value)
|
||||
settings.putBoolean(HINT_OPENTASKS_NOT_INSTALLED, false)
|
||||
else
|
||||
settings.remove(HINT_OPENTASKS_NOT_INSTALLED)
|
||||
}
|
||||
|
||||
init {
|
||||
checkInstalled()
|
||||
settings.addOnChangeListener(this)
|
||||
dontShow.observeForever(dontShowObserver)
|
||||
pkgChangedReceiver.register(true)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
settings.removeOnChangeListener(this)
|
||||
tasksWatcher.close()
|
||||
dontShow.removeObserver(dontShowObserver)
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
fun checkInstalled() {
|
||||
val taskProvider = TaskUtils.currentProvider(getApplication())
|
||||
currentProvider.postValue(taskProvider)
|
||||
|
||||
val openTasks = isInstalled(TaskProvider.ProviderName.OpenTasks.packageName)
|
||||
openTasksInstalled.postValue(openTasks)
|
||||
openTasksRequested.postValue(openTasks)
|
||||
openTasksSelected.postValue(taskProvider == TaskProvider.ProviderName.OpenTasks)
|
||||
|
||||
val tasksOrg = isInstalled(TaskProvider.ProviderName.TasksOrg.packageName)
|
||||
tasksOrgInstalled.postValue(tasksOrg)
|
||||
tasksOrgRequested.postValue(tasksOrg)
|
||||
tasksOrgSelected.postValue(taskProvider == TaskProvider.ProviderName.TasksOrg)
|
||||
|
||||
val jtxBoard = isInstalled(TaskProvider.ProviderName.JtxBoard.packageName)
|
||||
jtxInstalled.postValue(jtxBoard)
|
||||
jtxRequested.postValue(jtxBoard)
|
||||
jtxSelected.postValue(taskProvider == TaskProvider.ProviderName.JtxBoard)
|
||||
pkgChangedReceiver.close()
|
||||
}
|
||||
|
||||
private fun isInstalled(packageName: String): Boolean =
|
||||
try {
|
||||
getApplication<Application>().packageManager.getPackageInfo(packageName, 0)
|
||||
context.packageManager.getPackageInfo(packageName, 0)
|
||||
true
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
false
|
||||
}
|
||||
|
||||
fun selectPreferredProvider(provider: TaskProvider.ProviderName) {
|
||||
// Changes preferred task app setting, so onSettingsChanged() will be called
|
||||
TaskUtils.setPreferredProvider(getApplication(), provider)
|
||||
}
|
||||
|
||||
|
||||
override fun onSettingsChanged() {
|
||||
checkInstalled()
|
||||
fun selectProvider(provider: TaskProvider.ProviderName) = viewModelScope.launch(Dispatchers.Default) {
|
||||
TaskUtils.selectProvider(context, provider)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -190,19 +153,16 @@ fun TasksCard(
|
|||
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val jtxInstalled by model.jtxInstalled.observeAsState(initial = false)
|
||||
val jtxSelected by model.jtxSelected.observeAsState(initial = false)
|
||||
val jtxRequested by model.jtxRequested.observeAsState(initial = false)
|
||||
val jtxInstalled by model.jtxInstalled.observeAsState(false)
|
||||
val jtxSelected by model.jtxSelected.observeAsState(false)
|
||||
|
||||
val tasksOrgInstalled by model.tasksOrgInstalled.observeAsState(initial = false)
|
||||
val tasksOrgSelected by model.tasksOrgSelected.observeAsState(initial = false)
|
||||
val tasksOrgRequested by model.tasksOrgRequested.observeAsState(initial = false)
|
||||
val tasksOrgInstalled by model.tasksOrgInstalled.observeAsState(false)
|
||||
val tasksOrgSelected by model.tasksOrgSelected.observeAsState(false)
|
||||
|
||||
val openTasksInstalled by model.openTasksInstalled.observeAsState(initial = false)
|
||||
val openTasksSelected by model.openTasksSelected.observeAsState(initial = false)
|
||||
val openTasksRequested by model.openTasksRequested.observeAsState(initial = false)
|
||||
val openTasksInstalled by model.openTasksInstalled.observeAsState(false)
|
||||
val openTasksSelected by model.openTasksSelected.observeAsState(false)
|
||||
|
||||
val dontShow by model.dontShow.observeAsState(initial = false)
|
||||
val dontShow = model.dontShow.observeAsState().value ?: false
|
||||
|
||||
fun installApp(packageName: String) {
|
||||
val uri = Uri.parse("market://details?id=$packageName&referrer=" +
|
||||
|
@ -221,7 +181,7 @@ fun TasksCard(
|
|||
|
||||
fun onProviderSelected(provider: TaskProvider.ProviderName) {
|
||||
if (model.currentProvider.value != provider)
|
||||
model.selectPreferredProvider(provider)
|
||||
model.selectProvider(provider)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
|
@ -249,7 +209,7 @@ fun TasksCard(
|
|||
Text(stringResource(R.string.intro_tasks_jtx_info))
|
||||
},
|
||||
isSelected = jtxSelected,
|
||||
isToggled = jtxRequested,
|
||||
isToggled = jtxInstalled,
|
||||
enabled = jtxInstalled,
|
||||
onSelected = { onProviderSelected(TaskProvider.ProviderName.JtxBoard) },
|
||||
onToggled = { toggled ->
|
||||
|
@ -280,7 +240,7 @@ fun TasksCard(
|
|||
)
|
||||
},
|
||||
isSelected = tasksOrgSelected,
|
||||
isToggled = tasksOrgRequested,
|
||||
isToggled = tasksOrgInstalled,
|
||||
enabled = tasksOrgInstalled,
|
||||
onSelected = { onProviderSelected(TaskProvider.ProviderName.TasksOrg) },
|
||||
onToggled = { toggled ->
|
||||
|
@ -297,7 +257,7 @@ fun TasksCard(
|
|||
Text(stringResource(R.string.intro_tasks_opentasks_info))
|
||||
},
|
||||
isSelected = openTasksSelected,
|
||||
isToggled = openTasksRequested,
|
||||
isToggled = openTasksInstalled,
|
||||
enabled = openTasksInstalled,
|
||||
onSelected = { onProviderSelected(TaskProvider.ProviderName.OpenTasks) },
|
||||
onToggled = { toggled ->
|
||||
|
@ -316,13 +276,13 @@ fun TasksCard(
|
|||
) {
|
||||
Checkbox(
|
||||
checked = dontShow,
|
||||
onCheckedChange = { model.dontShow.value = it }
|
||||
onCheckedChange = { model.setDontShow(it) }
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.intro_tasks_dont_show),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { model.dontShow.value = !dontShow }
|
||||
.clickable { model.setDontShow(!dontShow) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
|
@ -121,7 +122,8 @@ class OpenSourcePage : IntroPage {
|
|||
Text(stringResource(R.string.intro_open_source_details))
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Checkbox(
|
||||
checked = dontShow,
|
||||
|
@ -130,7 +132,9 @@ class OpenSourcePage : IntroPage {
|
|||
Text(
|
||||
text = stringResource(R.string.intro_open_source_dont_show),
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.clickable { onChangeDontShow(!dontShow) }
|
||||
modifier = Modifier
|
||||
.clickable { onChangeDontShow(!dontShow) }
|
||||
.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue