Skip to content
Snippets Groups Projects
Commit 418c8fdf authored by Amirhossein Naghshzan's avatar Amirhossein Naghshzan
Browse files

ContactDetailsActivity: edit swarm group profile picture

Change-Id: Id25bf13e589714af66f37e2e9c2ba15e5e4b2e5f
parent d2af62c3
No related branches found
No related tags found
No related merge requests found
......@@ -19,23 +19,35 @@
*/
package cx.ring.client
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap
import android.os.Bundle
import android.provider.MediaStore
import android.util.Base64
import android.util.Log
import android.view.LayoutInflater
import android.view.MenuItem
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.tabs.TabLayout
import cx.ring.R
import cx.ring.account.RenameSwarmDialog
import cx.ring.application.JamiApplication
import cx.ring.databinding.ActivityContactDetailsBinding
import cx.ring.databinding.DialogProfileBinding
import cx.ring.databinding.ItemContactHorizontalBinding
import cx.ring.fragments.CallFragment
import cx.ring.fragments.ContactPickerFragment
......@@ -44,11 +56,16 @@ import cx.ring.fragments.ConversationFragment
import cx.ring.fragments.ConversationGalleryFragment
import cx.ring.fragments.ConversationMembersFragment
import cx.ring.services.SharedPreferencesServiceImpl.Companion.getConversationPreferences
import cx.ring.utils.AndroidFileUtils
import cx.ring.utils.BitmapUtils
import cx.ring.utils.ContentUriHandler
import cx.ring.utils.ConversationPath
import cx.ring.views.AvatarDrawable
import dagger.hilt.android.AndroidEntryPoint
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.schedulers.Schedulers
import net.jami.model.Call
import net.jami.model.Contact
import net.jami.model.Conversation
......@@ -56,7 +73,9 @@ import net.jami.model.Uri
import net.jami.services.AccountService
import net.jami.services.ContactService
import net.jami.services.ConversationFacade
import net.jami.services.DeviceRuntimeService
import net.jami.services.NotificationService
import java.io.ByteArrayOutputStream
import javax.inject.Inject
import javax.inject.Singleton
......@@ -75,8 +94,37 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
@Singleton lateinit
var mAccountService: AccountService
@Inject
@Singleton lateinit
var mDeviceRuntimeService: DeviceRuntimeService
private var binding: ActivityContactDetailsBinding? = null
private var path: ConversationPath? = null
private var mProfilePhoto: ImageView? = null
private var mSourcePhoto: Bitmap? = null
private var tmpProfilePhotoUri: android.net.Uri? = null
private val cameraResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
tmpProfilePhotoUri.let { photoUri ->
if (photoUri == null) {
if (data != null)
updatePhoto(Single.just(data.extras!!["data"] as Bitmap))
} else {
updatePhoto(photoUri)
}
}
tmpProfilePhotoUri = null
}
}
private val galleryResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
updatePhoto(data!!.data!!)
}
}
internal class ContactView(val binding: ItemContactHorizontalBinding, parentDisposable: CompositeDisposable)
: RecyclerView.ViewHolder(binding.root) {
......@@ -139,7 +187,9 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
if (vm.mode == Conversation.Mode.OneToOne) {
binding.title.setOnClickListener(null)
binding.description.setOnClickListener(null)
binding.contactImage.setOnClickListener(null)
} else {
binding.contactImage.setOnClickListener { profileImageClicked() }
binding.title.setOnClickListener {
val title = getString(R.string.dialogtitle_title)
val hint = getString(R.string.dialog_hint_title)
......@@ -195,6 +245,104 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
})
}
private fun profileImageClicked() {
val inflater = LayoutInflater.from(this)
val view = DialogProfileBinding.inflate(inflater).apply {
camera.setOnClickListener {
if (mDeviceRuntimeService.hasVideoPermission())
gotToImageCapture()
else
askCameraPermission()
}
gallery.setOnClickListener {
if (mDeviceRuntimeService.hasGalleryPermission())
goToGallery()
else
askGalleryPermission()
}
}
mProfilePhoto = view.profilePhoto
MaterialAlertDialogBuilder(this)
.setTitle(R.string.profile)
.setView(view.root)
.setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.cancel() }
.setPositiveButton(android.R.string.ok) { dialog, which ->
mSourcePhoto?.let { source ->
val os = ByteArrayOutputStream()
BitmapUtils.createScaledBitmap(source, 512)
.compress(Bitmap.CompressFormat.JPEG, 90, os)
val map: MutableMap<String, String> = HashMap()
map["avatar"] = Base64.encodeToString(os.toByteArray(), Base64.NO_WRAP)
mAccountService.updateConversationInfo(path!!.accountId, path!!.conversationUri.host, map)
}
}
.setOnDismissListener {
mProfilePhoto = null
mSourcePhoto = null
}
.show()
}
private fun gotToImageCapture() {
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
val file = AndroidFileUtils.createImageFile(this)
val uri = FileProvider.getUriForFile(this, ContentUriHandler.AUTHORITY_FILES, file)
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
.putExtra("android.intent.extras.CAMERA_FACING", 1)
.putExtra("android.intent.extras.LENS_FACING_FRONT", 1)
.putExtra("android.intent.extra.USE_FRONT_CAMERA", true)
tmpProfilePhotoUri = uri
cameraResultLauncher.launch(intent)
} catch (e: Exception) {
Toast.makeText(this, "Error starting camera: " + e.localizedMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, "Can't create temp file", e)
}
}
private fun askCameraPermission() {
requestPermissions(arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
), HomeActivity.REQUEST_PERMISSION_CAMERA)
}
private fun goToGallery() {
try {
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
galleryResultLauncher.launch(intent)
} catch (e: Exception) {
Toast.makeText(this, R.string.gallery_error_message, Toast.LENGTH_SHORT)
.show()
}
}
private fun askGalleryPermission() {
requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_PERMISSION_READ_STORAGE)
}
private fun updatePhoto(uriImage: android.net.Uri) {
updatePhoto(AndroidFileUtils.loadBitmap(this, uriImage))
}
private fun updatePhoto(image: Single<Bitmap>) {
mDisposableBag.add(image.subscribeOn(Schedulers.io())
.map { img ->
mSourcePhoto = img
AvatarDrawable.Builder()
.withPhoto(img)
.withCircleCrop(true)
.build(this)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ avatar: AvatarDrawable ->
mProfilePhoto?.setImageDrawable(avatar)
}) { e: Throwable ->
Log.e(TAG, "Error loading image", e)
})
}
public fun updateColor(color: Int) {
binding!!.appBar.backgroundTintList = ColorStateList.valueOf(color)
binding!!.addMember.backgroundTintList = ColorStateList.valueOf(color)
......@@ -227,7 +375,7 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
.putExtras(ConversationPath.toBundle(conversation))
.putExtra(Intent.EXTRA_PHONE_NUMBER, contactUri.uri)
.putExtra(CallFragment.KEY_HAS_VIDEO, hasVideo)
startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL)
startActivityForResult(intent, REQUEST_CODE_CALL)
}
}
......@@ -287,5 +435,7 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
const val TAB_ABOUT = 0
const val TAB_MEMBER = 1
const val TAB_DOCUMENT = 2
const val REQUEST_CODE_CALL = 3
const val REQUEST_PERMISSION_READ_STORAGE = 114
}
}
......@@ -28,8 +28,9 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_marginTop="24dp"
android:layout_marginStart="15dp"
android:padding="8dp"
android:layout_marginTop="12dp"
android:layout_marginStart="8dp"
android:src="@drawable/abc_ic_ab_back_material"
android:background="@null"
app:tint="@color/text_color_primary_dark" />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment