parent
115a195a61
commit
527d78229e
3 changed files with 62 additions and 21 deletions
|
@ -28,6 +28,7 @@ dependencies {
|
|||
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
|
||||
implementation(compose.desktop.components.splitPane)
|
||||
implementation(compose("org.jetbrains.compose.ui:ui-util"))
|
||||
implementation(compose("org.jetbrains.compose.components:components-animatedimage"))
|
||||
implementation("org.eclipse.jgit:org.eclipse.jgit:6.3.0.202209071007-r")
|
||||
implementation("org.apache.sshd:sshd-core:2.9.0")
|
||||
implementation("com.google.dagger:dagger:2.43.2")
|
||||
|
|
|
@ -12,23 +12,23 @@ import org.eclipse.jgit.treewalk.AbstractTreeIterator
|
|||
import org.eclipse.jgit.treewalk.WorkingTreeIterator
|
||||
import org.eclipse.jgit.util.LfsFactory
|
||||
import java.io.FileOutputStream
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import javax.inject.Inject
|
||||
import kotlin.io.path.createTempFile
|
||||
|
||||
|
||||
private const val DEFAULT_BINARY_FILE_THRESHOLD = PackConfig.DEFAULT_BIG_FILE_THRESHOLD
|
||||
private const val IMAGE_CONTENT_TYPE = "image/"
|
||||
|
||||
val animatedImages = arrayOf(
|
||||
"image/gif",
|
||||
"image/webp"
|
||||
)
|
||||
|
||||
class RawFileManager @Inject constructor(
|
||||
private val tempFilesManager: TempFilesManager,
|
||||
) {
|
||||
private val imageFormatsSupported = listOf(
|
||||
"png",
|
||||
"jpg",
|
||||
"jpeg",
|
||||
"webp",
|
||||
)
|
||||
|
||||
private fun source(iterator: AbstractTreeIterator, reader: ObjectReader): ContentSource {
|
||||
return if (iterator is WorkingTreeIterator)
|
||||
ContentSource.create(iterator)
|
||||
|
@ -86,15 +86,14 @@ class RawFileManager @Inject constructor(
|
|||
ldr.copyTo(out)
|
||||
}
|
||||
|
||||
return EntryContent.ImageBinary(tempFile)
|
||||
return EntryContent.ImageBinary(tempFile, Files.probeContentType(Path.of(entry.newPath)).orEmpty())
|
||||
}
|
||||
|
||||
// todo check if it's an image checking the binary format, checking the extension is a temporary workaround
|
||||
private fun isImage(entry: DiffEntry): Boolean {
|
||||
val path = entry.newPath
|
||||
val fileExtension = path.split(".").lastOrNull() ?: return false
|
||||
val contentType = Files.probeContentType(Path.of(path))
|
||||
|
||||
return imageFormatsSupported.contains(fileExtension.lowercase())
|
||||
return contentType?.startsWith(IMAGE_CONTENT_TYPE) ?: false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +102,7 @@ sealed class EntryContent {
|
|||
object InvalidObjectBlob : EntryContent()
|
||||
data class Text(val rawText: RawText) : EntryContent()
|
||||
sealed class BinaryContent : EntryContent()
|
||||
data class ImageBinary(val tempFilePath: Path) : BinaryContent()
|
||||
data class ImageBinary(val tempFilePath: Path, val contentType: String) : BinaryContent()
|
||||
object Binary : BinaryContent()
|
||||
object TooLargeEntry : EntryContent()
|
||||
}
|
|
@ -19,6 +19,7 @@ import androidx.compose.ui.focus.FocusRequester
|
|||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||
import androidx.compose.ui.input.pointer.PointerEventType
|
||||
import androidx.compose.ui.input.pointer.PointerIconDefaults
|
||||
|
@ -30,6 +31,10 @@ import androidx.compose.ui.text.font.FontFamily
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.jetpackduba.gitnuro.extensions.*
|
||||
import com.jetpackduba.gitnuro.git.DiffEntryType
|
||||
import com.jetpackduba.gitnuro.git.EntryContent
|
||||
import com.jetpackduba.gitnuro.git.animatedImages
|
||||
import com.jetpackduba.gitnuro.git.diff.DiffResult
|
||||
import com.jetpackduba.gitnuro.git.diff.Hunk
|
||||
import com.jetpackduba.gitnuro.git.diff.Line
|
||||
|
@ -38,16 +43,19 @@ import com.jetpackduba.gitnuro.git.workspace.StatusEntry
|
|||
import com.jetpackduba.gitnuro.git.workspace.StatusType
|
||||
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
import com.jetpackduba.gitnuro.keybindings.matchesBinding
|
||||
import com.jetpackduba.gitnuro.theme.*
|
||||
import com.jetpackduba.gitnuro.ui.components.ScrollableLazyColumn
|
||||
import com.jetpackduba.gitnuro.ui.components.SecondaryButton
|
||||
import com.jetpackduba.gitnuro.viewmodels.DiffViewModel
|
||||
import com.jetpackduba.gitnuro.viewmodels.TextDiffType
|
||||
import com.jetpackduba.gitnuro.viewmodels.ViewDiffResult
|
||||
import com.jetpackduba.gitnuro.extensions.*
|
||||
import com.jetpackduba.gitnuro.git.DiffEntryType
|
||||
import com.jetpackduba.gitnuro.git.EntryContent
|
||||
import com.jetpackduba.gitnuro.theme.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.diff.DiffEntry
|
||||
import org.jetbrains.compose.animatedimage.Blank
|
||||
import org.jetbrains.compose.animatedimage.animate
|
||||
import org.jetbrains.compose.animatedimage.loadAnimatedImage
|
||||
import org.jetbrains.compose.resources.loadOrNull
|
||||
import java.io.FileInputStream
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
|
@ -206,7 +214,7 @@ fun NonTextDiff(diffResult: DiffResult.NonText) {
|
|||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
SideTitle("Binary file")
|
||||
// SideTitle("Binary file")
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
SideDiff(newBinaryContent)
|
||||
}
|
||||
|
@ -227,7 +235,7 @@ fun SideTitle(text: String) {
|
|||
fun SideDiff(entryContent: EntryContent) {
|
||||
when (entryContent) {
|
||||
EntryContent.Binary -> BinaryDiff()
|
||||
is EntryContent.ImageBinary -> ImageDiff(entryContent.tempFilePath)
|
||||
is EntryContent.ImageBinary -> ImageDiff(entryContent.tempFilePath, entryContent.contentType)
|
||||
else -> {
|
||||
}
|
||||
// is EntryContent.Text -> //TODO maybe have a text view if the file was a binary before?
|
||||
|
@ -236,13 +244,46 @@ fun SideDiff(entryContent: EntryContent) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun ImageDiff(tempImagePath: Path) {
|
||||
private fun ImageDiff(tempImagePath: Path, contentType: String) {
|
||||
val imagePath = tempImagePath.absolutePathString()
|
||||
|
||||
if(animatedImages.contains(contentType)) {
|
||||
AnimatedImage(imagePath)
|
||||
} else {
|
||||
StaticImage(imagePath)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StaticImage(tempImagePath: String) {
|
||||
var image by remember(tempImagePath) { mutableStateOf<ImageBitmap?>(null) }
|
||||
|
||||
LaunchedEffect(tempImagePath) {
|
||||
withContext(Dispatchers.IO) {
|
||||
FileInputStream(tempImagePath).use { inputStream ->
|
||||
image = loadImageBitmap(inputStream = inputStream)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image(
|
||||
bitmap = loadImageBitmap(inputStream = FileInputStream(tempImagePath.absolutePathString())),
|
||||
bitmap = image ?: ImageBitmap.Blank,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
.handMouseClickable {
|
||||
openFileWithExternalApp(tempImagePath.absolutePathString())
|
||||
openFileWithExternalApp(tempImagePath)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AnimatedImage(tempImagePath: String) {
|
||||
Image(
|
||||
bitmap = loadOrNull(tempImagePath) { loadAnimatedImage(tempImagePath) }?.animate() ?: ImageBitmap.Blank,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
.handMouseClickable {
|
||||
openFileWithExternalApp(tempImagePath)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue