Skip to content
Merged
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
20 changes: 14 additions & 6 deletions app/src/main/java/com/prirai/android/nira/BrowserActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import mozilla.components.browser.state.action.AppLifecycleAction
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.state.WebExtensionState
import mozilla.components.browser.state.state.selectedOrDefaultSearchEngine
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.EngineView
import mozilla.components.feature.contextmenu.ext.DefaultSelectionActionDelegate
Expand Down Expand Up @@ -505,10 +506,10 @@ open class BrowserActivity : LocaleAwareAppCompatActivity(), ComponentCallbacks2
components.store.state.tabs.find { it.id == id }
}
val isPrivateMode = selectedTab?.content?.private ?: browsingModeManager.mode.isPrivate
val resolvedEngine = engine ?: resolveSearchEngine(isPrivateMode)

if ((!forceSearch && searchTermOrURL.isUrl()) || engine == null) {
if (resolvedEngine == null || (!forceSearch && searchTermOrURL.isUrl())) {
if (newTab) {
// Determine contextId for proper tab grouping and visibility
val contextId = getContextIdForNewTab(isPrivateMode, selectedTab)
components.tabsUseCases.addTab.invoke(
searchTermOrURL.toNormalizedUrl(),
Expand All @@ -521,21 +522,28 @@ open class BrowserActivity : LocaleAwareAppCompatActivity(), ComponentCallbacks2
}
} else {
if (newTab) {
// For search, use newTabSearch but set contextId via middleware after tab creation
// The ProfileMiddleware will set contextId based on private mode
components.searchUseCases.newTabSearch
.invoke(
searchTermOrURL,
SessionState.Source.Internal.UserEntered,
isPrivateMode,
searchEngine = engine
searchEngine = resolvedEngine
)
} else {
components.searchUseCases.defaultSearch.invoke(searchTermOrURL, engine)
components.searchUseCases.defaultSearch.invoke(searchTermOrURL, resolvedEngine)
}
}
}

private fun resolveSearchEngine(isPrivateMode: Boolean): SearchEngine? {
components.store.state.search.selectedOrDefaultSearchEngine(isPrivateMode)?.let { return it }
return try {
SearchEngineList(this).getSelectedEngine(UserPreferences(this))
} catch (_: Exception) {
null
}
}

/**
* Get the appropriate contextId for new tabs based on browsing mode and current profile.
* This ensures tabs are properly grouped and visible in tab bar/sheet.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import androidx.core.content.ContextCompat
import mozilla.components.browser.state.search.SearchEngine
import androidx.core.graphics.createBitmap
import com.prirai.android.nira.preferences.UserPreferences
import mozilla.components.browser.state.search.SearchEngine

class SearchEngineList(private val context: Context) {

Expand All @@ -22,69 +23,86 @@ class SearchEngineList(private val context: Context) {
return bitmap
}

fun getSelectedEngine(preferences: UserPreferences): SearchEngine {
if (preferences.customSearchEngine && preferences.customSearchEngineURL.isNotBlank()) {
return SearchEngine(
id = "custom",
name = "Custom Search",
icon = getIconBitmap(com.prirai.android.nira.R.drawable.ic_search),
type = SearchEngine.Type.CUSTOM,
resultUrls = listOf(preferences.customSearchEngineURL)
)
}
val engines = getEngines()
val index = preferences.searchEngineChoice.coerceIn(engines.indices)
return engines[index]
}

fun getEngines(): List<SearchEngine> {
return listOf(
SearchEngine(
id = "google-b-m",
name = "Google",
icon = getIconBitmap(com.prirai.android.nira.R.drawable.google),
type = SearchEngine.Type.BUNDLED,
resultUrls = listOf("https://www.google.com/?q={searchTerms}"),
suggestUrl = "https://www.google.com/"
resultUrls = listOf("https://www.google.com/search?q={searchTerms}"),
suggestUrl = "https://www.google.com/complete/search?client=firefox&q={searchTerms}"
),
SearchEngine(
id = "ddg",
name = "DuckDuckGo",
icon = getIconBitmap(com.prirai.android.nira.R.drawable.duckduckgo),
type = SearchEngine.Type.BUNDLED,
resultUrls = listOf("https://www.duckduckgo.com/?q={searchTerms}"),
suggestUrl = "https://www.duckduckgo.com/"
resultUrls = listOf("https://duckduckgo.com/?q={searchTerms}"),
suggestUrl = "https://ac.duckduckgo.com/ac/?q={searchTerms}&type=list"
),
SearchEngine(
id = "bing",
name = "Bing",
icon = getIconBitmap(com.prirai.android.nira.R.drawable.microsoft_bing),
type = SearchEngine.Type.BUNDLED,
resultUrls = listOf("https://www.bing.com/?q={searchTerms}"),
suggestUrl = "https://www.bing.com/"
resultUrls = listOf("https://www.bing.com/search?q={searchTerms}"),
suggestUrl = "https://www.bing.com/osjson.aspx?query={searchTerms}"
),
SearchEngine(
id = "baidu",
name = "Baidu",
icon = getIconBitmap(com.prirai.android.nira.R.drawable.baidu),
type = SearchEngine.Type.CUSTOM,
resultUrls = listOf("https://www.baidu.com/s?wd={searchTerms}"),
suggestUrl = "https://www.baidu.com/"
suggestUrl = "https://suggestion.baidu.com/su?wd={searchTerms}&action=opensearch"
),
SearchEngine(
id = "yandex",
name = "Yandex",
icon = getIconBitmap(com.prirai.android.nira.R.drawable.yandex),
type = SearchEngine.Type.CUSTOM,
resultUrls = listOf("https://yandex.com/search/?text={searchTerms}"),
suggestUrl = "https://www.yandex.com/"
suggestUrl = "https://suggest.yandex.com/suggest-ff.cgi?part={searchTerms}"
),
SearchEngine(
id = "naver",
name = "Naver",
icon = getIconBitmap(com.prirai.android.nira.R.drawable.naver),
type = SearchEngine.Type.CUSTOM,
resultUrls = listOf("https://m.search.naver.com/search.naver?query={searchTerms}"),
suggestUrl = "https://www.naver.com/"
suggestUrl = "https://ac.search.naver.com/nx/ac?q={searchTerms}&con=0&frm=nx&ans=2&r_format=json&r_enc=UTF-8&q_enc=UTF-8&st=100"
),
SearchEngine(
id = "qwant",
name = "Qwant",
icon = getIconBitmap(com.prirai.android.nira.R.drawable.qwant),
type = SearchEngine.Type.CUSTOM,
resultUrls = listOf("https://qwant.com/?q={searchTerms}")
resultUrls = listOf("https://www.qwant.com/?q={searchTerms}"),
suggestUrl = "https://api.qwant.com/v3/suggest?q={searchTerms}"
),
SearchEngine(
id = "startpage",
name = "StartPage",
icon = getIconBitmap(com.prirai.android.nira.R.drawable.startpage),
type = SearchEngine.Type.CUSTOM,
resultUrls = listOf("https://startpage.com/sp/search?query={searchTerms}")
resultUrls = listOf("https://www.startpage.com/sp/search?query={searchTerms}"),
suggestUrl = "https://www.startpage.com/suggestions?q={searchTerms}&format=opensearch"
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,12 @@ fun TabBarCompose(
buildBarItems(order, tabs)
}

// Track initial load to prevent animated transitions showing both states
var isInitialLoad by remember { mutableStateOf(true) }
LaunchedEffect(order) {
if (order != null && isInitialLoad) {
// Small delay to ensure order is fully processed
kotlinx.coroutines.delay(50)
isInitialLoad = false
val uniqueItems = remember(items) {
items.distinctBy { item ->
when (item) {
is BarItem.SingleTab -> "tab-${item.id}"
is BarItem.Group -> "group-${item.id}"
}
}
}

Expand Down Expand Up @@ -204,15 +203,22 @@ fun TabBarCompose(
horizontalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.fillMaxWidth()
) {
itemsIndexed(items, key = { _, item -> item.id }) { index, item ->
itemsIndexed(
uniqueItems,
key = { _, item ->
when (item) {
is BarItem.SingleTab -> "tab-${item.id}"
is BarItem.Group -> "group-${item.id}"
}
}
) { index, item ->
when (item) {
is BarItem.SingleTab -> {
var offsetY by remember { mutableStateOf(0f) }
var showMenu by remember { mutableStateOf(false) }

Box(
modifier = Modifier
.then(if (!isInitialLoad) Modifier.animateItem() else Modifier)
.draggableItem(
itemType = DraggableItemType.Tab(item.tab.id),
coordinator = coordinator
Expand Down Expand Up @@ -302,7 +308,6 @@ fun TabBarCompose(

Box(
modifier = Modifier
.then(if (!isInitialLoad) Modifier.animateItem() else Modifier)
.draggableItem(
itemType = DraggableItemType.Group(item.groupId),
coordinator = coordinator
Expand Down Expand Up @@ -393,12 +398,11 @@ fun TabBarCompose(
}

// Add invisible divider after each item for drag-and-drop (except the last one)
if (index < items.size - 1) {
if (index < uniqueItems.size - 1) {
TabDivider(
id = "divider_${index + 1}",
coordinator = coordinator,
position = index + 1,
modifier = if (!isInitialLoad) Modifier.animateItem() else Modifier
position = index + 1
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ class HistoryActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
recyclerView,
object : HistoryRecyclerViewItemTouchListener.OnItemClickListener {
override fun onItemClick(view: View?, position: Int) {
val visit = (recyclerView.adapter as HistoryItemRecyclerViewAdapter).getVisitAt(position)
?: return
onBackPressedDispatcher.onBackPressed()
components.sessionUseCases.loadUrl(
(recyclerView.adapter as HistoryItemRecyclerViewAdapter).getItem(
position
).url
)
components.sessionUseCases.loadUrl(visit.url)
}

override fun onLongItemClick(view: View?, position: Int) {
val adapter = recyclerView.adapter as HistoryItemRecyclerViewAdapter
if (adapter.getVisitAt(position) == null) return
val items = arrayOf(
resources.getString(R.string.open_new),
resources.getString(R.string.open_new_private),
Expand Down
Loading
Loading