diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7a9a413d2..1c9bf7da2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ - @@ -16,12 +17,22 @@ - + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/BaseMangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/BaseMangaRepository.kt index 9e60de4a4..b2c32b4d0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/BaseMangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/BaseMangaRepository.kt @@ -10,8 +10,6 @@ abstract class BaseMangaRepository(protected val loaderContext: MangaLoaderConte override val sortOrders: Set get() = emptySet() - override val isSearchAvailable get() = true - override suspend fun getPageFullUrl(page: MangaPage) : String = page.url override suspend fun getTags(): Set = emptySet() diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/MangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/MangaRepository.kt index 28ee01e4e..27009db46 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/MangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/MangaRepository.kt @@ -6,8 +6,6 @@ interface MangaRepository { val sortOrders: Set - val isSearchAvailable: Boolean - suspend fun getList(offset: Int, query: String? = null, sortOrder: SortOrder? = null, tag: MangaTag? = null): List suspend fun getDetails(manga: Manga) : Manga diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/GroupleRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/GroupleRepository.kt index 4a1e1f1a4..d3283f024 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/GroupleRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/GroupleRepository.kt @@ -25,13 +25,11 @@ abstract class GroupleRepository( sortOrder: SortOrder?, tag: MangaTag? ): List { - val url = if (tag == null) { - "https://$domain/list?sortType=${getSortKey(sortOrder)}&offset=$offset" - } else { - "https://$domain/list/genre/${tag.key}?sortType=${getSortKey(sortOrder)}&offset=$offset" - } - val doc = loaderContext.get(url) - .parseHtml() + val doc = when { + !query.isNullOrEmpty() -> loaderContext.post("https://$domain/search", mapOf("q" to query)) + tag == null -> loaderContext.get("https://$domain/list?sortType=${getSortKey(sortOrder)}&offset=$offset") + else -> loaderContext.get( "https://$domain/list/genre/${tag.key}?sortType=${getSortKey(sortOrder)}&offset=$offset") + }.parseHtml() val root = doc.body().getElementById("mangaBox") ?.selectFirst("div.tiles.row") ?: throw ParseException("Cannot find root") return root.select("div.tile").mapNotNull { node -> diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/MangaProviderFactory.kt b/app/src/main/java/org/koitharu/kotatsu/domain/MangaProviderFactory.kt index e22b11e99..d77243f59 100644 --- a/app/src/main/java/org/koitharu/kotatsu/domain/MangaProviderFactory.kt +++ b/app/src/main/java/org/koitharu/kotatsu/domain/MangaProviderFactory.kt @@ -1,13 +1,13 @@ package org.koitharu.kotatsu.domain import org.koin.core.KoinComponent -import org.koin.core.get +import org.koin.core.inject import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.parser.MangaRepository object MangaProviderFactory : KoinComponent { - private val loaderContext get() = get() + private val loaderContext by inject() fun create(source: MangaSource): MangaRepository { val constructor = source.cls.getConstructor(MangaLoaderContext::class.java) diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt index ceb2b2038..9ef2b5ef5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt @@ -57,7 +57,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList override fun onOptionsItemSelected(item: MenuItem): Boolean { return drawerToggle.onOptionsItemSelected(item) || when(item.itemId) { - else -> super.onOptionsItemSelected(item) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchActivity.kt new file mode 100644 index 000000000..59b1165b8 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchActivity.kt @@ -0,0 +1,31 @@ +package org.koitharu.kotatsu.ui.search + +import android.app.SearchManager +import android.content.Intent +import android.os.Bundle +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.ui.common.BaseActivity + +class SearchActivity : BaseActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_search) + val query = if (Intent.ACTION_SEARCH == intent.action) { + intent.getStringExtra(SearchManager.QUERY)?.trim() + } else { + null + } + if (query == null) { + finish() + return + } + supportActionBar?.setDisplayHomeAsUpEnabled(true) + title = query + supportActionBar?.setSubtitle(R.string.search_results) + supportFragmentManager + .beginTransaction() + .replace(R.id.container, SearchFragment.newInstance(query)) + .commit() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchFragment.kt new file mode 100644 index 000000000..fd17b41cd --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchFragment.kt @@ -0,0 +1,29 @@ +package org.koitharu.kotatsu.ui.search + +import moxy.ktx.moxyPresenter +import org.koitharu.kotatsu.ui.main.list.MangaListFragment +import org.koitharu.kotatsu.utils.ext.withArgs + +class SearchFragment : MangaListFragment() { + + private val presenter by moxyPresenter(factory = ::SearchPresenter) + + private val query by stringArg(ARG_QUERY) + + override fun onRequestMoreItems(offset: Int) { + presenter.loadList(query.orEmpty(), offset) + } + + override fun getTitle(): CharSequence? { + return query + } + + companion object { + + private const val ARG_QUERY = "query" + + fun newInstance(query: String) = SearchFragment().withArgs(1) { + putString(ARG_QUERY, query) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchPresenter.kt new file mode 100644 index 000000000..c0b909aff --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchPresenter.kt @@ -0,0 +1,47 @@ +package org.koitharu.kotatsu.ui.search + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import moxy.InjectViewState +import org.koitharu.kotatsu.BuildConfig +import org.koitharu.kotatsu.core.model.MangaSource +import org.koitharu.kotatsu.domain.MangaProviderFactory +import org.koitharu.kotatsu.ui.common.BasePresenter +import org.koitharu.kotatsu.ui.main.list.MangaListView + +@InjectViewState +class SearchPresenter : BasePresenter>() { + + private lateinit var sources: Array + + override fun onFirstViewAttach() { + sources = MangaSource.values() + super.onFirstViewAttach() + } + + fun loadList(query: String, offset: Int) { + launch { + viewState.onLoadingChanged(true) + try { + //TODO select source + val list = withContext(Dispatchers.IO) { + MangaProviderFactory.create(MangaSource.READMANGA_RU) + .getList(offset, query = query) + } + if (offset == 0) { + viewState.onListChanged(list) + } else { + viewState.onListAppended(list) + } + } catch (e: Exception) { + if (BuildConfig.DEBUG) { + e.printStackTrace() + } + viewState.onError(e) + } finally { + viewState.onLoadingChanged(false) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/SearchHelper.kt b/app/src/main/java/org/koitharu/kotatsu/utils/SearchHelper.kt index a101df1db..8d7c928fa 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/SearchHelper.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/SearchHelper.kt @@ -1,13 +1,20 @@ package org.koitharu.kotatsu.utils +import android.app.SearchManager +import android.content.ComponentName +import android.content.Context import android.view.MenuItem import androidx.appcompat.widget.SearchView +import org.koitharu.kotatsu.ui.search.SearchActivity object SearchHelper { @JvmStatic fun setupSearchView(menuItem: MenuItem) { val view = menuItem.actionView as? SearchView ?: return - //TODO + val context = view.context + val searchManager = context.applicationContext.getSystemService(Context.SEARCH_SERVICE) as SearchManager + val info = searchManager.getSearchableInfo(ComponentName(context, SearchActivity::class.java)) + view.setSearchableInfo(info) } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml new file mode 100644 index 000000000..bf6953216 --- /dev/null +++ b/app/src/main/res/layout/activity_search.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index faba3e7c4..61db1aaf5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,4 +35,6 @@ Create shortcut… Share %s Search + Search manga + Search results \ No newline at end of file diff --git a/app/src/main/res/xml/search.xml b/app/src/main/res/xml/search.xml new file mode 100644 index 000000000..161c80dd9 --- /dev/null +++ b/app/src/main/res/xml/search.xml @@ -0,0 +1,8 @@ + +