mirror of
https://github.com/bitfireAT/davx5-ose
synced 2024-07-22 03:01:24 +00:00
Intro pages: use Hilt for dependency injection (#779)
* Accounts: move syncAll to model; better Hilt usage * Move calculation of whether IntroActivity is shown into AccountsModel * Intro pages: inject dependencies with Hilt * Fix preview
This commit is contained in:
parent
4cffbe7b40
commit
1ad8e892b6
|
@ -7,15 +7,11 @@ package at.bitfire.davdroid.ui
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import at.bitfire.davdroid.ui.account.AccountActivity
|
||||
import at.bitfire.davdroid.ui.intro.IntroActivity
|
||||
import at.bitfire.davdroid.ui.setup.LoginActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
|
@ -30,27 +26,19 @@ class AccountsActivity: AppCompatActivity() {
|
|||
finish()
|
||||
}
|
||||
|
||||
val model by viewModels<AccountsModel>()
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// use a separate thread to check whether IntroActivity should be shown
|
||||
if (savedInstanceState == null) {
|
||||
// move to Model
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
if (IntroActivity.shouldShowIntroActivity(this@AccountsActivity))
|
||||
introActivityLauncher.launch(null)
|
||||
}
|
||||
}
|
||||
|
||||
// handle "Sync all" intent from launcher shortcut
|
||||
if (savedInstanceState == null && intent.action == Intent.ACTION_SYNC)
|
||||
model.syncAllAccounts()
|
||||
val syncAccounts = intent.action == Intent.ACTION_SYNC
|
||||
|
||||
setContent {
|
||||
AccountsScreen(
|
||||
initialSyncAccounts = syncAccounts,
|
||||
onShowAppIntro = {
|
||||
introActivityLauncher.launch(null)
|
||||
},
|
||||
accountsDrawerHandler = accountsDrawerHandler,
|
||||
onAddAccount = {
|
||||
startActivity(Intent(this, LoginActivity::class.java))
|
||||
|
|
|
@ -4,43 +4,58 @@ import android.accounts.Account
|
|||
import android.app.Application
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkQuery
|
||||
import at.bitfire.davdroid.db.AppDatabase
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.repository.AccountRepository
|
||||
import at.bitfire.davdroid.servicedetection.RefreshCollectionsWorker
|
||||
import at.bitfire.davdroid.syncadapter.BaseSyncWorker
|
||||
import at.bitfire.davdroid.syncadapter.OneTimeSyncWorker
|
||||
import at.bitfire.davdroid.syncadapter.SyncUtils
|
||||
import at.bitfire.davdroid.ui.account.AccountProgress
|
||||
import at.bitfire.davdroid.ui.intro.IntroPage
|
||||
import at.bitfire.davdroid.ui.intro.IntroPageFactory
|
||||
import at.bitfire.davdroid.util.broadcastReceiverFlow
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.text.Collator
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AccountsModel @Inject constructor(
|
||||
val context: Application,
|
||||
val accountRepository: AccountRepository,
|
||||
private val db: AppDatabase
|
||||
@HiltViewModel(assistedFactory = AccountsModel.Factory::class)
|
||||
class AccountsModel @AssistedInject constructor(
|
||||
@Assisted val syncAccountsOnInit: Boolean,
|
||||
private val context: Application,
|
||||
private val accountRepository: AccountRepository,
|
||||
private val db: AppDatabase,
|
||||
introPageFactory: IntroPageFactory
|
||||
): ViewModel() {
|
||||
|
||||
// UI state
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(syncAccountsOnInit: Boolean): AccountsModel
|
||||
}
|
||||
|
||||
|
||||
// Accounts UI state
|
||||
|
||||
enum class FABStyle {
|
||||
WithText,
|
||||
|
@ -98,6 +113,20 @@ class AccountsModel @Inject constructor(
|
|||
}
|
||||
|
||||
|
||||
// other UI state
|
||||
|
||||
val showAppIntro: Flow<Boolean> = flow<Boolean> {
|
||||
val anyShowAlwaysPage = introPageFactory.introPages.any { introPage ->
|
||||
val policy = introPage.getShowPolicy()
|
||||
Logger.log.fine("Intro page ${introPage::class.java.name} policy = $policy")
|
||||
|
||||
policy == IntroPage.ShowPolicy.SHOW_ALWAYS
|
||||
}
|
||||
|
||||
emit(anyShowAlwaysPage)
|
||||
}.flowOn(Dispatchers.Default)
|
||||
|
||||
|
||||
// warnings
|
||||
|
||||
private val connectivityManager = context.getSystemService<ConnectivityManager>()!!
|
||||
|
@ -167,12 +196,18 @@ class AccountsModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
if (syncAccountsOnInit)
|
||||
syncAllAccounts()
|
||||
}
|
||||
|
||||
|
||||
// actions
|
||||
|
||||
fun syncAllAccounts() {
|
||||
if (Build.VERSION.SDK_INT >= 25)
|
||||
context.getSystemService<ShortcutManager>()?.reportShortcutUsed(UiUtils.SHORTCUT_SYNC_ALL)
|
||||
// report shortcut action to system
|
||||
ShortcutManagerCompat.reportShortcutUsed(context, UiUtils.SHORTCUT_SYNC_ALL)
|
||||
|
||||
// Enqueue sync worker for all accounts and authorities. Will sync once internet is available
|
||||
for (account in accountRepository.getAll())
|
||||
|
|
|
@ -49,6 +49,7 @@ import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
|||
import androidx.compose.material3.rememberDrawerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
|
@ -63,8 +64,8 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import at.bitfire.davdroid.BuildConfig
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.ui.account.AccountProgress
|
||||
|
@ -76,16 +77,28 @@ import kotlinx.coroutines.launch
|
|||
|
||||
@Composable
|
||||
fun AccountsScreen(
|
||||
initialSyncAccounts: Boolean,
|
||||
onShowAppIntro: () -> Unit,
|
||||
accountsDrawerHandler: AccountsDrawerHandler,
|
||||
onAddAccount: () -> Unit,
|
||||
onShowAccount: (Account) -> Unit,
|
||||
onManagePermissions: () -> Unit,
|
||||
model: AccountsModel = viewModel()
|
||||
model: AccountsModel = hiltViewModel(
|
||||
creationCallback = { factory: AccountsModel.Factory ->
|
||||
factory.create(initialSyncAccounts)
|
||||
}
|
||||
)
|
||||
) {
|
||||
val accounts by model.accountInfos.collectAsStateWithLifecycle(emptyList())
|
||||
val showSyncAll by model.showSyncAll.collectAsStateWithLifecycle(true)
|
||||
val showAddAccount by model.showAddAccount.collectAsStateWithLifecycle(AccountsModel.FABStyle.Standard)
|
||||
|
||||
val showAppIntro by model.showAppIntro.collectAsState(false)
|
||||
LaunchedEffect(showAppIntro) {
|
||||
if (showAppIntro)
|
||||
onShowAppIntro()
|
||||
}
|
||||
|
||||
AccountsScreen(
|
||||
accountsDrawerHandler = accountsDrawerHandler,
|
||||
accounts = accounts,
|
||||
|
|
|
@ -57,27 +57,18 @@ import at.bitfire.davdroid.ui.intro.BatteryOptimizationsPage.Model.Companion.HIN
|
|||
import at.bitfire.davdroid.ui.intro.BatteryOptimizationsPage.Model.Companion.HINT_BATTERY_OPTIMIZATIONS
|
||||
import at.bitfire.davdroid.util.PermissionUtils
|
||||
import at.bitfire.davdroid.util.broadcastReceiverFlow
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.launch
|
||||
import org.apache.commons.text.WordUtils
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
class BatteryOptimizationsPage: IntroPage {
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface BatteryOptimizationsPageEntryPoint {
|
||||
fun settingsManager(): SettingsManager
|
||||
}
|
||||
|
||||
override fun getShowPolicy(application: Application): IntroPage.ShowPolicy {
|
||||
val settingsManager = EntryPointAccessors.fromApplication(application, BatteryOptimizationsPageEntryPoint::class.java).settingsManager()
|
||||
class BatteryOptimizationsPage @Inject constructor(
|
||||
private val application: Application,
|
||||
private val settingsManager: SettingsManager
|
||||
): IntroPage {
|
||||
|
||||
override fun getShowPolicy(): IntroPage.ShowPolicy {
|
||||
// show fragment when:
|
||||
// 1. DAVx5 is not whitelisted yet and "don't show anymore" has not been clicked, and/or
|
||||
// 2a. evil manufacturer AND
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package at.bitfire.davdroid.ui.intro
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
|
@ -14,7 +13,6 @@ import android.view.ViewGroup
|
|||
import androidx.activity.addCallback
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -24,40 +22,18 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
|
|||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.ViewModel
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.ui.M2Colors
|
||||
import at.bitfire.davdroid.ui.M2Theme
|
||||
import com.github.appintro.AppIntro2
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.android.components.ActivityComponent
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class IntroActivity : AppIntro2() {
|
||||
|
||||
companion object {
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(ActivityComponent::class)
|
||||
interface IntroActivityEntryPoint {
|
||||
fun introPageFactory(): IntroPageFactory
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun shouldShowIntroActivity(activity: Activity): Boolean {
|
||||
val introPageFactory = EntryPointAccessors.fromActivity(activity, IntroActivityEntryPoint::class.java).introPageFactory()
|
||||
return introPageFactory.introPages.any {
|
||||
it.getShowPolicy(activity.application) == IntroPage.ShowPolicy.SHOW_ALWAYS
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val model by viewModels<Model>()
|
||||
private var currentSlide = 0
|
||||
|
||||
|
@ -120,12 +96,6 @@ class IntroActivity : AppIntro2() {
|
|||
}
|
||||
}
|
||||
|
||||
// For on resume actions of intro pages
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
activity?.application?.let { page.onResume(it) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,9 +114,8 @@ class IntroActivity : AppIntro2() {
|
|||
|
||||
@HiltViewModel
|
||||
class Model @Inject constructor(
|
||||
application: Application,
|
||||
introPageFactory: IntroPageFactory
|
||||
): AndroidViewModel(application) {
|
||||
): ViewModel() {
|
||||
|
||||
private val introPages = introPageFactory.introPages
|
||||
|
||||
|
@ -164,10 +133,14 @@ class IntroActivity : AppIntro2() {
|
|||
|
||||
private fun calculatePages(): List<IntroPage> {
|
||||
for (page in introPages)
|
||||
Logger.log.fine("Found intro page ${page::class.java} with order ${page.getShowPolicy(getApplication())}")
|
||||
Logger.log.fine("Found intro page ${page::class.java} with order ${page.getShowPolicy()}")
|
||||
|
||||
val activePages: Map<IntroPage, IntroPage.ShowPolicy> = introPages
|
||||
.associateWith { it.getShowPolicy(getApplication()) }
|
||||
.associateWith { page ->
|
||||
page.getShowPolicy().also { policy ->
|
||||
Logger.log.fine("IntroActivity: found intro page ${page::class.java} with $policy")
|
||||
}
|
||||
}
|
||||
.filterValues { it != IntroPage.ShowPolicy.DONT_SHOW }
|
||||
|
||||
val anyShowAlways = activePages.values.any { it == IntroPage.ShowPolicy.SHOW_ALWAYS }
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package at.bitfire.davdroid.ui.intro
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
interface IntroPage {
|
||||
|
@ -19,15 +18,13 @@ interface IntroPage {
|
|||
* Used to determine whether an intro page of this type (for instance,
|
||||
* the [BatteryOptimizationsPage]) should be shown.
|
||||
*
|
||||
* @param application used to determine whether the page shall be shown
|
||||
*
|
||||
* @return Order with which an instance of this page type shall be created and shown. Possible values:
|
||||
*
|
||||
* * < 0: only show the page when there is at least one other page with positive order (lower numbers are shown first)
|
||||
* * [DONT_SHOW] (0): don't show the page
|
||||
* * ≥ 0: show the page (lower numbers are shown first)
|
||||
*/
|
||||
fun getShowPolicy(application: Application): ShowPolicy
|
||||
fun getShowPolicy(): ShowPolicy
|
||||
|
||||
/**
|
||||
* Composes this page. Will only be called when [getShowPolicy] is not [DONT_SHOW].
|
||||
|
@ -35,9 +32,4 @@ interface IntroPage {
|
|||
@Composable
|
||||
fun ComposePage()
|
||||
|
||||
/**
|
||||
* Called when the user leaves and re-enters the app intro
|
||||
*/
|
||||
fun onResume(application: Application) {}
|
||||
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package at.bitfire.davdroid.ui.intro
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
|
@ -37,24 +36,14 @@ import at.bitfire.davdroid.Constants.withStatParams
|
|||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.settings.SettingsManager
|
||||
import at.bitfire.davdroid.ui.composable.CardWithImage
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Inject
|
||||
|
||||
class OpenSourcePage : IntroPage {
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface OpenSourcePageEntryPoint {
|
||||
fun settingsManager(): SettingsManager
|
||||
}
|
||||
|
||||
override fun getShowPolicy(application: Application): IntroPage.ShowPolicy {
|
||||
val settingsManager = EntryPointAccessors.fromApplication(application, OpenSourcePageEntryPoint::class.java).settingsManager()
|
||||
class OpenSourcePage @Inject constructor(
|
||||
private val settingsManager: SettingsManager
|
||||
): IntroPage {
|
||||
|
||||
override fun getShowPolicy(): IntroPage.ShowPolicy {
|
||||
return if (System.currentTimeMillis() > (settingsManager.getLongOrNull(Model.SETTING_NEXT_DONATION_POPUP) ?: 0))
|
||||
IntroPage.ShowPolicy.SHOW_ALWAYS
|
||||
else
|
||||
|
@ -69,7 +58,7 @@ class OpenSourcePage : IntroPage {
|
|||
@Composable
|
||||
private fun Page(model: Model = viewModel()) {
|
||||
val dontShow by model.dontShow.collectAsStateWithLifecycle(false)
|
||||
PageContent(
|
||||
OpenSourcePage(
|
||||
dontShow = dontShow,
|
||||
onChangeDontShow = {
|
||||
model.setDontShow(it)
|
||||
|
@ -77,67 +66,6 @@ class OpenSourcePage : IntroPage {
|
|||
)
|
||||
}
|
||||
|
||||
@Preview(
|
||||
showBackground = true,
|
||||
showSystemUi = true
|
||||
)
|
||||
@Composable
|
||||
fun PageContent(
|
||||
dontShow: Boolean = false,
|
||||
onChangeDontShow: (Boolean) -> Unit = {}
|
||||
) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(8.dp)
|
||||
) {
|
||||
CardWithImage(
|
||||
title = stringResource(R.string.intro_open_source_title),
|
||||
image = painterResource(R.drawable.intro_open_source),
|
||||
imageContentScale = ContentScale.Inside,
|
||||
message = stringResource(
|
||||
R.string.intro_open_source_text,
|
||||
stringResource(R.string.app_name)
|
||||
)
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
uriHandler.openUri(
|
||||
Constants.HOMEPAGE_URL.buildUpon()
|
||||
.appendPath(Constants.HOMEPAGE_PATH_OPEN_SOURCE)
|
||||
.withStatParams("OpenSourcePage")
|
||||
.build()
|
||||
.toString()
|
||||
)
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.intro_open_source_details))
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Checkbox(
|
||||
checked = dontShow,
|
||||
onCheckedChange = onChangeDontShow
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.intro_open_source_dont_show),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
modifier = Modifier
|
||||
.clickable { onChangeDontShow(!dontShow) }
|
||||
.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(90.dp))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@HiltViewModel
|
||||
class Model @Inject constructor(
|
||||
val settings: SettingsManager
|
||||
|
@ -159,4 +87,61 @@ class OpenSourcePage : IntroPage {
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun OpenSourcePage(
|
||||
dontShow: Boolean = false,
|
||||
onChangeDontShow: (Boolean) -> Unit = {}
|
||||
) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(8.dp)
|
||||
) {
|
||||
CardWithImage(
|
||||
title = stringResource(R.string.intro_open_source_title),
|
||||
image = painterResource(R.drawable.intro_open_source),
|
||||
imageContentScale = ContentScale.Inside,
|
||||
message = stringResource(
|
||||
R.string.intro_open_source_text,
|
||||
stringResource(R.string.app_name)
|
||||
)
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
uriHandler.openUri(
|
||||
Constants.HOMEPAGE_URL.buildUpon()
|
||||
.appendPath(Constants.HOMEPAGE_PATH_OPEN_SOURCE)
|
||||
.withStatParams("OpenSourcePage")
|
||||
.build()
|
||||
.toString()
|
||||
)
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.intro_open_source_details))
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Checkbox(
|
||||
checked = dontShow,
|
||||
onCheckedChange = onChangeDontShow
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.intro_open_source_dont_show),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
modifier = Modifier
|
||||
.clickable { onChangeDontShow(!dontShow) }
|
||||
.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(90.dp))
|
||||
}
|
||||
}
|
|
@ -7,18 +7,21 @@ package at.bitfire.davdroid.ui.intro
|
|||
import android.app.Application
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import at.bitfire.davdroid.ui.PermissionsScreen
|
||||
import at.bitfire.davdroid.ui.PermissionsModel
|
||||
import at.bitfire.davdroid.ui.PermissionsScreen
|
||||
import at.bitfire.davdroid.util.PermissionUtils
|
||||
import at.bitfire.davdroid.util.PermissionUtils.CALENDAR_PERMISSIONS
|
||||
import at.bitfire.davdroid.util.PermissionUtils.CONTACT_PERMISSIONS
|
||||
import at.bitfire.ical4android.TaskProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
class PermissionsIntroPage: IntroPage {
|
||||
class PermissionsIntroPage @Inject constructor(
|
||||
private val application: Application
|
||||
): IntroPage {
|
||||
|
||||
var model: PermissionsModel? = null
|
||||
|
||||
override fun getShowPolicy(application: Application): IntroPage.ShowPolicy {
|
||||
override fun getShowPolicy(): IntroPage.ShowPolicy {
|
||||
// show PermissionsFragment as intro fragment when no permissions are granted
|
||||
val permissions = CONTACT_PERMISSIONS + CALENDAR_PERMISSIONS +
|
||||
TaskProvider.PERMISSIONS_JTX +
|
||||
|
@ -32,15 +35,7 @@ class PermissionsIntroPage: IntroPage {
|
|||
|
||||
@Composable
|
||||
override fun ComposePage() {
|
||||
val newModel: PermissionsModel = viewModel()
|
||||
model = newModel
|
||||
|
||||
PermissionsScreen(model = newModel)
|
||||
}
|
||||
|
||||
// Check whether permissions have changed after user comes back from settings app
|
||||
override fun onResume(application: Application) {
|
||||
model?.checkPermissions()
|
||||
PermissionsScreen()
|
||||
}
|
||||
|
||||
}
|
|
@ -10,22 +10,14 @@ import at.bitfire.davdroid.settings.SettingsManager
|
|||
import at.bitfire.davdroid.ui.TasksActivity
|
||||
import at.bitfire.davdroid.ui.TasksCard
|
||||
import at.bitfire.davdroid.util.TaskUtils
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Inject
|
||||
|
||||
class TasksIntroPage : IntroPage {
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface TasksIntroPageEntryPoint {
|
||||
fun settingsManager(): SettingsManager
|
||||
}
|
||||
|
||||
override fun getShowPolicy(application: Application): IntroPage.ShowPolicy {
|
||||
val settingsManager = EntryPointAccessors.fromApplication(application, TasksIntroPageEntryPoint::class.java).settingsManager()
|
||||
class TasksIntroPage @Inject constructor(
|
||||
private val application: Application,
|
||||
private val settingsManager: SettingsManager
|
||||
): IntroPage {
|
||||
|
||||
override fun getShowPolicy(): IntroPage.ShowPolicy {
|
||||
return if (TaskUtils.isAvailable(application) || settingsManager.getBooleanOrNull(TasksActivity.Model.HINT_OPENTASKS_NOT_INSTALLED) == false)
|
||||
IntroPage.ShowPolicy.DONT_SHOW
|
||||
else
|
||||
|
|
|
@ -35,7 +35,7 @@ import at.bitfire.davdroid.ui.M2Colors.primaryDark
|
|||
|
||||
class WelcomePage: IntroPage {
|
||||
|
||||
override fun getShowPolicy(application: Application) = IntroPage.ShowPolicy.SHOW_ONLY_WITH_OTHERS
|
||||
override fun getShowPolicy() = IntroPage.ShowPolicy.SHOW_ONLY_WITH_OTHERS
|
||||
|
||||
@Composable
|
||||
override fun ComposePage() {
|
||||
|
|
|
@ -15,7 +15,6 @@ import at.bitfire.davdroid.ui.setup.LoginTypesProvider
|
|||
import at.bitfire.davdroid.ui.setup.StandardLoginTypesProvider
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityComponent
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
|
@ -48,15 +47,4 @@ interface OseFlavorModules {
|
|||
fun introPageFactory(impl: OseIntroPageFactory): IntroPageFactory
|
||||
}
|
||||
|
||||
|
||||
//// intro pages ////
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface IntroPagesModule {
|
||||
@Provides
|
||||
@IntoSet
|
||||
fun introPage(): IntroPage = BatteryOptimizationsPage()
|
||||
}
|
||||
|
||||
}
|
|
@ -12,14 +12,19 @@ import at.bitfire.davdroid.ui.intro.TasksIntroPage
|
|||
import at.bitfire.davdroid.ui.intro.WelcomePage
|
||||
import javax.inject.Inject
|
||||
|
||||
class OseIntroPageFactory @Inject constructor(): IntroPageFactory {
|
||||
class OseIntroPageFactory @Inject constructor(
|
||||
batteryOptimizationsPage: BatteryOptimizationsPage,
|
||||
openSourcePage: OpenSourcePage,
|
||||
permissionsIntroPage: PermissionsIntroPage,
|
||||
tasksIntroPage: TasksIntroPage
|
||||
): IntroPageFactory {
|
||||
|
||||
override val introPages = arrayOf(
|
||||
WelcomePage(),
|
||||
TasksIntroPage(),
|
||||
PermissionsIntroPage(),
|
||||
BatteryOptimizationsPage(),
|
||||
OpenSourcePage()
|
||||
tasksIntroPage,
|
||||
permissionsIntroPage,
|
||||
batteryOptimizationsPage,
|
||||
openSourcePage
|
||||
)
|
||||
|
||||
}
|
Loading…
Reference in a new issue