Skip to content

Commit

Permalink
Added cards for permission requesting
Browse files Browse the repository at this point in the history
Signed-off-by: Arnau Mora <[email protected]>
  • Loading branch information
ArnyminerZ committed Aug 21, 2023
1 parent d89c3f4 commit 8ad10d9
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 72 deletions.
148 changes: 76 additions & 72 deletions app/src/main/java/at/bitfire/icsdroid/ui/CalendarListActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ import android.view.*
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
Expand Down Expand Up @@ -47,11 +45,13 @@ import at.bitfire.icsdroid.R
import at.bitfire.icsdroid.db.AppDatabase
import at.bitfire.icsdroid.ui.dialog.SyncIntervalDialog
import at.bitfire.icsdroid.ui.list.CalendarListItem
import at.bitfire.icsdroid.ui.reusable.ActionCard
import com.google.accompanist.themeadapter.material.MdcTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.*

@OptIn(ExperimentalFoundationApi::class)
class CalendarListActivity: AppCompatActivity() {

companion object {
Expand Down Expand Up @@ -153,12 +153,84 @@ class CalendarListActivity: AppCompatActivity() {

val subscriptions by model.subscriptions.observeAsState()

val askForCalendarPermission by model.askForCalendarPermission.observeAsState(false)
val askForNotificationPermission by model.askForNotificationPermission.observeAsState(false)
val askForWhitelisting by model.askForWhitelisting.observeAsState(false)

Box(
modifier = Modifier
.padding(paddingValues)
.pullRefresh(pullRefreshState)
) {
LazyColumn(Modifier.fillMaxSize()) {
// Calendar permission card
if (askForCalendarPermission) {
item(key = "calendar-perm") {
ActionCard(
title = stringResource(R.string.calendar_permissions_required),
message = stringResource(R.string.calendar_permissions_required_text),
actionText = stringResource(R.string.permissions_grant),
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.animateItemPlacement()
) {
requestCalendarPermissions()
}
}
}

// Notification permission card
if (askForNotificationPermission) {
item(key = "notification-perm") {
ActionCard(
title = stringResource(R.string.notification_permissions_required),
message = stringResource(R.string.notification_permissions_required_text),
actionText = stringResource(R.string.permissions_grant),
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.animateItemPlacement()
) {
requestNotificationPermission()
}
}
}

// Whitelisting card
if (askForWhitelisting && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
item(key = "battery-whitelisting") {
ActionCard(
title = stringResource(R.string.calendar_list_battery_whitelist),
message = stringResource(R.string.calendar_list_battery_whitelist_text),
actionText = stringResource(R.string.permissions_grant),
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.animateItemPlacement()
) {
val intent = Intent(
android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS
)
startActivity(intent)
}
}
}

if (subscriptions?.isEmpty() == true) {
item(key = "empty") {
Text(
text = stringResource(R.string.calendar_list_empty_info),
style = MaterialTheme.typography.body1,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 12.dp)
.animateItemPlacement()
)
}
}

items(subscriptions ?: emptyList()) { subscription ->
CalendarListItem(subscription = subscription, onClick = {
val intent = Intent(context, EditCalendarActivity::class.java)
Expand All @@ -168,22 +240,6 @@ class CalendarListActivity: AppCompatActivity() {
}
}

AnimatedVisibility(
visible = subscriptions?.isEmpty() == true,
enter = fadeIn(),
exit = fadeOut(),
modifier = Modifier
.align(Alignment.Center)
.fillMaxWidth()
.padding(horizontal = 12.dp)
) {
Text(
text = stringResource(R.string.calendar_list_empty_info),
style = MaterialTheme.typography.body1,
textAlign = TextAlign.Center
)
}

PullRefreshIndicator(
refreshing = isRefreshing,
state = pullRefreshState,
Expand Down Expand Up @@ -269,56 +325,6 @@ class CalendarListActivity: AppCompatActivity() {
}


/**
* Checks the current settings and permissions state, and shows a Snackbar using
* [snackBarHostState] if any action is necessary.
*
* Blocks the current thread until the Snackbar is hidden, or the action to be performed is
* completed.
*/
@Deprecated("TODO Logic like permissions should be moved to Model; permanent warnings should be shown as regular box above the subscriptions instead of a Snackbar")
private suspend fun checkSyncSettings() {
/*when {
// notification permissions are granted
!PermissionUtils.haveNotificationPermission(this) -> {
val response = snackBarHostState.showSnackbar(
message = getString(R.string.notification_permissions_required),
actionLabel = getString(R.string.permissions_grant),
duration = SnackbarDuration.Indefinite
)
if (response == SnackbarResult.ActionPerformed)
requestNotificationPermission()
}
// calendar permissions are granted
!PermissionUtils.haveCalendarPermissions(this) -> {
val response = snackBarHostState.showSnackbar(
message = getString(R.string.calendar_permissions_required),
actionLabel = getString(R.string.permissions_grant),
duration = SnackbarDuration.Indefinite
)
if (response == SnackbarResult.ActionPerformed)
requestCalendarPermissions()
}
// periodic sync enabled AND Android >= 6 AND not whitelisted from battery saving AND sync interval < 1 day
Build.VERSION.SDK_INT >= 23 &&
!(getSystemService(Context.POWER_SERVICE) as PowerManager).isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID) &&
AppAccount.syncInterval(this) < 86400 -> {
val response = snackBarHostState.showSnackbar(
message = getString(R.string.calendar_list_battery_whitelist),
actionLabel = getString(R.string.permissions_grant),
duration = SnackbarDuration.Indefinite
)
if (response == SnackbarResult.ActionPerformed) {
val intent = Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
startActivity(intent)
}
}
}*/
}


/* actions */

private fun onRefreshRequested() {
Expand All @@ -335,13 +341,11 @@ class CalendarListActivity: AppCompatActivity() {

class SubscriptionsModel(application: Application): AndroidViewModel(application) {

// TODO
val askForCalendarPermission = MutableLiveData(false)
val askForNotificationPermission = MutableLiveData(false)

// TODO
val askForWhitelisting = MutableLiveData(false)


/** whether there are running sync workers */
val isRefreshing = SyncWorker.liveStatus(application).map { workInfos ->
Expand Down
65 changes: 65 additions & 0 deletions app/src/main/java/at/bitfire/icsdroid/ui/reusable/ActionCard.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package at.bitfire.icsdroid.ui.reusable

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

/**
* Provides a card with a title, a description, and a button for performing an action.
*/
@Composable
fun ActionCard(
title: String,
message: String,
actionText: String,
modifier: Modifier = Modifier,
onAction: () -> Unit
) {
Card(
modifier = modifier,
elevation = 3.dp
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
) {
Text(
text = title,
modifier = Modifier.fillMaxWidth(),
style = MaterialTheme.typography.h6
)
Text(
text = message,
modifier = Modifier.fillMaxWidth(),
style = MaterialTheme.typography.body2
)
TextButton(
onClick = onAction,
modifier = Modifier.align(Alignment.End)
) {
Text(text = actionText)
}
}
}
}

@Preview(showBackground = true)
@Composable
fun ActionCard_Preview() {
ActionCard(
title = "Testing Card",
message = "This is the message shown in the card. Can be pretty long",
actionText = "Action",
onAction = {}
)
}

0 comments on commit 8ad10d9

Please sign in to comment.