Changed clone dialog design and improved text field behavior with long text
This commit is contained in:
parent
7148e59eeb
commit
d2608f8f60
6 changed files with 89 additions and 43 deletions
|
@ -15,6 +15,9 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusProperties
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.graphics.SolidColor
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
import androidx.compose.ui.graphics.takeOrElse
|
import androidx.compose.ui.graphics.takeOrElse
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
@ -28,11 +31,13 @@ fun AdjustableOutlinedTextField(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
isError: Boolean = false,
|
isError: Boolean = false,
|
||||||
|
singleLine: Boolean = false,
|
||||||
colors: TextFieldColors = outlinedTextFieldColors(),
|
colors: TextFieldColors = outlinedTextFieldColors(),
|
||||||
maxLines: Int = Int.MAX_VALUE,
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||||
textStyle: TextStyle = LocalTextStyle.current.copy(fontSize = MaterialTheme.typography.body1.fontSize),
|
textStyle: TextStyle = LocalTextStyle.current.copy(fontSize = MaterialTheme.typography.body1.fontSize),
|
||||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
shape: Shape = RoundedCornerShape(4.dp),
|
||||||
) {
|
) {
|
||||||
val textColor = textStyle.color.takeOrElse {
|
val textColor = textStyle.color.takeOrElse {
|
||||||
colors.textColor(enabled).value
|
colors.textColor(enabled).value
|
||||||
|
@ -51,13 +56,14 @@ fun AdjustableOutlinedTextField(
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
keyboardOptions = keyboardOptions,
|
keyboardOptions = keyboardOptions,
|
||||||
cursorBrush = SolidColor(cursorColor),
|
cursorBrush = SolidColor(cursorColor),
|
||||||
|
singleLine = singleLine,
|
||||||
decorationBox = { innerTextField ->
|
decorationBox = { innerTextField ->
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.border(
|
.border(
|
||||||
width = 1.dp,
|
width = 1.dp,
|
||||||
color = indicatorColor,
|
color = indicatorColor,
|
||||||
shape = RoundedCornerShape(4.dp)
|
shape = shape
|
||||||
)
|
)
|
||||||
.padding(12.dp),
|
.padding(12.dp),
|
||||||
contentAlignment = Alignment.CenterStart,
|
contentAlignment = Alignment.CenterStart,
|
||||||
|
|
|
@ -155,7 +155,7 @@ private fun TextInput(
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
onValueChange = onValueChange,
|
onValueChange = onValueChange,
|
||||||
colors = outlinedTextFieldColors(),
|
colors = outlinedTextFieldColors(),
|
||||||
maxLines = 1,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,14 +12,17 @@ import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.focus.FocusProperties
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusProperties
|
import androidx.compose.ui.focus.focusProperties
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import app.git.CloneStatus
|
import app.git.CloneStatus
|
||||||
import app.theme.outlinedTextFieldColors
|
import app.theme.outlinedTextFieldColors
|
||||||
import app.theme.primaryTextColor
|
import app.theme.primaryTextColor
|
||||||
import app.theme.textButtonColors
|
import app.theme.textButtonColors
|
||||||
|
import app.ui.components.AdjustableOutlinedTextField
|
||||||
import app.ui.components.PrimaryButton
|
import app.ui.components.PrimaryButton
|
||||||
import app.ui.openDirectoryDialog
|
import app.ui.openDirectoryDialog
|
||||||
import app.viewmodels.CloneViewModel
|
import app.viewmodels.CloneViewModel
|
||||||
|
@ -37,7 +40,8 @@ fun CloneDialog(
|
||||||
MaterialDialog(onCloseRequested = onClose) {
|
MaterialDialog(onCloseRequested = onClose) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(400.dp)
|
.width(720.dp)
|
||||||
|
.heightIn(min = 200.dp)
|
||||||
.animateContentSize()
|
.animateContentSize()
|
||||||
) {
|
) {
|
||||||
when (cloneStatusValue) {
|
when (cloneStatusValue) {
|
||||||
|
@ -46,7 +50,7 @@ fun CloneDialog(
|
||||||
}
|
}
|
||||||
|
|
||||||
is CloneStatus.Cancelling -> {
|
is CloneStatus.Cancelling -> {
|
||||||
onClose()
|
// onClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
is CloneStatus.Completed -> {
|
is CloneStatus.Completed -> {
|
||||||
|
@ -90,29 +94,24 @@ private fun CloneInput(
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
"Clone a new repository",
|
"Clone a new repository",
|
||||||
color = MaterialTheme.colors.primaryTextColor,
|
style = MaterialTheme.typography.h3,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 4.dp, horizontal = 8.dp)
|
.padding(vertical = 4.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
OutlinedTextField(
|
TextInput(
|
||||||
modifier = Modifier
|
title = "URL",
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 4.dp, horizontal = 8.dp)
|
|
||||||
.focusRequester(urlFocusRequester)
|
|
||||||
.focusProperties {
|
|
||||||
previous = cancelButtonFocusRequester
|
|
||||||
next = directoryFocusRequester
|
|
||||||
},
|
|
||||||
label = { Text("URL") },
|
|
||||||
textStyle = MaterialTheme.typography.body1,
|
|
||||||
maxLines = 1,
|
|
||||||
value = url,
|
value = url,
|
||||||
colors = outlinedTextFieldColors(),
|
focusRequester = urlFocusRequester,
|
||||||
|
focusProperties = {
|
||||||
|
previous = cancelButtonFocusRequester
|
||||||
|
next = directoryFocusRequester
|
||||||
|
},
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
cloneViewModel.resetStateIfError()
|
cloneViewModel.resetStateIfError()
|
||||||
url = it
|
url = it
|
||||||
|
@ -122,37 +121,35 @@ private fun CloneInput(
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth(),
|
||||||
.padding(vertical = 4.dp, horizontal = 8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
|
||||||
modifier = Modifier
|
TextInput(
|
||||||
.weight(1f)
|
modifier = Modifier.weight(1f),
|
||||||
.padding(end = 4.dp)
|
title = "Directory",
|
||||||
.focusRequester(directoryFocusRequester)
|
|
||||||
.focusProperties {
|
|
||||||
previous = urlFocusRequester
|
|
||||||
next = directoryButtonFocusRequester
|
|
||||||
},
|
|
||||||
textStyle = MaterialTheme.typography.body1,
|
|
||||||
maxLines = 1,
|
|
||||||
label = { Text("Directory") },
|
|
||||||
value = directory,
|
value = directory,
|
||||||
colors = outlinedTextFieldColors(),
|
focusRequester = directoryButtonFocusRequester,
|
||||||
|
focusProperties = {
|
||||||
|
previous = urlFocusRequester
|
||||||
|
next = directoryButtonFocusRequester
|
||||||
|
},
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
cloneViewModel.resetStateIfError()
|
cloneViewModel.resetStateIfError()
|
||||||
directory = it
|
directory = it
|
||||||
cloneViewModel.directory = directory
|
cloneViewModel.directory = directory
|
||||||
}
|
},
|
||||||
|
textFieldShape = RoundedCornerShape(topStart = 4.dp, bottomStart = 4.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
cloneViewModel.resetStateIfError()
|
cloneViewModel.resetStateIfError()
|
||||||
val newDirectory = openDirectoryDialog()
|
val newDirectory = openDirectoryDialog()
|
||||||
if (newDirectory != null)
|
if (newDirectory != null) {
|
||||||
directory = newDirectory
|
directory = newDirectory
|
||||||
|
cloneViewModel.directory = directory
|
||||||
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.focusRequester(directoryButtonFocusRequester)
|
.focusRequester(directoryButtonFocusRequester)
|
||||||
|
@ -160,6 +157,9 @@ private fun CloneInput(
|
||||||
previous = directoryFocusRequester
|
previous = directoryFocusRequester
|
||||||
next = cloneButtonFocusRequester
|
next = cloneButtonFocusRequester
|
||||||
}
|
}
|
||||||
|
.clip(RoundedCornerShape(topEnd = 4.dp, bottomEnd = 4.dp))
|
||||||
|
.background(MaterialTheme.colors.primary)
|
||||||
|
.height(44.5.dp) // Height of the AdjustableOutlinedTextField with a single line by default
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.Search,
|
Icons.Default.Search,
|
||||||
|
@ -288,4 +288,43 @@ private fun Cancelling() {
|
||||||
modifier = Modifier.padding(vertical = 16.dp),
|
modifier = Modifier.padding(vertical = 16.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TextInput(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
title: String,
|
||||||
|
value: String,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
focusRequester: FocusRequester,
|
||||||
|
focusProperties: FocusProperties.() -> Unit,
|
||||||
|
onValueChange: (String) -> Unit,
|
||||||
|
textFieldShape: Shape = RoundedCornerShape(4.dp),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.padding(vertical = 8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.body1,
|
||||||
|
modifier = Modifier
|
||||||
|
.width(100.dp)
|
||||||
|
.padding(end = 16.dp),
|
||||||
|
)
|
||||||
|
|
||||||
|
AdjustableOutlinedTextField(
|
||||||
|
value = value,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.focusRequester(focusRequester)
|
||||||
|
.focusProperties(focusProperties),
|
||||||
|
enabled = enabled,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
colors = outlinedTextFieldColors(),
|
||||||
|
singleLine = true,
|
||||||
|
shape = textFieldShape,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -228,7 +228,7 @@ fun EditRemotesDialog(
|
||||||
selectedRemote = newSelectedRemoteConfig
|
selectedRemote = newSelectedRemoteConfig
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
maxLines = 1,
|
singleLine = true,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp)
|
.padding(vertical = 8.dp)
|
||||||
|
@ -248,7 +248,7 @@ fun EditRemotesDialog(
|
||||||
remotesEditorData = remotesEditorData.copy(selectedRemote = newSelectedRemoteConfig)
|
remotesEditorData = remotesEditorData.copy(selectedRemote = newSelectedRemoteConfig)
|
||||||
remoteChanged = newSelectedRemoteConfig.haveUrisChanged
|
remoteChanged = newSelectedRemoteConfig.haveUrisChanged
|
||||||
},
|
},
|
||||||
maxLines = 1,
|
singleLine = true,
|
||||||
colors = outlinedTextFieldColors(),
|
colors = outlinedTextFieldColors(),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -268,7 +268,7 @@ fun EditRemotesDialog(
|
||||||
remotesEditorData = remotesEditorData.copy(selectedRemote = newSelectedRemoteConfig)
|
remotesEditorData = remotesEditorData.copy(selectedRemote = newSelectedRemoteConfig)
|
||||||
remoteChanged = newSelectedRemoteConfig.haveUrisChanged
|
remoteChanged = newSelectedRemoteConfig.haveUrisChanged
|
||||||
},
|
},
|
||||||
maxLines = 1,
|
singleLine = true,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp)
|
.padding(vertical = 8.dp)
|
||||||
|
|
|
@ -432,7 +432,7 @@ fun SettingIntInput(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors = outlinedTextFieldColors(),
|
colors = outlinedTextFieldColors(),
|
||||||
maxLines = 1,
|
singleLine = true,
|
||||||
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.End),
|
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.End),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@ import app.git.TabState
|
||||||
import app.git.remote_operations.CloneRepositoryUseCase
|
import app.git.remote_operations.CloneRepositoryUseCase
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -83,9 +83,10 @@ class CloneViewModel @Inject constructor(
|
||||||
directory = ""
|
directory = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cancelClone() {
|
fun cancelClone() = tabState.safeProcessingWihoutGit {
|
||||||
cloneJob?.cancel()
|
|
||||||
_cloneStatus.value = CloneStatus.Cancelling
|
_cloneStatus.value = CloneStatus.Cancelling
|
||||||
|
cloneJob?.cancelAndJoin()
|
||||||
|
_cloneStatus.value = CloneStatus.None
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetStateIfError() {
|
fun resetStateIfError() {
|
||||||
|
|
Loading…
Reference in a new issue