367 lines
16 KiB
Kotlin
367 lines
16 KiB
Kotlin
package com.jetpackduba.gitnuro.ui.dialogs
|
|
|
|
import androidx.compose.foundation.background
|
|
import androidx.compose.foundation.layout.*
|
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
import androidx.compose.foundation.lazy.items
|
|
import androidx.compose.material.*
|
|
import androidx.compose.material.icons.Icons
|
|
import androidx.compose.material.icons.filled.Clear
|
|
import androidx.compose.runtime.*
|
|
import androidx.compose.ui.Alignment
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.graphics.Color
|
|
import androidx.compose.ui.res.painterResource
|
|
import androidx.compose.ui.unit.dp
|
|
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
|
import com.jetpackduba.gitnuro.extensions.handOnHover
|
|
import com.jetpackduba.gitnuro.theme.backgroundSelected
|
|
import com.jetpackduba.gitnuro.theme.outlinedTextFieldColors
|
|
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
|
|
import com.jetpackduba.gitnuro.theme.textButtonColors
|
|
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
|
|
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
|
import com.jetpackduba.gitnuro.viewmodels.RemotesViewModel
|
|
import org.eclipse.jgit.transport.RemoteConfig
|
|
|
|
@Composable
|
|
fun EditRemotesDialog(
|
|
remotesViewModel: RemotesViewModel,
|
|
onDismiss: () -> Unit,
|
|
) {
|
|
var remotesEditorData by remember {
|
|
mutableStateOf(
|
|
RemotesEditorData(
|
|
emptyList(),
|
|
null,
|
|
)
|
|
)
|
|
}
|
|
|
|
val remotes by remotesViewModel.remotes.collectAsState()
|
|
var remoteChanged by remember { mutableStateOf(false) }
|
|
val selectedRemote = remotesEditorData.selectedRemote
|
|
|
|
|
|
LaunchedEffect(remotes) {
|
|
val newRemotesWrappers = remotes.map {
|
|
val remoteConfig = it.remoteInfo.remoteConfig
|
|
remoteConfig.toRemoteWrapper()
|
|
}
|
|
|
|
val safeSelectedRemote = remotesEditorData.selectedRemote
|
|
var newSelectedRemote: RemoteWrapper? = null
|
|
|
|
if (safeSelectedRemote != null) {
|
|
newSelectedRemote = newRemotesWrappers.firstOrNull { it.remoteName == safeSelectedRemote.remoteName }
|
|
}
|
|
|
|
remoteChanged = newSelectedRemote?.haveUrisChanged ?: false
|
|
|
|
remotesEditorData = remotesEditorData.copy(
|
|
listRemotes = newRemotesWrappers,
|
|
selectedRemote = newSelectedRemote,
|
|
)
|
|
}
|
|
|
|
MaterialDialog(
|
|
paddingVertical = 8.dp,
|
|
paddingHorizontal = 16.dp,
|
|
background = MaterialTheme.colors.surface,
|
|
onCloseRequested = onDismiss
|
|
) {
|
|
Column(
|
|
modifier = Modifier
|
|
.size(width = 900.dp, height = 600.dp),
|
|
horizontalAlignment = Alignment.CenterHorizontally,
|
|
verticalArrangement = Arrangement.Center,
|
|
) {
|
|
Row(
|
|
modifier = Modifier,
|
|
verticalAlignment = Alignment.CenterVertically,
|
|
) {
|
|
Text(
|
|
text = "Remotes",
|
|
color = MaterialTheme.colors.onBackground,
|
|
style = MaterialTheme.typography.h3,
|
|
modifier = Modifier.padding(vertical = 8.dp),
|
|
)
|
|
|
|
Spacer(modifier = Modifier.weight(1f))
|
|
|
|
IconButton(
|
|
onClick = onDismiss,
|
|
modifier = Modifier
|
|
.handOnHover()
|
|
) {
|
|
Icon(
|
|
imageVector = Icons.Default.Clear,
|
|
contentDescription = null,
|
|
tint = MaterialTheme.colors.onBackground,
|
|
)
|
|
}
|
|
}
|
|
Row(
|
|
modifier = Modifier
|
|
.padding(bottom = 8.dp)
|
|
) {
|
|
Column(
|
|
modifier = Modifier
|
|
.width(200.dp)
|
|
.fillMaxHeight()
|
|
.background(MaterialTheme.colors.background),
|
|
) {
|
|
if (remotesEditorData.listRemotes.isNotEmpty()) {
|
|
LazyColumn(
|
|
modifier = Modifier.weight(1f)
|
|
) {
|
|
items(remotesEditorData.listRemotes) { remote ->
|
|
val background = if (remote == selectedRemote) {
|
|
MaterialTheme.colors.backgroundSelected
|
|
} else
|
|
MaterialTheme.colors.background
|
|
|
|
Text(
|
|
text = remote.remoteName,
|
|
color = MaterialTheme.colors.onBackground,
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.handMouseClickable {
|
|
remotesEditorData = remotesEditorData.copy(selectedRemote = remote)
|
|
}
|
|
.background(background)
|
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
)
|
|
}
|
|
}
|
|
} else {
|
|
Box(
|
|
modifier = Modifier
|
|
.weight(1f)
|
|
.fillMaxWidth(),
|
|
contentAlignment = Alignment.Center,
|
|
) {
|
|
Text(
|
|
text = "No available remotes",
|
|
style = MaterialTheme.typography.body2.copy(color = MaterialTheme.colors.onBackgroundSecondary)
|
|
)
|
|
}
|
|
}
|
|
|
|
Row(
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
) {
|
|
IconButton(
|
|
modifier = Modifier
|
|
.size(36.dp)
|
|
.handOnHover(),
|
|
onClick = {
|
|
val remotesWithNew = remotesEditorData.listRemotes.toMutableList()
|
|
val newRemote = RemoteWrapper(
|
|
remoteName = "new_remote",
|
|
fetchUri = "",
|
|
originalFetchUri = "",
|
|
pushUri = "",
|
|
originalPushUri = "",
|
|
isNew = true
|
|
)
|
|
|
|
remotesWithNew.add(newRemote)
|
|
|
|
remotesEditorData = remotesEditorData.copy(
|
|
listRemotes = remotesWithNew,
|
|
selectedRemote = newRemote
|
|
)
|
|
}
|
|
) {
|
|
Icon(
|
|
painter = painterResource("add.svg"),
|
|
contentDescription = null,
|
|
tint = MaterialTheme.colors.onBackground,
|
|
)
|
|
}
|
|
IconButton(
|
|
modifier = Modifier
|
|
.size(36.dp)
|
|
.handOnHover(),
|
|
enabled = selectedRemote != null,
|
|
onClick = {
|
|
if (selectedRemote != null)
|
|
remotesViewModel.deleteRemote(selectedRemote.remoteName, selectedRemote.isNew)
|
|
}
|
|
) {
|
|
Icon(
|
|
painter = painterResource("remove.svg"),
|
|
contentDescription = null,
|
|
tint = if (selectedRemote != null)
|
|
MaterialTheme.colors.onBackground
|
|
else
|
|
MaterialTheme.colors.onBackgroundSecondary,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
Column(
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.padding(horizontal = 16.dp)
|
|
) {
|
|
if (selectedRemote != null) {
|
|
Column {
|
|
if (selectedRemote.isNew) {
|
|
Text(
|
|
text = "New remote name",
|
|
color = MaterialTheme.colors.onBackground,
|
|
modifier = Modifier.padding(top = 8.dp),
|
|
)
|
|
|
|
AdjustableOutlinedTextField(
|
|
value = selectedRemote.remoteName,
|
|
onValueChange = { newValue ->
|
|
val newSelectedRemoteConfig = selectedRemote.copy(remoteName = newValue)
|
|
val listRemotes = remotesEditorData.listRemotes.toMutableList()
|
|
val newRemoteToBeReplacedIndex = listRemotes.indexOfFirst { it.isNew }
|
|
listRemotes[newRemoteToBeReplacedIndex] = newSelectedRemoteConfig
|
|
|
|
remotesEditorData = remotesEditorData.copy(
|
|
listRemotes = listRemotes,
|
|
selectedRemote = newSelectedRemoteConfig
|
|
)
|
|
},
|
|
singleLine = true,
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.padding(vertical = 8.dp)
|
|
)
|
|
}
|
|
|
|
Text(
|
|
text = "Fetch URL",
|
|
color = MaterialTheme.colors.onBackground,
|
|
modifier = Modifier.padding(top = 8.dp),
|
|
)
|
|
|
|
AdjustableOutlinedTextField(
|
|
value = selectedRemote.fetchUri,
|
|
onValueChange = { newValue ->
|
|
val newSelectedRemoteConfig = selectedRemote.copy(fetchUri = newValue)
|
|
remotesEditorData = remotesEditorData.copy(selectedRemote = newSelectedRemoteConfig)
|
|
remoteChanged = newSelectedRemoteConfig.haveUrisChanged
|
|
},
|
|
singleLine = true,
|
|
colors = outlinedTextFieldColors(),
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.padding(vertical = 8.dp)
|
|
)
|
|
|
|
Text(
|
|
text = "Push URL",
|
|
color = MaterialTheme.colors.onBackground,
|
|
modifier = Modifier.padding(top = 8.dp),
|
|
)
|
|
|
|
AdjustableOutlinedTextField(
|
|
value = selectedRemote.pushUri,
|
|
onValueChange = { newValue ->
|
|
val newSelectedRemoteConfig = selectedRemote.copy(pushUri = newValue)
|
|
remotesEditorData = remotesEditorData.copy(selectedRemote = newSelectedRemoteConfig)
|
|
remoteChanged = newSelectedRemoteConfig.haveUrisChanged
|
|
},
|
|
singleLine = true,
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.padding(vertical = 8.dp)
|
|
)
|
|
|
|
Spacer(modifier = Modifier.weight(1f))
|
|
|
|
Row(
|
|
modifier = Modifier
|
|
.padding(top = 16.dp)
|
|
.align(Alignment.End),
|
|
verticalAlignment = Alignment.CenterVertically,
|
|
) {
|
|
Spacer(modifier = Modifier.weight(1f))
|
|
|
|
if (!selectedRemote.isNew) {
|
|
PrimaryButton(
|
|
text = "Discard changes",
|
|
modifier = Modifier.padding(end = 8.dp),
|
|
onClick = {
|
|
remotesEditorData = remotesEditorData.copy(
|
|
selectedRemote = selectedRemote.copy(
|
|
fetchUri = selectedRemote.originalFetchUri,
|
|
pushUri = selectedRemote.originalPushUri,
|
|
)
|
|
)
|
|
|
|
remoteChanged = false
|
|
},
|
|
backgroundColor = Color.Transparent,
|
|
backgroundDisabled = Color.Transparent,
|
|
enabled = remoteChanged,
|
|
textColor = MaterialTheme.colors.onBackground,
|
|
disabledTextColor = MaterialTheme.colors.onBackground.copy(alpha = 0.5f),
|
|
)
|
|
}
|
|
|
|
val text = if (selectedRemote.isNew)
|
|
"Add new remote"
|
|
else
|
|
"Save ${selectedRemote.remoteName} changes"
|
|
PrimaryButton(
|
|
modifier = Modifier,
|
|
enabled = remoteChanged,
|
|
onClick = {
|
|
if (selectedRemote.isNew)
|
|
remotesViewModel.addRemote(selectedRemote)
|
|
else
|
|
remotesViewModel.updateRemote(selectedRemote)
|
|
},
|
|
text = text,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
data class RemoteWrapper(
|
|
val remoteName: String,
|
|
val fetchUri: String,
|
|
val originalFetchUri: String,
|
|
val pushUri: String,
|
|
val originalPushUri: String,
|
|
val isNew: Boolean = false,
|
|
) {
|
|
val haveUrisChanged: Boolean = isNew ||
|
|
fetchUri != originalFetchUri ||
|
|
pushUri.toString() != originalPushUri
|
|
}
|
|
|
|
|
|
data class RemotesEditorData(
|
|
val listRemotes: List<RemoteWrapper>,
|
|
val selectedRemote: RemoteWrapper?,
|
|
)
|
|
|
|
fun RemoteConfig.toRemoteWrapper(): RemoteWrapper {
|
|
val fetchUri = this.urIs.firstOrNull()
|
|
val pushUri = this.pushURIs.firstOrNull()
|
|
?: this.urIs.firstOrNull() // If push URI == null, take fetch URI
|
|
|
|
return RemoteWrapper(
|
|
remoteName = this.name,
|
|
fetchUri = fetchUri?.toString().orEmpty(),
|
|
originalFetchUri = fetchUri?.toString().orEmpty(),
|
|
pushUri = pushUri?.toString().orEmpty(),
|
|
originalPushUri = pushUri?.toString().orEmpty(),
|
|
)
|
|
} |