Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.github.familyvault.utils

object MimeTypeParser {
private val mimeTypes: Map<String, String> = mapOf(
"html" to "text/html",
"htm" to "text/html",
"shtml" to "text/html",
"css" to "text/css",
"xml" to "text/xml",
"gif" to "image/gif",
"jpeg" to "image/jpeg",
"jpg" to "image/jpeg",
"js" to "application/javascript",
"atom" to "application/atom+xml",
"rss" to "application/rss+xml",
"mml" to "text/mathml",
"txt" to "text/plain",
"jad" to "text/vnd.sun.j2me.app-descriptor",
"wml" to "text/vnd.wap.wml",
"htc" to "text/x-component",
"png" to "image/png",
"tif" to "image/tiff",
"tiff" to "image/tiff",
"wbmp" to "image/vnd.wap.wbmp",
"ico" to "image/x-icon",
"jng" to "image/x-jng",
"bmp" to "image/x-ms-bmp",
"svg" to "image/svg+xml",
"svgz" to "image/svg+xml",
"webp" to "image/webp",
"woff" to "application/font-woff",
"jar" to "application/java-archive",
"war" to "application/java-archive",
"ear" to "application/java-archive",
"json" to "application/json",
"hqx" to "application/mac-binhex40",
"doc" to "application/msword",
"pdf" to "application/pdf",
"ps" to "application/postscript",
"eps" to "application/postscript",
"ai" to "application/postscript",
"rtf" to "application/rtf",
"m3u8" to "application/vnd.apple.mpegurl",
"xls" to "application/vnd.ms-excel",
"eot" to "application/vnd.ms-fontobject",
"ppt" to "application/vnd.ms-powerpoint",
"wmlc" to "application/vnd.wap.wmlc",
"kml" to "application/vnd.google-earth.kml+xml",
"kmz" to "application/vnd.google-earth.kmz",
"7z" to "application/x-7z-compressed",
"cco" to "application/x-cocoa",
"jardiff" to "application/x-java-archive-diff",
"jnlp" to "application/x-java-jnlp-file",
"run" to "application/x-makeself",
"pl" to "application/x-perl",
"pm" to "application/x-perl",
"prc" to "application/x-pilot",
"pdb" to "application/x-pilot",
"rar" to "application/x-rar-compressed",
"rpm" to "application/x-redhat-package-manager",
"sea" to "application/x-sea",
"swf" to "application/x-shockwave-flash",
"sit" to "application/x-stuffit",
"tcl" to "application/x-tcl",
"tk" to "application/x-tcl",
"der" to "application/x-x509-ca-cert",
"pem" to "application/x-x509-ca-cert",
"crt" to "application/x-x509-ca-cert",
"xpi" to "application/x-xpinstall",
"xhtml" to "application/xhtml+xml",
"xspf" to "application/xspf+xml",
"zip" to "application/zip",
"docx" to "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"xlsx" to "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"pptx" to "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"mid" to "audio/midi",
"midi" to "audio/midi",
"kar" to "audio/midi",
"mp3" to "audio/mpeg",
"ogg" to "audio/ogg",
"m4a" to "audio/x-m4a",
"ra" to "audio/x-realaudio",
"3gpp" to "video/3gpp",
"3gp" to "video/3gpp",
"ts" to "video/mp2t",
"mp4" to "video/mp4",
"mpeg" to "video/mpeg",
"mpg" to "video/mpeg",
"mov" to "video/quicktime",
"webm" to "video/webm",
"flv" to "video/x-flv",
"m4v" to "video/x-m4v",
"mng" to "video/x-mng",
"asx" to "video/x-ms-asf",
"asf" to "video/x-ms-asf",
"wmv" to "video/x-ms-wmv",
"avi" to "video/x-msvideo",
"pmxtt" to "application/x-stt",
"pmxmm" to "application/x-smm",
"pmxaa" to "audio/webm;codecs=opus",
"opus" to "audio/opus"
)

fun getMimeType(extension: String): String {
val type = mimeTypes.get(extension.lowercase())
if (type != null) return type
else return "application/octet-stream"
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,35 @@
package com.github.familyvault.services

import androidx.compose.runtime.mutableStateListOf
import androidx.compose.ui.graphics.ImageBitmap
import com.github.familyvault.utils.MimeTypeParser
import io.ktor.utils.io.core.toByteArray
import kotlinx.cinterop.BetaInteropApi
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.useContents
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.runBlocking
import platform.CoreGraphics.CGContextScaleCTM
import platform.CoreGraphics.CGContextTranslateCTM
import platform.Foundation.NSData
import platform.Foundation.NSURL
import platform.Foundation.dataWithContentsOfURL
import platform.PDFKit.PDFDocument
import platform.PDFKit.kPDFDisplayBoxMediaBox
import platform.UIKit.UIApplication
import platform.UIKit.UIColor
import platform.UIKit.UIDocumentPickerDelegateProtocol
import platform.UIKit.UIDocumentPickerViewController
import platform.UIKit.UIGraphicsImageRenderer
import platform.UIKit.UIImageJPEGRepresentation
import platform.UniformTypeIdentifiers.UTTypeArchive
import platform.UniformTypeIdentifiers.UTTypeImage
import platform.UniformTypeIdentifiers.UTTypeMovie
import platform.UniformTypeIdentifiers.UTTypePDF
import platform.UniformTypeIdentifiers.UTTypePresentation
import platform.UniformTypeIdentifiers.UTTypeSpreadsheet
import platform.UniformTypeIdentifiers.UTTypeText
import platform.darwin.NSObject
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
Expand All @@ -10,49 +38,145 @@ class DocumentPickerService : IDocumentPickerService {
private var continuation: Continuation<List<ByteArray>>? = null
private val selectedDocumentUrls = mutableStateListOf<String>()
private var isInitialized = false
private var documentPickerViewController: UIDocumentPickerViewController? = null
private val pickerController = DocumentPickerController(selectedDocumentUrls) {
continuation?.resume(getSelectedDocumentAsByteArrays())
continuation = null
documentPickerViewController = null
}

companion object {
private const val TAG = "DocumentPickerService"
}

fun initializeWithActivity() {
TODO("Method not yet implemented")
}

override fun openDocumentPicker() {
TODO("Method not yet implemented")
if (documentPickerViewController == null) documentPickerViewController =
UIDocumentPickerViewController(
forOpeningContentTypes = listOf(
UTTypeSpreadsheet,
UTTypePresentation,
UTTypePDF,
UTTypeText,
UTTypeMovie,
UTTypeArchive,
UTTypeImage
)
)
documentPickerViewController?.allowsMultipleSelection = true
documentPickerViewController?.setDelegate(pickerController)
UIApplication.sharedApplication.keyWindow?.rootViewController?.presentViewController(
documentPickerViewController!!,
true,
null
)
}

override suspend fun pickDocumentsAndReturnByteArrays(): List<ByteArray> =
TODO("Method not yet implemented")
suspendCoroutine { cont ->
continuation = cont
try {
openDocumentPicker()
} catch (e: Exception) {
cont.resume(emptyList())
}
}

override fun getBytesFromUri(uriString: String): ByteArray? {
TODO("Method not yet implemented")
return selectedDocumentUrls.firstOrNull { uri ->
uri == uriString
}.let { it ->
return@let runBlocking(Dispatchers.IO) {
suspendCoroutine { cont ->
cont.resume(it?.toByteArray())
}
}
}
}

override fun getSelectedDocumentAsByteArrays(): List<ByteArray> {
TODO("Method not yet implemented")
return selectedDocumentUrls.map { url ->
runBlocking {
suspendCoroutine { cont ->
val data: NSData = NSData.dataWithContentsOfURL(NSURL.fileURLWithPath(url))!!
cont.resume(data.toByteArray())
}
}
}
}

override fun getSelectedDocumentUrls(): List<String> = selectedDocumentUrls
override fun getSelectedDocumentUrls(): List<String> {
return selectedDocumentUrls
}

override fun clearSelectedDocuments() {
TODO("Method not yet implemented")
selectedDocumentUrls.clear()
}

override fun removeSelectedDocument(uri: String) {
TODO("Method not yet implemented")
selectedDocumentUrls.remove(uri)
}

override fun getDocumentNameFromUri(uriString: String): String? {
TODO("Method not yet implemented")
return NSURL.fileURLWithPath(uriString).lastPathComponent()
}

override fun getDocumentMimeTypeFromUri(uriString: String): String? {
TODO("Method not yet implemented")
return MimeTypeParser.getMimeType(
NSURL.fileURLWithPath(uriString).pathExtension().toString()
)
}

@OptIn(ExperimentalForeignApi::class)
override fun getDocumentPreviewPageFromUri(uriString: String): ByteArray {
TODO("Method not yet implemented")
val url = NSURL.fileURLWithPath(uriString)
val pdf = PDFDocument(url)
val page = pdf.pageAtIndex(0u)
val bounds = page?.boundsForBox(kPDFDisplayBoxMediaBox)

val renderer = UIGraphicsImageRenderer(bounds!!)
val image = renderer.imageWithActions { it ->
UIColor.whiteColor.set()
it?.fillRect(page.boundsForBox(kPDFDisplayBoxMediaBox))

val context = it!!.CGContext
CGContextTranslateCTM(context, 0.0, (bounds.useContents { size.height }))
CGContextScaleCTM(context, 1.0, (-1.0))
page.drawWithBox(kPDFDisplayBoxMediaBox, context)
}

val data = UIImageJPEGRepresentation(image, 0.95)
return data?.toByteArray()!!
}
}

@OptIn(BetaInteropApi::class)
class DocumentPickerController(
val selectedUris: MutableList<String>,
val onFinish: () -> Unit
) : NSObject(),
UIDocumentPickerDelegateProtocol {

override fun documentPicker(
controller: UIDocumentPickerViewController,
didPickDocumentsAtURLs: List<*>
) {
val pickedDocumentsURLs =
didPickDocumentsAtURLs.filterIsInstance<NSURL>().map { it.path ?: "" }

selectedUris.clear()
selectedUris.addAll(pickedDocumentsURLs)
controller.dismissViewControllerAnimated(true) {
onFinish()
}
}

override fun documentPickerWasCancelled(controller: UIDocumentPickerViewController) {
selectedUris.clear()
controller.dismissViewControllerAnimated(true) {
onFinish()
}
}
}