From fe316b5bbc9ca63c2f34bbdddc5e4699ade7fab7 Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 16 Jan 2020 23:27:40 -0800 Subject: [PATCH] Created searchactivity So jumping from extension intent to tachi is a better experince --- app/src/main/AndroidManifest.xml | 8 +- .../CatalogueSearchController.kt | 32 ++- .../kanade/tachiyomi/ui/main/MainActivity.kt | 29 ++- .../tachiyomi/ui/main/SearchActivity.kt | 241 ++++++++++++++++++ .../tachiyomi/ui/manga/MangaController.kt | 24 +- .../ui/manga/chapter/ChaptersController.kt | 6 +- .../ui/manga/info/MangaInfoController.kt | 4 +- 7 files changed, 304 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 90e37f3e10..8e4724bf52 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,12 +30,18 @@ android:networkSecurityConfig="@xml/network_security_config"> + + + + + diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/global_search/CatalogueSearchController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/global_search/CatalogueSearchController.kt index 5cefa5de6b..4fe98ad272 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/global_search/CatalogueSearchController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/global_search/CatalogueSearchController.kt @@ -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) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 55170c0b1f..e1f3a1076f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -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 } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt new file mode 100644 index 0000000000..2fd5019a2b --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt @@ -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(R.id.action_mode_bar) + contextView?.updateLayoutParams { + 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 + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index 3ab121fda9..baf637a923 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -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().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() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt index da476e4f99..76a9ffdd50 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt @@ -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(), 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() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt index cc84e0adf2..f8c0806629 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt @@ -749,8 +749,8 @@ class MangaInfoController : NucleusController(), } 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