From 7070bb5607f5ac9fd0825ab21e7abba675f98bdc Mon Sep 17 00:00:00 2001 From: "codrut.topliceanu" Date: Tue, 10 Aug 2021 16:56:34 +0300 Subject: [PATCH] For #17917: Use View binding in add-ons --- .../fenix/addons/AddonDetailsFragment.kt | 4 +- .../mozilla/fenix/addons/AddonDetailsView.kt | 33 +++-- .../addons/AddonInternalSettingsFragment.kt | 6 +- ... AddonPermissionDetailsBindingDelegate.kt} | 14 +- .../addons/AddonPermissionsDetailsFragment.kt | 4 +- .../fenix/addons/AddonsManagementFragment.kt | 45 +++--- .../addons/InstalledAddonDetailsFragment.kt | 134 ++++++++++-------- .../addons/NotYetSupportedAddonFragment.kt | 8 +- .../res/layout/overlay_add_on_progress.xml | 1 + .../fenix/addons/AddonDetailsViewTest.kt | 35 ++--- ...onPermissionDetailsBindingDelegateTest.kt} | 17 +-- 11 files changed, 165 insertions(+), 136 deletions(-) rename app/src/main/java/org/mozilla/fenix/addons/{AddonPermissionsDetailsView.kt => AddonPermissionDetailsBindingDelegate.kt} (83%) rename app/src/test/java/org/mozilla/fenix/addons/{AddonPermissionsDetailsViewTest.kt => AddonPermissionDetailsBindingDelegateTest.kt} (68%) diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonDetailsFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonDetailsFragment.kt index b391f5b69..7bc8471a6 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonDetailsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonDetailsFragment.kt @@ -21,6 +21,7 @@ import mozilla.components.feature.addons.update.DefaultAddonUpdater.UpdateAttemp import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentAddOnDetailsBinding import org.mozilla.fenix.ext.showToolbar /** @@ -38,7 +39,8 @@ class AddonDetailsFragment : Fragment(R.layout.fragment_add_on_details), AddonDe showToolbar(title = args.addon.translateName(it)) } - AddonDetailsView(view, interactor = this).bind(args.addon) + val binding = FragmentAddOnDetailsBinding.bind(view) + AddonDetailsView(binding, interactor = this).bind(args.addon) } override fun openWebsite(addonSiteUrl: Uri) { diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonDetailsView.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonDetailsView.kt index 5561941e0..7a81f3f9f 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonDetailsView.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonDetailsView.kt @@ -13,12 +13,11 @@ import android.view.View import androidx.core.net.toUri import androidx.core.text.HtmlCompat import androidx.core.text.getSpans -import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.fragment_add_on_details.* import mozilla.components.feature.addons.Addon import mozilla.components.feature.addons.ui.translateDescription import mozilla.components.feature.addons.ui.updatedAtDate import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentAddOnDetailsBinding import java.text.DateFormat import java.text.NumberFormat import java.util.Locale @@ -40,9 +39,9 @@ interface AddonDetailsInteractor { * Shows the details of an add-on. */ class AddonDetailsView( - override val containerView: View, + private val binding: FragmentAddOnDetailsBinding, private val interactor: AddonDetailsInteractor -) : LayoutContainer { +) { private val dateFormatter = DateFormat.getDateInstance() private val numberFormatter = NumberFormat.getNumberInstance(Locale.getDefault()) @@ -58,24 +57,24 @@ class AddonDetailsView( private fun bindRating(addon: Addon) { addon.rating?.let { rating -> - val resources = containerView.resources + val resources = binding.root.resources val ratingContentDescription = resources.getString(R.string.mozac_feature_addons_rating_content_description) - rating_view.contentDescription = String.format(ratingContentDescription, rating.average) - rating_view.rating = rating.average + binding.ratingView.contentDescription = String.format(ratingContentDescription, rating.average) + binding.ratingView.rating = rating.average - users_count.text = numberFormatter.format(rating.reviews) + binding.usersCount.text = numberFormatter.format(rating.reviews) } } private fun bindWebsite(addon: Addon) { - home_page_label.setOnClickListener { + binding.homePageLabel.setOnClickListener { interactor.openWebsite(addon.siteUrl.toUri()) } } private fun bindLastUpdated(addon: Addon) { - last_updated_text.text = dateFormatter.format(addon.updatedAtDate) + binding.lastUpdatedText.text = dateFormatter.format(addon.updatedAtDate) } private fun bindVersion(addon: Addon) { @@ -83,24 +82,24 @@ class AddonDetailsView( if (version.isNullOrEmpty()) { version = addon.version } - version_text.text = version + binding.versionText.text = version if (addon.isInstalled()) { - version_text.setOnLongClickListener { + binding.versionText.setOnLongClickListener { interactor.showUpdaterDialog(addon) true } } else { - version_text.setOnLongClickListener(null) + binding.versionText.setOnLongClickListener(null) } } private fun bindAuthors(addon: Addon) { - author_text.text = addon.authors.joinToString { author -> author.name }.trim() + binding.authorText.text = addon.authors.joinToString { author -> author.name }.trim() } private fun bindDetails(addon: Addon) { - val detailsText = addon.translateDescription(containerView.context) + val detailsText = addon.translateDescription(binding.root.context) val parsedText = detailsText.replace("\n", "
") val text = HtmlCompat.fromHtml(parsedText, HtmlCompat.FROM_HTML_MODE_COMPACT) @@ -110,8 +109,8 @@ class AddonDetailsView( for (link in links) { addActionToLinks(spannableStringBuilder, link) } - details.text = spannableStringBuilder - details.movementMethod = LinkMovementMethod.getInstance() + binding.details.text = spannableStringBuilder + binding.details.movementMethod = LinkMovementMethod.getInstance() } private fun addActionToLinks( diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonInternalSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonInternalSettingsFragment.kt index 94571480a..ac93df6c2 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonInternalSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonInternalSettingsFragment.kt @@ -10,9 +10,9 @@ import android.view.View import android.view.ViewGroup import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import kotlinx.android.synthetic.main.fragment_add_on_internal_settings.* import mozilla.components.feature.addons.ui.translateName import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentAddOnInternalSettingsBinding import org.mozilla.fenix.ext.showToolbar /** @@ -40,10 +40,10 @@ class AddonInternalSettingsFragment : AddonPopupBaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - + val binding = FragmentAddOnInternalSettingsBinding.bind(view) args.addon.installedState?.optionsPageUrl?.let { engineSession?.let { engineSession -> - addonSettingsEngineView.render(engineSession) + binding.addonSettingsEngineView.render(engineSession) engineSession.loadUrl(it) } } ?: findNavController().navigateUp() diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsView.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionDetailsBindingDelegate.kt similarity index 83% rename from app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsView.kt rename to app/src/main/java/org/mozilla/fenix/addons/AddonPermissionDetailsBindingDelegate.kt index 78f89a6cc..d1b817fba 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsView.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionDetailsBindingDelegate.kt @@ -5,14 +5,12 @@ package org.mozilla.fenix.addons import android.net.Uri -import android.view.View import androidx.core.net.toUri import androidx.recyclerview.widget.LinearLayoutManager -import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.fragment_add_on_permissions.* import mozilla.components.feature.addons.Addon import mozilla.components.feature.addons.ui.AddonPermissionsAdapter import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentAddOnPermissionsBinding import org.mozilla.fenix.theme.ThemeManager interface AddonPermissionsDetailsInteractor { @@ -26,10 +24,10 @@ interface AddonPermissionsDetailsInteractor { /** * Shows the permission details of an add-on. */ -class AddonPermissionsDetailsView( - override val containerView: View, +class AddonPermissionDetailsBindingDelegate( + val binding: FragmentAddOnPermissionsBinding, private val interactor: AddonPermissionsDetailsInteractor -) : LayoutContainer { +) { fun bind(addon: Addon) { bindPermissions(addon) @@ -37,7 +35,7 @@ class AddonPermissionsDetailsView( } private fun bindPermissions(addon: Addon) { - add_ons_permissions.apply { + binding.addOnsPermissions.apply { layoutManager = LinearLayoutManager(context) val sortedPermissions = addon.translatePermissions(context).sorted() adapter = AddonPermissionsAdapter( @@ -50,7 +48,7 @@ class AddonPermissionsDetailsView( } private fun bindLearnMore() { - learn_more_label.setOnClickListener { + binding.learnMoreLabel.setOnClickListener { interactor.openWebsite(LEARN_MORE_URL.toUri()) } } diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt index c34974725..a5503518c 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt @@ -13,6 +13,7 @@ import mozilla.components.feature.addons.ui.translateName import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentAddOnPermissionsBinding import org.mozilla.fenix.ext.showToolbar /** @@ -29,7 +30,8 @@ class AddonPermissionsDetailsFragment : context?.let { showToolbar(args.addon.translateName(it)) } - AddonPermissionsDetailsView(view, interactor = this).bind(args.addon) + val binding = FragmentAddOnPermissionsBinding.bind(view) + AddonPermissionDetailsBindingDelegate(binding, interactor = this).bind(args.addon) } override fun openWebsite(addonSiteUrl: Uri) { diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt index cee178ad7..dac6c41b1 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt @@ -17,9 +17,6 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager -import kotlinx.android.synthetic.main.fragment_add_ons_management.* -import kotlinx.android.synthetic.main.fragment_add_ons_management.view.* -import kotlinx.android.synthetic.main.overlay_add_on_progress.view.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch @@ -34,6 +31,7 @@ import org.mozilla.fenix.Config import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.FragmentAddOnsManagementBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.getRootView import org.mozilla.fenix.ext.requireComponents @@ -52,6 +50,9 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) private val args by navArgs() + private var _binding: FragmentAddOnsManagementBinding? = null + private val binding get() = _binding!! + /** * Whether or not an add-on installation is in progress. */ @@ -69,7 +70,8 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bindRecyclerView(view) + _binding = FragmentAddOnsManagementBinding.bind(view) + bindRecyclerView() } override fun onResume() { @@ -88,15 +90,16 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) super.onDestroyView() // letting go of the resources to avoid memory leak. adapter = null + _binding = null } - private fun bindRecyclerView(view: View) { + private fun bindRecyclerView() { val managementView = AddonsManagementView( navController = findNavController(), showPermissionDialog = ::showPermissionDialog ) - val recyclerView = view.add_ons_list + val recyclerView = binding.addOnsList recyclerView.layoutManager = LinearLayoutManager(requireContext()) val shouldRefresh = adapter != null @@ -126,8 +129,8 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) ) } isInstallationInProgress = false - view.add_ons_progress_bar.isVisible = false - view.add_ons_empty_message.isVisible = false + binding.addOnsProgressBar.isVisible = false + binding.addOnsEmptyMessage.isVisible = false recyclerView.adapter = adapter if (shouldRefresh) { @@ -145,12 +148,12 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) lifecycleScope.launch(Dispatchers.Main) { runIfFragmentIsAttached { showSnackBar( - view, + binding.root, getString(R.string.mozac_feature_addons_failed_to_query_add_ons) ) isInstallationInProgress = false - view.add_ons_progress_bar.isVisible = false - view.add_ons_empty_message.isVisible = true + binding.addOnsProgressBar.isVisible = false + binding.addOnsEmptyMessage.isVisible = true } } } @@ -277,10 +280,10 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) } private val onPositiveButtonClicked: ((Addon) -> Unit) = { addon -> - addonProgressOverlay?.visibility = View.VISIBLE + binding.addonProgressOverlay.overlayCardView.visibility = View.VISIBLE if (requireContext().settings().accessibilityServicesEnabled) { - announceForAccessibility(addonProgressOverlay.add_ons_overlay_text.text) + announceForAccessibility(binding.addonProgressOverlay.addOnsOverlayText.text) } isInstallationInProgress = true @@ -291,7 +294,7 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) runIfFragmentIsAttached { isInstallationInProgress = false adapter?.updateAddon(it) - addonProgressOverlay?.visibility = View.GONE + binding.addonProgressOverlay.overlayCardView.visibility = View.GONE showInstallationDialog(it) } }, @@ -310,17 +313,17 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) ) } } - addonProgressOverlay?.visibility = View.GONE + binding.addonProgressOverlay.overlayCardView.visibility = View.GONE isInstallationInProgress = false } } ) - addonProgressOverlay.cancel_button.setOnClickListener { + binding.addonProgressOverlay.cancelButton.setOnClickListener { lifecycleScope.launch(Dispatchers.Main) { // Hide the installation progress overlay once cancellation is successful. if (installOperation.cancel().await()) { - addonProgressOverlay.visibility = View.GONE + binding.addonProgressOverlay.overlayCardView.visibility = View.GONE } } } @@ -330,10 +333,14 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) val event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_ANNOUNCEMENT ) - addonProgressOverlay.onInitializeAccessibilityEvent(event) + + binding.addonProgressOverlay.overlayCardView.onInitializeAccessibilityEvent(event) event.text.add(announcementText) event.contentDescription = null - addonProgressOverlay.parent.requestSendAccessibilityEvent(addonProgressOverlay, event) + binding.addonProgressOverlay.overlayCardView.parent.requestSendAccessibilityEvent( + binding.addonProgressOverlay.overlayCardView, + event + ) } companion object { diff --git a/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt index bece38513..b7264ad86 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt @@ -15,7 +15,6 @@ import androidx.navigation.Navigation import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController import com.google.android.material.switchmaterial.SwitchMaterial -import kotlinx.android.synthetic.main.fragment_installed_add_on_details.view.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import mozilla.components.feature.addons.Addon @@ -24,6 +23,7 @@ import mozilla.components.feature.addons.ui.translateName import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.FragmentInstalledAddOnDetailsBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.ext.runIfFragmentIsAttached @@ -34,6 +34,8 @@ import org.mozilla.fenix.ext.runIfFragmentIsAttached @Suppress("LargeClass", "TooManyFunctions") class InstalledAddonDetailsFragment : Fragment() { private lateinit var addon: Addon + private var _binding: FragmentInstalledAddOnDetailsBinding? = null + private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, @@ -44,17 +46,28 @@ class InstalledAddonDetailsFragment : Fragment() { addon = AddonDetailsFragmentArgs.fromBundle(requireNotNull(arguments)).addon } - return inflater.inflate(R.layout.fragment_installed_add_on_details, container, false).also { - bindUI(it) - } + _binding = FragmentInstalledAddOnDetailsBinding.inflate( + inflater, + container, + false + ) + + bindUI() + + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bindAddon(view) + bindAddon() } - private fun bindAddon(view: View) { + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + private fun bindAddon() { lifecycleScope.launch(Dispatchers.IO) { try { val addons = requireContext().components.addonManager.getAddons() @@ -65,10 +78,10 @@ class InstalledAddonDetailsFragment : Fragment() { throw AddonManagerException(Exception("Addon ${addon.id} not found")) } else { addon = it - bindUI(view) + bindUI() } - view.add_on_progress_bar.isVisible = false - view.addon_container.isVisible = true + binding.addOnProgressBar.isVisible = false + binding.addonContainer.isVisible = true } } } @@ -76,7 +89,7 @@ class InstalledAddonDetailsFragment : Fragment() { lifecycleScope.launch(Dispatchers.Main) { runIfFragmentIsAttached { showSnackBar( - view, + binding.root, getString(R.string.mozac_feature_addons_failed_to_query_add_ons) ) findNavController().popBackStack() @@ -86,27 +99,27 @@ class InstalledAddonDetailsFragment : Fragment() { } } - private fun bindUI(view: View) { - val title = addon.translateName(view.context) + private fun bindUI() { + val title = addon.translateName(binding.root.context) showToolbar(title) - bindEnableSwitch(view) - bindSettings(view) - bindDetails(view) - bindPermissions(view) - bindAllowInPrivateBrowsingSwitch(view) - bindRemoveButton(view) + bindEnableSwitch() + bindSettings() + bindDetails() + bindPermissions() + bindAllowInPrivateBrowsingSwitch() + bindRemoveButton() } @SuppressWarnings("LongMethod") - private fun bindEnableSwitch(view: View) { - val switch = view.enable_switch - val privateBrowsingSwitch = view.allow_in_private_browsing_switch + private fun bindEnableSwitch() { + val switch = binding.enableSwitch + val privateBrowsingSwitch = binding.allowInPrivateBrowsingSwitch switch.setState(addon.isEnabled()) switch.setOnCheckedChangeListener { v, isChecked -> val addonManager = v.context.components.addonManager switch.isClickable = false - view.remove_add_on.isEnabled = false + binding.removeAddOn.isEnabled = false if (isChecked) { addonManager.enableAddon( addon, @@ -117,11 +130,11 @@ class InstalledAddonDetailsFragment : Fragment() { privateBrowsingSwitch.isVisible = it.isEnabled() privateBrowsingSwitch.isChecked = it.isAllowedInPrivateBrowsing() switch.setText(R.string.mozac_feature_addons_enabled) - view.settings.isVisible = shouldSettingsBeVisible() - view.remove_add_on.isEnabled = true + binding.settings.isVisible = shouldSettingsBeVisible() + binding.removeAddOn.isEnabled = true context?.let { showSnackBar( - view, + binding.root, getString( R.string.mozac_feature_addons_successfully_enabled, addon.translateName(it) @@ -133,11 +146,11 @@ class InstalledAddonDetailsFragment : Fragment() { onError = { runIfFragmentIsAttached { switch.isClickable = true - view.remove_add_on.isEnabled = true + binding.removeAddOn.isEnabled = true switch.setState(addon.isEnabled()) context?.let { showSnackBar( - view, + binding.root, getString( R.string.mozac_feature_addons_failed_to_enable, addon.translateName(it) @@ -148,7 +161,7 @@ class InstalledAddonDetailsFragment : Fragment() { } ) } else { - view.settings.isVisible = false + binding.settings.isVisible = false addonManager.disableAddon( addon, onSuccess = { @@ -157,10 +170,10 @@ class InstalledAddonDetailsFragment : Fragment() { switch.isClickable = true privateBrowsingSwitch.isVisible = it.isEnabled() switch.setText(R.string.mozac_feature_addons_disabled) - view.remove_add_on.isEnabled = true + binding.removeAddOn.isEnabled = true context?.let { showSnackBar( - view, + binding.root, getString( R.string.mozac_feature_addons_successfully_disabled, addon.translateName(it) @@ -173,11 +186,11 @@ class InstalledAddonDetailsFragment : Fragment() { runIfFragmentIsAttached { switch.isClickable = true privateBrowsingSwitch.isClickable = true - view.remove_add_on.isEnabled = true + binding.removeAddOn.isEnabled = true switch.setState(addon.isEnabled()) context?.let { showSnackBar( - view, + binding.root, getString( R.string.mozac_feature_addons_failed_to_disable, addon.translateName(it) @@ -191,8 +204,8 @@ class InstalledAddonDetailsFragment : Fragment() { } } - private fun bindSettings(view: View) { - view.settings.apply { + private fun bindSettings() { + binding.settings.apply { isVisible = shouldSettingsBeVisible() setOnClickListener { requireContext().components.analytics.metrics.track( @@ -216,34 +229,34 @@ class InstalledAddonDetailsFragment : Fragment() { } } - private fun bindDetails(view: View) { - view.details.setOnClickListener { + private fun bindDetails() { + binding.details.setOnClickListener { val directions = InstalledAddonDetailsFragmentDirections.actionInstalledAddonFragmentToAddonDetailsFragment( addon ) - Navigation.findNavController(view).navigate(directions) + Navigation.findNavController(binding.root).navigate(directions) } } - private fun bindPermissions(view: View) { - view.permissions.setOnClickListener { + private fun bindPermissions() { + binding.permissions.setOnClickListener { val directions = InstalledAddonDetailsFragmentDirections.actionInstalledAddonFragmentToAddonPermissionsDetailsFragment( addon ) - Navigation.findNavController(view).navigate(directions) + Navigation.findNavController(binding.root).navigate(directions) } } - private fun bindAllowInPrivateBrowsingSwitch(view: View) { - val switch = view.allow_in_private_browsing_switch + private fun bindAllowInPrivateBrowsingSwitch() { + val switch = binding.allowInPrivateBrowsingSwitch switch.isChecked = addon.isAllowedInPrivateBrowsing() switch.isVisible = addon.isEnabled() switch.setOnCheckedChangeListener { v, isChecked -> val addonManager = v.context.components.addonManager switch.isClickable = false - view.remove_add_on.isEnabled = false + binding.removeAddOn.isEnabled = false addonManager.setAddonAllowedInPrivateBrowsing( addon, isChecked, @@ -251,45 +264,45 @@ class InstalledAddonDetailsFragment : Fragment() { runIfFragmentIsAttached { this.addon = it switch.isClickable = true - view.remove_add_on.isEnabled = true + binding.removeAddOn.isEnabled = true } }, onError = { runIfFragmentIsAttached { switch.isChecked = addon.isAllowedInPrivateBrowsing() switch.isClickable = true - view.remove_add_on.isEnabled = true + binding.removeAddOn.isEnabled = true } } ) } } - private fun bindRemoveButton(view: View) { - view.remove_add_on.setOnClickListener { - setAllInteractiveViewsClickable(view, false) + private fun bindRemoveButton() { + binding.removeAddOn.setOnClickListener { + setAllInteractiveViewsClickable(binding, false) requireContext().components.addonManager.uninstallAddon( addon, onSuccess = { runIfFragmentIsAttached { - setAllInteractiveViewsClickable(view, true) + setAllInteractiveViewsClickable(binding, true) context?.let { showSnackBar( - view, + binding.root, getString( R.string.mozac_feature_addons_successfully_uninstalled, addon.translateName(it) ) ) } - view.findNavController().popBackStack() + binding.root.findNavController().popBackStack() } }, onError = { _, _ -> runIfFragmentIsAttached { - setAllInteractiveViewsClickable(view, true) + setAllInteractiveViewsClickable(binding, true) context?.let { showSnackBar( - view, + binding.root, getString( R.string.mozac_feature_addons_failed_to_uninstall, addon.translateName(it) @@ -302,12 +315,15 @@ class InstalledAddonDetailsFragment : Fragment() { } } - private fun setAllInteractiveViewsClickable(view: View, clickable: Boolean) { - view.enable_switch.isClickable = clickable - view.settings.isClickable = clickable - view.details.isClickable = clickable - view.permissions.isClickable = clickable - view.remove_add_on.isClickable = clickable + private fun setAllInteractiveViewsClickable( + binding: FragmentInstalledAddOnDetailsBinding, + clickable: Boolean + ) { + binding.enableSwitch.isClickable = clickable + binding.settings.isClickable = clickable + binding.details.isClickable = clickable + binding.permissions.isClickable = clickable + binding.removeAddOn.isClickable = clickable } private fun SwitchMaterial.setState(checked: Boolean) { diff --git a/app/src/main/java/org/mozilla/fenix/addons/NotYetSupportedAddonFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/NotYetSupportedAddonFragment.kt index 25147dba3..258d47243 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/NotYetSupportedAddonFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/NotYetSupportedAddonFragment.kt @@ -12,10 +12,10 @@ import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager -import kotlinx.android.synthetic.main.fragment_not_yet_supported_addons.view.* import mozilla.components.feature.addons.ui.UnsupportedAddonsAdapter import mozilla.components.feature.addons.ui.UnsupportedAddonsAdapterDelegate import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentNotYetSupportedAddonsBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.showToolbar @@ -40,12 +40,14 @@ class NotYetSupportedAddonFragment : addons = args.addons.toList() ) - view.unsupported_add_ons_list.apply { + val binding = FragmentNotYetSupportedAddonsBinding.bind(view) + + binding.unsupportedAddOnsList.apply { layoutManager = LinearLayoutManager(requireContext()) adapter = unsupportedAddonsAdapter } - view.learn_more_label.setOnClickListener { + binding.learnMoreLabel.setOnClickListener { val intent = Intent(Intent.ACTION_VIEW).setData(Uri.parse(LEARN_MORE_URL)) startActivity(intent) } diff --git a/app/src/main/res/layout/overlay_add_on_progress.xml b/app/src/main/res/layout/overlay_add_on_progress.xml index bfd2105d7..7ee5ecd1b 100644 --- a/app/src/main/res/layout/overlay_add_on_progress.xml +++ b/app/src/main/res/layout/overlay_add_on_progress.xml @@ -5,6 +5,7 @@ diff --git a/app/src/test/java/org/mozilla/fenix/addons/AddonDetailsViewTest.kt b/app/src/test/java/org/mozilla/fenix/addons/AddonDetailsViewTest.kt index 988eba2d4..98af34120 100644 --- a/app/src/test/java/org/mozilla/fenix/addons/AddonDetailsViewTest.kt +++ b/app/src/test/java/org/mozilla/fenix/addons/AddonDetailsViewTest.kt @@ -10,7 +10,6 @@ import android.view.LayoutInflater import android.view.View import io.mockk.mockk import io.mockk.verify -import kotlinx.android.synthetic.main.fragment_add_on_details.view.* import mozilla.components.feature.addons.Addon import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals @@ -18,13 +17,14 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentAddOnDetailsBinding import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) class AddonDetailsViewTest { private lateinit var view: View + private lateinit var binding: FragmentAddOnDetailsBinding private lateinit var interactor: AddonDetailsInteractor private lateinit var detailsView: AddonDetailsView private val baseAddon = Addon( @@ -37,10 +37,11 @@ class AddonDetailsViewTest { @Before fun setup() { - view = LayoutInflater.from(testContext).inflate(R.layout.fragment_add_on_details, null) + binding = FragmentAddOnDetailsBinding.inflate(LayoutInflater.from(testContext)) + view = binding.root interactor = mockk(relaxed = true) - detailsView = AddonDetailsView(view, interactor) + detailsView = AddonDetailsView(binding, interactor) } @Test @@ -50,7 +51,7 @@ class AddonDetailsViewTest { rating = null ) ) - assertEquals(0f, view.rating_view.rating) + assertEquals(0f, binding.ratingView.rating) detailsView.bind( baseAddon.copy( @@ -60,9 +61,9 @@ class AddonDetailsViewTest { ) ) ) - assertEquals("4.30/5", view.rating_view.contentDescription) - assertEquals(4.5f, view.rating_view.rating) - assertEquals("100", view.users_count.text) + assertEquals("4.30/5", binding.ratingView.contentDescription) + assertEquals(4.5f, binding.ratingView.rating) + assertEquals("100", binding.usersCount.text) } @Test @@ -73,7 +74,7 @@ class AddonDetailsViewTest { ) ) - view.home_page_label.performClick() + binding.homePageLabel.performClick() verify { interactor.openWebsite(Uri.parse("https://mozilla.org")) } } @@ -82,7 +83,7 @@ class AddonDetailsViewTest { fun `bind addons last updated`() { detailsView.bind(baseAddon) - assertEquals("Nov 23, 2020", view.last_updated_text.text) + assertEquals("Nov 23, 2020", binding.lastUpdatedText.text) } @Test @@ -93,8 +94,8 @@ class AddonDetailsViewTest { ) detailsView.bind(addon1) - assertEquals("1.0.0", view.version_text.text) - view.version_text.performLongClick() + assertEquals("1.0.0", binding.versionText.text) + binding.versionText.performLongClick() verify(exactly = 0) { interactor.showUpdaterDialog(addon1) } val addon2 = baseAddon.copy( @@ -106,8 +107,8 @@ class AddonDetailsViewTest { ) ) detailsView.bind(addon2) - assertEquals("2.0.0", view.version_text.text) - view.version_text.performLongClick() + assertEquals("2.0.0", binding.versionText.text) + binding.versionText.performLongClick() verify { interactor.showUpdaterDialog(addon2) } } @@ -123,7 +124,7 @@ class AddonDetailsViewTest { ) ) - assertEquals("Sarah Jane, John Smith", view.author_text.text) + assertEquals("Sarah Jane, John Smith", binding.authorText.text) } @Test @@ -132,8 +133,8 @@ class AddonDetailsViewTest { assertEquals( "Some blank addon\nwith a blank line", - view.details.text.toString() + binding.details.text.toString() ) - assertTrue(view.details.movementMethod is LinkMovementMethod) + assertTrue(binding.details.movementMethod is LinkMovementMethod) } } diff --git a/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsViewTest.kt b/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionDetailsBindingDelegateTest.kt similarity index 68% rename from app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsViewTest.kt rename to app/src/test/java/org/mozilla/fenix/addons/AddonPermissionDetailsBindingDelegateTest.kt index 4cb640565..840b873c4 100644 --- a/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsViewTest.kt +++ b/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionDetailsBindingDelegateTest.kt @@ -9,21 +9,21 @@ import android.view.View import androidx.core.net.toUri import io.mockk.mockk import io.mockk.verify -import kotlinx.android.synthetic.main.fragment_add_on_permissions.* import mozilla.components.feature.addons.Addon import mozilla.components.support.test.robolectric.testContext import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentAddOnPermissionsBinding import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) -class AddonPermissionsDetailsViewTest { +class AddonPermissionDetailsBindingDelegateTest { private lateinit var view: View + private lateinit var binding: FragmentAddOnPermissionsBinding private lateinit var interactor: AddonPermissionsDetailsInteractor - private lateinit var permissionsDetailsView: AddonPermissionsDetailsView + private lateinit var permissionDetailsBindingDelegate: AddonPermissionDetailsBindingDelegate private val addon = Addon( id = "", translatableName = mapOf( @@ -35,20 +35,21 @@ class AddonPermissionsDetailsViewTest { @Before fun setup() { - view = LayoutInflater.from(testContext).inflate(R.layout.fragment_add_on_permissions, null) + binding = FragmentAddOnPermissionsBinding.inflate(LayoutInflater.from(testContext)) + view = binding.root interactor = mockk(relaxed = true) - permissionsDetailsView = AddonPermissionsDetailsView(view, interactor) + permissionDetailsBindingDelegate = AddonPermissionDetailsBindingDelegate(binding, interactor) } @Test fun `clicking learn more opens learn more page in browser`() { - permissionsDetailsView.bind( + permissionDetailsBindingDelegate.bind( addon.copy( rating = null ) ) - permissionsDetailsView.learn_more_label.performClick() + permissionDetailsBindingDelegate.binding.learnMoreLabel.performClick() verify { interactor.openWebsite(learnMoreUrl.toUri()) } }