mirror of
https://github.com/AllanWang/Frost-for-Facebook.git
synced 2024-11-08 20:12:39 +01:00
Merge pull request #1951 from AllanWang/settings
This commit is contained in:
commit
f0b833e741
@ -190,6 +190,7 @@ dependencies {
|
|||||||
implementation("androidx.compose.ui:ui:${composeVersion}")
|
implementation("androidx.compose.ui:ui:${composeVersion}")
|
||||||
implementation("androidx.activity:activity-compose:1.7.2")
|
implementation("androidx.activity:activity-compose:1.7.2")
|
||||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
|
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
|
||||||
|
implementation("androidx.navigation:navigation-compose:2.6.0")
|
||||||
// Tooling support (Previews, etc.)
|
// Tooling support (Previews, etc.)
|
||||||
implementation("androidx.compose.ui:ui-tooling:${composeVersion}")
|
implementation("androidx.compose.ui:ui-tooling:${composeVersion}")
|
||||||
// Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
|
// Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Allan Wang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.pitchedapps.frost.compose
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.graphics.Color
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalInspectionMode
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
|
||||||
|
/** Wrapper used for compose previews */
|
||||||
|
@Composable
|
||||||
|
fun FrostPreview(content: @Composable () -> Unit) {
|
||||||
|
val isPreview = LocalInspectionMode.current
|
||||||
|
val activity = LocalContext.current as Activity
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
if (!isPreview) {
|
||||||
|
println("FrostPreview is in use")
|
||||||
|
}
|
||||||
|
val window = activity.window
|
||||||
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
window.statusBarColor = Color.TRANSPARENT
|
||||||
|
window.navigationBarColor = Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
FrostTheme(isDarkTheme = true, content = content)
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Allan Wang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.pitchedapps.frost.compose.settings
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic state container for settings.
|
||||||
|
*
|
||||||
|
* Allows for getting and assigning values. It is expected that assigning values will cause
|
||||||
|
* recompositions as needed.
|
||||||
|
*/
|
||||||
|
interface SettingState<T> {
|
||||||
|
val enabled: Boolean
|
||||||
|
var value: T
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Allan Wang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.pitchedapps.frost.compose.settings
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
|
||||||
|
@DslMarker annotation class SettingsDslMarker
|
||||||
|
|
||||||
|
@SettingsDslMarker
|
||||||
|
interface SettingsDsl {
|
||||||
|
/** Entry point to avoid cluttering the global namespace. */
|
||||||
|
companion object : SettingsDsl
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dsl for creating individual entries in a list */
|
||||||
|
@SettingsDslMarker
|
||||||
|
interface SettingsListDsl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sub list with group title
|
||||||
|
*
|
||||||
|
* TODO support collapsed and/or shown?
|
||||||
|
*/
|
||||||
|
// fun group(title: String, enabled: Boolean = true, action: SettingsListDsl.() -> Unit)
|
||||||
|
|
||||||
|
/** Generic item without content */
|
||||||
|
fun item(
|
||||||
|
title: String,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
icon: ImageVector? = null,
|
||||||
|
description: String? = null,
|
||||||
|
onClick: (() -> Unit)? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Long, non clickable content */
|
||||||
|
fun description(text: String, icon: ImageVector? = null)
|
||||||
|
|
||||||
|
fun checkbox(
|
||||||
|
title: String,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
icon: ImageVector? = null,
|
||||||
|
description: String? = null,
|
||||||
|
checked: Boolean,
|
||||||
|
onCheckedChanged: (Boolean) -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun switch(
|
||||||
|
title: String,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
icon: ImageVector? = null,
|
||||||
|
description: String? = null,
|
||||||
|
checked: Boolean,
|
||||||
|
onCheckedChanged: (Boolean) -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun custom(
|
||||||
|
title: String,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
icon: ImageVector? = null,
|
||||||
|
description: String? = null,
|
||||||
|
onClick: (() -> Unit)? = null,
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Allan Wang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.pitchedapps.frost.compose.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import com.pitchedapps.frost.compose.FrostPreview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingsListDsl(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
content: @Composable SettingsListDsl.() -> Unit
|
||||||
|
) {
|
||||||
|
val items = SettingsDsl.settingsListDsl(content)
|
||||||
|
|
||||||
|
LazyColumn(modifier = modifier) { items(items) { compose -> compose() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SettingsListDslPreview() {
|
||||||
|
|
||||||
|
data class Model(
|
||||||
|
val check1: Boolean = false,
|
||||||
|
val switch1: Boolean = false,
|
||||||
|
val switch2: Boolean = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
var state by remember { mutableStateOf(Model()) }
|
||||||
|
|
||||||
|
FrostPreview {
|
||||||
|
SettingsListDsl {
|
||||||
|
checkbox(
|
||||||
|
title = "Check 1",
|
||||||
|
checked = state.check1,
|
||||||
|
onCheckedChanged = { state = state.copy(check1 = it) },
|
||||||
|
)
|
||||||
|
checkbox(
|
||||||
|
title = "Check 1",
|
||||||
|
description = "Linked again",
|
||||||
|
checked = state.check1,
|
||||||
|
onCheckedChanged = { state = state.copy(check1 = it) },
|
||||||
|
)
|
||||||
|
switch(
|
||||||
|
title = "Switch 1",
|
||||||
|
checked = state.switch1,
|
||||||
|
onCheckedChanged = { state = state.copy(switch1 = it) },
|
||||||
|
)
|
||||||
|
switch(
|
||||||
|
title = "Switch 2",
|
||||||
|
enabled = state.switch1,
|
||||||
|
description = "Enabled by switch 1",
|
||||||
|
checked = state.switch2,
|
||||||
|
onCheckedChanged = { state = state.copy(switch2 = it) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Allan Wang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.pitchedapps.frost.compose.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material.ContentAlpha
|
||||||
|
import androidx.compose.material.LocalContentAlpha
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Person
|
||||||
|
import androidx.compose.material3.Checkbox
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.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.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.pitchedapps.frost.compose.FrostPreview
|
||||||
|
import com.pitchedapps.frost.ext.optionalCompose
|
||||||
|
import com.pitchedapps.frost.ext.thenIf
|
||||||
|
|
||||||
|
/** Basic building block for settings */
|
||||||
|
@Composable
|
||||||
|
fun SettingsListItem(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
title: String,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
icon: ImageVector? = null,
|
||||||
|
description: String? = null,
|
||||||
|
onClick: (() -> Unit)? = null,
|
||||||
|
content: (@Composable () -> Unit)? = null
|
||||||
|
) {
|
||||||
|
val alpha = if (enabled) LocalContentAlpha.current else ContentAlpha.disabled
|
||||||
|
ListItem(
|
||||||
|
modifier =
|
||||||
|
modifier.thenIf(onClick != null) {
|
||||||
|
Modifier.clickable(enabled = enabled) { onClick?.invoke() }
|
||||||
|
},
|
||||||
|
leadingContent =
|
||||||
|
icon.optionalCompose {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(24.dp).alpha(alpha),
|
||||||
|
imageVector = it,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
headlineContent = { Text(modifier = Modifier.alpha(alpha), text = title) },
|
||||||
|
supportingContent =
|
||||||
|
description.optionalCompose {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.alpha(alpha),
|
||||||
|
text = it,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailingContent = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun SettingsListItemPreview() {
|
||||||
|
var state by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
FrostPreview {
|
||||||
|
SettingsListItem(
|
||||||
|
icon = Icons.Outlined.Person,
|
||||||
|
title = "Test Title",
|
||||||
|
description = "Test Description",
|
||||||
|
) {
|
||||||
|
Checkbox(
|
||||||
|
checked = state,
|
||||||
|
onCheckedChange = { state = it },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Allan Wang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.pitchedapps.frost.compose.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.Checkbox
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LazyListScope.settingsListDsl(content: @Composable SettingsListDsl.() -> Unit) {
|
||||||
|
val items = SettingsDsl.settingsListDsl(content)
|
||||||
|
items(items) { compose -> compose() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingsDsl.settingsListDsl(
|
||||||
|
content: @Composable SettingsListDsl.() -> Unit
|
||||||
|
): List<@Composable () -> Unit> {
|
||||||
|
val data = SettingsListDslData()
|
||||||
|
data.content()
|
||||||
|
return data.items
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SettingsListDslData : SettingsListDsl {
|
||||||
|
val items: MutableList<@Composable () -> Unit> = mutableListOf()
|
||||||
|
|
||||||
|
private fun addCompose(content: @Composable () -> Unit) {
|
||||||
|
items.add(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun item(
|
||||||
|
title: String,
|
||||||
|
enabled: Boolean,
|
||||||
|
icon: ImageVector?,
|
||||||
|
description: String?,
|
||||||
|
onClick: (() -> Unit)?
|
||||||
|
) {
|
||||||
|
addCompose {
|
||||||
|
SettingsListItem(
|
||||||
|
icon = icon,
|
||||||
|
title = title,
|
||||||
|
enabled = enabled,
|
||||||
|
description = description,
|
||||||
|
onClick = onClick,
|
||||||
|
content = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun description(text: String, icon: ImageVector?) {}
|
||||||
|
|
||||||
|
override fun checkbox(
|
||||||
|
title: String,
|
||||||
|
enabled: Boolean,
|
||||||
|
icon: ImageVector?,
|
||||||
|
description: String?,
|
||||||
|
checked: Boolean,
|
||||||
|
onCheckedChanged: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
custom(
|
||||||
|
icon = icon,
|
||||||
|
title = title,
|
||||||
|
enabled = enabled,
|
||||||
|
description = description,
|
||||||
|
onClick = { onCheckedChanged(!checked) },
|
||||||
|
) {
|
||||||
|
Checkbox(
|
||||||
|
enabled = enabled,
|
||||||
|
checked = checked,
|
||||||
|
onCheckedChange = onCheckedChanged,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun switch(
|
||||||
|
title: String,
|
||||||
|
enabled: Boolean,
|
||||||
|
icon: ImageVector?,
|
||||||
|
description: String?,
|
||||||
|
checked: Boolean,
|
||||||
|
onCheckedChanged: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
custom(
|
||||||
|
icon = icon,
|
||||||
|
title = title,
|
||||||
|
enabled = enabled,
|
||||||
|
description = description,
|
||||||
|
onClick = { onCheckedChanged(!checked) },
|
||||||
|
) {
|
||||||
|
Switch(
|
||||||
|
enabled = enabled,
|
||||||
|
checked = checked,
|
||||||
|
onCheckedChange = onCheckedChanged,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun custom(
|
||||||
|
title: String,
|
||||||
|
enabled: Boolean,
|
||||||
|
icon: ImageVector?,
|
||||||
|
description: String?,
|
||||||
|
onClick: (() -> Unit)?,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
addCompose {
|
||||||
|
SettingsListItem(
|
||||||
|
icon = icon,
|
||||||
|
title = title,
|
||||||
|
enabled = enabled,
|
||||||
|
description = description,
|
||||||
|
onClick = onClick,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,3 +34,13 @@ fun Offset.toIntOffset() = IntOffset(x.roundToInt(), y.roundToInt())
|
|||||||
fun IntSize.toDpSize(density: Density): DpSize {
|
fun IntSize.toDpSize(density: Density): DpSize {
|
||||||
return with(density) { DpSize(width.toDp(), height.toDp()) }
|
return with(density) { DpSize(width.toDp(), height.toDp()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for functions that take in nullable compose lambdas.
|
||||||
|
*
|
||||||
|
* If the input is null, return null. Otherwise, return the provided composable lambda.
|
||||||
|
*/
|
||||||
|
fun <T> T?.optionalCompose(action: @Composable (T) -> Unit): (@Composable () -> Unit)? {
|
||||||
|
if (this == null) return null
|
||||||
|
return { action(this) }
|
||||||
|
}
|
||||||
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Allan Wang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.pitchedapps.frost.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.ArrowBack
|
||||||
|
import androidx.compose.material.icons.outlined.Info
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MediumTopAppBar
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.navigation.NavBackStackEntry
|
||||||
|
import androidx.navigation.NavGraphBuilder
|
||||||
|
import androidx.navigation.compose.NavHost
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import com.pitchedapps.frost.R
|
||||||
|
import com.pitchedapps.frost.compose.FrostPreview
|
||||||
|
import com.pitchedapps.frost.settings.screens.MainSettingsScreen
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun SettingsScreen() {
|
||||||
|
val navController = rememberNavController()
|
||||||
|
|
||||||
|
val topBarScrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
MediumTopAppBar(
|
||||||
|
scrollBehavior = topBarScrollBehavior,
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {}) {
|
||||||
|
Icon(imageVector = Icons.Outlined.ArrowBack, contentDescription = null)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = {
|
||||||
|
val entry by navController.currentBackStackEntryAsState()
|
||||||
|
|
||||||
|
val title =
|
||||||
|
entry
|
||||||
|
?.destination
|
||||||
|
?.route
|
||||||
|
?.let { SettingsPages.valueOf(it) }
|
||||||
|
?.titleId
|
||||||
|
?.let { stringResource(id = it) }
|
||||||
|
|
||||||
|
if (title != null) {
|
||||||
|
Text(text = title)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = { IconButton(onClick = {}) { Icon(Icons.Outlined.Info, null) } },
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { paddingValue ->
|
||||||
|
NavHost(
|
||||||
|
modifier =
|
||||||
|
Modifier.fillMaxSize()
|
||||||
|
.nestedScroll(topBarScrollBehavior.nestedScrollConnection)
|
||||||
|
.padding(paddingValue),
|
||||||
|
navController = navController,
|
||||||
|
startDestination = SettingsPages.Main.name,
|
||||||
|
) {
|
||||||
|
composable(SettingsPages.Main) { MainSettingsScreen() }
|
||||||
|
/*...*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NavGraphBuilder.composable(
|
||||||
|
route: SettingsPages,
|
||||||
|
content: @Composable (NavBackStackEntry) -> Unit
|
||||||
|
) = composable(route = route.name, content = content)
|
||||||
|
|
||||||
|
private enum class SettingsPages(val titleId: Int) {
|
||||||
|
Main(R.string.settings),
|
||||||
|
Appearance(R.string.appearance)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SettingsScreenPreview() {
|
||||||
|
FrostPreview { SettingsScreen() }
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Allan Wang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.pitchedapps.frost.settings.screens
|
||||||
|
|
||||||
|
import androidx.compose.material.icons.Icons.Outlined as MaterialIcons
|
||||||
|
import androidx.compose.material.icons.outlined.Info
|
||||||
|
import androidx.compose.material.icons.outlined.Lock
|
||||||
|
import androidx.compose.material.icons.outlined.Newspaper
|
||||||
|
import androidx.compose.material.icons.outlined.Notifications
|
||||||
|
import androidx.compose.material.icons.outlined.Palette
|
||||||
|
import androidx.compose.material.icons.outlined.Replay
|
||||||
|
import androidx.compose.material.icons.outlined.Translate
|
||||||
|
import androidx.compose.material.icons.outlined.TrendingUp
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import com.pitchedapps.frost.R
|
||||||
|
import com.pitchedapps.frost.compose.FrostPreview
|
||||||
|
import com.pitchedapps.frost.compose.settings.SettingsListDsl
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MainSettingsScreen(modifier: Modifier = Modifier) {
|
||||||
|
SettingsListDsl(modifier = modifier) {
|
||||||
|
item(
|
||||||
|
icon = MaterialIcons.Palette,
|
||||||
|
title = stringResource(id = R.string.appearance),
|
||||||
|
description = stringResource(id = R.string.appearance_desc),
|
||||||
|
)
|
||||||
|
item(
|
||||||
|
icon = MaterialIcons.TrendingUp,
|
||||||
|
title = stringResource(id = R.string.behaviour),
|
||||||
|
description = stringResource(id = R.string.behaviour_desc),
|
||||||
|
)
|
||||||
|
item(
|
||||||
|
icon = MaterialIcons.Newspaper,
|
||||||
|
title = stringResource(id = R.string.newsfeed),
|
||||||
|
description = stringResource(id = R.string.newsfeed_desc),
|
||||||
|
)
|
||||||
|
item(
|
||||||
|
icon = MaterialIcons.Notifications,
|
||||||
|
title = stringResource(id = R.string.notifications),
|
||||||
|
description = stringResource(id = R.string.notifications_desc),
|
||||||
|
)
|
||||||
|
item(
|
||||||
|
icon = MaterialIcons.Lock,
|
||||||
|
title = stringResource(id = R.string.security),
|
||||||
|
description = stringResource(id = R.string.security_desc),
|
||||||
|
)
|
||||||
|
item(
|
||||||
|
icon = MaterialIcons.Info,
|
||||||
|
title = stringResource(id = R.string.about_frost),
|
||||||
|
description = stringResource(id = R.string.about_frost_desc),
|
||||||
|
)
|
||||||
|
item(
|
||||||
|
icon = MaterialIcons.Translate,
|
||||||
|
title = stringResource(id = R.string.help_translate),
|
||||||
|
description = stringResource(id = R.string.help_translate_desc),
|
||||||
|
)
|
||||||
|
item(
|
||||||
|
icon = MaterialIcons.Replay,
|
||||||
|
title = stringResource(id = R.string.replay_intro),
|
||||||
|
)
|
||||||
|
// item(
|
||||||
|
// icon = MaterialIcons.Science,
|
||||||
|
// title = stringResource(id = R.string.experimental),
|
||||||
|
// description = stringResource(id = R.string.experimental_desc),
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MainSettingsScreenPreview() {
|
||||||
|
FrostPreview { MainSettingsScreen() }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user