mirror of https://github.com/tasks/tasks
parent
d062bbb574
commit
bfe0af5500
@ -0,0 +1,186 @@
|
|||||||
|
package org.tasks.compose
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.OutlinedTextField
|
||||||
|
import androidx.compose.material.RadioButton
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.TextFieldDefaults
|
||||||
|
import androidx.compose.material.darkColors
|
||||||
|
import androidx.compose.material.lightColors
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.TextRange
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.android.awaitFrame
|
||||||
|
import org.tasks.R
|
||||||
|
|
||||||
|
@ExperimentalComposeUiApi
|
||||||
|
object AddReminderDialog {
|
||||||
|
@Composable
|
||||||
|
fun AddReminderDialog(
|
||||||
|
visible: MutableState<Boolean> = mutableStateOf(true),
|
||||||
|
interval: MutableState<Long?>,
|
||||||
|
selected: MutableState<Int>,
|
||||||
|
) {
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.verticalScroll(scrollState)
|
||||||
|
) {
|
||||||
|
CenteredH6(resId = R.string.custom_notification)
|
||||||
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
OutlinedLongInput(interval, focusRequester)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
val options = listOf(
|
||||||
|
R.plurals.reminder_minutes,
|
||||||
|
R.plurals.reminder_hours,
|
||||||
|
R.plurals.reminder_days,
|
||||||
|
R.plurals.reminder_week,
|
||||||
|
)
|
||||||
|
options.forEachIndexed { index, option ->
|
||||||
|
RadioRow(index, option, interval, selected)
|
||||||
|
}
|
||||||
|
ShowKeyboard(visible, focusRequester)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalComposeUiApi
|
||||||
|
@Composable
|
||||||
|
fun ShowKeyboard(visible: MutableState<Boolean>, focusRequester: FocusRequester) {
|
||||||
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
|
LaunchedEffect(visible) {
|
||||||
|
focusRequester.freeFocus()
|
||||||
|
awaitFrame()
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
keyboardController?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OutlinedLongInput(
|
||||||
|
interval: MutableState<Long?>,
|
||||||
|
focusRequester: FocusRequester
|
||||||
|
) {
|
||||||
|
val value = rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||||
|
val text = interval.value.toString()
|
||||||
|
mutableStateOf(TextFieldValue(text = text, selection = TextRange(0, text.length)))
|
||||||
|
}
|
||||||
|
OutlinedTextField(
|
||||||
|
value = value.value,
|
||||||
|
onValueChange = {
|
||||||
|
value.value = it.copy(text = it.text.filter { t -> t.isDigit() })
|
||||||
|
interval.value = value.value.text.toLongOrNull()
|
||||||
|
},
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.focusRequester(focusRequester),
|
||||||
|
colors = TextFieldDefaults.outlinedTextFieldColors(
|
||||||
|
textColor = MaterialTheme.colors.onSurface,
|
||||||
|
focusedBorderColor = MaterialTheme.colors.onSurface
|
||||||
|
),
|
||||||
|
isError = value.value.text.toLongOrNull() == null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CenteredH6(@StringRes resId: Int) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = resId),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 16.dp),
|
||||||
|
color = MaterialTheme.colors.onSurface,
|
||||||
|
style = MaterialTheme.typography.h6
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RadioRow(index: Int, option: Int, interval: MutableState<Long?>, selected: MutableState<Int>) {
|
||||||
|
val number = interval.value?.toInt() ?: 1
|
||||||
|
val optionString = LocalContext.current.resources.getQuantityString(option, number)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable {
|
||||||
|
selected.value = index
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
RadioButton(
|
||||||
|
selected = index == selected.value,
|
||||||
|
onClick = {
|
||||||
|
selected.value = index
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp, 8.dp)
|
||||||
|
.align(CenterVertically)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = if (index == selected.value) {
|
||||||
|
stringResource(id = R.string.alarm_before_due, optionString)
|
||||||
|
} else {
|
||||||
|
optionString
|
||||||
|
},
|
||||||
|
modifier = Modifier.align(CenterVertically),
|
||||||
|
color = MaterialTheme.colors.onSurface,
|
||||||
|
style = MaterialTheme.typography.body1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalComposeUiApi
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
fun AddReminderOne() =
|
||||||
|
MaterialTheme(if (isSystemInDarkTheme()) darkColors() else lightColors()) {
|
||||||
|
AddReminderDialog.AddReminderDialog(
|
||||||
|
interval = mutableStateOf(1L),
|
||||||
|
selected = mutableStateOf(0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalComposeUiApi
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
fun AddReminderMultiple() =
|
||||||
|
MaterialTheme(if (isSystemInDarkTheme()) darkColors() else lightColors()) {
|
||||||
|
AddReminderDialog.AddReminderDialog(
|
||||||
|
interval = mutableStateOf(15L),
|
||||||
|
selected = mutableStateOf(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue