Fixed images viewing in system default image viewer not working

This commit is contained in:
Abdelilah El Aissaoui 2022-11-10 18:27:48 +01:00
parent 45ad7f64ac
commit 1bfa65b740
6 changed files with 92 additions and 29 deletions

View File

@ -0,0 +1,43 @@
package com.jetpackduba.gitnuro
import com.jetpackduba.gitnuro.extensions.OS
import com.jetpackduba.gitnuro.extensions.getCurrentOs
import com.jetpackduba.gitnuro.logging.printLog
import java.io.File
import javax.inject.Inject
private const val TAG = "AppFilesManager"
class AppFilesManager @Inject constructor() {
fun getAppFolder(): File {
val baseFolderPath = when (getCurrentOs()) {
OS.LINUX -> {
var configFolder: String? = System.getenv("XDG_CONFIG_HOME")
if (configFolder.isNullOrEmpty())
configFolder = "${System.getenv("HOME")}/.config"
configFolder
}
OS.WINDOWS -> System.getenv("APPDATA").orEmpty()
OS.MAC -> System.getProperty("user.home") + "/Library/Application"
else -> {
printLog(TAG, "Unknown OS")
throw Exception("Invalid OS")
}
}
val baseFolder = File(baseFolderPath)
baseFolder.mkdirs()
val appFolder = File(baseFolder, "gitnuro")
// TODO test if mkdir fails for some reason
if(!appFolder.exists() || !appFolder.isDirectory)
appFolder.mkdir()
return appFolder
}
}

View File

@ -1,20 +1,23 @@
package com.jetpackduba.gitnuro package com.jetpackduba.gitnuro
import com.jetpackduba.gitnuro.di.TabScope import com.jetpackduba.gitnuro.di.TabScope
import com.jetpackduba.gitnuro.extensions.openDirectory
import java.io.File
import java.nio.file.Files
import javax.inject.Inject import javax.inject.Inject
import kotlin.io.path.createTempDirectory
import kotlin.io.path.deleteIfExists
@TabScope @TabScope
class TempFilesManager @Inject constructor() { class TempFilesManager @Inject constructor(
val tempDir by lazy { private val appFilesManager: AppFilesManager,
val tempDirPath = createTempDirectory("gitnuro_") ) {
tempDirPath.toFile().deleteOnExit() fun tempDir(): File {
val appDataDir = appFilesManager.getAppFolder()
val tempDir = appDataDir.openDirectory("tmp")
tempDirPath if(!tempDir.exists() || !tempDir.isDirectory) {
} tempDir.mkdir()
}
fun removeTempDir() { return tempDir
tempDir.deleteIfExists()
} }
} }

View File

@ -0,0 +1,13 @@
package com.jetpackduba.gitnuro.extensions
import java.io.File
fun File.openDirectory(dirName: String): File {
val newDir = File(this, dirName)
if (!newDir.exists() || !newDir.isDirectory) {
newDir.mkdir()
}
return newDir
}

View File

@ -28,7 +28,7 @@ fun runCommand(command: String): String? {
fun runCommandWithoutResult(command: String, args: String, file: String): Boolean { fun runCommandWithoutResult(command: String, args: String, file: String): Boolean {
val parts: Array<String> = prepareCommand(command, args, file) val parts: Array<String> = prepareCommand(command, args, file)
printLog(TAG, "Running command $parts") printLog(TAG, "Running command ${parts.joinToString( )}")
return try { return try {
val p = Runtime.getRuntime().exec(parts) ?: return false val p = Runtime.getRuntime().exec(parts) ?: return false

View File

@ -1,7 +1,7 @@
package com.jetpackduba.gitnuro.git package com.jetpackduba.gitnuro.git
import com.jetpackduba.gitnuro.TempFilesManager import com.jetpackduba.gitnuro.TempFilesManager
import com.jetpackduba.gitnuro.extensions.systemSeparator import com.jetpackduba.gitnuro.extensions.fileName
import org.eclipse.jgit.diff.ContentSource import org.eclipse.jgit.diff.ContentSource
import org.eclipse.jgit.diff.DiffEntry import org.eclipse.jgit.diff.DiffEntry
import org.eclipse.jgit.diff.RawText import org.eclipse.jgit.diff.RawText
@ -11,16 +11,21 @@ import org.eclipse.jgit.storage.pack.PackConfig
import org.eclipse.jgit.treewalk.AbstractTreeIterator import org.eclipse.jgit.treewalk.AbstractTreeIterator
import org.eclipse.jgit.treewalk.WorkingTreeIterator import org.eclipse.jgit.treewalk.WorkingTreeIterator
import org.eclipse.jgit.util.LfsFactory import org.eclipse.jgit.util.LfsFactory
import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import javax.inject.Inject import javax.inject.Inject
import kotlin.io.path.createTempFile
private const val DEFAULT_BINARY_FILE_THRESHOLD = PackConfig.DEFAULT_BIG_FILE_THRESHOLD private const val DEFAULT_BINARY_FILE_THRESHOLD = PackConfig.DEFAULT_BIG_FILE_THRESHOLD
private const val IMAGE_CONTENT_TYPE = "image/" private const val IMAGE_CONTENT_TYPE = "image/"
/**
* Max of chars that a file name can have. Used to avoid issues with OS chars limit in file names.
*/
private const val FILE_NAME_MAX_LENGTH = 250
val animatedImages = arrayOf( val animatedImages = arrayOf(
"image/gif", "image/gif",
"image/webp" "image/webp"
@ -76,17 +81,21 @@ class RawFileManager @Inject constructor(
entry: DiffEntry, entry: DiffEntry,
side: DiffEntry.Side side: DiffEntry.Side
): EntryContent.ImageBinary { ): EntryContent.ImageBinary {
val tempDir = tempFilesManager.tempDir val tempDir = tempFilesManager.tempDir()
val tempFile = createTempFile(tempDir, prefix = "${entry.newPath.replace(systemSeparator, "_")}_${side.name}") val prefix = "${entry.getId(side).name().take(20)}_${side.name}_"
tempFile.toFile().deleteOnExit() val tempFileName = prefix + entry.fileName.take(FILE_NAME_MAX_LENGTH - prefix.length)
val out = FileOutputStream(tempFile.toFile()) val tempFile = File(tempDir, tempFileName)
tempFile.deleteOnExit()
val out = FileOutputStream(tempFile)
out.use { out.use {
ldr.copyTo(out) ldr.copyTo(out)
} }
return EntryContent.ImageBinary(tempFile, Files.probeContentType(Path.of(entry.newPath)).orEmpty()) return EntryContent.ImageBinary(tempFile.absolutePath, Files.probeContentType(Path.of(entry.newPath)).orEmpty())
} }
private fun isImage(entry: DiffEntry): Boolean { private fun isImage(entry: DiffEntry): Boolean {
@ -102,7 +111,7 @@ sealed class EntryContent {
object InvalidObjectBlob : EntryContent() object InvalidObjectBlob : EntryContent()
data class Text(val rawText: RawText) : EntryContent() data class Text(val rawText: RawText) : EntryContent()
sealed class BinaryContent : EntryContent() sealed class BinaryContent : EntryContent()
data class ImageBinary(val tempFilePath: Path, val contentType: String) : BinaryContent() data class ImageBinary(val imagePath: String, val contentType: String) : BinaryContent()
object Binary : BinaryContent() object Binary : BinaryContent()
object TooLargeEntry : EntryContent() object TooLargeEntry : EntryContent()
} }

View File

@ -27,7 +27,6 @@ import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.onPointerEvent import androidx.compose.ui.input.pointer.onPointerEvent
import androidx.compose.ui.res.loadImageBitmap import androidx.compose.ui.res.loadImageBitmap
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -58,8 +57,6 @@ import org.jetbrains.compose.animatedimage.animate
import org.jetbrains.compose.animatedimage.loadAnimatedImage import org.jetbrains.compose.animatedimage.loadAnimatedImage
import org.jetbrains.compose.resources.loadOrNull import org.jetbrains.compose.resources.loadOrNull
import java.io.FileInputStream import java.io.FileInputStream
import java.nio.file.Path
import kotlin.io.path.absolutePathString
import kotlin.math.max import kotlin.math.max
private const val MAX_MOVES_COUNT = 5 private const val MAX_MOVES_COUNT = 5
@ -253,7 +250,7 @@ fun SideTitle(text: String) {
fun SideDiff(entryContent: EntryContent) { fun SideDiff(entryContent: EntryContent) {
when (entryContent) { when (entryContent) {
EntryContent.Binary -> BinaryDiff() EntryContent.Binary -> BinaryDiff()
is EntryContent.ImageBinary -> ImageDiff(entryContent.tempFilePath, entryContent.contentType) is EntryContent.ImageBinary -> ImageDiff(entryContent.imagePath, entryContent.contentType)
else -> { else -> {
} }
// is EntryContent.Text -> //TODO maybe have a text view if the file was a binary before? // is EntryContent.Text -> //TODO maybe have a text view if the file was a binary before?
@ -262,9 +259,7 @@ fun SideDiff(entryContent: EntryContent) {
} }
@Composable @Composable
private fun ImageDiff(tempImagePath: Path, contentType: String) { private fun ImageDiff(imagePath: String, contentType: String) {
val imagePath = tempImagePath.absolutePathString()
if (animatedImages.contains(contentType)) { if (animatedImages.contains(contentType)) {
AnimatedImage(imagePath) AnimatedImage(imagePath)
} else { } else {
@ -305,13 +300,13 @@ private fun StaticImage(tempImagePath: String) {
} }
@Composable @Composable
private fun AnimatedImage(tempImagePath: String) { private fun AnimatedImage(iamgePath: String) {
Image( Image(
bitmap = loadOrNull(tempImagePath) { loadAnimatedImage(tempImagePath) }?.animate() ?: ImageBitmap.Blank, bitmap = loadOrNull(iamgePath) { loadAnimatedImage(iamgePath) }?.animate() ?: ImageBitmap.Blank,
contentDescription = null, contentDescription = null,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
.handMouseClickable { .handMouseClickable {
openFileWithExternalApp(tempImagePath) openFileWithExternalApp(iamgePath)
} }
) )
} }