Refactored remotes in side panel
This commit is contained in:
parent
22088a3fbd
commit
81836f44a5
@ -22,6 +22,7 @@ object AppIcons {
|
||||
const val DOWNLOAD = "download.svg"
|
||||
const val DRAG = "drag.svg"
|
||||
const val DROPDOWN = "dropdown.svg"
|
||||
const val EDIT = "edit.svg"
|
||||
const val ERROR = "error.svg"
|
||||
const val EXPAND_MORE = "expand_more.svg"
|
||||
const val FETCH = "fetch.svg"
|
||||
|
@ -14,7 +14,7 @@ import javax.inject.Inject
|
||||
|
||||
private const val TAG = "FetchAllBranchesUseCase"
|
||||
|
||||
class FetchAllBranchesUseCase @Inject constructor(
|
||||
class FetchAllRemotesUseCase @Inject constructor(
|
||||
private val handleTransportUseCase: HandleTransportUseCase,
|
||||
) {
|
||||
suspend operator fun invoke(git: Git) = withContext(Dispatchers.IO) {
|
@ -0,0 +1,32 @@
|
||||
package com.jetpackduba.gitnuro.models
|
||||
|
||||
import org.eclipse.jgit.transport.RemoteConfig
|
||||
|
||||
data class RemoteWrapper constructor(
|
||||
val remoteName: String,
|
||||
val fetchUri: String,
|
||||
val pushUri: String,
|
||||
val isNew: Boolean,
|
||||
)
|
||||
|
||||
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(),
|
||||
pushUri = pushUri?.toString().orEmpty(),
|
||||
isNew = false,
|
||||
)
|
||||
}
|
||||
|
||||
fun newRemoteWrapper(): RemoteWrapper {
|
||||
return RemoteWrapper(
|
||||
remoteName = "",
|
||||
fetchUri = "",
|
||||
pushUri = "",
|
||||
isNew = true,
|
||||
)
|
||||
}
|
@ -17,12 +17,18 @@ import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.extensions.isLocal
|
||||
import com.jetpackduba.gitnuro.extensions.isValid
|
||||
import com.jetpackduba.gitnuro.extensions.simpleName
|
||||
import com.jetpackduba.gitnuro.models.RemoteWrapper
|
||||
import com.jetpackduba.gitnuro.models.newRemoteWrapper
|
||||
import com.jetpackduba.gitnuro.models.toRemoteWrapper
|
||||
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
|
||||
import com.jetpackduba.gitnuro.ui.components.*
|
||||
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
|
||||
import com.jetpackduba.gitnuro.ui.components.ScrollableLazyColumn
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuHeader
|
||||
import com.jetpackduba.gitnuro.ui.components.SideMenuSubentry
|
||||
import com.jetpackduba.gitnuro.ui.components.tooltip.DelayedTooltip
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.*
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.AddEditRemoteDialog
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.AddSubmodulesDialog
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.EditRemotesDialog
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.SetDefaultUpstreamBranchDialog
|
||||
import com.jetpackduba.gitnuro.viewmodels.ChangeDefaultUpstreamBranchViewModel
|
||||
import com.jetpackduba.gitnuro.viewmodels.sidepanel.*
|
||||
@ -50,7 +56,7 @@ fun SidePanel(
|
||||
val stashesState by stashesViewModel.stashesState.collectAsState()
|
||||
val submodulesState by submodulesViewModel.submodules.collectAsState()
|
||||
|
||||
var showEditRemotesDialog by remember { mutableStateOf(false) }
|
||||
val (showAddEditRemote, setShowAddEditRemote) = remember { mutableStateOf<RemoteWrapper?>(null) }
|
||||
val (branchToChangeUpstream, setBranchToChangeUpstream) = remember { mutableStateOf<Ref?>(null) }
|
||||
var showEditSubmodulesDialog by remember { mutableStateOf(false) }
|
||||
|
||||
@ -80,7 +86,7 @@ fun SidePanel(
|
||||
remotes(
|
||||
remotesState = remotesState,
|
||||
remotesViewModel = remotesViewModel,
|
||||
onShowEditRemotesDialog = { showEditRemotesDialog = true },
|
||||
onShowAddEditRemoteDialog = { setShowAddEditRemote(it) },
|
||||
)
|
||||
|
||||
tags(
|
||||
@ -103,11 +109,12 @@ fun SidePanel(
|
||||
}
|
||||
}
|
||||
|
||||
if (showEditRemotesDialog) {
|
||||
EditRemotesDialog(
|
||||
if (showAddEditRemote != null) {
|
||||
AddEditRemoteDialog(
|
||||
remotesViewModel = remotesViewModel,
|
||||
remoteWrapper = showAddEditRemote,
|
||||
onDismiss = {
|
||||
showEditRemotesDialog = false
|
||||
setShowAddEditRemote(null)
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -218,7 +225,7 @@ fun LazyListScope.localBranches(
|
||||
fun LazyListScope.remotes(
|
||||
remotesState: RemotesState,
|
||||
remotesViewModel: RemotesViewModel,
|
||||
onShowEditRemotesDialog: () -> Unit,
|
||||
onShowAddEditRemoteDialog: (RemoteWrapper) -> Unit,
|
||||
) {
|
||||
val isExpanded = remotesState.isExpanded
|
||||
val remotes = remotesState.remotes
|
||||
@ -230,14 +237,14 @@ fun LazyListScope.remotes(
|
||||
itemsCount = remotes.count(),
|
||||
hoverIcon = {
|
||||
IconButton(
|
||||
onClick = onShowEditRemotesDialog,
|
||||
onClick = { onShowAddEditRemoteDialog(newRemoteWrapper()) },
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp)
|
||||
.size(16.dp)
|
||||
.handOnHover(),
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(AppIcons.SETTINGS),
|
||||
painter = painterResource(AppIcons.ADD),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
@ -255,7 +262,12 @@ fun LazyListScope.remotes(
|
||||
item {
|
||||
Remote(
|
||||
remote = remote,
|
||||
onRemoteClicked = { remotesViewModel.onRemoteClicked(remote) }
|
||||
onEditRemote = {
|
||||
val wrapper = remote.remoteInfo.remoteConfig.toRemoteWrapper()
|
||||
onShowAddEditRemoteDialog(wrapper)
|
||||
},
|
||||
onDeleteRemote = { remotesViewModel.deleteRemote(remote.remoteInfo.remoteConfig.name) },
|
||||
onRemoteClicked = { remotesViewModel.onRemoteClicked(remote) },
|
||||
)
|
||||
}
|
||||
|
||||
@ -461,7 +473,17 @@ private fun Branch(
|
||||
@Composable
|
||||
private fun Remote(
|
||||
remote: RemoteView,
|
||||
onEditRemote: () -> Unit,
|
||||
onDeleteRemote: () -> Unit,
|
||||
onRemoteClicked: () -> Unit,
|
||||
) {
|
||||
ContextMenu(
|
||||
items = {
|
||||
remoteContextMenu(
|
||||
onEdit = onEditRemote,
|
||||
onDelete = onDeleteRemote,
|
||||
)
|
||||
}
|
||||
) {
|
||||
SideMenuSubentry(
|
||||
text = remote.remoteInfo.remoteConfig.name,
|
||||
@ -470,6 +492,7 @@ private fun Remote(
|
||||
isSelected = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
|
@ -1,10 +1,20 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.jetpackduba.gitnuro.AppIcons
|
||||
|
||||
fun remoteContextMenu(
|
||||
onEditRemotes: () -> Unit,
|
||||
onEdit: () -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
): List<ContextMenuElement> = listOf(
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Edit remotes",
|
||||
onClick = onEditRemotes
|
||||
label = "Edit",
|
||||
icon = { painterResource(AppIcons.EDIT) },
|
||||
onClick = onEdit
|
||||
),
|
||||
ContextMenuElement.ContextTextEntry(
|
||||
label = "Delete",
|
||||
icon = { painterResource(AppIcons.DELETE) },
|
||||
onClick = onDelete
|
||||
),
|
||||
)
|
@ -0,0 +1,159 @@
|
||||
package com.jetpackduba.gitnuro.ui.dialogs
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
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.unit.dp
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.models.RemoteWrapper
|
||||
import com.jetpackduba.gitnuro.theme.outlinedTextFieldColors
|
||||
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
|
||||
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
||||
import com.jetpackduba.gitnuro.viewmodels.sidepanel.RemotesViewModel
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
|
||||
@Composable
|
||||
fun AddEditRemoteDialog(
|
||||
remotesViewModel: RemotesViewModel,
|
||||
remoteWrapper: RemoteWrapper,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
var remote: RemoteWrapper by remember(remoteWrapper) { mutableStateOf(remoteWrapper) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
remotesViewModel.remoteUpdated.collectLatest { onDismiss() }
|
||||
}
|
||||
|
||||
MaterialDialog(
|
||||
paddingVertical = 8.dp,
|
||||
paddingHorizontal = 16.dp,
|
||||
background = MaterialTheme.colors.surface,
|
||||
onCloseRequested = onDismiss
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(600.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = if (remote.isNew) "New remote" else "Edit remote \"${remote.remoteName}\"",
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
style = MaterialTheme.typography.h3,
|
||||
modifier = Modifier
|
||||
.padding(start = 8.dp, top = 8.dp, bottom = 8.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 8.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Column {
|
||||
if (remote.isNew) {
|
||||
Text(
|
||||
text = "Remote name",
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
)
|
||||
|
||||
AdjustableOutlinedTextField(
|
||||
value = remote.remoteName,
|
||||
onValueChange = { newValue ->
|
||||
remote = remote.copy(remoteName = newValue)
|
||||
},
|
||||
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 = remote.fetchUri,
|
||||
onValueChange = { newValue ->
|
||||
remote = remote.copy(fetchUri = newValue)
|
||||
},
|
||||
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 = remote.pushUri,
|
||||
onValueChange = { newValue ->
|
||||
remote = remote.copy(pushUri = newValue)
|
||||
},
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp)
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 32.dp)
|
||||
.align(Alignment.End),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
PrimaryButton(
|
||||
text = "Cancel",
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
onClick = onDismiss,
|
||||
backgroundColor = Color.Transparent,
|
||||
backgroundDisabled = Color.Transparent,
|
||||
textColor = MaterialTheme.colors.onBackground,
|
||||
disabledTextColor = MaterialTheme.colors.onBackground.copy(alpha = 0.5f),
|
||||
)
|
||||
|
||||
|
||||
PrimaryButton(
|
||||
modifier = Modifier,
|
||||
onClick = {
|
||||
if (remote.isNew)
|
||||
remotesViewModel.addRemote(remote)
|
||||
else
|
||||
remotesViewModel.updateRemote(remote)
|
||||
},
|
||||
text = "Save changes",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,371 +0,0 @@
|
||||
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.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
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.AppIcons
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.theme.backgroundSelected
|
||||
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
|
||||
import com.jetpackduba.gitnuro.theme.outlinedTextFieldColors
|
||||
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
|
||||
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
||||
import com.jetpackduba.gitnuro.viewmodels.sidepanel.RemotesViewModel
|
||||
import org.eclipse.jgit.transport.RemoteConfig
|
||||
|
||||
@Composable
|
||||
fun EditRemotesDialog(
|
||||
remotesViewModel: RemotesViewModel,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
var remotesEditorData by remember {
|
||||
mutableStateOf(
|
||||
RemotesEditorData(
|
||||
emptyList(),
|
||||
null,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val remotesState by remotesViewModel.remoteState.collectAsState()
|
||||
val remotes = remotesState.remotes
|
||||
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(AppIcons.ADD),
|
||||
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(AppIcons.REMOVE),
|
||||
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 != 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(),
|
||||
)
|
||||
}
|
@ -3,7 +3,7 @@ package com.jetpackduba.gitnuro.viewmodels
|
||||
import com.jetpackduba.gitnuro.TaskType
|
||||
import com.jetpackduba.gitnuro.git.RefreshType
|
||||
import com.jetpackduba.gitnuro.git.TabState
|
||||
import com.jetpackduba.gitnuro.git.remote_operations.FetchAllBranchesUseCase
|
||||
import com.jetpackduba.gitnuro.git.remote_operations.FetchAllRemotesUseCase
|
||||
import com.jetpackduba.gitnuro.git.remote_operations.PullBranchUseCase
|
||||
import com.jetpackduba.gitnuro.git.remote_operations.PullType
|
||||
import com.jetpackduba.gitnuro.git.remote_operations.PushBranchUseCase
|
||||
@ -19,7 +19,7 @@ class MenuViewModel @Inject constructor(
|
||||
private val tabState: TabState,
|
||||
private val pullBranchUseCase: PullBranchUseCase,
|
||||
private val pushBranchUseCase: PushBranchUseCase,
|
||||
private val fetchAllBranchesUseCase: FetchAllBranchesUseCase,
|
||||
private val fetchAllRemotesUseCase: FetchAllRemotesUseCase,
|
||||
private val popLastStashUseCase: PopLastStashUseCase,
|
||||
private val stashChangesUseCase: StashChangesUseCase,
|
||||
private val stageUntrackedFileUseCase: StageUntrackedFileUseCase,
|
||||
@ -50,7 +50,7 @@ class MenuViewModel @Inject constructor(
|
||||
taskType = TaskType.FETCH,
|
||||
positiveFeedbackText = "Fetch all completed",
|
||||
) { git ->
|
||||
fetchAllBranchesUseCase(git)
|
||||
fetchAllRemotesUseCase(git)
|
||||
}
|
||||
|
||||
fun push(force: Boolean = false, pushTags: Boolean = false) = tabState.safeProcessing(
|
||||
|
@ -6,15 +6,11 @@ import com.jetpackduba.gitnuro.extensions.lowercaseContains
|
||||
import com.jetpackduba.gitnuro.extensions.simpleName
|
||||
import com.jetpackduba.gitnuro.git.RefreshType
|
||||
import com.jetpackduba.gitnuro.git.TabState
|
||||
import com.jetpackduba.gitnuro.git.branches.CheckoutRefUseCase
|
||||
import com.jetpackduba.gitnuro.git.branches.DeleteLocallyRemoteBranchesUseCase
|
||||
import com.jetpackduba.gitnuro.git.branches.GetCurrentBranchUseCase
|
||||
import com.jetpackduba.gitnuro.git.branches.GetRemoteBranchesUseCase
|
||||
import com.jetpackduba.gitnuro.git.remote_operations.DeleteRemoteBranchUseCase
|
||||
import com.jetpackduba.gitnuro.git.remote_operations.PullFromSpecificBranchUseCase
|
||||
import com.jetpackduba.gitnuro.git.remote_operations.PushToSpecificBranchUseCase
|
||||
import com.jetpackduba.gitnuro.git.remotes.*
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.RemoteWrapper
|
||||
import com.jetpackduba.gitnuro.models.RemoteWrapper
|
||||
import com.jetpackduba.gitnuro.viewmodels.ISharedRemotesViewModel
|
||||
import com.jetpackduba.gitnuro.viewmodels.SharedRemotesViewModel
|
||||
import dagger.assisted.Assisted
|
||||
@ -45,6 +41,9 @@ class RemotesViewModel @AssistedInject constructor(
|
||||
private val remotes = MutableStateFlow<List<RemoteView>>(listOf())
|
||||
private val currentBranch = MutableStateFlow<Ref?>(null)
|
||||
|
||||
private val _remoteUpdated = MutableSharedFlow<Unit>()
|
||||
val remoteUpdated = _remoteUpdated.asSharedFlow()
|
||||
|
||||
val remoteState: StateFlow<RemotesState> =
|
||||
combine(remotes, isExpanded, filter, currentBranch) { remotes, isExpanded, filter, currentBranch ->
|
||||
val remotesFiltered = remotes.map { remote ->
|
||||
@ -115,8 +114,8 @@ class RemotesViewModel @AssistedInject constructor(
|
||||
tabState.newSelectedRef(ref, ref.objectId)
|
||||
}
|
||||
|
||||
fun deleteRemote(remoteName: String, isNew: Boolean) = tabState.safeProcessing(
|
||||
refreshType = if (isNew) RefreshType.REMOTES else RefreshType.ALL_DATA,
|
||||
fun deleteRemote(remoteName: String) = tabState.safeProcessing(
|
||||
refreshType = RefreshType.ALL_DATA,
|
||||
taskType = TaskType.DELETE_REMOTE,
|
||||
positiveFeedbackText = "Remote $remoteName deleted",
|
||||
) { git ->
|
||||
@ -176,6 +175,8 @@ class RemotesViewModel @AssistedInject constructor(
|
||||
uri = selectedRemoteConfig.pushUri,
|
||||
uriType = RemoteSetUrlCommand.UriType.PUSH
|
||||
)
|
||||
|
||||
_remoteUpdated.emit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
|
1
src/main/resources/edit.svg
Normal file
1
src/main/resources/edit.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M200-200h57l391-391-57-57-391 391v57Zm-80 80v-170l528-527q12-11 26.5-17t30.5-6q16 0 31 6t26 18l55 56q12 11 17.5 26t5.5 30q0 16-5.5 30.5T817-647L290-120H120Zm640-584-56-56 56 56Zm-141 85-28-29 57 57-29-28Z"/></svg>
|
After Width: | Height: | Size: 329 B |
Loading…
Reference in New Issue
Block a user