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 22a922debda72dcf31c4ac1f6185e9e83f84d59d..4a0846169bfa02c86b0d25c4b252ff3d1b5b45be 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 @@ -46,6 +46,7 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie private var mLinkAccount = false private var mAccountType: String? = null private var mAlertDialog: AlertDialog? = null + private var mJamsAccount = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -61,7 +62,11 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie mAccountType = AccountConfig.ACCOUNT_TYPE_JAMI } if (savedInstanceState == null) { - GuidedStepSupportFragment.addAsRoot(this, TVHomeAccountCreationFragment(), android.R.id.content) + GuidedStepSupportFragment.addAsRoot( + this, + TVHomeAccountCreationFragment(), + android.R.id.content + ) } else { mLinkAccount = savedInstanceState.getBoolean("mLinkAccount") } @@ -84,10 +89,16 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie fun createAccount() { val viewModel: AccountCreationViewModel by viewModels() val model = viewModel.model - if (model.isLink) { - presenter.initJamiAccountLink(model, getText(R.string.ring_account_default_name).toString()) + val defaultAccountName = getText(R.string.ring_account_default_name).toString() + if (!model.managementServer.isNullOrEmpty()) { + presenter.initJamiAccountConnect(model, defaultAccountName) + mJamsAccount = true + } else if (model.isLink) { + presenter.initJamiAccountLink(model, defaultAccountName) + mJamsAccount = false } else { - presenter.initJamiAccountCreation(model, getText(R.string.ring_account_default_name).toString()) + presenter.initJamiAccountCreation(model, defaultAccountName) + mJamsAccount = false } } @@ -98,12 +109,18 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie is TVProfileCreationFragment -> finish() is TVHomeAccountCreationFragment -> finishAffinity() is TVJamiAccountCreationFragment -> supportFragmentManager.popBackStack() + is TVJamiAccountConnectFragment -> supportFragmentManager.popBackStack() else -> super.onBackPressed() } } override fun goToProfileCreation() { - GuidedStepSupportFragment.add(supportFragmentManager, TVProfileCreationFragment()) + if (mJamsAccount) { + setResult(RESULT_OK, Intent()) + finish() + } else { + GuidedStepSupportFragment.add(supportFragmentManager, TVProfileCreationFragment()) + } } override fun displayProgress(display: Boolean) { @@ -124,7 +141,11 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie } override fun displayCreationError() { - Toast.makeText(this@TVAccountWizard, getString(R.string.account_creation_error), Toast.LENGTH_SHORT).show() + Toast.makeText( + this@TVAccountWizard, + getString(R.string.account_creation_error), + Toast.LENGTH_SHORT + ).show() } override fun blockOrientation() { @@ -149,7 +170,8 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie val model: AccountCreationViewModel by viewModels() return model.model.toVCard() .flatMap { vcard -> - account.loadedProfile = Single.fromCallable { VCardServiceImpl.readData(vcard) }.cache() + account.loadedProfile = + Single.fromCallable { VCardServiceImpl.readData(vcard) }.cache() VCardUtils.saveLocalProfileToDisk(vcard, account.accountId, filedir) } .subscribeOn(Schedulers.io()) @@ -178,13 +200,15 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie } override fun displayCannotBeFoundError() { - if (mAlertDialog != null && mAlertDialog!!.isShowing) { - return - } + if (mAlertDialog != null && mAlertDialog!!.isShowing) return + + val message = + if (mJamsAccount) getString(R.string.jams_account_cannot_be_found_message) + else getString(R.string.account_cannot_be_found_message) mAlertDialog = AlertDialog.Builder(this@TVAccountWizard) .setPositiveButton(android.R.string.ok, null) .setTitle(R.string.account_cannot_be_found_title) - .setMessage(R.string.account_cannot_be_found_message) + .setMessage(message) .show() } 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 4411608baac439a49c9fadc8201674ec5716f6a4..06f4496885405f56579f3af896f846b26177c6e4 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 @@ -47,7 +47,10 @@ class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreation } override fun goToAccountConnect() { - //TODO + model.model = AccountCreationModelImpl().apply { + isLink = true + } + add(parentFragmentManager, TVJamiAccountConnectFragment()) } override fun goToSIPAccountCreation() { @@ -68,12 +71,17 @@ class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreation val context = requireContext() addAction(context, actions, LINK_ACCOUNT, getString(R.string.account_link_button), "", true) addAction(context, actions, CREATE_ACCOUNT, getString(R.string.account_create_title), "", true) + addAction( + context, actions, CREATE_JAMS_ACCOUNT, + getString(R.string.account_connect_server_button), "", true + ) } override fun onGuidedActionClicked(action: GuidedAction) { when (action.id) { LINK_ACCOUNT -> presenter.clickOnLinkAccount() CREATE_ACCOUNT -> presenter.clickOnCreateAccount() + CREATE_JAMS_ACCOUNT -> presenter.clickOnConnectAccount() else -> requireActivity().finish() } } @@ -81,5 +89,6 @@ class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreation companion object { private const val LINK_ACCOUNT = 0L private const val CREATE_ACCOUNT = 1L + private const val CREATE_JAMS_ACCOUNT = 2L } } \ No newline at end of file diff --git a/jami-android/app/src/main/java/cx/ring/tv/account/TVJamiAccountConnectFragment.kt b/jami-android/app/src/main/java/cx/ring/tv/account/TVJamiAccountConnectFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..75cc1f603b08e510b6d6d4be0710ac81ac5201e4 --- /dev/null +++ b/jami-android/app/src/main/java/cx/ring/tv/account/TVJamiAccountConnectFragment.kt @@ -0,0 +1,136 @@ +/* + * 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.tv.account + +import android.graphics.Bitmap +import android.os.Bundle +import android.view.View +import androidx.fragment.app.activityViewModels +import androidx.leanback.widget.GuidanceStylist.Guidance +import androidx.leanback.widget.GuidedAction +import cx.ring.R +import cx.ring.account.AccountCreationViewModel +import dagger.hilt.android.AndroidEntryPoint +import net.jami.account.JamiAccountConnectPresenter +import net.jami.account.JamiConnectAccountView +import net.jami.utils.StringUtils.toPassword + +@AndroidEntryPoint +class TVJamiAccountConnectFragment : + JamiGuidedStepFragment<JamiAccountConnectPresenter, JamiConnectAccountView>(), + JamiConnectAccountView { + private val model: AccountCreationViewModel by activityViewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val m = model.model + presenter.init(m) + if (m.photo != null) { + guidanceStylist.iconView?.setImageBitmap(m.photo as Bitmap?) + } + } + + override fun onCreateGuidance(savedInstanceState: Bundle?): Guidance { + val title = getString(R.string.account_connect_server) + val breadcrumb = "" + val description = getString(R.string.help_credentials_enter) + val icon = requireContext().getDrawable(R.drawable.ic_contact_picture_fallback) + return Guidance(title, description, breadcrumb, icon) + } + + override fun onGuidedActionClicked(action: GuidedAction) { + when (action.id) { + CONNECT -> presenter.connectClicked() + } + } + + override fun onGuidedActionEditedAndProceed(action: GuidedAction): Long { + when (action.id) { + SERVER -> { + action.title = action.editTitle.toString() + .ifEmpty { getString(R.string.prompt_server) } + presenter.serverChanged(action.editTitle.toString()) + } + USERNAME -> { + action.title = action.editTitle.toString() + .ifEmpty { getString(R.string.account_username_label) } + presenter.usernameChanged(action.editTitle.toString()) + } + PASSWORD -> { + val description = action.editDescription.toString() + if (description.isNotEmpty()) action.description = toPassword(description) + else action.description = getString(R.string.account_enter_password) + presenter.passwordChanged(action.editDescription.toString()) + } + } + notifyActionChanged(findActionPositionById(action.id)) + return GuidedAction.ACTION_ID_NEXT + } + + override fun enableConnectButton(enable: Boolean) { + findActionPositionById(CONNECT).takeUnless { it == -1 }?.also { position -> + actions[position]?.isEnabled = enable + notifyActionChanged(position) + } + } + + override fun createAccount() { + (activity as TVAccountWizard?)?.createAccount() + } + + + override fun onCreateActions(actions: MutableList<GuidedAction>, savedInstanceState: Bundle?) { + val context = requireContext() + addEditTextAction( + context, actions, + id = SERVER, + title = R.string.prompt_server, + desc = R.string.account_enter_servername + ) + addEditTextAction( + context, actions, + id = USERNAME, + title = R.string.account_username_label, + desc = R.string.account_enter_username + ) + addPasswordAction( + context, actions, + id = PASSWORD, + title = getString(R.string.account_enter_password), + desc = "", editdesc = "" + ) + addDisabledAction( + context, actions, + id = CONNECT, + title = getString(R.string.account_connect_button), + desc = "", icon = null, next = true + ) + } + + override fun onProvideTheme(): Int = R.style.Theme_Ring_Leanback_GuidedStep_First + + override fun cancel() { + activity?.onBackPressedDispatcher?.onBackPressed() + } + + companion object { + private const val SERVER = 0L + private const val USERNAME = 1L + private const val PASSWORD = 2L + private const val CONNECT = 3L + } +} \ No newline at end of file diff --git a/jami-android/app/src/main/java/cx/ring/tv/main/MainFragment.kt b/jami-android/app/src/main/java/cx/ring/tv/main/MainFragment.kt index 0b0ac9774819e5332e48396c4fefcfd2d36831d1..c6180573cdbe4fa928d227b38db4c86931903cdf 100644 --- a/jami-android/app/src/main/java/cx/ring/tv/main/MainFragment.kt +++ b/jami-android/app/src/main/java/cx/ring/tv/main/MainFragment.kt @@ -249,6 +249,29 @@ class MainFragment : BaseBrowseFragment<MainPresenter>(), MainView { } else { mTitleView?.setAlias(address) } + val settingsAdapter = accountSettingsRow?.adapter as? ArrayObjectAdapter + if (account.hasManager()) { // Hide link device for jams account + settingsAdapter?.let { + var managementCardIndex: Int? = null + var addDeviceCardIndex: Int? = null + + for (i in 0 until it.size()) { + val card = it[i] as? IconCard + when (card?.type) { + Card.Type.ACCOUNT_EDIT_PROFILE -> managementCardIndex = i + Card.Type.ACCOUNT_ADD_DEVICE -> addDeviceCardIndex = i + else -> {} + } + } + if (addDeviceCardIndex != null) { + it.removeItems(addDeviceCardIndex, 1) + } + if (managementCardIndex != null) { + it.removeItems(managementCardIndex, 1) + } + } + } + settingsAdapter?.notifyArrayItemRangeChanged(0, settingsAdapter.size()) mTitleView?.apply { settingsButton.visibility = View.VISIBLE logoView.visibility = View.VISIBLE diff --git a/jami-android/app/src/main/res/values/strings_account.xml b/jami-android/app/src/main/res/values/strings_account.xml index 9ff10c8a316de23ae9cb93056829e212a3461146..26399727aae0680b1df67430c2286400511ef42f 100644 --- a/jami-android/app/src/main/res/values/strings_account.xml +++ b/jami-android/app/src/main/res/values/strings_account.xml @@ -213,6 +213,7 @@ along with this program; if not, write to the Free Software <string name="account_update_needed">Update needed</string> <string name="account_cannot_be_found_title">Account error</string> <string name="account_cannot_be_found_message">Unable to find account on the Jami network. Make sure it was exported on Jami from an existing device, and that provided credentials are correct.</string> + <string name="jams_account_cannot_be_found_message">An error occured while connecting the account. Please check credentials and try again.</string> <string name="account_sip_cannot_be_registered_message">You can continue with the account creation process or edit your information here. Edition is still possible later in the account settings.</string> <string name="account_no_network_title">Network error</string> <string name="account_no_network_message">A connectivity error occurred while adding Jami account to the distributed network. Check your device connectivity.</string> @@ -256,6 +257,9 @@ along with this program; if not, write to the Free Software <string name="help_credentials_enter">Enter your organisation credentials</string> <string name="help_connect_password_enter">Enter your organisation password</string> <string name="account_connect_prompt_username">Username</string> + <string name="account_connect_server">Connect to JAMS server</string> + <string name="account_enter_username">Enter username</string> + <string name="account_enter_servername">Enter server</string> <!-- Name registration --> <string name="error_username_empty">Enter a username</string>