Skip to content

Commit 4525d3a

Browse files
committed
Wire bookmarks import dialog / flow into BookmarksActivity
1 parent 3a473d1 commit 4525d3a

File tree

13 files changed

+353
-50
lines changed

13 files changed

+353
-50
lines changed

Task

Whitespace-only changes.

autofill/autofill-api/src/main/java/com/duckduckgo/autofill/api/AutofillCredentialDialogs.kt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
package com.duckduckgo.autofill.api
1818

19+
import android.os.Bundle
1920
import android.os.Parcelable
21+
import androidx.core.os.BundleCompat
2022
import androidx.fragment.app.DialogFragment
2123
import com.duckduckgo.autofill.api.domain.app.LoginCredentials
2224
import com.duckduckgo.autofill.api.domain.app.LoginTriggerType
@@ -184,6 +186,50 @@ interface EmailProtectionInContextSignUpDialog {
184186
}
185187
}
186188

189+
/**
190+
* Dialog which prompts the user to import bookmarks from Google
191+
* Results should be handled by defining a fragmentResultListener with key [ImportBookmarksPreImportDialog.RESULT_KEY]
192+
* e.g.,
193+
* supportFragmentManager.setFragmentResultListener(ImportBookmarksPreImportDialog.RESULT_KEY, this) { _, result ->
194+
* val choice = ImportBookmarksPreImportDialog.extractResult(result)
195+
* }
196+
*/
197+
interface ImportBookmarksPreImportDialog {
198+
199+
/**
200+
* Result of the dialog, as determined by which button the user pressed or if they cancelled the dialog
201+
*/
202+
@Parcelize
203+
sealed interface ImportBookmarksPreImportResult : Parcelable {
204+
205+
/**
206+
* User chose to proceed with the Google import
207+
*/
208+
@Parcelize
209+
data object ImportBookmarks : ImportBookmarksPreImportResult
210+
211+
/**
212+
* User chose to select a bookmarks file
213+
*/
214+
@Parcelize
215+
data object SelectBookmarksFile : ImportBookmarksPreImportResult
216+
217+
/**
218+
* User cancelled the dialog
219+
*/
220+
@Parcelize
221+
data object Cancel : ImportBookmarksPreImportResult
222+
}
223+
224+
companion object {
225+
const val RESULT_KEY = "ImportBookmarksPreImportDialog"
226+
227+
fun extractResult(bundle: Bundle): ImportBookmarksPreImportResult? {
228+
return BundleCompat.getParcelable(bundle, "result", ImportBookmarksPreImportResult::class.java)
229+
}
230+
}
231+
}
232+
187233
/**
188234
* Factory used to get instances of the various autofill dialogs
189235
*/
@@ -258,6 +304,11 @@ interface CredentialAutofillDialogFactory {
258304
tabId: String,
259305
url: String,
260306
): DialogFragment
307+
308+
/**
309+
* Creates a dialog which prompts the user to import bookmarks from Google
310+
*/
311+
fun autofillImportBookmarksPreImportDialog(importSource: AutofillImportBookmarksLaunchSource): DialogFragment
261312
}
262313

263314
private fun prefix(
@@ -280,4 +331,5 @@ enum class AutofillImportLaunchSource(val value: String) : Parcelable {
280331
enum class AutofillImportBookmarksLaunchSource(val value: String) : Parcelable {
281332
Unknown("unknown"),
282333
AutofillDevSettings("autofill_dev_settings"),
334+
BookmarksScreen("bookmarks_screen"),
283335
}

autofill/autofill-api/src/main/java/com/duckduckgo/autofill/api/AutofillScreens.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ sealed interface AutofillScreens {
5454
val loginCredentials: LoginCredentials,
5555
val source: AutofillScreenLaunchSource,
5656
) : ActivityParams
57+
58+
/**
59+
* Launch the Google Bookmarks import flow
60+
* @param importSource is used to indicate from where in the app the import was launched
61+
*/
62+
data class AutofillImportViaGoogleTakeoutScreen(val importSource: AutofillImportBookmarksLaunchSource) : ActivityParams
5763
}
5864

5965
enum class AutofillScreenLaunchSource {

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/takeout/webflow/ImportGoogleBookmarksWebFlowActivity.kt

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ import com.duckduckgo.anvil.annotations.InjectWith
2929
import com.duckduckgo.appbuildconfig.api.AppBuildConfig
3030
import com.duckduckgo.appbuildconfig.api.isInternalBuild
3131
import com.duckduckgo.autofill.api.AutofillImportBookmarksLaunchSource
32+
import com.duckduckgo.autofill.api.AutofillScreens
3233
import com.duckduckgo.autofill.impl.R
3334
import com.duckduckgo.autofill.impl.databinding.ActivityImportGoogleBookmarksWebflowBinding
34-
import com.duckduckgo.autofill.impl.importing.takeout.webflow.ImportGoogleBookmark.AutofillImportViaGoogleTakeoutScreen
3535
import com.duckduckgo.autofill.impl.importing.takeout.webflow.ImportGoogleBookmark.AutofillImportViaGoogleTakeoutScreenResultError
3636
import com.duckduckgo.autofill.impl.importing.takeout.webflow.ImportGoogleBookmark.AutofillImportViaGoogleTakeoutScreenResultSuccess
3737
import com.duckduckgo.autofill.impl.importing.takeout.webflow.ImportGoogleBookmark.ImportViaGoogleTakeoutScreen
@@ -46,7 +46,7 @@ import logcat.logcat
4646
import javax.inject.Inject
4747

4848
@InjectWith(ActivityScope::class)
49-
@ContributeToActivityStarter(AutofillImportViaGoogleTakeoutScreen::class)
49+
@ContributeToActivityStarter(AutofillScreens.AutofillImportViaGoogleTakeoutScreen::class)
5050
@ContributeToActivityStarter(AutofillImportViaGoogleTakeoutScreenResultSuccess::class)
5151
@ContributeToActivityStarter(AutofillImportViaGoogleTakeoutScreenResultError::class)
5252
class ImportGoogleBookmarksWebFlowActivity :
@@ -58,13 +58,13 @@ class ImportGoogleBookmarksWebFlowActivity :
5858
val binding: ActivityImportGoogleBookmarksWebflowBinding by viewBinding()
5959

6060
private var isOverlayCurrentlyShown = false
61+
private var isOnResultScreen = false
6162

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

6566
private val launchSource: AutofillImportBookmarksLaunchSource by lazy {
66-
intent.getActivityParams(ImportViaGoogleTakeoutScreen::class.java)?.launchSource
67-
?: AutofillImportBookmarksLaunchSource.Unknown
67+
intent.getActivityParams(ImportViaGoogleTakeoutScreen::class.java)?.launchSource ?: AutofillImportBookmarksLaunchSource.Unknown
6868
}
6969

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

8080
when {
81-
successResult != null -> showSuccessFragment(successResult.bookmarkCount)
82-
errorResult != null -> showErrorFragment(errorResult.errorReason)
81+
successResult != null -> {
82+
isOnResultScreen = true
83+
showSuccessFragment(successResult.bookmarkCount)
84+
}
85+
errorResult != null -> {
86+
isOnResultScreen = true
87+
showErrorFragment(errorResult.errorReason)
88+
}
8389
else -> launchWebFlow()
8490
}
8591
}
8692

8793
private fun launchWebFlow() {
8894
logcat { "Bookmark-import: Starting webflow" }
95+
isOnResultScreen = false
8996
replaceFragment(ImportGoogleBookmarksWebFlowFragment())
97+
updateToolbarTitle()
9098
invalidateOptionsMenu()
9199
}
92100

@@ -110,6 +118,8 @@ class ImportGoogleBookmarksWebFlowActivity :
110118

111119
replaceFragment(successFragment)
112120
isOverlayCurrentlyShown = false
121+
isOnResultScreen = true
122+
updateToolbarTitle()
113123
invalidateOptionsMenu()
114124
}
115125

@@ -125,6 +135,8 @@ class ImportGoogleBookmarksWebFlowActivity :
125135

126136
replaceFragment(errorFragment)
127137
isOverlayCurrentlyShown = false
138+
isOnResultScreen = true
139+
updateToolbarTitle()
128140
invalidateOptionsMenu()
129141
}
130142

@@ -147,6 +159,7 @@ class ImportGoogleBookmarksWebFlowActivity :
147159

148160
private fun showProgressOverlay() {
149161
isOverlayCurrentlyShown = true
162+
updateToolbarTitle()
150163

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

160173
private fun hideProgressOverlay() {
161174
isOverlayCurrentlyShown = false
175+
updateToolbarTitle()
162176

163177
val progressFragment = supportFragmentManager.findFragmentByTag(PROGRESS_OVERLAY_TAG)
164178
if (progressFragment != null) {
@@ -249,6 +263,7 @@ class ImportGoogleBookmarksWebFlowActivity :
249263
toggleOverlay()
250264
true
251265
}
266+
252267
else -> super.onOptionsItemSelected(item)
253268
}
254269
}
@@ -268,7 +283,16 @@ class ImportGoogleBookmarksWebFlowActivity :
268283
setNavigationIcon(com.duckduckgo.mobile.android.R.drawable.ic_close_24)
269284
}
270285
supportActionBar?.setDisplayHomeAsUpEnabled(true)
271-
setTitle("")
286+
updateToolbarTitle()
287+
}
288+
289+
private fun updateToolbarTitle() {
290+
val title = if (isOverlayCurrentlyShown || isOnResultScreen) {
291+
""
292+
} else {
293+
getString(R.string.importBookmarksFromGoogleWebFlowTitle)
294+
}
295+
setTitle(title)
272296
}
273297

274298
companion object {
@@ -283,11 +307,6 @@ object ImportGoogleBookmark {
283307
) : ActivityParams,
284308
Parcelable
285309

286-
@Parcelize
287-
data class AutofillImportViaGoogleTakeoutScreen(
288-
private val source: AutofillImportBookmarksLaunchSource,
289-
) : ImportViaGoogleTakeoutScreen(source)
290-
291310
@Parcelize
292311
data class AutofillImportViaGoogleTakeoutScreenResultSuccess(
293312
private val source: AutofillImportBookmarksLaunchSource,

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/ui/CredentialAutofillDialogAndroidFactory.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
package com.duckduckgo.autofill.impl.ui
1818

1919
import androidx.fragment.app.DialogFragment
20+
import com.duckduckgo.autofill.api.AutofillImportBookmarksLaunchSource
2021
import com.duckduckgo.autofill.api.AutofillImportLaunchSource
2122
import com.duckduckgo.autofill.api.CredentialAutofillDialogFactory
2223
import com.duckduckgo.autofill.api.CredentialUpdateExistingCredentialsDialog.CredentialUpdateType
2324
import com.duckduckgo.autofill.api.domain.app.LoginCredentials
2425
import com.duckduckgo.autofill.api.domain.app.LoginTriggerType
2526
import com.duckduckgo.autofill.impl.email.EmailProtectionChooseEmailFragment
2627
import com.duckduckgo.autofill.impl.email.incontext.prompt.EmailProtectionInContextSignUpPromptFragment
28+
import com.duckduckgo.autofill.impl.ui.credential.management.importbookmark.google.preimport.ImportFromGoogleBookmarksPreImportDialog
2729
import com.duckduckgo.autofill.impl.ui.credential.management.importpassword.google.ImportFromGooglePasswordsDialog
2830
import com.duckduckgo.autofill.impl.ui.credential.passwordgeneration.AutofillUseGeneratedPasswordDialogFragment
2931
import com.duckduckgo.autofill.impl.ui.credential.saving.AutofillSavingCredentialsDialogFragment
@@ -107,4 +109,8 @@ class CredentialAutofillDialogAndroidFactory @Inject constructor() : CredentialA
107109
override fun autofillImportPasswordsPromoDialog(importSource: AutofillImportLaunchSource, tabId: String, url: String): DialogFragment {
108110
return ImportFromGooglePasswordsDialog.instance(importSource = importSource, tabId = tabId, originalUrl = url)
109111
}
112+
113+
override fun autofillImportBookmarksPreImportDialog(importSource: AutofillImportBookmarksLaunchSource): DialogFragment {
114+
return ImportFromGoogleBookmarksPreImportDialog.instance(importSource = importSource)
115+
}
110116
}

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/ui/credential/management/importbookmark/google/preimport/ImportFromGoogleBookmarksPreImportDialog.kt

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ import android.view.LayoutInflater
2323
import android.view.View
2424
import android.view.ViewGroup
2525
import androidx.core.os.BundleCompat
26+
import androidx.fragment.app.setFragmentResult
2627
import com.duckduckgo.anvil.annotations.InjectWith
2728
import com.duckduckgo.autofill.api.AutofillImportBookmarksLaunchSource
2829
import com.duckduckgo.autofill.api.AutofillImportBookmarksLaunchSource.Unknown
30+
import com.duckduckgo.autofill.api.ImportBookmarksPreImportDialog
31+
import com.duckduckgo.autofill.api.ImportBookmarksPreImportDialog.ImportBookmarksPreImportResult
2932
import com.duckduckgo.autofill.impl.R
3033
import com.duckduckgo.autofill.impl.databinding.ContentImportBookmarksFromGooglePreimportDialogBinding
3134
import com.duckduckgo.autofill.impl.ui.credential.dialog.animateClosed
32-
import com.duckduckgo.autofill.impl.ui.credential.management.importbookmark.google.preimport.ImportFromGoogleBookmarksPreImportDialog.ImportBookmarksDialog.Companion.KEY_TAB_ID
3335
import com.duckduckgo.common.utils.FragmentViewModelFactory
3436
import com.duckduckgo.di.scopes.FragmentScope
3537
import com.google.android.material.bottomsheet.BottomSheetBehavior
@@ -57,12 +59,6 @@ class ImportFromGoogleBookmarksPreImportDialog : BottomSheetDialogFragment() {
5759
@Inject
5860
lateinit var viewModelFactory: FragmentViewModelFactory
5961

60-
private var importClickedCallback: (() -> Unit)? = null
61-
62-
fun setImportClickedCallback(callback: () -> Unit) {
63-
importClickedCallback = callback
64-
}
65-
6662
private fun getLaunchSource() =
6763
BundleCompat.getParcelable(arguments ?: Bundle(), KEY_LAUNCH_SOURCE, AutofillImportBookmarksLaunchSource::class.java) ?: Unknown
6864

@@ -104,43 +100,74 @@ class ImportFromGoogleBookmarksPreImportDialog : BottomSheetDialogFragment() {
104100
with(binding.importButton) {
105101
setOnClickListener { onImportButtonClicked() }
106102
}
103+
104+
with(binding.selectFileButton) {
105+
setOnClickListener { onSelectFileButtonClicked() }
106+
}
107107
}
108108

109109
private fun onImportButtonClicked() {
110-
importClickedCallback?.invoke()
110+
ignoreCancellationEvents = true
111+
112+
// Send fragment result
113+
val result = Bundle().apply {
114+
putParcelable(KEY_RESULT, ImportBookmarksPreImportResult.ImportBookmarks)
115+
putParcelable(KEY_IMPORT_SOURCE, getLaunchSource())
116+
}
117+
setFragmentResult(ImportBookmarksPreImportDialog.RESULT_KEY, result)
118+
}
119+
120+
private fun onSelectFileButtonClicked() {
121+
ignoreCancellationEvents = true
122+
123+
val result = Bundle().apply {
124+
putParcelable(KEY_RESULT, ImportBookmarksPreImportResult.SelectBookmarksFile)
125+
putParcelable(KEY_IMPORT_SOURCE, getLaunchSource())
126+
}
127+
setFragmentResult(ImportBookmarksPreImportDialog.RESULT_KEY, result)
111128
}
112129

113130
override fun onCancel(dialog: DialogInterface) {
114131
if (ignoreCancellationEvents) {
115132
logcat(VERBOSE) { "onCancel: Ignoring cancellation event" }
116133
return
117134
}
135+
136+
val result = Bundle().apply {
137+
putParcelable(KEY_RESULT, ImportBookmarksPreImportResult.Cancel)
138+
putParcelable(KEY_IMPORT_SOURCE, getLaunchSource())
139+
}
140+
setFragmentResult(ImportBookmarksPreImportDialog.RESULT_KEY, result)
118141
}
119142

120143
private fun configureCloseButton(binding: ContentImportBookmarksFromGooglePreimportDialogBinding) {
121-
binding.closeButton.setOnClickListener { (dialog as BottomSheetDialog).animateClosed() }
144+
binding.closeButton.setOnClickListener {
145+
ignoreCancellationEvents = true
146+
147+
val result = Bundle().apply {
148+
putParcelable(KEY_RESULT, ImportBookmarksPreImportResult.Cancel)
149+
putParcelable(KEY_IMPORT_SOURCE, getLaunchSource())
150+
}
151+
setFragmentResult(ImportBookmarksPreImportDialog.RESULT_KEY, result)
152+
153+
(dialog as BottomSheetDialog).animateClosed()
154+
}
122155
}
123156

124157
companion object {
125158
private const val KEY_LAUNCH_SOURCE = "launchSource"
159+
private const val KEY_IMPORT_SOURCE = "importSource"
160+
private const val KEY_RESULT = "result"
126161

127162
fun instance(
128163
importSource: AutofillImportBookmarksLaunchSource,
129-
tabId: String? = null,
130164
): ImportFromGoogleBookmarksPreImportDialog {
131165
val fragment = ImportFromGoogleBookmarksPreImportDialog()
132166
fragment.arguments =
133167
Bundle().apply {
134168
putParcelable(KEY_LAUNCH_SOURCE, importSource)
135-
putString(KEY_TAB_ID, tabId)
136169
}
137170
return fragment
138171
}
139172
}
140-
141-
interface ImportBookmarksDialog {
142-
companion object {
143-
const val KEY_TAB_ID = "tabId"
144-
}
145-
}
146173
}

autofill/autofill-impl/src/main/res/layout/content_import_bookmarks_from_google_preimport_dialog.xml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,25 @@
7979
<com.duckduckgo.common.ui.view.button.DaxButtonPrimary
8080
android:id="@+id/importButton"
8181
android:layout_width="0dp"
82-
android:layout_marginTop="@dimen/keyline_5"
83-
app:layout_constraintTop_toBottomOf="@id/onboardingSubtitle"
8482
android:layout_height="wrap_content"
83+
android:layout_gravity="center"
84+
android:layout_marginTop="@dimen/keyline_5"
85+
android:text="@string/importBookmarksFromGooglePreImportDialogImportButton"
86+
app:daxButtonSize="large"
8587
app:layout_constraintEnd_toEndOf="@id/guidelineEnd"
8688
app:layout_constraintStart_toStartOf="@id/guidelineStart"
89+
app:layout_constraintTop_toBottomOf="@id/onboardingSubtitle" />
90+
91+
<com.duckduckgo.common.ui.view.button.DaxButtonGhost
92+
android:id="@+id/selectFileButton"
93+
android:layout_width="0dp"
94+
android:layout_height="wrap_content"
8795
android:layout_gravity="center"
88-
android:text="@string/importBookmarksFromGooglePreImportDialogImportButton"
89-
app:daxButtonSize="large" />
96+
android:text="@string/importBookmarksFromGooglePreImportDialogSelectFileButton"
97+
app:daxButtonSize="large"
98+
app:layout_constraintEnd_toEndOf="@id/guidelineEnd"
99+
app:layout_constraintStart_toStartOf="@id/guidelineStart"
100+
app:layout_constraintTop_toBottomOf="@id/importButton" />
90101

91102
</androidx.constraintlayout.widget.ConstraintLayout>
92103

0 commit comments

Comments
 (0)