From 52e6a7fc9510bcef4df2418a86440e9f14986d31 Mon Sep 17 00:00:00 2001 From: Jay Date: Tue, 3 Mar 2020 20:31:17 -0800 Subject: [PATCH] Updates to stuff once more More manga type handling Fixed download progress colors Manga controller now listens to global updates Removed search activity layout, using main activty with navbar hidden Empty library while using filters now has new text --- .../tachiyomi/data/database/models/Manga.kt | 36 +++-- .../data/library/LibraryUpdateService.kt | 5 +- .../tachiyomi/ui/download/DownloadButton.kt | 4 +- .../tachiyomi/ui/library/LibraryController.kt | 2 +- .../ui/library/LibraryListController.kt | 6 +- .../tachiyomi/ui/library/LibraryPresenter.kt | 7 +- .../kanade/tachiyomi/ui/main/MainActivity.kt | 26 +-- .../tachiyomi/ui/main/SearchActivity.kt | 148 +----------------- .../ui/manga/MangaChaptersController.kt | 63 +++++--- .../tachiyomi/ui/manga/MangaController.kt | 5 +- .../tachiyomi/ui/manga/MangaHeaderHolder.kt | 1 + .../tachiyomi/ui/manga/MangaPresenter.kt | 53 +++---- .../ui/manga/info/MangaInfoController.kt | 2 - .../ui/security/BiometricActivity.kt | 4 +- .../ui/security/SecureActivityDelegate.kt | 2 + .../util/system/ContextExtensions.kt | 6 +- .../tachiyomi/widget/ElevationAppBarLayout.kt | 29 ++-- app/src/main/res/layout/main_activity.xml | 24 ++- app/src/main/res/layout/search_activity.xml | 50 ------ app/src/main/res/values/strings.xml | 2 + 20 files changed, 152 insertions(+), 323 deletions(-) delete mode 100644 app/src/main/res/layout/search_activity.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt index a5cba0d785..c1351872d3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt @@ -3,7 +3,8 @@ package eu.kanade.tachiyomi.data.database.models import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.ui.reader.ReaderActivity -import uy.kohesive.injekt.injectLazy +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get import java.util.Locale interface Manga : SManga { @@ -35,47 +36,62 @@ interface Manga : SManga { } fun mangaType(): Int { - val sourceManager: SourceManager by injectLazy() + val sourceName = Injekt.get().getOrStub(source).name val currentTags = currentGenres()?.split(",")?.map { it.trim().toLowerCase(Locale.US) } return if (currentTags?.any { tag -> tag.startsWith("english") || tag == "comic" - } == true) + } == true || isComicSource(sourceName)) TYPE_COMIC else if (currentTags?.any { tag -> tag.startsWith("chinese") || tag == "manhua" - } == true) + } == true || + sourceName.contains("manhua", true)) TYPE_MANHUA else if (currentTags?.any { tag -> tag == "long strip" || tag == "manhwa" || tag.contains("webtoon") - } == true || - sourceManager.getOrStub(source).name.contains("webtoon", true)) + } == true || isWebtoonSource(sourceName)) TYPE_MANHWA else TYPE_MANGA } fun defaultReaderType(): Int { - val sourceManager: SourceManager by injectLazy() + val sourceName = Injekt.get().getOrStub(source).name val currentTags = currentGenres()?.split(",")?.map { it.trim().toLowerCase(Locale.US) } return if (currentTags?.any { tag -> tag == "long strip" || tag == "manhwa" || tag.contains("webtoon") - } == true || - sourceManager.getOrStub(source).name.contains("webtoon", true)) + } == true || isWebtoonSource(sourceName)) ReaderActivity.WEBTOON else if (currentTags?.any { tag -> tag.startsWith("chinese") || tag == "manhua" || tag.startsWith("english") || tag == "comic" - } == true) + } == true || isComicSource(sourceName) || + sourceName.contains("manhua", true) ) ReaderActivity.LEFT_TO_RIGHT else 0 } + fun isWebtoonSource(sourceName: String): Boolean { + return sourceName.contains("webtoon", true) || + sourceName.contains("manwha", true) || + sourceName.contains("toonily", true) + } + + fun isComicSource(sourceName: String): Boolean { + return sourceName.contains("gunnerkrigg", true) || + sourceName.contains("gunnerkrigg", true) || + sourceName.contains("dilbert", true) || + sourceName.contains("cyanide", true) || + sourceName.contains("xkcd", true) || + sourceName.contains("tapastic", true) + } + // Used to display the chapter's title one way or another var displayMode: Int get() = chapter_flags and DISPLAY_MASK diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt index 1a9294c194..9319f77f5d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt @@ -196,8 +196,9 @@ class LibraryUpdateService( this.listener = listener } - fun removeListener() { - listener = null + fun removeListener(listener: LibraryServiceListener) { + if (this.listener == listener) + this.listener = null } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadButton.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadButton.kt index 64f77d178f..5f4a01851f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadButton.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadButton.kt @@ -17,6 +17,8 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut : FrameLayout(context, attrs) { private val activeColor = context.getResourceColor(R.attr.colorAccent) + private val progressBGColor = ContextCompat.getColor(context, + R.color.divider) private val disabledColor = ContextCompat.getColor(context, R.color.material_on_surface_disabled) private val downloadedColor = ContextCompat.getColor(context, @@ -60,7 +62,7 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut download_border.setImageDrawable(borderCircle) download_progress.isIndeterminate = false download_progress.progress = progress - download_border.drawable.setTint(disabledColor) + download_border.drawable.setTint(progressBGColor) download_progress.progressDrawable?.setTint(downloadedColor) download_icon.drawable.setTint(disabledColor) if (!isAnimating) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index dc486d68b4..c882759869 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -299,7 +299,7 @@ open class LibraryController( override fun onDestroyView(view: View) { pagerAdapter?.onDestroy() DownloadService.removeListener(this) - LibraryUpdateService.removeListener() + LibraryUpdateService.removeListener(this) pagerAdapter = null actionMode = null tabsVisibilitySubscription?.unsubscribe() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListController.kt index a425ab35d8..3f395484cc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListController.kt @@ -222,7 +222,11 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle), if (mangaMap.isNotEmpty()) { empty_view?.hide() } else { - empty_view?.show(R.drawable.ic_book_black_128dp, R.string.information_empty_library) + empty_view?.show( + R.drawable.ic_book_black_128dp, + if (bottom_sheet.hasActiveFilters()) R.string.information_empty_library_filtered + else R.string.information_empty_library + ) } adapter.setItems(mangaMap) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 39b33e6dbd..6ab2a3a5d7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -170,14 +170,9 @@ class LibraryPresenter( if (filterUnread == STATE_REALLY_EXCLUDE && item.manga.unread > 0) return@f false if (filterMangaType > 0) { - val mangaType = item.manga.mangaType() - if ((filterMangaType == Manga.TYPE_MANHUA) && mangaType != Manga.TYPE_MANHUA) - return@f false - if ((filterMangaType == Manga.TYPE_COMIC) && mangaType != Manga.TYPE_COMIC) return@f false - if ((filterMangaType == Manga.TYPE_MANHWA) && mangaType != Manga.TYPE_MANHWA) return@f false + if (filterMangaType != item.manga.mangaType()) return@f false } - if (filterCompleted == STATE_INCLUDE && item.manga.status != SManga.COMPLETED) return@f false if (filterCompleted == STATE_EXCLUDE && item.manga.status == SManga.COMPLETED) 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 de15c4f151..e4e1456cbd 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 @@ -80,8 +80,6 @@ open class MainActivity : BaseActivity(), DownloadServiceListener { private var currentGestureDelegate:SwipeGestureInterface? = null private lateinit var gestureDetector:GestureDetectorCompat - protected open var trulyGoBack = false - private var secondaryDrawer: ViewGroup? = null private var snackBar:Snackbar? = null @@ -112,7 +110,6 @@ open class MainActivity : BaseActivity(), DownloadServiceListener { Timber.e(e, "Exception when creating webview at start") } super.onCreate(savedInstanceState) - if (trulyGoBack) return // Do not let the launcher create a new activity http://stackoverflow.com/questions/16283079 if (!isTaskRoot) { @@ -314,8 +311,6 @@ open class MainActivity : BaseActivity(), DownloadServiceListener { container: ViewGroup, handler: ControllerChangeHandler) { syncActivityViewWithController(to, from) - if (to !is DialogController) - navigationView.visibility = if (router.backstackSize > 1) View.GONE else View.VISIBLE } override fun onChangeCompleted(to: Controller?, from: Controller?, isPush: Boolean, @@ -394,7 +389,6 @@ open class MainActivity : BaseActivity(), DownloadServiceListener { override fun onResume() { super.onResume() // setting in case someone comes from the search activity to main - usingBottomNav = true getExtensionUpdates() DownloadService.callListeners() } @@ -501,10 +495,10 @@ open class MainActivity : BaseActivity(), DownloadServiceListener { } override fun onBackPressed() { - if (trulyGoBack) { + /*if (trulyGoBack) { super.onBackPressed() return - } + }*/ /*if (drawer.isDrawerOpen(GravityCompat.START) || drawer.isDrawerOpen(GravityCompat.END)) { drawer.closeDrawers() } else {*/ @@ -560,17 +554,6 @@ open class MainActivity : BaseActivity(), DownloadServiceListener { } drawerArrow?.progress = 1f - /* if (from is TabbedController) { - from.cleanupTabs(tabs) - } - if (to is TabbedController) { - tabAnimator.expand() - to.configureTabs(tabs) - } else { - tabAnimator.collapse() - tabs.setupWithViewPager(null) - }*/ - currentGestureDelegate = to as? SwipeGestureInterface /*if (from is SecondaryDrawerController) { @@ -593,6 +576,9 @@ open class MainActivity : BaseActivity(), DownloadServiceListener { } else { appbar.enableElevation() } + + if (to !is DialogController) + navigationView.visibility = if (router.backstackSize > 1) View.GONE else View.VISIBLE } override fun downloadStatusChanged(downloading: Boolean) { @@ -672,8 +658,6 @@ open class MainActivity : BaseActivity(), DownloadServiceListener { const val INTENT_SEARCH_QUERY = "query" const val INTENT_SEARCH_FILTER = "filter" - var usingBottomNav = true - internal set } } 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 index 1e91002e44..15b731136f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt @@ -2,148 +2,24 @@ package eu.kanade.tachiyomi.ui.main import android.app.SearchManager 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.widget.FrameLayout -import android.widget.LinearLayout -import androidx.appcompat.graphics.drawable.DrawerArrowDrawable -import androidx.core.graphics.ColorUtils -import com.bluelinelabs.conductor.Conductor import com.bluelinelabs.conductor.Controller -import com.bluelinelabs.conductor.ControllerChangeHandler -import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate -import eu.kanade.tachiyomi.util.system.getResourceColor -import eu.kanade.tachiyomi.util.view.updateLayoutParams -import eu.kanade.tachiyomi.util.view.updatePadding -import kotlinx.android.synthetic.main.search_activity.* +import eu.kanade.tachiyomi.util.view.gone +import kotlinx.android.synthetic.main.main_activity.* class SearchActivity: MainActivity() { - override var trulyGoBack = true override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - usingBottomNav = false - setContentView(R.layout.search_activity) - - setSupportActionBar(sToolbar) - - drawerArrow = DrawerArrowDrawable(this) - drawerArrow?.color = getResourceColor(R.attr.actionBarTintColor) - sToolbar.navigationIcon = drawerArrow - - //tabAnimator = TabsAnimator(sTabs) - - 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 && - preferences.theme() >= 8) { - content.systemUiVisibility = content.systemUiVisibility.or(View - .SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && currentNightMode == Configuration - .UI_MODE_NIGHT_NO && preferences.theme() >= 8) - content.systemUiVisibility = content.systemUiVisibility.or(View - .SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) - - val searchContainer: FrameLayout = findViewById(R.id.search_container) - searchContainer.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 { + toolbar.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()) } override fun onBackPressed() { @@ -167,29 +43,15 @@ class SearchActivity: MainActivity() { if (from is DialogController || to is DialogController) { return } + toolbar.navigationIcon = drawerArrow 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 onResume() { - super.onResume() - usingBottomNav = false + navigationView.gone() } override fun handleIntentAction(intent: Intent): Boolean { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChaptersController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChaptersController.kt index 487bd9d14f..1e227db855 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChaptersController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChaptersController.kt @@ -44,6 +44,7 @@ import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.ui.base.controller.BaseController +import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController import eu.kanade.tachiyomi.ui.catalogue.CatalogueController import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog import eu.kanade.tachiyomi.ui.library.LibraryController @@ -75,7 +76,8 @@ class MangaChaptersController : BaseController, FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemLongClickListener, ChaptersAdapter.MangaHeaderInterface, - ChangeMangaCategoriesDialog.Listener { + ChangeMangaCategoriesDialog.Listener, + NoToolbarElevationController { constructor(manga: Manga?, fromCatalogue: Boolean = false, @@ -148,11 +150,11 @@ class MangaChaptersController : BaseController, val array = view.context.obtainStyledAttributes(attrsArray) val appbarHeight = array.getDimensionPixelSize(0, 0) array.recycle() - val offset = 20.dpToPx + val offset = 10.dpToPx recycler.doOnApplyWindowInsets { v, insets, _ -> - headerHeight = appbarHeight + insets.systemWindowInsetTop + offset - swipe_refresh.setProgressViewOffset(false, (-40).dpToPx, headerHeight) + headerHeight = appbarHeight + insets.systemWindowInsetTop + swipe_refresh.setProgressViewOffset(false, (-40).dpToPx, headerHeight + offset) (recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder) ?.setTopHeight(headerHeight) fast_scroller?.updateLayoutParams { @@ -169,15 +171,18 @@ class MangaChaptersController : BaseController, val atTop = !recycler.canScrollVertically(-1) if ((!atTop && !toolbarIsColored) || (atTop && toolbarIsColored)) { toolbarIsColored = !atTop - colorAnimator?.cancel() val color = coverColor ?: activity!!.getResourceColor(android.R.attr.colorPrimary) - val colorFrom = ColorUtils.setAlphaComponent( - color, if (toolbarIsColored) 0 else 255 - ) + val colorFrom = + if (colorAnimator?.isRunning == true) activity?.window?.statusBarColor + ?: color + else ColorUtils.setAlphaComponent( + color, if (toolbarIsColored) 0 else 255 + ) val colorTo = ColorUtils.setAlphaComponent( color, if (toolbarIsColored) 255 else 0 ) + colorAnimator?.cancel() colorAnimator = ValueAnimator.ofObject( ArgbEvaluator(), colorFrom, colorTo ) @@ -192,6 +197,15 @@ class MangaChaptersController : BaseController, } } } + setPaletteColor() + + swipe_refresh.setOnRefreshListener { + presenter.refreshAll() + } + } + + fun setPaletteColor() { + val view = view ?: return GlideApp.with(view.context).load(manga) .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) .signature(ObjectKey(MangaImpl.getLastCoverFetch(manga!!.id!!).toString())) @@ -224,19 +238,17 @@ class MangaChaptersController : BaseController, override fun onLoadCleared(placeholder: Drawable?) { } }) - - swipe_refresh.setOnRefreshListener { - presenter.refreshAll() - } } override fun onActivityResumed(activity: Activity) { super.onActivityResumed(activity) + presenter.isLockedFromSearch = SecureActivityDelegate.shouldBeLocked() + presenter.headerItem.isLocked = presenter.isLockedFromSearch presenter.fetchChapters() } fun showError(message: String) { - swipe_refresh?.isRefreshing = false + swipe_refresh?.isRefreshing = presenter.isLoading view?.snack(message) } @@ -275,25 +287,25 @@ class MangaChaptersController : BaseController, fun updateHeader() { if (presenter.chapters.isEmpty()) { - adapter?.updateDataSet(listOf(ChapterItem(Chapter.createH(), presenter.manga))) + adapter?.updateDataSet(listOf(presenter.headerItem)) } else { - swipe_refresh?.isRefreshing = false + swipe_refresh?.isRefreshing = presenter.isLoading adapter?.updateDataSet( - listOf(ChapterItem(Chapter.createH(), presenter.manga)) + presenter.chapters + listOf(ChapterItem(presenter.headerItem, presenter.manga)) + presenter.chapters ) } } fun updateChapters(chapters: List) { - swipe_refresh?.isRefreshing = false + swipe_refresh?.isRefreshing = presenter.isLoading if (presenter.chapters.isEmpty() && fromCatalogue && !presenter.hasRequested) { launchUI { swipe_refresh?.isRefreshing = true } presenter.fetchChaptersFromSource() } - adapter?.updateDataSet(listOf(ChapterItem(Chapter.createH(), presenter.manga)) + chapters) - } + adapter?.updateDataSet(listOf(presenter.headerItem) + chapters) +} override fun onItemClick(view: View?, position: Int): Boolean { val adapter = adapter ?: return false @@ -442,10 +454,15 @@ class MangaChaptersController : BaseController, val adapter = adapter ?: return val chapter = adapter.getItem(position) ?: return if (chapter.isHeader) return - if (chapter.status != Download.NOT_DOWNLOADED) { + if (chapter.status != Download.NOT_DOWNLOADED && chapter.status != Download.ERROR) { presenter.deleteChapters(listOf(chapter)) } - else presenter.downloadChapters(listOf(chapter)) + else { + val isError = chapter.status == Download.ERROR + presenter.downloadChapters(listOf(chapter)) + if (isError) + presenter.restartDownloads() + } } override fun tagClicked(text: String) { @@ -463,6 +480,10 @@ class MangaChaptersController : BaseController, override fun chapterCount():Int = presenter.chapters.size override fun favoriteManga(longPress: Boolean) { + if (presenter.isLockedFromSearch) { + SecureActivityDelegate.promptLockIfNeeded(activity) + return + } val manga = presenter.manga if (longPress) { if (!manga.favorite) { 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 fa1de78271..0b7d1fcdb1 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 @@ -35,9 +35,7 @@ import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.view.applyWindowInsetsForController -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 @@ -178,8 +176,7 @@ class MangaController : RxController, TabbedController, BottomNavBarInterface { } fun tabLayout():TabLayout? { - return if (activity is SearchActivity) activity?.sTabs - else activity?.tabs + return null } fun updateTitle(manga: Manga) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaHeaderHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaHeaderHolder.kt index 8ce651bf47..ce832c48d3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaHeaderHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaHeaderHolder.kt @@ -162,6 +162,7 @@ class MangaHeaderHolder( })) manga_source.text = adapter.coverListener?.mangaSource()?.toString() + if (!manga.initialized) return GlideApp.with(view.context).load(manga) .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) .signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString())) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index da7fbb1157..72da5d9fee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -5,12 +5,15 @@ import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.MangaImpl import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.DownloadQueue +import eu.kanade.tachiyomi.data.library.LibraryServiceListener +import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.Source @@ -21,7 +24,6 @@ import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.system.launchUI import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.launch @@ -39,19 +41,25 @@ class MangaPresenter(private val controller: MangaChaptersController, private val db: DatabaseHelper = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get()): CoroutineScope, - DownloadQueue.DownloadListener { + DownloadQueue.DownloadListener, + LibraryServiceListener { override var coroutineContext:CoroutineContext = Job() + Dispatchers.Default var isLockedFromSearch = false var hasRequested = false + var isLoading = false var chapters:List = emptyList() private set + var headerItem = ChapterItem(Chapter.createH(), manga) + fun onCreate() { isLockedFromSearch = SecureActivityDelegate.shouldBeLocked() + headerItem.isLocked = isLockedFromSearch downloadManager.addListener(this) + LibraryUpdateService.setListener(this) if (!manga.initialized) { controller.updateHeader() launchUI { @@ -67,31 +75,7 @@ class MangaPresenter(private val controller: MangaChaptersController, fun onDestroy() { downloadManager.removeListener(this) - } - - fun fetchMangaFromSource() { - GlobalScope.launch(Dispatchers.IO) { - withContext(Dispatchers.Main) { - controller.setRefresh(true) - } - val thumbnailUrl = manga.thumbnail_url - val networkManga = try { - source.fetchMangaDetails(manga).toBlocking().single() - } catch (e: java.lang.Exception) { - controller.showError(trimException(e)) - return@launch - } - if (networkManga != null) { - manga.copyFrom(networkManga) - manga.initialized = true - db.insertManga(manga).executeAsBlocking() - if (thumbnailUrl != networkManga.thumbnail_url) - MangaImpl.setLastCoverFetch(manga.id!!, Date().time) - withContext(Dispatchers.Main) { - controller.updateHeader() - } - } - } + LibraryUpdateService.removeListener(this) } fun fetchChapters() { @@ -275,6 +259,11 @@ class MangaPresenter(private val controller: MangaChaptersController, downloadManager.downloadChapters(manga, chapters) } + fun restartDownloads() { + if (downloadManager.isPaused()) + downloadManager.startDownloads() + } + /** * Deletes the given list of chapter. * @param chapters the list of chapters to delete. @@ -304,6 +293,7 @@ class MangaPresenter(private val controller: MangaChaptersController, fun refreshAll() { launch { + isLoading = true var mangaError: java.lang.Exception? = null var chapterError: java.lang.Exception? = null val chapters = async(Dispatchers.IO) { @@ -338,6 +328,7 @@ class MangaPresenter(private val controller: MangaChaptersController, syncChaptersWithSource(db, finChapters, manga, source) withContext(Dispatchers.IO) { updateChapters() } } + isLoading = false if (chapterError == null) withContext(Dispatchers.Main) { controller.updateChapters(this@MangaPresenter.chapters) } if (mangaError != null) @@ -350,6 +341,7 @@ class MangaPresenter(private val controller: MangaChaptersController, */ fun fetchChaptersFromSource() { hasRequested = true + isLoading = true launch(Dispatchers.IO) { val chapters = try { @@ -359,6 +351,7 @@ class MangaPresenter(private val controller: MangaChaptersController, withContext(Dispatchers.Main) { controller.showError(trimException(e)) } return@launch } ?: listOf() + isLoading = false try { syncChaptersWithSource(db, chapters, manga, source) @@ -480,4 +473,10 @@ class MangaPresenter(private val controller: MangaChaptersController, } toggleFavorite() } + + override fun onUpdateManga(manga: LibraryManga) { + if (manga.id == this.manga.id) { + fetchChapters() + } + } } \ No newline at end of file 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 c788c526c6..3fffd8daca 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 @@ -200,8 +200,6 @@ class MangaInfoController : NucleusController(), setFullCoverToThumb() } container?.setOnApplyWindowInsetsListener { _, insets -> - if (MainActivity.usingBottomNav) - return@setOnApplyWindowInsetsListener insets if (resources?.configuration?.orientation == Configuration.ORIENTATION_LANDSCAPE) { fab_favorite?.updateLayoutParams { bottomMargin = fabBaseMarginBottom + insets.systemWindowInsetBottom diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricActivity.kt index 067e2e4784..0cab38e2be 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricActivity.kt @@ -13,12 +13,14 @@ class BiometricActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + val fromSearch = intent.getBooleanExtra("fromSearch", false) val biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt .AuthenticationCallback() { override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { super.onAuthenticationError(errorCode, errString) - finishAffinity() + if (fromSearch) finish() + else finishAffinity() } override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt index e13ff2b81f..1974ddd730 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt @@ -6,6 +6,7 @@ import android.view.WindowManager import androidx.biometric.BiometricManager import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.ui.main.SearchActivity import uy.kohesive.injekt.injectLazy import java.util.Date @@ -33,6 +34,7 @@ object SecureActivityDelegate { if (lockApp && BiometricManager.from(activity).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) { if (isAppLocked()) { val intent = Intent(activity, BiometricActivity::class.java) + intent.putExtra("fromSearch", (activity is SearchActivity)) activity.startActivity(intent) activity.overridePendingTransition(0, 0) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt index e14d200d54..4abcf2eb6b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt @@ -12,13 +12,12 @@ import android.content.res.Resources import android.net.ConnectivityManager import android.net.Uri import android.os.PowerManager +import android.widget.Toast import androidx.annotation.AttrRes import androidx.annotation.StringRes import androidx.browser.customtabs.CustomTabsIntent import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat -import androidx.localbroadcastmanager.content.LocalBroadcastManager -import android.widget.Toast import com.nononsenseapps.filepicker.FilePickerActivity import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity @@ -102,6 +101,9 @@ val Int.pxToDp: Int val Int.dpToPx: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt() +val Float.dpToPx: Float + get() = (this * Resources.getSystem().displayMetrics.density) + /** * Property to get the notification manager from the context. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt index 3586ab9b50..7ee63bdd04 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt @@ -1,10 +1,8 @@ package eu.kanade.tachiyomi.widget -import android.animation.ObjectAnimator import android.animation.StateListAnimator import android.content.Context import android.util.AttributeSet -import com.google.android.material.R import com.google.android.material.appbar.AppBarLayout class ElevationAppBarLayout @JvmOverloads constructor( @@ -13,29 +11,24 @@ class ElevationAppBarLayout @JvmOverloads constructor( ) : AppBarLayout(context, attrs) { private var origStateAnimator: StateListAnimator? = null + private var origElevation: Float init { origStateAnimator = stateListAnimator + origElevation = elevation } fun enableElevation() { - stateListAnimator = origStateAnimator - } - - fun disableElevation() { - stateListAnimator = StateListAnimator().apply { - val objAnimator = ObjectAnimator.ofFloat(this, "elevation", 0f) - - // Enabled and collapsible, but not collapsed means not elevated - addState(intArrayOf(android.R.attr.enabled, R.attr.state_collapsible, -R.attr.state_collapsed), - objAnimator) - - // Default enabled state - addState(intArrayOf(android.R.attr.enabled), objAnimator) - - // Disabled state - addState(IntArray(0), objAnimator) + if (stateListAnimator == null) { + stateListAnimator = origStateAnimator + elevation = origElevation } } + fun disableElevation() { + stateListAnimator = null + elevation = 0f + //translationZ = 0.1f.dpToPx + } + } diff --git a/app/src/main/res/layout/main_activity.xml b/app/src/main/res/layout/main_activity.xml index cc8c2a41db..461c2acf16 100644 --- a/app/src/main/res/layout/main_activity.xml +++ b/app/src/main/res/layout/main_activity.xml @@ -6,12 +6,21 @@ android:layout_height="match_parent" android:orientation="vertical"> + + + + @@ -40,17 +49,6 @@ - - - - - - - - - - - - - - - - - - - \ 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 420fc249a9..a69fb1ccc2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -677,6 +677,8 @@ No recent chapters No recently read manga Your library is empty, add series to your library from the catalogues. + No matches found for your current + filters You have no categories. Hit the plus button to create one for organizing your library.