Skip to content

Commit 78b76f5

Browse files
committed
Duck.ai: Omnibar interactions
1 parent a76d661 commit 78b76f5

File tree

6 files changed

+98
-3
lines changed

6 files changed

+98
-3
lines changed

app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ import android.widget.Toast
3434
import androidx.activity.OnBackPressedCallback
3535
import androidx.activity.result.ActivityResult
3636
import androidx.activity.result.contract.ActivityResultContracts
37+
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
38+
import androidx.activity.viewModels
3739
import androidx.annotation.VisibleForTesting
3840
import androidx.core.view.isVisible
3941
import androidx.core.view.postDelayed
42+
import androidx.lifecycle.Lifecycle
4043
import androidx.lifecycle.Lifecycle.State.STARTED
4144
import androidx.lifecycle.lifecycleScope
4245
import androidx.lifecycle.repeatOnLifecycle
@@ -90,6 +93,7 @@ import com.duckduckgo.app.statistics.pixels.Pixel.PixelParameter
9093
import com.duckduckgo.app.tabs.TabManagerFeatureFlags
9194
import com.duckduckgo.app.tabs.model.TabEntity
9295
import com.duckduckgo.app.tabs.ui.DefaultSnackbar
96+
import com.duckduckgo.app.tabs.ui.TabSwitcherActivity
9397
import com.duckduckgo.appbuildconfig.api.AppBuildConfig
9498
import com.duckduckgo.autofill.api.emailprotection.EmailProtectionLinkVerifier
9599
import com.duckduckgo.browser.api.ui.BrowserScreens.BookmarksScreenNoParams
@@ -110,6 +114,7 @@ import com.duckduckgo.common.utils.playstore.PlayStoreUtils
110114
import com.duckduckgo.di.scopes.ActivityScope
111115
import com.duckduckgo.duckchat.api.DuckAiFeatureState
112116
import com.duckduckgo.duckchat.api.DuckChat
117+
import com.duckduckgo.duckchat.api.viewmodel.DuckChatSharedViewModel
113118
import com.duckduckgo.duckchat.impl.ui.DuckChatWebViewFragment
114119
import com.duckduckgo.duckchat.impl.ui.DuckChatWebViewFragment.Companion.KEY_DUCK_AI_TABS
115120
import com.duckduckgo.duckchat.impl.ui.DuckChatWebViewFragment.Companion.KEY_DUCK_AI_URL
@@ -249,6 +254,7 @@ open class BrowserActivity : DuckDuckGoActivity() {
249254
}
250255

251256
private val viewModel: BrowserViewModel by bindViewModel()
257+
private val duckChatViewModel: DuckChatSharedViewModel by viewModels()
252258

253259
private var instanceStateBundles: CombinedInstanceState? = null
254260

@@ -360,6 +366,8 @@ open class BrowserActivity : DuckDuckGoActivity() {
360366
viewModel.viewState.observe(this) {
361367
renderer.renderBrowserViewState(it)
362368
}
369+
observeDuckChatSharedCommands()
370+
363371
viewModel.awaitClearDataFinishedNotification()
364372
initializeServiceWorker()
365373

@@ -979,6 +987,37 @@ open class BrowserActivity : DuckDuckGoActivity() {
979987
)
980988
}
981989

990+
private val tabSwitcherActivityResult =
991+
registerForActivityResult(StartActivityForResult()) { result ->
992+
if (result.resultCode == RESULT_OK) {
993+
// Handle any result data if needed
994+
result.data?.let { intent ->
995+
intent.extras?.let { extras ->
996+
val deletedTabIds = extras.getStringArrayList(TabSwitcherActivity.EXTRA_KEY_DELETED_TAB_IDS)
997+
if (!deletedTabIds.isNullOrEmpty()) {
998+
onTabsDeletedInTabSwitcher(deletedTabIds)
999+
}
1000+
}
1001+
}
1002+
}
1003+
}
1004+
1005+
private fun observeDuckChatSharedCommands() {
1006+
lifecycleScope.launch {
1007+
repeatOnLifecycle(Lifecycle.State.STARTED) {
1008+
duckChatViewModel.command.collect { command ->
1009+
when (command) {
1010+
DuckChatSharedViewModel.Command.LaunchFire -> launchFire()
1011+
DuckChatSharedViewModel.Command.LaunchTabSwitcher -> {
1012+
val intent = TabSwitcherActivity.intent(this@BrowserActivity)
1013+
tabSwitcherActivityResult.launch(intent)
1014+
}
1015+
}
1016+
}
1017+
}
1018+
}
1019+
}
1020+
9821021
override fun onAttachFragment(fragment: androidx.fragment.app.Fragment) {
9831022
super.onAttachFragment(fragment)
9841023
hideMockupOmnibar()

duckchat/duckchat-api/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ android {
3030

3131
dependencies {
3232
implementation project(':navigation-api')
33+
implementation project(':common-utils')
3334

3435
implementation KotlinX.coroutines.core
3536
implementation AndroidX.appCompat
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2025 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.duckchat.api.viewmodel
18+
19+
import androidx.lifecycle.ViewModel
20+
import androidx.lifecycle.viewModelScope
21+
import kotlinx.coroutines.channels.Channel
22+
import kotlinx.coroutines.flow.receiveAsFlow
23+
import kotlinx.coroutines.launch
24+
25+
class DuckChatSharedViewModel() : ViewModel() {
26+
27+
private val _command = Channel<Command>()
28+
val command = _command.receiveAsFlow() // Activity will collect this
29+
30+
fun onFireButtonClicked() {
31+
viewModelScope.launch {
32+
_command.send(Command.LaunchFire)
33+
}
34+
}
35+
36+
fun onTabSwitcherCLicked() {
37+
viewModelScope.launch {
38+
_command.send(Command.LaunchTabSwitcher)
39+
}
40+
}
41+
42+
sealed class Command {
43+
object LaunchFire : Command()
44+
object LaunchTabSwitcher : Command()
45+
}
46+
}

duckchat/duckchat-impl/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ dependencies {
5252

5353
implementation KotlinX.coroutines.android
5454
implementation AndroidX.core.ktx
55+
implementation AndroidX.fragment.ktx
5556
implementation Google.android.material
5657
implementation Google.dagger
5758
implementation AndroidX.work.runtimeKtx

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatOmnibarLayout.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.duckduckgo.duckchat.impl.ui
1818

1919
import android.content.Context
2020
import android.util.AttributeSet
21+
import android.view.View
2122
import android.widget.FrameLayout
2223
import com.duckduckgo.anvil.annotations.InjectWith
2324
import com.duckduckgo.browser.ui.tabs.NewTabSwitcherButton
@@ -37,6 +38,7 @@ class DuckChatOmnibarLayout @JvmOverloads constructor(
3738
internal val fireIconMenu: FrameLayout by lazy { findViewById(R.id.inputFieldFireButton) }
3839
internal val browserMenu: FrameLayout by lazy { findViewById(R.id.inputFieldBrowserMenu) }
3940
internal val historyMenu: FrameLayout by lazy { findViewById(R.id.duckAiHistoryButton) }
41+
internal val inputCard: View by lazy { findViewById(R.id.inputModeWidgetCard) }
4042

4143
private var omnibarItemPressedListener: ItemPressedListener? = null
4244

@@ -52,7 +54,6 @@ class DuckChatOmnibarLayout @JvmOverloads constructor(
5254

5355
init {
5456
inflate(context, R.layout.view_duck_chat_omnibar, this)
55-
5657
AndroidSupportInjection.inject(this)
5758
}
5859

@@ -73,6 +74,9 @@ class DuckChatOmnibarLayout @JvmOverloads constructor(
7374
historyMenu.setOnClickListener {
7475
omnibarItemPressedListener?.onHistoryMenuPressed()
7576
}
77+
78+
inputCard.setOnClickListener {
79+
}
7680
}
7781

7882
fun setTabsCount(tabs: Int) {

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewFragment.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import android.webkit.WebView
3939
import androidx.annotation.AnyThread
4040
import androidx.appcompat.widget.Toolbar
4141
import androidx.core.content.ContextCompat
42+
import androidx.fragment.app.activityViewModels
4243
import androidx.lifecycle.Lifecycle
4344
import androidx.lifecycle.ViewModelProvider
4445
import androidx.lifecycle.flowWithLifecycle
@@ -65,6 +66,7 @@ import com.duckduckgo.downloads.api.DownloadStateListener
6566
import com.duckduckgo.downloads.api.DownloadsFileActions
6667
import com.duckduckgo.downloads.api.FileDownloader
6768
import com.duckduckgo.downloads.api.FileDownloader.PendingFileDownload
69+
import com.duckduckgo.duckchat.api.viewmodel.DuckChatSharedViewModel
6870
import com.duckduckgo.duckchat.impl.DuckChatInternal
6971
import com.duckduckgo.duckchat.impl.R
7072
import com.duckduckgo.duckchat.impl.databinding.ActivityDuckChatWebviewBinding
@@ -108,6 +110,8 @@ open class DuckChatWebViewFragment : DuckDuckGoFragment(R.layout.activity_duck_c
108110
ViewModelProvider(this, viewModelFactory)[DuckChatWebViewViewModel::class.java]
109111
}
110112

113+
private val sharedViewModel: DuckChatSharedViewModel by activityViewModels()
114+
111115
@Inject
112116
lateinit var webViewClient: DuckChatWebViewClient
113117

@@ -368,11 +372,11 @@ open class DuckChatWebViewFragment : DuckDuckGoFragment(R.layout.activity_duck_c
368372
duckChatOmnibar?.setOmnibarItemPressedListener(
369373
object : DuckChatOmnibarLayout.ItemPressedListener {
370374
override fun onTabsButtonPressed() {
371-
Snackbar.make(root, "Tabs", Snackbar.LENGTH_SHORT).show()
375+
sharedViewModel.onTabSwitcherCLicked()
372376
}
373377

374378
override fun onFireButtonPressed() {
375-
Snackbar.make(root, "Fire", Snackbar.LENGTH_SHORT).show()
379+
sharedViewModel.onFireButtonClicked()
376380
}
377381

378382
override fun onBrowserMenuPressed() {

0 commit comments

Comments
 (0)