TP-41986 | User confirmation before sending attachment (#8245)
Co-authored-by: Shivam Goyal <shivam.goyal@navi.com>
This commit is contained in:
@@ -48,7 +48,7 @@ awaitility = "4.1.0"
|
||||
branch = "5.1.1"
|
||||
cashfree = "2.0.6"
|
||||
chucker = "4.0.0"
|
||||
coilCompose = "2.4.0"
|
||||
coil = "2.4.0"
|
||||
compose-bom = "2023.09.01"
|
||||
compose-lib = '1.5.3'
|
||||
delight-advancedWebView = "v3.0.0"
|
||||
@@ -226,8 +226,8 @@ cashfree = { module = "com.cashfree.pg:api", version.ref = "cashfree" }
|
||||
chucker-library = { module = "com.github.chuckerteam.chucker:library", version.ref = "chucker" }
|
||||
chucker-libraryNoOp = { module = "com.github.chuckerteam.chucker:library-no-op", version.ref = "chucker" }
|
||||
|
||||
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" }
|
||||
|
||||
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
|
||||
coil-video = { module = "io.coil-kt:coil-video", version.ref = "coil" }
|
||||
dagger-hiltAndroid = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
|
||||
dagger-hiltAndroidCompiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }
|
||||
dagger-hiltAndroidTesting = { module = "com.google.dagger:hilt-android-testing", version.ref = "hilt" }
|
||||
|
||||
@@ -55,6 +55,8 @@ dependencies {
|
||||
|
||||
implementation libs.android.material
|
||||
|
||||
implementation libs.coil.video
|
||||
|
||||
implementation libs.dagger.hiltAndroid
|
||||
|
||||
kapt libs.dagger.hiltCompiler
|
||||
|
||||
@@ -48,6 +48,11 @@
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/BaseThemeStyle" />
|
||||
<activity
|
||||
android:name=".ui.activities.AttachmentConfirmationActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/BaseThemeStyle" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -7,10 +7,21 @@
|
||||
|
||||
package com.navi.chat.db.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.webkit.MimeTypeMap
|
||||
import com.google.gson.Gson
|
||||
import com.navi.chat.utils.TIME_FORMAT_TO_DISPLAY
|
||||
import com.navi.chat.utils.USER_SENDER_TYPE
|
||||
import com.navi.chat.utils.maxFileSizeInKb
|
||||
import com.navi.common.utils.log
|
||||
import com.navi.naviwidgets.models.NaviChatWidget
|
||||
import com.navi.naviwidgets.models.response.*
|
||||
import java.io.File
|
||||
|
||||
fun transformFirestoreToWidgetModel(data: Map<String, Any>): NaviChatWidget =
|
||||
when (data["widget_name"]) {
|
||||
@@ -105,4 +116,92 @@ fun getTimerExpiredResponse(timerExpired: Boolean, senderName: String) =
|
||||
senderName = senderName
|
||||
),
|
||||
shouldDisplayInChatHistory = false
|
||||
)
|
||||
)
|
||||
|
||||
fun getMimeType(context: Context, uri: Uri): String? {
|
||||
return context.contentResolver.getType(uri)
|
||||
}
|
||||
|
||||
fun timeInString(seconds: Int): String {
|
||||
return String.format(
|
||||
TIME_FORMAT_TO_DISPLAY, (seconds / 3600 * 60 + ((seconds % 3600) / 60)), (seconds % 60)
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("Range")
|
||||
fun getFileName(contentResolver: ContentResolver, uri: Uri): String {
|
||||
val uriString = uri.toString()
|
||||
var displayName = ""
|
||||
if (uriString.startsWith("content://")) {
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = contentResolver.query(uri, null, null, null, null)
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
} else if (uriString.startsWith("file://")) {
|
||||
displayName = File(uriString).name
|
||||
}
|
||||
return displayName
|
||||
}
|
||||
|
||||
fun isFileTooLarge(
|
||||
contentResolver: ContentResolver,
|
||||
uri: Uri,
|
||||
fileExtension: String?,
|
||||
maxFileSizeMap: Map<String, Long>?
|
||||
): Boolean {
|
||||
val fileSizeInKb = getFileSizeInBytes(contentResolver, uri)
|
||||
val maxSize = fileExtension?.let { maxFileSizeMap?.get(it.uppercase()) } ?: maxFileSizeInKb.toLong()
|
||||
return fileSizeInKb > maxSize * 1024
|
||||
}
|
||||
|
||||
private fun getFileSizeInBytes(contentResolver: ContentResolver, uri: Uri): Long {
|
||||
var fileSize: Long = 0
|
||||
|
||||
if (uri.scheme == "content") {
|
||||
val cursor = contentResolver.query(uri, null, null, null, null)
|
||||
cursor?.use {
|
||||
if (it.moveToFirst()) {
|
||||
val sizeIndex = it.getColumnIndex(OpenableColumns.SIZE)
|
||||
if (sizeIndex != -1) {
|
||||
fileSize = it.getLong(sizeIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (uri.scheme == "file") {
|
||||
try {
|
||||
val file = uri.path?.let { File(it) }
|
||||
if (file != null) {
|
||||
if (file.exists()) {
|
||||
fileSize = file.length()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
}
|
||||
}
|
||||
|
||||
return fileSize
|
||||
}
|
||||
|
||||
fun stringToMap(data: String): Map<String, Long> {
|
||||
val keyValuePairs = data.removeSurrounding("{", "}").split(", ").map { it.split("=") }
|
||||
|
||||
return keyValuePairs.associate { (key, value) -> key to value.toLong() }
|
||||
}
|
||||
|
||||
fun fileSizeWithinLimit(
|
||||
context: Context,
|
||||
selectedUri: Uri,
|
||||
contentResolver: ContentResolver,
|
||||
fileSizesMap: Map<String, Long>
|
||||
): Boolean {
|
||||
val mimeType = getMimeType(context, Uri.parse(selectedUri.toString()))
|
||||
val extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)?.lowercase()
|
||||
if (!isFileTooLarge(contentResolver, selectedUri, extension, fileSizesMap)) return true
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.chat.interfaces
|
||||
|
||||
interface AttachmentOptionClickListener {
|
||||
fun onGalleryAttachmentOptionClicked()
|
||||
fun onFileAttachmentOptionClicked()
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.navi.chat.ui.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import com.navi.chat.db.utils.getFileName
|
||||
import com.navi.chat.ui.compose.AttachmentPickerScreen
|
||||
import com.navi.chat.utils.FILENAME
|
||||
import com.navi.chat.utils.FILE_SIZES
|
||||
import com.navi.chat.utils.FILE_TYPE_PARAM
|
||||
import com.navi.chat.utils.FILE_URI
|
||||
import com.navi.chat.utils.NAVI_CHAT_ATTACHMENT_CONFIRMATION_ACTIVITY
|
||||
import com.navi.chat.utils.URI_LIST
|
||||
import com.navi.common.model.ModuleNameV2
|
||||
import com.navi.common.ui.activity.BaseActivity
|
||||
|
||||
class AttachmentConfirmationActivity : BaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val data = intent.getStringExtra(FILE_TYPE_PARAM)
|
||||
val fileSizes = intent.getStringExtra(FILE_SIZES)
|
||||
setContent {
|
||||
AttachmentPickerScreen(
|
||||
onBackPress = { onBackPressed() },
|
||||
onSendClick = { selectedImages ->
|
||||
val intent = createMyIntent(selectedImages)
|
||||
startActivity(intent)
|
||||
},
|
||||
onPlayClick = { fileUri ->
|
||||
val intent = Intent(this, NaviChatViewVideoActivity::class.java)
|
||||
val bundle = Bundle()
|
||||
bundle.putString(
|
||||
FILENAME, getFileName(this.contentResolver, fileUri)
|
||||
)
|
||||
intent.putExtra(FILE_URI, fileUri.toString())
|
||||
intent.putExtras(bundle)
|
||||
this.startActivity(intent)
|
||||
},
|
||||
onImageClick = { fileUri ->
|
||||
val intent = Intent(this, NaviChatViewImageActivity::class.java)
|
||||
val bundle = Bundle()
|
||||
bundle.putString(
|
||||
FILENAME, getFileName(this.contentResolver, fileUri)
|
||||
)
|
||||
intent.putExtra(FILE_URI, fileUri.toString())
|
||||
intent.putExtras(bundle)
|
||||
this.startActivity(intent)
|
||||
},
|
||||
data,
|
||||
fileSizes.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createMyIntent(selectedImages: List<Uri>): Intent {
|
||||
val intent = Intent(this, NaviChatActivity::class.java)
|
||||
intent.putParcelableArrayListExtra(URI_LIST, ArrayList(selectedImages))
|
||||
setResult(RESULT_OK, intent)
|
||||
finish()
|
||||
return intent
|
||||
}
|
||||
|
||||
override val screenName: String
|
||||
get() = NAVI_CHAT_ATTACHMENT_CONFIRMATION_ACTIVITY
|
||||
override val moduleName: ModuleNameV2
|
||||
get() = ModuleNameV2.CHAT
|
||||
}
|
||||
@@ -7,22 +7,49 @@
|
||||
|
||||
package com.navi.chat.ui.activities
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.navi.chat.R
|
||||
import com.navi.chat.base.ChatBaseActivity
|
||||
import com.navi.chat.databinding.ActivityNaviChatBinding
|
||||
import com.navi.chat.db.utils.getFileName
|
||||
import com.navi.chat.interfaces.AttachmentOptionClickListener
|
||||
import com.navi.chat.models.NaviChatSystemLocalData
|
||||
import com.navi.chat.ui.fragments.NaviChatFragment
|
||||
import com.navi.chat.utils.CONVERSATION_ID_PARAM
|
||||
import com.navi.chat.utils.DOCUMENT_ITEM
|
||||
import com.navi.chat.utils.FILE_SIZES
|
||||
import com.navi.chat.utils.FILE_TYPE_PARAM
|
||||
import com.navi.chat.utils.GALLERY_ITEM
|
||||
import com.navi.chat.utils.NAVI_CHAT_SYSTEM_LOCAL_DATA
|
||||
import com.navi.chat.utils.URI_LIST
|
||||
import com.navi.chat.viewmodels.AttachmentPickerViewModel
|
||||
|
||||
class NaviChatActivity : ChatBaseActivity() {
|
||||
class NaviChatActivity : ChatBaseActivity() , AttachmentOptionClickListener{
|
||||
|
||||
private lateinit var binding: ActivityNaviChatBinding
|
||||
private val currentScreenTag: String = NaviChatFragment.TAG
|
||||
private var chatFragment: NaviChatFragment? = null
|
||||
private val attachmentPickerViewModel by lazy {
|
||||
ViewModelProvider(this)[AttachmentPickerViewModel::class.java]
|
||||
}
|
||||
private var resultLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
val data = result.data
|
||||
val receivedDataList: List<Uri>? = data?.getParcelableArrayListExtra(URI_LIST)
|
||||
receivedDataList?.forEach { receivedData ->
|
||||
attachmentPickerViewModel.setImagePickerData(
|
||||
receivedData.toString(), getFileName(contentResolver, receivedData)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -88,4 +115,17 @@ class NaviChatActivity : ChatBaseActivity() {
|
||||
var isChatActivityVisible: Boolean = false
|
||||
private set
|
||||
}
|
||||
|
||||
override fun onGalleryAttachmentOptionClicked() {
|
||||
val intent = Intent(this, AttachmentConfirmationActivity::class.java)
|
||||
intent.putExtra(FILE_TYPE_PARAM, GALLERY_ITEM)
|
||||
intent.putExtra(FILE_SIZES, attachmentPickerViewModel.getFileSizes().toString())
|
||||
resultLauncher.launch(intent)
|
||||
}
|
||||
override fun onFileAttachmentOptionClicked() {
|
||||
val intent = Intent(this, AttachmentConfirmationActivity::class.java)
|
||||
intent.putExtra(FILE_TYPE_PARAM, DOCUMENT_ITEM)
|
||||
intent.putExtra(FILE_SIZES, attachmentPickerViewModel.getFileSizes().toString())
|
||||
resultLauncher.launch(intent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.navi.chat.ui.activities
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.net.toUri
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import com.navi.chat.R
|
||||
@@ -20,6 +21,7 @@ import com.navi.chat.di.dependencies.NaviChatModuleDependencies
|
||||
import com.navi.chat.di.modules.NaviChatModule
|
||||
import com.navi.chat.utils.ChatFileHelper
|
||||
import com.navi.chat.utils.FILENAME
|
||||
import com.navi.chat.utils.FILE_URI
|
||||
import com.navi.chat.utils.ToolbarInteraction
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import java.io.File
|
||||
@@ -71,8 +73,11 @@ class NaviChatViewImageActivity : ChatBaseActivity(), ToolbarInteraction {
|
||||
val sd: File = this.cacheDir
|
||||
val folder = File(sd, "/chat/")
|
||||
val outputFile = File(folder, fileName)
|
||||
val uri =
|
||||
val uri = if (outputFile.exists()) {
|
||||
FileProvider.getUriForFile(this, "${this.packageName}.fileprovider", outputFile)
|
||||
} else {
|
||||
intent.getStringExtra(FILE_URI)?.toUri()
|
||||
}
|
||||
Glide.with(this).load(uri).into(binding.ivImageAttachment)
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.file_cannot_be_opened), Toast.LENGTH_LONG)
|
||||
|
||||
@@ -19,6 +19,7 @@ import android.view.*
|
||||
import android.widget.SeekBar
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.navi.chat.R
|
||||
@@ -228,10 +229,15 @@ class NaviChatViewVideoActivity :
|
||||
val sd: File = this.cacheDir
|
||||
val folder = File(sd, "/chat/")
|
||||
val outputFile = File(folder, it)
|
||||
val uri =
|
||||
val uri = if (outputFile.exists()) {
|
||||
FileProvider.getUriForFile(this, "${this.packageName}.fileprovider", outputFile)
|
||||
} else {
|
||||
intent.getStringExtra(FILE_URI)?.toUri()
|
||||
}
|
||||
mediaPlayer?.apply {
|
||||
setDataSource(applicationContext, uri)
|
||||
if (uri != null) {
|
||||
setDataSource(applicationContext, uri)
|
||||
}
|
||||
}
|
||||
mediaPlayer?.setOnPreparedListener(this)
|
||||
mediaPlayer?.setOnCompletionListener(this)
|
||||
@@ -304,12 +310,12 @@ class NaviChatViewVideoActivity :
|
||||
|
||||
private fun pauseMediaPlayer() {
|
||||
mediaPlayer?.pause()
|
||||
binding.ivPlayPauseVideo.setImageResource(R.drawable.ic_play_video)
|
||||
binding.ivPlayPauseVideo.setImageResource(R.drawable.ic_play_video_purple)
|
||||
}
|
||||
|
||||
private fun startMediaPlayer() {
|
||||
mediaPlayer?.start()
|
||||
binding.ivPlayPauseVideo.setImageResource(R.drawable.ic_pause_icon)
|
||||
binding.ivPlayPauseVideo.setImageResource(R.drawable.ic_pause_icon_purple)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@@ -352,7 +358,7 @@ class NaviChatViewVideoActivity :
|
||||
// Go to start when video completes
|
||||
override fun onCompletion(mp: MediaPlayer?) {
|
||||
setVideoPlayerControlsVisibility(true)
|
||||
binding.ivPlayPauseVideo.setImageResource(R.drawable.ic_play_video)
|
||||
binding.ivPlayPauseVideo.setImageResource(R.drawable.ic_play_video_purple)
|
||||
mediaPlayerSeekTo(0)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.navi.chat.ui.components
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.annotation.CallSuper
|
||||
import com.navi.chat.utils.MIME_TYPE_DOCX
|
||||
import com.navi.chat.utils.MIME_TYPE_DOC
|
||||
import com.navi.chat.utils.MIME_TYPE_PDF
|
||||
|
||||
class FileDocument : ActivityResultContract<Array<String>, Uri?>() {
|
||||
@CallSuper
|
||||
override fun createIntent(context: Context, input: Array<String>): Intent {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
intent.type = MIME_TYPE_PDF
|
||||
intent.putExtra(
|
||||
Intent.EXTRA_MIME_TYPES, arrayOf(
|
||||
MIME_TYPE_PDF, MIME_TYPE_DOC, MIME_TYPE_DOCX
|
||||
)
|
||||
)
|
||||
return intent
|
||||
}
|
||||
|
||||
override fun getSynchronousResult(
|
||||
context: Context, input: Array<String>
|
||||
): SynchronousResult<Uri?>? = null
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
|
||||
return intent.takeIf { resultCode == Activity.RESULT_OK }?.data
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.navi.chat.ui.components
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.annotation.CallSuper
|
||||
import com.navi.chat.utils.IMAGE_TYPE
|
||||
import com.navi.chat.utils.VIDEO_TYPE
|
||||
|
||||
class GalleryDocument : ActivityResultContract<Array<String>, Uri?>() {
|
||||
@CallSuper
|
||||
override fun createIntent(context: Context, input: Array<String>): Intent {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
intent.type = IMAGE_TYPE
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf(IMAGE_TYPE, VIDEO_TYPE))
|
||||
return intent
|
||||
}
|
||||
|
||||
override fun getSynchronousResult(
|
||||
context: Context, input: Array<String>
|
||||
): SynchronousResult<Uri?>? = null
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
|
||||
return intent.takeIf { resultCode == Activity.RESULT_OK }?.data
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
package com.navi.chat.ui.compose
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.ImageLoader
|
||||
import coil.compose.AsyncImage
|
||||
import coil.compose.rememberAsyncImagePainter
|
||||
import coil.decode.VideoFrameDecoder
|
||||
import coil.request.ImageRequest
|
||||
import com.navi.chat.R
|
||||
import com.navi.chat.db.utils.fileSizeWithinLimit
|
||||
import com.navi.chat.db.utils.getFileName
|
||||
import com.navi.chat.db.utils.getMimeType
|
||||
import com.navi.chat.db.utils.stringToMap
|
||||
import com.navi.chat.db.utils.timeInString
|
||||
import com.navi.chat.ui.components.FileDocument
|
||||
import com.navi.chat.ui.components.GalleryDocument
|
||||
import com.navi.chat.ui.theme.NaviChatColor
|
||||
import com.navi.chat.utils.MIME_TYPE_DOCX
|
||||
import com.navi.chat.utils.MIME_TYPE_DOC
|
||||
import com.navi.chat.utils.GALLERY_ITEM
|
||||
import com.navi.chat.utils.IMAGE_TYPE
|
||||
import com.navi.chat.utils.MIME_TYPE_IMAGE
|
||||
import com.navi.chat.utils.MIME_TYPE_PDF
|
||||
import com.navi.chat.utils.MIME_TYPE_VIDEO
|
||||
import com.navi.chat.utils.VIDEO_TYPE
|
||||
import com.navi.chat.utils.maxFileLimit
|
||||
import com.navi.design.theme.composeFontFamily
|
||||
import com.navi.design.theme.ttComposeFontFamily
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun AttachmentPickerScreen(
|
||||
onBackPress: () -> Unit = {},
|
||||
onSendClick: (selectedImages: MutableList<Uri>) -> Unit,
|
||||
onPlayClick: (fileUri: Uri) -> Unit,
|
||||
onImageClick: (fileUri: Uri) -> Unit,
|
||||
data: String?,
|
||||
fileSizes: String,
|
||||
) {
|
||||
val selectedImages = remember { mutableStateListOf<Uri>() }
|
||||
val primaryButtonEnabled = remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(modifier = Modifier.fillMaxSize(), topBar = {
|
||||
NaviChatHeader(
|
||||
title = stringResource(id = R.string.navi_chat_toolbar_title),
|
||||
onNavigationIconClick = { onBackPress() },
|
||||
modifier = Modifier
|
||||
)
|
||||
}, bottomBar = {
|
||||
NaviChatFooter(
|
||||
secondaryButtonText = stringResource(id = R.string.cancel),
|
||||
primaryButtonText = stringResource(id = R.string.send),
|
||||
onSecondaryButtonClicked = { onBackPress() },
|
||||
onPrimaryButtonClicked = { onSendClick(selectedImages) },
|
||||
primaryButtonEnabled = primaryButtonEnabled.value
|
||||
)
|
||||
}, content = { paddingValues ->
|
||||
NaviChatAttachmentScreenBody(
|
||||
selectedImages,
|
||||
data,
|
||||
paddingValues,
|
||||
fileSizes,
|
||||
onPlayClick = { uri -> onPlayClick(uri) },
|
||||
onImageClick = { uri -> onImageClick(uri) },
|
||||
primaryButtonEnabled = primaryButtonEnabled
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NaviChatAttachmentScreenBody(
|
||||
selectedImages: MutableList<Uri>,
|
||||
data: String?,
|
||||
padding: PaddingValues,
|
||||
fileSizes: String,
|
||||
onPlayClick: (fileUri: Uri) -> Unit,
|
||||
onImageClick: (fileUri: Uri) -> Unit,
|
||||
primaryButtonEnabled: MutableState<Boolean>
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val contentResolver = context.contentResolver
|
||||
val fileSizesMap = stringToMap(fileSizes)
|
||||
|
||||
primaryButtonEnabled.value = selectedImages.size != 0
|
||||
val photoPickerLauncher = rememberLauncherForActivityResult(
|
||||
contract = GalleryDocument()
|
||||
) { selectedUri: Uri? ->
|
||||
if (selectedUri != null) {
|
||||
if (fileSizeWithinLimit(context, selectedUri, contentResolver, fileSizesMap)) {
|
||||
selectedImages.add(selectedUri)
|
||||
} else Toast.makeText(
|
||||
context, R.string.file_size_exceeded, Toast.LENGTH_SHORT
|
||||
).show()
|
||||
val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
contentResolver?.takePersistableUriPermission(selectedUri, takeFlags)
|
||||
}
|
||||
}
|
||||
|
||||
val documentPickerLauncher = rememberLauncherForActivityResult(
|
||||
contract = FileDocument()
|
||||
) { selectedUri: Uri? ->
|
||||
if (selectedUri != null) {
|
||||
if (fileSizeWithinLimit(context, selectedUri, contentResolver, fileSizesMap)) {
|
||||
selectedImages.add(selectedUri)
|
||||
} else Toast.makeText(
|
||||
context, R.string.file_size_exceeded, Toast.LENGTH_SHORT
|
||||
).show()
|
||||
val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
contentResolver?.takePersistableUriPermission(selectedUri, takeFlags)
|
||||
}
|
||||
}
|
||||
|
||||
val lazyListState = rememberLazyGridState()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
fun scrollToLastItem() {
|
||||
val lastIndex = selectedImages.size - 1
|
||||
if (lastIndex >= 0) {
|
||||
scope.launch {
|
||||
lazyListState.animateScrollToItem(lastIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
LaunchedEffect(selectedImages.size) {
|
||||
scrollToLastItem()
|
||||
}
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(2),
|
||||
state = lazyListState,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(
|
||||
bottom = padding.calculateBottomPadding(), top = 16.dp, start = 8.dp, end = 8.dp
|
||||
)
|
||||
) {
|
||||
items(selectedImages.size + 1) { index ->
|
||||
if (index < selectedImages.size) {
|
||||
GalleryItem(selectedImages[index],
|
||||
onRemoveClick = { selectedImages.removeAt(index) },
|
||||
onPlayClick = { onPlayClick(selectedImages[index]) },
|
||||
onImageClick = { onImageClick(selectedImages[index]) })
|
||||
} else {
|
||||
if (data == GALLERY_ITEM && selectedImages.size < maxFileLimit) {
|
||||
AddMedia(photoPickerLauncher)
|
||||
} else if (selectedImages.size < maxFileLimit) {
|
||||
AddDocument(documentPickerLauncher)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SuspiciousIndentation")
|
||||
@Composable
|
||||
fun GalleryItem(
|
||||
fileUri: Uri,
|
||||
onRemoveClick: () -> Unit,
|
||||
onPlayClick: (fileUri:Uri) -> Unit = {},
|
||||
onImageClick: (fileUri:Uri) -> Unit = {}
|
||||
) {
|
||||
|
||||
val context = LocalContext.current
|
||||
val mimeType = getMimeType(context, Uri.parse(fileUri.toString()))
|
||||
val allowedMimeTypes = listOf(
|
||||
MIME_TYPE_PDF,
|
||||
MIME_TYPE_DOC,
|
||||
MIME_TYPE_DOCX,
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(14.dp)
|
||||
.background(Color.White)
|
||||
.height(138.dp)
|
||||
.border(1.dp, NaviChatColor.ctaPrimary, RoundedCornerShape(4.dp)),
|
||||
) {
|
||||
if (mimeType != null) {
|
||||
if (mimeType.startsWith(MIME_TYPE_IMAGE)) {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current).data(fileUri).allowHardware(false).build(),
|
||||
contentDescription = "Image preview",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clickable(interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = { onImageClick(fileUri) }),
|
||||
)
|
||||
}
|
||||
if (allowedMimeTypes.any { mimeType.startsWith(it) }) {
|
||||
Box(modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
content = {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_doc_preview),
|
||||
contentDescription = "Document preview",
|
||||
)
|
||||
Spacer(modifier = Modifier.size(10.dp))
|
||||
val fileName = getFileName(context.contentResolver, fileUri)
|
||||
Text(
|
||||
text = fileName,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 18.sp,
|
||||
fontFamily = composeFontFamily,
|
||||
color = Color.Black,
|
||||
modifier = Modifier.padding(horizontal = 10.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 2,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (mimeType.startsWith(MIME_TYPE_VIDEO)) {
|
||||
val imageLoader = ImageLoader.Builder(context).components {
|
||||
add(VideoFrameDecoder.Factory())
|
||||
}.crossfade(true).build()
|
||||
|
||||
val painter = rememberAsyncImagePainter(
|
||||
model = fileUri,
|
||||
imageLoader = imageLoader
|
||||
)
|
||||
Box(
|
||||
modifier= Modifier.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = { onPlayClick(fileUri) })
|
||||
) {
|
||||
Image(
|
||||
painter = painter,
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_play_video_button),
|
||||
contentDescription = "Play video",
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(context, fileUri)
|
||||
val videoDurationString =
|
||||
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
|
||||
val videoDuration = videoDurationString?.toLong()
|
||||
retriever.release()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(top = 115.dp, end = 2.dp),
|
||||
contentAlignment = Alignment.BottomEnd
|
||||
) {
|
||||
val videoDurationInSeconds =
|
||||
timeInString((videoDuration?.div(1000))?.toInt() ?: 0)
|
||||
Text(
|
||||
text = videoDurationInSeconds,
|
||||
color = Color.White,
|
||||
fontSize = 12.sp,
|
||||
modifier = Modifier.padding(4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.offset(8.dp, (-12).dp)
|
||||
.fillMaxSize(),
|
||||
contentAlignment = Alignment.TopEnd
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onRemoveClick
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_remove_image),
|
||||
contentDescription = "Remove File",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddMedia(photoPickerLauncher: ManagedActivityResultLauncher<Array<String>, Uri?>)
|
||||
{
|
||||
Box(modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() }, indication = null
|
||||
) {
|
||||
photoPickerLauncher.launch(
|
||||
arrayOf(
|
||||
IMAGE_TYPE,
|
||||
VIDEO_TYPE,
|
||||
)
|
||||
)
|
||||
}
|
||||
.padding(14.dp)
|
||||
.border(
|
||||
width = 1.dp, color = NaviChatColor.ctaPrimary, shape = RoundedCornerShape(size = 4.dp)
|
||||
)
|
||||
.height(138.dp), contentAlignment = Alignment.Center, content = {
|
||||
Column(
|
||||
modifier = Modifier.padding(start = 15.dp, end = 15.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_add_image),
|
||||
contentDescription = stringResource(id = R.string.add_media)
|
||||
)
|
||||
Spacer(modifier = Modifier.size(8.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.add_media),
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = FontWeight(600),
|
||||
color = NaviChatColor.textSecondary,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddDocument(documentPickerLauncher: ManagedActivityResultLauncher<Array<String>, Uri?>)
|
||||
{
|
||||
Box(modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() }, indication = null
|
||||
) {
|
||||
documentPickerLauncher.launch(
|
||||
arrayOf(
|
||||
MIME_TYPE_PDF,
|
||||
MIME_TYPE_DOC,
|
||||
MIME_TYPE_DOCX,
|
||||
)
|
||||
)
|
||||
}
|
||||
.padding(14.dp)
|
||||
.border(
|
||||
width = 1.dp, color = NaviChatColor.ctaPrimary, shape = RoundedCornerShape(size = 4.dp)
|
||||
)
|
||||
.height(138.dp), contentAlignment = Alignment.Center, content = {
|
||||
Column(
|
||||
modifier = Modifier.padding(start = 15.dp, end = 15.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_add_image),
|
||||
contentDescription = stringResource(id = R.string.add_attachment),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(8.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.add_attachment),
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = FontWeight(600),
|
||||
color = NaviChatColor.textSecondary,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.navi.chat.ui.compose
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.navi.chat.R
|
||||
import com.navi.chat.ui.theme.NaviChatColor
|
||||
import com.navi.common.utils.ClickDebounce
|
||||
import com.navi.common.utils.get
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.theme.getFontWeight
|
||||
import com.navi.design.theme.ttComposeFontFamily
|
||||
|
||||
|
||||
@Composable
|
||||
fun NaviChatHeader(
|
||||
title: String,
|
||||
navigationIcon: Int = R.drawable.ic_chat_back_arrow,
|
||||
onNavigationIconClick: (() -> Unit),
|
||||
modifier: Modifier,
|
||||
backgroundColor: Color = Color.White
|
||||
) {
|
||||
TopAppBar(title = {
|
||||
Text(
|
||||
text = title,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.TT_REGULAR),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(end = 60.dp)
|
||||
)
|
||||
}, navigationIcon = {
|
||||
IconButton(onClick = { onNavigationIconClick.invoke() }) {
|
||||
Image(painter = painterResource(navigationIcon), contentDescription = null)
|
||||
}
|
||||
}, modifier = modifier.height(48.dp),
|
||||
elevation = 1.dp,
|
||||
backgroundColor = backgroundColor
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NaviChatFooter(
|
||||
secondaryButtonText: String,
|
||||
primaryButtonText: String,
|
||||
onSecondaryButtonClicked: () -> Unit,
|
||||
onPrimaryButtonClicked: () -> Unit,
|
||||
primaryButtonEnabled: Boolean = true
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 32.dp)
|
||||
.background(Color.White),
|
||||
) {
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Row {
|
||||
SecondaryRoundedButton(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = secondaryButtonText
|
||||
) {
|
||||
onSecondaryButtonClicked.invoke()
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
ThemeRoundedButton(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = primaryButtonText,
|
||||
enabled = primaryButtonEnabled
|
||||
) {
|
||||
onPrimaryButtonClicked.invoke()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ThemeRoundedButton(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String,
|
||||
cornerRadius: Dp = 4.dp,
|
||||
paddingValues: PaddingValues = PaddingValues(vertical = 14.dp, horizontal = 10.dp),
|
||||
fontSize: TextUnit = 14.sp,
|
||||
enabled: Boolean = true,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
|
||||
val clickDebounce = remember { ClickDebounce.get() }
|
||||
|
||||
Button(
|
||||
elevation = ButtonDefaults.elevation(defaultElevation = 0.dp),
|
||||
onClick = { clickDebounce.processClick { onClick() } },
|
||||
modifier = modifier,
|
||||
shape = RoundedCornerShape(cornerRadius),
|
||||
contentPadding = paddingValues,
|
||||
enabled = enabled,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = NaviChatColor.ctaPrimary,
|
||||
disabledBackgroundColor = NaviChatColor.ctaDisabled
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = fontSize,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
color = NaviChatColor.textWhite,
|
||||
letterSpacing = 0.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SecondaryRoundedButton(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String,
|
||||
cornerRadius: Dp = 4.dp,
|
||||
paddingValues: PaddingValues = PaddingValues(vertical = 14.dp, horizontal = 10.dp),
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val clickDebounce = remember { ClickDebounce.get() }
|
||||
|
||||
Button(
|
||||
elevation = ButtonDefaults.elevation(defaultElevation = 0.dp),
|
||||
onClick = { clickDebounce.processClick { onClick() } },
|
||||
modifier = modifier,
|
||||
shape = RoundedCornerShape(cornerRadius),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = NaviChatColor.ctaSecondary
|
||||
),
|
||||
contentPadding = paddingValues
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
color = NaviChatColor.ctaPrimary,
|
||||
letterSpacing = 0.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -9,19 +9,17 @@ package com.navi.chat.ui.fragments
|
||||
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.OpenableColumns
|
||||
import android.view.View
|
||||
import android.view.ViewStub
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -35,6 +33,7 @@ import com.navi.chat.databinding.ChatAttachmentBottomSheetBinding
|
||||
import com.navi.chat.di.components.DaggerNaviChatComponent
|
||||
import com.navi.chat.di.dependencies.NaviChatModuleDependencies
|
||||
import com.navi.chat.di.modules.NaviChatModule
|
||||
import com.navi.chat.interfaces.AttachmentOptionClickListener
|
||||
import com.navi.chat.interfaces.ChatAttachmentOptionsInterface
|
||||
import com.navi.chat.models.ChatAttachmentData
|
||||
import com.navi.chat.utils.FILE_MANAGER
|
||||
@@ -43,7 +42,6 @@ import com.navi.chat.viewmodels.AttachmentPickerViewModel
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
class ChatAttachmentBottomSheet : BaseBottomSheet(), ChatAttachmentOptionsInterface {
|
||||
|
||||
@@ -53,11 +51,15 @@ class ChatAttachmentBottomSheet : BaseBottomSheet(), ChatAttachmentOptionsInterf
|
||||
private val attachmentPickerViewModel by lazy {
|
||||
ViewModelProvider(requireActivity())[AttachmentPickerViewModel::class.java]
|
||||
}
|
||||
|
||||
private var attachmentOptionClickListener: AttachmentOptionClickListener? = null
|
||||
|
||||
override val screenName: String
|
||||
get() = TAG
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
attachmentOptionClickListener = context as? AttachmentOptionClickListener
|
||||
}
|
||||
override fun setContainerView(viewStub: ViewStub) {
|
||||
viewStub.layoutResource = R.layout.chat_attachment_bottom_sheet
|
||||
binding = DataBindingUtil.getBinding(viewStub.inflate())!!
|
||||
@@ -97,7 +99,7 @@ class ChatAttachmentBottomSheet : BaseBottomSheet(), ChatAttachmentOptionsInterf
|
||||
private fun createAttachmentOptionList(): ArrayList<ChatAttachmentData> {
|
||||
val attachmentDataArrayList = ArrayList<ChatAttachmentData>()
|
||||
|
||||
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_gallery_icon)?.let {
|
||||
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_gallery_icon_new)?.let {
|
||||
attachmentDataArrayList.add(
|
||||
ChatAttachmentData(
|
||||
it,
|
||||
@@ -106,7 +108,7 @@ class ChatAttachmentBottomSheet : BaseBottomSheet(), ChatAttachmentOptionsInterf
|
||||
)
|
||||
)
|
||||
}
|
||||
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_file_manager_icon)?.let {
|
||||
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_file_manager_icon_new)?.let {
|
||||
attachmentDataArrayList.add(
|
||||
ChatAttachmentData(
|
||||
it,
|
||||
@@ -122,44 +124,15 @@ class ChatAttachmentBottomSheet : BaseBottomSheet(), ChatAttachmentOptionsInterf
|
||||
if (isLegacyExternalStoragePermissionRequired()) {
|
||||
requestLegacyWriteExternalStoragePermission()
|
||||
} else {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
intent.type = "image/*"
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/*", "video/*"))
|
||||
resultLauncher.launch(Intent.createChooser(intent, "Select image or video"))
|
||||
attachmentOptionClickListener?.onGalleryAttachmentOptionClicked()
|
||||
}
|
||||
}
|
||||
|
||||
private var resultLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
attachmentPickerViewModel.setImagePickerData(
|
||||
result.data, result.data?.data?.let { getFileName(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFile() {
|
||||
if (isLegacyExternalStoragePermissionRequired()) {
|
||||
requestLegacyWriteExternalStoragePermission()
|
||||
} else {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "application/*"
|
||||
putExtra(
|
||||
Intent.EXTRA_MIME_TYPES,
|
||||
arrayOf(
|
||||
DOC,
|
||||
DOCX,
|
||||
PDF
|
||||
)
|
||||
)
|
||||
putExtra(
|
||||
Intent.ACTION_OPEN_DOCUMENT,
|
||||
requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
|
||||
)
|
||||
}
|
||||
resultLauncher1.launch(intent)
|
||||
attachmentOptionClickListener?.onFileAttachmentOptionClicked()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,36 +156,6 @@ class ChatAttachmentBottomSheet : BaseBottomSheet(), ChatAttachmentOptionsInterf
|
||||
}
|
||||
}
|
||||
|
||||
private var resultLauncher1 =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
attachmentPickerViewModel.setPdfPickerData(
|
||||
result.data, result.data?.data?.let { getFileName(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("Range")
|
||||
private fun getFileName(uri: Uri): String {
|
||||
val uriString = uri.toString()
|
||||
var displayName = ""
|
||||
if (uriString.startsWith("content://")) {
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity?.contentResolver?.query(uri, null, null, null, null)
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
displayName =
|
||||
cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
} else if (uriString.startsWith("file://")) {
|
||||
displayName = File(uriString).name
|
||||
}
|
||||
return displayName
|
||||
}
|
||||
|
||||
override fun onClickChatAttachmentOption(attachmentsType: String) {
|
||||
when (attachmentsType) {
|
||||
GALLERY -> {
|
||||
@@ -233,4 +176,4 @@ class ChatAttachmentBottomSheet : BaseBottomSheet(), ChatAttachmentOptionsInterf
|
||||
const val DOC = "application/msword"
|
||||
const val DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,6 +380,7 @@ class NaviChatFragment : ChatBaseFragment(), WidgetCallback, MessageOperation, T
|
||||
fileSizes.clear()
|
||||
it?.let {
|
||||
fileSizes.putAll(it.fileSizeInKB.orEmpty())
|
||||
it.fileSizeInKB?.let { it1 -> attachmentPickerViewModel.setFileSizes(it1) }
|
||||
it.botTypingCuesDelayInMs?.let { botDelayInMs ->
|
||||
delayForTypingCuesForBot = botDelayInMs
|
||||
Timber.d("Updated delayForTypingCuesForBot to $botDelayInMs")
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.navi.chat.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
object NaviChatColor {
|
||||
val textSecondary = Color(0xFF444444)
|
||||
val textWhite = Color(0xFFFFFFFF)
|
||||
val ctaPrimary = Color(0xFF1F002A)
|
||||
val ctaSecondary = Color(0xFFF5F5F5)
|
||||
val ctaDisabled = Color(0xFFB5ACB9)
|
||||
}
|
||||
@@ -50,6 +50,20 @@ const val BOT = "BOT"
|
||||
const val DIGITAL_GOLD = "DIGITAL_GOLD"
|
||||
const val FILENAME = "filename"
|
||||
const val NODE_UUID_PARAM = "nodeUuid"
|
||||
const val GALLERY_ITEM = "image"
|
||||
const val DOCUMENT_ITEM = "document"
|
||||
const val URI_LIST = "uriList"
|
||||
const val FILE_SIZES = "fileSizes"
|
||||
const val FILE_URI = "fileUri"
|
||||
const val IMAGE_TYPE = "image/*"
|
||||
const val VIDEO_TYPE = "video/*"
|
||||
const val MIME_TYPE_IMAGE = "image/"
|
||||
const val MIME_TYPE_VIDEO = "video/"
|
||||
const val MIME_TYPE_PDF = "application/pdf"
|
||||
const val MIME_TYPE_DOC = "application/msword"
|
||||
const val MIME_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
||||
const val maxFileLimit = 6
|
||||
const val maxFileSizeInKb = 15000
|
||||
|
||||
/* Video Player Instance Save Constant */
|
||||
const val CURRENT_VIDEO_POSITION_IN_MS = "currentVideoPositionInMs"
|
||||
@@ -59,3 +73,4 @@ const val TIME_FORMAT_TO_DISPLAY = "%02d:%02d"
|
||||
|
||||
/* Screen names */
|
||||
const val NAVI_CHAT_VIEW_VIDEO_ACTIVITY = "naviChatViewVideoActivity"
|
||||
const val NAVI_CHAT_ATTACHMENT_CONFIRMATION_ACTIVITY = "naviChatAttachmentConfirmationActivity"
|
||||
|
||||
@@ -12,6 +12,7 @@ import android.app.Application
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.navi.chat.R
|
||||
@@ -39,6 +40,7 @@ class AttachmentPickerViewModel(application: Application) : AndroidViewModel(app
|
||||
private val defaultMaxFileSizeInMb = 15
|
||||
var maxFileSizeInMb = defaultMaxFileSizeInMb
|
||||
|
||||
private var fileSizes = HashMap<String, Int>()
|
||||
val dispatcher = CoroutineDispatcherProvider()
|
||||
val fileHelper = ChatFileHelper(dispatcher)
|
||||
private var isToastVisible = false
|
||||
@@ -116,14 +118,21 @@ class AttachmentPickerViewModel(application: Application) : AndroidViewModel(app
|
||||
}
|
||||
}
|
||||
|
||||
fun setImagePickerData(data: Intent?, fileName: String?) {
|
||||
fun setImagePickerData(data: String?, fileName: String?) {
|
||||
viewModelScope.launch(dispatcher.io) {
|
||||
val imageData = data?.data
|
||||
imageData?.let { emitFileData(imageData, fileName, FileHelper.JPG_EXTENSION) }
|
||||
data?.let { emitFileData(data.toUri(), fileName, FileHelper.JPG_EXTENSION) }
|
||||
dismissDialog()
|
||||
}
|
||||
}
|
||||
|
||||
fun setFileSizes(sizes: HashMap<String, Int>) {
|
||||
fileSizes = sizes
|
||||
}
|
||||
|
||||
fun getFileSizes(): HashMap<String, Int> {
|
||||
return fileSizes
|
||||
}
|
||||
|
||||
private fun dismissDialog() {
|
||||
viewModelScope.launch(dispatcher.main) { _dismissBottomSheetDialog.emit(true) }
|
||||
}
|
||||
|
||||
9
navi-chat/src/main/res/drawable/ic_add_image.xml
Normal file
9
navi-chat/src/main/res/drawable/ic_add_image.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="25dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="25"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.5,2C6.977,2 2.5,6.477 2.5,12C2.5,17.523 6.977,22 12.5,22C18.023,22 22.5,17.523 22.5,12C22.5,6.477 18.023,2 12.5,2ZM16.5,13H13.5V16H11.5V13H8.5V11H11.5V8H13.5V11H16.5V13Z"
|
||||
android:fillColor="#1F002A"/>
|
||||
</vector>
|
||||
22
navi-chat/src/main/res/drawable/ic_doc_preview.xml
Normal file
22
navi-chat/src/main/res/drawable/ic_doc_preview.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="54dp"
|
||||
android:height="54dp"
|
||||
android:viewportWidth="54"
|
||||
android:viewportHeight="54">
|
||||
<path
|
||||
android:pathData="M9.065,4.648C10.308,3.406 11.993,2.708 13.75,2.708H32.521C33.106,2.708 33.668,2.941 34.082,3.355L46.228,15.501C46.642,15.915 46.875,16.476 46.875,17.062V44.666C46.875,46.423 46.177,48.109 44.935,49.351C43.692,50.593 42.007,51.291 40.25,51.291H9.333C8.114,51.291 7.125,50.303 7.125,49.083C7.125,47.863 8.114,46.875 9.333,46.875H40.25C40.836,46.875 41.397,46.642 41.812,46.228C42.226,45.814 42.458,45.252 42.458,44.666V17.977L31.606,7.125H13.75C13.164,7.125 12.603,7.357 12.189,7.771C11.774,8.186 11.542,8.747 11.542,9.333V18.166C11.542,19.386 10.553,20.375 9.333,20.375C8.114,20.375 7.125,19.386 7.125,18.166V9.333C7.125,7.576 7.823,5.891 9.065,4.648Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M31.417,2.708C32.637,2.708 33.625,3.697 33.625,4.916V15.958H44.667C45.887,15.958 46.875,16.947 46.875,18.166C46.875,19.386 45.887,20.375 44.667,20.375H31.417C30.197,20.375 29.208,19.386 29.208,18.166V4.916C29.208,3.697 30.197,2.708 31.417,2.708Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M2.708,33.625C2.708,32.406 3.697,31.417 4.917,31.417H27C28.22,31.417 29.208,32.406 29.208,33.625C29.208,34.845 28.22,35.834 27,35.834H4.917C3.697,35.834 2.708,34.845 2.708,33.625Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M18.813,25.439C19.676,24.576 21.074,24.576 21.936,25.439L28.561,32.064C29.424,32.926 29.424,34.324 28.561,35.187L21.936,41.812C21.074,42.674 19.676,42.674 18.813,41.812C17.951,40.949 17.951,39.551 18.813,38.689L23.877,33.625L18.813,28.562C17.951,27.699 17.951,26.301 18.813,25.439Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M21.999,9.315V7.046C21.997,5.854 21.522,4.909 20.586,4.237C20.028,3.837 19.386,3.643 18.622,3.643H18.61C17.436,3.646 16.261,3.647 15.086,3.647C13.465,3.647 11.844,3.645 10.223,3.642C10.129,3.642 10.062,3.616 10.048,3.602C9.639,3.197 9.119,3 8.452,3C8.222,3 7.993,3 7.762,3H6.619C6.153,3 5.687,3 5.221,3.002C4.989,3.003 4.803,3.02 4.636,3.056C3.641,3.27 2.999,4.103 3,5.18C3.002,7.286 3.002,9.393 3.002,11.5C3.002,13.535 3.002,15.571 3.004,17.606C3.004,18.674 3.41,19.56 4.208,20.237C4.809,20.748 5.544,20.997 6.455,20.997H12.497C13.019,20.997 13.54,20.997 14.062,20.999C14.583,20.999 15.105,21 15.627,21C16.787,21 17.678,20.996 18.519,20.99C19.018,20.986 19.426,20.925 19.769,20.805C21.159,20.316 21.992,19.114 21.995,17.59C22.001,14.832 22,12.027 21.999,9.316V9.315ZM8.035,19.377C7.796,19.377 7.557,19.376 7.318,19.376C7.02,19.376 6.723,19.377 6.425,19.38H6.401C5.883,19.38 5.417,19.195 5.091,18.86C4.76,18.522 4.588,18.06 4.592,17.525C4.604,16.11 4.601,14.671 4.599,13.28C4.598,12.683 4.597,12.086 4.597,11.489C4.597,11.489 4.597,7.028 4.597,5.275C4.597,4.753 4.731,4.618 5.246,4.618H5.282C5.58,4.618 5.88,4.619 6.178,4.62C6.477,4.621 6.777,4.622 7.076,4.622C7.598,4.622 8.023,4.618 8.415,4.611H8.442C8.807,4.611 9.01,4.744 9.164,5.086C9.384,5.572 9.627,6.055 9.863,6.523C9.963,6.722 10.063,6.919 10.161,7.118C10.573,7.951 11.238,8.373 12.139,8.373H12.155C12.952,8.369 13.816,8.367 14.875,8.367C15.49,8.367 16.107,8.367 16.722,8.368C17.332,8.368 17.941,8.369 18.551,8.369C19.033,8.369 19.403,8.478 19.715,8.712C20.177,9.059 20.401,9.539 20.402,10.18C20.402,11.087 20.402,11.994 20.402,12.901C20.401,14.428 20.4,16.008 20.406,17.561C20.407,18.075 20.237,18.521 19.915,18.85C19.579,19.193 19.092,19.382 18.547,19.382H18.537C17.306,19.377 15.966,19.375 14.32,19.375C13.392,19.375 12.464,19.375 11.536,19.377C10.608,19.377 9.68,19.379 8.753,19.379C8.514,19.379 8.276,19.379 8.037,19.378L8.035,19.377ZM18.554,6.785C17.953,6.786 17.352,6.786 16.752,6.786H15.015C14.17,6.786 13.174,6.786 12.177,6.792C11.83,6.792 11.644,6.676 11.516,6.376C11.38,6.061 11.233,5.758 11.078,5.437C11.051,5.379 11.023,5.322 10.994,5.263C10.994,5.263 14.463,5.262 15.425,5.262C16.492,5.262 17.56,5.262 18.627,5.264C19.52,5.265 20.113,5.716 20.34,6.569C20.394,6.771 20.401,6.998 20.408,7.239V7.28C20.321,7.225 20.238,7.177 20.151,7.133C19.681,6.899 19.162,6.785 18.565,6.785H18.553L18.554,6.785Z"
|
||||
android:fillColor="#1F002A"/>
|
||||
</vector>
|
||||
12
navi-chat/src/main/res/drawable/ic_gallery_icon_new.xml
Normal file
12
navi-chat/src/main/res/drawable/ic_gallery_icon_new.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M11.746,19.998C9.058,19.998 6.369,19.994 3.682,20.001C2.814,20.003 2.092,19.712 1.542,19.047C1.156,18.579 1.007,18.023 1.006,17.435C1,13.479 0.996,9.522 1.006,5.566C1.011,4.055 2.087,3.006 3.624,3.004C9.059,2.998 14.493,2.999 19.929,3.004C21.188,3.005 22.107,3.693 22.438,4.868C22.508,5.115 22.531,5.38 22.531,5.637C22.537,9.545 22.537,13.453 22.535,17.361C22.535,18.957 21.471,19.995 19.841,19.996C17.143,19.998 14.446,19.996 11.748,19.996L11.746,19.998ZM13.621,15.005C15.995,13.522 18.351,12.051 20.7,10.571C20.78,10.52 20.833,10.369 20.834,10.264C20.848,8.743 20.853,7.224 20.859,5.703C20.863,4.94 20.552,4.635 19.773,4.635C14.438,4.635 9.103,4.635 3.768,4.635C2.992,4.635 2.677,4.942 2.676,5.699C2.676,8.144 2.676,10.588 2.676,13.032C2.676,13.132 2.676,13.233 2.676,13.386C2.821,13.296 2.91,13.244 2.996,13.186C3.998,12.51 5.014,11.854 5.995,11.152C7.152,10.324 8.498,10.429 9.523,11.373C10.859,12.604 12.241,13.787 13.621,15.005ZM14.87,18.365C14.815,18.296 14.8,18.27 14.78,18.252C12.612,16.33 10.446,14.407 8.275,12.49C7.895,12.154 7.504,12.14 7.07,12.432C5.663,13.377 4.258,14.324 2.861,15.282C2.764,15.348 2.689,15.509 2.685,15.629C2.666,16.187 2.676,16.745 2.677,17.303C2.679,18.069 2.983,18.365 3.767,18.365C7.355,18.365 10.944,18.365 14.531,18.365H14.871H14.87ZM20.858,12.44C18.832,13.701 16.874,14.92 14.903,16.148C15.712,16.863 16.487,17.554 17.274,18.233C17.365,18.312 17.516,18.357 17.64,18.358C18.374,18.37 19.109,18.365 19.844,18.364C20.53,18.363 20.837,18.067 20.839,17.402C20.846,15.864 20.851,14.326 20.858,12.788C20.858,12.694 20.858,12.601 20.858,12.44Z"
|
||||
android:fillColor="#1F002A"/>
|
||||
<path
|
||||
android:pathData="M16.25,8.81C16.272,10.232 15.083,11.424 13.626,11.441C12.201,11.456 11.002,10.3 10.958,8.872C10.917,7.479 12.141,6.258 13.593,6.245C15.035,6.232 16.226,7.384 16.248,8.81H16.25ZM13.614,7.892C13.049,7.894 12.64,8.306 12.646,8.867C12.65,9.365 13.082,9.794 13.578,9.791C14.147,9.789 14.577,9.384 14.585,8.843C14.594,8.326 14.147,7.889 13.614,7.892Z"
|
||||
android:fillColor="#1F002A"/>
|
||||
</vector>
|
||||
15
navi-chat/src/main/res/drawable/ic_pause_icon_purple.xml
Normal file
15
navi-chat/src/main/res/drawable/ic_pause_icon_purple.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="53dp"
|
||||
android:height="53dp"
|
||||
android:viewportWidth="53"
|
||||
android:viewportHeight="53">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M26.5,26.5m-26,0a26,26 0,1 1,52 0a26,26 0,1 1,-52 0"
|
||||
android:fillColor="#F9F9F9"
|
||||
android:strokeColor="#EBEBEB"/>
|
||||
<path
|
||||
android:pathData="M22,34.375C23.237,34.375 24.25,33.362 24.25,32.125V20.875C24.25,19.638 23.237,18.625 22,18.625C20.763,18.625 19.75,19.638 19.75,20.875V32.125C19.75,33.362 20.763,34.375 22,34.375ZM28.75,20.875V32.125C28.75,33.362 29.763,34.375 31,34.375C32.237,34.375 33.25,33.362 33.25,32.125V20.875C33.25,19.638 32.237,18.625 31,18.625C29.763,18.625 28.75,19.638 28.75,20.875Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
10
navi-chat/src/main/res/drawable/ic_play_button.xml
Normal file
10
navi-chat/src/main/res/drawable/ic_play_button.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="54dp"
|
||||
android:height="54dp"
|
||||
android:viewportWidth="54"
|
||||
android:viewportHeight="54">
|
||||
<path
|
||||
android:pathData="M15.75,13.802V40.199C15.75,42.211 18.065,43.434 19.849,42.339L41.512,29.14C43.162,28.147 43.162,25.853 41.512,24.834L19.849,11.661C18.065,10.566 15.75,11.789 15.75,13.802Z"
|
||||
android:fillColor="#F9F9F9"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
13
navi-chat/src/main/res/drawable/ic_play_video_button.xml
Normal file
13
navi-chat/src/main/res/drawable/ic_play_video_button.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="98dp"
|
||||
android:height="98dp"
|
||||
android:viewportWidth="98"
|
||||
android:viewportHeight="98">
|
||||
<path
|
||||
android:pathData="M46,46m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"
|
||||
android:fillColor="#1F002A"/>
|
||||
<path
|
||||
android:pathData="M41,40.134V51.866C41,52.761 42.029,53.304 42.822,52.817L52.45,46.951C53.183,46.51 53.183,45.49 52.45,45.037L42.822,39.183C42.029,38.696 41,39.239 41,40.134Z"
|
||||
android:fillColor="#F5F5F5"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
15
navi-chat/src/main/res/drawable/ic_play_video_purple.xml
Normal file
15
navi-chat/src/main/res/drawable/ic_play_video_purple.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="53dp"
|
||||
android:height="53dp"
|
||||
android:viewportWidth="53"
|
||||
android:viewportHeight="53">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M26.5,26.5m-26,0a26,26 0,1 1,52 0a26,26 0,1 1,-52 0"
|
||||
android:fillColor="#F9F9F9"
|
||||
android:strokeColor="#EBEBEB"/>
|
||||
<path
|
||||
android:pathData="M20.059,18.944V34.057C20.059,35.21 21.385,35.91 22.406,35.283L34.809,27.726C35.754,27.157 35.754,25.844 34.809,25.261L22.406,17.719C21.385,17.092 20.059,17.792 20.059,18.944Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
21
navi-chat/src/main/res/drawable/ic_remove_image.xml
Normal file
21
navi-chat/src/main/res/drawable/ic_remove_image.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,0L12,0A12,12 0,0 1,24 12L24,12A12,12 0,0 1,12 24L12,24A12,12 0,0 1,0 12L0,12A12,12 0,0 1,12 0z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M12,3C7.029,3 3,7.029 3,12C3,16.971 7.029,21 12,21C16.971,21 21,16.971 21,12C21,7.029 16.971,3 12,3ZM1,12C1,5.925 5.925,1 12,1C18.075,1 23,5.925 23,12C23,18.075 18.075,23 12,23C5.925,23 1,18.075 1,12Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M15.707,8.293C16.098,8.683 16.098,9.317 15.707,9.707L9.707,15.707C9.317,16.098 8.683,16.098 8.293,15.707C7.902,15.317 7.902,14.683 8.293,14.293L14.293,8.293C14.683,7.902 15.317,7.902 15.707,8.293Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M8.293,8.293C8.683,7.902 9.317,7.902 9.707,8.293L15.707,14.293C16.098,14.683 16.098,15.317 15.707,15.707C15.317,16.098 14.683,16.098 14.293,15.707L8.293,9.707C7.902,9.317 7.902,8.683 8.293,8.293Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,12m0,12a12,12 0,1 1,0 -24a12,12 0,1 1,0 24"
|
||||
android:fillColor="#F5F5F5"/>
|
||||
<path
|
||||
android:pathData="M16.465,12.019C16.465,12.368 16.316,12.667 16.066,12.867L10.529,17.806C10.13,18.105 9.531,18.055 9.232,17.656C8.932,17.257 8.932,16.708 9.331,16.409L14.22,12.118C14.27,12.068 14.27,12.019 14.22,11.919L9.331,7.628C8.932,7.279 8.882,6.73 9.232,6.331C9.581,5.932 10.13,5.882 10.529,6.232C10.529,6.232 10.529,6.232 10.579,6.281L16.116,11.17C16.316,11.37 16.465,11.719 16.465,12.019Z"
|
||||
android:fillColor="#1F002A"/>
|
||||
</vector>
|
||||
11
navi-chat/src/main/res/drawable/ic_tooltip_slider_purple.xml
Normal file
11
navi-chat/src/main/res/drawable/ic_tooltip_slider_purple.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M10,10m-9,0a9,9 0,1 1,18 0a9,9 0,1 1,-18 0"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#1F002A"
|
||||
android:strokeColor="#ffffff"/>
|
||||
</vector>
|
||||
@@ -57,7 +57,7 @@
|
||||
android:id="@+id/ivPlayPauseVideo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_pause_icon"
|
||||
android:src="@drawable/ic_pause_icon_purple"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -84,8 +84,8 @@
|
||||
app:layout_constraintEnd_toStartOf="@id/totalDuration"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginBottom="@dimen/dp_34"
|
||||
android:progressTint="@color/outrageous_orange"
|
||||
android:thumb="@drawable/ic_tooltip_slider_thumb"
|
||||
android:progressTint="@color/dark_purple"
|
||||
android:thumb="@drawable/ic_tooltip_slider_purple"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
tools:progress="50"
|
||||
android:progressBackgroundTint="@color/white"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
android:layout_marginStart="@dimen/layout_dp_16"
|
||||
android:layout_marginTop="@dimen/layout_dp_16"
|
||||
android:textColor="@color/dark_gray"
|
||||
android:fontFamily="@font/tt_regular"
|
||||
android:fontFamily="@font/tt_medium"
|
||||
android:textSize="@dimen/sp_18"
|
||||
android:text="@string/add_files"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvChat"
|
||||
android:background="@color/white"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/layout_dp_0"
|
||||
android:visibility="visible"
|
||||
@@ -99,7 +100,8 @@
|
||||
android:id="@+id/ivSendAttachment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="@dimen/dp_16"
|
||||
android:layout_marginEnd="@dimen/dp_9"
|
||||
android:padding="@dimen/dp_7"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
app:layout_constraintEnd_toStartOf="@id/guideline1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_description"
|
||||
tools:src="@drawable/ic_gallery_icon" />
|
||||
tools:src="@drawable/ic_gallery_icon_new" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline1"
|
||||
@@ -62,7 +62,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/layout_dp_32"
|
||||
android:contentDescription="@string/right_arrow"
|
||||
android:src="@drawable/ic_right_arrow"
|
||||
android:src="@drawable/ic_right_arrow_purple_white_bg"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_description"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/white"
|
||||
android:elevation="@dimen/dp_1"
|
||||
android:layout_height="@dimen/layout_dp_48">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
<string name="error_playing_video">Error occurred while playing video</string>
|
||||
<string name="error_while_calling_api">The link you are trying to access has expired.</string>
|
||||
<string name="characters_left">%d/%d characters left</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="send">Send</string>
|
||||
<string name="add_attachment">Add Attachment</string>
|
||||
<string name="add_media">Add Media</string>
|
||||
<string name="file_size_exceeded">File size is too large</string>
|
||||
<!--Default value-->
|
||||
<string name="default_value">00:00</string>
|
||||
</resources>
|
||||
@@ -84,7 +84,7 @@ class NaviChatReceivedMessageWithAttachmentLayout @JvmOverloads constructor(
|
||||
|
||||
when (state) {
|
||||
VIEW_STATE -> {
|
||||
tvReceivedMessage.progressImage.setBackgroundResource(R.drawable.ic_preview)
|
||||
tvReceivedMessage.progressImage.setBackgroundResource(R.drawable.ic_preview_purple)
|
||||
tvReceivedMessage.progressState.progress = ProgressBar.GONE
|
||||
tvReceivedMessage.progressImage.setOnClickListener {
|
||||
naviChatFileAttachmentWidget.widgetData?.fileName?.let { uri ->
|
||||
@@ -95,7 +95,7 @@ class NaviChatReceivedMessageWithAttachmentLayout @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
DOWNLOAD_STATE, FAILED_STATE -> {
|
||||
tvReceivedMessage.progressImage.setBackgroundResource(R.drawable.ic_download)
|
||||
tvReceivedMessage.progressImage.setBackgroundResource(R.drawable.ic_download_purple)
|
||||
tvReceivedMessage.progressState.progress = ProgressBar.GONE
|
||||
tvReceivedMessage.progressImage.setOnClickListener {
|
||||
naviChatFileAttachmentWidget.widgetData.let { widgetData ->
|
||||
@@ -134,9 +134,9 @@ class NaviChatReceivedMessageWithAttachmentLayout @JvmOverloads constructor(
|
||||
|
||||
private fun getBackgroundDrawable(fileType: String?): Int {
|
||||
return when (fileType) {
|
||||
AWSFileType.MP4.value -> R.drawable.ic_video_preview
|
||||
AWSFileType.MP4.value -> R.drawable.ic_video_preview_purple
|
||||
AWSFileType.JPG.value, AWSFileType.JPEG.value,
|
||||
AWSFileType.PNG.value -> R.drawable.ic_image_preview
|
||||
AWSFileType.PNG.value -> R.drawable.ic_image_preview_purple
|
||||
else -> R.drawable.ic_document_preview
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,11 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
|
||||
when (state) {
|
||||
VIEW_STATE -> {
|
||||
tvSentMessage.progressImage.setBackgroundResource(R.drawable.ic_preview)
|
||||
if (naviChatFileAttachmentWidget.widgetData?.fileType == AWSFileType.MP4.value) {
|
||||
tvSentMessage.progressImage.setBackgroundResource(R.drawable.ic_play_preview_purple)
|
||||
} else {
|
||||
tvSentMessage.progressImage.setBackgroundResource(R.drawable.ic_preview_purple)
|
||||
}
|
||||
tvSentMessage.progressState.progress = ProgressBar.GONE
|
||||
tvSentMessage.progressImage.setOnClickListener {
|
||||
naviChatFileAttachmentWidget.id?.let {
|
||||
@@ -97,7 +101,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
}
|
||||
}
|
||||
FAILURE_AND_RETRY_STATE -> {
|
||||
tvSentMessage.progressImage.setBackgroundResource(R.drawable.ic_retry)
|
||||
tvSentMessage.progressImage.setBackgroundResource(R.drawable.ic_retry_new)
|
||||
tvSentMessage.progressState.progress = ProgressBar.GONE
|
||||
tvSentMessage.progressImage.setOnClickListener {
|
||||
naviChatFileAttachmentWidget.id?.let {
|
||||
@@ -106,7 +110,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
}
|
||||
}
|
||||
UPLOADING_STATE -> {
|
||||
tvSentMessage.progressImage.setBackgroundResource(R.drawable.ic_cancel)
|
||||
tvSentMessage.progressImage.setBackgroundResource(R.drawable.ic_cancel_purple)
|
||||
tvSentMessage.progressState.progress = ProgressBar.VISIBLE
|
||||
tvSentMessage.progressImage.setOnClickListener {
|
||||
naviChatFileAttachmentWidget.id?.let {
|
||||
@@ -116,7 +120,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
}
|
||||
DOWNLOAD_STATE,
|
||||
FAILED_STATE -> {
|
||||
tvSentMessage.progressImage.setBackgroundResource(R.drawable.ic_download)
|
||||
tvSentMessage.progressImage.setBackgroundResource(R.drawable.ic_download_purple)
|
||||
tvSentMessage.progressState.progress = ProgressBar.GONE
|
||||
tvSentMessage.progressImage.setOnClickListener {
|
||||
naviChatFileAttachmentWidget.widgetData?.fileUuid?.let {
|
||||
@@ -163,10 +167,10 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
|
||||
private fun getBackgroundDrawable(fileType: String?): Int {
|
||||
return when (fileType) {
|
||||
AWSFileType.MP4.value -> R.drawable.ic_video_preview
|
||||
AWSFileType.MP4.value -> R.drawable.ic_video_preview_purple
|
||||
AWSFileType.JPG.value,
|
||||
AWSFileType.JPEG.value,
|
||||
AWSFileType.PNG.value -> R.drawable.ic_image_preview
|
||||
AWSFileType.PNG.value -> R.drawable.ic_image_preview_purple
|
||||
else -> R.drawable.ic_document_preview
|
||||
}
|
||||
}
|
||||
|
||||
15
navi-widgets/src/main/res/drawable/ic_cancel_purple.xml
Normal file
15
navi-widgets/src/main/res/drawable/ic_cancel_purple.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="12dp"
|
||||
android:height="12dp"
|
||||
android:viewportWidth="12"
|
||||
android:viewportHeight="12">
|
||||
<path
|
||||
android:pathData="M6,6m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"
|
||||
android:fillColor="#1F002A"/>
|
||||
<path
|
||||
android:pathData="M9.121,3.023L9.121,3.023A0.563,0.563 0,0 1,9.121 3.818L3.818,9.122A0.563,0.563 58.086,0 1,3.023 9.122L3.023,9.122A0.563,0.563 58.086,0 1,3.023 8.326L8.326,3.023A0.563,0.563 0,0 1,9.121 3.023z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M3.023,3.023L3.023,3.023A0.563,0.563 75.486,0 1,3.818 3.023L9.122,8.326A0.563,0.563 51.903,0 1,9.122 9.122L9.122,9.122A0.563,0.563 51.903,0 1,8.326 9.122L3.023,3.819A0.563,0.563 75.486,0 1,3.023 3.023z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
@@ -1,27 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="21dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="21">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M0.004,10.379C0.004,7.386 0.004,4.393 0.004,1.4C0.005,0.752 0.322,0.277 0.908,0.072C1.065,0.018 1.242,0.007 1.41,0.007C4.644,0.003 7.877,0.008 11.111,-0C11.548,-0.001 11.899,0.149 12.2,0.443C13.308,1.527 14.417,2.609 15.525,3.693C15.846,4.005 16,4.377 16,4.825C15.996,9.675 15.998,14.526 15.997,19.376C15.997,20.037 15.677,20.523 15.087,20.725C14.931,20.779 14.753,20.788 14.584,20.788C10.197,20.791 5.81,20.782 1.423,20.799C0.592,20.802 -0.003,20.166 0,19.381C0.011,16.381 0.004,13.38 0.004,10.379ZM11.114,0.868H10.816C7.719,0.868 4.623,0.868 1.527,0.868C1.033,0.868 0.889,1.008 0.888,1.488C0.888,7.428 0.888,13.368 0.888,19.308C0.888,19.791 1.03,19.927 1.527,19.928C5.842,19.928 10.157,19.928 14.472,19.928C14.969,19.928 15.112,19.791 15.112,19.309C15.112,14.552 15.112,9.796 15.112,5.039V4.77H14.81C14.039,4.77 13.266,4.775 12.495,4.768C11.938,4.764 11.495,4.539 11.256,4.038C11.16,3.84 11.124,3.598 11.12,3.376C11.105,2.551 11.114,1.727 11.114,0.868ZM14.367,3.911C13.576,3.138 12.777,2.357 11.999,1.599C11.999,2.181 11.994,2.815 12.001,3.447C12.005,3.74 12.191,3.899 12.529,3.909C12.844,3.919 13.161,3.911 13.477,3.911C13.79,3.911 14.101,3.911 14.367,3.911Z"
|
||||
android:fillColor="#6B6B6B"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M3.6,8.799H12.4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#6B6B6B"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M3.6,12H12.4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#6B6B6B"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M3.6,15.199H12.4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#6B6B6B"
|
||||
android:strokeLineCap="round"/>
|
||||
android:pathData="M6,2C4.906,2 4,2.906 4,4V20C4,21.094 4.906,22 6,22H18C19.094,22 20,21.094 20,20V6.586L15.414,2H6ZM6,4H14V8H18V20H6V4ZM8,10V12H16V10H8ZM8,13V15H16V13H8ZM8,16V18H13V16H8Z"
|
||||
android:fillColor="#1F002A"/>
|
||||
</vector>
|
||||
|
||||
23
navi-widgets/src/main/res/drawable/ic_download_purple.xml
Normal file
23
navi-widgets/src/main/res/drawable/ic_download_purple.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M12,12m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0"
|
||||
android:fillColor="#1F002A"
|
||||
android:strokeColor="#1F002A"/>
|
||||
<path
|
||||
android:pathData="M6.75,13.167C7.072,13.167 7.334,13.428 7.334,13.75V16.084C7.334,16.238 7.395,16.387 7.505,16.496C7.614,16.605 7.762,16.667 7.917,16.667H16.084C16.238,16.667 16.387,16.605 16.496,16.496C16.605,16.387 16.667,16.238 16.667,16.084V13.75C16.667,13.428 16.928,13.167 17.25,13.167C17.573,13.167 17.834,13.428 17.834,13.75V16.084C17.834,16.548 17.649,16.993 17.321,17.321C16.993,17.649 16.548,17.834 16.084,17.834H7.917C7.453,17.834 7.008,17.649 6.68,17.321C6.351,16.993 6.167,16.548 6.167,16.084V13.75C6.167,13.428 6.428,13.167 6.75,13.167Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M8.671,10.421C8.899,10.193 9.268,10.193 9.496,10.421L12,12.925L14.504,10.421C14.732,10.193 15.101,10.193 15.329,10.421C15.557,10.649 15.557,11.018 15.329,11.246L12.413,14.163C12.185,14.39 11.815,14.39 11.587,14.163L8.671,11.246C8.443,11.018 8.443,10.649 8.671,10.421Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M12,6.167C12.323,6.167 12.584,6.428 12.584,6.75V13.75C12.584,14.073 12.323,14.334 12,14.334C11.678,14.334 11.417,14.073 11.417,13.75V6.75C11.417,6.428 11.678,6.167 12,6.167Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,22 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="25dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="25">
|
||||
<path
|
||||
android:pathData="M5,4.5C4.735,4.5 4.48,4.605 4.293,4.793C4.105,4.98 4,5.235 4,5.5V19.5C4,19.765 4.105,20.02 4.293,20.207C4.48,20.395 4.735,20.5 5,20.5H19C19.265,20.5 19.52,20.395 19.707,20.207C19.895,20.02 20,19.765 20,19.5V11.5C20,10.948 20.448,10.5 21,10.5C21.552,10.5 22,10.948 22,11.5V19.5C22,20.296 21.684,21.059 21.121,21.621C20.559,22.184 19.796,22.5 19,22.5H5C4.204,22.5 3.441,22.184 2.879,21.621C2.316,21.059 2,20.296 2,19.5V5.5C2,4.704 2.316,3.941 2.879,3.379C3.441,2.816 4.204,2.5 5,2.5H13C13.552,2.5 14,2.948 14,3.5C14,4.052 13.552,4.5 13,4.5H5Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M6.732,7.232C7.201,6.763 7.837,6.5 8.5,6.5C9.163,6.5 9.799,6.763 10.268,7.232C10.737,7.701 11,8.337 11,9C11,9.663 10.737,10.299 10.268,10.768C9.799,11.237 9.163,11.5 8.5,11.5C7.837,11.5 7.201,11.237 6.732,10.768C6.263,10.299 6,9.663 6,9C6,8.337 6.263,7.701 6.732,7.232ZM8.5,8.5C8.367,8.5 8.24,8.553 8.146,8.646C8.053,8.74 8,8.867 8,9C8,9.133 8.053,9.26 8.146,9.354C8.24,9.447 8.367,9.5 8.5,9.5C8.633,9.5 8.76,9.447 8.854,9.354C8.947,9.26 9,9.133 9,9C9,8.867 8.947,8.74 8.854,8.646C8.76,8.553 8.633,8.5 8.5,8.5Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M15.293,9.793C15.683,9.402 16.317,9.402 16.707,9.793L21.707,14.793C22.098,15.183 22.098,15.817 21.707,16.207C21.317,16.598 20.683,16.598 20.293,16.207L16,11.914L5.707,22.207C5.317,22.598 4.683,22.598 4.293,22.207C3.902,21.817 3.902,21.183 4.293,20.793L15.293,9.793Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M15,5.5C15,4.948 15.448,4.5 16,4.5H22C22.552,4.5 23,4.948 23,5.5C23,6.052 22.552,6.5 22,6.5H16C15.448,6.5 15,6.052 15,5.5Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
@@ -1,9 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/border_grey_color" />
|
||||
|
||||
<corners
|
||||
android:bottomLeftRadius="@dimen/dp_16"
|
||||
android:bottomRightRadius="@dimen/dp_20"
|
||||
android:topLeftRadius="@dimen/dp_16" />
|
||||
<solid android:color="@color/navi_chat_received_message_bg_color" />
|
||||
android:bottomLeftRadius="@dimen/dp_20"
|
||||
android:bottomRightRadius="@dimen/dp_4"
|
||||
android:topLeftRadius="@dimen/dp_20"
|
||||
android:topRightRadius="@dimen/dp_20" />
|
||||
<solid android:color="@color/white" />
|
||||
</shape>
|
||||
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M12,12m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0"
|
||||
android:fillColor="#F9F9F9"
|
||||
android:strokeColor="#EBEBEB"/>
|
||||
<path
|
||||
android:pathData="M9.083,8.578V15.422C9.083,15.944 9.684,16.261 10.146,15.977L15.763,12.555C16.19,12.298 16.19,11.703 15.763,11.439L10.146,8.024C9.684,7.74 9.083,8.057 9.083,8.578Z"
|
||||
android:fillColor="#1F002A"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
8
navi-widgets/src/main/res/drawable/ic_preview_purple.xml
Normal file
8
navi-widgets/src/main/res/drawable/ic_preview_purple.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<vector android:height="24dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#F9F9F9"
|
||||
android:pathData="M12,12m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0"
|
||||
android:strokeColor="#EBEBEB" android:strokeWidth="1"/>
|
||||
<path android:fillColor="#1F002A" android:fillType="evenOdd" android:pathData="M6.249,12C6.313,12.11 6.397,12.251 6.502,12.413C6.771,12.829 7.169,13.383 7.686,13.934C8.731,15.049 10.191,16.083 12,16.083C13.809,16.083 15.269,15.049 16.314,13.934C16.831,13.383 17.229,12.829 17.498,12.413C17.603,12.251 17.688,12.11 17.751,12C17.688,11.89 17.603,11.749 17.498,11.587C17.229,11.171 16.831,10.617 16.314,10.066C15.269,8.951 13.809,7.917 12,7.917C10.191,7.917 8.731,8.951 7.686,10.066C7.169,10.617 6.771,11.171 6.502,11.587C6.397,11.749 6.313,11.89 6.249,12ZM18.417,12C18.938,11.739 18.938,11.739 18.938,11.739L18.937,11.737L18.935,11.733L18.929,11.72C18.923,11.709 18.915,11.694 18.905,11.675C18.885,11.636 18.855,11.582 18.817,11.514C18.74,11.377 18.627,11.184 18.478,10.954C18.182,10.496 17.742,9.883 17.165,9.268C16.022,8.049 14.275,6.75 12,6.75C9.725,6.75 7.978,8.049 6.835,9.268C6.258,9.883 5.818,10.496 5.522,10.954C5.373,11.184 5.26,11.377 5.183,11.514C5.145,11.582 5.115,11.636 5.095,11.675C5.085,11.694 5.077,11.709 5.071,11.72L5.065,11.733L5.063,11.737L5.062,11.738C5.062,11.738 5.062,11.739 5.583,12L5.062,11.739C4.979,11.903 4.979,12.097 5.062,12.261L5.583,12C5.062,12.261 5.061,12.261 5.062,12.261L5.063,12.263L5.065,12.267L5.071,12.28C5.077,12.291 5.085,12.306 5.095,12.325C5.115,12.364 5.145,12.418 5.183,12.486C5.26,12.623 5.373,12.816 5.522,13.046C5.818,13.504 6.258,14.117 6.835,14.732C7.978,15.951 9.725,17.25 12,17.25C14.275,17.25 16.022,15.951 17.165,14.732C17.742,14.117 18.182,13.504 18.478,13.046C18.627,12.816 18.74,12.623 18.817,12.486C18.855,12.418 18.885,12.364 18.905,12.325C18.915,12.306 18.923,12.291 18.929,12.28L18.935,12.267L18.937,12.263L18.938,12.262C18.938,12.262 18.938,12.261 18.417,12ZM18.417,12L18.938,12.261C19.021,12.097 19.02,11.903 18.938,11.739L18.417,12Z"/>
|
||||
<path android:fillColor="#1F002A" android:fillType="evenOdd" android:pathData="M12,10.834C11.356,10.834 10.834,11.356 10.834,12C10.834,12.645 11.356,13.167 12,13.167C12.645,13.167 13.167,12.645 13.167,12C13.167,11.356 12.645,10.834 12,10.834ZM9.667,12C9.667,10.712 10.712,9.667 12,9.667C13.289,9.667 14.334,10.712 14.334,12C14.334,13.289 13.289,14.334 12,14.334C10.712,14.334 9.667,13.289 9.667,12Z"/>
|
||||
</vector>
|
||||
16
navi-widgets/src/main/res/drawable/ic_retry_new.xml
Normal file
16
navi-widgets/src/main/res/drawable/ic_retry_new.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,12m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"
|
||||
android:fillColor="#ffffff"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M5,5h14v14h-14z"/>
|
||||
<path
|
||||
android:pathData="M11.858,16.65C10.555,16.65 9.452,16.198 8.548,15.293C7.643,14.389 7.191,13.286 7.191,11.983C7.191,10.68 7.643,9.577 8.548,8.673C9.452,7.768 10.555,7.316 11.858,7.316C12.529,7.316 13.171,7.455 13.783,7.732C14.396,8.009 14.921,8.405 15.358,8.921V7.9C15.358,7.578 15.619,7.316 15.941,7.316V7.316C16.264,7.316 16.525,7.578 16.525,7.9V10.4C16.525,10.952 16.077,11.4 15.525,11.4H13.025C12.703,11.4 12.441,11.139 12.441,10.816V10.816C12.441,10.494 12.703,10.233 13.025,10.233H14.891C14.58,9.689 14.155,9.261 13.616,8.95C13.076,8.639 12.49,8.483 11.858,8.483C10.886,8.483 10.059,8.823 9.379,9.504C8.698,10.184 8.358,11.011 8.358,11.983C8.358,12.955 8.698,13.782 9.379,14.462C10.059,15.143 10.886,15.483 11.858,15.483C12.607,15.483 13.282,15.269 13.885,14.841C14.376,14.493 14.747,14.055 15,13.526C15.105,13.306 15.317,13.15 15.561,13.15V13.15C15.974,13.15 16.277,13.543 16.107,13.92C15.797,14.608 15.334,15.192 14.716,15.673C13.88,16.324 12.927,16.65 11.858,16.65Z"
|
||||
android:fillColor="#1F002A"/>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h24v24h-24z"/>
|
||||
<path
|
||||
android:pathData="M15,8V16H5V8H15ZM16,6H4C3.45,6 3,6.45 3,7V17C3,17.55 3.45,18 4,18H16C16.55,18 17,17.55 17,17V13.5L21,17.5V6.5L17,10.5V7C17,6.45 16.55,6 16,6Z"
|
||||
android:fillColor="#000000"/>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -18,8 +18,8 @@
|
||||
app:layout_constraintEnd_toStartOf="@id/tvMessage"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:src="@drawable/ic_image_preview"
|
||||
tools:src="@drawable/ic_image_preview" />
|
||||
android:src="@drawable/ic_image_preview_purple"
|
||||
tools:src="@drawable/ic_image_preview_purple" />
|
||||
|
||||
<com.navi.design.textview.NaviTextView
|
||||
android:id="@+id/tvMessage"
|
||||
@@ -59,6 +59,6 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/tvMessage"
|
||||
app:layout_constraintTop_toTopOf="@id/tvMessage"
|
||||
tools:src="@drawable/ic_cancel" />
|
||||
tools:src="@drawable/ic_cancel_purple" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
@@ -54,7 +54,7 @@
|
||||
android:layout_gravity="end"
|
||||
android:paddingLeft="@dimen/dp_4"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvTimestamp"
|
||||
app:layout_constraintTop_toTopOf="@id/tvTimestamp"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvSentMessage"
|
||||
app:layout_constraintEnd_toEndOf="@id/tvSentMessage"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
|
||||
Reference in New Issue
Block a user