yayan vor 1 Jahr
Ursprung
Commit
aba53ddf39

+ 2 - 3
app/src/main/java/io/nexilis/alpha/ui/components/Attachments.kt

@@ -49,7 +49,6 @@ import androidx.compose.ui.window.Popup
 import androidx.core.content.FileProvider
 import androidx.core.net.toUri
 import androidx.navigation.NavType
-import io.nexilis.alpha.BuildConfig
 import io.nexilis.service.core.BlueSky
 import io.nexilis.service.core.DarkLimeGreen
 import io.nexilis.service.core.Orange
@@ -140,7 +139,7 @@ fun Attachments(modifier: Modifier, onAttachment: (List<Uri>) -> Unit) {
                             val file = context.createFile(".jpeg")
                             tempUri = FileProvider.getUriForFile(
                                 context,
-                                BuildConfig.APPLICATION_ID + ".provider", file
+                                context.applicationContext.packageName + ".provider", file
                             )
                             launcherCamera.launch(tempUri)
                         } else {
@@ -166,7 +165,7 @@ fun Attachments(modifier: Modifier, onAttachment: (List<Uri>) -> Unit) {
                             val file = context.createFile(".mp4")
                             tempUri = FileProvider.getUriForFile(
                                 context,
-                                BuildConfig.APPLICATION_ID + ".provider", file
+                                context.applicationContext.packageName + ".provider", file
                             )
                             launcherCaptureVideo.launch(tempUri)
                         } else {

+ 31 - 11
app/src/main/java/io/nexilis/alpha/ui/components/ContentChat.kt

@@ -3,6 +3,7 @@ package io.nexilis.alpha.ui.components
 import android.graphics.BitmapFactory
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.aspectRatio
@@ -15,12 +16,15 @@ import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.DownloadForOffline
 import androidx.compose.material.icons.filled.Headset
 import androidx.compose.material.icons.filled.PlayArrow
+import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.LinearProgressIndicator
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
@@ -35,13 +39,14 @@ import androidx.compose.ui.text.toUpperCase
 import androidx.compose.ui.unit.dp
 import androidx.core.content.FileProvider
 import androidx.exifinterface.media.ExifInterface
+import androidx.hilt.navigation.compose.hiltViewModel
 import coil.compose.rememberAsyncImagePainter
-import io.nexilis.alpha.BuildConfig
 import io.nexilis.alpha.R
 import io.nexilis.service.core.Orange
 import io.nexilis.service.core.extension
 import io.nexilis.service.core.toHumanStandard
 import io.nexilis.service.data.entities.Message
+import io.nexilis.service.data.viewmodels.ProgressViewModel
 import java.io.File
 import java.io.FileInputStream
 
@@ -52,7 +57,7 @@ fun ContentChat(modifier: Modifier = Modifier, message: Message) {
         Column(modifier = Modifier.padding(2.dp)) {
             val file = File(context.filesDir, message.image_id)
             val uri = FileProvider.getUriForFile(
-                context, BuildConfig.APPLICATION_ID + ".provider", file
+                context, context.applicationContext.packageName + ".provider", file
             )
             var width: Int
             var height: Int
@@ -113,7 +118,7 @@ fun ContentChat(modifier: Modifier = Modifier, message: Message) {
                 .padding(8.dp)
             ) {
                 FileType(
-                    file = message.file_id, modifier = Modifier
+                    message = message, modifier = Modifier
                         .align(Alignment.CenterVertically)
                 )
                 Column(
@@ -234,8 +239,8 @@ fun ContentChat(modifier: Modifier = Modifier, message: Message) {
 }
 
 @Composable
-fun FileType(file: String, modifier: Modifier) {
-    val imageVector = when (file.extension) {
+fun FileType(message: Message, modifier: Modifier) {
+    val imageVector = when (message.file_id.extension) {
         "apk", "aab" -> ImageVector.vectorResource(id = R.drawable.ic_apk)
         "aac", "mp3", "m4a", "ogg" -> ImageVector.vectorResource(id = R.drawable.ic_audio)
         "xls", "xlsx" -> ImageVector.vectorResource(id = R.drawable.ic_excel)
@@ -248,12 +253,27 @@ fun FileType(file: String, modifier: Modifier) {
         "zip", "gz", "rar" -> ImageVector.vectorResource(id = R.drawable.ic_zip)
         else -> ImageVector.vectorResource(id = R.drawable.ic_file)
     }
-    Image(
-        modifier = modifier
-            .size(48.dp),
-        imageVector = imageVector,
-        contentDescription = null
-    )
+    val progressViewModel: ProgressViewModel = hiltViewModel()
+    val progress by progressViewModel.get(message.message_id).observeAsState()
+    Box {
+        Image(
+            modifier = modifier
+                .size(48.dp),
+            imageVector = imageVector,
+            contentDescription = null
+        )
+        progress?.let {
+            if (it.value > 0f && it.value < 1f) {
+                CircularProgressIndicator(
+                    progress = { it.value },
+                    modifier = Modifier
+                        .align(Alignment.Center)
+                        .size(32.dp),
+                )
+            }
+        }
+
+    }
 }
 
 @Composable

+ 2 - 3
app/src/main/java/io/nexilis/alpha/ui/main/Chat.kt

@@ -28,7 +28,6 @@ import kotlinx.coroutines.launch
 @Composable
 fun Chat(
     navController: NavHostController,
-    contentPadding: PaddingValues,
     pin: String,
     me: Buddy
 ) {
@@ -40,7 +39,6 @@ fun Chat(
     ConstraintLayout(
         modifier = Modifier
             .fillMaxSize()
-            .consumeWindowInsets(contentPadding)
             .imePadding()
 //            .imeNestedScroll()
     ) {
@@ -56,7 +54,8 @@ fun Chat(
         ) {
             items(
                 count = lazyPagingItems.itemCount,
-                key = lazyPagingItems.itemKey { it.message_id }) { index ->
+                key = lazyPagingItems.itemKey { it.message_id }
+            ) { index ->
                 lazyPagingItems[index]?.let { message ->
                     ListItem(modifier = Modifier.fillMaxWidth(), headlineContent = {
                         Row(

+ 0 - 1
app/src/main/java/io/nexilis/alpha/ui/main/Main.kt

@@ -103,7 +103,6 @@ fun Main(navController: NavHostController, me: Buddy) {
                             Chat(
                                 navController = navMainController,
                                 pin = pin,
-                                contentPadding = contentPadding,
                                 me = me
                             )
                         }

+ 1 - 2
app/src/main/java/io/nexilis/alpha/ui/main/Profile.kt

@@ -30,7 +30,6 @@ import androidx.core.content.FileProvider
 import androidx.hilt.navigation.compose.hiltViewModel
 import coil.compose.rememberAsyncImagePainter
 import coil.request.ImageRequest
-import io.nexilis.alpha.BuildConfig
 import io.nexilis.service.core.createFile
 import io.nexilis.service.data.entities.Buddy
 import io.nexilis.service.data.viewmodels.BuddyViewModel
@@ -43,7 +42,7 @@ fun Profile(contentPadding: PaddingValues = PaddingValues(0.dp), me: Buddy) {
     val file = context.createFile(".jpeg")
     val uri = FileProvider.getUriForFile(
         context,
-        BuildConfig.APPLICATION_ID + ".provider", file
+        context.applicationContext.packageName + ".provider", file
     )
     var imageUri by remember { mutableStateOf<Uri>(Uri.EMPTY) }
     val launcher = rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) {

+ 5 - 0
cpaas-lite/src/main/java/io/nexilis/service/core/ApiModule.kt

@@ -92,6 +92,11 @@ object ApiModule {
         return database.prefsDao()
     }
 
+    @Provides
+    fun provideProgressDao(database: ApiRoomDatabase): ProgressDao {
+        return database.progressDao()
+    }
+
     @Provides
     fun providePullDao(database: ApiRoomDatabase): PullDao {
         return database.pullDao()

+ 40 - 3
cpaas-lite/src/main/java/io/nexilis/service/core/Network.kt

@@ -8,6 +8,7 @@ import androidx.core.content.FileProvider
 import io.nexilis.service.tag
 import okhttp3.Call
 import okhttp3.Callback
+import okhttp3.MediaType
 import okhttp3.MediaType.Companion.toMediaTypeOrNull
 import okhttp3.MultipartBody
 import okhttp3.OkHttpClient
@@ -16,6 +17,10 @@ import okhttp3.RequestBody
 import okhttp3.RequestBody.Companion.asRequestBody
 import okhttp3.RequestBody.Companion.toRequestBody
 import okhttp3.Response
+import okio.Buffer
+import okio.BufferedSink
+import okio.ForwardingSink
+import okio.Sink
 import okio.buffer
 import okio.sink
 import java.io.File
@@ -65,7 +70,7 @@ class Network {
         })
     }
 
-    fun upload(url: String, file: File) : Boolean {
+    fun uploadSync(url: String, file: File, onProgress: (Long, Long) -> Unit): Boolean {
         val client = OkHttpClient()
         val body: RequestBody = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             MultipartBody.Builder()
@@ -90,7 +95,7 @@ class Network {
             .url(url)
             .addHeader("User-Agent", "Mozilla/5.0")
             .addHeader("Cookie", "PHPSESSID=123;MOBILE=123")
-            .post(body)
+            .post(ProgressRequestBody(delegate = body, onProgress = onProgress))
             .build()
         Log.d(tag, "upload:execute:$url:${file.name}:${file.length()}")
         client.newCall(request).execute().use { response ->
@@ -149,4 +154,36 @@ class Network {
         return null
     }
 
-}
+}
+
+class ProgressRequestBody(
+    private val delegate: RequestBody,
+    private val onProgress: (Long, Long) -> Unit
+) : RequestBody() {
+    override fun contentType(): MediaType? {
+        return delegate.contentType()
+    }
+
+    override fun contentLength(): Long {
+        return delegate.contentLength()
+    }
+
+    override fun writeTo(sink: BufferedSink) {
+        val bufferedSink = ProgressSink(sink, onProgress).buffer()
+        delegate.writeTo(bufferedSink)
+        bufferedSink.flush()
+    }
+
+    inner class ProgressSink(delegate: Sink, private val onProgress: (Long, Long) -> Unit) :
+        ForwardingSink(delegate) {
+        private var byteProgress: Long = 0
+
+        override fun write(source: Buffer, byteCount: Long) {
+            super.write(source, byteCount)
+            byteProgress += byteCount
+            onProgress(byteProgress, contentLength())
+        }
+    }
+
+}
+

+ 10 - 2
cpaas-lite/src/main/java/io/nexilis/service/core/Outgoing.kt

@@ -90,10 +90,18 @@ class Outgoing(private val context: Context, parameters: WorkerParameters) :
                     else message.file_id
                     Log.d(tag, "message.file:$file")
                     if (file.isNotEmpty()) {
-                        val upload = Network().upload(
+                        val upload = Network().uploadSync(
                             "https://digixplatform.com/uploader",
                             File(context.filesDir, file)
-                        )
+                        ) { progress, length ->
+                            setProgressAsync(
+                                workDataOf(
+                                    "message_id" to id,
+                                    "progress" to progress,
+                                    "length" to length
+                                )
+                            )
+                        }
                         if (!upload) {
                             Log.d(tag, "Failed to upload image:${message.message_id}")
                             return Result.retry()

+ 21 - 0
cpaas-lite/src/main/java/io/nexilis/service/data/daos/ProgressDao.kt

@@ -0,0 +1,21 @@
+package io.nexilis.service.data.daos
+
+import androidx.lifecycle.LiveData
+import androidx.room.Dao
+import androidx.room.Query
+import androidx.room.Upsert
+import io.nexilis.service.data.entities.*
+
+@Dao
+interface ProgressDao {
+
+    @Query("select * from Progress where `message_id` = :id")
+    fun get(id: String): LiveData<Progress?>
+
+    @Upsert
+    suspend fun upsert(entity: Progress)
+
+    @Query("delete from Progress where `message_id` = :id")
+    suspend fun delete(id: String)
+
+}

+ 11 - 0
cpaas-lite/src/main/java/io/nexilis/service/data/entities/Progress.kt

@@ -0,0 +1,11 @@
+package io.nexilis.service.data.entities
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity
+data class Progress(
+    @PrimaryKey
+    val message_id: String,
+    val value: Float,
+) : MainEntity

+ 1 - 1
cpaas-lite/src/main/java/io/nexilis/service/data/entities/RemoteKey.kt

@@ -8,4 +8,4 @@ data class RemoteKey(
     @PrimaryKey
     val id: String,
     val nextOffset: Int,
-)
+) : MainEntity

+ 21 - 0
cpaas-lite/src/main/java/io/nexilis/service/data/repositories/MessageRepository.kt

@@ -5,6 +5,7 @@ import android.util.Log
 import androidx.activity.ComponentActivity
 import androidx.lifecycle.LiveData
 import androidx.paging.PagingSource
+import androidx.work.Data
 import androidx.work.OneTimeWorkRequestBuilder
 import androidx.work.OutOfQuotaPolicy
 import androidx.work.WorkManager
@@ -15,9 +16,11 @@ import io.nexilis.service.core.Outgoing
 import io.nexilis.service.data.daos.GroupMemberDao
 import io.nexilis.service.data.daos.MessageDao
 import io.nexilis.service.data.daos.MessageStatusDao
+import io.nexilis.service.data.daos.ProgressDao
 import io.nexilis.service.data.entities.MainEntity
 import io.nexilis.service.data.entities.Message
 import io.nexilis.service.data.entities.MessageStatus
+import io.nexilis.service.data.entities.Progress
 import io.nexilis.service.tag
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
@@ -30,6 +33,7 @@ class MessageRepository @Inject constructor(
     private val dao: MessageDao,
     private val messageStatusDao: MessageStatusDao,
     private val groupMemberDao: GroupMemberDao,
+    private val progressDao: ProgressDao
 ) : Repository {
 
     val all: LiveData<List<Message>> = dao.getAll()
@@ -97,6 +101,23 @@ class MessageRepository @Inject constructor(
         withContext(Dispatchers.Main) {
             WorkManager.getInstance(context).getWorkInfoByIdLiveData(id)
                 .observe(context as ComponentActivity) { workInfo ->
+                    if (workInfo != null) {
+                        val progress = workInfo.progress
+                        if (progress != Data.EMPTY) {
+                            val messageId = progress.getString("message_id")
+                            val value = progress.getLong("progress", 0)
+                            val length = progress.getLong("length", 0)
+                            apiScope.launch(Dispatchers.IO) {
+                                messageId?.let {
+                                    Log.d(
+                                        tag,
+                                        "progress from work:$it:$value:$length:${value.toFloat() / length.toFloat()}"
+                                    )
+                                    progressDao.upsert(Progress(it, value.toFloat() / length.toFloat()))
+                                }
+                            }
+                        }
+                    }
                     if (workInfo.state.isFinished) {
                         val messageId = workInfo.outputData.getString("message_id") ?: ""
                         val pin = workInfo.outputData.getString("opposite_pin") ?: ""

+ 22 - 0
cpaas-lite/src/main/java/io/nexilis/service/data/repositories/ProgressRepository.kt

@@ -0,0 +1,22 @@
+package io.nexilis.service.data.repositories
+
+import androidx.lifecycle.LiveData
+import io.nexilis.service.data.daos.ProgressDao
+import io.nexilis.service.data.entities.MainEntity
+import io.nexilis.service.data.entities.Progress
+import javax.inject.Inject
+
+class ProgressRepository @Inject constructor(private val dao: ProgressDao) : Repository {
+
+    fun get(id: String) : LiveData<Progress?> {
+        return dao.get(id)
+    }
+
+    suspend fun upsert(entity: MainEntity) {
+        dao.upsert(entity as Progress)
+    }
+
+    override suspend fun insert(entity: MainEntity) {
+
+    }
+}

+ 2 - 0
cpaas-lite/src/main/java/io/nexilis/service/data/rooms/ApiRoomDatabase.kt

@@ -27,6 +27,7 @@ import io.nexilis.service.data.entities.*
         MessageStatus::class,
         MessageSummary::class,
         Prefs::class,
+        Progress::class,
         Pull::class,
         RemoteKey::class,
         WorkingArea::class
@@ -49,6 +50,7 @@ abstract class ApiRoomDatabase : RoomDatabase() {
     abstract fun messageStatusDao(): MessageStatusDao
     abstract fun messageSummaryDao(): MessageSummaryDao
     abstract fun prefsDao(): PrefsDao
+    abstract fun progressDao(): ProgressDao
     abstract fun pullDao(): PullDao
     abstract fun remoteKeyDao(): RemoteKeyDao
     abstract fun workingAreaDao(): WorkingAreaDao

+ 18 - 0
cpaas-lite/src/main/java/io/nexilis/service/data/viewmodels/ProgressViewModel.kt

@@ -0,0 +1,18 @@
+package io.nexilis.service.data.viewmodels
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.ViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import io.nexilis.service.data.entities.Progress
+import io.nexilis.service.data.repositories.ProgressRepository
+import javax.inject.Inject
+
+@HiltViewModel
+class ProgressViewModel @Inject constructor(private val repository: ProgressRepository) :
+    ViewModel() {
+
+    fun get(id: String) : LiveData<Progress?> {
+        return repository.get(id)
+    }
+
+}