yayan hace 1 año
padre
commit
9675989256

+ 68 - 30
app/src/main/java/io/nexilis/alpha/ui/components/Attachments.kt

@@ -57,17 +57,20 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.window.Popup
+import androidx.core.content.FileProvider
 import androidx.core.net.toUri
 import androidx.hilt.navigation.compose.hiltViewModel
 import androidx.navigation.NavHostController
 import androidx.navigation.NavType
 import coil.compose.AsyncImage
 import coil.request.ImageRequest
+import io.nexilis.alpha.BuildConfig
 import io.nexilis.alpha.R
 import io.nexilis.service.core.BlueSky
 import io.nexilis.service.core.DarkLimeGreen
 import io.nexilis.service.core.Orange
 import io.nexilis.service.core.Purple
+import io.nexilis.service.core.createImageFile
 import io.nexilis.service.core.getMimeType
 import io.nexilis.service.core.getSharedPreferences
 import io.nexilis.service.data.entities.Message
@@ -90,6 +93,10 @@ fun Attachments(modifier: Modifier, onAttachment: (List<Uri>) -> Unit) {
     var isOpenMenu by remember {
         mutableStateOf(false)
     }
+    val context = LocalContext.current
+    var uri by remember {
+        mutableStateOf<Uri>(Uri.EMPTY)
+    }
     IconButton(onClick = {
         keyboardController?.hide()
         isOpenMenu = !isOpenMenu
@@ -105,36 +112,54 @@ fun Attachments(modifier: Modifier, onAttachment: (List<Uri>) -> Unit) {
         Popup(popupPositionProvider = positionProvider, onDismissRequest = { isOpenMenu = false }) {
             Box(modifier = modifier) {
                 Row(Modifier.align(Alignment.Center)) {
-                    Column {
-                        val context = LocalContext.current
-                        val launcher =
-                            rememberLauncherForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) {
-                                onAttachment(it)
-                                isOpenMenu = false
-                            }
-                        val permissionLauncher = rememberLauncherForActivityResult(
-                            ActivityResultContracts.RequestPermission()
-                        ) {
+                    var mimeType = arrayOf(
+                        "doc/*",
+                        "docx/*",
+                        "application/*"
+                    )
+                    val launcherFiles =
+                        rememberLauncherForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) {
+                            onAttachment(it)
+                            isOpenMenu = false
+                        }
+                    val permissionLauncherFiles = rememberLauncherForActivityResult(
+                        ActivityResultContracts.RequestPermission()
+                    ) {
+                        if (it) {
+                            launcherFiles.launch(mimeType)
+                        } else {
+                            Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT)
+                                .show()
+                        }
+                    }
+
+                    val launcherCamera =
+                        rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) {
                             if (it) {
-                                Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT)
-                                    .show()
-                                launcher.launch(
-                                    arrayOf(
-                                        "doc/*",
-                                        "docx/*",
-                                        "application/*",
-                                        "image/*"
-                                    )
-                                )
-                            } else {
-                                Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT)
-                                    .show()
+                                onAttachment(listOf(uri))
                             }
+                            isOpenMenu = false
+                        }
+                    val permissionLauncherCamera = rememberLauncherForActivityResult(
+                        ActivityResultContracts.RequestPermission()
+                    ) {
+                        if (it) {
+                            val file = context.createImageFile()
+                            uri = FileProvider.getUriForFile(
+                                context,
+                                BuildConfig.APPLICATION_ID + ".provider", file
+                            )
+                            launcherCamera.launch(uri)
+                        } else {
+                            Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT)
+                                .show()
                         }
+                    }
+                    Column {
                         AttachmentButton(
                             color = MaterialTheme.colorScheme.primary,
                             onClick = {
-                                permissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
+                                permissionLauncherFiles.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
                             },
                             text = {
                                 Text(text = "File", style = MaterialTheme.typography.bodySmall)
@@ -146,7 +171,12 @@ fun Attachments(modifier: Modifier, onAttachment: (List<Uri>) -> Unit) {
                             )
                         }
                         Spacer(modifier = Modifier.size(32.dp))
-                        AttachmentButton(color = Color.Orange, onClick = {}, text = {
+                        AttachmentButton(color = Color.Orange, onClick = {
+                            mimeType = arrayOf(
+                                "audio/*"
+                            )
+                            permissionLauncherFiles.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
+                        }, text = {
                             Text(text = "Audio", style = MaterialTheme.typography.bodySmall)
                         }) {
                             Icon(
@@ -158,7 +188,9 @@ fun Attachments(modifier: Modifier, onAttachment: (List<Uri>) -> Unit) {
                     }
                     Spacer(modifier = Modifier.size(16.dp))
                     Column {
-                        AttachmentButton(color = Color.Red, onClick = {}, text = {
+                        AttachmentButton(color = Color.Red, onClick = {
+                            permissionLauncherCamera.launch(Manifest.permission.CAMERA)
+                        }, text = {
                             Text(text = "Camera", style = MaterialTheme.typography.bodySmall)
                         }) {
                             Icon(
@@ -180,7 +212,13 @@ fun Attachments(modifier: Modifier, onAttachment: (List<Uri>) -> Unit) {
                     }
                     Spacer(modifier = Modifier.size(16.dp))
                     Column {
-                        AttachmentButton(color = Color.Purple, onClick = {}, text = {
+                        AttachmentButton(color = Color.Purple, onClick = {
+                            mimeType = arrayOf(
+                                "image/*",
+                                "video/*"
+                            )
+                            permissionLauncherFiles.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
+                        }, text = {
                             Text(text = "Gallery", style = MaterialTheme.typography.bodySmall)
                         }) {
                             Icon(
@@ -365,9 +403,9 @@ fun AttachmentCaption(
                                         message_large_text = "",
                                         message_text_plain = "",
                                         thumb_id = item.name,
-                                        image_id = item.name
-                                    ),
-                                    al.toList()
+                                        image_id = item.name,
+                                        uri = item.uri
+                                    )
                                 )
                             }
                         }

+ 67 - 4
app/src/main/java/io/nexilis/alpha/ui/main/Chat.kt

@@ -33,6 +33,7 @@ import io.nexilis.alpha.ui.components.getAttachmentItem
 import io.nexilis.alpha.ui.screen.Screen
 import io.nexilis.service.data.entities.Buddy
 import io.nexilis.service.data.entities.Message
+import io.nexilis.service.data.viewmodels.BuddyViewModel
 import io.nexilis.service.data.viewmodels.MessageViewModel
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
@@ -52,8 +53,14 @@ fun Chat(
     val state = rememberLazyListState()
     val context = LocalContext.current
     LaunchedEffect(key1 = list) {
-        list?.size?.minus(1)?.let { state.scrollToItem(it) }
+        list?.size?.let { size ->
+            if (size > 0) {
+                size.minus(1).let { state.scrollToItem(it) }
+            }
+        }
     }
+    var openAlertDialog by remember { mutableStateOf(false) }
+    val attachments = remember { mutableStateListOf<Uri>() }
     Column(
         modifier = Modifier
             .fillMaxSize()
@@ -120,6 +127,7 @@ fun Chat(
                         }
                         .background(MaterialTheme.colorScheme.surface),
                     onAttachment = { list ->
+                        attachments.addAll(list)
                         val items = list.map {
                             context.getAttachmentItem(it)
                         }
@@ -131,7 +139,7 @@ fun Chat(
                                 restoreState = true
                             }
                         } else if (items.size > 1) {
-
+                            openAlertDialog = true
                         }
                     }
                 )
@@ -157,9 +165,10 @@ fun Chat(
                                     status = "1",
                                     message_text = textInput.text,
                                     opposite_pin = pin,
-                                    f_display_name = it.first_name + " " + it.last_name,
+                                    f_display_name = "${it.first_name} ${it.last_name}".trim(),
                                     message_large_text = "",
-                                    message_text_plain = ""
+                                    message_text_plain = "",
+                                    uri = if (attachments.size > 0) attachments[0] else Uri.EMPTY
                                 )
                             )
                             textInput = TextFieldValue("")
@@ -185,6 +194,60 @@ fun Chat(
             keyboardOptions = KeyboardOptions(KeyboardCapitalization.Sentences),
             maxLines = 3
         )
+        if (openAlertDialog) {
+            val buddyModel: BuddyViewModel = hiltViewModel()
+            val buddy by buddyModel.getBuddy(pin).observeAsState()
+            buddy?.let {
+                AlertDialog(
+                    text = {
+                        Text(text = "Send ${attachments.size} documents to ${it.first_name} ${it.last_name}?".trim())
+                    },
+                    onDismissRequest = {
+                        openAlertDialog = false
+                    },
+                    confirmButton = {
+                        TextButton(
+                            onClick = {
+                                openAlertDialog = false
+                                me.let {
+                                    attachments.forEach { uri ->
+                                        messageModel.send(
+                                            context,
+                                            Message(
+                                                message_id = System.nanoTime().toString(),
+                                                f_pin = it.f_pin,
+                                                l_pin = pin,
+                                                message_scope_id = "3", // 3: chat, 15: sms, 16: email
+                                                server_date = System.currentTimeMillis(),
+                                                status = "1",
+                                                message_text = "",
+                                                opposite_pin = pin,
+                                                f_display_name = "${it.first_name} ${it.last_name}".trim(),
+                                                message_large_text = "",
+                                                message_text_plain = "",
+                                                uri = uri
+                                            )
+                                        )
+                                    }
+                                    textInput = TextFieldValue("")
+                                }
+                            }
+                        ) {
+                            Text("Send")
+                        }
+                    },
+                    dismissButton = {
+                        TextButton(
+                            onClick = {
+                                openAlertDialog = false
+                            }
+                        ) {
+                            Text("Cancel")
+                        }
+                    }
+                )
+            }
+        }
     }
 }
 

+ 3 - 1
cpaas-lite/src/main/java/io/nexilis/service/core/Extension.kt

@@ -79,7 +79,9 @@ fun Context.getMimeType(uri: Uri): String {
             return it
         }
     }
-    return contentResolver.getType(uri) ?: ""
+    val mimeType = contentResolver.getType(uri) ?: ""
+    Log.d(tag, "getMimeType:$mimeType")
+    return mimeType
 }
 
 fun String.toMD5(): String {

+ 2 - 1
cpaas-lite/src/main/java/io/nexilis/service/core/Incoming.kt

@@ -450,7 +450,8 @@ class Incoming(private val context: Context) {
                     data.bodies["lcltm"]?.toLong() ?: System.currentTimeMillis(),
                     data.bodies["ics"]?.toInt() ?: 0,
                     data.bodies["icc"]?.toInt() ?: 0,
-                    data.bodies["ccid"] ?: ""
+                    data.bodies["ccid"] ?: "",
+                    0
                 )
             )
             if (scope == "4") {

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

@@ -38,10 +38,10 @@ class Outgoing(private val context: Context, parameters: WorkerParameters) :
                         "A118" to message.credential,
                         "A149" to message.attachment_flag.toString(),
                         "A52" to message.blog_id,
-                        "ics" to message.is_consult.toString(),
-                        "icc" to message.is_call_center.toString(),
+                        "ics" to message.consult.toString(),
+                        "icc" to message.call_center.toString(),
                         "ccid" to message.call_center_id,
-                        "iwm" to message.is_work_mode.toString(),
+                        "iwm" to message.work_mode.toString(),
                         "Bf" to message.read_receipts.toString()
                     )
                     if (message.message_scope_id == "5") {
@@ -76,7 +76,7 @@ class Outgoing(private val context: Context, parameters: WorkerParameters) :
                     }
                     val data = Data(
                         code = "S0",
-                        status = message.message_id,
+                        status = message.message_id + System.nanoTime().toString(),
                         f_pin = message.f_pin,
                         bodies = bodies
                     )

+ 170 - 56
cpaas-lite/src/main/java/io/nexilis/service/data/entities/Message.kt

@@ -1,67 +1,181 @@
 package io.nexilis.service.data.entities
 
+import android.net.Uri
 import androidx.room.Entity
+import androidx.room.Ignore
 import androidx.room.Index
 
 @Entity(
     primaryKeys = ["message_id"],
     indices = [
-        Index(value = ["opposite_pin", "chat_id", "server_date", "account_type", "mail_account", "reff_id", "local_timestamp", "is_call_center"])
+        Index(value = ["opposite_pin", "chat_id", "server_date", "account_type", "mail_account", "reff_id", "local_timestamp", "call_center"])
     ]
 )
 data class Message(
-    val message_id: String,
-    val f_pin: String,
-    val l_pin: String,
-    val message_scope_id: String,
-    val server_date: Long,
-    val status: String,
-    val message_text: String,
-    val audio_id: String = "",
-    val video_id: String = "",
-    val image_id: String = "",
-    val thumb_id: String = "",
-    val opposite_pin: String,
-    val lock: String = "",
-    val format: String = "",
-    val broadcast_flag: Int = 0,
-    val blog_id: String = "",
-    val f_user_id: String = "",
-    val l_user_id: String = "",
-    val read_receipts: Int = 0,
-    val chat_id: String = "",
-    val file_id: String = "",
-    val delivery_receipts: Int = 0,
-    val account_type: String = "",
-    val contact: String = "",
-    val credential: String = "",
-    val attachment_flag: Int = 0,
-    val is_stared: Int = 0,
-    val f_display_name: String = "",
-    val reff_id: String = "",
-    val sent_qty: Int = 0,
-    val delivered_qty: Int = 0,
-    val read_qty: Int = 0,
-    val ack_qty: Int = 0,
-    val read_local_qty: Int = 0,
-    val delivered_pin: String = "",
-    val read_pin: String = "",
-    val ack_pin: String = "",
-    val read_local_pin: String = "",
-    val expired_qty: String = "",
-    val message_large_text: String,
-    val tag_forum: String = "",
-    val tag_activity: String = "",
-    val unk_numbers: Int = 0,
-    val conn_state: Int = 1,
-    val tag_client: String = "",
-    val tag_subactivity: String = "",
-    val messagenumber: Int = 0,
-    val mail_account: String = "",
-    val message_text_plain: String,
-    val local_timestamp: Long = 0,
-    val is_consult: Int = 0,
-    val is_call_center: Int = 0,
-    val call_center_id: String = "",
-    val is_work_mode: Int = 0
-) : MainEntity
+    var message_id: String = "",
+    var f_pin: String = "",
+    var l_pin: String = "",
+    var message_scope_id: String = "",
+    var server_date: Long = 0,
+    var status: String = "",
+    var message_text: String = "",
+    var audio_id: String = "",
+    var video_id: String = "",
+    var image_id: String = "",
+    var thumb_id: String = "",
+    var opposite_pin: String = "",
+    var lock: String = "",
+    var format: String = "",
+    var broadcast_flag: Int = 0,
+    var blog_id: String = "",
+    var f_user_id: String = "",
+    var l_user_id: String = "",
+    var read_receipts: Int = 0,
+    var chat_id: String = "",
+    var file_id: String = "",
+    var delivery_receipts: Int = 0,
+    var account_type: String = "",
+    var contact: String = "",
+    var credential: String = "",
+    var attachment_flag: Int = 0,
+    var stared: Int = 0,
+    var f_display_name: String = "",
+    var reff_id: String = "",
+    var sent_qty: Int = 0,
+    var delivered_qty: Int = 0,
+    var read_qty: Int = 0,
+    var ack_qty: Int = 0,
+    var read_local_qty: Int = 0,
+    var delivered_pin: String = "",
+    var read_pin: String = "",
+    var ack_pin: String = "",
+    var read_local_pin: String = "",
+    var expired_qty: String = "",
+    var message_large_text: String = "",
+    var tag_forum: String = "",
+    var tag_activity: String = "",
+    var unk_numbers: Int = 0,
+    var conn_state: Int = 1,
+    var tag_client: String = "",
+    var tag_subactivity: String = "",
+    var messagenumber: Int = 0,
+    var mail_account: String = "",
+    var message_text_plain: String = "",
+    var local_timestamp: Long = 0,
+    var consult: Int = 0,
+    var call_center: Int = 0,
+    var call_center_id: String = "",
+    var work_mode: Int = 0,
+    @Ignore var uri: Uri = Uri.EMPTY
+) : MainEntity {
+    constructor(
+        message_id: String = "",
+        f_pin: String = "",
+        l_pin: String = "",
+        message_scope_id: String = "",
+        server_date: Long = 0,
+        status: String = "",
+        message_text: String = "",
+        audio_id: String = "",
+        video_id: String = "",
+        image_id: String = "",
+        thumb_id: String = "",
+        opposite_pin: String = "",
+        lock: String = "",
+        format: String = "",
+        broadcast_flag: Int = 0,
+        blog_id: String = "",
+        f_user_id: String = "",
+        l_user_id: String = "",
+        read_receipts: Int = 0,
+        chat_id: String = "",
+        file_id: String = "",
+        delivery_receipts: Int = 0,
+        account_type: String = "",
+        contact: String = "",
+        credential: String = "",
+        attachment_flag: Int = 0,
+        stared: Int = 0,
+        f_display_name: String = "",
+        reff_id: String = "",
+        sent_qty: Int = 0,
+        delivered_qty: Int = 0,
+        read_qty: Int = 0,
+        ack_qty: Int = 0,
+        read_local_qty: Int = 0,
+        delivered_pin: String = "",
+        read_pin: String = "",
+        ack_pin: String = "",
+        read_local_pin: String = "",
+        expired_qty: String = "",
+        message_large_text: String = "",
+        tag_forum: String = "",
+        tag_activity: String = "",
+        unk_numbers: Int = 0,
+        conn_state: Int = 1,
+        tag_client: String = "",
+        tag_subactivity: String = "",
+        messagenumber: Int = 0,
+        mail_account: String = "",
+        message_text_plain: String = "",
+        local_timestamp: Long = 0,
+        consult: Int = 0,
+        call_center: Int = 0,
+        call_center_id: String = "",
+        work_mode: Int = 0
+    ) : this("",
+        "",
+        "",
+        "",
+        0,
+        "",
+        "",
+        "",
+        "",
+        "",
+        "",
+        "",
+        "",
+        "",
+        0,
+        "",
+        "",
+        "",
+        0,
+        "",
+        "",
+        0,
+        "",
+        "",
+        "",
+        0,
+        0,
+        "",
+        "",
+        0,
+        0,
+        0,
+        0,
+        0,
+        "",
+        "",
+        "",
+        "",
+        "",
+        "",
+        "",
+        "",
+        0,
+        0,
+        "",
+        "",
+        0,
+        "",
+        "",
+        0,
+        0,
+        0,
+        "",
+        0,
+        Uri.EMPTY)
+}

+ 16 - 7
cpaas-lite/src/main/java/io/nexilis/service/data/viewmodels/MessageViewModel.kt

@@ -2,12 +2,12 @@ package io.nexilis.service.data.viewmodels
 
 import android.content.Context
 import android.net.Uri
-import android.util.Log
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import dagger.hilt.android.lifecycle.HiltViewModel
 import io.nexilis.service.core.getFileName
+import io.nexilis.service.core.getMimeType
 import io.nexilis.service.core.toFile
 import io.nexilis.service.data.daos.MessageStatusDao
 import io.nexilis.service.data.entities.Message
@@ -39,16 +39,25 @@ class MessageViewModel @Inject constructor(
 
     fun send(
         context: Context,
-        entity: Message,
-        files: List<Uri>? = null
+        entity: Message
     ) =
         viewModelScope.launch(Dispatchers.IO) {
-            files?.forEach { uri ->
-                context.contentResolver.openInputStream(uri).use { input ->
-                    input?.toFile(context, uri.getFileName(context))
+            if (entity.uri != Uri.EMPTY) {
+                context.contentResolver.openInputStream(entity.uri).use { input ->
+                    input?.toFile(context, entity.uri.getFileName(context))
+                }
+                val mimeType = context.getMimeType(entity.uri)
+                if (mimeType.startsWith("image")) {
+                    entity.thumb_id = entity.uri.getFileName(context) ?: ""
+                    entity.image_id = entity.thumb_id
+                } else if (mimeType.startsWith("audio")) {
+                    entity.audio_id = entity.uri.getFileName(context) ?: ""
+                } else if (mimeType.startsWith("video")) {
+                    entity.video_id = entity.uri.getFileName(context) ?: ""
+                } else {
+                    entity.file_id = entity.uri.getFileName(context) ?: ""
                 }
             }
-            Log.d("SAPI", "send:files:$files")
             repository.send(context, entity) { id, pin, status ->
                 viewModelScope.launch(Dispatchers.IO) {
                     messageStatusDao.updateStatus(