1
0
Fork 0

For #7272: Show info when saved logins list is empty. (#7891)

* For #7272: Show info when saved logins list is empty

* For #7272: Updated unit tests
master
Mihai Adrian 2020-01-25 04:13:44 +02:00 committed by liuche
parent 10bf49918f
commit 622fdadde8
10 changed files with 85 additions and 5 deletions

View File

@ -23,5 +23,6 @@ enum class BrowserDirection(@IdRes val fragmentId: Int) {
FromExceptions(R.id.exceptionsFragment),
FromAbout(R.id.aboutFragment),
FromTrackingProtection(R.id.trackingProtectionFragment),
FromDefaultBrowserSettingsFragment(R.id.defaultBrowserSettingsFragment)
FromDefaultBrowserSettingsFragment(R.id.defaultBrowserSettingsFragment),
FromSavedLoginsFragment(R.id.savedLoginsFragment)
}

View File

@ -61,6 +61,7 @@ import org.mozilla.fenix.settings.DefaultBrowserSettingsFragmentDirections
import org.mozilla.fenix.settings.SettingsFragmentDirections
import org.mozilla.fenix.settings.TrackingProtectionFragmentDirections
import org.mozilla.fenix.settings.about.AboutFragmentDirections
import org.mozilla.fenix.settings.logins.SavedLoginsFragmentDirections
import org.mozilla.fenix.theme.DefaultThemeManager
import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.BrowsersCache
@ -308,6 +309,10 @@ open class HomeActivity : LocaleAwareAppCompatActivity() {
DefaultBrowserSettingsFragmentDirections.actionDefaultBrowserSettingsFragmentToBrowserFragment(
customTabSessionId
)
BrowserDirection.FromSavedLoginsFragment ->
SavedLoginsFragmentDirections.actionSavedLoginsFragmentToBrowserFragment(
customTabSessionId
)
}
private fun load(

View File

@ -34,7 +34,8 @@ object SupportUtils {
SET_AS_DEFAULT_BROWSER("set-firefox-preview-default"),
SEARCH_SUGGESTION("how-search-firefox-preview"),
CUSTOM_SEARCH_ENGINES("custom-search-engines"),
UPGRADE_FAQ("firefox-preview-upgrade-faqs")
UPGRADE_FAQ("firefox-preview-upgrade-faqs"),
SYNC_SETUP("how-set-firefox-sync-firefox-preview")
}
/**

View File

@ -20,11 +20,14 @@ import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mozilla.components.lib.state.ext.consumeFrom
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.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.showToolbar
import org.mozilla.fenix.settings.SupportUtils
class SavedLoginsFragment : Fragment() {
private lateinit var savedLoginsStore: SavedLoginsFragmentStore
@ -53,7 +56,7 @@ class SavedLoginsFragment : Fragment() {
)
)
}
savedLoginsInteractor = SavedLoginsInteractor(::itemClicked)
savedLoginsInteractor = SavedLoginsInteractor(::itemClicked, ::openLearnMore)
savedLoginsView = SavedLoginsView(view.savedLoginsLayout, savedLoginsInteractor)
lifecycleScope.launch(Main) { loadAndMapLogins() }
return view
@ -86,6 +89,15 @@ class SavedLoginsFragment : Fragment() {
findNavController().navigate(directions)
}
private fun openLearnMore() {
(activity as HomeActivity).openToBrowserAndLoad(
searchTermOrURL = SupportUtils.getGenericSumoURLForTopic
(SupportUtils.SumoTopic.SYNC_SETUP),
newTab = true,
from = BrowserDirection.FromSavedLoginsFragment
)
}
private suspend fun loadAndMapLogins() {
val syncedLogins = withContext(IO) {
requireContext().components.core.syncablePasswordsStorage.withUnlocked {

View File

@ -9,9 +9,13 @@ package org.mozilla.fenix.settings.logins
* Provides implementations for the SavedLoginsViewInteractor
*/
class SavedLoginsInteractor(
private val itemClicked: (SavedLoginsItem) -> Unit
private val itemClicked: (SavedLoginsItem) -> Unit,
private val learnMore: () -> Unit
) : SavedLoginsViewInteractor {
override fun itemClicked(item: SavedLoginsItem) {
itemClicked.invoke(item)
}
override fun onLearnMore() {
learnMore.invoke()
}
}

View File

@ -4,6 +4,9 @@
package org.mozilla.fenix.settings.logins
import android.text.SpannableString
import android.text.method.LinkMovementMethod
import android.text.style.UnderlineSpan
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.FrameLayout
@ -22,6 +25,8 @@ interface SavedLoginsViewInteractor {
* Called whenever one item is clicked
*/
fun itemClicked(item: SavedLoginsItem)
fun onLearnMore()
}
/**
@ -43,10 +48,21 @@ class SavedLoginsView(
adapter = loginsAdapter
layoutManager = LinearLayoutManager(containerView.context)
}
val learnMoreText = view.saved_passwords_empty_learn_more.text.toString()
val textWithLink = SpannableString(learnMoreText).apply {
setSpan(UnderlineSpan(), 0, learnMoreText.length, 0)
}
with(view.saved_passwords_empty_learn_more) {
movementMethod = LinkMovementMethod.getInstance()
text = textWithLink
setOnClickListener { interactor.onLearnMore() }
}
}
fun update(state: SavedLoginsFragmentState) {
view.saved_logins_list.isVisible = state.items.isNotEmpty()
view.saved_passwords_empty_view.isVisible = state.items.isEmpty()
loginsAdapter.submitList(state.items)
}
}

View File

@ -3,14 +3,44 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/saved_logins_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/saved_passwords_empty_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_margin="@dimen/exceptions_description_margin">
<TextView
android:id="@+id/saved_passwords_empty_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="@string/preferences_passwords_saved_logins_description_empty_text"
android:textColor="?secondaryText"
android:textSize="16sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/saved_passwords_empty_learn_more"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="@string/preferences_passwords_saved_logins_description_empty_learn_more_link"
android:textColor="?secondaryText"
android:textSize="16sp"
app:layout_constraintTop_toBottomOf="@id/saved_passwords_empty_message" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/saved_logins_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:listitem="@layout/logins_item" />
</FrameLayout>

View File

@ -662,6 +662,11 @@
<action
android:id="@+id/action_savedLoginsFragment_to_savedLoginSiteInfoFragment"
app:destination="@id/savedLoginSiteInfoFragment" />
<action
android:id="@+id/action_savedLoginsFragment_to_browserFragment"
app:destination="@id/browserFragment"
app:popUpTo="@id/settingsFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/savedLoginSiteInfoFragment"

View File

@ -1038,6 +1038,10 @@
<string name="preferences_passwords_sync_logins_sign_in">Sign in to Sync</string>
<!-- Preference to access list of saved logins -->
<string name="preferences_passwords_saved_logins">Saved logins</string>
<!-- Description of empty list of saved passwords -->
<string name="preferences_passwords_saved_logins_description_empty_text">The logins you save or sync to Firefox will show up here.</string>
<!-- Preference to access list of saved logins -->
<string name="preferences_passwords_saved_logins_description_empty_learn_more_link">Learn more about Sync.</string>
<!-- Preference to access list of login exceptions that we never save logins for -->
<string name="preferences_passwords_exceptions">Exceptions</string>
<!-- Empty description of list of login exceptions that we never save logins for -->

View File

@ -13,8 +13,10 @@ class SavedLoginsInteractorTest {
@Test
fun itemClicked() {
val savedLoginClicked: (SavedLoginsItem) -> Unit = mockk(relaxed = true)
val learnMore: () -> Unit = mockk(relaxed = true)
val interactor = SavedLoginsInteractor(
savedLoginClicked
savedLoginClicked,
learnMore
)
val item = SavedLoginsItem("mozilla.org", "username", "password")