diff --git a/app/src/main/java/org/mozilla/fenix/BrowserDirection.kt b/app/src/main/java/org/mozilla/fenix/BrowserDirection.kt index f33b8e107..9cc7ad3a1 100644 --- a/app/src/main/java/org/mozilla/fenix/BrowserDirection.kt +++ b/app/src/main/java/org/mozilla/fenix/BrowserDirection.kt @@ -20,7 +20,6 @@ enum class BrowserDirection(@IdRes val fragmentId: Int) { FromSearchDialog(R.id.searchDialogFragment), FromSettings(R.id.settingsFragment), FromBookmarks(R.id.bookmarkFragment), - FromBookmarkSearchDialog(R.id.bookmarkSearchDialogFragment), FromHistory(R.id.historyFragment), FromHistorySearchDialog(R.id.historySearchDialogFragment), FromHistoryMetadataGroup(R.id.historyMetadataGroupFragment), diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index e9ef9a566..3a1fce6f9 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -997,8 +997,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { SettingsFragmentDirections.actionGlobalBrowser(customTabSessionId) BrowserDirection.FromBookmarks -> BookmarkFragmentDirections.actionGlobalBrowser(customTabSessionId) - BrowserDirection.FromBookmarkSearchDialog -> - SearchDialogFragmentDirections.actionGlobalBrowser(customTabSessionId) BrowserDirection.FromHistory -> HistoryFragmentDirections.actionGlobalBrowser(customTabSessionId) BrowserDirection.FromHistorySearchDialog -> diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkController.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkController.kt index a91b16e7d..7d0a0b326 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkController.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkController.kt @@ -28,7 +28,6 @@ import org.mozilla.fenix.ext.bookmarkStorage import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.navigateSafe -import org.mozilla.fenix.utils.Settings @VisibleForTesting internal const val WARN_OPEN_ALL_SIZE = 15 @@ -86,7 +85,6 @@ class DefaultBookmarkController( private val deleteBookmarkFolder: (Set) -> Unit, private val showTabTray: (Boolean) -> Unit, private val warnLargeOpenAll: (Int, () -> Unit) -> Unit, - private val settings: Settings, ) : BookmarkController { private val resources: Resources = activity.resources @@ -256,13 +254,10 @@ class DefaultBookmarkController( } override fun handleSearch() { - val directions = if (settings.showUnifiedSearchFeature) { - BookmarkFragmentDirections.actionGlobalSearchDialog(sessionId = null) - } else { - BookmarkFragmentDirections.actionBookmarkFragmentToBookmarkSearchDialogFragment() - } - - navController.navigateSafe(R.id.bookmarkFragment, directions) + navController.navigateSafe( + R.id.bookmarkFragment, + BookmarkFragmentDirections.actionGlobalSearchDialog(sessionId = null), + ) } private fun openInNewTabAndShow( diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt index abc69cb14..2108dc143 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt @@ -107,7 +107,6 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan deleteBookmarkFolder = ::showRemoveFolderDialog, showTabTray = ::showTabTray, warnLargeOpenAll = ::warnLargeOpenAll, - settings = requireComponents.settings, ), ) diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchController.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchController.kt deleted file mode 100644 index e88f0678f..000000000 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchController.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks - -import mozilla.components.concept.engine.EngineSession.LoadUrlFlags -import mozilla.components.service.glean.private.NoExtras -import org.mozilla.fenix.BrowserDirection -import org.mozilla.fenix.GleanMetrics.BookmarksManagement -import org.mozilla.fenix.HomeActivity - -/** - * An interface that handles the view manipulation of the Bookmark Search, triggered by the Interactor - */ -interface BookmarkSearchController { - fun handleEditingCancelled() - fun handleTextChanged(text: String) - fun handleUrlTapped(url: String, flags: LoadUrlFlags = LoadUrlFlags.none()) -} - -class BookmarkSearchDialogController( - private val activity: HomeActivity, - private val fragmentStore: BookmarkSearchFragmentStore, - private val clearToolbarFocus: () -> Unit, -) : BookmarkSearchController { - - override fun handleEditingCancelled() { - clearToolbarFocus() - } - - override fun handleTextChanged(text: String) { - fragmentStore.dispatch(BookmarkSearchFragmentAction.UpdateQuery(text)) - } - - override fun handleUrlTapped(url: String, flags: LoadUrlFlags) { - BookmarksManagement.searchResultTapped.record(NoExtras()) - clearToolbarFocus() - - activity.openToBrowserAndLoad( - searchTermOrURL = url, - newTab = true, - from = BrowserDirection.FromBookmarkSearchDialog, - flags = flags, - ) - } -} diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchDialogFragment.kt deleted file mode 100644 index eb288b072..000000000 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchDialogFragment.kt +++ /dev/null @@ -1,314 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks - -import android.annotation.SuppressLint -import android.app.Activity -import android.app.Dialog -import android.content.Context -import android.content.DialogInterface -import android.content.Intent -import android.os.Build -import android.os.Bundle -import android.speech.RecognizerIntent -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.ViewStub -import android.view.accessibility.AccessibilityEvent -import android.view.inputmethod.InputMethodManager -import androidx.activity.result.ActivityResult -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AppCompatDialogFragment -import androidx.appcompat.content.res.AppCompatResources -import androidx.constraintlayout.widget.ConstraintProperties.BOTTOM -import androidx.constraintlayout.widget.ConstraintProperties.PARENT_ID -import androidx.constraintlayout.widget.ConstraintProperties.TOP -import androidx.constraintlayout.widget.ConstraintSet -import androidx.core.view.isVisible -import androidx.lifecycle.lifecycleScope -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.launch -import mozilla.components.browser.toolbar.BrowserToolbar -import mozilla.components.lib.state.ext.consumeFlow -import mozilla.components.lib.state.ext.consumeFrom -import mozilla.components.support.base.feature.UserInteractionHandler -import mozilla.components.support.ktx.android.view.hideKeyboard -import org.mozilla.fenix.BrowserDirection -import org.mozilla.fenix.HomeActivity -import org.mozilla.fenix.R -import org.mozilla.fenix.components.toolbar.ToolbarPosition -import org.mozilla.fenix.databinding.FragmentBookmarkSearchDialogBinding -import org.mozilla.fenix.databinding.SearchSuggestionsHintBinding -import org.mozilla.fenix.ext.settings -import org.mozilla.fenix.library.bookmarks.awesomebar.AwesomeBarView -import org.mozilla.fenix.library.bookmarks.toolbar.ToolbarView -import org.mozilla.fenix.settings.SupportUtils - -@Suppress("TooManyFunctions", "LargeClass") -class BookmarkSearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { - private var _binding: FragmentBookmarkSearchDialogBinding? = null - private val binding get() = _binding!! - - private lateinit var interactor: BookmarkSearchDialogInteractor - private lateinit var store: BookmarkSearchFragmentStore - private lateinit var toolbarView: ToolbarView - private lateinit var awesomeBarView: AwesomeBarView - - private val speechIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH) - private var voiceSearchButtonAlreadyAdded = false - private var dialogHandledAction = false - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setStyle(STYLE_NO_TITLE, R.style.SearchDialogStyle) - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - return object : Dialog(requireContext(), this.theme) { - @Deprecated("Deprecated in Java") - override fun onBackPressed() { - this@BookmarkSearchDialogFragment.onBackPressed() - } - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = FragmentBookmarkSearchDialogBinding.inflate(inflater, container, false) - val activity = requireActivity() as HomeActivity - - store = BookmarkSearchFragmentStore( - createInitialBookmarkSearchFragmentState(), - ) - - interactor = BookmarkSearchDialogInteractor( - BookmarkSearchDialogController( - activity = activity, - fragmentStore = store, - clearToolbarFocus = { - dialogHandledAction = true - toolbarView.view.hideKeyboard() - toolbarView.view.clearFocus() - }, - ), - ) - - toolbarView = ToolbarView( - context = requireContext(), - interactor = interactor, - isPrivate = false, - view = binding.toolbar, - ) - - val awesomeBar = binding.awesomeBar - - awesomeBarView = AwesomeBarView( - activity, - interactor, - awesomeBar, - ) - - awesomeBarView.view.setOnEditSuggestionListener(toolbarView.view::setSearchTerms) - - return binding.root - } - - @SuppressLint("ClickableViewAccessibility") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - setupConstraints(view) - - binding.searchWrapper.setOnTouchListener { _, _ -> - dismissAllowingStateLoss() - true - } - val stubListener = ViewStub.OnInflateListener { _, inflated -> - val searchSuggestionHintBinding = SearchSuggestionsHintBinding.bind(inflated) - - searchSuggestionHintBinding.learnMore.setOnClickListener { - (activity as HomeActivity) - .openToBrowserAndLoad( - searchTermOrURL = SupportUtils.getGenericSumoURLForTopic( - SupportUtils.SumoTopic.SEARCH_SUGGESTION, - ), - newTab = true, - from = BrowserDirection.FromBookmarkSearchDialog, - ) - } - - searchSuggestionHintBinding.allow.setOnClickListener { - inflated.visibility = View.GONE - requireContext().settings().also { - it.shouldShowSearchSuggestionsInPrivate = true - it.showSearchSuggestionsInPrivateOnboardingFinished = true - } - } - - searchSuggestionHintBinding.dismiss.setOnClickListener { - inflated.visibility = View.GONE - requireContext().settings().also { - it.shouldShowSearchSuggestionsInPrivate = false - it.showSearchSuggestionsInPrivateOnboardingFinished = true - } - } - - searchSuggestionHintBinding.text.text = - getString(R.string.search_suggestions_onboarding_text, getString(R.string.app_name)) - - searchSuggestionHintBinding.title.text = - getString(R.string.search_suggestions_onboarding_title) - } - - binding.searchSuggestionsHintDivider.isVisible = false - binding.searchSuggestionsHint.isVisible = false - binding.searchSuggestionsHint.setOnInflateListener((stubListener)) - if (view.context.settings().accessibilityServicesEnabled) { - updateAccessibilityTraversalOrder() - } - - addVoiceSearchButton() - observeAwesomeBarState() - - consumeFrom(store) { - toolbarView.update(it) - awesomeBarView.update(it) - } - } - - private fun observeAwesomeBarState() = consumeFlow(store) { flow -> - flow.map { state -> state.query.isNotBlank() } - .distinctUntilChanged() - .collect { shouldShowAwesomebar -> - binding.awesomeBar.visibility = if (shouldShowAwesomebar) { - View.VISIBLE - } else { - View.INVISIBLE - } - } - } - - private fun updateAccessibilityTraversalOrder() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) { - viewLifecycleOwner.lifecycleScope.launch { - binding.searchWrapper.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) - } - } - } - - override fun onPause() { - super.onPause() - view?.hideKeyboard() - } - - override fun onDestroyView() { - super.onDestroyView() - - _binding = null - } - - /* - * This way of dismissing the keyboard is needed to smoothly dismiss the keyboard while the dialog - * is also dismissing. - */ - private fun hideDeviceKeyboard() { - // If the interactor/controller has handled a search event itself, it will hide the keyboard. - if (!dialogHandledAction) { - val imm = - requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(view?.windowToken, InputMethodManager.HIDE_IMPLICIT_ONLY) - } - } - - override fun onDismiss(dialog: DialogInterface) { - super.onDismiss(dialog) - hideDeviceKeyboard() - } - - override fun onBackPressed(): Boolean { - view?.hideKeyboard() - dismissAllowingStateLoss() - - return true - } - - private fun setupConstraints(view: View) { - if (view.context.settings().toolbarPosition == ToolbarPosition.BOTTOM) { - ConstraintSet().apply { - clone(binding.searchWrapper) - - clear(binding.toolbar.id, TOP) - connect(binding.toolbar.id, BOTTOM, PARENT_ID, BOTTOM) - - clear(binding.pillWrapper.id, BOTTOM) - connect(binding.pillWrapper.id, BOTTOM, binding.toolbar.id, TOP) - - clear(binding.awesomeBar.id, TOP) - clear(binding.awesomeBar.id, BOTTOM) - connect(binding.awesomeBar.id, TOP, binding.searchSuggestionsHint.id, BOTTOM) - connect(binding.awesomeBar.id, BOTTOM, binding.pillWrapper.id, TOP) - - clear(binding.searchSuggestionsHint.id, TOP) - clear(binding.searchSuggestionsHint.id, BOTTOM) - connect(binding.searchSuggestionsHint.id, TOP, PARENT_ID, TOP) - connect(binding.searchSuggestionsHint.id, BOTTOM, binding.searchHintBottomBarrier.id, TOP) - - applyTo(binding.searchWrapper) - } - } - } - - private val startVoiceSearchForResult = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> - if (result.resultCode == Activity.RESULT_OK) { - val intent = result.data - intent?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)?.first()?.also { - toolbarView.view.edit.updateUrl(url = it, shouldHighlight = true) - interactor.onTextChanged(it) - toolbarView.view.edit.focus() - } - } - } - - private fun addVoiceSearchButton() { - val shouldShowVoiceSearch = isSpeechAvailable() && - requireContext().settings().shouldShowVoiceSearch - - if (voiceSearchButtonAlreadyAdded || !shouldShowVoiceSearch) return - - toolbarView.view.addEditActionEnd( - BrowserToolbar.Button( - imageDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_microphone)!!, - contentDescription = requireContext().getString(R.string.voice_search_content_description), - visible = { true }, - listener = ::launchVoiceSearch, - ), - ) - - voiceSearchButtonAlreadyAdded = true - } - - private fun launchVoiceSearch() { - // Note if a user disables speech while the app is on the search fragment - // the voice button will still be available and *will* cause a crash if tapped, - // since the `visible` call is only checked on create. In order to avoid extra complexity - // around such a small edge case, we make the button have no functionality in this case. - if (!isSpeechAvailable()) { return } - - speechIntent.apply { - putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM) - putExtra(RecognizerIntent.EXTRA_PROMPT, requireContext().getString(R.string.voice_search_explainer)) - } - - startVoiceSearchForResult.launch(speechIntent) - } - - private fun isSpeechAvailable(): Boolean = speechIntent.resolveActivity(requireContext().packageManager) != null -} diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchDialogInteractor.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchDialogInteractor.kt deleted file mode 100644 index a0d71c956..000000000 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchDialogInteractor.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks - -import mozilla.components.concept.engine.EngineSession.LoadUrlFlags -import org.mozilla.fenix.library.bookmarks.awesomebar.AwesomeBarInteractor -import org.mozilla.fenix.library.bookmarks.toolbar.ToolbarInteractor - -/** - * Interactor for the bookmark search - * Provides implementations for the AwesomeBarView and ToolbarView - */ -class BookmarkSearchDialogInteractor( - private val bookmarkSearchController: BookmarkSearchDialogController, -) : AwesomeBarInteractor, ToolbarInteractor { - - override fun onEditingCanceled() { - bookmarkSearchController.handleEditingCancelled() - } - - override fun onTextChanged(text: String) { - bookmarkSearchController.handleTextChanged(text) - } - - override fun onUrlTapped(url: String, flags: LoadUrlFlags) { - bookmarkSearchController.handleUrlTapped(url, flags) - } -} diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchFragmentStore.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchFragmentStore.kt deleted file mode 100644 index 184503b3f..000000000 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchFragmentStore.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks - -import mozilla.components.lib.state.Action -import mozilla.components.lib.state.State -import mozilla.components.lib.state.Store - -/** - * The [Store] for holding the [BookmarkSearchFragmentState] and applying [BookmarkSearchFragmentAction]s. - */ -class BookmarkSearchFragmentStore( - initialState: BookmarkSearchFragmentState, -) : Store( - initialState, - ::bookmarkSearchStateReducer, -) - -/** - * The state for the Bookmark Search Screen - * - * @property query The current search query string - */ -data class BookmarkSearchFragmentState( - val query: String, -) : State - -fun createInitialBookmarkSearchFragmentState(): BookmarkSearchFragmentState { - return BookmarkSearchFragmentState(query = "") -} - -/** - * Actions to dispatch through the [BookmarkSearchFragmentStore] to modify [BookmarkSearchFragmentState] - * through the reducer. - */ -sealed class BookmarkSearchFragmentAction : Action { - data class UpdateQuery(val query: String) : BookmarkSearchFragmentAction() -} - -/** - * The [BookmarkSearchFragmentState] Reducer. - */ -private fun bookmarkSearchStateReducer( - state: BookmarkSearchFragmentState, - action: BookmarkSearchFragmentAction, -): BookmarkSearchFragmentState { - return when (action) { - is BookmarkSearchFragmentAction.UpdateQuery -> - state.copy(query = action.query) - } -} diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/awesomebar/AwesomeBarInteractor.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/awesomebar/AwesomeBarInteractor.kt deleted file mode 100644 index fef316b0c..000000000 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/awesomebar/AwesomeBarInteractor.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks.awesomebar - -import mozilla.components.concept.engine.EngineSession.LoadUrlFlags - -/** - * Interface for the AwesomeBarView Interactor. This interface is implemented by objects that want - * to respond to user interaction on the AwesomebarView - */ -interface AwesomeBarInteractor { - - /** - * Called whenever a suggestion containing a URL is tapped - * @param url the url the suggestion was providing - */ - fun onUrlTapped(url: String, flags: LoadUrlFlags = LoadUrlFlags.none()) -} diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/awesomebar/AwesomeBarView.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/awesomebar/AwesomeBarView.kt deleted file mode 100644 index c94a3bcb5..000000000 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/awesomebar/AwesomeBarView.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks.awesomebar - -import androidx.appcompat.content.res.AppCompatResources.getDrawable -import mozilla.components.concept.engine.EngineSession -import mozilla.components.feature.awesomebar.provider.BookmarksStorageSuggestionProvider -import mozilla.components.feature.session.SessionUseCases -import org.mozilla.fenix.HomeActivity -import org.mozilla.fenix.R -import org.mozilla.fenix.browser.browsingmode.BrowsingMode -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.library.bookmarks.BookmarkSearchFragmentState - -/** - * View that contains and configures the BrowserAwesomeBar - */ -class AwesomeBarView( - activity: HomeActivity, - val interactor: AwesomeBarInteractor, - val view: AwesomeBarWrapper, -) { - private val bookmarksStorageSuggestionProvider: BookmarksStorageSuggestionProvider - - private val loadUrlUseCase = object : SessionUseCases.LoadUrlUseCase { - override fun invoke( - url: String, - flags: EngineSession.LoadUrlFlags, - additionalHeaders: Map?, - ) { - interactor.onUrlTapped(url, flags) - } - } - - init { - val components = activity.components - - val engineForSpeculativeConnects = when (activity.browsingModeManager.mode) { - BrowsingMode.Normal -> components.core.engine - BrowsingMode.Private -> null - } - - bookmarksStorageSuggestionProvider = - BookmarksStorageSuggestionProvider( - bookmarksStorage = components.core.bookmarksStorage, - loadUrlUseCase = loadUrlUseCase, - icons = components.core.icons, - indicatorIcon = getDrawable(activity, R.drawable.ic_search_results_bookmarks), - engine = engineForSpeculativeConnects, - showEditSuggestion = false, - ) - - view.addProviders(bookmarksStorageSuggestionProvider) - } - - fun update(state: BookmarkSearchFragmentState) { - view.onInputChanged(state.query) - } -} diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/awesomebar/AwesomeBarWrapper.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/awesomebar/AwesomeBarWrapper.kt deleted file mode 100644 index a4079c967..000000000 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/awesomebar/AwesomeBarWrapper.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks.awesomebar - -import android.content.Context -import android.util.AttributeSet -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.AbstractComposeView -import mozilla.components.compose.browser.awesomebar.AwesomeBar -import mozilla.components.compose.browser.awesomebar.AwesomeBarDefaults -import mozilla.components.compose.browser.awesomebar.AwesomeBarOrientation -import mozilla.components.concept.awesomebar.AwesomeBar -import mozilla.components.support.ktx.android.view.hideKeyboard -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.settings -import org.mozilla.fenix.theme.FirefoxTheme - -/** - * This wrapper wraps the `AwesomeBar()` composable and exposes it as a `View` and `concept-awesomebar` - * implementation to be integrated in the view hierarchy of [BookmarkSearchDialogFragment] until more parts - * of that screen have been refactored to use Jetpack Compose. - */ -class AwesomeBarWrapper @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0, -) : AbstractComposeView(context, attrs, defStyleAttr), AwesomeBar { - private val providers = mutableStateOf(emptyList()) - private val text = mutableStateOf("") - private var onEditSuggestionListener: ((String) -> Unit)? = null - private var onStopListener: (() -> Unit)? = null - - @Composable - override fun Content() { - if (providers.value.isEmpty()) { - return - } - - val orientation = if (context.settings().shouldUseBottomToolbar) { - AwesomeBarOrientation.BOTTOM - } else { - AwesomeBarOrientation.TOP - } - - FirefoxTheme { - AwesomeBar( - text = text.value, - providers = providers.value, - orientation = orientation, - colors = AwesomeBarDefaults.colors( - background = Color.Transparent, - title = FirefoxTheme.colors.textPrimary, - description = FirefoxTheme.colors.textSecondary, - autocompleteIcon = FirefoxTheme.colors.textSecondary, - ), - onSuggestionClicked = { suggestion -> - suggestion.onSuggestionClicked?.invoke() - onStopListener?.invoke() - }, - onAutoComplete = { suggestion -> - onEditSuggestionListener?.invoke(suggestion.editSuggestion!!) - }, - onScroll = { hideKeyboard() }, - profiler = context.components.core.engine.profiler, - ) - } - } - - override fun addProviders(vararg providers: AwesomeBar.SuggestionProvider) { - val newProviders = this.providers.value.toMutableList() - newProviders.addAll(providers) - this.providers.value = newProviders - } - - override fun containsProvider(provider: AwesomeBar.SuggestionProvider): Boolean { - return providers.value.any { current -> current.id == provider.id } - } - - override fun onInputChanged(text: String) { - this.text.value = text - } - - override fun removeAllProviders() { - providers.value = emptyList() - } - - override fun removeProviders(vararg providers: AwesomeBar.SuggestionProvider) { - val newProviders = this.providers.value.toMutableList() - newProviders.removeAll(providers) - this.providers.value = newProviders - } - - override fun setOnEditSuggestionListener(listener: (String) -> Unit) { - onEditSuggestionListener = listener - } - - override fun setOnStopListener(listener: () -> Unit) { - onStopListener = listener - } -} diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/toolbar/ToolbarView.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/toolbar/ToolbarView.kt deleted file mode 100644 index 3c1d02eae..000000000 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/toolbar/ToolbarView.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks.toolbar - -import android.content.Context -import androidx.annotation.VisibleForTesting -import androidx.appcompat.content.res.AppCompatResources -import androidx.core.content.ContextCompat -import mozilla.components.browser.toolbar.BrowserToolbar -import mozilla.components.support.ktx.android.content.getColorFromAttr -import mozilla.components.support.ktx.android.content.res.resolveAttribute -import mozilla.components.support.ktx.android.view.hideKeyboard -import org.mozilla.fenix.R -import org.mozilla.fenix.library.bookmarks.BookmarkSearchFragmentState - -/** - * Interface for the Toolbar Interactor. This interface is implemented by objects that want - * to respond to user interaction on the [ToolbarView] - */ -interface ToolbarInteractor { - - /** - * Called when a user removes focus from the [ToolbarView] - */ - fun onEditingCanceled() - - /** - * Called whenever the text inside the [ToolbarView] changes - * @param text the current text displayed by [ToolbarView] - */ - fun onTextChanged(text: String) -} - -/** - * View that contains and configures the BrowserToolbar to only be used in its editing mode. - */ -@Suppress("LongParameterList") -class ToolbarView( - private val context: Context, - private val interactor: ToolbarInteractor, - private val isPrivate: Boolean, - val view: BrowserToolbar, -) { - - @VisibleForTesting - internal var isInitialized = false - - init { - view.apply { - editMode() - - background = AppCompatResources.getDrawable( - context, - context.theme.resolveAttribute(R.attr.layer1), - ) - - edit.hint = context.getString(R.string.bookmark_search) - - edit.colors = edit.colors.copy( - text = context.getColorFromAttr(R.attr.textPrimary), - hint = context.getColorFromAttr(R.attr.textSecondary), - suggestionBackground = ContextCompat.getColor( - context, - R.color.suggestion_highlight_color, - ), - clear = context.getColorFromAttr(R.attr.textPrimary), - ) - - edit.setUrlBackground( - AppCompatResources.getDrawable(context, R.drawable.search_url_background), - ) - - private = isPrivate - - setOnUrlCommitListener { - hideKeyboard() - - // We need to return false to not show display mode - false - } - - setDefaultIcon() - - setOnEditListener( - object : mozilla.components.concept.toolbar.Toolbar.OnEditListener { - override fun onCancelEditing(): Boolean { - interactor.onEditingCanceled() - // We need to return false to not show display mode - return false - } - - override fun onTextChanged(text: String) { - url = text - interactor.onTextChanged(text) - } - }, - ) - } - } - - fun update(state: BookmarkSearchFragmentState) { - if (!isInitialized) { - view.url = state.query - view.setSearchTerms(state.query) - - // We must trigger an onTextChanged so when search terms are set when transitioning to `editMode` - // we have the most up to date text - interactor.onTextChanged(view.url.toString()) - - view.editMode() - isInitialized = true - } - } - - private fun setDefaultIcon() { - val bookmarkSearchIcon = - AppCompatResources.getDrawable(context, R.drawable.ic_bookmarks_menu) - - bookmarkSearchIcon?.let { - view.edit.setIcon(bookmarkSearchIcon, context.getString(R.string.bookmark_search)) - } - } -} diff --git a/app/src/main/res/layout/fragment_bookmark_search_dialog.xml b/app/src/main/res/layout/fragment_bookmark_search_dialog.xml deleted file mode 100644 index 9a78b6853..000000000 --- a/app/src/main/res/layout/fragment_bookmark_search_dialog.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 700e9a514..bf081d363 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -382,19 +382,8 @@ - - - - Unit = { }, - ): BookmarkSearchDialogController { - return BookmarkSearchDialogController( - activity = activity, - fragmentStore = store, - clearToolbarFocus = clearToolbarFocus, - ) - } -} diff --git a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchDialogInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchDialogInteractorTest.kt deleted file mode 100644 index 307c35438..000000000 --- a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchDialogInteractorTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks - -import io.mockk.mockk -import io.mockk.verify -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test - -class BookmarkSearchDialogInteractorTest { - - lateinit var searchController: BookmarkSearchDialogController - lateinit var interactor: BookmarkSearchDialogInteractor - - @Before - fun setup() { - searchController = mockk(relaxed = true) - interactor = BookmarkSearchDialogInteractor( - searchController, - ) - } - - @Test - fun onEditingCanceled() = runTest { - interactor.onEditingCanceled() - - verify { - searchController.handleEditingCancelled() - } - } - - @Test - fun onTextChanged() { - interactor.onTextChanged("test") - - verify { searchController.handleTextChanged("test") } - } - - @Test - fun onUrlTapped() { - interactor.onUrlTapped("test") - - verify { - searchController.handleUrlTapped("test") - } - } -} diff --git a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchFragmentStoreTest.kt b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchFragmentStoreTest.kt deleted file mode 100644 index 55b9cd8ba..000000000 --- a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchFragmentStoreTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -package org.mozilla.fenix.library.bookmarks - -import kotlinx.coroutines.test.runTest -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotSame -import org.junit.Test - -class BookmarkSearchFragmentStoreTest { - - @Test - fun `GIVEN createInitialBookmarkSearchFragmentState THEN query is empty`() { - val expected = BookmarkSearchFragmentState(query = "") - - assertEquals( - expected, - createInitialBookmarkSearchFragmentState(), - ) - } - - @Test - fun updateQuery() = runTest { - val initialState = BookmarkSearchFragmentState(query = "") - val store = BookmarkSearchFragmentStore(initialState) - val query = "test query" - - store.dispatch(BookmarkSearchFragmentAction.UpdateQuery(query)).join() - assertNotSame(initialState, store.state) - assertEquals(query, store.state.query) - } -} diff --git a/detekt-baseline.xml b/detekt-baseline.xml index ba9a630ad..095460896 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -83,9 +83,6 @@ UndocumentedPublicClass:BookmarkFragmentStore.kt$BookmarkFragmentStore : Store UndocumentedPublicClass:BookmarkItemMenu.kt$BookmarkItemMenu UndocumentedPublicClass:BookmarkItemMenu.kt$BookmarkItemMenu$Item - UndocumentedPublicClass:BookmarkSearchController.kt$BookmarkSearchDialogController : BookmarkSearchController - UndocumentedPublicClass:BookmarkSearchDialogFragment.kt$BookmarkSearchDialogFragment : AppCompatDialogFragmentUserInteractionHandler - UndocumentedPublicClass:BookmarkSearchFragmentStore.kt$BookmarkSearchFragmentAction$UpdateQuery : BookmarkSearchFragmentAction UndocumentedPublicClass:BookmarkView.kt$BookmarkView : LibraryPageViewUserInteractionHandler UndocumentedPublicClass:BookmarksUseCase.kt$BookmarksUseCase$AddBookmarksUseCase UndocumentedPublicClass:BottomSpacerViewHolder.kt$BottomSpacerViewHolder : ViewHolder @@ -262,15 +259,6 @@ UndocumentedPublicClass:NoCollectionsMessageViewHolder.kt$NoCollectionsMessageViewHolder : ViewHolder UndocumentedPublicClass:NormalBrowserTrayList.kt$NormalBrowserTrayList : AbstractBrowserTrayList UndocumentedPublicClass:OnSharedPreferenceChangeListener.kt$OnSharedPreferenceChangeListener : OnSharedPreferenceChangeListenerDefaultLifecycleObserver - UndocumentedPublicClass:OnboardingFinishViewHolder.kt$OnboardingFinishViewHolder : ViewHolder - UndocumentedPublicClass:OnboardingHeaderViewHolder.kt$OnboardingHeaderViewHolder : ViewHolder - UndocumentedPublicClass:OnboardingManualSignInViewHolder.kt$OnboardingManualSignInViewHolder : ViewHolder - UndocumentedPublicClass:OnboardingPrivacyNoticeViewHolder.kt$OnboardingPrivacyNoticeViewHolder : ViewHolder - UndocumentedPublicClass:OnboardingRadioButton.kt$OnboardingRadioButton : AppCompatRadioButtonGroupableRadioButton - UndocumentedPublicClass:OnboardingSectionHeaderViewHolder.kt$OnboardingSectionHeaderViewHolder : ViewHolder - UndocumentedPublicClass:OnboardingThemePickerViewHolder.kt$OnboardingThemePickerViewHolder : ViewHolder - UndocumentedPublicClass:OnboardingToolbarPositionPickerViewHolder.kt$OnboardingToolbarPositionPickerViewHolder : ViewHolder - UndocumentedPublicClass:OnboardingTrackingProtectionViewHolder.kt$OnboardingTrackingProtectionViewHolder : ViewHolder UndocumentedPublicClass:PagedHistoryProvider.kt$HistoryDB$Group : HistoryDB UndocumentedPublicClass:PagedHistoryProvider.kt$HistoryDB$Metadata : HistoryDB UndocumentedPublicClass:PagedHistoryProvider.kt$HistoryDB$Regular : HistoryDB @@ -492,7 +480,6 @@ UndocumentedPublicFunction:AddonPermissionDetailsBindingDelegate.kt$AddonPermissionDetailsBindingDelegate$fun bind(addon: Addon) UndocumentedPublicFunction:AppRequestInterceptor.kt$AppRequestInterceptor$fun setNavigationController(navController: NavController) UndocumentedPublicFunction:AppViewHolder.kt$AppViewHolder$fun bind(item: AppShareOption) - UndocumentedPublicFunction:AwesomeBarView.kt$AwesomeBarView$fun update(state: BookmarkSearchFragmentState) UndocumentedPublicFunction:AwesomeBarView.kt$AwesomeBarView$fun update(state: HistorySearchFragmentState) UndocumentedPublicFunction:AwesomeBarView.kt$AwesomeBarView$fun update(state: SearchFragmentState) UndocumentedPublicFunction:AwesomeBarView.kt$AwesomeBarView$fun updateSuggestionProvidersVisibility( state: SearchProviderState, ) @@ -519,10 +506,6 @@ UndocumentedPublicFunction:BookmarkController.kt$BookmarkController$fun handleSelectionModeSwitch() UndocumentedPublicFunction:BookmarkFragmentStore.kt$operator fun BookmarkNode.contains(item: BookmarkNode): Boolean UndocumentedPublicFunction:BookmarkNodeViewHolder.kt$BookmarkNodeViewHolder$fun bind( item: BookmarkNode, mode: BookmarkFragmentState.Mode, payload: BookmarkPayload, ) - UndocumentedPublicFunction:BookmarkSearchController.kt$BookmarkSearchController$fun handleEditingCancelled() - UndocumentedPublicFunction:BookmarkSearchController.kt$BookmarkSearchController$fun handleTextChanged(text: String) - UndocumentedPublicFunction:BookmarkSearchController.kt$BookmarkSearchController$fun handleUrlTapped(url: String, flags: LoadUrlFlags = LoadUrlFlags.none()) - UndocumentedPublicFunction:BookmarkSearchFragmentStore.kt$fun createInitialBookmarkSearchFragmentState(): BookmarkSearchFragmentState UndocumentedPublicFunction:BookmarkView.kt$BookmarkView$fun update(state: BookmarkFragmentState) UndocumentedPublicFunction:BrowserAnimator.kt$BrowserAnimator$fun beginAnimateInIfNecessary() UndocumentedPublicFunction:BrowserAnimator.kt$BrowserAnimator.Companion$fun getToolbarNavOptions(context: Context): NavOptions @@ -707,9 +690,6 @@ UndocumentedPublicFunction:NavController.kt$fun NavController.navigateSafe( @IdRes resId: Int, directions: NavDirections, ) UndocumentedPublicFunction:NimbusBranchesView.kt$NimbusBranchesView$fun update(state: NimbusBranchesState) UndocumentedPublicFunction:NotificationManager.kt$NotificationManager$fun showReceivedTabs(context: Context, device: Device?, tabs: List<TabData>) - UndocumentedPublicFunction:OnboardingRadioButton.kt$OnboardingRadioButton$fun addIllustration(illustration: ImageView) - UndocumentedPublicFunction:OnboardingRadioButton.kt$OnboardingRadioButton$fun onClickListener(listener: () -> Unit) - UndocumentedPublicFunction:OnboardingSectionHeaderViewHolder.kt$OnboardingSectionHeaderViewHolder$fun bind(labelBuilder: (Context) -> String) UndocumentedPublicFunction:PagerIndicator.kt$fun Context.dpToPx(value: Float): Int UndocumentedPublicFunction:PagerIndicator.kt$fun View.dpToPx(value: Float): Int UndocumentedPublicFunction:PasswordRevealHelper.kt$fun togglePasswordReveal(passwordText: TextView, revealPasswordButton: ImageButton) @@ -793,7 +773,6 @@ UndocumentedPublicFunction:SessionControlAdapter.kt$AdapterItem$open fun contentsSameAs(other: AdapterItem) UndocumentedPublicFunction:SessionControlView.kt$SessionControlView$fun update(state: AppState, shouldReportMetrics: Boolean = false) UndocumentedPublicFunction:Settings.kt$Settings$@VisibleForTesting(otherwise = PRIVATE) fun setStrictETP() - UndocumentedPublicFunction:Settings.kt$Settings$fun addSearchWidgetInstalled(count: Int) UndocumentedPublicFunction:Settings.kt$Settings$fun amoCollectionOverrideConfigured(): Boolean UndocumentedPublicFunction:Settings.kt$Settings$fun getDeleteDataOnQuit(type: DeleteBrowsingDataOnQuitType): Boolean UndocumentedPublicFunction:Settings.kt$Settings$fun getSitePermissionsCustomSettingsRules(): SitePermissionsRules @@ -875,7 +854,6 @@ UndocumentedPublicFunction:TabLayout.kt$fun TabLayout.isPrivateModeSelected(): Boolean UndocumentedPublicFunction:TabLayout.kt$fun TabLayout.isSyncedModeSelected(): Boolean UndocumentedPublicFunction:TabLayoutMediator.kt$TabLayoutMediator$fun selectTabAtPosition(position: Int) - UndocumentedPublicFunction:TabPreview.kt$TabPreview$fun loadPreviewThumbnail(thumbnailId: String) UndocumentedPublicFunction:TabSessionState.kt$fun TabSessionState.isActive(maxActiveTime: Long): Boolean UndocumentedPublicFunction:TabsTrayStore.kt$Page.Companion$fun positionToPage(position: Int): Page UndocumentedPublicFunction:ThemeManager.kt$ThemeManager$fun applyStatusBarTheme(window: Window, context: Context) @@ -885,7 +863,6 @@ UndocumentedPublicFunction:ToolbarIntegration.kt$ToolbarIntegration$fun invalidateMenu() UndocumentedPublicFunction:ToolbarPopupWindow.kt$ToolbarPopupWindow$fun show( view: WeakReference<View>, customTabId: String? = null, handlePasteAndGo: (String) -> Unit, handlePaste: (String) -> Unit, copyVisible: Boolean = true, ) UndocumentedPublicFunction:ToolbarView.kt$ToolbarView$fun update(searchState: SearchFragmentState) - UndocumentedPublicFunction:ToolbarView.kt$ToolbarView$fun update(state: BookmarkSearchFragmentState) UndocumentedPublicFunction:ToolbarView.kt$ToolbarView$fun update(state: HistorySearchFragmentState) UndocumentedPublicFunction:TopPlaceholderViewHolder.kt$TopPlaceholderViewHolder$fun bind() UndocumentedPublicFunction:TopSiteItemViewHolder.kt$TopSiteItemViewHolder$fun bind(topSite: TopSite, position: Int)