From d915e97ad27336c65eeb052455f78a4dadcb03b3 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Sun, 20 Aug 2023 20:19:57 +0200 Subject: [PATCH] Started account profile view --- .../java/org/linphone/ui/main/MainActivity.kt | 6 +- .../contacts/fragment/EditContactFragment.kt | 4 +- .../contacts/fragment/NewContactFragment.kt | 2 +- .../viewmodel/ContactNewOrEditViewModel.kt | 19 ++- .../conversations/NewConversationFragment.kt | 2 +- .../fragment/AccountProfileFragment.kt | 112 ++++++++++++++++++ .../fragment/AcocuntProfileFragment.kt | 26 ---- .../viewmodel/AccountProfileViewModel.kt | 80 +++++++++++++ .../res/layout/account_profile_fragment.xml | 107 +++++++++++++++++ .../layout/contact_new_or_edit_fragment.xml | 4 +- .../layout/conversation_start_fragment.xml | 4 +- .../main/res/navigation/main_nav_graph.xml | 10 +- 12 files changed, 323 insertions(+), 53 deletions(-) create mode 100644 app/src/main/java/org/linphone/ui/main/settings/fragment/AccountProfileFragment.kt delete mode 100644 app/src/main/java/org/linphone/ui/main/settings/fragment/AcocuntProfileFragment.kt create mode 100644 app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt diff --git a/app/src/main/java/org/linphone/ui/main/MainActivity.kt b/app/src/main/java/org/linphone/ui/main/MainActivity.kt index 95fafda02..29bfd71bf 100644 --- a/app/src/main/java/org/linphone/ui/main/MainActivity.kt +++ b/app/src/main/java/org/linphone/ui/main/MainActivity.kt @@ -44,7 +44,7 @@ import org.linphone.core.Account import org.linphone.databinding.AccountPopupMenuBinding import org.linphone.databinding.MainActivityBinding import org.linphone.ui.assistant.AssistantActivity -import org.linphone.ui.main.settings.fragment.AcocuntProfileFragmentDirections +import org.linphone.ui.main.settings.fragment.AccountProfileFragmentDirections import org.linphone.ui.main.viewmodel.DrawerMenuViewModel import org.linphone.utils.slideInToastFromTopForDuration @@ -212,8 +212,8 @@ class MainActivity : AppCompatActivity() { popupView.setManageProfileClickListener { val navController = findNavController(R.id.main_nav_host_fragment) - val identity = account.params.identityAddress?.asString().orEmpty() - val action = AcocuntProfileFragmentDirections.actionGlobalAcocuntProfileFragment( + val identity = account.params.identityAddress?.asStringUriOnly().orEmpty() + val action = AccountProfileFragmentDirections.actionGlobalAccountProfileFragment( identity ) navController.navigate(action) diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/EditContactFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/EditContactFragment.kt index 5d7e4588a..8a7824f39 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/EditContactFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/fragment/EditContactFragment.kt @@ -101,10 +101,10 @@ class EditContactFragment : GenericFragment() { postponeEnterTransition() val refKey = args.contactRefKey - Log.i("[Contact Edit Fragment] Looking up for contact with ref key [$refKey]") + Log.i("$TAG Looking up for contact with ref key [$refKey]") viewModel.findFriendByRefKey(refKey) - binding.setCancelClickListener { + binding.setBackClickListener { val model = ConfirmationDialogModel() val dialog = DialogUtils.getCancelContactChangesConfirmationDialog( requireActivity(), diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/NewContactFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/NewContactFragment.kt index a40d26626..84386f45d 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/NewContactFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/fragment/NewContactFragment.kt @@ -98,7 +98,7 @@ class NewContactFragment : GenericFragment() { viewModel.findFriendByRefKey("") - binding.setCancelClickListener { + binding.setBackClickListener { val model = ConfirmationDialogModel() val dialog = DialogUtils.getCancelContactChangesConfirmationDialog( requireActivity(), diff --git a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactNewOrEditViewModel.kt b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactNewOrEditViewModel.kt index de9788945..89cf11323 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactNewOrEditViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactNewOrEditViewModel.kt @@ -114,12 +114,9 @@ class ContactNewOrEditViewModel() : ViewModel() { if (!::friend.isInitialized) { friend = core.createFriend() } + friend.name = "${firstName.value.orEmpty().trim()} ${lastName.value.orEmpty().trim()}" - if (isEdit.value == true) { - friend.edit() - } - - friend.name = "${firstName.value.orEmpty()} ${lastName.value.orEmpty()}" + friend.edit() val vCard = friend.vcard if (vCard != null) { @@ -133,8 +130,8 @@ class ContactNewOrEditViewModel() : ViewModel() { } } - friend.organization = company.value.orEmpty() - friend.jobTitle = jobTitle.value.orEmpty() + friend.organization = company.value.orEmpty().trim() + friend.jobTitle = jobTitle.value.orEmpty().trim() for (address in friend.addresses) { friend.removeAddress(address) @@ -142,7 +139,7 @@ class ContactNewOrEditViewModel() : ViewModel() { for (address in sipAddresses) { val data = address.value.value if (!data.isNullOrEmpty()) { - val parsedAddress = core.interpretUrl(data, true) + val parsedAddress = core.interpretUrl(data.trim(), true) if (parsedAddress != null) { friend.addAddress(parsedAddress) } @@ -155,7 +152,7 @@ class ContactNewOrEditViewModel() : ViewModel() { for (number in phoneNumbers) { val data = number.value.value if (!data.isNullOrEmpty()) { - friend.addPhoneNumber(data) + friend.addPhoneNumber(data.trim()) } } @@ -170,9 +167,9 @@ class ContactNewOrEditViewModel() : ViewModel() { // TODO : generate unique ref key } status = core.defaultFriendList?.addFriend(friend) ?: Status.InvalidFriend - } else { - friend.done() } + + friend.done() coreContext.contactsManager.notifyContactsListChanged() saveChangesEvent.postValue( diff --git a/app/src/main/java/org/linphone/ui/main/conversations/NewConversationFragment.kt b/app/src/main/java/org/linphone/ui/main/conversations/NewConversationFragment.kt index 26115a1a4..5a41c3360 100644 --- a/app/src/main/java/org/linphone/ui/main/conversations/NewConversationFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/conversations/NewConversationFragment.kt @@ -94,7 +94,7 @@ class NewConversationFragment : Fragment() { } } - binding.setCancelClickListener { + binding.setBackClickListener { requireActivity().onBackPressedDispatcher.onBackPressed() } diff --git a/app/src/main/java/org/linphone/ui/main/settings/fragment/AccountProfileFragment.kt b/app/src/main/java/org/linphone/ui/main/settings/fragment/AccountProfileFragment.kt new file mode 100644 index 000000000..826d50f11 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/settings/fragment/AccountProfileFragment.kt @@ -0,0 +1,112 @@ +package org.linphone.ui.main.settings.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts +import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import androidx.navigation.navGraphViewModels +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.linphone.R +import org.linphone.core.tools.Log +import org.linphone.databinding.AccountProfileFragmentBinding +import org.linphone.ui.main.contacts.fragment.EditContactFragment +import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.settings.viewmodel.AccountProfileViewModel +import org.linphone.utils.FileUtils + +class AccountProfileFragment : GenericFragment() { + companion object { + const val TAG = "[Account Profile Fragment]" + } + + private lateinit var binding: AccountProfileFragmentBinding + + private val viewModel: AccountProfileViewModel by navGraphViewModels( + R.id.accountProfileFragment + ) + + private val args: AccountProfileFragmentArgs by navArgs() + + private val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> + if (uri != null) { + Log.i("$TAG Picture picked [$uri]") + // TODO FIXME: use a better file name + val localFileName = FileUtils.getFileStoragePath("temp", true) + lifecycleScope.launch { + if (FileUtils.copyFile(uri, localFileName)) { + withContext(Dispatchers.Main) { + viewModel.setImage(localFileName) + } + } else { + Log.e( + "${EditContactFragment.TAG} Failed to copy file from [$uri] to [${localFileName.absolutePath}]" + ) + } + } + } else { + Log.w("${EditContactFragment.TAG} No picture picked") + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = AccountProfileFragmentBinding.inflate(layoutInflater) + return binding.root + } + + override fun goBack() { + findNavController().popBackStack() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + postponeEnterTransition() + + binding.lifecycleOwner = viewLifecycleOwner + binding.viewModel = viewModel + + val identity = args.accountIdentity + Log.i("$TAG Looking up for account with identity address [$identity]") + viewModel.findAccountMatchingIdentity(identity) + + binding.setBackClickListener { + goBack() + } + + binding.setPickImageClickListener { + pickImage() + } + + viewModel.accountFoundEvent.observe(viewLifecycleOwner) { + it.consume { found -> + if (found) { + startPostponedEnterTransition() + } else { + // TODO Error + goBack() + } + } + } + } + + override fun onPause() { + super.onPause() + + viewModel.saveDisplayNameChanges() + } + + private fun pickImage() { + pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) + } +} diff --git a/app/src/main/java/org/linphone/ui/main/settings/fragment/AcocuntProfileFragment.kt b/app/src/main/java/org/linphone/ui/main/settings/fragment/AcocuntProfileFragment.kt deleted file mode 100644 index c8d04fc25..000000000 --- a/app/src/main/java/org/linphone/ui/main/settings/fragment/AcocuntProfileFragment.kt +++ /dev/null @@ -1,26 +0,0 @@ -package org.linphone.ui.main.settings.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import org.linphone.databinding.AccountProfileFragmentBinding -import org.linphone.ui.main.fragment.GenericFragment - -class AcocuntProfileFragment : GenericFragment() { - private lateinit var binding: AccountProfileFragmentBinding - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - binding = AccountProfileFragmentBinding.inflate(layoutInflater) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.lifecycleOwner = viewLifecycleOwner - } -} diff --git a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt new file mode 100644 index 000000000..bd54e1293 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt @@ -0,0 +1,80 @@ +package org.linphone.ui.main.settings.viewmodel + +import androidx.annotation.UiThread +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import java.io.File +import org.linphone.LinphoneApplication.Companion.coreContext +import org.linphone.core.Account +import org.linphone.utils.Event + +class AccountProfileViewModel : ViewModel() { + val picturePath = MutableLiveData() + + val displayName = MutableLiveData() + + val accountFoundEvent = MutableLiveData>() + + private lateinit var account: Account + + @UiThread + fun findAccountMatchingIdentity(identity: String) { + coreContext.postOnCoreThread { core -> + val found = core.accountList.find { + it.params.identityAddress?.asStringUriOnly() == identity + } + if (found != null) { + account = found + displayName.postValue(account.params.identityAddress?.displayName) + + val friend = coreContext.contactsManager.localFriends.find { + it.addresses.find { address -> + address.asStringUriOnly() == identity + } != null + } + if (friend != null) { + picturePath.postValue(friend.photo) + } else { + // TODO + } + accountFoundEvent.postValue(Event(true)) + } else { + accountFoundEvent.postValue(Event(false)) + } + } + } + + @UiThread + fun saveDisplayNameChanges() { + coreContext.postOnCoreThread { + if (::account.isInitialized) { + val params = account.params + val copy = params.clone() + val address = params.identityAddress + address?.displayName = displayName.value.orEmpty().trim() + copy.identityAddress = address + account.params = copy + } + } + } + + @UiThread + fun setImage(file: File) { + val path = file.absolutePath + picturePath.value = path + coreContext.postOnCoreThread { + if (::account.isInitialized) { + val friend = coreContext.contactsManager.localFriends.find { + it.addresses.find { address -> + address.asStringUriOnly() == account.params.identityAddress?.asStringUriOnly() + } != null + } + if (friend != null) { + friend.edit() + friend.photo = path + friend.done() + } + } + } + } +} diff --git a/app/src/main/res/layout/account_profile_fragment.xml b/app/src/main/res/layout/account_profile_fragment.xml index f1e8f3c96..c4864c5a0 100644 --- a/app/src/main/res/layout/account_profile_fragment.xml +++ b/app/src/main/res/layout/account_profile_fragment.xml @@ -5,6 +5,15 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/contact_new_or_edit_fragment.xml b/app/src/main/res/layout/contact_new_or_edit_fragment.xml index 5113ec1e4..35a60926c 100644 --- a/app/src/main/res/layout/contact_new_or_edit_fragment.xml +++ b/app/src/main/res/layout/contact_new_or_edit_fragment.xml @@ -6,7 +6,7 @@ + android:id="@+id/action_global_accountProfileFragment" + app:destination="@id/accountProfileFragment" />