Created searchactivity

So jumping from extension intent to tachi is a better experince
This commit is contained in:
Jay 2020-01-16 23:27:40 -08:00
parent 6a7e9937de
commit fe316b5bbc
7 changed files with 304 additions and 40 deletions

View File

@ -30,12 +30,18 @@
android:networkSecurityConfig="@xml/network_security_config">
<activity
android:name=".ui.main.MainActivity"
android:launchMode="singleTask"
android:theme="@style/Theme.Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/>
<!--suppress AndroidDomInspection -->
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/>
</activity>
<activity
android:name=".ui.main.SearchActivity"
android:theme="@style/Theme.Splash">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<action android:name="com.google.android.gms.actions.SEARCH_ACTION"/>

View File

@ -1,9 +1,13 @@
package eu.kanade.tachiyomi.ui.catalogue.global_search
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.SearchView
import android.view.*
import com.jakewharton.rxbinding.support.v7.widget.queryTextChangeEvents
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga
@ -30,6 +34,8 @@ open class CatalogueSearchController(
*/
protected var adapter: CatalogueSearchAdapter? = null
private var customTitle:String? = null
/**
* Called when controller is initialized.
*/
@ -54,7 +60,7 @@ open class CatalogueSearchController(
* @return title.
*/
override fun getTitle(): String? {
return presenter.query
return customTitle ?: presenter.query
}
/**
@ -100,6 +106,7 @@ open class CatalogueSearchController(
val searchItem = menu.findItem(R.id.action_search)
val searchView = searchItem.actionView as SearchView
searchItem.isVisible = customTitle == null
searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
searchView.onActionViewExpanded() // Required to show the query in the view
@ -135,6 +142,11 @@ open class CatalogueSearchController(
recycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(view.context)
recycler.adapter = adapter
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
if (extensionFilter != null)
{
customTitle = view.context?.getString(R.string.loading)
setTitle()
}
}
override fun onDestroyView(view: View) {
@ -171,13 +183,6 @@ open class CatalogueSearchController(
return null
}
override fun handleBack(): Boolean {
return if (extensionFilter != null) {
activity?.finishAffinity()
true
} else super.handleBack()
}
/**
* Add search result to adapter.
*
@ -188,11 +193,16 @@ open class CatalogueSearchController(
val results = searchResult.first().results
if (results != null && results.size == 1) {
val manga = results.first().manga
router.pushController(MangaController(manga,true,fromExtension = true)
router.replaceTopController(MangaController(manga,true,fromExtension = true)
.withFadeTransaction()
)
return
}
else if (results != null) {
customTitle = null
setTitle()
activity?.invalidateOptionsMenu()
}
}
adapter?.updateDataSet(searchResult)
}

View File

@ -73,19 +73,22 @@ import uy.kohesive.injekt.injectLazy
import java.util.Date
import java.util.concurrent.TimeUnit
class MainActivity : BaseActivity() {
open class MainActivity : BaseActivity() {
private lateinit var router: Router
protected lateinit var router: Router
val preferences: PreferencesHelper by injectLazy()
private var drawerArrow: DrawerArrowDrawable? = null
protected var drawerArrow: DrawerArrowDrawable? = null
protected open var trulyGoBack = false
private var secondaryDrawer: ViewGroup? = null
private var snackBar:Snackbar? = null
var extraViewForUndo:View? = null
private var extraViewForUndo:View? = null
private var canDismissSnackBar = false
fun setUndoSnackBar(snackBar: Snackbar?, extraViewToCheck: View? = null) {
this.snackBar = snackBar
canDismissSnackBar = false
@ -117,7 +120,8 @@ class MainActivity : BaseActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
// Some webview somwewhere breaks night mode, we create a webview to solve this: https://stackoverflow.com/a/45430282
// Some webview somewwhere breaks night mode, we create a webview to solve this:
// https://stackoverflow.com/a/45430282
if (preferences.theme() in 2..4) {
Timber.d("Manually instantiating WebView to avoid night mode issue.");
try {
@ -132,12 +136,13 @@ class MainActivity : BaseActivity() {
else -> MODE_NIGHT_FOLLOW_SYSTEM
})
super.onCreate(savedInstanceState)
if (trulyGoBack) return
// Do not let the launcher create a new activity http://stackoverflow.com/questions/16283079
if (!isTaskRoot) {
/* if (!isTaskRoot) {
finish()
return
}
}*/
setContentView(R.layout.main_activity)
@ -291,7 +296,7 @@ class MainActivity : BaseActivity() {
setExtensionsBadge()
}
fun setExtensionsBadge() {
private fun setExtensionsBadge() {
val extUpdateText: TextView = nav_view.menu.findItem(
R.id.nav_drawer_extensions
@ -346,7 +351,7 @@ class MainActivity : BaseActivity() {
}
}
private fun handleIntentAction(intent: Intent): Boolean {
protected open fun handleIntentAction(intent: Intent): Boolean {
val notificationId = intent.getIntExtra("notificationId", -1)
if (notificationId > -1) NotificationReceiver.dismissNotification(
applicationContext, notificationId, intent.getIntExtra("groupId", 0)
@ -401,6 +406,10 @@ class MainActivity : BaseActivity() {
}
override fun onBackPressed() {
if (trulyGoBack) {
super.onBackPressed()
return
}
val backstackSize = router.backstackSize
if (drawer.isDrawerOpen(GravityCompat.START) || drawer.isDrawerOpen(GravityCompat.END)) {
drawer.closeDrawers()
@ -449,7 +458,7 @@ class MainActivity : BaseActivity() {
return super.dispatchTouchEvent(ev)
}
private fun syncActivityViewWithController(to: Controller?, from: Controller? = null) {
protected open fun syncActivityViewWithController(to: Controller?, from: Controller? = null) {
if (from is DialogController || to is DialogController) {
return
}

View File

@ -0,0 +1,241 @@
package eu.kanade.tachiyomi.ui.main
import android.animation.ObjectAnimator
import android.app.SearchManager
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
import androidx.core.graphics.ColorUtils
import androidx.core.view.GravityCompat
import com.bluelinelabs.conductor.Conductor
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.Router
import com.bluelinelabs.conductor.RouterTransaction
import com.google.android.material.tabs.TabLayout
import eu.kanade.tachiyomi.Migrations
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
import eu.kanade.tachiyomi.ui.download.DownloadController
import eu.kanade.tachiyomi.ui.extension.ExtensionController
import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
import eu.kanade.tachiyomi.util.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.getResourceColor
import eu.kanade.tachiyomi.util.marginBottom
import eu.kanade.tachiyomi.util.marginTop
import eu.kanade.tachiyomi.util.openInBrowser
import eu.kanade.tachiyomi.util.updateLayoutParams
import eu.kanade.tachiyomi.util.updatePadding
import eu.kanade.tachiyomi.util.updatePaddingRelative
import kotlinx.android.synthetic.main.search_activity.*
import timber.log.Timber
import uy.kohesive.injekt.injectLazy
class SearchActivity: MainActivity() {
override var trulyGoBack = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.search_activity)
setSupportActionBar(sToolbar)
drawerArrow = DrawerArrowDrawable(this)
drawerArrow?.color = Color.WHITE
sToolbar.navigationIcon = drawerArrow
tabAnimator = TabsAnimator(sTabs)
// Set behavior of Navigation drawer
//router.setRoot(controller.withFadeTransaction().tag(id.toString()))
val container: ViewGroup = findViewById(R.id.controller_container)
val content: LinearLayout = findViewById(R.id.main_content)
container.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
content.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
content.setOnApplyWindowInsetsListener { v, insets ->
window.navigationBarColor =
// if the os does not support light nav bar and is portrait, draw a dark translucent
// nav bar
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
(v.rootWindowInsets.systemWindowInsetLeft > 0 ||
v.rootWindowInsets.systemWindowInsetRight > 0))
// For lollipop, draw opaque nav bar
Color.BLACK
else Color.argb(179, 0, 0, 0)
}
// if the android q+ device has gesture nav, transparent nav bar
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& (v.rootWindowInsets.systemWindowInsetBottom != v.rootWindowInsets
.tappableElementInsets.bottom)) {
getColor(android.R.color.transparent)
}
// if in landscape with 2/3 button mode, fully opaque nav bar
else if (v.rootWindowInsets.systemWindowInsetLeft > 0
|| v.rootWindowInsets.systemWindowInsetRight > 0) {
getResourceColor(android.R.attr.colorBackground)
}
// if in portrait with 2/3 button mode, translucent nav bar
else {
ColorUtils.setAlphaComponent(
getResourceColor(android.R.attr.colorBackground), 179)
}
v.setPadding(insets.systemWindowInsetLeft, insets.systemWindowInsetTop,
insets.systemWindowInsetRight, 0)
insets
}
val currentNightMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
if (Build.VERSION.SDK_INT >= 26 && currentNightMode == Configuration.UI_MODE_NIGHT_NO) {
content.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
}
val drawerContainer: FrameLayout = findViewById(R.id.search_container)
drawerContainer.setOnApplyWindowInsetsListener { v, insets ->
window.statusBarColor = getResourceColor(R.attr.colorPrimary)
val contextView = window?.decorView?.findViewById<View>(R.id.action_mode_bar)
contextView?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
leftMargin = insets.systemWindowInsetLeft
rightMargin = insets.systemWindowInsetRight
}
// Consume any horizontal insets and pad all content in. There's not much we can do
// with horizontal insets
v.updatePadding(
left = insets.systemWindowInsetLeft,
right = insets.systemWindowInsetRight
)
insets.replaceSystemWindowInsets(
0, insets.systemWindowInsetTop,
0, insets.systemWindowInsetBottom
)
}
router = Conductor.attachRouter(this, container, savedInstanceState)
if (!router.hasRootController()) {
// Set start screen
handleIntentAction(intent)
}
sToolbar.setNavigationOnClickListener {
popToRoot()
}
router.addChangeListener(object : ControllerChangeHandler.ControllerChangeListener {
override fun onChangeStarted(to: Controller?, from: Controller?, isPush: Boolean,
container: ViewGroup, handler: ControllerChangeHandler
) {
syncActivityViewWithController(to, from)
}
override fun onChangeCompleted(to: Controller?, from: Controller?, isPush: Boolean,
container: ViewGroup, handler: ControllerChangeHandler
) {
}
})
syncActivityViewWithController(router.backstack.lastOrNull()?.controller())
}
private fun Context.popToRoot() {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK or Intent
.FLAG_ACTIVITY_REORDER_TO_FRONT
action = when (preferences.startScreen()) {
2 -> SHORTCUT_RECENTLY_READ
3 -> SHORTCUT_RECENTLY_UPDATED
else -> SHORTCUT_LIBRARY
}
}
startActivity(intent)
finishAfterTransition()
}
override fun syncActivityViewWithController(to: Controller?, from: Controller?) {
if (from is DialogController || to is DialogController) {
return
}
drawerArrow?.progress = 1f
if (from is TabbedController) {
from.cleanupTabs(sTabs)
}
if (to is TabbedController) {
tabAnimator.expand()
to.configureTabs(sTabs)
} else {
tabAnimator.collapse()
sTabs.setupWithViewPager(null)
}
if (to is NoToolbarElevationController) {
appbar.disableElevation()
} else {
appbar.enableElevation()
}
}
override fun handleIntentAction(intent: Intent): Boolean {
val notificationId = intent.getIntExtra("notificationId", -1)
if (notificationId > -1) NotificationReceiver.dismissNotification(
applicationContext, notificationId, intent.getIntExtra("groupId", 0)
)
when (intent.action) {
Intent.ACTION_SEARCH, "com.google.android.gms.actions.SEARCH_ACTION" -> {
//If the intent match the "standard" Android search intent
// or the Google-specific search intent (triggered by saying or typing "search *query* on *Tachiyomi*" in Google Search/Google Assistant)
//Get the search query provided in extras, and if not null, perform a global search with it.
val query = intent.getStringExtra(SearchManager.QUERY)
if (query != null && query.isNotEmpty()) {
router.replaceTopController(CatalogueSearchController(query).withFadeTransaction())
}
}
INTENT_SEARCH -> {
val query = intent.getStringExtra(INTENT_SEARCH_QUERY)
val filter = intent.getStringExtra(INTENT_SEARCH_FILTER)
if (query != null && query.isNotEmpty()) {
if (router.backstackSize > 1) {
router.popToRoot()
}
router.replaceTopController(CatalogueSearchController(query, filter).withFadeTransaction())
}
}
else -> return false
}
return true
}
}

View File

@ -27,12 +27,15 @@ import eu.kanade.tachiyomi.ui.base.controller.RxController
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.SearchActivity
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersController
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
import eu.kanade.tachiyomi.ui.manga.track.TrackController
import eu.kanade.tachiyomi.util.toast
import kotlinx.android.synthetic.main.main_activity.*
import kotlinx.android.synthetic.main.manga_controller.*
import kotlinx.android.synthetic.main.search_activity.*
import rx.Subscription
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -66,7 +69,6 @@ class MangaController : RxController, TabbedController {
if (manga != null) {
source = Injekt.get<SourceManager>().getOrStub(manga.source)
}
backClosesApp = fromExtension
}
constructor(manga: Manga?, startY:Float?) : super(Bundle().apply {
@ -91,21 +93,12 @@ class MangaController : RxController, TabbedController {
)
}
override fun handleBack(): Boolean {
return if (backClosesApp) {
activity?.finishAffinity()
true
} else super.handleBack()
}
var manga: Manga? = null
private set
var source: Source? = null
private set
private var backClosesApp = false
var startingChapterYPos:Float? = null
private var adapter: MangaDetailAdapter? = null
@ -153,11 +146,16 @@ class MangaController : RxController, TabbedController {
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
super.onChangeStarted(handler, type)
if (type.isEnter) {
activity?.tabs?.setupWithViewPager(manga_pager)
tabLayout()?.setupWithViewPager(manga_pager)
trackingIconSubscription = trackingIconRelay.subscribe { setTrackingIconInternal(it) }
}
}
fun tabLayout():TabLayout? {
return if (activity is SearchActivity) activity?.sTabs
else activity?.tabs
}
override fun onChangeEnded(handler: ControllerChangeHandler, type: ControllerChangeType) {
super.onChangeEnded(handler, type)
if (manga == null || source == null) {
@ -183,7 +181,7 @@ class MangaController : RxController, TabbedController {
}
private fun setTrackingIconInternal(visible: Boolean) {
val tab = activity?.tabs?.getTabAt(TRACK_CONTROLLER) ?: return
val tab = tabLayout()?.getTabAt(TRACK_CONTROLLER) ?: return
val drawable = if (visible)
VectorDrawableCompat.create(resources!!, R.drawable.ic_done_white_18dp, null)
else null
@ -209,7 +207,7 @@ class MangaController : RxController, TabbedController {
}
override fun configureRouter(router: Router, position: Int) {
val touchOffset = if (activity?.tabs?.height == 0) 144f else 0f
val touchOffset = if (tabLayout()?.height == 0) 144f else 0f
if (!router.hasRootController()) {
val controller = when (position) {
INFO_CONTROLLER -> MangaInfoController()

View File

@ -26,7 +26,6 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.popControllerWithTag
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
@ -114,8 +113,9 @@ class ChaptersController() : NucleusController<ChaptersPresenter>(),
bottomMargin = insets.systemWindowInsetBottom
}
// offset the recycler by the fab's inset + some inset on top
v.updatePaddingRelative(bottom = padding.bottom + (fab?.marginBottom ?: 0) +
fabBaseMarginBottom + (fab?.height ?: 0))
val scale: Float = v.context.resources.displayMetrics.density
val pixels = (88 * scale + 0.5f).toInt()
v.updatePaddingRelative(bottom = padding.bottom + insets.systemWindowInsetBottom + pixels)
}
swipe_refresh.refreshes().subscribeUntilDestroy { fetchChaptersFromSource() }

View File

@ -749,8 +749,8 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
}
override fun handleBack(): Boolean {
if (manga_cover_full?.visibility == View.VISIBLE && activity?.tabs?.selectedTabPosition
== 0)
if (manga_cover_full?.visibility == View.VISIBLE &&
(parentController as? MangaController)?.tabLayout()?.selectedTabPosition == 0)
{
manga_cover_full?.performClick()
return true