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 + if (stateListAnimator == null) { + stateListAnimator = origStateAnimator + elevation = origElevation + } } 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) - } + 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.