Private
Public Access
1
0

attachments: proper metadata plumbing

This commit is contained in:
2024-04-08 12:07:34 -07:00
parent 5a148e2b20
commit 20e33f70a8
3 changed files with 39 additions and 58 deletions

View File

@@ -2,55 +2,23 @@ package net.buzzert.kordophonedroid.ui.messagelist
import android.content.Context
import android.net.Uri
import android.util.Log
import androidx.compose.runtime.mutableStateListOf
import androidx.core.net.toFile
import android.webkit.MimeTypeMap
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import coil.Coil
import coil.ComponentRegistry
import coil.ImageLoader
import coil.ImageLoaderFactory
import coil.decode.DataSource
import coil.decode.ImageSource
import coil.disk.DiskCache
import coil.fetch.FetchResult
import coil.fetch.Fetcher
import coil.fetch.SourceResult
import coil.memory.MemoryCache
import coil.request.CachePolicy
import coil.request.Options
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import net.buzzert.kordophone.backend.model.Conversation
import net.buzzert.kordophone.backend.model.GUID
import net.buzzert.kordophone.backend.model.Message
import net.buzzert.kordophone.backend.model.OutgoingMessage
import net.buzzert.kordophone.backend.model.UploadingAttachmentMetadata
import net.buzzert.kordophone.backend.server.ChatRepository
import net.buzzert.kordophonedroid.ui.attachments.AttachmentFetchData
import net.buzzert.kordophonedroid.ui.attachments.AttachmentViewModel
import okio.ByteString.Companion.toByteString
import java.io.BufferedInputStream
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.nio.file.FileSystem
import java.util.Date
import java.util.UUID
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.xml.transform.Source
import kotlin.time.Duration.Companion.seconds
const val MVM_LOG: String = "MessageListViewModel"
@@ -106,7 +74,22 @@ class MessageListViewModel @Inject constructor(
conversation = conversation!!,
attachmentUris = attachmentUris,
attachmentDataSource = { uri ->
context.contentResolver.openInputStream(uri)
val resolver = context.contentResolver
val inputStream = resolver.openInputStream(uri)
val mimeType = resolver.getType(uri)
val extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType) ?: "jpg"
val filename = uri.lastPathSegment + ".$extension"
if (inputStream != null && mimeType != null) {
UploadingAttachmentMetadata(
inputStream = inputStream,
mimeType = mimeType,
filename = filename
)
} else {
null
}
}
)

View File

@@ -71,11 +71,17 @@ data class Message(
}
}
data class UploadingAttachmentMetadata(
val inputStream: InputStream,
val mimeType: String,
val filename: String,
)
data class OutgoingMessage(
val body: String,
val conversation: Conversation,
val attachmentUris: Set<Uri>,
val attachmentDataSource: (Uri) -> InputStream?
val attachmentDataSource: (Uri) -> UploadingAttachmentMetadata?
) {
val guid: String = UUID.randomUUID().toString()

View File

@@ -1,45 +1,37 @@
package net.buzzert.kordophone.backend.server
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.net.toFile
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import net.buzzert.kordophone.backend.db.CachedChatDatabase
import net.buzzert.kordophone.backend.events.MessageDeliveredEvent
import net.buzzert.kordophone.backend.model.Conversation
import net.buzzert.kordophone.backend.model.GUID
import net.buzzert.kordophone.backend.model.Message
import net.buzzert.kordophone.backend.model.OutgoingMessage
import net.buzzert.kordophone.backend.model.UpdateItem
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.RequestBody
import okio.BufferedSource
import java.io.File
import java.io.InputStream
import java.lang.Error
import java.net.URL
import java.util.Date
import java.util.Queue
import java.util.UUID
import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.CancellationException
import kotlin.Boolean
import kotlin.Int
import kotlin.String
import kotlin.let
const val REPO_LOG: String = "ChatRepository"
const val CONVERSATION_MESSAGE_SYNC_COUNT = 10
@@ -210,7 +202,10 @@ class ChatRepository(
private suspend fun uploadAttachment(filename: String, mediaType: String, source: InputStream): String {
val attachmentData = source.readBytes()
val requestBody = RequestBody.create(MediaType.get(mediaType), attachmentData)
source.close()
withContext(Dispatchers.IO) {
source.close()
}
val response = apiInterface.uploadAttachment(filename, requestBody)
return response.bodyOnSuccessOrThrow().transferGUID
@@ -237,7 +232,7 @@ class ChatRepository(
.onEach { it.conversation = conversation }
}
private suspend fun handleConversationChangedUpdate(conversation: Conversation) {
private fun handleConversationChangedUpdate(conversation: Conversation) {
Log.d(REPO_LOG, "Handling conversation changed update")
database.writeConversations(listOf(conversation))
}
@@ -276,13 +271,10 @@ class ChatRepository(
val attachmentGUIDs = mutableListOf<String>()
try {
for (uri: Uri in it.attachmentUris) {
val inputStream = it.attachmentDataSource(uri)
?: throw java.lang.Exception("No input stream")
val filename = uri.lastPathSegment ?: "attachment.png"
val mediaType = "image/png" // TODO: Actually get this: it needs to be plumbed through ContentResolver
val guid = uploadAttachment(filename, mediaType, inputStream)
val uploadData = it.attachmentDataSource(uri)
?: throw java.lang.Exception("No upload data.")
val guid = uploadAttachment(uploadData.filename, uploadData.mimeType, uploadData.inputStream)
attachmentGUIDs.add(guid)
}
} catch (e: java.lang.Exception) {