Fixed images viewing in system default image viewer not working
This commit is contained in:
parent
45ad7f64ac
commit
1bfa65b740
43
src/main/kotlin/com/jetpackduba/gitnuro/AppFilesManager.kt
Normal file
43
src/main/kotlin/com/jetpackduba/gitnuro/AppFilesManager.kt
Normal 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
|
||||
}
|
||||
}
|
@ -1,20 +1,23 @@
|
||||
package com.jetpackduba.gitnuro
|
||||
|
||||
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 kotlin.io.path.createTempDirectory
|
||||
import kotlin.io.path.deleteIfExists
|
||||
|
||||
@TabScope
|
||||
class TempFilesManager @Inject constructor() {
|
||||
val tempDir by lazy {
|
||||
val tempDirPath = createTempDirectory("gitnuro_")
|
||||
tempDirPath.toFile().deleteOnExit()
|
||||
class TempFilesManager @Inject constructor(
|
||||
private val appFilesManager: AppFilesManager,
|
||||
) {
|
||||
fun tempDir(): File {
|
||||
val appDataDir = appFilesManager.getAppFolder()
|
||||
val tempDir = appDataDir.openDirectory("tmp")
|
||||
|
||||
tempDirPath
|
||||
if(!tempDir.exists() || !tempDir.isDirectory) {
|
||||
tempDir.mkdir()
|
||||
}
|
||||
|
||||
fun removeTempDir() {
|
||||
tempDir.deleteIfExists()
|
||||
return tempDir
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -28,7 +28,7 @@ fun runCommand(command: String): String? {
|
||||
fun runCommandWithoutResult(command: String, args: String, file: String): Boolean {
|
||||
val parts: Array<String> = prepareCommand(command, args, file)
|
||||
|
||||
printLog(TAG, "Running command $parts")
|
||||
printLog(TAG, "Running command ${parts.joinToString( )}")
|
||||
|
||||
return try {
|
||||
val p = Runtime.getRuntime().exec(parts) ?: return false
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.jetpackduba.gitnuro.git
|
||||
|
||||
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.DiffEntry
|
||||
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.WorkingTreeIterator
|
||||
import org.eclipse.jgit.util.LfsFactory
|
||||
import java.io.File
|
||||
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/"
|
||||
|
||||
/**
|
||||
* 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(
|
||||
"image/gif",
|
||||
"image/webp"
|
||||
@ -76,17 +81,21 @@ class RawFileManager @Inject constructor(
|
||||
entry: DiffEntry,
|
||||
side: DiffEntry.Side
|
||||
): EntryContent.ImageBinary {
|
||||
val tempDir = tempFilesManager.tempDir
|
||||
val tempDir = tempFilesManager.tempDir()
|
||||
|
||||
val tempFile = createTempFile(tempDir, prefix = "${entry.newPath.replace(systemSeparator, "_")}_${side.name}")
|
||||
tempFile.toFile().deleteOnExit()
|
||||
val prefix = "${entry.getId(side).name().take(20)}_${side.name}_"
|
||||
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 {
|
||||
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 {
|
||||
@ -102,7 +111,7 @@ sealed class EntryContent {
|
||||
object InvalidObjectBlob : EntryContent()
|
||||
data class Text(val rawText: RawText) : 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 TooLargeEntry : EntryContent()
|
||||
}
|
@ -27,7 +27,6 @@ import androidx.compose.ui.input.pointer.PointerEventType
|
||||
import androidx.compose.ui.input.pointer.onPointerEvent
|
||||
import androidx.compose.ui.res.loadImageBitmap
|
||||
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.style.TextOverflow
|
||||
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.resources.loadOrNull
|
||||
import java.io.FileInputStream
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.math.max
|
||||
|
||||
private const val MAX_MOVES_COUNT = 5
|
||||
@ -253,7 +250,7 @@ fun SideTitle(text: String) {
|
||||
fun SideDiff(entryContent: EntryContent) {
|
||||
when (entryContent) {
|
||||
EntryContent.Binary -> BinaryDiff()
|
||||
is EntryContent.ImageBinary -> ImageDiff(entryContent.tempFilePath, entryContent.contentType)
|
||||
is EntryContent.ImageBinary -> ImageDiff(entryContent.imagePath, entryContent.contentType)
|
||||
else -> {
|
||||
}
|
||||
// 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
|
||||
private fun ImageDiff(tempImagePath: Path, contentType: String) {
|
||||
val imagePath = tempImagePath.absolutePathString()
|
||||
|
||||
private fun ImageDiff(imagePath: String, contentType: String) {
|
||||
if (animatedImages.contains(contentType)) {
|
||||
AnimatedImage(imagePath)
|
||||
} else {
|
||||
@ -305,13 +300,13 @@ private fun StaticImage(tempImagePath: String) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AnimatedImage(tempImagePath: String) {
|
||||
private fun AnimatedImage(iamgePath: String) {
|
||||
Image(
|
||||
bitmap = loadOrNull(tempImagePath) { loadAnimatedImage(tempImagePath) }?.animate() ?: ImageBitmap.Blank,
|
||||
bitmap = loadOrNull(iamgePath) { loadAnimatedImage(iamgePath) }?.animate() ?: ImageBitmap.Blank,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
.handMouseClickable {
|
||||
openFileWithExternalApp(tempImagePath)
|
||||
openFileWithExternalApp(iamgePath)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user