Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Login] Use Magic Link for suspicious emails [Part 2] #13345

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import com.woocommerce.android.R
import com.woocommerce.android.e2e.helpers.util.Screen

class MagicLinkScreen : Screen {
constructor() : super(R.id.login_enter_password)
constructor() : super(R.id.login_magic_link_fallback_button)

fun proceedWithPassword(): PasswordScreen {
clickOn(R.id.login_enter_password)
clickOn(R.id.login_magic_link_fallback_button)
return PasswordScreen()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import org.wordpress.android.login.LoginMagicLinkRequestFragment
import org.wordpress.android.login.LoginMode
import org.wordpress.android.login.LoginSiteAddressFragment
import org.wordpress.android.login.LoginUsernamePasswordFragment
import org.wordpress.android.login.MagicLinkFallbackButton
import org.wordpress.android.util.ToastUtils
import javax.inject.Inject
import kotlin.text.RegexOption.IGNORE_CASE
Expand Down Expand Up @@ -351,13 +352,23 @@ class LoginActivity :

if (authOptions != null) {
if (authOptions.isPasswordless) {
showMagicLinkRequestScreen(email, verifyEmail, allowPassword = false, forceRequestAtStart = true)
showMagicLinkRequestScreen(
email = email,
verifyEmail = verifyEmail,
fallbackButton = MagicLinkFallbackButton.None,
forceRequestAtStart = true
)
} else {
showEmailPasswordScreen(email, verifyEmail)
}
} else {
if (isMagicLinkEnabled) {
showMagicLinkRequestScreen(email, verifyEmail, allowPassword = true, forceRequestAtStart = false)
showMagicLinkRequestScreen(
email = email,
verifyEmail = verifyEmail,
fallbackButton = MagicLinkFallbackButton.Password,
forceRequestAtStart = false
)
} else {
showEmailPasswordScreen(email, verifyEmail)
}
Expand All @@ -376,7 +387,7 @@ class LoginActivity :
private fun showMagicLinkRequestScreen(
email: String?,
verifyEmail: Boolean,
allowPassword: Boolean,
fallbackButton: MagicLinkFallbackButton,
forceRequestAtStart: Boolean
) {
val scheme = WOOCOMMERCE
Expand All @@ -387,7 +398,7 @@ class LoginActivity :
false,
null,
verifyEmail,
allowPassword,
fallbackButton,
forceRequestAtStart
)
changeFragment(loginMagicLinkRequestFragment, true, LoginMagicLinkRequestFragment.TAG, false)
Expand Down Expand Up @@ -445,8 +456,8 @@ class LoginActivity :
changeFragment(loginUsernamePasswordFragment, true, LoginUsernamePasswordFragment.TAG)
}

override fun showMagicLinkSentScreen(email: String?, allowPassword: Boolean) {
val loginMagicLinkSentFragment = LoginMagicLinkSentImprovedFragment.newInstance(email, allowPassword)
override fun showMagicLinkSentScreen(email: String?, fallbackButton: MagicLinkFallbackButton) {
val loginMagicLinkSentFragment = LoginMagicLinkSentImprovedFragment.newInstance(email, fallbackButton)
changeFragment(loginMagicLinkSentFragment, true, LoginMagicLinkSentImprovedFragment.TAG, false)
}

Expand Down Expand Up @@ -896,9 +907,17 @@ class LoginActivity :
TODO("Not yet implemented")
}

override fun useMagicLinkInstead(email: String?, verifyEmail: Boolean, requestAtStart: Boolean) {
showMagicLinkRequestScreen(email, verifyEmail, allowPassword = false, forceRequestAtStart = requestAtStart)
}
override fun useMagicLinkInstead(
email: String?,
verifyEmail: Boolean,
requestAtStart: Boolean,
fallbackButton: MagicLinkFallbackButton
) = showMagicLinkRequestScreen(
email = email,
verifyEmail = verifyEmail,
fallbackButton = fallbackButton,
forceRequestAtStart = requestAtStart
)

/**
* Allows for special handling of errors that come up during the login by address: check site address.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import org.wordpress.android.fluxc.store.AccountStore
import org.wordpress.android.fluxc.store.SiteStore
import org.wordpress.android.login.LoginAnalyticsListener
import org.wordpress.android.login.LoginAnalyticsListener.CreatedAccountSource
import java.util.HashMap
import javax.inject.Singleton

@Singleton
Expand Down Expand Up @@ -272,6 +271,10 @@ class LoginAnalyticsTracker(
unifiedLoginTracker.trackClick(Click.LOGIN_WITH_PASSWORD)
}

override fun trackLoginWithWpComUsernamePasswordClick() {
unifiedLoginTracker.trackClick(Click.LOGIN_WITH_WP_COM_USERNAME_PASSWORD)
}

override fun trackShowHelpClick() {
unifiedLoginTracker.trackClick(Click.SHOW_HELP)
unifiedLoginTracker.track(step = Step.HELP)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,46 @@ import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.MenuProvider
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import com.woocommerce.android.R
import com.woocommerce.android.databinding.FragmentLoginMagicLinkSentImprovedBinding
import com.woocommerce.android.extensions.serializable
import dagger.hilt.android.AndroidEntryPoint
import org.wordpress.android.login.LoginAnalyticsListener
import org.wordpress.android.login.LoginListener
import org.wordpress.android.login.MagicLinkFallbackButton
import javax.inject.Inject

@AndroidEntryPoint
class LoginMagicLinkSentImprovedFragment : Fragment(R.layout.fragment_login_magic_link_sent_improved), MenuProvider {
companion object {
const val TAG = "login_magic_link_sent_fragment_tag"
private const val ARG_EMAIL_ADDRESS = "ARG_EMAIL_ADDRESS"
private const val ARG_ALLOW_PASSWORD = "ARG_ALLOW_PASSWORD"
private const val ARG_FALLBACK_BUTTON: String = "ARG_FALLBACK_BUTTON"

fun newInstance(email: String?, allowPassword: Boolean = true): LoginMagicLinkSentImprovedFragment {
fun newInstance(email: String?, fallbackButton: MagicLinkFallbackButton): LoginMagicLinkSentImprovedFragment {
val fragment = LoginMagicLinkSentImprovedFragment()
val args = Bundle()
args.putString(ARG_EMAIL_ADDRESS, email)
args.putBoolean(ARG_ALLOW_PASSWORD, allowPassword)
args.putSerializable(ARG_FALLBACK_BUTTON, fallbackButton)
fragment.arguments = args
return fragment
}
}

private var mLoginListener: LoginListener? = null
private var mEmail: String? = null
private var mAllowPassword = false
private var loginListener: LoginListener? = null
private var email: String? = null
private var fallbackButton: MagicLinkFallbackButton = MagicLinkFallbackButton.None

@Inject lateinit var mAnalyticsListener: LoginAnalyticsListener

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val args = arguments
if (args != null) {
mEmail = args.getString(ARG_EMAIL_ADDRESS)
mAllowPassword = args.getBoolean(ARG_ALLOW_PASSWORD)
email = args.getString(ARG_EMAIL_ADDRESS)
fallbackButton = args.serializable(ARG_FALLBACK_BUTTON) ?: MagicLinkFallbackButton.None
}
savedInstanceState?.let {
mAnalyticsListener.trackLoginMagicLinkOpenEmailClientViewed()
Expand All @@ -55,7 +58,7 @@ class LoginMagicLinkSentImprovedFragment : Fragment(R.layout.fragment_login_magi
override fun onAttach(context: Context) {
super.onAttach(context)
if (activity is LoginListener) {
mLoginListener = activity as LoginListener
loginListener = activity as LoginListener
}
}

Expand All @@ -68,15 +71,29 @@ class LoginMagicLinkSentImprovedFragment : Fragment(R.layout.fragment_login_magi

requireActivity().addMenuProvider(this, viewLifecycleOwner)

binding.loginOpenEmailClient.setOnClickListener { mLoginListener?.openEmailClient(true) }
with(binding.loginEnterPassword) {
visibility = if (mAllowPassword) View.VISIBLE else View.GONE
binding.loginOpenEmailClient.setOnClickListener { loginListener?.openEmailClient(true) }
with(binding.loginMagicLinkFallbackButton) {
text = if (fallbackButton == MagicLinkFallbackButton.Password) {
getString(R.string.or_use_password_below_qr_code_scan_option)
} else {
getString(R.string.login_use_wpcom_username_instead)
}
isVisible = fallbackButton != MagicLinkFallbackButton.None
setOnClickListener {
mAnalyticsListener.trackLoginWithPasswordClick()
mLoginListener?.usePasswordInstead(mEmail)
when (fallbackButton) {
MagicLinkFallbackButton.Password -> {
mAnalyticsListener.trackLoginWithPasswordClick()
loginListener?.usePasswordInstead(email)
}
MagicLinkFallbackButton.UsernameAndPassword -> {
mAnalyticsListener.trackLoginWithWpComUsernamePasswordClick()
loginListener?.loginViaWpcomUsernameInstead()
}
MagicLinkFallbackButton.None -> error("This button should not be visible")
}
}
}
binding.email.text = mEmail
binding.email.text = email
}

override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
Expand All @@ -88,7 +105,7 @@ class LoginMagicLinkSentImprovedFragment : Fragment(R.layout.fragment_login_magi
return when (menuItem.itemId) {
org.wordpress.android.login.R.id.help -> {
mAnalyticsListener.trackShowHelpClick()
mLoginListener?.helpMagicLinkSent(mEmail)
loginListener?.helpMagicLinkSent(email)
true
}

Expand All @@ -103,6 +120,6 @@ class LoginMagicLinkSentImprovedFragment : Fragment(R.layout.fragment_login_magi

override fun onDetach() {
super.onDetach()
mLoginListener = null
loginListener = null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class MagicLinkInterceptActivity : AppCompatActivity() {
viewModel.fetchAccountInfo()
}

findViewById<TextView>(R.id.login_enter_password).visibility = View.GONE
findViewById<TextView>(R.id.login_magic_link_fallback_button).visibility = View.GONE

initializeViewModel()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ class UnifiedLoginTracker
SUBMIT_2FA_CODE("submit_2fa_code"),
REQUEST_MAGIC_LINK("request_magic_link"),
LOGIN_WITH_PASSWORD("login_with_password"),
LOGIN_WITH_WP_COM_USERNAME_PASSWORD("login_with_wp_com_username_password"),
HELP_FINDING_SITE_ADDRESS("help_finding_site_address"),
SELECT_EMAIL_FIELD("select_email_field"),
PICK_EMAIL_FROM_HINT("pick_email_from_hint"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
android:text="@string/open_mail" />

<com.google.android.material.button.MaterialButton
android:id="@+id/login_enter_password"
android:id="@+id/login_magic_link_fallback_button"
style="@style/Widget.LoginFlow.Button.Tertiary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
Expand Down
2 changes: 1 addition & 1 deletion WooCommerce/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2654,7 +2654,7 @@
<string name="enter_username_instead">Log in with your username.</string>
<string name="enter_verification_code">Almost there! Please enter the verification code for WordPress.com from your authenticator app.</string>
<string name="enter_verification_code_sms">We sent a text message to the phone number ending in %s. Please enter the verification code in the SMS.</string>

<string name="login_use_wpcom_username_instead">Use username and password instead</string>

<string name="requesting_otp">Requesting a verification code via SMS.</string>
<string name="requesting_sms_otp_success">SMS requested, please check your messages for the code.</string>
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ tinder-statemachine = '0.2.0'
wiremock = '2.26.3'
wordpress-aztec = 'v2.1.4'
wordpress-fluxc = 'trunk-0264533ce612f74e1ae6fcbaefeb69b252163774'
wordpress-login = '156-98aa2c6174009b24253133b6733be119b70b7178'
wordpress-login = '157-2b5183bb47cd6f53738862849e31c4efcad52ed0'
wordpress-libaddressinput = '0.0.2'
wordpress-mediapicker = '0.3.1'
wordpress-utils = '3.15.0'
Expand Down
Loading