mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-15 18:36:01 -04:00
Merge pull request #2156 from briancherin/1648-search-results-new-tab
#1648 Add open in new tab button to search results
This commit is contained in:
commit
bd4335ea94
@ -151,6 +151,7 @@ import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.TAG_CURRENT_FILE;
|
||||
import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.TAG_CURRENT_POSITIONS;
|
||||
import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.TAG_CURRENT_TAB;
|
||||
import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.TAG_FILE_SEARCHED;
|
||||
import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.TAG_FILE_SEARCHED_NEW_TAB;
|
||||
import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.TAG_KIWIX;
|
||||
import static org.kiwix.kiwixmobile.core.utils.LanguageUtils.getResourceString;
|
||||
import static org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil.PREF_KIWIX_MOBILE;
|
||||
@ -430,8 +431,10 @@ public abstract class CoreReaderFragment extends BaseFragment
|
||||
private void handleIntentExtras(Intent intent) {
|
||||
|
||||
if (intent.hasExtra(TAG_FILE_SEARCHED)) {
|
||||
boolean openInNewTab = isInTabSwitcher()
|
||||
|| intent.getBooleanExtra(TAG_FILE_SEARCHED_NEW_TAB, false);
|
||||
searchForTitle(intent.getStringExtra(TAG_FILE_SEARCHED),
|
||||
isInTabSwitcher());
|
||||
openInNewTab);
|
||||
selectTab(webViewList.size() - 1);
|
||||
}
|
||||
if (intent.hasExtra(EXTRA_CHOSE_X_URL)) {
|
||||
@ -1510,7 +1513,9 @@ public abstract class CoreReaderFragment extends BaseFragment
|
||||
compatCallback.findAll();
|
||||
compatCallback.showSoftInput();
|
||||
} else {
|
||||
searchForTitle(title, wasFromTabSwitcher);
|
||||
boolean openInNewTab = wasFromTabSwitcher ||
|
||||
data.getBooleanExtra(TAG_FILE_SEARCHED_NEW_TAB, false);
|
||||
searchForTitle(title, openInNewTab);
|
||||
}
|
||||
} else if (resultCode == RESULT_CANCELED) {
|
||||
Log.w(TAG_KIWIX, "Search cancelled or exited");
|
||||
|
@ -49,6 +49,7 @@ import org.kiwix.kiwixmobile.core.search.viewmodel.Action.CreatedWithIntent
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ExitedSearch
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.Filter
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemClick
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnOpenInNewTabClick
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemLongClick
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.SearchOrigin.FromWebView
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.SearchViewModel
|
||||
@ -70,10 +71,10 @@ class SearchActivity : BaseActivity() {
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
private val searchAdapter: SearchAdapter by lazy {
|
||||
SearchAdapter(
|
||||
RecentSearchDelegate(::onItemClick) {
|
||||
RecentSearchDelegate(::onItemClick, ::onItemClickNewTab) {
|
||||
searchViewModel.actions.offer(OnItemLongClick(it))
|
||||
},
|
||||
ZimSearchResultDelegate(::onItemClick)
|
||||
ZimSearchResultDelegate(::onItemClick, ::onItemClickNewTab)
|
||||
)
|
||||
}
|
||||
|
||||
@ -155,6 +156,10 @@ class SearchActivity : BaseActivity() {
|
||||
searchViewModel.actions.offer(OnItemClick(it))
|
||||
}
|
||||
|
||||
private fun onItemClickNewTab(it: SearchListItem) {
|
||||
searchViewModel.actions.offer(OnOpenInNewTabClick(it))
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
searchViewModel.actions.offer(ActivityResultReceived(requestCode, resultCode, data))
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.kiwix.kiwixmobile.core.search.adapter
|
||||
|
||||
import android.view.ViewGroup
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.base.adapter.AbsDelegateAdapter
|
||||
import org.kiwix.kiwixmobile.core.extensions.ViewGroupExtensions.inflate
|
||||
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem.RecentSearchListItem
|
||||
@ -31,27 +32,31 @@ sealed class SearchDelegate<I : SearchListItem, out VH : SearchViewHolder<I>> :
|
||||
|
||||
class RecentSearchDelegate(
|
||||
private val onClickListener: (SearchListItem) -> Unit,
|
||||
private val onClickListenerNewTab: (SearchListItem) -> Unit,
|
||||
private val onLongClickListener: (SearchListItem) -> Unit
|
||||
) : SearchDelegate<RecentSearchListItem, RecentSearchViewHolder>() {
|
||||
override val itemClass = RecentSearchListItem::class.java
|
||||
|
||||
override fun createViewHolder(parent: ViewGroup) =
|
||||
RecentSearchViewHolder(
|
||||
parent.inflate(android.R.layout.simple_selectable_list_item, false),
|
||||
parent.inflate(R.layout.list_item_search, false),
|
||||
onClickListener,
|
||||
onClickListenerNewTab,
|
||||
onLongClickListener
|
||||
)
|
||||
}
|
||||
|
||||
class ZimSearchResultDelegate(
|
||||
private val onClickListener: (SearchListItem) -> Unit
|
||||
private val onClickListener: (SearchListItem) -> Unit,
|
||||
private val onClickListenerNewTab: (SearchListItem) -> Unit
|
||||
) : SearchDelegate<ZimSearchResultListItem, ZimSearchResultViewHolder>() {
|
||||
override val itemClass = ZimSearchResultListItem::class.java
|
||||
|
||||
override fun createViewHolder(parent: ViewGroup) =
|
||||
ZimSearchResultViewHolder(
|
||||
parent.inflate(android.R.layout.simple_selectable_list_item, false),
|
||||
onClickListener
|
||||
parent.inflate(R.layout.list_item_search, false),
|
||||
onClickListener,
|
||||
onClickListenerNewTab
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,8 @@
|
||||
package org.kiwix.kiwixmobile.core.search.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import kotlinx.android.synthetic.main.list_item_search.list_item_search_new_tab_button
|
||||
import kotlinx.android.synthetic.main.list_item_search.list_item_search_text
|
||||
import org.kiwix.kiwixmobile.core.base.adapter.BaseViewHolder
|
||||
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem.RecentSearchListItem
|
||||
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem.ZimSearchResultListItem
|
||||
@ -30,6 +31,7 @@ sealed class SearchViewHolder<in T : SearchListItem>(containerView: View) :
|
||||
class RecentSearchViewHolder(
|
||||
override val containerView: View,
|
||||
private val onClickListener: (SearchListItem) -> Unit,
|
||||
private val onClickListenerNewTab: (SearchListItem) -> Unit,
|
||||
private val onLongClickListener: (SearchListItem) -> Unit
|
||||
) : SearchViewHolder<RecentSearchListItem>(containerView) {
|
||||
override fun bind(item: RecentSearchListItem) {
|
||||
@ -38,17 +40,20 @@ sealed class SearchViewHolder<in T : SearchListItem>(containerView: View) :
|
||||
onLongClickListener(item)
|
||||
true
|
||||
}
|
||||
(containerView as TextView).text = item.value
|
||||
list_item_search_new_tab_button.setOnClickListener { onClickListenerNewTab(item) }
|
||||
list_item_search_text.text = item.value
|
||||
}
|
||||
}
|
||||
|
||||
class ZimSearchResultViewHolder(
|
||||
override val containerView: View,
|
||||
private val onClickListener: (SearchListItem) -> Unit
|
||||
private val onClickListener: (SearchListItem) -> Unit,
|
||||
private val onClickListenerNewTab: (SearchListItem) -> Unit
|
||||
) : SearchViewHolder<ZimSearchResultListItem>(containerView) {
|
||||
override fun bind(item: ZimSearchResultListItem) {
|
||||
containerView.setOnClickListener { onClickListener(item) }
|
||||
(containerView as TextView).text = item.value
|
||||
list_item_search_new_tab_button.setOnClickListener { onClickListenerNewTab(item) }
|
||||
list_item_search_text.text = item.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ sealed class Action {
|
||||
object StartSpeechInputFailed : Action()
|
||||
|
||||
data class OnItemClick(val searchListItem: SearchListItem) : Action()
|
||||
data class OnOpenInNewTabClick(val searchListItem: SearchListItem) : Action()
|
||||
|
||||
data class OnItemLongClick(val searchListItem: SearchListItem) : Action()
|
||||
data class Filter(val term: String) : Action()
|
||||
data class ScreenWasStartedFrom(val searchOrigin: SearchOrigin) : Action()
|
||||
|
@ -38,6 +38,7 @@ import org.kiwix.kiwixmobile.core.search.viewmodel.Action.CreatedWithIntent
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ExitedSearch
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.Filter
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemClick
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnOpenInNewTabClick
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemLongClick
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ReceivedPromptForSpeechInput
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ScreenWasStartedFrom
|
||||
@ -89,7 +90,8 @@ class SearchViewModel @Inject constructor(
|
||||
private fun actionMapper() = actions.map {
|
||||
when (it) {
|
||||
ExitedSearch -> effects.offer(Finish)
|
||||
is OnItemClick -> saveSearchAndOpenItem(it)
|
||||
is OnItemClick -> saveSearchAndOpenItem(it.searchListItem, false)
|
||||
is OnOpenInNewTabClick -> saveSearchAndOpenItem(it.searchListItem, true)
|
||||
is OnItemLongClick -> showDeleteDialog(it)
|
||||
is Filter -> filter.offer(it.term)
|
||||
ClickedSearchInText -> searchPreviousScreenWhenStateIsValid()
|
||||
@ -118,12 +120,12 @@ class SearchViewModel @Inject constructor(
|
||||
effects.offer(ShowDeleteSearchDialog(longClick.searchListItem, actions))
|
||||
}
|
||||
|
||||
private fun saveSearchAndOpenItem(it: OnItemClick) {
|
||||
private fun saveSearchAndOpenItem(searchListItem: SearchListItem, openInNewTab: Boolean) {
|
||||
effects.offer(
|
||||
SaveSearchToRecents(recentSearchDao, it.searchListItem, zimReaderContainer.id)
|
||||
SaveSearchToRecents(recentSearchDao, searchListItem, zimReaderContainer.id)
|
||||
)
|
||||
effects.offer(
|
||||
OpenSearchItem(it.searchListItem)
|
||||
OpenSearchItem(searchListItem, openInNewTab)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,17 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem
|
||||
import org.kiwix.kiwixmobile.core.utils.TAG_FILE_SEARCHED
|
||||
import org.kiwix.kiwixmobile.core.utils.TAG_FILE_SEARCHED_NEW_TAB
|
||||
|
||||
data class OpenSearchItem(private val searchListItem: SearchListItem) : SideEffect<Unit> {
|
||||
data class OpenSearchItem(
|
||||
private val searchListItem: SearchListItem,
|
||||
private val openInNewTab: Boolean = false
|
||||
) : SideEffect<Unit> {
|
||||
override fun invokeWith(activity: AppCompatActivity) {
|
||||
activity.setResult(
|
||||
Activity.RESULT_OK,
|
||||
Intent().putExtra(TAG_FILE_SEARCHED, searchListItem.value)
|
||||
.putExtra(TAG_FILE_SEARCHED_NEW_TAB, openInNewTab)
|
||||
)
|
||||
activity.finish()
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ const val RESULT_HISTORY_CLEARED = 1239
|
||||
|
||||
// Tags
|
||||
const val TAG_FILE_SEARCHED = "searchedarticle"
|
||||
const val TAG_FILE_SEARCHED_NEW_TAB = "searchedarticlenewtab"
|
||||
const val TAG_CURRENT_FILE = "currentzimfile"
|
||||
const val TAG_CURRENT_ARTICLES = "currentarticles"
|
||||
const val TAG_CURRENT_POSITIONS = "currentpositions"
|
||||
|
23
core/src/main/res/drawable/ic_open_in_new_24dp.xml
Normal file
23
core/src/main/res/drawable/ic_open_in_new_24dp.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<!--
|
||||
~ Kiwix Android
|
||||
~ Copyright (c) 2020 Kiwix <android.kiwix.org>
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
-->
|
||||
|
||||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#565656" android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z"/>
|
||||
</vector>
|
51
core/src/main/res/layout/list_item_search.xml
Normal file
51
core/src/main/res/layout/list_item_search.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Kiwix Android
|
||||
~ Copyright (c) 2020 Kiwix <android.kiwix.org>
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/list_item_search_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/listChoiceBackgroundIndicator"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:paddingStart="8dip"
|
||||
android:paddingEnd="8dip"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
app:layout_constraintEnd_toStartOf="@+id/list_item_search_new_tab_button"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/list_item_search_new_tab_button"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:contentDescription="@string/search_open_in_new_tab"
|
||||
app:srcCompat="@drawable/ic_open_in_new_24dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -278,6 +278,7 @@
|
||||
<string name="diagnostic_report_message">Please send all the following details so we can diagnose the problem</string>
|
||||
<string name="percentage">%d%%</string>
|
||||
<string name="pref_text_zoom_title">Text Zoom</string>
|
||||
<string name="search_open_in_new_tab">Open in new tab</string>
|
||||
<string name="experimental_navigation">Experimental Navigation</string>
|
||||
<string-array name="pref_night_modes_entries">
|
||||
<item>@string/on</item>
|
||||
|
@ -45,6 +45,7 @@ import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ExitedSearch
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.Filter
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemClick
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnItemLongClick
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.OnOpenInNewTabClick
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ReceivedPromptForSpeechInput
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.ScreenWasStartedFrom
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.Action.StartSpeechInputFailed
|
||||
@ -226,7 +227,17 @@ internal class SearchViewModelTest {
|
||||
actionResultsInEffects(
|
||||
OnItemClick(searchListItem),
|
||||
SaveSearchToRecents(recentSearchDao, searchListItem, "id"),
|
||||
OpenSearchItem(searchListItem)
|
||||
OpenSearchItem(searchListItem, false)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OnOpenInNewTabClick offers Saves and Opens in new tab`() {
|
||||
val searchListItem = RecentSearchListItem("")
|
||||
actionResultsInEffects(
|
||||
OnOpenInNewTabClick(searchListItem),
|
||||
SaveSearchToRecents(recentSearchDao, searchListItem, "id"),
|
||||
OpenSearchItem(searchListItem, true)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import io.mockk.verify
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem.RecentSearchListItem
|
||||
import org.kiwix.kiwixmobile.core.utils.TAG_FILE_SEARCHED
|
||||
import org.kiwix.kiwixmobile.core.utils.TAG_FILE_SEARCHED_NEW_TAB
|
||||
|
||||
internal class OpenSearchItemTest {
|
||||
|
||||
@ -39,8 +40,26 @@ internal class OpenSearchItemTest {
|
||||
val intent = mockk<Intent>()
|
||||
every {
|
||||
anyConstructed<Intent>().putExtra(TAG_FILE_SEARCHED, searchListItem.value)
|
||||
.putExtra(TAG_FILE_SEARCHED_NEW_TAB, false)
|
||||
} returns intent
|
||||
OpenSearchItem(searchListItem).invokeWith(activity)
|
||||
OpenSearchItem(searchListItem, false).invokeWith(activity)
|
||||
verify {
|
||||
activity.setResult(Activity.RESULT_OK, intent)
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `invoke with returns an Ok Result with list item value for new tab`() {
|
||||
val searchListItem = RecentSearchListItem("")
|
||||
val activity: AppCompatActivity = mockk()
|
||||
mockkConstructor(Intent::class)
|
||||
val intent = mockk<Intent>()
|
||||
every {
|
||||
anyConstructed<Intent>().putExtra(TAG_FILE_SEARCHED, searchListItem.value)
|
||||
.putExtra(TAG_FILE_SEARCHED_NEW_TAB, true)
|
||||
} returns intent
|
||||
OpenSearchItem(searchListItem, true).invokeWith(activity)
|
||||
verify {
|
||||
activity.setResult(Activity.RESULT_OK, intent)
|
||||
activity.finish()
|
||||
|
Loading…
x
Reference in New Issue
Block a user