Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
Empty file added Task
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package com.duckduckgo.autofill.api

import android.os.Bundle
import android.os.Parcelable
import androidx.core.os.BundleCompat
import androidx.fragment.app.DialogFragment
import com.duckduckgo.autofill.api.domain.app.LoginCredentials
import com.duckduckgo.autofill.api.domain.app.LoginTriggerType
Expand Down Expand Up @@ -184,6 +186,50 @@ interface EmailProtectionInContextSignUpDialog {
}
}

/**
* Dialog which prompts the user to import bookmarks from Google
* Results should be handled by defining a fragmentResultListener with key [ImportBookmarksPreImportDialog.RESULT_KEY]
* e.g.,
* supportFragmentManager.setFragmentResultListener(ImportBookmarksPreImportDialog.RESULT_KEY, this) { _, result ->
* val choice = ImportBookmarksPreImportDialog.extractResult(result)
* }
*/
interface ImportBookmarksPreImportDialog {

/**
* Result of the dialog, as determined by which button the user pressed or if they cancelled the dialog
*/
@Parcelize
sealed interface ImportBookmarksPreImportResult : Parcelable {

/**
* User chose to proceed with the Google import
*/
@Parcelize
data object ImportBookmarks : ImportBookmarksPreImportResult

/**
* User chose to select a bookmarks file
*/
@Parcelize
data object SelectBookmarksFile : ImportBookmarksPreImportResult

/**
* User cancelled the dialog
*/
@Parcelize
data object Cancel : ImportBookmarksPreImportResult
}

companion object {
const val RESULT_KEY = "ImportBookmarksPreImportDialog"

fun extractResult(bundle: Bundle): ImportBookmarksPreImportResult? {
return BundleCompat.getParcelable(bundle, "result", ImportBookmarksPreImportResult::class.java)
}
}
}

/**
* Factory used to get instances of the various autofill dialogs
*/
Expand Down Expand Up @@ -258,6 +304,11 @@ interface CredentialAutofillDialogFactory {
tabId: String,
url: String,
): DialogFragment

/**
* Creates a dialog which prompts the user to import bookmarks from Google
*/
fun autofillImportBookmarksPreImportDialog(importSource: AutofillImportBookmarksLaunchSource): DialogFragment
}

private fun prefix(
Expand All @@ -280,4 +331,5 @@ enum class AutofillImportLaunchSource(val value: String) : Parcelable {
enum class AutofillImportBookmarksLaunchSource(val value: String) : Parcelable {
Unknown("unknown"),
AutofillDevSettings("autofill_dev_settings"),
BookmarksScreen("bookmarks_screen"),
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ sealed interface AutofillScreens {
val loginCredentials: LoginCredentials,
val source: AutofillScreenLaunchSource,
) : ActivityParams

/**
* Launch the Google Bookmarks import flow
* @param importSource is used to indicate from where in the app the import was launched
*/
data class AutofillImportViaGoogleTakeoutScreen(val importSource: AutofillImportBookmarksLaunchSource) : ActivityParams
}

enum class AutofillScreenLaunchSource {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ import com.duckduckgo.anvil.annotations.InjectWith
import com.duckduckgo.appbuildconfig.api.AppBuildConfig
import com.duckduckgo.appbuildconfig.api.isInternalBuild
import com.duckduckgo.autofill.api.AutofillImportBookmarksLaunchSource
import com.duckduckgo.autofill.api.AutofillScreens
import com.duckduckgo.autofill.impl.R
import com.duckduckgo.autofill.impl.databinding.ActivityImportGoogleBookmarksWebflowBinding
import com.duckduckgo.autofill.impl.importing.takeout.webflow.ImportGoogleBookmark.AutofillImportViaGoogleTakeoutScreen
import com.duckduckgo.autofill.impl.importing.takeout.webflow.ImportGoogleBookmark.AutofillImportViaGoogleTakeoutScreenResultError
import com.duckduckgo.autofill.impl.importing.takeout.webflow.ImportGoogleBookmark.AutofillImportViaGoogleTakeoutScreenResultSuccess
import com.duckduckgo.autofill.impl.importing.takeout.webflow.ImportGoogleBookmark.ImportViaGoogleTakeoutScreen
Expand All @@ -46,7 +46,7 @@ import logcat.logcat
import javax.inject.Inject

@InjectWith(ActivityScope::class)
@ContributeToActivityStarter(AutofillImportViaGoogleTakeoutScreen::class)
@ContributeToActivityStarter(AutofillScreens.AutofillImportViaGoogleTakeoutScreen::class)
@ContributeToActivityStarter(AutofillImportViaGoogleTakeoutScreenResultSuccess::class)
@ContributeToActivityStarter(AutofillImportViaGoogleTakeoutScreenResultError::class)
class ImportGoogleBookmarksWebFlowActivity :
Expand All @@ -58,13 +58,13 @@ class ImportGoogleBookmarksWebFlowActivity :
val binding: ActivityImportGoogleBookmarksWebflowBinding by viewBinding()

private var isOverlayCurrentlyShown = false
private var isOnResultScreen = false

private val canShowDebugMenu: Boolean
get() = appBuildConfig.isInternalBuild() && isOverlayCurrentlyShown

private val launchSource: AutofillImportBookmarksLaunchSource by lazy {
intent.getActivityParams(ImportViaGoogleTakeoutScreen::class.java)?.launchSource
?: AutofillImportBookmarksLaunchSource.Unknown
intent.getActivityParams(ImportViaGoogleTakeoutScreen::class.java)?.launchSource ?: AutofillImportBookmarksLaunchSource.Unknown
}

override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -78,15 +78,23 @@ class ImportGoogleBookmarksWebFlowActivity :
val errorResult = intent.getActivityParams(AutofillImportViaGoogleTakeoutScreenResultError::class.java)

when {
successResult != null -> showSuccessFragment(successResult.bookmarkCount)
errorResult != null -> showErrorFragment(errorResult.errorReason)
successResult != null -> {
isOnResultScreen = true
showSuccessFragment(successResult.bookmarkCount)
}
errorResult != null -> {
isOnResultScreen = true
showErrorFragment(errorResult.errorReason)
}
else -> launchWebFlow()
}
}

private fun launchWebFlow() {
logcat { "Bookmark-import: Starting webflow" }
isOnResultScreen = false
replaceFragment(ImportGoogleBookmarksWebFlowFragment())
updateToolbarTitle()
invalidateOptionsMenu()
}

Expand All @@ -110,6 +118,8 @@ class ImportGoogleBookmarksWebFlowActivity :

replaceFragment(successFragment)
isOverlayCurrentlyShown = false
isOnResultScreen = true
updateToolbarTitle()
invalidateOptionsMenu()
}

Expand All @@ -125,6 +135,8 @@ class ImportGoogleBookmarksWebFlowActivity :

replaceFragment(errorFragment)
isOverlayCurrentlyShown = false
isOnResultScreen = true
updateToolbarTitle()
invalidateOptionsMenu()
}

Expand All @@ -147,6 +159,7 @@ class ImportGoogleBookmarksWebFlowActivity :

private fun showProgressOverlay() {
isOverlayCurrentlyShown = true
updateToolbarTitle()

val progressFragment = supportFragmentManager.findFragmentByTag(PROGRESS_OVERLAY_TAG)
if (progressFragment == null) {
Expand All @@ -159,6 +172,7 @@ class ImportGoogleBookmarksWebFlowActivity :

private fun hideProgressOverlay() {
isOverlayCurrentlyShown = false
updateToolbarTitle()

val progressFragment = supportFragmentManager.findFragmentByTag(PROGRESS_OVERLAY_TAG)
if (progressFragment != null) {
Expand Down Expand Up @@ -249,6 +263,7 @@ class ImportGoogleBookmarksWebFlowActivity :
toggleOverlay()
true
}

else -> super.onOptionsItemSelected(item)
}
}
Expand All @@ -268,7 +283,16 @@ class ImportGoogleBookmarksWebFlowActivity :
setNavigationIcon(com.duckduckgo.mobile.android.R.drawable.ic_close_24)
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setTitle("")
updateToolbarTitle()
}

private fun updateToolbarTitle() {
val title = if (isOverlayCurrentlyShown || isOnResultScreen) {
""
} else {
getString(R.string.importBookmarksFromGoogleWebFlowTitle)
}
setTitle(title)
}

companion object {
Expand All @@ -283,11 +307,6 @@ object ImportGoogleBookmark {
) : ActivityParams,
Parcelable

@Parcelize
data class AutofillImportViaGoogleTakeoutScreen(
private val source: AutofillImportBookmarksLaunchSource,
) : ImportViaGoogleTakeoutScreen(source)

@Parcelize
data class AutofillImportViaGoogleTakeoutScreenResultSuccess(
private val source: AutofillImportBookmarksLaunchSource,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
package com.duckduckgo.autofill.impl.ui

import androidx.fragment.app.DialogFragment
import com.duckduckgo.autofill.api.AutofillImportBookmarksLaunchSource
import com.duckduckgo.autofill.api.AutofillImportLaunchSource
import com.duckduckgo.autofill.api.CredentialAutofillDialogFactory
import com.duckduckgo.autofill.api.CredentialUpdateExistingCredentialsDialog.CredentialUpdateType
import com.duckduckgo.autofill.api.domain.app.LoginCredentials
import com.duckduckgo.autofill.api.domain.app.LoginTriggerType
import com.duckduckgo.autofill.impl.email.EmailProtectionChooseEmailFragment
import com.duckduckgo.autofill.impl.email.incontext.prompt.EmailProtectionInContextSignUpPromptFragment
import com.duckduckgo.autofill.impl.ui.credential.management.importbookmark.google.preimport.ImportFromGoogleBookmarksPreImportDialog
import com.duckduckgo.autofill.impl.ui.credential.management.importpassword.google.ImportFromGooglePasswordsDialog
import com.duckduckgo.autofill.impl.ui.credential.passwordgeneration.AutofillUseGeneratedPasswordDialogFragment
import com.duckduckgo.autofill.impl.ui.credential.saving.AutofillSavingCredentialsDialogFragment
Expand Down Expand Up @@ -107,4 +109,8 @@ class CredentialAutofillDialogAndroidFactory @Inject constructor() : CredentialA
override fun autofillImportPasswordsPromoDialog(importSource: AutofillImportLaunchSource, tabId: String, url: String): DialogFragment {
return ImportFromGooglePasswordsDialog.instance(importSource = importSource, tabId = tabId, originalUrl = url)
}

override fun autofillImportBookmarksPreImportDialog(importSource: AutofillImportBookmarksLaunchSource): DialogFragment {
return ImportFromGoogleBookmarksPreImportDialog.instance(importSource = importSource)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.BundleCompat
import androidx.fragment.app.setFragmentResult
import com.duckduckgo.anvil.annotations.InjectWith
import com.duckduckgo.autofill.api.AutofillImportBookmarksLaunchSource
import com.duckduckgo.autofill.api.AutofillImportBookmarksLaunchSource.Unknown
import com.duckduckgo.autofill.api.ImportBookmarksPreImportDialog
import com.duckduckgo.autofill.api.ImportBookmarksPreImportDialog.ImportBookmarksPreImportResult
import com.duckduckgo.autofill.impl.R
import com.duckduckgo.autofill.impl.databinding.ContentImportBookmarksFromGooglePreimportDialogBinding
import com.duckduckgo.autofill.impl.ui.credential.dialog.animateClosed
import com.duckduckgo.autofill.impl.ui.credential.management.importbookmark.google.preimport.ImportFromGoogleBookmarksPreImportDialog.ImportBookmarksDialog.Companion.KEY_TAB_ID
import com.duckduckgo.common.utils.FragmentViewModelFactory
import com.duckduckgo.di.scopes.FragmentScope
import com.google.android.material.bottomsheet.BottomSheetBehavior
Expand Down Expand Up @@ -57,12 +59,6 @@ class ImportFromGoogleBookmarksPreImportDialog : BottomSheetDialogFragment() {
@Inject
lateinit var viewModelFactory: FragmentViewModelFactory

private var importClickedCallback: (() -> Unit)? = null

fun setImportClickedCallback(callback: () -> Unit) {
importClickedCallback = callback
}

private fun getLaunchSource() =
BundleCompat.getParcelable(arguments ?: Bundle(), KEY_LAUNCH_SOURCE, AutofillImportBookmarksLaunchSource::class.java) ?: Unknown

Expand Down Expand Up @@ -104,43 +100,74 @@ class ImportFromGoogleBookmarksPreImportDialog : BottomSheetDialogFragment() {
with(binding.importButton) {
setOnClickListener { onImportButtonClicked() }
}

with(binding.selectFileButton) {
setOnClickListener { onSelectFileButtonClicked() }
}
}

private fun onImportButtonClicked() {
importClickedCallback?.invoke()
ignoreCancellationEvents = true

// Send fragment result
val result = Bundle().apply {
putParcelable(KEY_RESULT, ImportBookmarksPreImportResult.ImportBookmarks)
putParcelable(KEY_IMPORT_SOURCE, getLaunchSource())
}
setFragmentResult(ImportBookmarksPreImportDialog.RESULT_KEY, result)
}

private fun onSelectFileButtonClicked() {
ignoreCancellationEvents = true

val result = Bundle().apply {
putParcelable(KEY_RESULT, ImportBookmarksPreImportResult.SelectBookmarksFile)
putParcelable(KEY_IMPORT_SOURCE, getLaunchSource())
}
setFragmentResult(ImportBookmarksPreImportDialog.RESULT_KEY, result)
}

override fun onCancel(dialog: DialogInterface) {
if (ignoreCancellationEvents) {
logcat(VERBOSE) { "onCancel: Ignoring cancellation event" }
return
}

val result = Bundle().apply {
putParcelable(KEY_RESULT, ImportBookmarksPreImportResult.Cancel)
putParcelable(KEY_IMPORT_SOURCE, getLaunchSource())
}
setFragmentResult(ImportBookmarksPreImportDialog.RESULT_KEY, result)
}

private fun configureCloseButton(binding: ContentImportBookmarksFromGooglePreimportDialogBinding) {
binding.closeButton.setOnClickListener { (dialog as BottomSheetDialog).animateClosed() }
binding.closeButton.setOnClickListener {
ignoreCancellationEvents = true

val result = Bundle().apply {
putParcelable(KEY_RESULT, ImportBookmarksPreImportResult.Cancel)
putParcelable(KEY_IMPORT_SOURCE, getLaunchSource())
}
setFragmentResult(ImportBookmarksPreImportDialog.RESULT_KEY, result)

(dialog as BottomSheetDialog).animateClosed()
}
}

companion object {
private const val KEY_LAUNCH_SOURCE = "launchSource"
private const val KEY_IMPORT_SOURCE = "importSource"
private const val KEY_RESULT = "result"

fun instance(
importSource: AutofillImportBookmarksLaunchSource,
tabId: String? = null,
): ImportFromGoogleBookmarksPreImportDialog {
val fragment = ImportFromGoogleBookmarksPreImportDialog()
fragment.arguments =
Bundle().apply {
putParcelable(KEY_LAUNCH_SOURCE, importSource)
putString(KEY_TAB_ID, tabId)
}
return fragment
}
}

interface ImportBookmarksDialog {
companion object {
const val KEY_TAB_ID = "tabId"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,25 @@
<com.duckduckgo.common.ui.view.button.DaxButtonPrimary
android:id="@+id/importButton"
android:layout_width="0dp"
android:layout_marginTop="@dimen/keyline_5"
app:layout_constraintTop_toBottomOf="@id/onboardingSubtitle"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/keyline_5"
android:text="@string/importBookmarksFromGooglePreImportDialogImportButton"
app:daxButtonSize="large"
app:layout_constraintEnd_toEndOf="@id/guidelineEnd"
app:layout_constraintStart_toStartOf="@id/guidelineStart"
app:layout_constraintTop_toBottomOf="@id/onboardingSubtitle" />

<com.duckduckgo.common.ui.view.button.DaxButtonGhost
android:id="@+id/selectFileButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/importBookmarksFromGooglePreImportDialogImportButton"
app:daxButtonSize="large" />
android:text="@string/importBookmarksFromGooglePreImportDialogSelectFileButton"
app:daxButtonSize="large"
app:layout_constraintEnd_toEndOf="@id/guidelineEnd"
app:layout_constraintStart_toStartOf="@id/guidelineStart"
app:layout_constraintTop_toBottomOf="@id/importButton" />

</androidx.constraintlayout.widget.ConstraintLayout>

Expand Down
Loading
Loading