Skip to content
Snippets Groups Projects
Commit 5b72e1cd authored by Adrien Béraud's avatar Adrien Béraud
Browse files

tv: allow to import archive

Change-Id: Ie1742017450c0c728c2ecd582b620cc602e6c4b9
parent 09d9b9eb
No related branches found
No related tags found
No related merge requests found
Showing
with 268 additions and 16 deletions
...@@ -98,6 +98,7 @@ class HomeAccountCreationFragment : ...@@ -98,6 +98,7 @@ class HomeAccountCreationFragment :
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
mCompositeDisposable.dispose()
binding = null binding = null
} }
...@@ -111,6 +112,10 @@ class HomeAccountCreationFragment : ...@@ -111,6 +112,10 @@ class HomeAccountCreationFragment :
.launch(Intent(requireContext(), LinkDeviceImportSideActivity::class.java)) .launch(Intent(requireContext(), LinkDeviceImportSideActivity::class.java))
} }
override fun goToBackupAccountLink() {
TODO("Not yet implemented")
}
override fun goToAccountConnect() { override fun goToAccountConnect() {
replaceFragmentWithSlide(JamiAccountConnectFragment(), JamiAccountConnectFragment.TAG, R.id.wizard_container) replaceFragmentWithSlide(JamiAccountConnectFragment(), JamiAccountConnectFragment.TAG, R.id.wizard_container)
} }
......
...@@ -83,6 +83,8 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie ...@@ -83,6 +83,8 @@ class TVAccountWizard : BaseActivity<AccountWizardPresenter>(), AccountWizardVie
if (!model.managementServer.isNullOrEmpty()) { if (!model.managementServer.isNullOrEmpty()) {
presenter.initJamiAccountConnect(model, defaultAccountName) presenter.initJamiAccountConnect(model, defaultAccountName)
mJamsAccount = true mJamsAccount = true
} else if (model.archive != null) {
presenter.initJamiAccountBackup(model, getText(R.string.ring_account_default_name).toString())
} else { } else {
presenter.initJamiAccountCreation(model, defaultAccountName) presenter.initJamiAccountCreation(model, defaultAccountName)
mJamsAccount = false mJamsAccount = false
......
...@@ -17,41 +17,85 @@ ...@@ -17,41 +17,85 @@
package cx.ring.tv.account package cx.ring.tv.account
import android.app.Activity import android.app.Activity
import android.app.Instrumentation
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.leanback.widget.GuidanceStylist.Guidance import androidx.leanback.widget.GuidanceStylist.Guidance
import androidx.leanback.widget.GuidedAction import androidx.leanback.widget.GuidedAction
import cx.ring.R import cx.ring.R
import cx.ring.account.AccountCreationViewModel import cx.ring.account.AccountCreationViewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import androidx.activity.result.contract.ActivityResultContracts
import com.google.android.material.snackbar.Snackbar
import cx.ring.account.HomeAccountCreationFragment
import cx.ring.account.JamiImportBackupFragment
import cx.ring.utils.AndroidFileUtils.getCacheFile
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable
import net.jami.account.HomeAccountCreationPresenter import net.jami.account.HomeAccountCreationPresenter
import net.jami.account.HomeAccountCreationView import net.jami.account.HomeAccountCreationView
import net.jami.model.AccountCreationModel import net.jami.model.AccountCreationModel
import java.io.File
@AndroidEntryPoint @AndroidEntryPoint
class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreationPresenter, HomeAccountCreationView>(), class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreationPresenter, HomeAccountCreationView>(),
HomeAccountCreationView { HomeAccountCreationView {
private val model: AccountCreationViewModel by activityViewModels() private val model: AccountCreationViewModel by activityViewModels()
private val mCompositeDisposable = CompositeDisposable()
override fun goToAccountCreation() { private val startForResult =
add(parentFragmentManager, TVJamiAccountCreationFragment()) registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
finish()
}
} }
override fun goToAccountLink() { private val selectFile = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
startActivityForResult(Intent(requireContext(), TVImportWizard::class.java), 56) Log.w(TAG, "Selected file: $uri")
if (uri == null) {
return@registerForActivityResult
}
getCacheFile(requireContext(), uri)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ file: File ->
model.model.archive = file
Log.w(TAG, "Loaded file: $file")
presenter.clickOnBackupAccountLink()
}) { e: Throwable ->
Log.e(HomeAccountCreationFragment.Companion.TAG, "Error importing archive", e)
view?.let { view ->
Snackbar.make(
view,
getString(R.string.import_archive_error),
Snackbar.LENGTH_LONG
).show()
}
}.let { mCompositeDisposable.add(it) }
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { private fun finish(){
if (requestCode == 56 && resultCode == Activity.RESULT_OK) {
activity?.finish() activity?.finish()
} }
override fun goToAccountCreation() {
add(parentFragmentManager, TVJamiAccountCreationFragment())
}
override fun goToAccountLink() {
startForResult.launch(Intent(requireContext(), TVImportWizard::class.java))
} }
override fun goToAccountConnect() { override fun goToAccountConnect() {
add(parentFragmentManager, TVJamiAccountConnectFragment()) add(parentFragmentManager, TVJamiAccountConnectFragment())
} }
override fun goToBackupAccountLink() {
Log.w(TAG, "goToBackupAccountLink")
add(parentFragmentManager, TVJamiLinkAccountFragment())
}
override fun goToSIPAccountCreation() { override fun goToSIPAccountCreation() {
//TODO //TODO
} }
...@@ -68,17 +112,16 @@ class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreation ...@@ -68,17 +112,16 @@ class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreation
override fun onCreateActions(actions: MutableList<GuidedAction>, savedInstanceState: Bundle?) { override fun onCreateActions(actions: MutableList<GuidedAction>, savedInstanceState: Bundle?) {
val context = requireContext() 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_ACCOUNT, getString(R.string.account_create_title), "", true)
addAction( addAction(context, actions, LINK_ACCOUNT, getString(R.string.account_link_device), "", true)
context, actions, CREATE_JAMS_ACCOUNT, addAction(context, actions, LINK_BACKUP_ACCOUNT, getString(R.string.account_link_archive_button), "", true)
getString(R.string.account_connect_server_button), "", true addAction(context, actions, CREATE_JAMS_ACCOUNT, getString(R.string.account_connect_server_button), "", true)
)
} }
override fun onGuidedActionClicked(action: GuidedAction) { override fun onGuidedActionClicked(action: GuidedAction) {
when (action.id) { when (action.id) {
LINK_ACCOUNT -> presenter.clickOnLinkAccount() LINK_ACCOUNT -> presenter.clickOnLinkAccount()
LINK_BACKUP_ACCOUNT -> selectFile.launch("*/*")
CREATE_ACCOUNT -> presenter.clickOnCreateAccount() CREATE_ACCOUNT -> presenter.clickOnCreateAccount()
CREATE_JAMS_ACCOUNT -> presenter.clickOnConnectAccount() CREATE_JAMS_ACCOUNT -> presenter.clickOnConnectAccount()
else -> requireActivity().finish() else -> requireActivity().finish()
...@@ -86,8 +129,13 @@ class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreation ...@@ -86,8 +129,13 @@ class TVHomeAccountCreationFragment : JamiGuidedStepFragment<HomeAccountCreation
} }
companion object { companion object {
private const val TAG = "TVHomeAccountCreationFragment"
private const val LINK_ACCOUNT = 0L private const val LINK_ACCOUNT = 0L
private const val CREATE_ACCOUNT = 1L private const val LINK_BACKUP_ACCOUNT = 1L
private const val CREATE_JAMS_ACCOUNT = 2L private const val CREATE_ACCOUNT = 2L
private const val CREATE_JAMS_ACCOUNT = 3L
private const val REQUEST_CODE_IMPORT = 56
} }
} }
\ No newline at end of file
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
*/ */
package cx.ring.tv.account package cx.ring.tv.account
import android.app.Activity
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
......
/*
* Copyright (C) 2004-2025 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.JamiLinkAccountPresenter
import net.jami.account.JamiLinkAccountView
import net.jami.utils.StringUtils.toPassword
@AndroidEntryPoint
class TVJamiLinkAccountFragment : JamiGuidedStepFragment<JamiLinkAccountPresenter, JamiLinkAccountView>(),
JamiLinkAccountView {
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 = Guidance(
getString(R.string.account_link_archive_button),
getString(R.string.help_password_enter),
"",
requireContext().getDrawable(R.drawable.ic_contact_picture_fallback)
)
override fun onCreateActions(actions: MutableList<GuidedAction>, savedInstanceState: Bundle?) {
val context = requireContext()
addPasswordAction(context, actions, PASSWORD, getString(R.string.account_enter_password), "", "")
addDisabledAction(context, actions, LINK, getString(R.string.import_side_main_title), "", null, true)
}
override fun onProvideTheme(): Int = R.style.Theme_Ring_Leanback_GuidedStep_First
override fun onGuidedActionClicked(action: GuidedAction) {
if (action.id == LINK) {
presenter.linkClicked()
}
}
override fun enableLinkButton(enable: Boolean) {
findActionPositionById(LINK).takeUnless { it == -1 }?.also { position ->
actions[position]?.isEnabled = enable
notifyActionChanged(position)
}
}
override fun showPin(show: Boolean) {}
override fun createAccount() {
(activity as TVAccountWizard?)?.createAccount()
}
override fun onGuidedActionEditedAndProceed(action: GuidedAction): Long {
val password = action.editDescription.toString()
action.description = if (password.isNotEmpty()) toPassword(password) else getString(R.string.account_enter_password)
when (action.id) {
PASSWORD -> {
notifyActionChanged(findActionPositionById(PASSWORD))
presenter.passwordChanged(password)
}
}
return GuidedAction.ACTION_ID_NEXT
}
override fun cancel() {
activity?.onBackPressedDispatcher?.onBackPressed()
}
companion object {
private const val PASSWORD = 1L
private const val LINK = 3L
}
}
\ No newline at end of file
...@@ -154,7 +154,7 @@ class AccountWizardPresenter @Inject constructor( ...@@ -154,7 +154,7 @@ class AccountWizardPresenter @Inject constructor(
mCreatingAccount = false mCreatingAccount = false
view.displayGenericError() view.displayGenericError()
} else { } else {
view.goToProfileCreation() view.finish(true)
} }
} }
}) { }) {
......
...@@ -28,6 +28,10 @@ class HomeAccountCreationPresenter @Inject constructor() : RootPresenter<HomeAcc ...@@ -28,6 +28,10 @@ class HomeAccountCreationPresenter @Inject constructor() : RootPresenter<HomeAcc
view?.goToAccountLink() view?.goToAccountLink()
} }
fun clickOnBackupAccountLink() {
view?.goToBackupAccountLink()
}
fun clickOnConnectAccount() { fun clickOnConnectAccount() {
view?.goToAccountConnect() view?.goToAccountConnect()
} }
......
...@@ -19,6 +19,7 @@ package net.jami.account ...@@ -19,6 +19,7 @@ package net.jami.account
interface HomeAccountCreationView { interface HomeAccountCreationView {
fun goToAccountCreation() fun goToAccountCreation()
fun goToAccountLink() fun goToAccountLink()
fun goToBackupAccountLink()
fun goToAccountConnect() fun goToAccountConnect()
fun goToSIPAccountCreation() fun goToSIPAccountCreation()
} }
\ No newline at end of file
/*
* Copyright (C) 2004-2025 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 net.jami.account
import net.jami.model.AccountCreationModel
import net.jami.mvp.RootPresenter
import javax.inject.Inject
class JamiLinkAccountPresenter @Inject constructor() : RootPresenter<JamiLinkAccountView>() {
private var mAccountCreationModel: AccountCreationModel? = null
fun init(accountCreationModel: AccountCreationModel?) {
mAccountCreationModel = accountCreationModel
if (mAccountCreationModel == null) {
view?.cancel()
return
}
val hasArchive = mAccountCreationModel?.archive != null
val view = view
if (view != null) {
view.showPin(!hasArchive)
view.enableLinkButton(hasArchive)
}
}
fun passwordChanged(password: String) {
mAccountCreationModel?.password = password
showHideLinkButton()
}
fun pinChanged(pin: String) {
mAccountCreationModel?.pin = pin
showHideLinkButton()
}
fun resetPin() {
mAccountCreationModel?.pin = ""
showHideLinkButton()
}
fun linkClicked() {
if (isFormValid) {
view?.createAccount()
}
}
private fun showHideLinkButton() {
view?.enableLinkButton(isFormValid)
}
private val isFormValid: Boolean
get() = mAccountCreationModel?.archive != null || mAccountCreationModel!!.pin.isNotEmpty()
}
\ No newline at end of file
/*
* Copyright (C) 2004-2025 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 net.jami.account
import net.jami.model.AccountCreationModel
interface JamiLinkAccountView {
fun enableLinkButton(enable: Boolean)
fun showPin(show: Boolean)
fun createAccount()
fun cancel()
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment