Skip to content
Snippets Groups Projects
Commit 353df454 authored by Pavan Koushik Nellore's avatar Pavan Koushik Nellore Committed by Adrien Béraud
Browse files

tv: Add account export wizard

Implement TV-specific fragments and
activity to handle account export flow.

Change-Id: If05a7a9145dac2a24694284914e0a94502a3489f
parent 9b03a3e7
No related branches found
No related tags found
No related merge requests found
...@@ -383,6 +383,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -383,6 +383,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:exported="false" android:exported="false"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
<activity
android:name=".tv.account.TVExportWizard"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:exported="false"
android:theme="@style/AppTheme" />
<activity <activity
android:name=".tv.search.SearchActivity" android:name=".tv.search.SearchActivity"
android:exported="false" android:exported="false"
......
/*
* 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.app.AlertDialog
import android.app.DownloadManager
import android.content.Context
import android.os.Bundle
import android.view.View
import androidx.leanback.widget.GuidanceStylist.Guidance
import androidx.leanback.widget.GuidedAction
import cx.ring.R
import cx.ring.databinding.ItemProgressDialogBinding
import cx.ring.utils.AndroidFileUtils.getMimeType
import dagger.hilt.android.AndroidEntryPoint
import net.jami.account.JamiAccountSummaryPresenter
import net.jami.account.JamiAccountSummaryView
import net.jami.model.Account
import net.jami.model.Profile
import java.io.File
@AndroidEntryPoint
class TVAccountExport : JamiGuidedStepFragment<JamiAccountSummaryPresenter, JamiAccountSummaryView>(), JamiAccountSummaryView {
private var mWaitDialog: AlertDialog? = null
private lateinit var mIdAccount: String
private var mHasPassword = false
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter.setAccountId(mIdAccount)
}
override fun onCreateGuidance(savedInstanceState: Bundle?): Guidance {
// Todo: finish to clean up.
val title = getString(R.string.account_export_title)
val breadcrumb = ""
val icon = requireContext().getDrawable(R.drawable.baseline_devices_24)
return Guidance(title, null, breadcrumb, icon)
}
override fun onCreateActions(actions: MutableList<GuidedAction>, savedInstanceState: Bundle?) {
val context = requireContext()
// Todo: finish to clean up.
// if (mHasPassword) {
// addPasswordAction(context, actions, PASSWORD, getString(R.string.account_enter_password), "", "")
// } else {
addAction(context, actions, ACTION, R.string.account_start_export_button)
// }
}
override fun onGuidedActionClicked(action: GuidedAction) {
// Todo: finish to clean up.
// presenter.startAccountExport("")
}
override fun onGuidedActionEditedAndProceed(action: GuidedAction): Long {
// Todo: finish to clean up.
// presenter.startAccountExport(action.description.toString())
return GuidedAction.ACTION_ID_NEXT
}
override fun onProvideTheme(): Int {
return R.style.Theme_Ring_Leanback_GuidedStep_First
}
override fun showExportingProgressDialog() {
mWaitDialog = AlertDialog.Builder(requireActivity())
.setView(ItemProgressDialogBinding.inflate(layoutInflater).root)
.setTitle(R.string.export_account_wait_title)
.setMessage(R.string.export_account_wait_message)
.setCancelable(false)
.show()
}
override fun showPasswordProgressDialog() {}
override fun accountChanged(account: Account, profile: Profile) {}
override fun passwordChangeEnded(accountId: String, ok: Boolean, newPassword: String) {}
override fun displayCompleteArchive(dest: File) {
val downloadManager = requireContext().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
downloadManager.addCompletedDownload(
dest.name,
dest.name,
true,
getMimeType(dest.absolutePath),
dest.absolutePath,
dest.length(),
true
)
}
override fun gotToImageCapture() {}
override fun askCameraPermission() {}
override fun goToGallery() {}
override fun goToMedia(accountId: String) {}
override fun goToSystem(accountId: String) {}
override fun goToAdvanced(accountId: String) {}
override fun goToAccount(accountId: String) {}
override fun showRevokingProgressDialog() {}
override fun deviceRevocationEnded(device: String, status: Int) {}
override fun updateDeviceList(devices: Map<String, String>, currentDeviceId: String) {}
companion object {
private const val PASSWORD = 1L
private const val ACTION = 2L
fun createInstance(idAccount: String, hasPassword: Boolean): TVAccountExport =
TVAccountExport().apply {
mIdAccount = idAccount
mHasPassword = hasPassword
}
}
}
\ 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 cx.ring.tv.account
import android.os.Bundle
import android.util.Log
import android.view.*
import androidx.fragment.app.Fragment
import com.google.zxing.BarcodeFormat
import com.google.zxing.ResultPoint
import com.journeyapps.barcodescanner.BarcodeCallback
import com.journeyapps.barcodescanner.BarcodeResult
import com.journeyapps.barcodescanner.DefaultDecoderFactory
import cx.ring.R
import cx.ring.databinding.FragmentExportSideStep1Binding
import cx.ring.linkdevice.viewmodel.ExportSideInputError
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class TVAccountExportStep1Fragment : Fragment() {
private var _binding: FragmentExportSideStep1Binding? = null
private val binding get() = _binding!!
private enum class InputMode { QR, CODE }
private var currentMode = InputMode.QR
private var isLoading = false
interface OnInputCallback {
fun onAuthenticationUri(authenticationUri: String)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = FragmentExportSideStep1Binding.inflate(inflater, container, false)
.also { _binding = it }
.root
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initializeBarcode()
showInputQr()
binding.switchMode.setOnClickListener {
if (currentMode == InputMode.QR) showInputCode()
else showInputQr()
}
binding.connect.setOnClickListener {
Log.i(TAG, "Connect clicked, authentication uri = ${binding.code.text}")
showInputCode(loading = true)
(requireActivity() as OnInputCallback)
.onAuthenticationUri(binding.code.text.toString())
}
}
override fun onResume() {
super.onResume()
if (currentMode == InputMode.QR) {
binding.barcodeScanner.resume()
}
}
override fun onPause() {
super.onPause()
if (currentMode == InputMode.QR) {
binding.barcodeScanner.pause()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
fun showError(error: ExportSideInputError?) {
if (currentMode == InputMode.QR) showInputQr(error = error)
else showInputCode(error = error)
}
private fun initializeBarcode() {
binding.barcodeScanner.apply {
barcodeView.decoderFactory = DefaultDecoderFactory(listOf(BarcodeFormat.QR_CODE))
decodeContinuous(onBarcodeResult)
}
}
private fun showInputQr(loading: Boolean = false, error: ExportSideInputError? = null) {
binding.barcodeScanner.resume()
isLoading = loading
currentMode = InputMode.QR
binding.inputCode.visibility = View.INVISIBLE
binding.inputQr.visibility = View.VISIBLE
binding.switchMode.text = getText(R.string.export_side_step1_switch_to_code)
if (loading) {
binding.barcodeScanner.visibility = View.INVISIBLE
binding.loadingQr.visibility = View.VISIBLE
binding.errorQr.visibility = View.INVISIBLE
binding.switchMode.isEnabled = false
} else if (error != null) {
initializeBarcode()
binding.barcodeScanner.resume()
binding.errorQr.text = when (error) {
ExportSideInputError.INVALID_INPUT ->
getString(R.string.export_side_step1_error_malformed)
}
binding.switchMode.isEnabled = true
binding.barcodeScanner.visibility = View.VISIBLE
binding.loadingQr.visibility = View.INVISIBLE
binding.errorQr.visibility = View.VISIBLE
binding.errorQr.visibility = View.VISIBLE
} else {
binding.barcodeScanner.resume()
binding.barcodeScanner.visibility = View.VISIBLE
binding.loadingQr.visibility = View.INVISIBLE
binding.errorQr.visibility = View.INVISIBLE
binding.switchMode.isEnabled = true
}
}
private fun showInputCode(loading: Boolean = false, error: ExportSideInputError? = null) {
binding.barcodeScanner.pause()
isLoading = loading
currentMode = InputMode.CODE
binding.inputCode.visibility = View.VISIBLE
binding.inputQr.visibility = View.INVISIBLE
binding.switchMode.text = getText(R.string.export_side_step1_switch_to_qr)
binding.codeLayout.error = when (error) {
ExportSideInputError.INVALID_INPUT -> getText(R.string.export_side_step1_error_malformed)
else -> null
}
if (loading) {
binding.loadingCode.visibility = View.VISIBLE
binding.connect.isEnabled = false
binding.code.isEnabled = false
binding.switchMode.isEnabled = false
} else {
binding.connect.isEnabled = true
binding.code.isEnabled = true
binding.switchMode.isEnabled = true
binding.loadingCode.visibility = View.INVISIBLE
}
}
private val onBarcodeResult = object : BarcodeCallback {
override fun barcodeResult(result: BarcodeResult) {
if (!result.text.startsWith(SCHEME)) return
Log.i(TAG, "QR scanned: ${result.text}")
binding.barcodeScanner.pause()
binding.barcodeScanner.barcodeView.stopDecoding()
showInputQr(loading = true)
(requireActivity() as OnInputCallback).onAuthenticationUri(result.text)
}
override fun possibleResultPoints(resultPoints: List<ResultPoint>) {}
}
companion object {
private const val TAG = "TVAccountExportStep1Fragment"
const val SCHEME = "jami-auth://"
}
}
/*
* 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.os.Bundle
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ProgressBar
import androidx.leanback.app.GuidedStepSupportFragment
import androidx.leanback.widget.GuidanceStylist
import androidx.leanback.widget.GuidedAction
import androidx.leanback.widget.GuidedActionsStylist
import cx.ring.R
import cx.ring.views.AvatarDrawable
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class TVAccountExportStep2Fragment : GuidedStepSupportFragment() {
private var peerAddress: String? = null
private lateinit var progressBar: ProgressBar
interface OnReviewCallback {
fun onIdentityConfirmation(confirm: Boolean)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val rootView = super.onCreateView(inflater, container, savedInstanceState)
// Wrap GuidedStepSupportFragment view inside FrameLayout
val frameLayout = FrameLayout(requireContext()).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
// Create and add ProgressBar
progressBar = ProgressBar(requireContext()).apply {
visibility = View.GONE
isIndeterminate = true
}
frameLayout.addView(rootView)
frameLayout.addView(progressBar, FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
).apply {
gravity = Gravity.CENTER
})
return frameLayout
}
override fun onCreateGuidance(savedInstanceState: Bundle?): GuidanceStylist.Guidance {
val id = arguments?.getString(ARG_ACCOUNT_ID) ?: ""
val name = arguments?.getString(ARG_REGISTERED_NAME) ?: id
Log.d(TAG, "onCreateGuidance: id=$id, name=$name")
return GuidanceStylist.Guidance(
getString(R.string.export_side_main_title),
id,
null,
AvatarDrawable.Builder()
.withId(id)
.withName(name)
.withCircleCrop(true)
.build(requireContext())
.apply {
setInSize(resources.getDimensionPixelSize(R.dimen.tv_avatar_size))
}
)
}
override fun onCreateActionsStylist(): GuidedActionsStylist {
return TVGuidedActionsStylist()
}
override fun onCreateActions(actions: MutableList<GuidedAction>, savedInstanceState: Bundle?) {
peerAddress = arguments?.getString(ARG_PEER_ADDRESS)
val isPasswordMode = peerAddress.isNullOrEmpty()
if (isPasswordMode) {
actions.add(
GuidedAction.Builder(requireContext())
.id(ACTION_ID_PASSWORD_NOTICE)
.title(getString(R.string.export_side_step2_password))
.infoOnly(true)
.enabled(false)
.focusable(false)
.build()
)
} else {
actions.add(
GuidedAction.Builder(requireContext())
.id(ACTION_ID_PEER_IP)
.title(getString(R.string.export_side_step2_advice_ip_only))
.description(peerAddress ?: "")
.infoOnly(true)
.enabled(false)
.focusable(false)
.build()
)
}
actions.add(
GuidedAction.Builder(requireContext())
.id(GuidedAction.ACTION_ID_CONTINUE)
.title(R.string.export_side_step2_confirm)
.build()
)
actions.add(
GuidedAction.Builder(requireContext())
.id(GuidedAction.ACTION_ID_CANCEL)
.title(android.R.string.cancel)
.build()
)
}
override fun onGuidedActionClicked(action: GuidedAction) {
val callback = activity as? TVExportWizard ?: return
when (action.id) {
GuidedAction.ACTION_ID_CONTINUE -> {
showLoading()
callback.onIdentityConfirmation(true)
}
GuidedAction.ACTION_ID_CANCEL -> {
callback.onIdentityConfirmation(false)
}
}
}
private fun showLoading() {
actions.forEach { it.isEnabled = false }
setActions(actions)
(getGuidedActionsStylist() as? GuidedActionsStylist)?.actionsGridView?.apply {
animate()
.alpha(0f)
.setDuration(200)
.withEndAction { visibility = View.INVISIBLE }
.start()
}
progressBar.visibility = View.VISIBLE
}
fun update(peerAddress: String?) {
val isPasswordMode = peerAddress.isNullOrEmpty()
val isCurrentlyPasswordMode = findActionPositionById(ACTION_ID_PASSWORD_NOTICE) != -1
val isCurrentlyIPMode = findActionPositionById(ACTION_ID_PEER_IP) != -1
if (isPasswordMode && !isCurrentlyPasswordMode) {
actions.clear()
setupPasswordModeActions()
} else if (!isPasswordMode && !isCurrentlyIPMode) {
actions.clear()
setupIPModeActions(peerAddress)
} else if (!isPasswordMode && isCurrentlyIPMode) {
val ipIndex = findActionPositionById(ACTION_ID_PEER_IP)
if (ipIndex != -1) {
actions[ipIndex].description = peerAddress
notifyActionChanged(ipIndex)
}
}
}
private fun setupPasswordModeActions() {
actions.add(
GuidedAction.Builder(requireContext())
.id(ACTION_ID_PASSWORD_NOTICE)
.title(getString(R.string.export_side_step2_password))
.infoOnly(true)
.enabled(false)
.focusable(false)
.build()
)
actions.add(
GuidedAction.Builder(requireContext())
.id(GuidedAction.ACTION_ID_CONTINUE)
.title(R.string.export_side_step2_confirm)
.enabled(true)
.build()
)
actions.add(
GuidedAction.Builder(requireContext())
.id(GuidedAction.ACTION_ID_CANCEL)
.title(android.R.string.cancel)
.build()
)
setActions(actions)
}
private fun setupIPModeActions(peerAddress: String?) {
actions.add(
GuidedAction.Builder(requireContext())
.id(ACTION_ID_PEER_IP)
.title(getString(R.string.export_side_step2_advice_ip_only))
.description(peerAddress ?: "")
.infoOnly(true)
.enabled(false)
.focusable(false)
.build()
)
actions.add(
GuidedAction.Builder(requireContext())
.id(GuidedAction.ACTION_ID_CONTINUE)
.title(R.string.export_side_step2_confirm)
.enabled(true)
.build()
)
actions.add(
GuidedAction.Builder(requireContext())
.id(GuidedAction.ACTION_ID_CANCEL)
.title(android.R.string.cancel)
.build()
)
setActions(actions)
}
override fun onProvideTheme(): Int = R.style.Theme_Ring_Leanback_GuidedStep_First
companion object {
private const val TAG = "TVAccountExportStep2Fragment"
private const val ACTION_ID_PASSWORD_NOTICE = 1L
private const val ACTION_ID_PEER_IP = 2L
private const val ARG_PEER_ADDRESS = "peerAddress"
private const val ARG_ACCOUNT_ID = "accountId"
private const val ARG_REGISTERED_NAME = "registeredName"
fun build(
peerAddress: String?, accountId: String, registeredName: String
): TVAccountExportStep2Fragment {
return TVAccountExportStep2Fragment().apply {
arguments = Bundle().apply {
putString(ARG_PEER_ADDRESS, peerAddress)
putString(ARG_ACCOUNT_ID, accountId)
putString(ARG_REGISTERED_NAME, registeredName)
}
}
}
}
}
class TVGuidedActionsStylist : GuidedActionsStylist() {
override fun onBindViewHolder(viewHolder: ViewHolder, action: GuidedAction) {
super.onBindViewHolder(viewHolder, action)
viewHolder.titleView?.apply {
maxLines = 5
isSingleLine = false
ellipsize = null
}
}
}
/*
* 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.app.Activity
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.leanback.app.GuidedStepSupportFragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import cx.ring.application.JamiApplication
import cx.ring.linkdevice.view.ExportSideStep3Fragment
import cx.ring.linkdevice.viewmodel.AddDeviceExportState
import cx.ring.linkdevice.viewmodel.ExportSideInputError
import cx.ring.linkdevice.viewmodel.ExportSideViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import net.jami.services.AccountService
@AndroidEntryPoint
class TVExportWizard : AppCompatActivity(),
TVAccountExportStep1Fragment.OnInputCallback,
TVAccountExportStep2Fragment.OnReviewCallback,
ExportSideStep3Fragment.OnResultCallback {
private val exportSideViewModel by lazy {
ViewModelProvider(this)[ExportSideViewModel::class.java]
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
JamiApplication.instance?.startDaemon(this)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(android.R.id.content, TVAccountExportStep1Fragment())
.commitNow()
}
observeUiState()
}
private fun observeUiState() {
lifecycleScope.launch {
exportSideViewModel.uiState.collect { state ->
try {
when (state) {
is AddDeviceExportState.Init -> showInit(state.error)
is AddDeviceExportState.TokenAvailable ->
throw UnsupportedOperationException()
is AddDeviceExportState.Connecting ->
Log.d(TAG, "State: Connecting")
is AddDeviceExportState.Authenticating ->
showAuthenticating(state.peerAddress)
is AddDeviceExportState.InProgress -> showInProgress()
is AddDeviceExportState.Done -> showDone(state.error)
}
} catch (e: Exception) {
Log.e(TAG, "Error while processing UI state.", e)
}
}
}
}
private fun showInit(error: ExportSideInputError?) {
(supportFragmentManager.findFragmentById(android.R.id.content)
as? TVAccountExportStep1Fragment)?.showError(error)
}
private fun showAuthenticating(peerAddress: String?) {
val accountId = intent.getStringExtra(EXTRA_ACCOUNT_ID) ?: ""
val registeredName = intent.getStringExtra(EXTRA_REGISTERED_NAME) ?: accountId
val fragment = supportFragmentManager
.findFragmentById(android.R.id.content) as? TVAccountExportStep2Fragment
if (fragment == null) {
GuidedStepSupportFragment.addAsRoot(
this,
TVAccountExportStep2Fragment.build(peerAddress, accountId, registeredName),
android.R.id.content
)
} else {
fragment.update(peerAddress)
}
}
private fun showInProgress() {
val fragment = ExportSideStep3Fragment()
supportFragmentManager.beginTransaction()
.replace(android.R.id.content, fragment)
.commitNow()
fragment.showLoading()
}
private fun showDone(error: AccountService.AuthError?) {
val fragment = ExportSideStep3Fragment()
supportFragmentManager.beginTransaction()
.replace(android.R.id.content, fragment)
.commitNow()
if (error != null) {
fragment.showError(error)
} else {
fragment.showDone()
}
}
override fun onAuthenticationUri(authenticationUri: String) {
exportSideViewModel.onAuthenticationUri(authenticationUri)
}
override fun onIdentityConfirmation(confirm: Boolean) {
if (!confirm) {
finish(1)
} else {
exportSideViewModel.onIdentityConfirmation()
}
}
override fun onExit(returnCode: Int) {
finish(returnCode)
}
private fun finish(returnCode: Int = 0) {
if (returnCode != 0) {
Log.w(TAG, "Account exportation failed.")
exportSideViewModel.onCancel()
}
setResult(if (returnCode == 0) Activity.RESULT_OK else Activity.RESULT_CANCELED)
finish()
}
companion object {
private const val TAG = "TVExportWizard"
const val EXTRA_ACCOUNT_ID = "account_id"
const val EXTRA_REGISTERED_NAME = "registered_name"
}
}
...@@ -34,7 +34,7 @@ import androidx.tvprovider.media.tv.ChannelLogoUtils ...@@ -34,7 +34,7 @@ import androidx.tvprovider.media.tv.ChannelLogoUtils
import androidx.tvprovider.media.tv.PreviewProgram import androidx.tvprovider.media.tv.PreviewProgram
import androidx.tvprovider.media.tv.TvContractCompat import androidx.tvprovider.media.tv.TvContractCompat
import cx.ring.R import cx.ring.R
import cx.ring.tv.account.TVAccountExport import cx.ring.tv.account.TVExportWizard
import cx.ring.tv.account.TVProfileEditingFragment import cx.ring.tv.account.TVProfileEditingFragment
import cx.ring.tv.account.TVShareActivity import cx.ring.tv.account.TVShareActivity
import cx.ring.tv.call.TVCallActivity import cx.ring.tv.call.TVCallActivity
...@@ -294,12 +294,18 @@ class MainFragment : BaseBrowseFragment<MainPresenter>(), MainView { ...@@ -294,12 +294,18 @@ class MainFragment : BaseBrowseFragment<MainPresenter>(), MainView {
} }
} }
override fun showExportDialog(pAccountID: String, hasPassword: Boolean) { override fun showExportDialog(accountId: String, registeredName: String?) {
val wizard: GuidedStepSupportFragment = Log.d(TAG, "showExportDialog called with accountId: $accountId, name: $registeredName")
TVAccountExport.createInstance(pAccountID, hasPassword)
GuidedStepSupportFragment.add(parentFragmentManager, wizard, R.id.main_browse_fragment) val intent = Intent(requireContext(), TVExportWizard::class.java).apply {
putExtra(TVExportWizard.EXTRA_ACCOUNT_ID, accountId)
putExtra(TVExportWizard.EXTRA_REGISTERED_NAME, registeredName)
} }
startActivity(intent)
}
override fun showProfileEditing() { override fun showProfileEditing() {
GuidedStepSupportFragment.add( GuidedStepSupportFragment.add(
parentFragmentManager, parentFragmentManager,
......
...@@ -62,7 +62,7 @@ class MainPresenter @Inject constructor( ...@@ -62,7 +62,7 @@ class MainPresenter @Inject constructor(
fun onExportClicked() { fun onExportClicked() {
val account = accountService.currentAccount ?: return val account = accountService.currentAccount ?: return
view?.showExportDialog(account.accountId, account.hasPassword()) view?.showExportDialog(account.accountId, account.displayUsername)
} }
fun onEditProfileClicked() { fun onEditProfileClicked() {
......
...@@ -26,7 +26,7 @@ interface MainView { ...@@ -26,7 +26,7 @@ interface MainView {
fun showContactRequests(contactRequests: List<Conversation>) fun showContactRequests(contactRequests: List<Conversation>)
fun callContact(accountID: String, ringID: String) fun callContact(accountID: String, ringID: String)
fun displayAccountInfo(viewModel: HomeNavigationViewModel) fun displayAccountInfo(viewModel: HomeNavigationViewModel)
fun showExportDialog(pAccountID: String, hasPassword: Boolean) fun showExportDialog(accountId: String, registeredName: String?)
fun showProfileEditing() fun showProfileEditing()
fun showAccountShare() fun showAccountShare()
fun showSettings() fun showSettings()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment