diff --git a/build.gradle.kts b/build.gradle.kts index bc2f726..a7edc82 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,10 +4,10 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { // Kotlin version must match compose version - kotlin("jvm") version "1.6.10" - kotlin("kapt") version "1.6.10" - kotlin("plugin.serialization") version "1.6.10" - id("org.jetbrains.compose") version "1.1.1" + kotlin("jvm") version "1.7.0" + kotlin("kapt") version "1.7.0" + kotlin("plugin.serialization") version "1.7.0" + id("org.jetbrains.compose") version "1.2.0-alpha01-dev755" } // Remember to update Constants.APP_VERSION when changing this version @@ -29,9 +29,9 @@ dependencies { implementation(compose.desktop.components.splitPane) implementation("org.eclipse.jgit:org.eclipse.jgit:6.2.0.202206071550-r") implementation("org.apache.sshd:sshd-core:2.9.0") - implementation("com.google.dagger:dagger:2.43") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3") - kapt("com.google.dagger:dagger-compiler:2.43") + implementation("com.google.dagger:dagger:2.43.2") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0") + kapt("com.google.dagger:dagger-compiler:2.43.2") testImplementation(platform("org.junit:junit-bom:5.9.0")) testImplementation("org.junit.jupiter:junit-jupiter:5.9.0") testImplementation("io.mockk:mockk:1.12.5") diff --git a/src/main/kotlin/app/ui/UncommitedChanges.kt b/src/main/kotlin/app/ui/UncommitedChanges.kt index 224d064..9896f91 100644 --- a/src/main/kotlin/app/ui/UncommitedChanges.kt +++ b/src/main/kotlin/app/ui/UncommitedChanges.kt @@ -6,10 +6,9 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.ContextMenuArea -import androidx.compose.foundation.ContextMenuItem -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background +import androidx.compose.foundation.* +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsHoveredAsState import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed @@ -25,7 +24,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.input.key.onPreviewKeyEvent -import androidx.compose.ui.input.pointer.pointerMoveFilter import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -45,7 +43,6 @@ import app.ui.context_menu.EntryType import app.ui.context_menu.statusEntriesContextMenuItems import app.viewmodels.StageStatus import app.viewmodels.StatusViewModel -import kotlinx.coroutines.flow.collect import org.eclipse.jgit.lib.RepositoryState @Composable @@ -216,6 +213,7 @@ fun UncommitedChanges( }, onMerge = { doCommit(false) } ) + repositoryState.isRebasing -> RebasingButtons( canContinue = staged.isNotEmpty() || unstaged.isNotEmpty(), haveConflictsBeenSolved = unstaged.isEmpty(), @@ -226,6 +224,7 @@ fun UncommitedChanges( onContinue = { statusViewModel.continueRebase() }, onSkip = { statusViewModel.skipRebase() }, ) + repositoryState.isCherryPicking -> CherryPickingButtons( haveConflictsBeenSolved = unstaged.isEmpty(), onAbort = { @@ -236,6 +235,7 @@ fun UncommitedChanges( doCommit(false) } ) + repositoryState.isReverting -> RevertingButtons( haveConflictsBeenSolved = unstaged.none { it.statusType == StatusType.CONFLICTING }, canCommit = commitMessage.isNotBlank(), @@ -247,6 +247,7 @@ fun UncommitedChanges( doCommit(false) } ) + else -> UncommitedChangesButtons( canCommit = canCommit, canAmend = canAmend, @@ -572,22 +573,14 @@ private fun FileEntry( onButtonClick: () -> Unit, onGenerateContextMenu: (StatusEntry) -> List, ) { - var active by remember { mutableStateOf(false) } + val hoverInteraction = remember { MutableInteractionSource() } + val isHovered by hoverInteraction.collectIsHoveredAsState() Box( modifier = Modifier .handMouseClickable { onClick() } .fillMaxWidth() - .pointerMoveFilter( - onEnter = { - active = true - false - }, - onExit = { - active = false - false - } - ) + .hoverable(hoverInteraction) ) { ContextMenuArea( items = { @@ -635,7 +628,7 @@ private fun FileEntry( AnimatedVisibility( modifier = Modifier .align(Alignment.CenterEnd), - visible = active, + visible = isHovered, enter = fadeIn(), exit = fadeOut(), ) { diff --git a/src/main/kotlin/app/ui/dialogs/CloneDialog.kt b/src/main/kotlin/app/ui/dialogs/CloneDialog.kt index 7d63065..30fcb45 100644 --- a/src/main/kotlin/app/ui/dialogs/CloneDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/CloneDialog.kt @@ -13,7 +13,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusOrder +import androidx.compose.ui.focus.focusProperties +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.unit.dp import app.git.CloneStatus import app.theme.outlinedTextFieldColors @@ -43,18 +44,22 @@ fun CloneDialog( is CloneStatus.Cloning -> { Cloning(cloneViewModel, cloneStatusValue) } + is CloneStatus.Cancelling -> { onClose() } + is CloneStatus.Completed -> { onOpenRepository(cloneStatusValue.repoDir) onClose() } + is CloneStatus.Fail -> CloneInput( cloneViewModel = cloneViewModel, onClose = onClose, errorMessage = cloneStatusValue.reason ) + CloneStatus.None -> CloneInput( cloneViewModel = cloneViewModel, onClose = onClose, @@ -98,7 +103,8 @@ private fun CloneInput( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp, horizontal = 8.dp) - .focusOrder(urlFocusRequester) { + .focusRequester(urlFocusRequester) + .focusProperties { previous = cancelButtonFocusRequester next = directoryFocusRequester }, @@ -124,7 +130,8 @@ private fun CloneInput( modifier = Modifier .weight(1f) .padding(end = 4.dp) - .focusOrder(directoryFocusRequester) { + .focusRequester(directoryFocusRequester) + .focusProperties { previous = urlFocusRequester next = directoryButtonFocusRequester }, @@ -148,7 +155,8 @@ private fun CloneInput( directory = newDirectory }, modifier = Modifier - .focusOrder(directoryButtonFocusRequester) { + .focusRequester(directoryButtonFocusRequester) + .focusProperties { previous = directoryFocusRequester next = cloneButtonFocusRequester } @@ -188,7 +196,8 @@ private fun CloneInput( TextButton( modifier = Modifier .padding(end = 8.dp) - .focusOrder(cancelButtonFocusRequester) { + .focusRequester(cancelButtonFocusRequester) + .focusProperties { previous = cloneButtonFocusRequester next = urlFocusRequester }, @@ -204,7 +213,8 @@ private fun CloneInput( cloneViewModel.clone(directory, url) }, modifier = Modifier - .focusOrder(cloneButtonFocusRequester) { + .focusRequester(cloneButtonFocusRequester) + .focusProperties { previous = directoryButtonFocusRequester next = cancelButtonFocusRequester }, diff --git a/src/main/kotlin/app/ui/dialogs/NewBranchDialog.kt b/src/main/kotlin/app/ui/dialogs/NewBranchDialog.kt index 4adfb5a..ac31b88 100644 --- a/src/main/kotlin/app/ui/dialogs/NewBranchDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/NewBranchDialog.kt @@ -7,10 +7,10 @@ import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.* import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusOrder +import androidx.compose.ui.focus.focusProperties +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.unit.dp import app.keybindings.KeybindingOption @@ -35,7 +35,8 @@ fun NewBranchDialog( ) { OutlinedTextField( modifier = Modifier - .focusOrder(branchFieldFocusRequester) { + .focusRequester(branchFieldFocusRequester) + .focusProperties { this.next = buttonFieldFocusRequester } .width(300.dp) @@ -76,10 +77,12 @@ fun NewBranchDialog( Text("Cancel") } PrimaryButton( - modifier = Modifier.focusOrder(buttonFieldFocusRequester) { - this.previous = branchFieldFocusRequester - this.next = branchFieldFocusRequester - }, + modifier = Modifier + .focusRequester(buttonFieldFocusRequester) + .focusProperties { + this.previous = branchFieldFocusRequester + this.next = branchFieldFocusRequester + }, enabled = branchField.isNotBlank(), onClick = { onAccept(branchField) diff --git a/src/main/kotlin/app/ui/dialogs/NewTagDialog.kt b/src/main/kotlin/app/ui/dialogs/NewTagDialog.kt index cdace9e..1aefcdc 100644 --- a/src/main/kotlin/app/ui/dialogs/NewTagDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/NewTagDialog.kt @@ -8,10 +8,10 @@ import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.* import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusOrder +import androidx.compose.ui.focus.focusProperties +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.unit.dp import app.keybindings.KeybindingOption @@ -38,7 +38,8 @@ fun NewTagDialog( ) { OutlinedTextField( modifier = Modifier - .focusOrder(tagFieldFocusRequester) { + .focusRequester(tagFieldFocusRequester) + .focusProperties { this.next = buttonFieldFocusRequester } .width(300.dp) @@ -79,10 +80,12 @@ fun NewTagDialog( Text("Cancel") } PrimaryButton( - modifier = Modifier.focusOrder(buttonFieldFocusRequester) { - this.previous = tagFieldFocusRequester - this.next = tagFieldFocusRequester - }, + modifier = Modifier + .focusRequester(buttonFieldFocusRequester) + .focusProperties { + this.previous = tagFieldFocusRequester + this.next = tagFieldFocusRequester + }, enabled = tagField.isNotBlank(), onClick = { onAccept(tagField) diff --git a/src/main/kotlin/app/ui/dialogs/PasswordDialog.kt b/src/main/kotlin/app/ui/dialogs/PasswordDialog.kt index c1ccec8..0a8cbe5 100644 --- a/src/main/kotlin/app/ui/dialogs/PasswordDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/PasswordDialog.kt @@ -10,7 +10,8 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusOrder +import androidx.compose.ui.focus.focusProperties +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp @@ -46,7 +47,8 @@ fun PasswordDialog( OutlinedTextField( modifier = Modifier .padding(bottom = 8.dp) - .focusOrder(passwordFieldFocusRequester) { + .focusRequester(passwordFieldFocusRequester) + .focusProperties { this.next = buttonFieldFocusRequester } .width(300.dp) @@ -88,9 +90,11 @@ fun PasswordDialog( Text("Cancel") } PrimaryButton( - modifier = Modifier.focusOrder(buttonFieldFocusRequester) { - this.previous = passwordFieldFocusRequester - }, + modifier = Modifier + .focusRequester(buttonFieldFocusRequester) + .focusProperties { + this.previous = passwordFieldFocusRequester + }, onClick = { onAccept(passwordField) }, diff --git a/src/main/kotlin/app/ui/dialogs/ResetDialog.kt b/src/main/kotlin/app/ui/dialogs/ResetDialog.kt index 6c74aaa..6fc6715 100644 --- a/src/main/kotlin/app/ui/dialogs/ResetDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/ResetDialog.kt @@ -7,12 +7,11 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.mouseClickable +import androidx.compose.foundation.onClick import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.input.pointer.isPrimaryPressed import androidx.compose.ui.unit.dp import app.git.ResetType import app.theme.primaryTextColor @@ -92,11 +91,9 @@ fun RadioButtonText( Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier - .mouseClickable { - if (this.buttons.isPrimaryPressed) { - if (onClick != null) { - onClick() - } + .onClick { + if (onClick != null) { + onClick() } } ) { diff --git a/src/main/kotlin/app/ui/dialogs/StashWithMessageDialog.kt b/src/main/kotlin/app/ui/dialogs/StashWithMessageDialog.kt index 8e82400..6eb60f9 100644 --- a/src/main/kotlin/app/ui/dialogs/StashWithMessageDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/StashWithMessageDialog.kt @@ -8,10 +8,10 @@ import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.* import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusOrder +import androidx.compose.ui.focus.focusProperties +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.unit.dp import app.keybindings.KeybindingOption @@ -38,7 +38,8 @@ fun StashWithMessageDialog( ) { OutlinedTextField( modifier = Modifier - .focusOrder(textFieldFocusRequester) { + .focusRequester(textFieldFocusRequester) + .focusProperties { this.next = buttonFieldFocusRequester } .width(300.dp) @@ -78,10 +79,12 @@ fun StashWithMessageDialog( Text("Cancel") } PrimaryButton( - modifier = Modifier.focusOrder(buttonFieldFocusRequester) { - this.previous = textFieldFocusRequester - this.next = textFieldFocusRequester - }, + modifier = Modifier + .focusRequester(buttonFieldFocusRequester) + .focusProperties { + this.previous = textFieldFocusRequester + this.next = textFieldFocusRequester + }, enabled = textField.isNotBlank(), onClick = { onAccept(textField) diff --git a/src/main/kotlin/app/ui/dialogs/UserPasswordDialog.kt b/src/main/kotlin/app/ui/dialogs/UserPasswordDialog.kt index f350585..7ca6bac 100644 --- a/src/main/kotlin/app/ui/dialogs/UserPasswordDialog.kt +++ b/src/main/kotlin/app/ui/dialogs/UserPasswordDialog.kt @@ -8,10 +8,10 @@ import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.* import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusOrder +import androidx.compose.ui.focus.focusProperties +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp @@ -54,7 +54,8 @@ fun UserPasswordDialog( OutlinedTextField( modifier = Modifier - .focusOrder(userFieldFocusRequester) { + .focusRequester(userFieldFocusRequester) + .focusProperties { this.next = passwordFieldFocusRequester } .width(300.dp) @@ -83,7 +84,8 @@ fun UserPasswordDialog( OutlinedTextField( modifier = Modifier .padding(bottom = 8.dp) - .focusOrder(passwordFieldFocusRequester) { + .focusRequester(passwordFieldFocusRequester) + .focusProperties { this.previous = userFieldFocusRequester this.next = buttonFieldFocusRequester } @@ -128,10 +130,12 @@ fun UserPasswordDialog( Text("Cancel") } PrimaryButton( - modifier = Modifier.focusOrder(buttonFieldFocusRequester) { - this.previous = passwordFieldFocusRequester - this.next = userFieldFocusRequester - }, + modifier = Modifier + .focusRequester(buttonFieldFocusRequester) + .focusProperties { + this.previous = passwordFieldFocusRequester + this.next = userFieldFocusRequester + }, onClick = { onAccept(userField, passwordField) },