Rewrite TasksIntroPage to M3 (#760)

* Migrated to M3

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Fixed theme

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Moved Composables and Model to individual files

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Move AppTheme to screen composable

* Fixed model name

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

* Minor re-ordering

---------

Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
This commit is contained in:
Arnau Mora 2024-05-09 18:51:38 +02:00 committed by GitHub
parent 857309c451
commit 364f372a8b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 322 additions and 314 deletions

View file

@ -79,11 +79,11 @@ import at.bitfire.davdroid.util.broadcastReceiverFlow
import at.bitfire.ical4android.TaskProvider
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class AppSettingsActivity: AppCompatActivity() {
@ -541,7 +541,7 @@ class AppSettingsActivity: AppCompatActivity() {
fun resetHints() {
settings.remove(BatteryOptimizationsPage.Model.HINT_BATTERY_OPTIMIZATIONS)
settings.remove(BatteryOptimizationsPage.Model.HINT_AUTOSTART_PERMISSION)
settings.remove(TasksActivity.Model.HINT_OPENTASKS_NOT_INSTALLED)
settings.remove(TasksModel.HINT_OPENTASKS_NOT_INSTALLED)
settings.remove(OpenSourcePage.Model.SETTING_NEXT_DONATION_POPUP)
}

View file

@ -4,64 +4,10 @@
package at.bitfire.davdroid.ui
import android.app.Application
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Checkbox
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.SnackbarDuration
import androidx.compose.material.SnackbarHostState
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.text.HtmlCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.R
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.UiUtils.toAnnotatedString
import at.bitfire.davdroid.ui.composable.BasicTopAppBar
import at.bitfire.davdroid.ui.composable.CardWithImage
import at.bitfire.davdroid.ui.composable.RadioWithSwitch
import at.bitfire.davdroid.ui.widget.ClickableTextWithLink
import at.bitfire.davdroid.util.TaskUtils
import at.bitfire.davdroid.util.packageChangedFlow
import at.bitfire.ical4android.TaskProvider
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class TasksActivity: AppCompatActivity() {
@ -70,263 +16,9 @@ class TasksActivity: AppCompatActivity() {
super.onCreate(savedInstanceState)
setContent {
M2Theme {
Scaffold(
topBar = {
BasicTopAppBar(
titleStringRes = R.string.intro_tasks_title,
onNavigateUp = ::onSupportNavigateUp
)
}
) { paddingValues ->
Box(Modifier.padding(paddingValues)) {
TasksCard()
}
}
}
}
}
@HiltViewModel
class Model @Inject constructor(
val context: Application,
val settings: SettingsManager
) : ViewModel() {
companion object {
/**
* Whether this fragment (which asks for OpenTasks installation) shall be shown.
* If this setting is true or null/not set, the notice shall be shown. Only if this
* setting is false, the notice shall not be shown.
*/
const val HINT_OPENTASKS_NOT_INSTALLED = "hint_OpenTasksNotInstalled"
}
val showAgain = settings.getBooleanFlow(HINT_OPENTASKS_NOT_INSTALLED, true)
fun setShowAgain(showAgain: Boolean) {
if (showAgain)
settings.remove(HINT_OPENTASKS_NOT_INSTALLED)
else
settings.putBoolean(HINT_OPENTASKS_NOT_INSTALLED, false)
}
val currentProvider = TaskUtils.currentProviderFlow(context, viewModelScope)
val jtxSelected = currentProvider.map { it == TaskProvider.ProviderName.JtxBoard }
val tasksOrgSelected = currentProvider.map { it == TaskProvider.ProviderName.TasksOrg }
val openTasksSelected = currentProvider.map { it == TaskProvider.ProviderName.OpenTasks }
var jtxInstalled by mutableStateOf(false)
var tasksOrgInstalled by mutableStateOf(false)
var openTasksInstalled by mutableStateOf(false)
init {
viewModelScope.launch {
packageChangedFlow(context).collect {
jtxInstalled = isInstalled(TaskProvider.ProviderName.JtxBoard.packageName)
tasksOrgInstalled = isInstalled(TaskProvider.ProviderName.TasksOrg.packageName)
openTasksInstalled = isInstalled(TaskProvider.ProviderName.OpenTasks.packageName)
}
}
}
private fun isInstalled(packageName: String): Boolean =
try {
context.packageManager.getPackageInfo(packageName, 0)
true
} catch (e: PackageManager.NameNotFoundException) {
false
}
fun selectProvider(provider: TaskProvider.ProviderName) = viewModelScope.launch(Dispatchers.Default) {
TaskUtils.selectProvider(context, provider)
}
}
}
@Composable
fun TasksCard(
model: TasksActivity.Model = viewModel()
) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
val jtxInstalled = model.jtxInstalled
val jtxSelected by model.jtxSelected.collectAsStateWithLifecycle(false)
val tasksOrgInstalled = model.tasksOrgInstalled
val tasksOrgSelected by model.tasksOrgSelected.collectAsStateWithLifecycle(false)
val openTasksInstalled = model.openTasksInstalled
val openTasksSelected by model.openTasksSelected.collectAsStateWithLifecycle(false)
val showAgain by model.showAgain.collectAsStateWithLifecycle(true)
TasksCardContent(
jtxSelected = jtxSelected,
jtxInstalled = jtxInstalled,
tasksOrgSelected = tasksOrgSelected,
tasksOrgInstalled = tasksOrgInstalled,
openTasksSelected = openTasksSelected,
openTasksInstalled = openTasksInstalled,
showAgain = showAgain,
onSetShowAgain = model::setShowAgain,
onProviderSelected = { provider ->
if (model.currentProvider.value != provider)
model.selectProvider(provider)
},
installApp = { packageName ->
val uri = Uri.parse("market://details?id=$packageName&referrer=" +
Uri.encode("utm_source=" + BuildConfig.APPLICATION_ID))
val intent = Intent(Intent.ACTION_VIEW, uri)
if (intent.resolveActivity(context.packageManager) != null)
context.startActivity(intent)
else
coroutineScope.launch {
snackbarHostState.showSnackbar(
message = context.getString(R.string.intro_tasks_no_app_store),
duration = SnackbarDuration.Long
)
}
}
)
}
@Preview(showBackground = true, showSystemUi = true)
@Composable
fun TasksCardContent_Preview() {
M2Theme {
TasksCardContent(
jtxSelected = true,
jtxInstalled = true,
tasksOrgSelected = false,
tasksOrgInstalled = false,
openTasksSelected = false,
openTasksInstalled = false,
showAgain = true,
onSetShowAgain = {},
onProviderSelected = {},
installApp = {}
)
}
}
@Composable
fun TasksCardContent(
jtxSelected: Boolean,
jtxInstalled: Boolean,
tasksOrgSelected: Boolean,
tasksOrgInstalled: Boolean,
openTasksSelected: Boolean,
openTasksInstalled: Boolean,
showAgain: Boolean,
onSetShowAgain: (Boolean) -> Unit,
onProviderSelected: (TaskProvider.ProviderName) -> Unit,
installApp: (String) -> Unit,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.verticalScroll(rememberScrollState())
) {
CardWithImage(
image = painterResource(R.drawable.intro_tasks),
imageAlignment = BiasAlignment(0f, .1f),
title = stringResource(R.string.intro_tasks_title),
message = stringResource(R.string.intro_tasks_text1),
modifier = Modifier.padding(8.dp)
) {
RadioWithSwitch(
title = stringResource(R.string.intro_tasks_jtx),
summary = {
Text(stringResource(R.string.intro_tasks_jtx_info))
},
isSelected = jtxSelected,
isToggled = jtxInstalled,
enabled = jtxInstalled,
onSelected = { onProviderSelected(TaskProvider.ProviderName.JtxBoard) },
onToggled = { toggled ->
if (toggled) installApp(TaskProvider.ProviderName.JtxBoard.packageName)
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp)
TasksScreen(
onNavUp = ::onSupportNavigateUp
)
RadioWithSwitch(
title = stringResource(R.string.intro_tasks_tasks_org),
summary = {
val summary = HtmlCompat.fromHtml(
stringResource(R.string.intro_tasks_tasks_org_info),
HtmlCompat.FROM_HTML_MODE_COMPACT
).toAnnotatedString()
ClickableTextWithLink(summary)
},
isSelected = tasksOrgSelected,
isToggled = tasksOrgInstalled,
enabled = tasksOrgInstalled,
onSelected = { onProviderSelected(TaskProvider.ProviderName.TasksOrg) },
onToggled = { toggled ->
if (toggled) installApp(TaskProvider.ProviderName.TasksOrg.packageName)
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp)
)
RadioWithSwitch(
title = stringResource(R.string.intro_tasks_opentasks),
summary = {
Text(stringResource(R.string.intro_tasks_opentasks_info))
},
isSelected = openTasksSelected,
isToggled = openTasksInstalled,
enabled = openTasksInstalled,
onSelected = { onProviderSelected(TaskProvider.ProviderName.OpenTasks) },
onToggled = { toggled ->
if (toggled) installApp(TaskProvider.ProviderName.OpenTasks.packageName)
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp)
)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp)
) {
Checkbox(
checked = !showAgain,
onCheckedChange = { onSetShowAgain(!it) }
)
Text(
text = stringResource(R.string.intro_tasks_dont_show),
style = MaterialTheme.typography.body2,
modifier = Modifier
.fillMaxWidth()
.clickable { onSetShowAgain(!showAgain) }
)
}
}
Text(
text = stringResource(
R.string.intro_leave_unchecked,
stringResource(R.string.app_settings_reset_hints)
),
style = MaterialTheme.typography.body2,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 12.dp, vertical = 8.dp)
)
}
}

View file

@ -0,0 +1,76 @@
package at.bitfire.davdroid.ui
import android.app.Application
import android.content.pm.PackageManager
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.util.TaskUtils
import at.bitfire.davdroid.util.packageChangedFlow
import at.bitfire.ical4android.TaskProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@HiltViewModel
class TasksModel @Inject constructor(
val context: Application,
val settings: SettingsManager
) : ViewModel() {
companion object {
/**
* Whether this fragment (which asks for OpenTasks installation) shall be shown.
* If this setting is true or null/not set, the notice shall be shown. Only if this
* setting is false, the notice shall not be shown.
*/
const val HINT_OPENTASKS_NOT_INSTALLED = "hint_OpenTasksNotInstalled"
}
val showAgain = settings.getBooleanFlow(HINT_OPENTASKS_NOT_INSTALLED, true)
fun setShowAgain(showAgain: Boolean) {
if (showAgain)
settings.remove(HINT_OPENTASKS_NOT_INSTALLED)
else
settings.putBoolean(HINT_OPENTASKS_NOT_INSTALLED, false)
}
val currentProvider = TaskUtils.currentProviderFlow(context, viewModelScope)
val jtxSelected = currentProvider.map { it == TaskProvider.ProviderName.JtxBoard }
val tasksOrgSelected = currentProvider.map { it == TaskProvider.ProviderName.TasksOrg }
val openTasksSelected = currentProvider.map { it == TaskProvider.ProviderName.OpenTasks }
var jtxInstalled by mutableStateOf(false)
var tasksOrgInstalled by mutableStateOf(false)
var openTasksInstalled by mutableStateOf(false)
init {
viewModelScope.launch {
packageChangedFlow(context).collect {
jtxInstalled = isInstalled(TaskProvider.ProviderName.JtxBoard.packageName)
tasksOrgInstalled = isInstalled(TaskProvider.ProviderName.TasksOrg.packageName)
openTasksInstalled = isInstalled(TaskProvider.ProviderName.OpenTasks.packageName)
}
}
}
private fun isInstalled(packageName: String): Boolean =
try {
context.packageManager.getPackageInfo(packageName, 0)
true
} catch (e: PackageManager.NameNotFoundException) {
false
}
fun selectProvider(provider: TaskProvider.ProviderName) = viewModelScope.launch(Dispatchers.Default) {
TaskUtils.selectProvider(context, provider)
}
}

View file

@ -0,0 +1,240 @@
package at.bitfire.davdroid.ui
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.text.HtmlCompat
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.UiUtils.toAnnotatedString
import at.bitfire.davdroid.ui.composable.BasicTopAppBar
import at.bitfire.davdroid.ui.composable.CardWithImage
import at.bitfire.davdroid.ui.composable.RadioWithSwitch
import at.bitfire.davdroid.ui.widget.ClickableTextWithLink
import at.bitfire.ical4android.TaskProvider
import kotlinx.coroutines.launch
@Composable
fun TasksScreen(onNavUp: () -> Unit) {
AppTheme {
Scaffold(
topBar = {
BasicTopAppBar(
titleStringRes = R.string.intro_tasks_title,
onNavigateUp = onNavUp
)
}
) { paddingValues ->
Box(Modifier.padding(paddingValues)) {
TasksCard()
}
}
}
}
@Composable
fun TasksCard(
model: TasksModel = viewModel()
) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
val jtxInstalled = model.jtxInstalled
val jtxSelected by model.jtxSelected.collectAsStateWithLifecycle(false)
val tasksOrgInstalled = model.tasksOrgInstalled
val tasksOrgSelected by model.tasksOrgSelected.collectAsStateWithLifecycle(false)
val openTasksInstalled = model.openTasksInstalled
val openTasksSelected by model.openTasksSelected.collectAsStateWithLifecycle(false)
val showAgain by model.showAgain.collectAsStateWithLifecycle(true)
TasksCard(
jtxSelected = jtxSelected,
jtxInstalled = jtxInstalled,
tasksOrgSelected = tasksOrgSelected,
tasksOrgInstalled = tasksOrgInstalled,
openTasksSelected = openTasksSelected,
openTasksInstalled = openTasksInstalled,
showAgain = showAgain,
onSetShowAgain = model::setShowAgain,
onProviderSelected = { provider ->
if (model.currentProvider.value != provider)
model.selectProvider(provider)
},
installApp = { packageName ->
val uri = Uri.parse("market://details?id=$packageName&referrer=" +
Uri.encode("utm_source=" + BuildConfig.APPLICATION_ID))
val intent = Intent(Intent.ACTION_VIEW, uri)
if (intent.resolveActivity(context.packageManager) != null)
context.startActivity(intent)
else
coroutineScope.launch {
snackbarHostState.showSnackbar(
message = context.getString(R.string.intro_tasks_no_app_store),
duration = SnackbarDuration.Long
)
}
}
)
}
@Composable
fun TasksCard(
jtxSelected: Boolean,
jtxInstalled: Boolean,
tasksOrgSelected: Boolean,
tasksOrgInstalled: Boolean,
openTasksSelected: Boolean,
openTasksInstalled: Boolean,
onProviderSelected: (TaskProvider.ProviderName) -> Unit = {},
installApp: (String) -> Unit = {},
showAgain: Boolean,
onSetShowAgain: (Boolean) -> Unit = {}
) {
Column(
modifier = Modifier
.fillMaxHeight()
.verticalScroll(rememberScrollState())
) {
CardWithImage(
image = painterResource(R.drawable.intro_tasks),
imageAlignment = BiasAlignment(0f, .1f),
title = stringResource(R.string.intro_tasks_title),
message = stringResource(R.string.intro_tasks_text1),
modifier = Modifier.padding(8.dp)
) {
RadioWithSwitch(
title = stringResource(R.string.intro_tasks_jtx),
summary = {
Text(stringResource(R.string.intro_tasks_jtx_info))
},
isSelected = jtxSelected,
isToggled = jtxInstalled,
enabled = jtxInstalled,
onSelected = { onProviderSelected(TaskProvider.ProviderName.JtxBoard) },
onToggled = { toggled ->
if (toggled) installApp(TaskProvider.ProviderName.JtxBoard.packageName)
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp)
)
RadioWithSwitch(
title = stringResource(R.string.intro_tasks_tasks_org),
summary = {
val summary = HtmlCompat.fromHtml(
stringResource(R.string.intro_tasks_tasks_org_info),
HtmlCompat.FROM_HTML_MODE_COMPACT
).toAnnotatedString()
ClickableTextWithLink(summary)
},
isSelected = tasksOrgSelected,
isToggled = tasksOrgInstalled,
enabled = tasksOrgInstalled,
onSelected = { onProviderSelected(TaskProvider.ProviderName.TasksOrg) },
onToggled = { toggled ->
if (toggled) installApp(TaskProvider.ProviderName.TasksOrg.packageName)
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp)
)
RadioWithSwitch(
title = stringResource(R.string.intro_tasks_opentasks),
summary = {
Text(stringResource(R.string.intro_tasks_opentasks_info))
},
isSelected = openTasksSelected,
isToggled = openTasksInstalled,
enabled = openTasksInstalled,
onSelected = { onProviderSelected(TaskProvider.ProviderName.OpenTasks) },
onToggled = { toggled ->
if (toggled) installApp(TaskProvider.ProviderName.OpenTasks.packageName)
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp)
)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp)
) {
Checkbox(
checked = !showAgain,
onCheckedChange = { onSetShowAgain(!it) }
)
Text(
text = stringResource(R.string.intro_tasks_dont_show),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.fillMaxWidth()
.clickable { onSetShowAgain(!showAgain) }
)
}
}
Text(
text = stringResource(
R.string.intro_leave_unchecked,
stringResource(R.string.app_settings_reset_hints)
),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 12.dp, vertical = 8.dp)
)
}
}
@Preview(showBackground = true, showSystemUi = true)
@Composable
fun TasksCard_Preview() {
AppTheme {
TasksCard(
jtxSelected = true,
jtxInstalled = true,
tasksOrgSelected = false,
tasksOrgInstalled = false,
openTasksSelected = false,
openTasksInstalled = false,
showAgain = true
)
}
}

View file

@ -7,8 +7,8 @@ package at.bitfire.davdroid.ui.intro
import android.app.Application
import androidx.compose.runtime.Composable
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.TasksActivity
import at.bitfire.davdroid.ui.TasksCard
import at.bitfire.davdroid.ui.TasksModel
import at.bitfire.davdroid.util.TaskUtils
import javax.inject.Inject
@ -18,7 +18,7 @@ class TasksIntroPage @Inject constructor(
): IntroPage {
override fun getShowPolicy(): IntroPage.ShowPolicy {
return if (TaskUtils.isAvailable(application) || settingsManager.getBooleanOrNull(TasksActivity.Model.HINT_OPENTASKS_NOT_INSTALLED) == false)
return if (TaskUtils.isAvailable(application) || settingsManager.getBooleanOrNull(TasksModel.HINT_OPENTASKS_NOT_INSTALLED) == false)
IntroPage.ShowPolicy.DONT_SHOW
else
IntroPage.ShowPolicy.SHOW_ALWAYS