From cca7892e912e2f682ce1ccc4b0a06a4f67511bc9 Mon Sep 17 00:00:00 2001 From: mcarare Date: Mon, 5 Jul 2021 18:18:20 +0300 Subject: [PATCH] For #17917: Use View binding in settings screens. --- .../fenix/settings/SettingsFragment.kt | 15 +-- .../fenix/settings/about/AboutFragment.kt | 22 ++-- .../settings/about/AboutLibrariesFragment.kt | 9 +- .../about/viewholders/AboutItemViewHolder.kt | 6 +- .../fenix/settings/account/SignOutFragment.kt | 23 ++-- .../settings/account/TurnOnSyncFragment.kt | 18 +-- .../advanced/LocaleSettingsFragment.kt | 20 +++- .../settings/advanced/LocaleSettingsView.kt | 6 +- .../settings/advanced/LocaleViewHolders.kt | 34 +++--- .../creditcards/CreditCardEditorFragment.kt | 5 +- .../CreditCardsManagementFragment.kt | 5 +- .../creditcards/view/CreditCardEditorView.kt | 67 ++++++----- .../view/CreditCardsManagementView.kt | 20 ++-- .../DeleteBrowsingDataFragment.kt | 58 ++++++---- .../DeleteBrowsingDataItem.kt | 31 ++--- .../logins/fragment/EditLoginFragment.kt | 109 ++++++++++-------- .../logins/fragment/LoginDetailFragment.kt | 43 ++++--- .../logins/fragment/SavedLoginsFragment.kt | 6 +- .../QuickSettingsSheetDialogFragment.kt | 18 ++- .../settings/quicksettings/WebsiteInfoView.kt | 33 +++--- .../quicksettings/WebsitePermissionsView.kt | 35 +++--- .../search/AddSearchEngineFragment.kt | 106 +++++++++-------- .../search/EditCustomSearchEngineFragment.kt | 44 ++++--- .../search/RadioSearchEngineListPreference.kt | 26 ++--- ...tePermissionsManagePhoneFeatureFragment.kt | 58 +++++----- .../res/layout/fragment_add_search_engine.xml | 4 +- .../res/layout/layout_add_credit_card.xml | 1 + .../settings/about/AboutPageAdapterTest.kt | 14 ++- .../viewholders/AboutItemViewHolderTest.kt | 3 +- .../advanced/LocaleViewHoldersTest.kt | 25 ++-- .../creditcards/CreditCardEditorViewTest.kt | 60 +++++----- .../CreditCardItemViewHolderTest.kt | 8 +- .../CreditCardsManagementViewTest.kt | 14 ++- .../quicksettings/WebsiteInfoViewTest.kt | 20 ++-- 34 files changed, 545 insertions(+), 421 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt index 147ac7d95b..c0acaa5ec0 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt @@ -26,7 +26,6 @@ import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference import androidx.recyclerview.widget.RecyclerView -import kotlinx.android.synthetic.main.amo_collection_override_dialog.view.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -41,6 +40,7 @@ import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.AmoCollectionOverrideDialogBinding import org.mozilla.fenix.experiments.ExperimentBranch import org.mozilla.fenix.experiments.FeatureId import org.mozilla.fenix.ext.application @@ -352,6 +352,7 @@ class SettingsFragment : PreferenceFragmentCompat() { val context = requireContext() val dialogView = LayoutInflater.from(context).inflate(R.layout.amo_collection_override_dialog, null) + val binding = AmoCollectionOverrideDialogBinding.bind(dialogView) AlertDialog.Builder(context).apply { setTitle(context.getString(R.string.preferences_customize_amo_collection)) setView(dialogView) @@ -360,8 +361,8 @@ class SettingsFragment : PreferenceFragmentCompat() { } setPositiveButton(R.string.customize_addon_collection_ok) { _, _ -> - context.settings().overrideAmoUser = dialogView.custom_amo_user.text.toString() - context.settings().overrideAmoCollection = dialogView.custom_amo_collection.text.toString() + context.settings().overrideAmoUser = binding.customAmoUser.text.toString() + context.settings().overrideAmoCollection = binding.customAmoCollection.text.toString() Toast.makeText( context, @@ -374,10 +375,10 @@ class SettingsFragment : PreferenceFragmentCompat() { }, AMO_COLLECTION_OVERRIDE_EXIT_DELAY) } - dialogView.custom_amo_collection.setText(context.settings().overrideAmoCollection) - dialogView.custom_amo_user.setText(context.settings().overrideAmoUser) - dialogView.custom_amo_user.requestFocus() - dialogView.custom_amo_user.showKeyboard() + binding.customAmoCollection.setText(context.settings().overrideAmoCollection) + binding.customAmoUser.setText(context.settings().overrideAmoUser) + binding.customAmoUser.requestFocus() + binding.customAmoUser.showKeyboard() create() }.show() diff --git a/app/src/main/java/org/mozilla/fenix/settings/about/AboutFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/about/AboutFragment.kt index 29d81b6b54..c962e573d8 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/about/AboutFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/about/AboutFragment.kt @@ -14,7 +14,6 @@ import androidx.core.content.pm.PackageInfoCompat import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DividerItemDecoration -import kotlinx.android.synthetic.main.fragment_about.* import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.Config @@ -22,6 +21,7 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.crashes.CrashListActivity +import org.mozilla.fenix.databinding.FragmentAboutBinding import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar @@ -43,19 +43,22 @@ class AboutFragment : Fragment(), AboutPageListener { private lateinit var headerAppName: String private lateinit var appName: String private var aboutPageAdapter: AboutPageAdapter? = AboutPageAdapter(this) + private var _binding: FragmentAboutBinding? = null + + private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - val rootView = inflater.inflate(R.layout.fragment_about, container, false) + ): View { + _binding = FragmentAboutBinding.inflate(inflater, container, false) appName = getString(R.string.app_name) headerAppName = if (Config.channel.isRelease) getString(R.string.daylight_app_name) else appName showToolbar(getString(R.string.preferences_about, appName)) - return rootView + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -63,7 +66,7 @@ class AboutFragment : Fragment(), AboutPageListener { aboutPageAdapter = AboutPageAdapter(this) } - about_list.run { + binding.aboutList.run { adapter = aboutPageAdapter addItemDecoration( DividerItemDecoration( @@ -75,7 +78,7 @@ class AboutFragment : Fragment(), AboutPageListener { lifecycle.addObserver( SecretDebugMenuTrigger( - logoView = wordmark, + logoView = binding.wordmark, settings = view.context.settings() ) ) @@ -87,6 +90,7 @@ class AboutFragment : Fragment(), AboutPageListener { override fun onDestroyView() { super.onDestroyView() aboutPageAdapter = null + _binding = null } private fun populateAboutHeader() { @@ -121,9 +125,9 @@ class AboutFragment : Fragment(), AboutPageListener { val content = getString(R.string.about_content, headerAppName) val buildDate = BuildConfig.BUILD_DATE - about_text.text = aboutText - about_content.text = content - build_date.text = buildDate + binding.aboutText.text = aboutText + binding.aboutContent.text = content + binding.buildDate.text = buildDate } private fun populateAboutList(): List { diff --git a/app/src/main/java/org/mozilla/fenix/settings/about/AboutLibrariesFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/about/AboutLibrariesFragment.kt index ca132a32ee..4f44f9edd0 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/about/AboutLibrariesFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/about/AboutLibrariesFragment.kt @@ -13,8 +13,8 @@ import android.widget.ListView import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment -import kotlinx.android.synthetic.main.fragment_about_libraries.view.* import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentAboutLibrariesBinding import org.mozilla.fenix.ext.showToolbar import java.nio.charset.Charset import java.util.Locale @@ -34,11 +34,16 @@ import java.util.Locale * to show the extracted licenses to the end-user. */ class AboutLibrariesFragment : Fragment(R.layout.fragment_about_libraries) { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val appName = getString(R.string.app_name) + val binding = FragmentAboutLibrariesBinding.bind(view) showToolbar(getString(R.string.open_source_licenses_title, appName)) + setupLibrariesListView(binding.aboutLibrariesListview) + } - setupLibrariesListView(view.about_libraries_listview) + override fun onDestroyView() { + super.onDestroyView() } private fun setupLibrariesListView(listView: ListView) { diff --git a/app/src/main/java/org/mozilla/fenix/settings/about/viewholders/AboutItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/settings/about/viewholders/AboutItemViewHolder.kt index 220af45c22..4de2e1f848 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/about/viewholders/AboutItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/about/viewholders/AboutItemViewHolder.kt @@ -6,8 +6,8 @@ package org.mozilla.fenix.settings.about.viewholders import android.view.View import androidx.recyclerview.widget.RecyclerView -import kotlinx.android.synthetic.main.about_list_item.view.* import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.AboutListItemBinding import org.mozilla.fenix.settings.about.AboutPageItem import org.mozilla.fenix.settings.about.AboutPageListener @@ -16,8 +16,8 @@ class AboutItemViewHolder( listener: AboutPageListener ) : RecyclerView.ViewHolder(view) { - private val title = view.about_item_title private lateinit var item: AboutPageItem + val binding = AboutListItemBinding.bind(view) init { itemView.setOnClickListener { @@ -27,7 +27,7 @@ class AboutItemViewHolder( fun bind(item: AboutPageItem) { this.item = item - title.text = item.title + binding.aboutItemTitle.text = item.title } companion object { diff --git a/app/src/main/java/org/mozilla/fenix/settings/account/SignOutFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/account/SignOutFragment.kt index e5f960008f..100e9a7b2c 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/account/SignOutFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/account/SignOutFragment.kt @@ -15,16 +15,19 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.google.android.material.bottomsheet.BottomSheetBehavior import androidx.appcompat.app.AppCompatDialogFragment -import kotlinx.android.synthetic.main.fragment_sign_out.view.* import kotlinx.coroutines.launch import mozilla.components.service.fxa.manager.FxaAccountManager import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentSignOutBinding import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.runIfFragmentIsAttached class SignOutFragment : AppCompatDialogFragment() { private lateinit var accountManager: FxaAccountManager + private var _binding: FragmentSignOutBinding? = null + private val binding get() = _binding!! + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, R.style.BottomSheet) @@ -46,12 +49,13 @@ class SignOutFragment : AppCompatDialogFragment() { savedInstanceState: Bundle? ): View? { accountManager = requireComponents.backgroundServices.accountManager - val view = inflater.inflate(R.layout.fragment_sign_out, container, false) - view.sign_out_message.text = String.format( - view.context.getString( + _binding = FragmentSignOutBinding.inflate(inflater, container, false) + + binding.signOutMessage.text = String.format( + binding.root.context.getString( R.string.sign_out_confirmation_message_2 ), - view.context.getString(R.string.app_name) + binding.root.context.getString(R.string.app_name) ) return view } @@ -59,7 +63,7 @@ class SignOutFragment : AppCompatDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - view.signOutDisconnect.setOnClickListener { + binding.signOutDisconnect.setOnClickListener { lifecycleScope.launch { requireComponents .backgroundServices.accountAbnormalities.userRequestedLogout() @@ -74,8 +78,13 @@ class SignOutFragment : AppCompatDialogFragment() { } } - view.signOutCancel.setOnClickListener { + binding.signOutCancel.setOnClickListener { dismiss() } } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/account/TurnOnSyncFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/account/TurnOnSyncFragment.kt index 19973a28e4..7162b11dfc 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/account/TurnOnSyncFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/account/TurnOnSyncFragment.kt @@ -14,7 +14,6 @@ import androidx.fragment.app.Fragment import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import kotlinx.android.synthetic.main.fragment_turn_on_sync.view.* import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.OAuthAccount @@ -26,6 +25,7 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.FragmentTurnOnSyncBinding import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar @@ -57,6 +57,9 @@ class TurnOnSyncFragment : Fragment(), AccountObserver { requireContext().settings().setCameraPermissionNeededState = false } + private var _binding: FragmentTurnOnSyncBinding? = null + private val binding get() = _binding!! + private fun navigateToPairFragment() { val directions = TurnOnSyncFragmentDirections.actionTurnOnSyncFragmentToPairFragment() requireView().findNavController().navigate(directions) @@ -84,6 +87,7 @@ class TurnOnSyncFragment : Fragment(), AccountObserver { override fun onDestroy() { super.onDestroy() requireComponents.analytics.metrics.track(Event.SyncAuthClosed) + _binding = null } override fun onResume() { @@ -110,11 +114,11 @@ class TurnOnSyncFragment : Fragment(), AccountObserver { // Headless fragment. Don't need UI if we're taking the user to another screen. return null } + _binding = FragmentTurnOnSyncBinding.inflate(inflater, container, false) - val view = inflater.inflate(R.layout.fragment_turn_on_sync, container, false) - view.signInScanButton.setOnClickListener(paringClickListener) - view.signInEmailButton.setOnClickListener(signInClickListener) - view.signInInstructions.text = HtmlCompat.fromHtml( + binding.signInScanButton.setOnClickListener(paringClickListener) + binding.signInEmailButton.setOnClickListener(signInClickListener) + binding.signInInstructions.text = HtmlCompat.fromHtml( if (requireContext().settings().allowDomesticChinaFxaServer && Config.channel.isMozillaOnline) getString(R.string.sign_in_instructions_cn) else getString(R.string.sign_in_instructions), @@ -125,14 +129,14 @@ class TurnOnSyncFragment : Fragment(), AccountObserver { DefaultSyncController(activity = activity as HomeActivity) ) - view.createAccount.apply { + binding.createAccount.apply { text = HtmlCompat.fromHtml( getString(R.string.sign_in_create_account_text), HtmlCompat.FROM_HTML_MODE_LEGACY ) setOnClickListener(createAccountClickListener) } - return view + return binding.root } override fun onAuthenticated(account: OAuthAccount, authType: AuthType) { diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt index a2ee4533f1..37e342fd2b 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt @@ -13,14 +13,16 @@ import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.appcompat.widget.SearchView import androidx.fragment.app.Fragment -import kotlinx.android.synthetic.main.fragment_locale_settings.view.* import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.ktx.android.view.hideKeyboard import mozilla.components.support.locale.LocaleUseCases import org.mozilla.fenix.R import org.mozilla.fenix.components.StoreProvider +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.FragmentLocaleSettingsBinding import org.mozilla.fenix.ext.components +import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.showToolbar class LocaleSettingsFragment : Fragment() { @@ -29,6 +31,9 @@ class LocaleSettingsFragment : Fragment() { private lateinit var interactor: LocaleSettingsInteractor private lateinit var localeView: LocaleSettingsView + private var _binding: FragmentLocaleSettingsBinding? = null + private val binding get() = _binding!! + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -38,8 +43,9 @@ class LocaleSettingsFragment : Fragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - val view = inflater.inflate(R.layout.fragment_locale_settings, container, false) + ): View { + _binding = FragmentLocaleSettingsBinding.inflate(inflater, container, false) + val view = binding.root val browserStore = requireContext().components.core.store val localeUseCase = LocaleUseCases(browserStore) @@ -56,7 +62,7 @@ class LocaleSettingsFragment : Fragment() { localeUseCase = localeUseCase ) ) - localeView = LocaleSettingsView(view.locale_container, interactor) + localeView = LocaleSettingsView(binding.root, interactor) return view } @@ -97,4 +103,10 @@ class LocaleSettingsFragment : Fragment() { localeView.update(it) } } + + override fun onDestroy() { + super.onDestroy() + requireComponents.analytics.metrics.track(Event.SyncAuthClosed) + _binding = null + } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsView.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsView.kt index acef1e9478..f5372e7817 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsView.kt @@ -8,8 +8,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.LinearLayoutManager -import kotlinx.android.synthetic.main.component_locale_settings.view.* import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.ComponentLocaleSettingsBinding import java.util.Locale interface LocaleSettingsViewInteractor { @@ -29,10 +29,12 @@ class LocaleSettingsView( val view: View = LayoutInflater.from(container.context) .inflate(R.layout.component_locale_settings, container, true) + val binding = ComponentLocaleSettingsBinding.bind(view) + private val localeAdapter: LocaleAdapter init { - view.locale_list.apply { + binding.localeList.apply { localeAdapter = LocaleAdapter(interactor) adapter = localeAdapter layoutManager = LinearLayoutManager(context) diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt index 831158be60..9335469e9b 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt @@ -7,10 +7,10 @@ package org.mozilla.fenix.settings.advanced import android.view.View import androidx.annotation.VisibleForTesting import androidx.core.view.isVisible -import kotlinx.android.synthetic.main.locale_settings_item.* +import androidx.recyclerview.widget.RecyclerView import mozilla.components.support.locale.LocaleManager import org.mozilla.fenix.R -import org.mozilla.fenix.utils.view.ViewHolder +import org.mozilla.fenix.databinding.LocaleSettingsItemBinding import java.util.Locale class LocaleViewHolder( @@ -19,6 +19,8 @@ class LocaleViewHolder( private val interactor: LocaleSettingsViewInteractor ) : BaseLocaleViewHolder(view, selectedLocale) { + private val binding = LocaleSettingsItemBinding.bind(view) + override fun bind(locale: Locale) { if (locale.toString().equals("vec", ignoreCase = true)) { locale.toString() @@ -27,11 +29,11 @@ class LocaleViewHolder( bindChineseLocale(locale) } else { // Capitalisation is done using the rules of the appropriate locale (endonym and exonym). - locale_title_text.text = getDisplayName(locale) + binding.localeTitleText.text = getDisplayName(locale) // Show the given locale using the device locale for the subtitle. - locale_subtitle_text.text = locale.getProperDisplayName() + binding.localeSubtitleText.text = locale.getProperDisplayName() } - locale_selected_icon.isVisible = isCurrentLocaleSelected(locale, isDefault = false) + binding.localeSelectedIcon.isVisible = isCurrentLocaleSelected(locale, isDefault = false) itemView.setOnClickListener { interactor.onLocaleSelected(locale) @@ -40,14 +42,14 @@ class LocaleViewHolder( private fun bindChineseLocale(locale: Locale) { if (locale.country == "CN") { - locale_title_text.text = + binding.localeTitleText.text = Locale.forLanguageTag("zh-Hans").getDisplayName(locale).capitalize(locale) - locale_subtitle_text.text = + binding.localeSubtitleText.text = Locale.forLanguageTag("zh-Hans").displayName.capitalize(Locale.getDefault()) } else if (locale.country == "TW") { - locale_title_text.text = + binding.localeTitleText.text = Locale.forLanguageTag("zh-Hant").getDisplayName(locale).capitalize(locale) - locale_subtitle_text.text = + binding.localeSubtitleText.text = Locale.forLanguageTag("zh-Hant").displayName.capitalize(Locale.getDefault()) } } @@ -271,19 +273,21 @@ class SystemLocaleViewHolder( private val interactor: LocaleSettingsViewInteractor ) : BaseLocaleViewHolder(view, selectedLocale) { + private val binding = LocaleSettingsItemBinding.bind(view) + override fun bind(locale: Locale) { - locale_title_text.text = itemView.context.getString(R.string.default_locale_text) + binding.localeTitleText.text = itemView.context.getString(R.string.default_locale_text) if (locale.script == "Hant") { - locale_subtitle_text.text = + binding.localeSubtitleText.text = Locale.forLanguageTag("zh-Hant").displayName.capitalize(Locale.getDefault()) } else if (locale.script == "Hans") { - locale_subtitle_text.text = + binding.localeSubtitleText.text = Locale.forLanguageTag("zh-Hans").displayName.capitalize(Locale.getDefault()) } else { // Use the device locale for the system locale subtitle. - locale_subtitle_text.text = locale.getDisplayName(locale).capitalize(locale) + binding.localeSubtitleText.text = locale.getDisplayName(locale).capitalize(locale) } - locale_selected_icon.isVisible = isCurrentLocaleSelected(locale, isDefault = true) + binding.localeSelectedIcon.isVisible = isCurrentLocaleSelected(locale, isDefault = true) itemView.setOnClickListener { interactor.onDefaultLocaleSelected() } @@ -293,7 +297,7 @@ class SystemLocaleViewHolder( abstract class BaseLocaleViewHolder( view: View, private val selectedLocale: Locale -) : ViewHolder(view) { +) : RecyclerView.ViewHolder(view) { @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) internal fun isCurrentLocaleSelected(locale: Locale, isDefault: Boolean): Boolean { diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt index c47f874a2f..54709410dc 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt @@ -14,6 +14,7 @@ import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import org.mozilla.fenix.R import org.mozilla.fenix.SecureFragment +import org.mozilla.fenix.databinding.FragmentCreditCardEditorBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.redirectToReAuth import org.mozilla.fenix.ext.settings @@ -63,9 +64,11 @@ class CreditCardEditorFragment : SecureFragment(R.layout.fragment_credit_card_ed ) ) + val binding = FragmentCreditCardEditorBinding.bind(view) + creditCardEditorState = args.creditCard?.toCreditCardEditorState(storage) ?: getInitialCreditCardEditorState() - creditCardEditorView = CreditCardEditorView(view, interactor) + creditCardEditorView = CreditCardEditorView(binding, interactor) creditCardEditorView.bind(creditCardEditorState) } diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementFragment.kt index e54f42e2aa..5d420e2fc6 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsManagementFragment.kt @@ -10,7 +10,6 @@ import android.view.View import android.view.ViewGroup import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController -import kotlinx.android.synthetic.main.fragment_saved_cards.view.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch @@ -18,6 +17,7 @@ import mozilla.components.lib.state.ext.consumeFrom import org.mozilla.fenix.R import org.mozilla.fenix.SecureFragment import org.mozilla.fenix.components.StoreProvider +import org.mozilla.fenix.databinding.ComponentCreditCardsBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.redirectToReAuth import org.mozilla.fenix.ext.showToolbar @@ -51,8 +51,9 @@ class CreditCardsManagementFragment : SecureFragment() { navController = findNavController() ) ) + val binding = ComponentCreditCardsBinding.bind(view) - creditCardsView = CreditCardsManagementView(view.saved_cards_layout, interactor) + creditCardsView = CreditCardsManagementView(binding, interactor) loadCreditCards() diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardEditorView.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardEditorView.kt index 20f650325d..896a663834 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardEditorView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardEditorView.kt @@ -7,8 +7,6 @@ package org.mozilla.fenix.settings.creditcards.view import android.view.View import android.widget.ArrayAdapter import androidx.annotation.VisibleForTesting -import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.fragment_credit_card_editor.* import mozilla.components.concept.storage.CreditCardNumber import mozilla.components.concept.storage.NewCreditCardFields import mozilla.components.concept.storage.UpdatableCreditCardFields @@ -16,6 +14,7 @@ import mozilla.components.support.ktx.android.content.getColorFromAttr import mozilla.components.support.ktx.android.view.hideKeyboard import mozilla.components.support.utils.creditCardIIN import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentCreditCardEditorBinding import org.mozilla.fenix.ext.toEditable import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment import org.mozilla.fenix.settings.creditcards.CreditCardEditorState @@ -31,16 +30,16 @@ import java.util.Locale * Shows a credit card editor for adding or updating a credit card. */ class CreditCardEditorView( - override val containerView: View, + private val binding: FragmentCreditCardEditorBinding, private val interactor: CreditCardEditorInteractor -) : LayoutContainer { +) { /** * Binds the given [CreditCardEditorState] in the [CreditCardEditorFragment]. */ fun bind(state: CreditCardEditorState) { if (state.isEditing) { - delete_button.apply { + binding.deleteButton.apply { visibility = View.VISIBLE setOnClickListener { @@ -49,16 +48,16 @@ class CreditCardEditorView( } } - cancel_button.setOnClickListener { + binding.cancelButton.setOnClickListener { interactor.onCancelButtonClicked() } - save_button.setOnClickListener { + binding.saveButton.setOnClickListener { saveCreditCard(state) } - card_number_input.text = state.cardNumber.toEditable() - name_on_card_input.text = state.billingName.toEditable() + binding.cardNumberInput.text = state.cardNumber.toEditable() + binding.nameOnCardInput.text = state.billingName.toEditable() bindExpiryMonthDropDown(state.expiryMonth) bindExpiryYearDropDown(state.expiryYears) @@ -71,28 +70,28 @@ class CreditCardEditorView( * information. */ internal fun saveCreditCard(state: CreditCardEditorState) { - containerView.hideKeyboard() + binding.root.hideKeyboard() if (validateForm()) { - val cardNumber = card_number_input.text.toString().toCreditCardNumber() + val cardNumber = binding.cardNumberInput.text.toString().toCreditCardNumber() if (state.isEditing) { val fields = UpdatableCreditCardFields( - billingName = name_on_card_input.text.toString(), + billingName = binding.nameOnCardInput.text.toString(), cardNumber = CreditCardNumber.Plaintext(cardNumber), cardNumberLast4 = cardNumber.last4Digits(), - expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(), - expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(), + expiryMonth = (binding.expiryMonthDropDown.selectedItemPosition + 1).toLong(), + expiryYear = binding.expiryYearDropDown.selectedItem.toString().toLong(), cardType = cardNumber.creditCardIIN()?.creditCardIssuerNetwork?.name ?: "" ) interactor.onUpdateCreditCard(state.guid, fields) } else { val fields = NewCreditCardFields( - billingName = name_on_card_input.text.toString(), + billingName = binding.nameOnCardInput.text.toString(), plaintextCardNumber = CreditCardNumber.Plaintext(cardNumber), cardNumberLast4 = cardNumber.last4Digits(), - expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(), - expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(), + expiryMonth = (binding.expiryMonthDropDown.selectedItemPosition + 1).toLong(), + expiryYear = binding.expiryYearDropDown.selectedItem.toString().toLong(), cardType = cardNumber.creditCardIIN()?.creditCardIssuerNetwork?.name ?: "" ) interactor.onSaveCreditCard(fields) @@ -109,26 +108,26 @@ class CreditCardEditorView( internal fun validateForm(): Boolean { var isValid = true - if (card_number_input.text.toString().validateCreditCardNumber()) { - card_number_layout.error = null - card_number_title.setTextColor(containerView.context.getColorFromAttr(R.attr.primaryText)) + if (binding.cardNumberInput.text.toString().validateCreditCardNumber()) { + binding.cardNumberLayout.error = null + binding.cardNumberTitle.setTextColor(binding.root.context.getColorFromAttr(R.attr.primaryText)) } else { isValid = false - card_number_layout.error = - containerView.context.getString(R.string.credit_cards_number_validation_error_message) - card_number_title.setTextColor(containerView.context.getColorFromAttr(R.attr.destructive)) + binding.cardNumberLayout.error = + binding.root.context.getString(R.string.credit_cards_number_validation_error_message) + binding.cardNumberTitle.setTextColor(binding.root.context.getColorFromAttr(R.attr.destructive)) } - if (name_on_card_input.text.toString().isNotBlank()) { - name_on_card_layout.error = null - name_on_card_title.setTextColor(containerView.context.getColorFromAttr(R.attr.primaryText)) + if (binding.nameOnCardInput.text.toString().isNotBlank()) { + binding.nameOnCardInput.error = null + binding.nameOnCardTitle.setTextColor(binding.root.context.getColorFromAttr(R.attr.primaryText)) } else { isValid = false - name_on_card_layout.error = - containerView.context.getString(R.string.credit_cards_name_on_card_validation_error_message) - name_on_card_title.setTextColor(containerView.context.getColorFromAttr(R.attr.destructive)) + binding.nameOnCardLayout.error = + binding.root.context.getString(R.string.credit_cards_name_on_card_validation_error_message) + binding.nameOnCardTitle.setTextColor(binding.root.context.getColorFromAttr(R.attr.destructive)) } return isValid @@ -143,7 +142,7 @@ class CreditCardEditorView( private fun bindExpiryMonthDropDown(expiryMonth: Int) { val adapter = ArrayAdapter( - containerView.context, + binding.root.context, android.R.layout.simple_spinner_dropdown_item ) val dateFormat = SimpleDateFormat("MMMM (MM)", Locale.getDefault()) @@ -156,8 +155,8 @@ class CreditCardEditorView( adapter.add(dateFormat.format(calendar.time)) } - expiry_month_drop_down.adapter = adapter - expiry_month_drop_down.setSelection(expiryMonth - 1) + binding.expiryMonthDropDown.adapter = adapter + binding.expiryMonthDropDown.setSelection(expiryMonth - 1) } /** @@ -169,7 +168,7 @@ class CreditCardEditorView( private fun bindExpiryYearDropDown(expiryYears: Pair) { val adapter = ArrayAdapter( - containerView.context, + binding.root.context, android.R.layout.simple_spinner_dropdown_item ) val (startYear, endYear) = expiryYears @@ -178,7 +177,7 @@ class CreditCardEditorView( adapter.add(year.toString()) } - expiry_year_drop_down.adapter = adapter + binding.expiryYearDropDown.adapter = adapter } companion object { diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsManagementView.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsManagementView.kt index 42b40634da..403b676a13 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsManagementView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardsManagementView.kt @@ -5,12 +5,10 @@ package org.mozilla.fenix.settings.creditcards.view import android.view.LayoutInflater -import android.view.ViewGroup import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager -import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.component_credit_cards.* import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.ComponentCreditCardsBinding import org.mozilla.fenix.settings.creditcards.CreditCardsListState import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor @@ -18,29 +16,29 @@ import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementIn * Shows a list of credit cards. */ class CreditCardsManagementView( - override val containerView: ViewGroup, + val binding: ComponentCreditCardsBinding, val interactor: CreditCardsManagementInteractor -) : LayoutContainer { +) { private val creditCardsAdapter = CreditCardsAdapter(interactor) init { - LayoutInflater.from(containerView.context).inflate(LAYOUT_ID, containerView, true) + LayoutInflater.from(binding.root.context).inflate(LAYOUT_ID, binding.root, true) - credit_cards_list.apply { + binding.creditCardsList.apply { adapter = creditCardsAdapter - layoutManager = LinearLayoutManager(containerView.context) + layoutManager = LinearLayoutManager(binding.root.context) } - add_credit_card_button.setOnClickListener { interactor.onAddCreditCardClick() } + binding.addCreditCardButton.addCreditCardLayout.setOnClickListener { interactor.onAddCreditCardClick() } } /** * Updates the display of the credit cards based on the given [CreditCardsListState]. */ fun update(state: CreditCardsListState) { - progress_bar.isVisible = state.isLoading - credit_cards_list.isVisible = state.creditCards.isNotEmpty() + binding.progressBar.isVisible = state.isLoading + binding.creditCardsList.isVisible = state.creditCards.isNotEmpty() creditCardsAdapter.submitList(state.creditCards) } diff --git a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataFragment.kt index 7839ca965d..f12aae7f1d 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataFragment.kt @@ -11,8 +11,6 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController -import kotlinx.android.synthetic.main.fragment_delete_browsing_data.* -import kotlinx.android.synthetic.main.fragment_delete_browsing_data.view.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers.IO @@ -28,6 +26,7 @@ import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.FragmentDeleteBrowsingDataBinding import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar @@ -40,10 +39,15 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da private var scope: CoroutineScope? = null private lateinit var settings: Settings + private var _binding: FragmentDeleteBrowsingDataBinding? = null + private val binding get() = _binding!! + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val tabsUseCases = requireComponents.useCases.tabsUseCases val downloadUseCases = requireComponents.useCases.downloadUseCases + + _binding = FragmentDeleteBrowsingDataBinding.bind(view) controller = DefaultDeleteBrowsingDataController( tabsUseCases.removeAllTabs, downloadUseCases.removeAllDownloads, @@ -74,7 +78,7 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da } } - view.delete_data?.setOnClickListener { + binding.deleteData.setOnClickListener { askToDelete() } updateDeleteButton() @@ -117,8 +121,8 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da private fun updateDeleteButton() { val enabled = getCheckboxes().any { it.isChecked } - view?.delete_data?.isEnabled = enabled - view?.delete_data?.alpha = if (enabled) ENABLED_ALPHA else DISABLED_ALPHA + binding.deleteData.isEnabled = enabled + binding.deleteData.alpha = if (enabled) ENABLED_ALPHA else DISABLED_ALPHA } private fun askToDelete() { @@ -168,18 +172,18 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da } private fun startDeletion() { - progress_bar.visibility = View.VISIBLE - delete_browsing_data_wrapper.isEnabled = false - delete_browsing_data_wrapper.isClickable = false - delete_browsing_data_wrapper.alpha = DISABLED_ALPHA + binding.progressBar.visibility = View.VISIBLE + binding.deleteBrowsingDataWrapper.isEnabled = false + binding.deleteBrowsingDataWrapper.isClickable = false + binding.deleteBrowsingDataWrapper.alpha = DISABLED_ALPHA } private fun finishDeletion() { - val popAfter = open_tabs_item.isChecked - progress_bar.visibility = View.GONE - delete_browsing_data_wrapper.isEnabled = true - delete_browsing_data_wrapper.isClickable = true - delete_browsing_data_wrapper.alpha = ENABLED_ALPHA + val popAfter = binding.openTabsItem.isChecked + binding.progressBar.visibility = View.GONE + binding.deleteBrowsingDataWrapper.isEnabled = true + binding.deleteBrowsingDataWrapper.isClickable = true + binding.deleteBrowsingDataWrapper.alpha = ENABLED_ALPHA updateItemCounts() @@ -206,7 +210,7 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da override fun onPause() { super.onPause() - progress_bar.visibility = View.GONE + binding.progressBar.visibility = View.GONE } override fun onStop() { @@ -214,6 +218,11 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da scope?.cancel() } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + private fun updateItemCounts() { updateTabCount() updateHistoryCount() @@ -223,7 +232,7 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da } private fun updateTabCount(openTabs: Int = requireComponents.core.store.state.tabs.size) { - view?.open_tabs_item?.apply { + binding.openTabsItem.apply { subtitleView.text = resources.getString( R.string.preferences_delete_browsing_data_tabs_subtitle, openTabs @@ -232,12 +241,12 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da } private fun updateHistoryCount() { - view?.browsing_data_item?.subtitleView?.text = "" + binding.browsingDataItem.subtitleView.text = "" viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { val historyCount = requireComponents.core.historyStorage.getVisited().size launch(Dispatchers.Main) { - view?.browsing_data_item?.apply { + binding.browsingDataItem.apply { subtitleView.text = resources.getString( R.string.preferences_delete_browsing_data_browsing_data_subtitle, @@ -261,14 +270,13 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da } private fun getCheckboxes(): List { - val fragmentView = requireView() return listOf( - fragmentView.open_tabs_item, - fragmentView.browsing_data_item, - fragmentView.cookies_item, - fragmentView.cached_files_item, - fragmentView.site_permissions_item, - fragmentView.downloads_item + binding.openTabsItem, + binding.browsingDataItem, + binding.cookiesItem, + binding.cachedFilesItem, + binding.sitePermissionsItem, + binding.downloadsItem ) } diff --git a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataItem.kt b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataItem.kt index 64f7726285..c8208bd7c7 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataItem.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataItem.kt @@ -11,10 +11,8 @@ import android.view.View import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.withStyledAttributes -import kotlinx.android.synthetic.main.delete_browsing_data_item.view.checkbox -import kotlinx.android.synthetic.main.delete_browsing_data_item.view.subtitle -import kotlinx.android.synthetic.main.delete_browsing_data_item.view.title import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.DeleteBrowsingDataItemBinding class DeleteBrowsingDataItem @JvmOverloads constructor( context: Context, @@ -27,26 +25,33 @@ class DeleteBrowsingDataItem @JvmOverloads constructor( private const val DISABLED_ALPHA = 0.6f } + private var binding: DeleteBrowsingDataItemBinding + val titleView: TextView - get() = title + get() = binding.title val subtitleView: TextView - get() = subtitle + get() = binding.subtitle var isChecked: Boolean - get() = checkbox.isChecked - set(value) { checkbox.isChecked = value } + get() = binding.checkbox.isChecked + set(value) { + binding.checkbox.isChecked = value + } var onCheckListener: ((Boolean) -> Unit)? = null init { - LayoutInflater.from(context).inflate(R.layout.delete_browsing_data_item, this, true) + val view = + LayoutInflater.from(context).inflate(R.layout.delete_browsing_data_item, this, true) + + binding = DeleteBrowsingDataItemBinding.bind(view) setOnClickListener { - checkbox.isChecked = !checkbox.isChecked + binding.checkbox.isChecked = !binding.checkbox.isChecked } - checkbox.setOnCheckedChangeListener { _, isChecked -> + binding.checkbox.setOnCheckedChangeListener { _, isChecked -> onCheckListener?.invoke(isChecked) } @@ -60,10 +65,10 @@ class DeleteBrowsingDataItem @JvmOverloads constructor( R.string.empty_string ) - title.text = resources.getString(titleId) + binding.title.text = resources.getString(titleId) val subtitleText = resources.getString(subtitleId) - subtitle.text = subtitleText - if (subtitleText.isBlank()) subtitle.visibility = View.GONE + binding.subtitle.text = subtitleText + if (subtitleText.isBlank()) binding.subtitle.visibility = View.GONE } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/EditLoginFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/EditLoginFragment.kt index 9a60a4674e..38bd7a66fb 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/EditLoginFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/EditLoginFragment.kt @@ -19,13 +19,13 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import kotlinx.android.synthetic.main.fragment_edit_login.* import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.ktx.android.view.hideKeyboard import org.mozilla.fenix.R import org.mozilla.fenix.components.StoreProvider import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.FragmentEditLoginBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.redirectToReAuth import org.mozilla.fenix.ext.requireComponents @@ -59,9 +59,15 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { private var validPassword = true private var validUsername = true + private var _binding: FragmentEditLoginBinding? = null + private val binding get() = _binding!! + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setHasOptionsMenu(true) + + _binding = FragmentEditLoginBinding.bind(view) + oldLogin = args.savedLoginItem loginsFragmentStore = StoreProvider.get(this) { @@ -83,16 +89,16 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { interactor.findPotentialDuplicates(args.savedLoginItem.guid) // initialize editable values - hostnameText.text = args.savedLoginItem.origin.toEditable() - usernameText.text = args.savedLoginItem.username.toEditable() - passwordText.text = args.savedLoginItem.password.toEditable() + binding.hostnameText.text = args.savedLoginItem.origin.toEditable() + binding.usernameText.text = args.savedLoginItem.username.toEditable() + binding.passwordText.text = args.savedLoginItem.password.toEditable() - clearUsernameTextButton.isEnabled = oldLogin.username.isNotEmpty() + binding.clearUsernameTextButton.isEnabled = oldLogin.username.isNotEmpty() formatEditableValues() setUpClickListeners() setUpTextListeners() - togglePasswordReveal(passwordText, revealPasswordButton) + togglePasswordReveal(binding.passwordText, binding.revealPasswordButton) consumeFrom(loginsFragmentStore) { listOfPossibleDupes = loginsFragmentStore.state.duplicateLogins @@ -100,32 +106,32 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { } private fun formatEditableValues() { - hostnameText.isClickable = false - hostnameText.isFocusable = false - usernameText.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS + binding.hostnameText.isClickable = false + binding.hostnameText.isFocusable = false + binding.usernameText.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS // TODO: extend PasswordTransformationMethod() to change bullets to asterisks - passwordText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD - passwordText.compoundDrawablePadding = + binding.passwordText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD + binding.passwordText.compoundDrawablePadding = requireContext().resources .getDimensionPixelOffset(R.dimen.saved_logins_end_icon_drawable_padding) } private fun setUpClickListeners() { - clearUsernameTextButton.setOnClickListener { - usernameText.text?.clear() - usernameText.isCursorVisible = true - usernameText.hasFocus() - inputLayoutUsername.hasFocus() + binding.clearUsernameTextButton.setOnClickListener { + binding.usernameText.text?.clear() + binding.usernameText.isCursorVisible = true + binding.usernameText.hasFocus() + binding.inputLayoutUsername.hasFocus() it.isEnabled = false } - clearPasswordTextButton.setOnClickListener { - passwordText.text?.clear() - passwordText.isCursorVisible = true - passwordText.hasFocus() - inputLayoutPassword.hasFocus() + binding.clearPasswordTextButton.setOnClickListener { + binding.passwordText.text?.clear() + binding.passwordText.isCursorVisible = true + binding.passwordText.hasFocus() + binding.inputLayoutPassword.hasFocus() } - revealPasswordButton.setOnClickListener { - togglePasswordReveal(passwordText, revealPasswordButton) + binding.revealPasswordButton.setOnClickListener { + togglePasswordReveal(binding.passwordText, binding.revealPasswordButton) } } @@ -136,28 +142,28 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { view?.hideKeyboard() } } - editLoginLayout.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus -> + binding.editLoginLayout.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus -> if (!hasFocus) { view?.hideKeyboard() } } - usernameText.addTextChangedListener(object : TextWatcher { + binding.usernameText.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(u: Editable?) { when (oldLogin.username) { u.toString() -> { usernameChanged = false validUsername = true - inputLayoutUsername.error = null - inputLayoutUsername.errorIconDrawable = null - clearUsernameTextButton.isVisible = true + binding.inputLayoutUsername.error = null + binding.inputLayoutUsername.errorIconDrawable = null + binding.clearUsernameTextButton.isVisible = true } else -> { usernameChanged = true setDupeError() } } - clearUsernameTextButton.isEnabled = u.toString().isNotEmpty() + binding.clearUsernameTextButton.isEnabled = u.toString().isNotEmpty() setSaveButtonState() } @@ -170,30 +176,30 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { } }) - passwordText.addTextChangedListener(object : TextWatcher { + binding.passwordText.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(p: Editable?) { when { p.toString().isEmpty() -> { passwordChanged = true - revealPasswordButton.isVisible = false - clearPasswordTextButton.isVisible = false + binding.revealPasswordButton.isVisible = false + binding.clearPasswordTextButton.isVisible = false setPasswordError() } p.toString() == oldLogin.password -> { passwordChanged = false validPassword = true - inputLayoutPassword.error = null - inputLayoutPassword.errorIconDrawable = null - revealPasswordButton.isVisible = true - clearPasswordTextButton.isVisible = true + binding.inputLayoutPassword.error = null + binding.inputLayoutPassword.errorIconDrawable = null + binding.revealPasswordButton.isVisible = true + binding.clearPasswordTextButton.isVisible = true } else -> { passwordChanged = true validPassword = true - inputLayoutPassword.error = null - inputLayoutPassword.errorIconDrawable = null - revealPasswordButton.isVisible = true - clearPasswordTextButton.isVisible = true + binding.inputLayoutPassword.error = null + binding.inputLayoutPassword.errorIconDrawable = null + binding.revealPasswordButton.isVisible = true + binding.clearPasswordTextButton.isVisible = true } } setSaveButtonState() @@ -213,8 +219,8 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { loginsFragmentStore.state.duplicateLogins.filter { it.username == username }.any() private fun setDupeError() { - if (isDupe(usernameText.text.toString())) { - inputLayoutUsername?.let { + if (isDupe(binding.usernameText.text.toString())) { + binding.inputLayoutUsername.let { usernameChanged = true validUsername = false it.error = context?.getString(R.string.saved_login_duplicate) @@ -224,19 +230,19 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { ContextCompat.getColor(requireContext(), R.color.design_error) ) ) - clearUsernameTextButton.isVisible = false + binding.clearUsernameTextButton.isVisible = false } } else { usernameChanged = true validUsername = true - inputLayoutUsername.error = null - inputLayoutUsername.errorIconDrawable = null - clearUsernameTextButton.isVisible = true + binding.inputLayoutUsername.error = null + binding.inputLayoutUsername.errorIconDrawable = null + binding.clearUsernameTextButton.isVisible = true } } private fun setPasswordError() { - inputLayoutPassword?.let { layout -> + binding.inputLayoutPassword.let { layout -> validPassword = false layout.error = context?.getString(R.string.saved_login_password_required) layout.setErrorIconDrawable(R.drawable.mozac_ic_warning_with_bottom_padding) @@ -277,12 +283,17 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { view?.hideKeyboard() interactor.onSaveLogin( args.savedLoginItem.guid, - usernameText.text.toString(), - passwordText.text.toString() + binding.usernameText.text.toString(), + binding.passwordText.text.toString() ) requireComponents.analytics.metrics.track(Event.EditLoginSave) true } else -> false } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/LoginDetailFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/LoginDetailFragment.kt index bb976de113..17953c7912 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/LoginDetailFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/LoginDetailFragment.kt @@ -21,7 +21,6 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.google.android.material.snackbar.Snackbar -import kotlinx.android.synthetic.main.fragment_login_detail.* import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ObsoleteCoroutinesApi import mozilla.components.lib.state.ext.consumeFrom @@ -31,6 +30,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.StoreProvider import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.FragmentLoginDetailBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.increaseTapArea import org.mozilla.fenix.ext.redirectToReAuth @@ -61,12 +61,16 @@ class LoginDetailFragment : Fragment(R.layout.fragment_login_detail) { private lateinit var menu: Menu private var deleteDialog: AlertDialog? = null + private var _binding: FragmentLoginDetailBinding? = null + private val binding get() = _binding!! + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_login_detail, container, false) + _binding = FragmentLoginDetailBinding.bind(view) savedLoginsStore = StoreProvider.get(this) { LoginsFragmentStore( createInitialLoginsListState(requireContext().settings()) @@ -104,7 +108,7 @@ class LoginDetailFragment : Fragment(R.layout.fragment_login_detail) { ) setUpPasswordReveal() } - togglePasswordReveal(passwordText, revealPasswordButton) + togglePasswordReveal(binding.passwordText, binding.revealPasswordButton) } override fun onCreate(savedInstanceState: Bundle?) { @@ -137,34 +141,34 @@ class LoginDetailFragment : Fragment(R.layout.fragment_login_detail) { } private fun setUpPasswordReveal() { - passwordText.inputType = + binding.passwordText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD - revealPasswordButton.increaseTapArea(BUTTON_INCREASE_DPS) - revealPasswordButton.setOnClickListener { - togglePasswordReveal(passwordText, revealPasswordButton) + binding.revealPasswordButton.increaseTapArea(BUTTON_INCREASE_DPS) + binding.revealPasswordButton.setOnClickListener { + togglePasswordReveal(binding.passwordText, binding.revealPasswordButton) } - passwordText.setOnClickListener { - togglePasswordReveal(passwordText, revealPasswordButton) + binding.passwordText.setOnClickListener { + togglePasswordReveal(binding.passwordText, binding.revealPasswordButton) } } private fun setUpCopyButtons() { - webAddressText.text = login?.origin - openWebAddress.increaseTapArea(BUTTON_INCREASE_DPS) - copyUsername.increaseTapArea(BUTTON_INCREASE_DPS) - copyPassword.increaseTapArea(BUTTON_INCREASE_DPS) + binding.webAddressText.text = login?.origin + binding.openWebAddress.increaseTapArea(BUTTON_INCREASE_DPS) + binding.copyUsername.increaseTapArea(BUTTON_INCREASE_DPS) + binding.copyPassword.increaseTapArea(BUTTON_INCREASE_DPS) - openWebAddress.setOnClickListener { + binding.openWebAddress.setOnClickListener { navigateToBrowser(requireNotNull(login?.origin)) } - usernameText.text = login?.username - copyUsername.setOnClickListener( + binding.usernameText.text = login?.username + binding.copyUsername.setOnClickListener( CopyButtonListener(login?.username, R.string.logins_username_copied) ) - passwordText.text = login?.password - copyPassword.setOnClickListener( + binding.passwordText.text = login?.password + binding.copyPassword.setOnClickListener( CopyButtonListener(login?.password, R.string.logins_password_copied) ) } @@ -247,6 +251,11 @@ class LoginDetailFragment : Fragment(R.layout.fragment_login_detail) { } } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + private companion object { private const val BUTTON_INCREASE_DPS = 24 } diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsFragment.kt index 3a3c4f6d9e..3ccb5491fc 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsFragment.kt @@ -20,7 +20,6 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController -import kotlinx.android.synthetic.main.fragment_saved_logins.view.* import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.concept.menu.MenuController import mozilla.components.concept.menu.Orientation @@ -29,6 +28,7 @@ import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.StoreProvider +import org.mozilla.fenix.databinding.FragmentSavedLoginsBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.redirectToReAuth import org.mozilla.fenix.ext.settings @@ -70,6 +70,8 @@ class SavedLoginsFragment : Fragment() { savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_saved_logins, container, false) + val binding = FragmentSavedLoginsBinding.bind(view) + savedLoginsStore = StoreProvider.get(this) { LoginsFragmentStore( createInitialLoginsListState(requireContext().settings()) @@ -99,7 +101,7 @@ class SavedLoginsFragment : Fragment() { ) savedLoginsListView = SavedLoginsListView( - view.savedLoginsLayout, + binding.savedLoginsLayout, savedLoginsInteractor ) savedLoginsInteractor.loadAndMapLogins() diff --git a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt index c190495d52..6d8d96c0f3 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt @@ -25,8 +25,6 @@ import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog -import kotlinx.android.synthetic.main.fragment_quick_settings_dialog_sheet.* -import kotlinx.android.synthetic.main.fragment_quick_settings_dialog_sheet.view.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.plus @@ -35,6 +33,7 @@ import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.IntentReceiverActivity import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.FragmentQuickSettingsDialogSheetBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.settings.PhoneFeature import com.google.android.material.R as MaterialR @@ -55,6 +54,9 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() { private var tryToRequestPermissions: Boolean = false private val args by navArgs() + private var _binding: FragmentQuickSettingsDialogSheetBinding? = null + private val binding get() = _binding!! + @Suppress("DEPRECATION") // https://github.com/mozilla-mobile/fenix/issues/19920 override fun onCreateView( @@ -64,7 +66,10 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() { ): View { val context = requireContext() val components = context.components + val rootView = inflateRootView(container) + _binding = FragmentQuickSettingsDialogSheetBinding.bind(rootView) + quickSettingsStore = QuickSettingsFragmentStore.createStore( context = context, websiteUrl = args.url, @@ -98,9 +103,9 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() { interactor = QuickSettingsInteractor(quickSettingsController) - websiteInfoView = WebsiteInfoView(rootView.websiteInfoLayout) + websiteInfoView = WebsiteInfoView(binding.websiteInfoLayout) websitePermissionsView = - WebsitePermissionsView(rootView.websitePermissionsLayout, interactor) + WebsitePermissionsView(binding.websitePermissionsLayout, interactor) return rootView } @@ -152,7 +157,8 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() { quickSettingsController.handleAndroidPermissionGranted(it) } } else { - val shouldShowRequestPermissionRationale = permissions.all { shouldShowRequestPermissionRationale(it) } + val shouldShowRequestPermissionRationale = + permissions.all { shouldShowRequestPermissionRationale(it) } if (!shouldShowRequestPermissionRationale && tryToRequestPermissions) { // The user has permanently blocked these permissions and he/she is trying to enabling them. @@ -187,7 +193,7 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() { requestCode == REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS && grantResults.all { it == PERMISSION_GRANTED } private fun showPermissionsView() { - websitePermissionsGroup.isVisible = true + binding.websitePermissionsGroup.isVisible = true } private fun launchIntentReceiver() { diff --git a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsiteInfoView.kt b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsiteInfoView.kt index 1c2d5098c5..a78c1dcf8c 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsiteInfoView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsiteInfoView.kt @@ -5,14 +5,12 @@ package org.mozilla.fenix.settings.quicksettings import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat.getColor import androidx.core.view.isVisible -import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.quicksettings_website_info.* import mozilla.components.support.ktx.android.content.getDrawableWithTint import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.QuicksettingsWebsiteInfoBinding /** * MVI View that knows to display a whether the current website uses a secure connection or not. @@ -23,10 +21,12 @@ import org.mozilla.fenix.R */ class WebsiteInfoView( container: ViewGroup -) : LayoutContainer { - - override val containerView: View = LayoutInflater.from(container.context) - .inflate(R.layout.quicksettings_website_info, container, true) +) { + val binding = QuicksettingsWebsiteInfoBinding.inflate( + LayoutInflater.from(container.context), + container, + false + ) /** * Allows changing what this View displays. @@ -41,24 +41,25 @@ class WebsiteInfoView( } private fun bindUrl(websiteUrl: String) { - url.text = websiteUrl + binding.url.text = websiteUrl } private fun bindTitle(websiteTitle: String) { - title.text = websiteTitle + binding.title.text = websiteTitle } private fun bindCertificateName(cert: String) { - val certificateLabel = containerView.context.getString(R.string.certificate_info_verified_by, cert) - certificateInfo.text = certificateLabel - certificateInfo.isVisible = cert.isNotEmpty() + val certificateLabel = + binding.root.context.getString(R.string.certificate_info_verified_by, cert) + binding.certificateInfo.text = certificateLabel + binding.certificateInfo.isVisible = cert.isNotEmpty() } private fun bindSecurityInfo(uiValues: WebsiteSecurityUiValues) { - val tint = getColor(containerView.context, uiValues.iconTintRes) - securityInfo.setText(uiValues.securityInfoRes) - securityInfoIcon.setImageDrawable( - containerView.context.getDrawableWithTint(uiValues.iconRes, tint) + val tint = getColor(binding.root.context, uiValues.iconTintRes) + binding.securityInfo.setText(uiValues.securityInfoRes) + binding.securityInfoIcon.setImageDrawable( + binding.root.context.getDrawableWithTint(uiValues.iconRes, tint) ) } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsitePermissionsView.kt b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsitePermissionsView.kt index dc1735d337..6e520c5e9a 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsitePermissionsView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsitePermissionsView.kt @@ -14,9 +14,8 @@ import androidx.annotation.VisibleForTesting import androidx.appcompat.widget.AppCompatSpinner import androidx.core.content.ContextCompat import androidx.core.view.isVisible -import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.quicksettings_permissions.view.* import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.QuicksettingsPermissionsBinding import org.mozilla.fenix.settings.PhoneFeature import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY import org.mozilla.fenix.settings.PhoneFeature.CAMERA @@ -65,38 +64,38 @@ interface WebsitePermissionInteractor { * @param interactor [WebsitePermissionInteractor] which will have delegated to all user interactions. */ class WebsitePermissionsView( - override val containerView: ViewGroup, + containerView: ViewGroup, val interactor: WebsitePermissionInteractor -) : LayoutContainer { +) { private val context = containerView.context - val view: View = LayoutInflater.from(context) - .inflate(R.layout.quicksettings_permissions, containerView, true) + val binding = + QuicksettingsPermissionsBinding.inflate(LayoutInflater.from(context), containerView, false) @VisibleForTesting internal var permissionViews: Map = EnumMap( mapOf( - CAMERA to ToggleablePermission(view.cameraLabel, view.cameraStatus), - LOCATION to ToggleablePermission(view.locationLabel, view.locationStatus), + CAMERA to ToggleablePermission(binding.cameraLabel, binding.cameraStatus), + LOCATION to ToggleablePermission(binding.locationLabel, binding.locationStatus), MICROPHONE to ToggleablePermission( - view.microphoneLabel, - view.microphoneStatus + binding.microphoneLabel, + binding.microphoneStatus ), NOTIFICATION to ToggleablePermission( - view.notificationLabel, - view.notificationStatus + binding.notificationLabel, + binding.notificationStatus ), PERSISTENT_STORAGE to ToggleablePermission( - view.persistentStorageLabel, - view.persistentStorageStatus + binding.persistentStorageLabel, + binding.persistentStorageStatus ), MEDIA_KEY_SYSTEM_ACCESS to ToggleablePermission( - view.mediaKeySystemAccessLabel, - view.mediaKeySystemAccessStatus + binding.mediaKeySystemAccessLabel, + binding.mediaKeySystemAccessStatus ), AUTOPLAY to SpinnerPermission( - view.autoplayLabel, - view.autoplayStatus + binding.autoplayLabel, + binding.autoplayStatus ) ) ) diff --git a/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt index 4521cc3654..9f3712c2ad 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt @@ -15,21 +15,11 @@ import android.view.View import android.view.ViewGroup import android.widget.CompoundButton import android.widget.LinearLayout +import android.widget.RadioButton import androidx.constraintlayout.widget.ConstraintLayout import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController -import kotlinx.android.synthetic.main.custom_search_engine.custom_search_engine_form -import kotlinx.android.synthetic.main.custom_search_engine.custom_search_engine_name_field -import kotlinx.android.synthetic.main.custom_search_engine.custom_search_engine_search_string_field -import kotlinx.android.synthetic.main.custom_search_engine.custom_search_engines_learn_more -import kotlinx.android.synthetic.main.custom_search_engine.edit_engine_name -import kotlinx.android.synthetic.main.custom_search_engine.edit_search_string -import kotlinx.android.synthetic.main.fragment_add_search_engine.search_engine_group -import kotlinx.android.synthetic.main.search_engine_radio_button.view.engine_icon -import kotlinx.android.synthetic.main.search_engine_radio_button.view.engine_text -import kotlinx.android.synthetic.main.search_engine_radio_button.view.overflow_menu -import kotlinx.android.synthetic.main.search_engine_radio_button.view.radio_button import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch @@ -43,6 +33,10 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.CustomSearchEngineBinding +import org.mozilla.fenix.databinding.CustomSearchEngineRadioButtonBinding +import org.mozilla.fenix.databinding.FragmentAddSearchEngineBinding +import org.mozilla.fenix.databinding.SearchEngineRadioButtonBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.showToolbar @@ -55,6 +49,10 @@ class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), private var selectedIndex: Int = -1 private val engineViews = mutableListOf() + private var _binding: FragmentAddSearchEngineBinding? = null + private val binding get() = _binding!! + private lateinit var customSearchEngine: CustomSearchEngineBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -77,6 +75,8 @@ class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ) + _binding = FragmentAddSearchEngineBinding.bind(view) + customSearchEngine = binding.customSearchEngine val setupSearchEngineItem: (Int, SearchEngine) -> Unit = { index, engine -> val engineId = engine.id @@ -85,24 +85,24 @@ class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), layoutInflater = layoutInflater, res = requireContext().resources ) - engineItem.id = index - engineItem.tag = engineId - engineItem.radio_button.isChecked = selectedIndex == index - engineViews.add(engineItem) - search_engine_group.addView(engineItem, layoutParams) + engineItem.root.id = index + engineItem.root.tag = engineId + engineItem.radioButton.isChecked = selectedIndex == index + engineViews.add(engineItem.root) + binding.searchEngineGroup.addView(engineItem.root, layoutParams) } availableEngines.forEachIndexed(setupSearchEngineItem) val engineItem = makeCustomButton(layoutInflater) - engineItem.id = CUSTOM_INDEX - engineItem.radio_button.isChecked = selectedIndex == CUSTOM_INDEX - engineViews.add(engineItem) - search_engine_group.addView(engineItem, layoutParams) + engineItem.root.id = CUSTOM_INDEX + engineItem.radioButton.isChecked = selectedIndex == CUSTOM_INDEX + engineViews.add(engineItem.root) + binding.searchEngineGroup.addView(engineItem.root, layoutParams) toggleCustomForm(selectedIndex == CUSTOM_INDEX) - custom_search_engines_learn_more.setOnClickListener { + customSearchEngine.customSearchEnginesLearnMore.setOnClickListener { (activity as HomeActivity).openToBrowserAndLoad( searchTermOrURL = SupportUtils.getSumoURLForTopic( requireContext(), @@ -119,6 +119,11 @@ class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), showToolbar(getString(R.string.search_engine_add_custom_search_engine_title)) } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.add_custom_searchengine_menu, menu) } @@ -143,11 +148,11 @@ class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), @Suppress("ComplexMethod") private fun createCustomEngine() { - custom_search_engine_name_field.error = "" - custom_search_engine_search_string_field.error = "" + customSearchEngine.customSearchEngineNameField.error = "" + customSearchEngine.customSearchEngineSearchStringField.error = "" - val name = edit_engine_name.text?.toString()?.trim() ?: "" - val searchString = edit_search_string.text?.toString() ?: "" + val name = customSearchEngine.editEngineName.text?.toString()?.trim() ?: "" + val searchString = customSearchEngine.editSearchString.text?.toString() ?: "" if (checkForErrors(name, searchString)) { return @@ -163,7 +168,7 @@ class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), when (result) { SearchStringValidator.Result.CannotReach -> { - custom_search_engine_search_string_field.error = resources + customSearchEngine.customSearchEngineSearchStringField.error = resources .getString(R.string.search_add_custom_engine_error_cannot_reach, name) } SearchStringValidator.Result.Success -> { @@ -198,17 +203,17 @@ class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), fun checkForErrors(name: String, searchString: String): Boolean { return when { name.isEmpty() -> { - custom_search_engine_name_field.error = resources + customSearchEngine.customSearchEngineNameField.error = resources .getString(R.string.search_add_custom_engine_error_empty_name) true } searchString.isEmpty() -> { - custom_search_engine_search_string_field.error = + customSearchEngine.customSearchEngineSearchStringField.error = resources.getString(R.string.search_add_custom_engine_error_empty_search_string) true } !searchString.contains("%s") -> { - custom_search_engine_search_string_field.error = + customSearchEngine.customSearchEngineSearchStringField.error = resources.getString(R.string.search_add_custom_engine_error_missing_template) true } @@ -218,14 +223,16 @@ class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { engineViews.forEach { - when (it.radio_button == buttonView) { + when (it.findViewById(R.id.radio_button) == buttonView) { true -> { selectedIndex = it.id } false -> { - it.radio_button.setOnCheckedChangeListener(null) - it.radio_button.isChecked = false - it.radio_button.setOnCheckedChangeListener(this) + it.findViewById(R.id.radio_button).also { radioButton -> + radioButton.setOnCheckedChangeListener(null) + radioButton.isChecked = false + radioButton.setOnCheckedChangeListener(this) + } } } } @@ -233,37 +240,40 @@ class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), toggleCustomForm(selectedIndex == -1) } - private fun makeCustomButton(layoutInflater: LayoutInflater): View { + private fun makeCustomButton(layoutInflater: LayoutInflater): CustomSearchEngineRadioButtonBinding { val wrapper = layoutInflater .inflate(R.layout.custom_search_engine_radio_button, null) as ConstraintLayout - wrapper.setOnClickListener { wrapper.radio_button.isChecked = true } - wrapper.radio_button.setOnCheckedChangeListener(this) - return wrapper + val customSearchEngineRadioButtonBinding = CustomSearchEngineRadioButtonBinding.bind(wrapper) + wrapper.setOnClickListener { customSearchEngineRadioButtonBinding.radioButton.isChecked = true } + customSearchEngineRadioButtonBinding.radioButton.setOnCheckedChangeListener(this) + return customSearchEngineRadioButtonBinding } private fun toggleCustomForm(isEnabled: Boolean) { - custom_search_engine_form.alpha = if (isEnabled) ENABLED_ALPHA else DISABLED_ALPHA - edit_search_string.isEnabled = isEnabled - edit_engine_name.isEnabled = isEnabled - custom_search_engines_learn_more.isEnabled = isEnabled + customSearchEngine.customSearchEngineForm.alpha = if (isEnabled) ENABLED_ALPHA else DISABLED_ALPHA + customSearchEngine.editSearchString.isEnabled = isEnabled + customSearchEngine.editEngineName.isEnabled = isEnabled + customSearchEngine.customSearchEnginesLearnMore.isEnabled = isEnabled } private fun makeButtonFromSearchEngine( engine: SearchEngine, layoutInflater: LayoutInflater, res: Resources - ): View { + ): SearchEngineRadioButtonBinding { val wrapper = layoutInflater .inflate(R.layout.search_engine_radio_button, null) as LinearLayout - wrapper.setOnClickListener { wrapper.radio_button.isChecked = true } - wrapper.radio_button.setOnCheckedChangeListener(this) - wrapper.engine_text.text = engine.name + val searchEngineRadioButtonBinding = SearchEngineRadioButtonBinding.bind(wrapper) + + wrapper.setOnClickListener { searchEngineRadioButtonBinding.radioButton.isChecked = true } + searchEngineRadioButtonBinding.radioButton.setOnCheckedChangeListener(this) + searchEngineRadioButtonBinding.engineText.text = engine.name val iconSize = res.getDimension(R.dimen.preference_icon_drawable_size).toInt() val engineIcon = BitmapDrawable(res, engine.icon) engineIcon.setBounds(0, 0, iconSize, iconSize) - wrapper.engine_icon.setImageDrawable(engineIcon) - wrapper.overflow_menu.visibility = View.GONE - return wrapper + searchEngineRadioButtonBinding.engineIcon.setImageDrawable(engineIcon) + searchEngineRadioButtonBinding.overflowMenu.visibility = View.GONE + return searchEngineRadioButtonBinding } companion object { diff --git a/app/src/main/java/org/mozilla/fenix/settings/search/EditCustomSearchEngineFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/search/EditCustomSearchEngineFragment.kt index b4fd0687bf..7bca15b056 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/search/EditCustomSearchEngineFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/search/EditCustomSearchEngineFragment.kt @@ -13,11 +13,6 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import kotlinx.android.synthetic.main.custom_search_engine.custom_search_engine_name_field -import kotlinx.android.synthetic.main.custom_search_engine.custom_search_engine_search_string_field -import kotlinx.android.synthetic.main.custom_search_engine.custom_search_engines_learn_more -import kotlinx.android.synthetic.main.custom_search_engine.edit_engine_name -import kotlinx.android.synthetic.main.custom_search_engine.edit_search_string import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch @@ -28,6 +23,8 @@ import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar +import org.mozilla.fenix.databinding.CustomSearchEngineBinding +import org.mozilla.fenix.databinding.FragmentAddSearchEngineBinding import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.settings.SupportUtils @@ -40,6 +37,10 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng private val args by navArgs() private lateinit var searchEngine: SearchEngine + private var _binding: FragmentAddSearchEngineBinding? = null + private val binding get() = _binding!! + private lateinit var customSearchEngine: CustomSearchEngineBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -56,10 +57,13 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng val url = searchEngine.resultUrls[0] - edit_engine_name.setText(searchEngine.name) - edit_search_string.setText(url.toEditableUrl()) + _binding = FragmentAddSearchEngineBinding.bind(view) + customSearchEngine = binding.customSearchEngine + + customSearchEngine.editEngineName.setText(searchEngine.name) + customSearchEngine.editSearchString.setText(url.toEditableUrl()) - custom_search_engines_learn_more.setOnClickListener { + customSearchEngine.customSearchEnginesLearnMore.setOnClickListener { (activity as HomeActivity).openToBrowserAndLoad( searchTermOrURL = SupportUtils.getSumoURLForTopic( requireContext(), @@ -76,6 +80,11 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng showToolbar(getString(R.string.search_engine_edit_custom_search_engine_title)) } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.edit_custom_searchengine_menu, menu) } @@ -92,11 +101,11 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng @Suppress("LongMethod") private fun saveCustomEngine() { - custom_search_engine_name_field.error = "" - custom_search_engine_search_string_field.error = "" + customSearchEngine.customSearchEngineNameField.error = "" + customSearchEngine.customSearchEngineSearchStringField.error = "" - val name = edit_engine_name.text?.toString()?.trim() ?: "" - val searchString = edit_search_string.text?.toString() ?: "" + val name = customSearchEngine.editEngineName.text?.toString()?.trim() ?: "" + val searchString = customSearchEngine.editSearchString.text?.toString() ?: "" if (checkForErrors(name, searchString)) { return @@ -112,7 +121,7 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng when (result) { SearchStringValidator.Result.CannotReach -> { - custom_search_engine_search_string_field.error = resources + customSearchEngine.customSearchEngineSearchStringField.error = resources .getString(R.string.search_add_custom_engine_error_cannot_reach, name) } @@ -120,7 +129,8 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng val update = searchEngine.copy( name = name, resultUrls = listOf(searchString.toSearchUrl()), - icon = requireComponents.core.icons.loadIcon(IconRequest(searchString)).await().bitmap + icon = requireComponents.core.icons.loadIcon(IconRequest(searchString)) + .await().bitmap ) requireComponents.useCases.searchUseCases.addSearchEngine(update) @@ -147,17 +157,17 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng private fun checkForErrors(name: String, searchString: String): Boolean { return when { name.isEmpty() -> { - custom_search_engine_name_field.error = resources + customSearchEngine.customSearchEngineNameField.error = resources .getString(R.string.search_add_custom_engine_error_empty_name) true } searchString.isEmpty() -> { - custom_search_engine_search_string_field.error = + customSearchEngine.customSearchEngineSearchStringField.error = resources.getString(R.string.search_add_custom_engine_error_empty_search_string) true } !searchString.contains("%s") -> { - custom_search_engine_search_string_field.error = + customSearchEngine.customSearchEngineSearchStringField.error = resources.getString(R.string.search_add_custom_engine_error_missing_template) true } diff --git a/app/src/main/java/org/mozilla/fenix/settings/search/RadioSearchEngineListPreference.kt b/app/src/main/java/org/mozilla/fenix/settings/search/RadioSearchEngineListPreference.kt index caea80564f..46717f8fe4 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/search/RadioSearchEngineListPreference.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/search/RadioSearchEngineListPreference.kt @@ -18,10 +18,6 @@ import androidx.core.view.isVisible import androidx.navigation.Navigation import androidx.preference.Preference import androidx.preference.PreferenceViewHolder -import kotlinx.android.synthetic.main.search_engine_radio_button.view.engine_icon -import kotlinx.android.synthetic.main.search_engine_radio_button.view.engine_text -import kotlinx.android.synthetic.main.search_engine_radio_button.view.overflow_menu -import kotlinx.android.synthetic.main.search_engine_radio_button.view.radio_button import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.collect @@ -36,6 +32,7 @@ import mozilla.components.lib.state.ext.flow import mozilla.components.support.ktx.android.view.toScope import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged import org.mozilla.fenix.R +import org.mozilla.fenix.databinding.SearchEngineRadioButtonBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.getRootView import org.mozilla.fenix.utils.allowUndo @@ -102,13 +99,16 @@ class RadioSearchEngineListPreference @JvmOverloads constructor( val isCustomSearchEngine = engine.type == SearchEngine.Type.CUSTOM val wrapper = layoutInflater.inflate(itemResId, null) as LinearLayout - wrapper.setOnClickListener { wrapper.radio_button.isChecked = true } - wrapper.radio_button.tag = engine.id - wrapper.radio_button.isChecked = isSelected - wrapper.radio_button.setOnCheckedChangeListener(this) - wrapper.engine_text.text = engine.name - wrapper.overflow_menu.isVisible = allowDeletion || isCustomSearchEngine - wrapper.overflow_menu.setOnClickListener { + + val binding = SearchEngineRadioButtonBinding.bind(wrapper) + + wrapper.setOnClickListener { binding.radioButton.isChecked = true } + binding.radioButton.tag = engine.id + binding.radioButton.isChecked = isSelected + binding.radioButton.setOnCheckedChangeListener(this) + binding.engineText.text = engine.name + binding.overflowMenu.isVisible = allowDeletion || isCustomSearchEngine + binding.overflowMenu.setOnClickListener { SearchEngineMenu( context = context, allowDeletion = allowDeletion, @@ -122,12 +122,12 @@ class RadioSearchEngineListPreference @JvmOverloads constructor( ) } } - ).menuBuilder.build(context).show(wrapper.overflow_menu) + ).menuBuilder.build(context).show(binding.overflowMenu) } val iconSize = res.getDimension(R.dimen.preference_icon_drawable_size).toInt() val engineIcon = BitmapDrawable(res, engine.icon) engineIcon.setBounds(0, 0, iconSize, iconSize) - wrapper.engine_icon.setImageDrawable(engineIcon) + binding.engineIcon.setImageDrawable(engineIcon) return wrapper } diff --git a/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsManagePhoneFeatureFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsManagePhoneFeatureFragment.kt index a5f1bd0a64..618c79c7c0 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsManagePhoneFeatureFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsManagePhoneFeatureFragment.kt @@ -21,20 +21,19 @@ import android.widget.Button import android.widget.RadioButton import androidx.fragment.app.Fragment import androidx.navigation.fragment.navArgs -import kotlinx.android.synthetic.main.fragment_manage_site_permissions_feature_phone.view.* import mozilla.components.feature.sitepermissions.SitePermissionsRules import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ALLOWED -import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ASK_TO_ALLOW import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.BLOCKED import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.databinding.FragmentManageSitePermissionsFeaturePhoneBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar +import org.mozilla.fenix.settings.PhoneFeature import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY_AUDIBLE import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY_INAUDIBLE -import org.mozilla.fenix.settings.PhoneFeature.MEDIA_KEY_SYSTEM_ACCESS import org.mozilla.fenix.settings.setStartCheckedIndicator import org.mozilla.fenix.utils.Settings @@ -49,25 +48,23 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() { private val args by navArgs() private val settings by lazy { requireContext().settings() } private lateinit var blockedByAndroidView: View + private var _binding: FragmentManageSitePermissionsFeaturePhoneBinding? = null + private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - val rootView = inflater.inflate( - R.layout.fragment_manage_site_permissions_feature_phone, - container, - false - ) + ): View { + _binding = FragmentManageSitePermissionsFeaturePhoneBinding.inflate(inflater, container, false) - initFirstRadio(rootView) - initSecondRadio(rootView) - initThirdRadio(rootView) - initFourthRadio(rootView) - bindBlockedByAndroidContainer(rootView) + initFirstRadio() + initSecondRadio() + initThirdRadio() + initFourthRadio() + bindBlockedByAndroidContainer() - return rootView + return binding.root } override fun onResume() { @@ -76,8 +73,13 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() { initBlockedByAndroidView(args.phoneFeature, blockedByAndroidView) } - private fun initFirstRadio(rootView: View) { - with(rootView.ask_to_allow_radio) { + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + private fun initFirstRadio() { + with(binding.askToAllowRadio) { if (args.phoneFeature == AUTOPLAY_AUDIBLE) { text = getString(R.string.preference_option_autoplay_allowed2) setOnClickListener { @@ -91,16 +93,16 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() { getString(R.string.phone_feature_recommended) ) setOnClickListener { - saveActionInSettings(ASK_TO_ALLOW) + saveActionInSettings(SitePermissionsRules.Action.ASK_TO_ALLOW) } - restoreState(ASK_TO_ALLOW) + restoreState(SitePermissionsRules.Action.ASK_TO_ALLOW) visibility = View.VISIBLE } } } - private fun initSecondRadio(rootView: View) { - with(rootView.block_radio) { + private fun initSecondRadio() { + with(binding.blockRadio) { if (args.phoneFeature == AUTOPLAY_AUDIBLE) { text = getCombinedLabel( getString(R.string.preference_option_autoplay_allowed_wifi_only2), @@ -120,8 +122,8 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() { } } - private fun initThirdRadio(rootView: View) { - with(rootView.third_radio) { + private fun initThirdRadio() { + with(binding.thirdRadio) { if (args.phoneFeature == AUTOPLAY_AUDIBLE) { visibility = View.VISIBLE text = getCombinedLabel( @@ -132,7 +134,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() { saveActionInSettings(AUTOPLAY_BLOCK_AUDIBLE) } restoreState(AUTOPLAY_BLOCK_AUDIBLE) - } else if (args.phoneFeature == MEDIA_KEY_SYSTEM_ACCESS) { + } else if (args.phoneFeature == PhoneFeature.MEDIA_KEY_SYSTEM_ACCESS) { visibility = View.VISIBLE text = getString(R.string.preference_option_phone_feature_allowed) setOnClickListener { @@ -145,8 +147,8 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() { } } - private fun initFourthRadio(rootView: View) { - with(rootView.fourth_radio) { + private fun initFourthRadio() { + with(binding.fourthRadio) { if (args.phoneFeature == AUTOPLAY_AUDIBLE) { visibility = View.VISIBLE text = getString(R.string.preference_option_autoplay_blocked3) @@ -215,8 +217,8 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() { context?.components?.useCases?.sessionUseCases?.reload?.invoke() } - private fun bindBlockedByAndroidContainer(rootView: View) { - blockedByAndroidView = rootView.findViewById(R.id.permissions_blocked_container) + private fun bindBlockedByAndroidContainer() { + blockedByAndroidView = binding.root.findViewById(R.id.permissions_blocked_container) initSettingsButton(blockedByAndroidView) } diff --git a/app/src/main/res/layout/fragment_add_search_engine.xml b/app/src/main/res/layout/fragment_add_search_engine.xml index 7a0127fd5a..6ee839df32 100644 --- a/app/src/main/res/layout/fragment_add_search_engine.xml +++ b/app/src/main/res/layout/fragment_add_search_engine.xml @@ -19,6 +19,8 @@ android:id="@+id/search_engine_group" android:layout_width="match_parent" android:layout_height="wrap_content" /> - + diff --git a/app/src/main/res/layout/layout_add_credit_card.xml b/app/src/main/res/layout/layout_add_credit_card.xml index 9d98036530..4857fb1613 100644 --- a/app/src/main/res/layout/layout_add_credit_card.xml +++ b/app/src/main/res/layout/layout_add_credit_card.xml @@ -3,6 +3,7 @@ - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> = listOf(mockk(), mockk()) creditCardsView.update(CreditCardsListState( @@ -50,7 +52,7 @@ class CreditCardsManagementViewTest { isLoading = false )) - assertFalse(view.progress_bar.isVisible) - assertTrue(view.credit_cards_list.isVisible) + assertFalse(componentCreditCardsBinding.progressBar.isVisible) + assertTrue(componentCreditCardsBinding.creditCardsList.isVisible) } } diff --git a/app/src/test/java/org/mozilla/fenix/settings/quicksettings/WebsiteInfoViewTest.kt b/app/src/test/java/org/mozilla/fenix/settings/quicksettings/WebsiteInfoViewTest.kt index a623a34a6e..f393464f09 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/quicksettings/WebsiteInfoViewTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/quicksettings/WebsiteInfoViewTest.kt @@ -6,9 +6,6 @@ package org.mozilla.fenix.settings.quicksettings import android.widget.FrameLayout import androidx.core.view.isVisible -import kotlinx.android.synthetic.main.library_site_item.title -import kotlinx.android.synthetic.main.library_site_item.url -import kotlinx.android.synthetic.main.quicksettings_website_info.* import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -16,16 +13,19 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mozilla.fenix.databinding.QuicksettingsWebsiteInfoBinding import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) class WebsiteInfoViewTest { private lateinit var view: WebsiteInfoView + private lateinit var binding: QuicksettingsWebsiteInfoBinding @Before fun setup() { view = WebsiteInfoView(FrameLayout(testContext)) + binding = view.binding } @Test @@ -37,10 +37,10 @@ class WebsiteInfoViewTest { certificateName = "" )) - assertEquals("https://mozilla.org", view.url.text) - assertEquals("Mozilla", view.title.text) - assertEquals("Secure Connection", view.securityInfo.text) - assertFalse(view.certificateInfo.isVisible) + assertEquals("https://mozilla.org", binding.url.text) + assertEquals("Mozilla", binding.title.text) + assertEquals("Secure Connection", binding.securityInfo.text) + assertFalse(binding.certificateInfo.isVisible) } @Test @@ -52,8 +52,8 @@ class WebsiteInfoViewTest { certificateName = "Certificate" )) - assertEquals("Insecure Connection", view.securityInfo.text) - assertEquals("Verified By: Certificate", view.certificateInfo.text) - assertTrue(view.certificateInfo.isVisible) + assertEquals("Insecure Connection", binding.securityInfo.text) + assertEquals("Verified By: Certificate", binding.certificateInfo.text) + assertTrue(binding.certificateInfo.isVisible) } }