1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-11-08 12:02:33 +01:00

Convert to only list item dsl

This commit is contained in:
Allan Wang 2023-06-22 17:01:21 -07:00
parent 4e9672c078
commit b73c014063
No known key found for this signature in database
GPG Key ID: C93E3F9C679D7A56
7 changed files with 298 additions and 250 deletions

View File

@ -1,57 +0,0 @@
/*
* 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.material3.Checkbox
import androidx.compose.material3.Switch
import androidx.compose.runtime.Composable
fun SettingsContentScope.checkbox(state: SettingState<Boolean>): SettingsContent =
object : SettingsContent {
override fun onClick() {
state.value = !state.value
}
@Composable
override fun compose() {
Checkbox(
enabled = state.enabled,
checked = state.value,
onCheckedChange = { state.value = it },
)
}
}
fun SettingsContentScope.switch(
state: SettingState<Boolean>,
): SettingsContent =
object : SettingsContent {
override fun onClick() {
state.value = !state.value
}
@Composable
override fun compose() {
Switch(
enabled = state.enabled,
checked = state.value,
onCheckedChange = { state.value = it },
)
}
}

View File

@ -1,64 +0,0 @@
/*
* 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.layout.LayoutScopeMarker
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@LayoutScopeMarker
interface SettingsContentScope {
@Composable
fun <T, R> T.rememberSetting(
enabler: T.() -> Boolean = { true },
getter: T.() -> R,
setter: T.(R) -> Unit
): SettingState<R> {
return remember(this) {
object : SettingState<R> {
override val enabled: Boolean
get() = enabler()
override var value: R
get() = getter()
set(value) {
setter(value)
}
}
}
}
@Composable
fun <T> MutableState<T>.asSettingState(): SettingState<T> {
return remember(this) {
object : SettingState<T> {
override val enabled: Boolean = true
override var value: T by this@asSettingState
}
}
}
}
interface SettingsContent {
fun onClick()
@Composable fun compose()
}

View File

@ -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,
)
}

View File

@ -0,0 +1,76 @@
/*
* 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.material3.MaterialTheme
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
@Composable
fun SettingsListDsl(modifier: Modifier = Modifier, content: 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()) }
MaterialTheme {
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) },
)
}
}
}

View File

@ -18,16 +18,22 @@ 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.MaterialTheme
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
@ -38,60 +44,54 @@ import com.pitchedapps.frost.ext.thenIf
@Composable
fun SettingsListItem(
modifier: Modifier = Modifier,
icon: ImageVector? = null,
title: String,
enabled: Boolean = true,
icon: ImageVector? = null,
description: String? = null,
content: (@Composable SettingsContentScope.() -> SettingsContent)? = null
onClick: (() -> Unit)? = null,
content: (@Composable () -> Unit)? = null
) {
val settingsContent = content?.invoke(SettingsContentScopeImpl)
val alpha = if (enabled) LocalContentAlpha.current else ContentAlpha.disabled
ListItem(
modifier =
modifier.thenIf(settingsContent != null) {
Modifier.clickable(
onClick = settingsContent!!::onClick,
)
modifier.thenIf(onClick != null) {
Modifier.clickable(enabled = enabled) { onClick?.invoke() }
},
leadingContent =
icon.optionalCompose {
Icon(
modifier = Modifier.size(24.dp),
modifier = Modifier.size(24.dp).alpha(alpha),
imageVector = it,
contentDescription = null,
)
},
headlineContent = { Text(text = title) },
supportingContent = description.optionalCompose { Text(text = it) },
trailingContent =
settingsContent.takeIf { it !is SettingsContentClickOnly }.optionalCompose { it.compose() },
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() {
val state = remember { mutableStateOf(false) }
var state by remember { mutableStateOf(false) }
MaterialTheme {
SettingsListItem(
icon = Icons.Outlined.Person,
title = "Test Title",
description = "Test Description",
) {
checkbox(state.asSettingState())
Checkbox(
checked = state,
onCheckedChange = { state = it },
)
}
}
}
private object SettingsContentScopeImpl : SettingsContentScope
private class SettingsContentClickOnly(private val action: () -> Unit) : SettingsContent {
override fun onClick() {
action()
}
@Composable override fun compose() = Unit
}
fun SettingsContentScope.click(action: () -> Unit): SettingsContent =
SettingsContentClickOnly(action)

View File

@ -0,0 +1,114 @@
/*
* 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.material3.Checkbox
import androidx.compose.material3.Switch
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
fun SettingsDsl.settingsListDsl(content: 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 {}
}
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,
)
}
}
}

View File

@ -1,100 +0,0 @@
/*
* 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.material3.MaterialTheme
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.tooling.preview.Preview
@Composable fun SettingsScreen() {}
@Preview
@Composable
fun SettingsScreenPreview() {
data class Model(
val check1: Boolean = false,
val switch1: Boolean = false,
val switch2: Boolean = false,
)
var state by remember { mutableStateOf(Model()) }
val composables: List<@Composable () -> Unit> = remember {
listOf(
{
SettingsListItem(
title = "Check 1",
) {
checkbox(
state.rememberSetting(
getter = { state.check1 },
setter = { state = state.copy(check1 = it) },
),
)
}
},
{
SettingsListItem(
title = "Check 1",
description = "Linked again",
) {
checkbox(
state.rememberSetting(
getter = { state.check1 },
setter = { state = state.copy(check1 = it) },
),
)
}
},
{
SettingsListItem(
title = "Switch 1",
) {
switch(
state.rememberSetting(
getter = { state.switch1 },
setter = { state = state.copy(switch1 = it) },
),
)
}
},
{
SettingsListItem(
title = "Switch 2",
description = "Enabled by switch 1",
) {
switch(
state.rememberSetting(
enabler = { state.switch1 },
getter = { state.switch2 },
setter = { state = state.copy(switch2 = it) },
),
)
}
},
)
}
MaterialTheme { LazyColumn { items(composables) { compose -> compose() } } }
}