Add Terms of Service and Privacy Policy

This commit is contained in:
Ash
2022-04-06 18:14:44 +08:00
parent aca2e9c41b
commit 4f7ebb7958
12 changed files with 350 additions and 62 deletions
@@ -3,10 +3,7 @@ package me.ash.reader.ui.ext
import android.content.Context
import android.util.Log
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.*
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first
@@ -15,6 +12,8 @@ import kotlinx.coroutines.runBlocking
import java.io.IOException
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
val Context.isFirstLaunch: Boolean
get() = this.dataStore.get(DataStoreKeys.IsFirstLaunch) ?: true
val Context.currentAccountId: Int
get() = this.dataStore.get(DataStoreKeys.CurrentAccountId)!!
val Context.currentAccountType: Int
@@ -46,6 +45,11 @@ fun <T> DataStore<Preferences>.get(dataStoreKeys: DataStoreKeys<T>): T? {
sealed class DataStoreKeys<T> {
abstract val key: Preferences.Key<T>
object IsFirstLaunch : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("isFirstLaunch")
}
object CurrentAccountId : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int>
get() = intPreferencesKey("currentAccountId")
@@ -11,6 +11,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import com.google.accompanist.insets.ProvideWindowInsets
import com.google.accompanist.insets.navigationBarsHeight
import com.google.accompanist.insets.statusBarsPadding
@@ -18,13 +19,16 @@ import com.google.accompanist.navigation.animation.AnimatedNavHost
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import me.ash.reader.ui.ext.animatedComposable
import me.ash.reader.ui.ext.isFirstLaunch
import me.ash.reader.ui.page.home.HomePage
import me.ash.reader.ui.page.settings.SettingsPage
import me.ash.reader.ui.page.startup.StartupPage
import me.ash.reader.ui.theme.AppTheme
@OptIn(ExperimentalAnimationApi::class, androidx.compose.material.ExperimentalMaterialApi::class)
@Composable
fun HomeEntry() {
val context = LocalContext.current
val navController = rememberAnimatedNavController()
AppTheme {
@@ -42,8 +46,11 @@ fun HomeEntry() {
) {
AnimatedNavHost(
navController = navController,
startDestination = RouteName.HOME,
startDestination = if (context.isFirstLaunch) RouteName.STARTUP else RouteName.HOME,
) {
animatedComposable(route = RouteName.STARTUP) {
StartupPage(navController)
}
animatedComposable(route = RouteName.HOME) {
HomePage(navController)
}
@@ -1,6 +1,7 @@
package me.ash.reader.ui.page.common
object RouteName {
const val STARTUP = "startup"
const val HOME = "home"
const val FEED = "feed"
const val ARTICLE = "article"
@@ -1,7 +1,8 @@
package me.ash.reader.ui.page.settings
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.*
@@ -9,22 +10,15 @@ import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material.icons.rounded.Close
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import me.ash.reader.R
import me.ash.reader.ui.component.Banner
import me.ash.reader.ui.component.DisplayText
import me.ash.reader.ui.component.FeedbackIconButton
import me.ash.reader.ui.component.SelectableSettingGroupItem
import me.ash.reader.ui.ext.paddingFixedHorizontal
import me.ash.reader.ui.ext.roundClick
import me.ash.reader.ui.page.common.RouteName
@OptIn(ExperimentalMaterial3Api::class)
@@ -108,48 +102,3 @@ fun SettingsPage(
}
)
}
@Composable
fun SettingsItem(
title: String = "",
description: String = "",
imageVector: ImageVector,
) {
Row(modifier = Modifier
.fillMaxWidth()
.roundClick { }
) {
Row(
modifier = Modifier.paddingFixedHorizontal(top = 16.dp, bottom = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(modifier = Modifier.width(4.dp))
Icon(
imageVector = imageVector,
contentDescription = title,
tint = MaterialTheme.colorScheme.onPrimaryContainer,
)
Spacer(modifier = Modifier.width(20.dp))
Column {
Text(
text = title,
fontSize = 20.sp,
color = MaterialTheme.colorScheme.onPrimaryContainer,
)
Text(
text = description,
color = MaterialTheme.colorScheme.outline,
)
}
}
}
}
@Preview
@Composable
fun SettingsPreview() {
Row(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) {
SettingsPage(navController = NavHostController(LocalContext.current))
}
}
@@ -0,0 +1,137 @@
package me.ash.reader.ui.page.startup
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.rounded.CheckCircleOutline
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
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.unit.dp
import androidx.navigation.NavHostController
import com.ireward.htmlcompose.HtmlText
import kotlinx.coroutines.launch
import me.ash.reader.R
import me.ash.reader.ui.component.DisplayText
import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put
import me.ash.reader.ui.page.common.RouteName
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun StartupPage(
navController: NavHostController,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
Scaffold(
modifier = Modifier.background(MaterialTheme.colorScheme.surface),
topBar = {},
content = {
LazyColumn {
item {
Spacer(modifier = Modifier.height(64.dp))
DisplayText(text = stringResource(R.string.welcome), desc = "")
}
item {
Spacer(modifier = Modifier.height(16.dp))
Image(
modifier = Modifier.padding(horizontal = 16.dp),
painter = painterResource(id = R.drawable.welcome),
contentDescription = stringResource(R.string.welcome),
)
}
item {
TipsItem(
modifier = Modifier
.padding(horizontal = 24.dp)
.padding(top = 40.dp)
)
}
item {
Spacer(modifier = Modifier.height(10.dp))
TextButton(
modifier = Modifier.padding(horizontal = 12.dp),
onClick = {
context.let {
it.startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(it.getString(R.string.terms_link))
)
)
}
}
) {
HtmlText(
text = stringResource(R.string.view_terms),
style = MaterialTheme.typography.bodySmall.copy(
color = MaterialTheme.colorScheme.outline,
),
)
}
Spacer(modifier = Modifier.height(100.dp))
}
}
},
bottomBar = {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
ExtendedFloatingActionButton(
onClick = {
navController.navigate(route = RouteName.HOME)
scope.launch {
context.dataStore.put(DataStoreKeys.IsFirstLaunch, false)
}
},
icon = {
Icon(
Icons.Rounded.CheckCircleOutline,
stringResource(R.string.agree_and_continue)
)
},
text = { Text(text = stringResource(R.string.agree_and_continue)) },
)
}
}
)
}
@Composable
private fun TipsItem(
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxWidth()
) {
Icon(
imageVector = Icons.Outlined.Info,
contentDescription = stringResource(R.string.tips_and_support),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
Spacer(modifier = Modifier.height(22.dp))
Text(
text = stringResource(R.string.agree_terms),
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}