Skip to content

Commit af084fb

Browse files
authored
Add "Backups reminder" intro screen (#1937)
* Add BackupsPage to intro UI * Add BackupsPage UI - Implement BackupsPage composable with UI elements - Add strings for backups reminder and acceptance * Add to "Reset hints" * Add another paragraph * Update backup screen hints - Update backups reminder text - Remove redundant versioning note - Update acceptance message
1 parent 47685e6 commit af084fb

File tree

4 files changed

+146
-2
lines changed

4 files changed

+146
-2
lines changed

app/src/main/kotlin/at/bitfire/davdroid/ui/AppSettingsModel.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import at.bitfire.davdroid.repository.PreferenceRepository
2020
import at.bitfire.davdroid.settings.Settings
2121
import at.bitfire.davdroid.settings.SettingsManager
2222
import at.bitfire.davdroid.sync.TasksAppManager
23+
import at.bitfire.davdroid.ui.intro.BackupsPage
2324
import at.bitfire.davdroid.ui.intro.BatteryOptimizationsPageModel
2425
import at.bitfire.davdroid.ui.intro.OpenSourcePage
2526
import at.bitfire.davdroid.util.PermissionUtils
@@ -33,6 +34,7 @@ import kotlinx.coroutines.flow.asStateFlow
3334
import kotlinx.coroutines.flow.map
3435
import kotlinx.coroutines.flow.stateIn
3536
import kotlinx.coroutines.launch
37+
import kotlinx.coroutines.runBlocking
3638
import javax.inject.Inject
3739

3840
@HiltViewModel
@@ -98,11 +100,12 @@ class AppSettingsModel @Inject constructor(
98100
UiUtils.updateTheme(context)
99101
}
100102

101-
fun resetHints() {
103+
fun resetHints() = runBlocking(ioDispatcher) {
104+
settings.remove(BackupsPage.Model.SETTING_BACKUPS_ACCEPTED)
102105
settings.remove(BatteryOptimizationsPageModel.HINT_BATTERY_OPTIMIZATIONS)
103106
settings.remove(BatteryOptimizationsPageModel.HINT_AUTOSTART_PERMISSION)
104-
settings.remove(TasksModel.HINT_OPENTASKS_NOT_INSTALLED)
105107
settings.remove(OpenSourcePage.Model.SETTING_NEXT_DONATION_POPUP)
108+
settings.remove(TasksModel.HINT_OPENTASKS_NOT_INSTALLED)
106109
}
107110

108111

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
3+
*/
4+
5+
package at.bitfire.davdroid.ui.intro
6+
7+
import androidx.compose.foundation.clickable
8+
import androidx.compose.foundation.layout.Column
9+
import androidx.compose.foundation.layout.Row
10+
import androidx.compose.foundation.layout.fillMaxSize
11+
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.rememberScrollState
13+
import androidx.compose.foundation.verticalScroll
14+
import androidx.compose.material.icons.Icons
15+
import androidx.compose.material.icons.outlined.Backup
16+
import androidx.compose.material3.Checkbox
17+
import androidx.compose.material3.MaterialTheme
18+
import androidx.compose.material3.Text
19+
import androidx.compose.runtime.Composable
20+
import androidx.compose.runtime.getValue
21+
import androidx.compose.ui.Alignment
22+
import androidx.compose.ui.Modifier
23+
import androidx.compose.ui.res.stringResource
24+
import androidx.compose.ui.tooling.preview.Preview
25+
import androidx.compose.ui.unit.dp
26+
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
27+
import androidx.lifecycle.ViewModel
28+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
29+
import at.bitfire.davdroid.R
30+
import at.bitfire.davdroid.settings.SettingsManager
31+
import at.bitfire.davdroid.ui.AppTheme
32+
import at.bitfire.davdroid.ui.composable.CardWithImage
33+
import dagger.hilt.android.lifecycle.HiltViewModel
34+
import javax.inject.Inject
35+
36+
class BackupsPage @Inject constructor(
37+
val settingsManager: SettingsManager
38+
): IntroPage() {
39+
40+
override fun getShowPolicy(): ShowPolicy =
41+
if (Model.backupsAccepted(settingsManager))
42+
ShowPolicy.DONT_SHOW
43+
else
44+
ShowPolicy.SHOW_ALWAYS
45+
46+
@Composable
47+
override fun ComposePage() {
48+
val model = hiltViewModel<Model>()
49+
val accepted by model.backupsAcceptedFlow.collectAsStateWithLifecycle(false)
50+
BackupsPage(
51+
accepted = accepted,
52+
updateAccepted = model::setBackupsAccepted
53+
)
54+
}
55+
56+
57+
@HiltViewModel
58+
class Model @Inject constructor(
59+
private val settings: SettingsManager
60+
): ViewModel() {
61+
62+
val backupsAcceptedFlow = settings.getBooleanFlow(SETTING_BACKUPS_ACCEPTED, false)
63+
64+
fun setBackupsAccepted(accepted: Boolean) {
65+
settings.putBoolean(SETTING_BACKUPS_ACCEPTED, accepted)
66+
}
67+
68+
companion object {
69+
70+
/** boolean setting (default: false) */
71+
const val SETTING_BACKUPS_ACCEPTED = "intro_backups_accepted"
72+
73+
fun backupsAccepted(settingsManager: SettingsManager): Boolean =
74+
settingsManager.getBooleanOrNull(SETTING_BACKUPS_ACCEPTED) ?: false
75+
76+
}
77+
78+
}
79+
80+
}
81+
82+
@Composable
83+
fun BackupsPage(
84+
accepted: Boolean,
85+
updateAccepted: (Boolean) -> Unit
86+
) {
87+
Column(
88+
modifier = Modifier
89+
.fillMaxSize()
90+
.verticalScroll(rememberScrollState())
91+
.padding(8.dp)
92+
) {
93+
CardWithImage(
94+
title = stringResource(R.string.intro_backups_title),
95+
icon = Icons.Outlined.Backup,
96+
modifier = Modifier.padding(vertical = 8.dp)
97+
) {
98+
Text(
99+
text = stringResource(R.string.intro_backups_important),
100+
modifier = Modifier.padding(bottom = 8.dp)
101+
)
102+
Text(
103+
text = stringResource(R.string.intro_backups_something_wrong, stringResource(R.string.app_name))
104+
)
105+
106+
Row(
107+
verticalAlignment = Alignment.CenterVertically,
108+
modifier = Modifier.padding(top = 8.dp, bottom = 16.dp)
109+
) {
110+
Checkbox(
111+
checked = accepted,
112+
onCheckedChange = updateAccepted
113+
)
114+
Text(
115+
text = stringResource(R.string.intro_backups_accept),
116+
style = MaterialTheme.typography.bodyLarge,
117+
modifier = Modifier
118+
.clickable { updateAccepted(!accepted) }
119+
.padding(start = 8.dp)
120+
)
121+
}
122+
}
123+
}
124+
}
125+
126+
@Preview
127+
@Composable
128+
fun BackupsPagePreview() {
129+
AppTheme {
130+
BackupsPage(
131+
accepted = true,
132+
updateAccepted = {}
133+
)
134+
}
135+
}

app/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
<string name="intro_tasks_tasks_org_info"><![CDATA[Some features <a href="https://www.davx5.com/faq/tasks/advanced-task-features">are not supported</a>.]]></string>
5959
<string name="intro_tasks_no_app_store">No app store available</string>
6060
<string name="intro_tasks_dont_show">I don\'t need tasks support.*</string>
61+
<string name="intro_backups_title">Backups reminder</string>
62+
<string name="intro_backups_important">It\'s important to back up your data (including contacts and calendars) regularly to prevent potential data loss.</string>
63+
<string name="intro_backups_something_wrong">Something can always go wrong, whether on the server, within %s, or in other apps, which for instance might accidentally delete all calendar entries. (The deletions would then be synchronized to the server.)</string>
64+
<string name="intro_backups_accept">I already have a working backup strategy or I don\'t need one.</string>
6165
<string name="intro_open_source_title">Open-source software</string>
6266
<string name="intro_open_source_text">We\'re happy that you use %s, which is open-source software. Development, maintenance and support are hard work. Please consider contributing (there are many ways) or a donation. It would be highly appreciated!</string>
6367
<string name="intro_open_source_details">How to contribute/donate</string>

app/src/ose/kotlin/at/bitfire/davdroid/ui/intro/OseIntroPageFactory.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package at.bitfire.davdroid.ui.intro
77
import javax.inject.Inject
88

99
class OseIntroPageFactory @Inject constructor(
10+
backupsPage: BackupsPage,
1011
batteryOptimizationsPage: BatteryOptimizationsPage,
1112
openSourcePage: OpenSourcePage,
1213
permissionsIntroPage: PermissionsIntroPage,
@@ -18,6 +19,7 @@ class OseIntroPageFactory @Inject constructor(
1819
tasksIntroPage,
1920
permissionsIntroPage,
2021
batteryOptimizationsPage,
22+
backupsPage,
2123
openSourcePage
2224
)
2325

0 commit comments

Comments
 (0)