|
@@ -33,7 +33,9 @@ import android.content.ClipData
|
|
|
import android.content.Context
|
|
|
import android.content.Intent
|
|
|
import android.content.pm.PackageManager
|
|
|
+import android.content.res.AssetFileDescriptor
|
|
|
import android.content.res.Resources
|
|
|
+import android.database.Cursor
|
|
|
import android.graphics.Bitmap
|
|
|
import android.graphics.drawable.ColorDrawable
|
|
|
import android.media.MediaPlayer
|
|
@@ -46,6 +48,7 @@ import android.os.Handler
|
|
|
import android.os.SystemClock
|
|
|
import android.os.VibrationEffect
|
|
|
import android.os.Vibrator
|
|
|
+import android.provider.ContactsContract
|
|
|
import android.text.Editable
|
|
|
import android.text.InputFilter
|
|
|
import android.text.TextUtils
|
|
@@ -69,6 +72,7 @@ import android.widget.RelativeLayout
|
|
|
import android.widget.Toast
|
|
|
import androidx.appcompat.view.ContextThemeWrapper
|
|
|
import androidx.core.content.ContextCompat
|
|
|
+import androidx.core.content.FileProvider
|
|
|
import androidx.core.content.PermissionChecker
|
|
|
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
|
|
import androidx.core.widget.doAfterTextChanged
|
|
@@ -93,6 +97,7 @@ import com.facebook.drawee.backends.pipeline.Fresco
|
|
|
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
|
|
import com.facebook.imagepipeline.image.CloseableImage
|
|
|
import com.google.android.flexbox.FlexboxLayout
|
|
|
+import com.nextcloud.talk.BuildConfig
|
|
|
import com.nextcloud.talk.R
|
|
|
import com.nextcloud.talk.activities.CallActivity
|
|
|
import com.nextcloud.talk.activities.MainActivity
|
|
@@ -140,6 +145,7 @@ import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback
|
|
|
import com.nextcloud.talk.utils.ApiUtils
|
|
|
import com.nextcloud.talk.utils.ConductorRemapping
|
|
|
import com.nextcloud.talk.utils.ConductorRemapping.remapChatController
|
|
|
+import com.nextcloud.talk.utils.ContactUtils
|
|
|
import com.nextcloud.talk.utils.DateUtils
|
|
|
import com.nextcloud.talk.utils.DisplayUtils
|
|
|
import com.nextcloud.talk.utils.KeyboardUtils
|
|
@@ -1100,6 +1106,15 @@ class ChatController(args: Bundle) :
|
|
|
)
|
|
|
}
|
|
|
|
|
|
+ private fun requestReadContacts() {
|
|
|
+ requestPermissions(
|
|
|
+ arrayOf(
|
|
|
+ Manifest.permission.READ_CONTACTS
|
|
|
+ ),
|
|
|
+ REQUEST_READ_CONTACT_PERMISSION
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
private fun checkReadOnlyState() {
|
|
|
if (currentConversation != null && isAlive()) {
|
|
|
if (currentConversation?.shouldShowLobby(conversationUser) ?: false ||
|
|
@@ -1186,62 +1201,83 @@ class ChatController(args: Bundle) :
|
|
|
}
|
|
|
|
|
|
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
|
|
|
+ if (resultCode != RESULT_OK) {
|
|
|
+ Log.e(TAG, "resultCode for received intent was != ok")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
if (requestCode == REQUEST_CODE_CHOOSE_FILE) {
|
|
|
- if (resultCode == RESULT_OK) {
|
|
|
- try {
|
|
|
- checkNotNull(intent)
|
|
|
- filesToUpload.clear()
|
|
|
- intent.clipData?.let {
|
|
|
- for (index in 0 until it.itemCount) {
|
|
|
- filesToUpload.add(it.getItemAt(index).uri.toString())
|
|
|
- }
|
|
|
- } ?: run {
|
|
|
- checkNotNull(intent.data)
|
|
|
- intent.data.let {
|
|
|
- filesToUpload.add(intent.data.toString())
|
|
|
- }
|
|
|
+ try {
|
|
|
+ checkNotNull(intent)
|
|
|
+ filesToUpload.clear()
|
|
|
+ intent.clipData?.let {
|
|
|
+ for (index in 0 until it.itemCount) {
|
|
|
+ filesToUpload.add(it.getItemAt(index).uri.toString())
|
|
|
}
|
|
|
- require(filesToUpload.isNotEmpty())
|
|
|
+ } ?: run {
|
|
|
+ checkNotNull(intent.data)
|
|
|
+ intent.data.let {
|
|
|
+ filesToUpload.add(intent.data.toString())
|
|
|
+ }
|
|
|
+ }
|
|
|
+ require(filesToUpload.isNotEmpty())
|
|
|
|
|
|
- val filenamesWithLinebreaks = StringBuilder("\n")
|
|
|
+ val filenamesWithLinebreaks = StringBuilder("\n")
|
|
|
|
|
|
- for (file in filesToUpload) {
|
|
|
- val filename = UriUtils.getFileName(Uri.parse(file), context)
|
|
|
- filenamesWithLinebreaks.append(filename).append("\n")
|
|
|
- }
|
|
|
+ for (file in filesToUpload) {
|
|
|
+ val filename = UriUtils.getFileName(Uri.parse(file), context)
|
|
|
+ filenamesWithLinebreaks.append(filename).append("\n")
|
|
|
+ }
|
|
|
|
|
|
- val confirmationQuestion = when (filesToUpload.size) {
|
|
|
- 1 -> context?.resources?.getString(R.string.nc_upload_confirm_send_single)?.let {
|
|
|
- String.format(it, title)
|
|
|
- }
|
|
|
- else -> context?.resources?.getString(R.string.nc_upload_confirm_send_multiple)?.let {
|
|
|
- String.format(it, title)
|
|
|
- }
|
|
|
+ val confirmationQuestion = when (filesToUpload.size) {
|
|
|
+ 1 -> context?.resources?.getString(R.string.nc_upload_confirm_send_single)?.let {
|
|
|
+ String.format(it, title)
|
|
|
+ }
|
|
|
+ else -> context?.resources?.getString(R.string.nc_upload_confirm_send_multiple)?.let {
|
|
|
+ String.format(it, title)
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- LovelyStandardDialog(activity)
|
|
|
- .setPositiveButtonColorRes(R.color.nc_darkGreen)
|
|
|
- .setTitle(confirmationQuestion)
|
|
|
- .setMessage(filenamesWithLinebreaks.toString())
|
|
|
- .setPositiveButton(R.string.nc_yes) { v ->
|
|
|
- if (UploadAndShareFilesWorker.isStoragePermissionGranted(context!!)) {
|
|
|
- uploadFiles(filesToUpload, false)
|
|
|
- } else {
|
|
|
- UploadAndShareFilesWorker.requestStoragePermission(this)
|
|
|
- }
|
|
|
+ LovelyStandardDialog(activity)
|
|
|
+ .setPositiveButtonColorRes(R.color.nc_darkGreen)
|
|
|
+ .setTitle(confirmationQuestion)
|
|
|
+ .setMessage(filenamesWithLinebreaks.toString())
|
|
|
+ .setPositiveButton(R.string.nc_yes) { v ->
|
|
|
+ if (UploadAndShareFilesWorker.isStoragePermissionGranted(context!!)) {
|
|
|
+ uploadFiles(filesToUpload, false)
|
|
|
+ } else {
|
|
|
+ UploadAndShareFilesWorker.requestStoragePermission(this)
|
|
|
}
|
|
|
- .setNegativeButton(R.string.nc_no) {}
|
|
|
- .show()
|
|
|
- } catch (e: IllegalStateException) {
|
|
|
- Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG)
|
|
|
- .show()
|
|
|
- Log.e(javaClass.simpleName, "Something went wrong when trying to upload file", e)
|
|
|
- } catch (e: IllegalArgumentException) {
|
|
|
- Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG)
|
|
|
- .show()
|
|
|
- Log.e(javaClass.simpleName, "Something went wrong when trying to upload file", e)
|
|
|
- }
|
|
|
+ }
|
|
|
+ .setNegativeButton(R.string.nc_no) {}
|
|
|
+ .show()
|
|
|
+ } catch (e: IllegalStateException) {
|
|
|
+ Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG)
|
|
|
+ .show()
|
|
|
+ Log.e(javaClass.simpleName, "Something went wrong when trying to upload file", e)
|
|
|
+ } catch (e: IllegalArgumentException) {
|
|
|
+ Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG)
|
|
|
+ .show()
|
|
|
+ Log.e(javaClass.simpleName, "Something went wrong when trying to upload file", e)
|
|
|
+ }
|
|
|
+ } else if (requestCode == REQUEST_CODE_SELECT_CONTACT) {
|
|
|
+ val contactUri = intent?.data ?: return
|
|
|
+ val cursor: Cursor? = activity?.contentResolver!!.query(contactUri, null, null, null, null)
|
|
|
+
|
|
|
+ if (cursor != null && cursor.moveToFirst()) {
|
|
|
+ val id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
|
|
|
+ val fileName = ContactUtils.getDisplayNameFromDeviceContact(context!!, id) + ".vcf"
|
|
|
+ val file = File(context?.cacheDir, fileName)
|
|
|
+ writeContactToVcfFile(cursor, file)
|
|
|
+
|
|
|
+ val shareUri = FileProvider.getUriForFile(
|
|
|
+ activity!!,
|
|
|
+ BuildConfig.APPLICATION_ID,
|
|
|
+ File(file.absolutePath)
|
|
|
+ )
|
|
|
+ uploadFiles(mutableListOf(shareUri.toString()), false)
|
|
|
}
|
|
|
+ cursor?.close()
|
|
|
} else if (requestCode == REQUEST_CODE_PICK_CAMERA) {
|
|
|
if (resultCode == RESULT_OK) {
|
|
|
try {
|
|
@@ -1273,6 +1309,21 @@ class ChatController(args: Bundle) :
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private fun writeContactToVcfFile(cursor: Cursor, file: File) {
|
|
|
+ val lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY))
|
|
|
+ val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey)
|
|
|
+
|
|
|
+ val fd: AssetFileDescriptor = activity?.contentResolver!!.openAssetFileDescriptor(uri, "r")!!
|
|
|
+ val fis = fd.createInputStream()
|
|
|
+
|
|
|
+ file.createNewFile()
|
|
|
+ fis.use { input ->
|
|
|
+ file.outputStream().use { output ->
|
|
|
+ input.copyTo(output)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
|
|
if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION) {
|
|
|
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
@@ -1295,6 +1346,17 @@ class ChatController(args: Bundle) :
|
|
|
Toast.LENGTH_LONG
|
|
|
).show()
|
|
|
}
|
|
|
+ } else if (requestCode == REQUEST_READ_CONTACT_PERMISSION) {
|
|
|
+ if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
|
+ val intent = Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
|
|
|
+ startActivityForResult(intent, REQUEST_CODE_SELECT_CONTACT)
|
|
|
+ } else {
|
|
|
+ Toast.makeText(
|
|
|
+ context,
|
|
|
+ context!!.getString(R.string.nc_share_contact_permission),
|
|
|
+ Toast.LENGTH_LONG
|
|
|
+ ).show()
|
|
|
+ }
|
|
|
} else if (requestCode == REQUEST_CAMERA_PERMISSION) {
|
|
|
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
|
Log.d(TAG, "launch cam activity since permission for cam has been granted")
|
|
@@ -1358,6 +1420,10 @@ class ChatController(args: Bundle) :
|
|
|
)
|
|
|
}
|
|
|
|
|
|
+ fun sendChooseContactIntent() {
|
|
|
+ requestReadContacts()
|
|
|
+ }
|
|
|
+
|
|
|
fun showBrowserScreen(browserType: BrowserController.BrowserType) {
|
|
|
val bundle = Bundle()
|
|
|
bundle.putParcelable(BundleKeys.KEY_BROWSER_TYPE, Parcels.wrap<BrowserController.BrowserType>(browserType))
|
|
@@ -2621,7 +2687,9 @@ class ChatController(args: Bundle) :
|
|
|
private const val MESSAGE_MAX_LENGTH: Int = 1000
|
|
|
private const val AGE_THREHOLD_FOR_DELETE_MESSAGE: Int = 21600000 // (6 hours in millis = 6 * 3600 * 1000)
|
|
|
private const val REQUEST_CODE_CHOOSE_FILE: Int = 555
|
|
|
+ private const val REQUEST_CODE_SELECT_CONTACT: Int = 666
|
|
|
private const val REQUEST_RECORD_AUDIO_PERMISSION = 222
|
|
|
+ private const val REQUEST_READ_CONTACT_PERMISSION = 234
|
|
|
private const val REQUEST_CAMERA_PERMISSION = 223
|
|
|
private const val REQUEST_CODE_PICK_CAMERA: Int = 333
|
|
|
private const val OBJECT_MESSAGE: String = "{object}"
|