mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-09 19:55:11 +01:00
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
This commit is contained in:
parent
0c81459143
commit
52e6a7fc95
@ -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<SourceManager>().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<SourceManager>().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
|
||||
|
@ -196,8 +196,9 @@ class LibraryUpdateService(
|
||||
this.listener = listener
|
||||
}
|
||||
|
||||
fun removeListener() {
|
||||
listener = null
|
||||
fun removeListener(listener: LibraryServiceListener) {
|
||||
if (this.listener == listener)
|
||||
this.listener = null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<View>(R.id.action_mode_bar)
|
||||
contextView?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
leftMargin = insets.systemWindowInsetLeft
|
||||
rightMargin = insets.systemWindowInsetRight
|
||||
}
|
||||
// Consume any horizontal insets and pad all content in. There's not much we can do
|
||||
// with horizontal insets
|
||||
v.updatePadding(
|
||||
left = insets.systemWindowInsetLeft,
|
||||
right = insets.systemWindowInsetRight
|
||||
)
|
||||
insets.replaceSystemWindowInsets(
|
||||
0, insets.systemWindowInsetTop,
|
||||
0, insets.systemWindowInsetBottom
|
||||
)
|
||||
}
|
||||
|
||||
router = Conductor.attachRouter(this, container, savedInstanceState)
|
||||
if (!router.hasRootController()) {
|
||||
// Set start screen
|
||||
handleIntentAction(intent)
|
||||
}
|
||||
|
||||
sToolbar.setNavigationOnClickListener {
|
||||
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 {
|
||||
|
@ -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<ViewGroup.MarginLayoutParams> {
|
||||
@ -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<ChapterItem>) {
|
||||
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) {
|
||||
|
@ -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) {
|
||||
|
@ -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()))
|
||||
|
@ -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<ChapterItem> = 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()
|
||||
}
|
||||
}
|
||||
}
|
@ -200,8 +200,6 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||
setFullCoverToThumb()
|
||||
}
|
||||
container?.setOnApplyWindowInsetsListener { _, insets ->
|
||||
if (MainActivity.usingBottomNav)
|
||||
return@setOnApplyWindowInsetsListener insets
|
||||
if (resources?.configuration?.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
fab_favorite?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
bottomMargin = fabBaseMarginBottom + insets.systemWindowInsetBottom
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,12 +6,21 @@
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.bluelinelabs.conductor.ChangeHandlerFrameLayout
|
||||
android:id="@+id/controller_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/navigationView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
</com.bluelinelabs.conductor.ChangeHandlerFrameLayout>
|
||||
|
||||
<eu.kanade.tachiyomi.widget.ElevationAppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:stateListAnimator="@null"
|
||||
android:translationZ="0.1dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
@ -40,17 +49,6 @@
|
||||
|
||||
</eu.kanade.tachiyomi.widget.ElevationAppBarLayout>
|
||||
|
||||
<com.bluelinelabs.conductor.ChangeHandlerFrameLayout
|
||||
android:id="@+id/controller_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/navigationView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
</com.bluelinelabs.conductor.ChangeHandlerFrameLayout>
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/navigationView"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -1,50 +0,0 @@
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/search_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/main_content"
|
||||
android:layout_width="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<eu.kanade.tachiyomi.widget.ElevationAppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/sToolbar"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="?attr/actionBarTheme"/>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/sTabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/Theme.ActionBar.Tab"
|
||||
android:background="?colorPrimary"
|
||||
app:tabRippleColor="@color/rippleColor"
|
||||
app:tabIndicatorColor="?attr/actionBarTintColor"
|
||||
app:tabTextColor="?attr/actionBarTintColor"
|
||||
app:tabInlineLabel="true"
|
||||
app:tabGravity="center"
|
||||
app:tabMode="auto"
|
||||
app:tabMinWidth="75dp"/>
|
||||
|
||||
</eu.kanade.tachiyomi.widget.ElevationAppBarLayout>
|
||||
|
||||
<com.bluelinelabs.conductor.ChangeHandlerFrameLayout
|
||||
android:id="@+id/controller_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
@ -677,6 +677,8 @@
|
||||
<string name="information_no_recent">No recent chapters</string>
|
||||
<string name="information_no_recent_manga">No recently read manga</string>
|
||||
<string name="information_empty_library">Your library is empty, add series to your library from the catalogues.</string>
|
||||
<string name="information_empty_library_filtered">No matches found for your current
|
||||
filters</string>
|
||||
<string name="information_empty_category">You have no categories. Hit the plus button to create one for organizing your library.</string>
|
||||
|
||||
<!-- Download Notification -->
|
||||
|
Loading…
Reference in New Issue
Block a user