Skip to content

Commit

Permalink
feat: Bring settings back
Browse files Browse the repository at this point in the history
Change-Id: I8424bcc084e88f7dcef368a497799643b21fa492
  • Loading branch information
XayahSuSuSu committed Jan 28, 2024
1 parent 0223ce6 commit 4594d79
Show file tree
Hide file tree
Showing 11 changed files with 451 additions and 0 deletions.
1 change: 1 addition & 0 deletions source/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ dependencies {
"alphaImplementation"(project(":feature:flavor:alpha"))
"alphaImplementation"(project(":feature:flavor:foss"))
implementation(project(":feature:main:home"))
implementation(project(":feature:main:settings"))
implementation(project(":feature:main:packages"))
implementation(project(":feature:main:medium"))
implementation(project(":feature:main:directory"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.xayah.core.ui.util.currentRoute
import com.xayah.core.ui.util.fromString
import com.xayah.core.ui.util.value
import com.xayah.feature.main.home.PageHome
import com.xayah.feature.main.settings.PageSettings

@ExperimentalAnimationApi
@ExperimentalMaterial3Api
Expand Down Expand Up @@ -95,6 +96,7 @@ fun MainIndexGraph() {
composable(MainIndexRoutes.CloudAccount.route) {
}
composable(MainIndexRoutes.Settings.route) {
PageSettings()
}
}
}
Expand Down
1 change: 1 addition & 0 deletions source/feature/main/settings/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
23 changes: 23 additions & 0 deletions source/feature/main/settings/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
alias(libs.plugins.library.common)
alias(libs.plugins.library.hilt)
alias(libs.plugins.library.compose)
}

android {
namespace = "com.xayah.feature.main.settings"
}

dependencies {
// Core
implementation(project(":core:common"))
implementation(project(":core:ui"))
implementation(project(":core:datastore"))

// Compose Navigation
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.hilt.navigation.compose)

// Preferences DataStore
implementation(libs.androidx.datastore.preferences)
}
2 changes: 2 additions & 0 deletions source/feature/main/settings/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package com.xayah.feature.main.settings

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.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Switch
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import com.xayah.core.ui.component.BodySmallText
import com.xayah.core.ui.component.LabelSmallText
import com.xayah.core.ui.component.ModalStringListDropdownMenu
import com.xayah.core.ui.component.TitleMediumText
import com.xayah.core.ui.component.TitleSmallText
import com.xayah.core.ui.component.paddingEnd
import com.xayah.core.ui.component.paddingHorizontal
import com.xayah.core.ui.component.paddingStart
import com.xayah.core.ui.component.paddingTop
import com.xayah.core.ui.component.paddingVertical
import com.xayah.core.ui.material3.toColor
import com.xayah.core.ui.material3.tokens.ColorSchemeKeyTokens
import com.xayah.core.ui.model.ImageVectorToken
import com.xayah.core.ui.model.StringResourceToken
import com.xayah.core.ui.token.ModalMenuTokens
import com.xayah.core.ui.token.PaddingTokens
import com.xayah.core.ui.util.value

@Composable
fun SettingsInfo(modifier: Modifier = Modifier, info: SettingsInfoItem) {
Column(modifier = modifier) {
Icon(imageVector = info.icon.value, contentDescription = null)
CompositionLocalProvider(LocalContentColor provides ColorSchemeKeyTokens.OnSurfaceVariant.toColor()) {
LabelSmallText(
modifier = Modifier.paddingTop(PaddingTokens.Level1),
text = info.title.value,
color = if (info.onWarning) ColorSchemeKeyTokens.Error.toColor() else Color.Unspecified
)
}
TitleMediumText(
text = info.content.value,
color = if (info.onWarning) ColorSchemeKeyTokens.Error.toColor() else Color.Unspecified,
fontWeight = FontWeight.Bold
)
}
}

@Composable
fun SettingsTitle(modifier: Modifier = Modifier, title: StringResourceToken) {
TitleSmallText(
modifier = modifier.paddingHorizontal(PaddingTokens.Level7),
text = title.value,
color = ColorSchemeKeyTokens.Primary.toColor(),
fontWeight = FontWeight.Bold
)
}

@Composable
fun SettingsClickable(
modifier: Modifier = Modifier,
leadingContent: @Composable (() -> Unit)? = null,
headlineContent: @Composable () -> Unit,
supportingContent: @Composable (() -> Unit)? = null,
trailingContent: @Composable (() -> Unit)? = null,
onClick: () -> Unit,
) {
Row(
modifier = modifier
.clickable(onClick = onClick)
.paddingVertical(PaddingTokens.Level3)
.paddingEnd(PaddingTokens.Level3),
verticalAlignment = Alignment.CenterVertically
) {
Box(modifier = Modifier.width(PaddingTokens.Level7), contentAlignment = Alignment.Center) {
leadingContent?.invoke()
}
Column(modifier = Modifier.weight(1f)) {
headlineContent.invoke()
supportingContent?.let { content ->
CompositionLocalProvider(LocalContentColor provides ColorSchemeKeyTokens.OnSurfaceVariant.toColor(), content = content)
}
}
trailingContent?.invoke()
}
}

@Composable
fun SettingsSwitch(
modifier: Modifier = Modifier,
icon: ImageVectorToken? = null,
title: StringResourceToken,
content: StringResourceToken,
checked: Boolean = false,
onCheckedChange: () -> Unit,
) {
SettingsClickable(
modifier = modifier,
leadingContent = {
icon?.let { Icon(imageVector = it.value, contentDescription = null) }
},
headlineContent = {
TitleMediumText(text = title.value)
},
supportingContent = {
BodySmallText(text = content.value, fontWeight = FontWeight.Bold)
},
trailingContent = {
Switch(modifier = Modifier.paddingStart(PaddingTokens.Level3), checked = checked, onCheckedChange = {
onCheckedChange()
})
}
) {
onCheckedChange()
}
}

@Composable
fun SettingsModalDropdownMenu(
modifier: Modifier = Modifier,
icon: ImageVectorToken? = null,
title: StringResourceToken,
content: StringResourceToken,
selected: String,
selectedIndex: Int = 0,
list: List<String>,
onClick: (() -> Unit)? = null,
onSelected: (index: Int, selected: String) -> Unit,
) {
var expanded by remember { mutableStateOf(false) }

SettingsClickable(
modifier = modifier,
leadingContent = {
icon?.let { Icon(imageVector = it.value, contentDescription = null) }
},
headlineContent = {
TitleMediumText(text = title.value)
},
supportingContent = {
BodySmallText(text = content.value, fontWeight = FontWeight.Bold)
},
trailingContent = {
Box(modifier = Modifier.wrapContentSize(Alignment.Center)) {
TitleMediumText(modifier = Modifier.paddingStart(PaddingTokens.Level3), text = selected)

ModalStringListDropdownMenu(
expanded = expanded,
selectedIndex = selectedIndex,
list = list,
maxDisplay = ModalMenuTokens.DefaultMaxDisplay,
onSelected = { index, selected ->
expanded = false
onSelected(index, selected)
},
onDismissRequest = { expanded = false }
)
}
}
) {
expanded = true
onClick?.invoke()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package com.xayah.feature.main.settings

import android.os.Build
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
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.icons.Icons
import androidx.compose.material.icons.rounded.Link
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedCard
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.xayah.core.datastore.readBackupItself
import com.xayah.core.datastore.readCleanRestoring
import com.xayah.core.datastore.readCompatibleMode
import com.xayah.core.datastore.readCompressionTest
import com.xayah.core.datastore.readFollowSymlinks
import com.xayah.core.datastore.readMonet
import com.xayah.core.datastore.saveBackupItself
import com.xayah.core.datastore.saveCleanRestoring
import com.xayah.core.datastore.saveCompatibleMode
import com.xayah.core.datastore.saveCompressionTest
import com.xayah.core.datastore.saveFollowSymlinks
import com.xayah.core.datastore.saveMonet
import com.xayah.core.ui.component.VerticalGrid
import com.xayah.core.ui.component.paddingHorizontal
import com.xayah.core.ui.component.paddingVertical
import com.xayah.core.ui.model.ImageVectorToken
import com.xayah.core.ui.model.StringResourceToken
import com.xayah.core.ui.token.PaddingTokens
import com.xayah.core.ui.util.fromDrawable
import com.xayah.core.ui.util.fromStringId
import com.xayah.core.ui.util.fromVector
import kotlinx.coroutines.runBlocking
import com.xayah.core.ui.R as UiR

@ExperimentalAnimationApi
@ExperimentalMaterial3Api
@Composable
fun PageSettings() {
val viewModel = hiltViewModel<IndexViewModel>()
val uiState by viewModel.uiState.collectAsStateWithLifecycle()

Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
Spacer(modifier = Modifier.paddingVertical(PaddingTokens.Level3))
InfoCard(uiState.settingsInfoItems)
Divider(modifier = Modifier.padding(PaddingTokens.Level3))
ApplicationSettings()
SettingsTitle(modifier = Modifier.paddingVertical(PaddingTokens.Level3), title = StringResourceToken.fromStringId(R.string.backup))
BackupSettings()
SettingsTitle(modifier = Modifier.paddingVertical(PaddingTokens.Level3), title = StringResourceToken.fromStringId(R.string.restore))
RestoreSettings()
Spacer(modifier = Modifier.paddingVertical(PaddingTokens.Level3))
}
}

@Composable
private fun RestoreSettings() {
val context = LocalContext.current
val cleanRestoring by context.readCleanRestoring().collectAsState(initial = true)
SettingsSwitch(
icon = ImageVectorToken.fromDrawable(UiR.drawable.ic_rounded_mop),
title = StringResourceToken.fromStringId(R.string.clean_restoring),
content = StringResourceToken.fromStringId(R.string.clean_restoring_desc),
checked = cleanRestoring,
) {
runBlocking { context.saveCleanRestoring(cleanRestoring.not()) }
}
}

@Composable
private fun BackupSettings() {
val context = LocalContext.current
val backupItself by context.readBackupItself().collectAsState(initial = true)
SettingsSwitch(
icon = ImageVectorToken.fromDrawable(UiR.drawable.ic_rounded_join_inner),
title = StringResourceToken.fromStringId(R.string.backup_itself),
content = StringResourceToken.fromStringId(R.string.backup_itself_desc),
checked = backupItself,
) {
runBlocking { context.saveBackupItself(backupItself.not()) }
}
val compressionTest by context.readCompressionTest().collectAsState(initial = true)
SettingsSwitch(
icon = ImageVectorToken.fromDrawable(UiR.drawable.ic_rounded_layers),
title = StringResourceToken.fromStringId(R.string.compression_test),
content = StringResourceToken.fromStringId(R.string.compression_test_desc),
checked = compressionTest
) {
runBlocking { context.saveCompressionTest(compressionTest.not()) }
}
val compatibleMode by context.readCompatibleMode().collectAsState(initial = true)
SettingsSwitch(
icon = ImageVectorToken.fromDrawable(UiR.drawable.ic_rounded_build),
title = StringResourceToken.fromStringId(R.string.compatible_mode),
content = StringResourceToken.fromStringId(R.string.compatible_mode_desc),
checked = compatibleMode
) {
runBlocking { context.saveCompatibleMode(compatibleMode.not()) }
}
val followSymlinks by context.readFollowSymlinks().collectAsState(initial = true)
SettingsSwitch(
icon = ImageVectorToken.fromVector(Icons.Rounded.Link),
title = StringResourceToken.fromStringId(R.string.follow_symlinks),
content = StringResourceToken.fromStringId(R.string.follow_symlinks_desc),
checked = followSymlinks
) {
runBlocking { context.saveFollowSymlinks(followSymlinks.not()) }
}
}

@Composable
private fun ApplicationSettings() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val context = LocalContext.current
val monet by context.readMonet().collectAsState(initial = true)
SettingsSwitch(
icon = ImageVectorToken.fromDrawable(UiR.drawable.ic_round_auto_awesome),
title = StringResourceToken.fromStringId(R.string.monet),
checked = monet,
content = StringResourceToken.fromStringId(R.string.monet_desc)
) {
runBlocking { context.saveMonet(monet.not()) }
}
}
}

@Composable
private fun InfoCard(items: List<SettingsInfoItem>) {
OutlinedCard(
modifier = Modifier
.fillMaxWidth()
.paddingHorizontal(PaddingTokens.Level3)
) {
VerticalGrid(columns = 2, count = items.size) { index ->
SettingsInfo(
modifier = Modifier
.padding(PaddingTokens.Level3)
.fillMaxSize()
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null
) { if (items[index].onClick != null) items[index].onClick!!.invoke() },
info = items[index]
)
}
}
}
Loading

0 comments on commit 4594d79

Please sign in to comment.