1
0
Fork 0

For #1019 Add onboarding search suggestion hint panel

master
mcarare 2019-11-15 18:01:34 +02:00 committed by Emily Kager
parent 5543f3272d
commit 1d36098878
11 changed files with 171 additions and 8 deletions

View File

@ -14,11 +14,11 @@ import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.searchEngineManager
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.searchEngineManager
/**
* An interface that handles the view manipulation of the Search, triggered by the Interactor
@ -69,6 +69,12 @@ class DefaultSearchController(
store.dispatch(SearchFragmentAction.ShowSearchShortcutEnginePicker(
text.isEmpty() && context.settings().shouldShowSearchShortcuts
))
store.dispatch(SearchFragmentAction.ShowSearchSuggestionsHint(
text.isNotEmpty() &&
(context as HomeActivity).browsingModeManager.mode.isPrivate &&
!context.settings().shouldShowSearchSuggestionsInPrivate &&
!context.settings().showSearchSuggestionsInPrivateOnboardingFinished
))
}
override fun handleUrlTapped(url: String) {

View File

@ -14,13 +14,16 @@ import android.text.style.StyleSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewStub
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.transition.TransitionInflater
import kotlinx.android.synthetic.main.fragment_search.*
import kotlinx.android.synthetic.main.fragment_search.view.*
import kotlinx.android.synthetic.main.search_suggestions_onboarding.view.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.concept.storage.HistoryStorage
import mozilla.components.feature.qr.QrFeature
@ -34,12 +37,13 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getSpannable
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.search.awesomebar.AwesomeBarView
import org.mozilla.fenix.search.toolbar.ToolbarView
import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
@Suppress("TooManyFunctions", "LargeClass")
class SearchFragment : Fragment(), BackHandler {
@ -95,6 +99,7 @@ class SearchFragment : Fragment(), BackHandler {
searchEngineSource = currentSearchEngine,
defaultEngineSource = currentSearchEngine,
showSearchSuggestions = showSearchSuggestions,
showSearchSuggestionsHint = false,
showSearchShortcuts = requireContext().settings().shouldShowSearchShortcuts && url.isEmpty(),
showClipboardSuggestions = requireContext().settings().shouldShowClipboardSuggestions,
showHistorySuggestions = requireContext().settings().shouldShowHistorySuggestions,
@ -184,6 +189,34 @@ class SearchFragment : Fragment(), BackHandler {
qrFeature.get()?.scan(R.id.container)
}
val stubListener = ViewStub.OnInflateListener { _, inflated ->
inflated.learn_more.setOnClickListener {
(activity as HomeActivity)
.openToBrowserAndLoad(
searchTermOrURL = SupportUtils.getGenericSumoURLForTopic(
SupportUtils.SumoTopic.SEARCH_SUGGESTION),
newTab = searchStore.state.session == null,
from = BrowserDirection.FromSearch
)
}
inflated.allow.setOnClickListener {
inflated.visibility = View.GONE
context?.settings()?.shouldShowSearchSuggestionsInPrivate = true
context?.settings()?.showSearchSuggestionsInPrivateOnboardingFinished = true
}
inflated.dismiss.setOnClickListener {
inflated.visibility = View.GONE
context?.settings()?.shouldShowSearchSuggestionsInPrivate = false
context?.settings()?.showSearchSuggestionsInPrivateOnboardingFinished = true
}
}
view.search_suggestions_onboarding.setOnInflateListener((stubListener)
)
view.toolbar_wrapper.clipToOutline = false
fill_link_from_clipboard.setOnClickListener {
@ -200,6 +233,7 @@ class SearchFragment : Fragment(), BackHandler {
toolbarView.update(it)
updateSearchWithLabel(it)
updateClipboardSuggestion(it, requireContext().components.clipboardHandler.url)
updateSearchSuggestionsHintVisibility(it)
}
startPostponedEnterTransition()
@ -287,6 +321,11 @@ class SearchFragment : Fragment(), BackHandler {
} else null
}
private fun updateSearchSuggestionsHintVisibility(state: SearchFragmentState) {
view?.findViewById<View>(R.id.search_suggestions_onboarding)
?.isVisible = state.showSearchSuggestionsHint
}
companion object {
private const val SHARED_TRANSITION_MS = 200L
private const val REQUEST_CODE_CAMERA_PERMISSIONS = 1

View File

@ -36,6 +36,7 @@ sealed class SearchEngineSource {
* @property searchEngineSource The current selected search engine with the context of how it was selected
* @property defaultEngineSource The current default search engine source
* @property showSearchSuggestions Whether or not to show search suggestions from the search engine in the AwesomeBar
* @property showSearchSuggestionsHint Whether or not to show search suggestions in private hint panel
* @property showSearchShortcuts Whether or not to show search shortcuts in the AwesomeBar
* @property showClipboardSuggestions Whether or not to show clipboard suggestion in the AwesomeBar
* @property showHistorySuggestions Whether or not to show history suggestions in the AwesomeBar
@ -48,6 +49,7 @@ data class SearchFragmentState(
val searchEngineSource: SearchEngineSource,
val defaultEngineSource: SearchEngineSource.Default,
val showSearchSuggestions: Boolean,
val showSearchSuggestionsHint: Boolean,
val showSearchShortcuts: Boolean,
val showClipboardSuggestions: Boolean,
val showHistorySuggestions: Boolean,
@ -63,6 +65,7 @@ sealed class SearchFragmentAction : Action {
data class SearchShortcutEngineSelected(val engine: SearchEngine) : SearchFragmentAction()
data class SelectNewDefaultSearchEngine(val engine: SearchEngine) : SearchFragmentAction()
data class ShowSearchShortcutEnginePicker(val show: Boolean) : SearchFragmentAction()
data class ShowSearchSuggestionsHint(val show: Boolean) : SearchFragmentAction()
data class UpdateQuery(val query: String) : SearchFragmentAction()
}
@ -84,5 +87,7 @@ private fun searchStateReducer(state: SearchFragmentState, action: SearchFragmen
state.copy(
searchEngineSource = SearchEngineSource.Default(action.engine)
)
is SearchFragmentAction.ShowSearchSuggestionsHint ->
state.copy(showSearchSuggestionsHint = action.show)
}
}

View File

@ -71,7 +71,7 @@ internal fun SearchFragment.setOutOfExperimentConstraints(layout: ConstraintLayo
awesomeBar {
connect(
TOP to TOP of UNSET,
TOP to BOTTOM of search_with_shortcuts,
TOP to BOTTOM of awesomeBar_barrier,
BOTTOM to TOP of pillWrapper
)
}

View File

@ -31,6 +31,7 @@ object SupportUtils {
WHATS_NEW("whats-new-firefox-preview"),
SEND_TABS("send-tab-preview"),
SET_AS_DEFAULT_BROWSER("set-firefox-preview-default"),
SEARCH_SUGGESTION("how-search-firefox-preview"),
CUSTOM_SEARCH_ENGINES("custom-search-engines")
}

View File

@ -263,11 +263,16 @@ class Settings private constructor(
default = true
)
val shouldShowSearchSuggestionsInPrivate by booleanPreference(
var shouldShowSearchSuggestionsInPrivate by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions_in_private),
default = false
)
var showSearchSuggestionsInPrivateOnboardingFinished by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions_in_private_onboarding),
default = false
)
@VisibleForTesting(otherwise = PRIVATE)
internal val trackingProtectionOnboardingCount by intPreference(
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_onboarding),

View File

@ -14,6 +14,6 @@
app:layout_constraintBottom_toTopOf="@id/search_divider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar_wrapper"
app:layout_constraintTop_toBottomOf="@id/awesomeBar_barrier"
mozac:awesomeBarDescriptionTextColor="?secondaryText"
mozac:awesomeBarTitleTextColor="?primaryText" />

View File

@ -11,6 +11,18 @@
android:background="?foundation"
tools:context=".search.SearchFragment">
<ViewStub
android:id="@+id/search_suggestions_onboarding"
android:inflatedId="@+id/search_suggestions_onboarding"
android:layout="@layout/search_suggestions_onboarding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/awesomeBar_barrier"
app:layout_constraintTop_toBottomOf="@id/toolbar_wrapper"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/toolbar_wrapper"
android:layout_width="0dp"
@ -103,11 +115,18 @@
android:layout_marginTop="@dimen/search_fragment_shortcuts_label_margin_vertical"
android:layout_marginEnd="@dimen/search_fragment_shortcuts_label_margin_horizontal"
android:text="@string/search_shortcuts_search_with"
android:visibility="gone"
app:layout_constraintStart_toStartOf="@id/toolbar_wrapper"
app:layout_constraintTop_toBottomOf="@id/fill_link_from_clipboard"
app:layout_constraintBottom_toTopOf="@id/awesomeBar_barrier"
tools:text="Search with" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/awesomeBar_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="search_with_shortcuts,search_suggestions_onboarding"/>
<View
android:id="@+id/search_divider"
android:layout_width="match_parent"

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:paddingBottom="10dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/info_button"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_info"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/title"
android:textAppearance="?android:attr/textAppearanceListItem"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:text="@string/search_suggestions_onboarding_title"
android:paddingBottom="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/text"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/search_suggestions_onboarding_text"
app:layout_constraintStart_toStartOf="@id/title"
app:layout_constraintEnd_toEndOf="@id/title"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintBottom_toTopOf="@id/learn_more"/>
<TextView
android:id="@+id/learn_more"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?attr/accentHighContrast"
android:textStyle="bold"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/exceptions_empty_message_learn_more_link"
app:layout_constraintStart_toStartOf="@id/title"
app:layout_constraintEnd_toEndOf="@id/title"
app:layout_constraintTop_toBottomOf="@id/text"
app:layout_constraintBottom_toTopOf="@id/allow"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/allow"
style="@style/ThemeIndependentMaterialGreyButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="12dp"
android:text="@string/search_suggestions_onboarding_allow_button"
app:layout_constraintEnd_toEndOf="@id/title"
app:layout_constraintTop_toBottomOf="@id/text"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/dismiss"
android:textColor="#ffffff"
android:textStyle="bold"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="@string/search_suggestions_onboarding_do_not_allow_button"
app:layout_constraintEnd_toStartOf="@id/allow"
app:layout_constraintBottom_toBottomOf="@id/allow"
app:layout_constraintTop_toTopOf="@id/allow"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -75,6 +75,7 @@
<string name="pref_key_search_browsing_history" translatable="false">pref_key_search_browsing_history</string>
<string name="pref_key_search_bookmarks" translatable="false">pref_key_search_bookmarks</string>
<string name="pref_key_show_search_suggestions_in_private" translatable="false">pref_key_show_search_suggestions_in_private</string>
<string name="pref_key_show_search_suggestions_in_private_onboarding" translatable="false">pref_key_show_search_suggestions_in_privateonboarding</string>
<!-- Site Permissions Settings -->

View File

@ -116,6 +116,16 @@
<string name="search_shortcuts_search_with">Search with</string>
<!-- Button in the search view that lets a user navigate to the site in their clipboard -->
<string name="awesomebar_clipboard_title">Fill link from clipboard</string>
<!-- Button in the search suggestions onboarding that allows search suggestions in private sessions -->
<string name="search_suggestions_onboarding_allow_button">Allow</string>
<!-- Button in the search suggestions onboarding that does not allow search suggestions in private sessions -->
<string name="search_suggestions_onboarding_do_not_allow_button">Don\'t allow</string>
<!-- Search suggestion onboarding hint title text -->
<string name="search_suggestions_onboarding_title">Allow search suggestions in private sessions?</string>
<!-- Search suggestion onboarding hint description text -->
<string name="search_suggestions_onboarding_text">Firefox Preview will share everything you type in the address bar with your default search engine.</string>
<!-- Search suggestion onboarding hint Learn more link text -->
<string name="search_suggestions_onboarding_learn_more_link">Learn more</string>
<!-- Search Widget -->
<!-- Text preview for smaller sized widgets -->