Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions catalog/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
<activity
android:name=".compose.CharcoalTypographyComposeActivity"
android:exported="false" />
<activity
android:name=".compose.CharcoalDropdownComposeActivity"
android:exported="false" />
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ class CatalogComposeActivity : AppCompatActivity() {
RedirectPattern.Typography -> startActivity(
CharcoalTypographyComposeActivity.createIntent(this)
)
RedirectPattern.Dropdown -> startActivity(
CharcoalDropdownComposeActivity.createIntent(this)
)
}
}

Expand All @@ -66,6 +69,7 @@ private sealed class RedirectPattern {
object TopAppBar : RedirectPattern()
object RadioButton : RedirectPattern()
object Typography : RedirectPattern()
object Dropdown : RedirectPattern()
}

@Composable
Expand Down Expand Up @@ -111,6 +115,7 @@ private fun BodyContent(
ContentColumn(text = "TopAppBar", onClick = { onRedirect(RedirectPattern.TopAppBar) })
ContentColumn(text = "RadioButton", onClick = { onRedirect(RedirectPattern.RadioButton) })
ContentColumn(text = "Typography", onClick = { onRedirect(RedirectPattern.Typography) })
ContentColumn(text = "Dropdown", onClick = { onRedirect(RedirectPattern.Dropdown) })
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package net.pixiv.charcoal.android.catalog.compose

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import net.pixiv.charcoal.android.compose.component.dropdown.CharcoalDropdown1
import net.pixiv.charcoal.android.compose.component.dropdown.CharcoalDropdown2
import net.pixiv.charcoal.android.compose.component.textfield.CharcoalTextField
import net.pixiv.charcoal.android.compose.component.topAppBar.CharcoalTopAppBar
import net.pixiv.charcoal.android.compose.theme.CharcoalTheme

class CharcoalDropdownComposeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
DropdownCatalog(
onNavigationClick = { finish() },
)
}
}

companion object {
fun createIntent(context: Context): Intent {
return Intent(context, CharcoalDropdownComposeActivity::class.java)
}
}
}

@Composable
private fun DropdownCatalog(
onNavigationClick: (() -> Unit),
) {
var selectedOption by remember { mutableStateOf("Apple") }
val options = listOf("Apple", "Orange", "Banana")

var text by remember { mutableStateOf("Hoge") }

CharcoalTheme {
Scaffold(
topBar = {
CharcoalTopAppBar(
title = { Text(text = "CharcoalDropdown") },
navigationIcon = {
IconButton(onClick = { onNavigationClick() }) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = null
)
}
}
)
}
) {
Column(
modifier = Modifier.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
CharcoalDropdown1(
selectedOption = selectedOption,
options = options,
onValueChange = { index ->
selectedOption = options[index]
}
)
CharcoalDropdown2(
selectedOption = selectedOption,
options = options,
onValueChange = { index ->
selectedOption = options[index]
}
)
TextField(
modifier = Modifier
.fillMaxWidth()
.weight(1.0f),
value = text,
onValueChange = { value -> text = value },
textStyle = CharcoalTheme.typography.regular14,
colors = TextFieldDefaults.textFieldColors(backgroundColor = CharcoalTheme.colorToken.surface3)
)
CharcoalTextField(
modifier = Modifier
.fillMaxWidth()
.weight(1.0f),
value = text,
onValueChange = { value -> text = value },
textStyle = CharcoalTheme.typography.regular14,
colors = TextFieldDefaults.textFieldColors(backgroundColor = CharcoalTheme.colorToken.surface3)
)
}
}
}
}

@Preview
@Composable
private fun Preview() {
DropdownCatalog(onNavigationClick = {})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package net.pixiv.charcoal.android.compose.component.dropdown

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ExposedDropdownMenuBox
import androidx.compose.material.ExposedDropdownMenuDefaults
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TextFieldDefaults
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.Modifier
import androidx.compose.ui.text.TextStyle
import net.pixiv.charcoal.android.compose.component.textfield.CharcoalTextField
import net.pixiv.charcoal.android.compose.theme.CharcoalTheme

@Composable
@OptIn(ExperimentalMaterialApi::class)
fun CharcoalDropdown1(
selectedOption: String,
options: List<String>,
onValueChange: (Int) -> Unit,
textStyle: TextStyle = CharcoalTheme.typography.regular14
) {
var expanded by remember { mutableStateOf(false) }

CompositionLocalProvider(LocalTextStyle provides textStyle ) {
ExposedDropdownMenuBox(
modifier = Modifier.fillMaxWidth(),
expanded = expanded,
onExpandedChange = {
expanded = !expanded
}
) {
TextField(
modifier = Modifier.fillMaxWidth(),
readOnly = true,
value = selectedOption,
onValueChange = { },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(
expanded = expanded
)
},
colors = TextFieldDefaults.textFieldColors(backgroundColor = CharcoalTheme.colorToken.surface3)
)
ExposedDropdownMenu(
modifier = Modifier.fillMaxWidth(),
expanded = expanded,
onDismissRequest = {
expanded = false
}
) {
options.forEachIndexed { index, selectionOption ->
DropdownMenuItem(
modifier = Modifier.fillMaxWidth(),
onClick = {
onValueChange(index)
expanded = false
}
) {
Text(text = selectionOption)
}
}
}
}
}
}

@Composable
@OptIn(ExperimentalMaterialApi::class)
fun CharcoalDropdown2(
selectedOption: String,
options: List<String>,
onValueChange: (Int) -> Unit,
textStyle: TextStyle = CharcoalTheme.typography.regular14
) {
var expanded by remember { mutableStateOf(false) }

CompositionLocalProvider(LocalTextStyle provides textStyle ) {
ExposedDropdownMenuBox(
modifier = Modifier.fillMaxWidth(),
expanded = expanded,
onExpandedChange = {
expanded = !expanded
}
) {
CharcoalTextField(
modifier = Modifier.fillMaxWidth(),
readOnly = true,
value = selectedOption,
onValueChange = { },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(
expanded = expanded
)
},
colors = TextFieldDefaults.textFieldColors(backgroundColor = CharcoalTheme.colorToken.surface3)
)
ExposedDropdownMenu(
modifier = Modifier.fillMaxWidth(),
expanded = expanded,
onDismissRequest = {
expanded = false
}
) {
options.forEachIndexed { index, selectionOption ->
DropdownMenuItem(
modifier = Modifier.fillMaxWidth(),
onClick = {
onValueChange(index)
expanded = false
}
) {
Text(text = selectionOption)
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package net.pixiv.charcoal.android.compose.component.textfield

import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.shape.ZeroCornerSize
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.material.TextFieldDefaults.indicatorLine
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.*
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import net.pixiv.charcoal.android.compose.theme.CharcoalTheme

@Composable
fun CharcoalTextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = TextStyle.Default,
textColor: Color = CharcoalTheme.colorToken.text2,
label: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
isError: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions(),
singleLine: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape =
MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
colors: TextFieldColors = TextFieldDefaults.textFieldColors()
) {
val internalModifier = if (singleLine) modifier.height(40.dp) else modifier
val internalTextStyle by remember {
mutableStateOf(textStyle.copy(color = textColor))
}

@OptIn(ExperimentalMaterialApi::class)
BasicTextField(
value = value,
modifier = internalModifier
.background(colors.backgroundColor(enabled).value, shape)
.indicatorLine(enabled, isError, interactionSource, colors)
.defaultMinSize(
minWidth = TextFieldDefaults.MinWidth,
minHeight = TextFieldDefaults.MinHeight
),
onValueChange = onValueChange,
enabled = enabled,
readOnly = readOnly,
textStyle = internalTextStyle,
cursorBrush = SolidColor(CharcoalTheme.colorToken.brand),
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
interactionSource = interactionSource,
singleLine = singleLine,
maxLines = maxLines,
decorationBox = @Composable { innerTextField ->
TextFieldDefaults.TextFieldDecorationBox(
value = value,
visualTransformation = visualTransformation,
innerTextField = innerTextField,
placeholder = placeholder,
label = label,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
singleLine = singleLine,
enabled = enabled,
isError = isError,
interactionSource = interactionSource,
colors = colors,
contentPadding = PaddingValues(8.dp)
)
}
)
}