diff --git a/jami-android/app/src/main/java/cx/ring/account/AccountCreationModelImpl.kt b/jami-android/app/src/main/java/cx/ring/account/AccountCreationModelImpl.kt deleted file mode 100644 index fb97c93a54c42e870548ce279c69fef4c8bf674f..0000000000000000000000000000000000000000 --- a/jami-android/app/src/main/java/cx/ring/account/AccountCreationModelImpl.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2004-2024 Savoir-faire Linux Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ -package cx.ring.account - -import net.jami.model.AccountCreationModel -import ezvcard.VCard -import ezvcard.property.FormattedName -import ezvcard.property.Uid -import android.graphics.Bitmap -import cx.ring.utils.BitmapUtils -import ezvcard.property.Photo -import ezvcard.property.RawProperty -import io.reactivex.rxjava3.core.Single - -class AccountCreationModelImpl : AccountCreationModel() { - override fun toVCard(): Single<VCard> = Single.fromCallable { - val vcard = VCard() - vcard.formattedName = FormattedName(fullName) - vcard.uid = Uid(username) - val bmp = photo as Bitmap? - if (bmp != null) { - vcard.removeProperties(Photo::class.java) - vcard.addPhoto(BitmapUtils.bitmapToPhoto(bmp)) - } - vcard.removeProperties(RawProperty::class.java) - vcard - } -} \ No newline at end of file diff --git a/jami-android/app/src/main/java/cx/ring/account/AccountCreationViewModel.kt b/jami-android/app/src/main/java/cx/ring/account/AccountCreationViewModel.kt index f44959df98265984926b82843dc6e450b170d604..cc2bbcb7c9712c0595e6b890d89ff1726e36c4e5 100644 --- a/jami-android/app/src/main/java/cx/ring/account/AccountCreationViewModel.kt +++ b/jami-android/app/src/main/java/cx/ring/account/AccountCreationViewModel.kt @@ -1,7 +1,8 @@ package cx.ring.account import androidx.lifecycle.ViewModel +import net.jami.model.AccountCreationModel class AccountCreationViewModel: ViewModel() { - var model = AccountCreationModelImpl() + var model = AccountCreationModel() } \ No newline at end of file diff --git a/jami-android/app/src/main/java/cx/ring/account/AccountWizardActivity.kt b/jami-android/app/src/main/java/cx/ring/account/AccountWizardActivity.kt index b5ebf9b62d88371254756ee1157262a90dd6afbb..dc0876e737df836e2a1d06ef31ae3cb346219bcb 100644 --- a/jami-android/app/src/main/java/cx/ring/account/AccountWizardActivity.kt +++ b/jami-android/app/src/main/java/cx/ring/account/AccountWizardActivity.kt @@ -19,9 +19,11 @@ package cx.ring.account import android.Manifest import android.content.Intent import android.content.pm.ActivityInfo +import android.graphics.Bitmap import android.os.Build import android.os.Bundle import android.text.TextUtils +import android.util.Log import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels @@ -34,17 +36,15 @@ import cx.ring.databinding.ItemProgressDialogBinding import cx.ring.fragments.AccountMigrationFragment import cx.ring.fragments.SIPAccountCreationFragment import cx.ring.mvp.BaseActivity -import cx.ring.services.VCardServiceImpl import cx.ring.utils.BiometricHelper +import cx.ring.utils.BitmapUtils import dagger.hilt.android.AndroidEntryPoint -import ezvcard.VCard import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.schedulers.Schedulers import net.jami.account.AccountWizardPresenter import net.jami.account.AccountWizardView import net.jami.model.Account import net.jami.model.AccountConfig -import net.jami.utils.VCardUtils @AndroidEntryPoint class AccountWizardActivity : BaseActivity<AccountWizardPresenter>(), AccountWizardView { @@ -91,15 +91,18 @@ class AccountWizardActivity : BaseActivity<AccountWizardPresenter>(), AccountWiz super.onDestroy() } - override fun saveProfile(account: Account): Single<VCard> { - val filedir = filesDir + override fun saveProfile(account: Account) { val model: AccountCreationViewModel by viewModels() - return model.model.toVCard() - .flatMap { vcard: VCard -> - account.loadedProfile = Single.fromCallable { VCardServiceImpl.readData(vcard) }.cache() - VCardUtils.saveLocalProfileToDisk(vcard, account.accountId, filedir) - } - .subscribeOn(Schedulers.io()) + val name = model.model.fullName + val photo = model.model.photo as? Bitmap? + if (photo != null) { + Single.just(photo).map { BitmapUtils.bitmapToBase64(it)!! } + .observeOn(Schedulers.computation()) + .subscribe({ presenter.updateProfile(account.accountId, name, it, "PNG") }) + { e -> Log.e(TAG, "Error updating profile", e) } + } else { + presenter.updateProfile(account.accountId, model.model.fullName, "", "") + } } fun createAccount() { diff --git a/jami-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.kt b/jami-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.kt index 7186e99a2e779a6c4cca2073843572671fa65623..27f6d38772a339f3254bf1e8f1f17d3b94863d23 100644 --- a/jami-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.kt +++ b/jami-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.kt @@ -35,6 +35,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import net.jami.account.HomeAccountCreationPresenter import net.jami.account.HomeAccountCreationView +import net.jami.model.AccountCreationModel import net.jami.utils.Log import java.io.File @@ -51,7 +52,7 @@ class HomeAccountCreationFragment : getCacheFile(requireContext(), uri) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ file: File -> - model.model = AccountCreationModelImpl().apply { + model.model = AccountCreationModel().apply { isLink = true archive = file } @@ -89,19 +90,19 @@ class HomeAccountCreationFragment : } override fun goToAccountCreation() { - model.model = AccountCreationModelImpl() + model.model = AccountCreationModel() replaceFragmentWithSlide(JamiAccountCreationFragment(), JamiAccountCreationFragment.TAG, R.id.wizard_container) } override fun goToAccountLink() { - model.model = AccountCreationModelImpl().apply { + model.model = AccountCreationModel().apply { isLink = true } replaceFragmentWithSlide(JamiLinkAccountFragment(), JamiLinkAccountFragment.TAG, R.id.wizard_container) } override fun goToAccountConnect() { - model.model = AccountCreationModelImpl().apply { + model.model = AccountCreationModel().apply { isLink = true } replaceFragmentWithSlide(JamiAccountConnectFragment(), JamiAccountConnectFragment.TAG, R.id.wizard_container) diff --git a/jami-android/app/src/main/java/cx/ring/account/JamiAccountSummaryFragment.kt b/jami-android/app/src/main/java/cx/ring/account/JamiAccountSummaryFragment.kt index ebb05e61457450b777ae9211dd6b782a1711777d..6d12eafd1239ec5e073565c1189d144a4b7b0f76 100644 --- a/jami-android/app/src/main/java/cx/ring/account/JamiAccountSummaryFragment.kt +++ b/jami-android/app/src/main/java/cx/ring/account/JamiAccountSummaryFragment.kt @@ -80,6 +80,7 @@ import net.jami.model.Account import net.jami.model.Contact import net.jami.model.Profile import net.jami.services.AccountService +import net.jami.utils.VCardUtils import java.io.File import javax.inject.Inject @@ -271,7 +272,7 @@ class JamiAccountSummaryFragment : binding.username.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus: Boolean -> val name = binding.username.text if (!hasFocus) { - presenter.saveVCardFormattedName(name.toString()) + presenter.updateProfile(name.toString()) } } } @@ -343,9 +344,11 @@ class JamiAccountSummaryFragment : .setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.cancel() } .setPositiveButton(android.R.string.ok) { dialog, which -> mSourcePhoto?.let { source -> - presenter.saveVCard(mBinding!!.username.text.toString(), - Single.just(source).map { obj -> BitmapUtils.bitmapToPhoto(obj) }) - } ?: presenter.saveVCard(mBinding!!.username.text.toString(), null) + Single.just(source).map { BitmapUtils.bitmapToBase64(it)!! } + .observeOn(Schedulers.computation()) + .subscribe({ presenter.updateProfile(mBinding!!.username.text.toString(), it, "PNG") }) + { e -> Log.e(TAG, "Error updating profile", e) } + } ?: presenter.updateProfile(mBinding!!.username.text.toString(), "", "") } .setOnDismissListener { dialogDisposableBag.dispose() diff --git a/jami-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.kt b/jami-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.kt index 4a0846169bfa02c86b0d25c4b252ff3d1b5b45be..70675a81af2ee73fd4f9f7cdaec8ff4202cb465a 100644 --- a/jami-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.kt +++ b/jami-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.kt @@ -17,6 +17,7 @@ package cx.ring.tv.account import android.content.Intent +import android.graphics.Bitmap import android.os.Build import android.os.Bundle import android.widget.Toast @@ -29,16 +30,13 @@ import cx.ring.account.AccountCreationViewModel import cx.ring.application.JamiApplication import cx.ring.databinding.ItemProgressDialogBinding import cx.ring.mvp.BaseActivity -import cx.ring.services.VCardServiceImpl +import cx.ring.utils.BitmapUtils import dagger.hilt.android.AndroidEntryPoint -import ezvcard.VCard -import io.reactivex.rxjava3.core.Single -import io.reactivex.rxjava3.schedulers.Schedulers import net.jami.account.AccountWizardPresenter import net.jami.account.AccountWizardView import net.jami.model.Account import net.jami.model.AccountConfig -import net.jami.utils.VCardUtils +import net.jami.model.AccountCreationModel @AndroidEntryPoint class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardView { @@ -165,16 +163,14 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie } } - override fun saveProfile(account: Account): Single<VCard> { - val filedir = filesDir + override fun saveProfile(account: Account){ val model: AccountCreationViewModel by viewModels() - return model.model.toVCard() - .flatMap { vcard -> - account.loadedProfile = - Single.fromCallable { VCardServiceImpl.readData(vcard) }.cache() - VCardUtils.saveLocalProfileToDisk(vcard, account.accountId, filedir) - } - .subscribeOn(Schedulers.io()) + val base64img = BitmapUtils.bitmapToBase64(model.model.photo as? Bitmap) + if (base64img != null) { + presenter.updateProfile(account.accountId, model.model.fullName, base64img, "PNG") + } else { + presenter.updateProfile(account.accountId, model.model.fullName, "", "") + } } override fun displayGenericError() { diff --git a/jami-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.kt b/jami-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.kt index 06f4496885405f56579f3af896f846b26177c6e4..06022db504f8e0d838fa50193db91526b509ef62 100644 --- a/jami-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.kt +++ b/jami-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.kt @@ -21,11 +21,11 @@ import androidx.fragment.app.activityViewModels import androidx.leanback.widget.GuidanceStylist.Guidance import androidx.leanback.widget.GuidedAction import cx.ring.R -import cx.ring.account.AccountCreationModelImpl import cx.ring.account.AccountCreationViewModel import dagger.hilt.android.AndroidEntryPoint import net.jami.account.HomeAccountCreationPresenter import net.jami.account.HomeAccountCreationView +import net.jami.model.AccountCreationModel @AndroidEntryPoint class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreationPresenter, HomeAccountCreationView>(), @@ -33,21 +33,21 @@ class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreation private val model: AccountCreationViewModel by activityViewModels() override fun goToAccountCreation() { - model.model = AccountCreationModelImpl().apply { + model.model = AccountCreationModel().apply { isLink = false } add(parentFragmentManager, TVJamiAccountCreationFragment()) } override fun goToAccountLink() { - model.model = AccountCreationModelImpl().apply { + model.model = AccountCreationModel().apply { isLink = true } add(parentFragmentManager, TVJamiLinkAccountFragment()) } override fun goToAccountConnect() { - model.model = AccountCreationModelImpl().apply { + model.model = AccountCreationModel().apply { isLink = true } add(parentFragmentManager, TVJamiAccountConnectFragment()) diff --git a/jami-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.kt b/jami-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.kt index 3e641ff1c8acb831383f23b47a3300a79a97abd4..a6eb0419b877fc7602e5bba359625b5d5d9cbf4d 100644 --- a/jami-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.kt +++ b/jami-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.kt @@ -19,7 +19,6 @@ package cx.ring.tv.account import android.Manifest import android.app.Activity import android.content.Intent -import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri import android.os.Bundle @@ -35,12 +34,13 @@ import cx.ring.account.ProfileCreationFragment import cx.ring.tv.camera.CustomCameraActivity import cx.ring.utils.AndroidFileUtils import cx.ring.utils.BitmapUtils +import cx.ring.utils.ContentUri.getUri import cx.ring.views.AvatarDrawable import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.core.Single import net.jami.navigation.HomeNavigationPresenter import net.jami.navigation.HomeNavigationView import net.jami.navigation.HomeNavigationViewModel +import net.jami.utils.VCardUtils @AndroidEntryPoint class TVProfileEditingFragment : JamiGuidedStepFragment<HomeNavigationPresenter, HomeNavigationView>(), HomeNavigationView { @@ -49,8 +49,7 @@ class TVProfileEditingFragment : JamiGuidedStepFragment<HomeNavigationPresenter, private val pickProfilePicture = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> if (uri != null) - presenter.saveVCardPhoto(AndroidFileUtils.loadBitmap(requireContext(), uri) - .map { BitmapUtils.bitmapToPhoto(it) }) + setProfilePicture(uri) } private val requestCameraPermission = @@ -68,12 +67,8 @@ class TVProfileEditingFragment : JamiGuidedStepFragment<HomeNavigationPresenter, Log.e(TAG, "onActivityResult: Not able to get picture from extra") return } - val uri = extras[MediaStore.EXTRA_OUTPUT] as Uri? - if (uri != null) { - val cr = requireContext().contentResolver - presenter.saveVCardPhoto(Single.fromCallable { - cr.openInputStream(uri).use { BitmapFactory.decodeStream(it) } - }.map { obj: Bitmap -> BitmapUtils.bitmapToPhoto(obj) }) + extras.getUri(MediaStore.EXTRA_OUTPUT)?.let { + setProfilePicture(it) } } else -> { @@ -81,6 +76,23 @@ class TVProfileEditingFragment : JamiGuidedStepFragment<HomeNavigationPresenter, } } + private fun setProfilePicture(uri: Uri) { + val displayName = getCurrentDisplayname() ?: "" + AndroidFileUtils.getCacheFile(requireContext(), uri) + .subscribe({ file -> + val fileType = VCardUtils.pictureTypeFromMime(AndroidFileUtils.getMimeType(requireContext().contentResolver, uri)) + presenter.updateProfile(displayName, file, fileType) + }) { + presenter.updateProfile(displayName) + } + } + + private fun getCurrentDisplayname(): String? { + val usernameAction = actions.find { it.id == USER_NAME } + return usernameAction?.editTitle?.toString() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) iconSize = resources.getDimension(R.dimen.tv_avatar_size).toInt() @@ -104,7 +116,7 @@ class TVProfileEditingFragment : JamiGuidedStepFragment<HomeNavigationPresenter, override fun onGuidedActionEditedAndProceed(action: GuidedAction): Long { when (action.id) { - USER_NAME -> presenter.saveVCardFormattedName(action.editTitle.toString()) + USER_NAME -> presenter.updateProfile(action.editTitle.toString()) CAMERA -> presenter.cameraClicked() GALLERY -> presenter.galleryClicked() } @@ -142,8 +154,6 @@ class TVProfileEditingFragment : JamiGuidedStepFragment<HomeNavigationPresenter, startActivityForResult(Intent(activity, CustomCameraActivity::class.java), ProfileCreationFragment.REQUEST_CODE_PHOTO) } - - override fun askCameraPermission() { requestCameraPermission.launch(Manifest.permission.CAMERA) } diff --git a/jami-android/app/src/main/java/cx/ring/utils/BitmapUtils.kt b/jami-android/app/src/main/java/cx/ring/utils/BitmapUtils.kt index 4b11860daff4687ed44dd5973a498b3abbd4838c..8639fe9acc4e6d9257952dd8b23e1fd72f967834 100644 --- a/jami-android/app/src/main/java/cx/ring/utils/BitmapUtils.kt +++ b/jami-android/app/src/main/java/cx/ring/utils/BitmapUtils.kt @@ -58,6 +58,19 @@ object BitmapUtils { null } + fun bitmapToBase64(bitmap: Bitmap?): String? { + if (bitmap == null) return null + return try { + val byteArrayOutputStream = ByteArrayOutputStream() + bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream) + val byteArray = byteArrayOutputStream.toByteArray() + Base64.encodeToString(byteArray, Base64.NO_WRAP) + } catch (e: Exception) { + Log.e(TAG, "Error converting Bitmap to Base64", e) + null + } + } + fun bytesToBitmap(imageData: ByteArray?): Bitmap? = if (imageData != null && imageData.isNotEmpty()) { BitmapFactory.decodeByteArray(imageData, 0, imageData.size) } else null diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/account/AccountWizardPresenter.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/account/AccountWizardPresenter.kt index 942a7018eb1c2405b103506b79c83869940b9735..2c253348e3269ec22d705e910e08824e8805145d 100644 --- a/jami-android/libjamiclient/src/main/kotlin/net/jami/account/AccountWizardPresenter.kt +++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/account/AccountWizardPresenter.kt @@ -210,8 +210,8 @@ class AccountWizardPresenter @Inject constructor( } .firstOrError() if (saveProfile) { - newAccount = newAccount.flatMap { a: Account -> - view!!.saveProfile(a).map { a } + newAccount = newAccount.doOnSuccess { account -> + view!!.saveProfile(account) } } mCompositeDisposable.add(newAccount @@ -238,6 +238,10 @@ class AccountWizardPresenter @Inject constructor( }) } + fun updateProfile(accountId:String, displayName: String, avatar: String, fileType: String) { + mAccountService.updateProfile(accountId, displayName, avatar, fileType) + } + fun errorDialogClosed() { view!!.goToHomeCreation() } diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/account/AccountWizardView.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/account/AccountWizardView.kt index cd06bc4d2ab834cd768f1ef9f2314170cfe563ee..7a5ce22d40a785d5c200a5ecbe2f6d68eaed8a5d 100644 --- a/jami-android/libjamiclient/src/main/kotlin/net/jami/account/AccountWizardView.kt +++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/account/AccountWizardView.kt @@ -28,7 +28,7 @@ interface AccountWizardView { fun displayCreationError() fun blockOrientation() fun finish(affinity: Boolean) - fun saveProfile(account: Account): Single<VCard> + fun saveProfile(account: Account) fun displayGenericError() fun displayNetworkError() fun displayCannotBeFoundError() diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/account/JamiAccountSummaryPresenter.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/account/JamiAccountSummaryPresenter.kt index d4053e6df0433edf72b297ac079853e9637b6afe..c1e65e1152de62bbe616fc507ce0d19f77004ac0 100644 --- a/jami-android/libjamiclient/src/main/kotlin/net/jami/account/JamiAccountSummaryPresenter.kt +++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/account/JamiAccountSummaryPresenter.kt @@ -16,13 +16,7 @@ */ package net.jami.account -import ezvcard.VCard -import ezvcard.property.Photo -import ezvcard.property.RawProperty -import ezvcard.property.Uid import io.reactivex.rxjava3.core.Scheduler -import io.reactivex.rxjava3.core.Single -import io.reactivex.rxjava3.schedulers.Schedulers import net.jami.model.Account import net.jami.mvp.RootPresenter import net.jami.services.AccountService @@ -30,7 +24,6 @@ import net.jami.services.DeviceRuntimeService import net.jami.services.HardwareService import net.jami.services.VCardService import net.jami.utils.Log -import net.jami.utils.VCardUtils import java.io.File import java.net.SocketException import javax.inject.Inject @@ -40,7 +33,6 @@ class JamiAccountSummaryPresenter @Inject constructor( private val mAccountService: AccountService, private val mDeviceRuntimeService: DeviceRuntimeService, private val mHardwareService: HardwareService, - private val mVcardService: VCardService, @param:Named("UiScheduler") private val mUiScheduler: Scheduler ) : RootPresenter<JamiAccountSummaryView>() { private var mAccountID: String? = null @@ -107,75 +99,12 @@ class JamiAccountSummaryPresenter @Inject constructor( { view?.passwordChangeEnded(accountId, false) }) } - fun saveVCardFormattedName(username: String?) { + fun updateProfile(displayName: String, avatar: String? = null, fileType: String = "") { val accountId = mAccountID ?: return - val account = mAccountService.getAccount(accountId) - val filesDir = mDeviceRuntimeService.provideFilesDir() - mCompositeDisposable.add(VCardUtils.loadLocalProfileFromDiskWithDefault(filesDir, accountId) - .doOnSuccess { vcard: VCard -> - val previousName = vcard.formattedName?.value - if ((previousName.isNullOrEmpty() && username.isNullOrEmpty()) || previousName == username) - throw IllegalArgumentException("Name didn't change") - vcard.setFormattedName(username) - vcard.removeProperties(RawProperty::class.java) - account?.loadedProfile = mVcardService.loadVCardProfile(vcard).cache() - } - .flatMap { vcard: VCard -> VCardUtils.saveLocalProfileToDisk(vcard, accountId, filesDir) } - .subscribeOn(Schedulers.io()) - .subscribe({}) { e: Throwable -> Log.e(TAG, "Error saving vCard " + e.message) }) - } - - /** - * Save the vCard to the disk. - * @param username: the username to save, if null, the username will be removed from the vCard - * @param photo: the photo to save, if null, the photo will be removed from the vCard - */ - fun saveVCard(username: String?, photo: Single<Photo>?) { - val accountId = mAccountID ?: return - val account = mAccountService.getAccount(accountId)!! - val ringId = account.username - val filesDir = mDeviceRuntimeService.provideFilesDir() - - if (photo == null) { - mCompositeDisposable.add( - VCardUtils.loadLocalProfileFromDiskWithDefault(filesDir, accountId) - .subscribeOn(Schedulers.io()) - .map { vcard: VCard -> - vcard.uid = Uid(ringId) - if (!username.isNullOrEmpty()) vcard.setFormattedName(username) - vcard.removeProperties(Photo::class.java) - vcard.removeProperties(RawProperty::class.java) - vcard - } - .flatMap { vcard: VCard -> - VCardUtils.saveLocalProfileToDisk(vcard, accountId, filesDir) - } - .subscribe({ vcard: VCard -> - account.loadedProfile = mVcardService.loadVCardProfile(vcard).cache() - }) { e: Throwable -> Log.e(TAG, "Error saving vCard !", e) } - ) - } else { - mCompositeDisposable.add( - Single.zip( - VCardUtils.loadLocalProfileFromDiskWithDefault(filesDir, accountId) - .subscribeOn(Schedulers.io()), - photo - ) { vcard: VCard, pic: Photo -> - vcard.uid = Uid(ringId) - if (!username.isNullOrEmpty()) vcard.setFormattedName(username) - vcard.removeProperties(Photo::class.java) - vcard.addPhoto(pic) - vcard.removeProperties(RawProperty::class.java) - vcard - } - .flatMap { vcard: VCard -> - VCardUtils.saveLocalProfileToDisk(vcard, accountId, filesDir) - } - .subscribeOn(Schedulers.io()) - .subscribe({ vcard: VCard -> - account.loadedProfile = mVcardService.loadVCardProfile(vcard).cache() - }) { e: Throwable -> Log.e(TAG, "Error saving vCard !", e) }) - } + if (avatar == null) + mAccountService.updateProfile(accountId, displayName) + else + mAccountService.updateProfile(accountId, displayName, avatar, fileType) } fun cameraClicked() { diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/model/AccountCreationModel.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/model/AccountCreationModel.kt index fd7058d2a8e6230166585aae79851cdb3a07efef..448e5158d17ad6ff9d2bc956979c665691b8112b 100644 --- a/jami-android/libjamiclient/src/main/kotlin/net/jami/model/AccountCreationModel.kt +++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/model/AccountCreationModel.kt @@ -23,7 +23,7 @@ import io.reactivex.rxjava3.subjects.BehaviorSubject import io.reactivex.rxjava3.subjects.Subject import java.io.File -abstract class AccountCreationModel { +class AccountCreationModel { var managementServer: String? = null var username = "" var password = "" @@ -57,8 +57,6 @@ abstract class AccountCreationModel { field = pin.uppercase() } - abstract fun toVCard(): Single<VCard> - val profileUpdates: Observable<AccountCreationModel> get() = profile } diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/navigation/HomeNavigationPresenter.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/navigation/HomeNavigationPresenter.kt index aee60c4f49d571f36d78bb3151f015d22b352807..d4fabd255bba21d082a2d788bddb53977ff0edc7 100644 --- a/jami-android/libjamiclient/src/main/kotlin/net/jami/navigation/HomeNavigationPresenter.kt +++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/navigation/HomeNavigationPresenter.kt @@ -16,21 +16,14 @@ */ package net.jami.navigation -import ezvcard.VCard -import ezvcard.property.Photo -import ezvcard.property.RawProperty -import ezvcard.property.Uid import io.reactivex.rxjava3.core.Scheduler -import io.reactivex.rxjava3.core.Single -import io.reactivex.rxjava3.schedulers.Schedulers -import net.jami.model.Account import net.jami.mvp.RootPresenter import net.jami.services.AccountService import net.jami.services.DeviceRuntimeService import net.jami.services.HardwareService import net.jami.services.VCardService import net.jami.utils.Log -import net.jami.utils.VCardUtils +import java.io.File import javax.inject.Inject import javax.inject.Named @@ -52,75 +45,6 @@ class HomeNavigationPresenter @Inject constructor( }) { e: Throwable -> Log.e(TAG, "Error loading account list !", e) }) } - fun saveVCardPhoto(photo: Single<Photo>) { - val account = mAccountService.currentAccount!! - val accountId = account.accountId - val ringId = account.username - val filesDir = mDeviceRuntimeService.provideFilesDir() - mCompositeDisposable.add(Single.zip( - VCardUtils.loadLocalProfileFromDiskWithDefault(filesDir, accountId).subscribeOn(Schedulers.io()), - photo.subscribeOn(Schedulers.io()) - ) { vcard: VCard, pic: Photo -> - vcard.apply { - uid = Uid(ringId) - removeProperties(Photo::class.java) - addPhoto(pic) - removeProperties(RawProperty::class.java) - } - } - .subscribeOn(Schedulers.io()) - .subscribe({ vcard -> - account.loadedProfile = mVCardService.loadVCardProfile(vcard).cache() - VCardUtils.saveLocalProfileToDisk(vcard, accountId, filesDir) - .subscribeOn(Schedulers.io()) - .subscribe() - }) { e: Throwable -> Log.e(TAG, "Error saving vCard !", e) }) - } - - fun saveVCardFormattedName(username: String?) { - val account = mAccountService.currentAccount!! - val accountId = account.accountId - val filesDir = mDeviceRuntimeService.provideFilesDir() - mCompositeDisposable.add(VCardUtils.loadLocalProfileFromDiskWithDefault(filesDir, accountId) - .doOnSuccess { vcard: VCard -> - vcard.setFormattedName(username) - vcard.removeProperties(RawProperty::class.java) - } - .subscribeOn(Schedulers.io()) - .subscribe({ vcard -> - account.loadedProfile = mVCardService.loadVCardProfile(vcard).cache() - VCardUtils.saveLocalProfileToDisk(vcard, accountId, filesDir) - .subscribeOn(Schedulers.io()) - .subscribe() - }) { e: Throwable -> Log.e(TAG, "Error saving vCard !", e) }) - } - - fun saveVCard(account: Account, username: String?, photo: Single<Photo>) { - val accountId = account.accountId - val ringId = account.username - val filesDir = mDeviceRuntimeService.provideFilesDir() - mCompositeDisposable.add(Single.zip( - VCardUtils.loadLocalProfileFromDiskWithDefault(filesDir, accountId).subscribeOn(Schedulers.io()), - photo - ) { vcard: VCard, pic: Photo -> - vcard.uid = Uid(ringId) - if (!username.isNullOrEmpty()) { - vcard.setFormattedName(username) - } - vcard.removeProperties(Photo::class.java) - vcard.addPhoto(pic) - vcard.removeProperties(RawProperty::class.java) - account.loadedProfile = mVCardService.loadVCardProfile(vcard).cache() - vcard - } - .flatMap { vcard -> VCardUtils.saveLocalProfileToDisk(vcard, accountId, filesDir) } - .subscribeOn(Schedulers.io()) - .subscribe({}) { e: Throwable -> Log.e(TAG, "Error saving vCard !", e) }) - } - - fun getUri(account: Account, defaultNameSip: CharSequence): String? = - if (account.isIP2IP) defaultNameSip.toString() else account.displayUri - fun cameraClicked() { if (mDeviceRuntimeService.hasVideoPermission()) view?.gotToImageCapture() @@ -132,6 +56,18 @@ class HomeNavigationPresenter @Inject constructor( view?.goToGallery() } + fun updateProfile(displayName: String, avatar: String? = null, fileType: String = "") { + val account = mAccountService.currentAccount ?: return + if (avatar == null) + mAccountService.updateProfile(account.accountId, displayName, "", "") + else + mAccountService.updateProfile(account.accountId, displayName, avatar, fileType) + } + fun updateProfile(displayName: String, avatar: File, fileType: String) { + val account = mAccountService.currentAccount ?: return + mAccountService.updateProfile(account.accountId, displayName, avatar, fileType) + } + fun cameraPermissionChanged(isGranted: Boolean) { if (isGranted && mHardwareService.isVideoAvailable) { mHardwareService.initVideo() diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt index 704892793dca330290ff8c9dd30d68e61832efb0..a93648410247db8bb0b4e7a7ba69408f13592e23 100644 --- a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt +++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt @@ -610,6 +610,16 @@ class AccountService( mHistoryService.clearHistory(accountId).subscribe() } + fun updateProfile(accountId: String, displayName: String, avatarBase64: String, fileType: String) { + JamiService.updateProfile(accountId, displayName, avatarBase64, fileType, if (avatarBase64.isEmpty()) 2 else 1) + } + fun updateProfile(accountId: String, displayName: String, avatarPath: File, fileType: String) { + JamiService.updateProfile(accountId, displayName, avatarPath.absolutePath, fileType, 0) + } + fun updateProfile(accountId: String, displayName: String) { + JamiService.updateProfile(accountId, displayName, "", "", 0) + } + /** * Exports the account on the DHT (used for multi-devices feature) */ diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/utils/VCardUtils.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/utils/VCardUtils.kt index e6c7f8a56f4d7cf52d3b4a2210ddfdc321794e54..659cfe50538ab7bd991d2ba341d190ffac55b8f1 100644 --- a/jami-android/libjamiclient/src/main/kotlin/net/jami/utils/VCardUtils.kt +++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/utils/VCardUtils.kt @@ -37,10 +37,7 @@ import java.util.HashMap object VCardUtils { val TAG = VCardUtils::class.simpleName!! - const val MIME_PROFILE_VCARD = "x-ring/ring.profile.vcard" const val VCARD_KEY_MIME_TYPE = "mimeType" - const val VCARD_KEY_PART = "part" - const val VCARD_KEY_OF = "of" const val LOCAL_USER_VCARD_NAME = "profile.vcf" private const val VCARD_MAX_SIZE = 1024L * 1024L * 8 @@ -131,6 +128,14 @@ object VCardUtils { } } + fun pictureTypeFromMime(mimeType: String?): String = + when (mimeType?.lowercase()) { + null -> "" + "image/jpeg" -> "JPEG" + "image/png" -> "PNG" + else -> "JPEG" + } + @Throws(IOException::class) fun loadPeerProfileFromDisk(filesDir: File, cacheDir: File, filename: String, accountId: String): Pair<String?, ByteArray?> { val cacheFolder = peerProfileCachePath(cacheDir, accountId)