For #17917: Use View binding in settings screens.
This commit is contained in:
parent
84d9f272af
commit
cca7892e91
|
@ -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()
|
||||
|
||||
|
|
|
@ -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<AboutPageItem> {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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<String>(
|
||||
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<Int, Int>) {
|
||||
val adapter =
|
||||
ArrayAdapter<String>(
|
||||
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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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<DeleteBrowsingDataItem> {
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<QuickSettingsSheetDialogFragmentArgs>()
|
||||
|
||||
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() {
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PhoneFeature, PermissionViewHolder> = 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
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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<View>()
|
||||
|
||||
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<RadioButton>(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<RadioButton>(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 {
|
||||
|
|
|
@ -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<EditCustomSearchEngineFragmentArgs>()
|
||||
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
|
||||
|
||||
custom_search_engines_learn_more.setOnClickListener {
|
||||
customSearchEngine.editEngineName.setText(searchEngine.name)
|
||||
customSearchEngine.editSearchString.setText(url.toEditableUrl())
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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<SitePermissionsManagePhoneFeatureFragmentArgs>()
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
android:id="@+id/search_engine_group"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<include layout="@layout/custom_search_engine" />
|
||||
<include
|
||||
android:id="@+id/custom_search_engine"
|
||||
layout="@layout/custom_search_engine" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
|
|
@ -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/. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/add_credit_card_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -5,18 +5,18 @@
|
|||
package org.mozilla.fenix.settings.about
|
||||
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import kotlinx.android.synthetic.main.about_list_item.view.*
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.databinding.AboutListItemBinding
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.settings.about.viewholders.AboutItemViewHolder
|
||||
|
||||
|
@ -66,14 +66,22 @@ class AboutPageAdapterTest {
|
|||
fun `the adapter binds the right item to a ViewHolder`() {
|
||||
val adapter = AboutPageAdapter(listener)
|
||||
val parentView: ViewGroup = mockk(relaxed = true)
|
||||
every { parentView.about_item_title } returns TextView(testContext)
|
||||
|
||||
mockkStatic(AboutListItemBinding::class)
|
||||
val binding: AboutListItemBinding = mockk()
|
||||
|
||||
every { AboutListItemBinding.bind(parentView) } returns binding
|
||||
every { binding.root } returns mockk()
|
||||
|
||||
val viewHolder = spyk(AboutItemViewHolder(parentView, mockk()))
|
||||
|
||||
every {
|
||||
adapter.onCreateViewHolder(
|
||||
parentView,
|
||||
AboutItemViewHolder.LAYOUT_ID
|
||||
)
|
||||
} returns viewHolder
|
||||
|
||||
every { viewHolder.bind(any()) } just Runs
|
||||
|
||||
adapter.submitList(aboutList)
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.android.synthetic.main.about_list_item.view.*
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
|
@ -37,7 +36,7 @@ class AboutItemViewHolderTest {
|
|||
val holder = AboutItemViewHolder(view, listener)
|
||||
holder.bind(item)
|
||||
|
||||
assertEquals("Libraries", view.about_item_title.text)
|
||||
assertEquals("Libraries", holder.binding.aboutItemTitle.text)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -13,7 +13,6 @@ import io.mockk.just
|
|||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.verify
|
||||
import kotlinx.android.synthetic.main.locale_settings_item.view.*
|
||||
import mozilla.components.support.locale.LocaleManager
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Assert.assertEquals
|
||||
|
@ -23,6 +22,7 @@ import org.junit.Before
|
|||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.databinding.LocaleSettingsItemBinding
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import java.util.Locale
|
||||
|
||||
|
@ -34,6 +34,7 @@ class LocaleViewHoldersTest {
|
|||
private lateinit var interactor: LocaleSettingsViewInteractor
|
||||
private lateinit var localeViewHolder: LocaleViewHolder
|
||||
private lateinit var systemLocaleViewHolder: SystemLocaleViewHolder
|
||||
private lateinit var localeSettingsItemBinding: LocaleSettingsItemBinding
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
|
@ -42,6 +43,8 @@ class LocaleViewHoldersTest {
|
|||
|
||||
view = LayoutInflater.from(testContext)
|
||||
.inflate(R.layout.locale_settings_item, null)
|
||||
|
||||
localeSettingsItemBinding = LocaleSettingsItemBinding.bind(view)
|
||||
interactor = mockk()
|
||||
|
||||
localeViewHolder = LocaleViewHolder(view, selectedLocale, interactor)
|
||||
|
@ -52,9 +55,9 @@ class LocaleViewHoldersTest {
|
|||
fun `bind LocaleViewHolder`() {
|
||||
localeViewHolder.bind(selectedLocale)
|
||||
|
||||
assertEquals("English (United States)", view.locale_title_text.text)
|
||||
assertEquals("English (United States)", view.locale_subtitle_text.text)
|
||||
assertFalse(view.locale_selected_icon.isVisible)
|
||||
assertEquals("English (United States)", localeSettingsItemBinding.localeTitleText.text)
|
||||
assertEquals("English (United States)", localeSettingsItemBinding.localeSubtitleText.text)
|
||||
assertFalse(localeSettingsItemBinding.localeSelectedIcon.isVisible)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -74,8 +77,8 @@ class LocaleViewHoldersTest {
|
|||
|
||||
localeViewHolder.bind(otherLocale)
|
||||
|
||||
assertEquals("Vèneto", view.locale_title_text.text)
|
||||
assertEquals("Venetian", view.locale_subtitle_text.text)
|
||||
assertEquals("Vèneto", localeSettingsItemBinding.localeTitleText.text)
|
||||
assertEquals("Venetian", localeSettingsItemBinding.localeSubtitleText.text)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -85,17 +88,17 @@ class LocaleViewHoldersTest {
|
|||
|
||||
localeViewHolder.bind(otherLocale)
|
||||
|
||||
assertEquals("Yyy", view.locale_title_text.text)
|
||||
assertEquals("Yyy", view.locale_subtitle_text.text)
|
||||
assertEquals("Yyy", localeSettingsItemBinding.localeTitleText.text)
|
||||
assertEquals("Yyy", localeSettingsItemBinding.localeSubtitleText.text)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `bind SystemLocaleViewHolder`() {
|
||||
systemLocaleViewHolder.bind(selectedLocale)
|
||||
|
||||
assertEquals("Follow device language", view.locale_title_text.text)
|
||||
assertEquals("English (United States)", view.locale_subtitle_text.text)
|
||||
assertTrue(view.locale_selected_icon.isVisible)
|
||||
assertEquals("Follow device language", localeSettingsItemBinding.localeTitleText.text)
|
||||
assertEquals("English (United States)", localeSettingsItemBinding.localeSubtitleText.text)
|
||||
assertTrue(localeSettingsItemBinding.localeSelectedIcon.isVisible)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -10,7 +10,6 @@ import io.mockk.every
|
|||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import kotlinx.android.synthetic.main.fragment_credit_card_editor.view.*
|
||||
import mozilla.components.concept.storage.CreditCard
|
||||
import mozilla.components.concept.storage.CreditCardNumber
|
||||
import mozilla.components.concept.storage.NewCreditCardFields
|
||||
|
@ -26,6 +25,7 @@ import org.junit.Before
|
|||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.databinding.FragmentCreditCardEditorBinding
|
||||
import org.mozilla.fenix.ext.toEditable
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment.Companion.NUMBER_OF_YEARS_TO_SHOW
|
||||
|
@ -41,6 +41,7 @@ class CreditCardEditorViewTest {
|
|||
private lateinit var creditCardEditorView: CreditCardEditorView
|
||||
private lateinit var storage: AutofillCreditCardsAddressesStorage
|
||||
private lateinit var crypto: AutofillCrypto
|
||||
private lateinit var fragmentCreditCardEditorBinding: FragmentCreditCardEditorBinding
|
||||
|
||||
private val cardNumber = "4111111111111111"
|
||||
private val creditCard = CreditCard(
|
||||
|
@ -60,6 +61,7 @@ class CreditCardEditorViewTest {
|
|||
@Before
|
||||
fun setup() {
|
||||
view = LayoutInflater.from(testContext).inflate(R.layout.fragment_credit_card_editor, null)
|
||||
fragmentCreditCardEditorBinding = FragmentCreditCardEditorBinding.bind(view)
|
||||
interactor = mockk(relaxed = true)
|
||||
storage = mockk(relaxed = true)
|
||||
crypto = mockk(relaxed = true)
|
||||
|
@ -67,7 +69,7 @@ class CreditCardEditorViewTest {
|
|||
every { storage.getCreditCardCrypto() } returns crypto
|
||||
every { crypto.decrypt(any(), any()) } returns CreditCardNumber.Plaintext(cardNumber)
|
||||
|
||||
creditCardEditorView = spyk(CreditCardEditorView(view, interactor))
|
||||
creditCardEditorView = spyk(CreditCardEditorView(fragmentCreditCardEditorBinding, interactor))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -78,37 +80,37 @@ class CreditCardEditorViewTest {
|
|||
val startYear = calendar.get(Calendar.YEAR)
|
||||
val endYear = startYear + NUMBER_OF_YEARS_TO_SHOW - 1
|
||||
|
||||
assertEquals("", view.card_number_input.text.toString())
|
||||
assertEquals("", view.name_on_card_input.text.toString())
|
||||
assertEquals("", fragmentCreditCardEditorBinding.cardNumberInput.text.toString())
|
||||
assertEquals("", fragmentCreditCardEditorBinding.nameOnCardInput.text.toString())
|
||||
|
||||
with(view.expiry_month_drop_down) {
|
||||
with(fragmentCreditCardEditorBinding.expiryMonthDropDown) {
|
||||
assertEquals(12, count)
|
||||
assertEquals("January (01)", selectedItem.toString())
|
||||
assertEquals("December (12)", getItemAtPosition(count - 1).toString())
|
||||
}
|
||||
|
||||
with(view.expiry_year_drop_down) {
|
||||
with(fragmentCreditCardEditorBinding.expiryYearDropDown) {
|
||||
assertEquals(10, count)
|
||||
assertEquals(startYear.toString(), selectedItem.toString())
|
||||
assertEquals(endYear.toString(), getItemAtPosition(count - 1).toString())
|
||||
}
|
||||
|
||||
assertEquals(View.GONE, view.delete_button.visibility)
|
||||
assertEquals(View.GONE, fragmentCreditCardEditorBinding.deleteButton.visibility)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN a credit card THEN credit card form inputs are displaying the provided credit card information`() {
|
||||
creditCardEditorView.bind(creditCard.toCreditCardEditorState(storage))
|
||||
|
||||
assertEquals(cardNumber, view.card_number_input.text.toString())
|
||||
assertEquals(creditCard.billingName, view.name_on_card_input.text.toString())
|
||||
assertEquals(cardNumber, fragmentCreditCardEditorBinding.cardNumberInput.text.toString())
|
||||
assertEquals(creditCard.billingName, fragmentCreditCardEditorBinding.nameOnCardInput.text.toString())
|
||||
|
||||
with(view.expiry_month_drop_down) {
|
||||
with(fragmentCreditCardEditorBinding.expiryMonthDropDown) {
|
||||
assertEquals(12, count)
|
||||
assertEquals("May (05)", selectedItem.toString())
|
||||
}
|
||||
|
||||
with(view.expiry_year_drop_down) {
|
||||
with(fragmentCreditCardEditorBinding.expiryYearDropDown) {
|
||||
val endYear = creditCard.expiryYear + NUMBER_OF_YEARS_TO_SHOW - 1
|
||||
|
||||
assertEquals(10, count)
|
||||
|
@ -121,9 +123,9 @@ class CreditCardEditorViewTest {
|
|||
fun `GIVEN a credit card WHEN the delete card button is clicked THEN interactor is called`() {
|
||||
creditCardEditorView.bind(creditCard.toCreditCardEditorState(storage))
|
||||
|
||||
assertEquals(View.VISIBLE, view.delete_button.visibility)
|
||||
assertEquals(View.VISIBLE, fragmentCreditCardEditorBinding.deleteButton.visibility)
|
||||
|
||||
view.delete_button.performClick()
|
||||
fragmentCreditCardEditorBinding.deleteButton.performClick()
|
||||
|
||||
verify { interactor.onDeleteCardButtonClicked(creditCard.guid) }
|
||||
}
|
||||
|
@ -132,7 +134,7 @@ class CreditCardEditorViewTest {
|
|||
fun `WHEN the cancel button is clicked THEN interactor is called`() {
|
||||
creditCardEditorView.bind(getInitialCreditCardEditorState())
|
||||
|
||||
view.cancel_button.performClick()
|
||||
fragmentCreditCardEditorBinding.cancelButton.performClick()
|
||||
|
||||
verify { interactor.onCancelButtonClicked() }
|
||||
}
|
||||
|
@ -148,11 +150,11 @@ class CreditCardEditorViewTest {
|
|||
val expiryMonth = 5
|
||||
val expiryYear = calendar.get(Calendar.YEAR)
|
||||
|
||||
view.card_number_input.text = cardNumber.toEditable()
|
||||
view.name_on_card_input.text = billingName.toEditable()
|
||||
view.expiry_month_drop_down.setSelection(expiryMonth - 1)
|
||||
fragmentCreditCardEditorBinding.cardNumberInput.text = cardNumber.toEditable()
|
||||
fragmentCreditCardEditorBinding.nameOnCardInput.text = billingName.toEditable()
|
||||
fragmentCreditCardEditorBinding.expiryMonthDropDown.setSelection(expiryMonth - 1)
|
||||
|
||||
view.save_button.performClick()
|
||||
fragmentCreditCardEditorBinding.saveButton.performClick()
|
||||
|
||||
verify {
|
||||
creditCardEditorView.validateForm()
|
||||
|
@ -174,9 +176,9 @@ class CreditCardEditorViewTest {
|
|||
}
|
||||
|
||||
billingName = ""
|
||||
view.name_on_card_input.text = billingName.toEditable()
|
||||
fragmentCreditCardEditorBinding.nameOnCardInput.text = billingName.toEditable()
|
||||
|
||||
view.save_button.performClick()
|
||||
fragmentCreditCardEditorBinding.saveButton.performClick()
|
||||
|
||||
assertFalse(creditCardEditorView.validateForm())
|
||||
|
||||
|
@ -205,11 +207,11 @@ class CreditCardEditorViewTest {
|
|||
val expiryMonth = 5
|
||||
val expiryYear = calendar.get(Calendar.YEAR)
|
||||
|
||||
view.card_number_input.text = cardNumber.toEditable()
|
||||
view.name_on_card_input.text = billingName.toEditable()
|
||||
view.expiry_month_drop_down.setSelection(expiryMonth - 1)
|
||||
fragmentCreditCardEditorBinding.cardNumberInput.text = cardNumber.toEditable()
|
||||
fragmentCreditCardEditorBinding.nameOnCardInput.text = billingName.toEditable()
|
||||
fragmentCreditCardEditorBinding.expiryMonthDropDown.setSelection(expiryMonth - 1)
|
||||
|
||||
view.save_button.performClick()
|
||||
fragmentCreditCardEditorBinding.saveButton.performClick()
|
||||
|
||||
verify {
|
||||
creditCardEditorView.validateForm()
|
||||
|
@ -242,11 +244,11 @@ class CreditCardEditorViewTest {
|
|||
val expiryMonth = 5
|
||||
val expiryYear = calendar.get(Calendar.YEAR)
|
||||
|
||||
view.card_number_input.text = cardNumber.toEditable()
|
||||
view.name_on_card_input.text = billingName.toEditable()
|
||||
view.expiry_month_drop_down.setSelection(expiryMonth - 1)
|
||||
fragmentCreditCardEditorBinding.cardNumberInput.text = cardNumber.toEditable()
|
||||
fragmentCreditCardEditorBinding.nameOnCardInput.text = billingName.toEditable()
|
||||
fragmentCreditCardEditorBinding.expiryMonthDropDown.setSelection(expiryMonth - 1)
|
||||
|
||||
view.save_button.performClick()
|
||||
fragmentCreditCardEditorBinding.saveButton.performClick()
|
||||
|
||||
verify {
|
||||
creditCardEditorView.validateForm()
|
||||
|
@ -272,7 +274,7 @@ class CreditCardEditorViewTest {
|
|||
fun `GIVEN a valid credit card WHEN the save button is clicked THEN interactor is called`() {
|
||||
creditCardEditorView.bind(creditCard.toCreditCardEditorState(storage))
|
||||
|
||||
view.save_button.performClick()
|
||||
fragmentCreditCardEditorBinding.saveButton.performClick()
|
||||
|
||||
verify {
|
||||
interactor.onUpdateCreditCard(
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.android.synthetic.main.credit_card_list_item.view.*
|
||||
import mozilla.components.concept.storage.CreditCard
|
||||
import mozilla.components.concept.storage.CreditCardNumber
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
|
@ -17,6 +16,7 @@ import org.junit.Assert.assertEquals
|
|||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.databinding.CreditCardListItemBinding
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor
|
||||
import org.mozilla.fenix.settings.creditcards.view.CreditCardItemViewHolder
|
||||
|
@ -26,6 +26,7 @@ class CreditCardItemViewHolderTest {
|
|||
|
||||
private lateinit var view: View
|
||||
private lateinit var interactor: CreditCardsManagementInteractor
|
||||
private lateinit var binding: CreditCardListItemBinding
|
||||
|
||||
private val creditCard = CreditCard(
|
||||
guid = "id",
|
||||
|
@ -44,6 +45,7 @@ class CreditCardItemViewHolderTest {
|
|||
@Before
|
||||
fun setup() {
|
||||
view = LayoutInflater.from(testContext).inflate(CreditCardItemViewHolder.LAYOUT_ID, null)
|
||||
binding = CreditCardListItemBinding.bind(view)
|
||||
interactor = mockk(relaxed = true)
|
||||
}
|
||||
|
||||
|
@ -51,8 +53,8 @@ class CreditCardItemViewHolderTest {
|
|||
fun `GIVEN a new credit card item on bind THEN set the card number and expiry date text`() {
|
||||
CreditCardItemViewHolder(view, interactor).bind(creditCard)
|
||||
|
||||
assertEquals(creditCard.obfuscatedCardNumber, view.credit_card_number.text)
|
||||
assertEquals("0${creditCard.expiryMonth}/${creditCard.expiryYear}", view.expiry_date.text)
|
||||
assertEquals(creditCard.obfuscatedCardNumber, binding.creditCardNumber.text)
|
||||
assertEquals("0${creditCard.expiryMonth}/${creditCard.expiryYear}", binding.expiryDate.text)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.view.LayoutInflater
|
|||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import io.mockk.mockk
|
||||
import kotlinx.android.synthetic.main.component_credit_cards.view.*
|
||||
import mozilla.components.concept.storage.CreditCard
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Assert.assertFalse
|
||||
|
@ -17,6 +16,7 @@ import org.junit.Before
|
|||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.databinding.ComponentCreditCardsBinding
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor
|
||||
import org.mozilla.fenix.settings.creditcards.view.CreditCardsManagementView
|
||||
|
@ -27,22 +27,24 @@ class CreditCardsManagementViewTest {
|
|||
private lateinit var view: ViewGroup
|
||||
private lateinit var interactor: CreditCardsManagementInteractor
|
||||
private lateinit var creditCardsView: CreditCardsManagementView
|
||||
private lateinit var componentCreditCardsBinding: ComponentCreditCardsBinding
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
view = LayoutInflater.from(testContext).inflate(CreditCardsManagementView.LAYOUT_ID, null)
|
||||
.findViewById(R.id.credit_cards_wrapper)
|
||||
componentCreditCardsBinding = ComponentCreditCardsBinding.bind(view)
|
||||
interactor = mockk(relaxed = true)
|
||||
|
||||
creditCardsView = CreditCardsManagementView(view, interactor)
|
||||
creditCardsView = CreditCardsManagementView(componentCreditCardsBinding, interactor)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdate() {
|
||||
creditCardsView.update(CreditCardsListState(creditCards = emptyList()))
|
||||
|
||||
assertTrue(view.progress_bar.isVisible)
|
||||
assertFalse(view.credit_cards_list.isVisible)
|
||||
assertTrue(componentCreditCardsBinding.progressBar.isVisible)
|
||||
assertFalse(componentCreditCardsBinding.creditCardsList.isVisible)
|
||||
|
||||
val creditCards: List<CreditCard> = 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue