mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-14 05:15:10 +01:00
Bottom nav view animation on push/pop
Fade in and out on pop/push respectively No longer refreshing cover if the url doesn't change Fixing uniform layout Fixes for categories Manga controller has all chapter filter options working, shows current filters beside button Manga details controller now has working toolbar menu as well
This commit is contained in:
parent
52e6a7fc95
commit
ffb8a7bd17
@ -25,7 +25,7 @@ object Migrations {
|
|||||||
if (BuildConfig.INCLUDE_UPDATER && preferences.automaticUpdates()) {
|
if (BuildConfig.INCLUDE_UPDATER && preferences.automaticUpdates()) {
|
||||||
UpdaterJob.setupTask()
|
UpdaterJob.setupTask()
|
||||||
}
|
}
|
||||||
return false
|
return BuildConfig.DEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldVersion < 14) {
|
if (oldVersion < 14) {
|
||||||
|
@ -455,11 +455,12 @@ class LibraryUpdateService(
|
|||||||
.concatMap { manga ->
|
.concatMap { manga ->
|
||||||
val source = sourceManager.get(manga.source) as? HttpSource
|
val source = sourceManager.get(manga.source) as? HttpSource
|
||||||
?: return@concatMap Observable.empty<LibraryManga>()
|
?: return@concatMap Observable.empty<LibraryManga>()
|
||||||
|
|
||||||
source.fetchMangaDetails(manga)
|
source.fetchMangaDetails(manga)
|
||||||
.map { networkManga ->
|
.map { networkManga ->
|
||||||
|
val thumbnailUrl = manga.thumbnail_url
|
||||||
manga.copyFrom(networkManga)
|
manga.copyFrom(networkManga)
|
||||||
db.insertManga(manga).executeAsBlocking()
|
db.insertManga(manga).executeAsBlocking()
|
||||||
|
if (thumbnailUrl != networkManga.thumbnail_url)
|
||||||
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
|
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
|
||||||
manga
|
manga
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,11 @@ import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
|||||||
import eu.kanade.tachiyomi.ui.catalogue.latest.LatestUpdatesController
|
import eu.kanade.tachiyomi.ui.catalogue.latest.LatestUpdatesController
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController
|
import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController
|
||||||
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
|
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
|
||||||
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForController
|
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
|
||||||
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
|
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.catalogue_main_controller.*
|
import kotlinx.android.synthetic.main.catalogue_main_controller.*
|
||||||
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
|
|||||||
*/
|
*/
|
||||||
override fun onViewCreated(view: View) {
|
override fun onViewCreated(view: View) {
|
||||||
super.onViewCreated(view)
|
super.onViewCreated(view)
|
||||||
view.applyWindowInsetsForController()
|
view.applyWindowInsetsForRootController(activity!!.navigationView)
|
||||||
|
|
||||||
adapter = CatalogueAdapter(this)
|
adapter = CatalogueAdapter(this)
|
||||||
|
|
||||||
|
@ -53,8 +53,8 @@ class CategoryHolder(view: View, val adapter: CategoryAdapter) : BaseFlexibleVie
|
|||||||
title.setTextColor(ContextCompat.getColor(itemView.context, R.color.textColorHint))
|
title.setTextColor(ContextCompat.getColor(itemView.context, R.color.textColorHint))
|
||||||
regularDrawable = ContextCompat.getDrawable(itemView.context, R.drawable
|
regularDrawable = ContextCompat.getDrawable(itemView.context, R.drawable
|
||||||
.ic_add_white_24dp)
|
.ic_add_white_24dp)
|
||||||
edit_button.gone()
|
|
||||||
image.gone()
|
image.gone()
|
||||||
|
edit_button.setImageDrawable(null)
|
||||||
edit_text.setText("")
|
edit_text.setText("")
|
||||||
edit_text.hint = title.text
|
edit_text.hint = title.text
|
||||||
}
|
}
|
||||||
@ -62,7 +62,6 @@ class CategoryHolder(view: View, val adapter: CategoryAdapter) : BaseFlexibleVie
|
|||||||
title.setTextColor(ContextCompat.getColor(itemView.context, R.color.textColorPrimary))
|
title.setTextColor(ContextCompat.getColor(itemView.context, R.color.textColorPrimary))
|
||||||
regularDrawable = ContextCompat.getDrawable(itemView.context, R.drawable
|
regularDrawable = ContextCompat.getDrawable(itemView.context, R.drawable
|
||||||
.ic_reorder_grey_24dp)
|
.ic_reorder_grey_24dp)
|
||||||
edit_button.visible()
|
|
||||||
image.visible()
|
image.visible()
|
||||||
edit_text.setText(title.text)
|
edit_text.setText(title.text)
|
||||||
}
|
}
|
||||||
@ -94,12 +93,13 @@ class CategoryHolder(view: View, val adapter: CategoryAdapter) : BaseFlexibleVie
|
|||||||
else {
|
else {
|
||||||
if (!createCategory) {
|
if (!createCategory) {
|
||||||
setDragHandleView(reorder)
|
setDragHandleView(reorder)
|
||||||
|
edit_button.setImageDrawable(ContextCompat.getDrawable(itemView.context, R.drawable.ic_edit_white_24dp))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
edit_button.setImageDrawable(null)
|
||||||
reorder.setOnTouchListener { _, _ -> true}
|
reorder.setOnTouchListener { _, _ -> true}
|
||||||
}
|
}
|
||||||
edit_text.clearFocus()
|
edit_text.clearFocus()
|
||||||
edit_button.setImageDrawable(ContextCompat.getDrawable(itemView.context, R.drawable.ic_edit_white_24dp))
|
|
||||||
edit_button.drawable.mutate().setTint(ContextCompat.getColor(itemView.context, R
|
edit_button.drawable.mutate().setTint(ContextCompat.getColor(itemView.context, R
|
||||||
.color.gray_button))
|
.color.gray_button))
|
||||||
reorder.setImageDrawable(regularDrawable)
|
reorder.setImageDrawable(regularDrawable)
|
||||||
|
@ -59,7 +59,7 @@ class CategoryPresenter(
|
|||||||
*/
|
*/
|
||||||
fun createCategory(name: String): Boolean {
|
fun createCategory(name: String): Boolean {
|
||||||
// Do not allow duplicate categories.
|
// Do not allow duplicate categories.
|
||||||
if (categoryExists(name)) {
|
if (categoryExists(name, null)) {
|
||||||
controller.onCategoryExistsError()
|
controller.onCategoryExistsError()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ class CategoryPresenter(
|
|||||||
*/
|
*/
|
||||||
fun renameCategory(category: Category, name: String): Boolean {
|
fun renameCategory(category: Category, name: String): Boolean {
|
||||||
// Do not allow duplicate categories.
|
// Do not allow duplicate categories.
|
||||||
if (categoryExists(name)) {
|
if (categoryExists(name, category.id)) {
|
||||||
controller.onCategoryExistsError()
|
controller.onCategoryExistsError()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -131,8 +131,8 @@ class CategoryPresenter(
|
|||||||
/**
|
/**
|
||||||
* Returns true if a category with the given name already exists.
|
* Returns true if a category with the given name already exists.
|
||||||
*/
|
*/
|
||||||
private fun categoryExists(name: String): Boolean {
|
private fun categoryExists(name: String, id: Int?): Boolean {
|
||||||
return categories.any { it.name.equals(name, true) }
|
return categories.any { it.name.equals(name, true) && id != it.id }
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -51,7 +51,7 @@ import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig
|
|||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForController
|
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
|
||||||
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
|
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
|
||||||
@ -176,7 +176,7 @@ open class LibraryController(
|
|||||||
|
|
||||||
override fun onViewCreated(view: View) {
|
override fun onViewCreated(view: View) {
|
||||||
super.onViewCreated(view)
|
super.onViewCreated(view)
|
||||||
view.applyWindowInsetsForController()
|
view.applyWindowInsetsForRootController(activity!!.navigationView)
|
||||||
mangaPerRow = getColumnsPreferenceForCurrentOrientation().getOrDefault()
|
mangaPerRow = getColumnsPreferenceForCurrentOrientation().getOrDefault()
|
||||||
if (!::presenter.isInitialized)
|
if (!::presenter.isInitialized)
|
||||||
presenter = LibraryPresenter(this)
|
presenter = LibraryPresenter(this)
|
||||||
|
@ -69,7 +69,8 @@ class LibraryGridHolder(
|
|||||||
var glide = GlideApp.with(adapter.recyclerView.context).load(item.manga)
|
var glide = GlideApp.with(adapter.recyclerView.context).load(item.manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||||
.signature(ObjectKey(MangaImpl.getLastCoverFetch(id).toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(id).toString()))
|
||||||
glide = if (fixedSize) glide.centerCrop() else glide.override(cover_thumbnail.maxHeight)
|
glide = if (fixedSize) glide.centerCrop().override(cover_thumbnail.maxHeight)
|
||||||
|
else glide.override(cover_thumbnail.maxHeight)
|
||||||
glide.into(cover_thumbnail)
|
glide.into(cover_thumbnail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import android.view.Gravity
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.ImageView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -21,6 +22,7 @@ import eu.kanade.tachiyomi.util.system.dpToPx
|
|||||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||||
import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
|
import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
|
||||||
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class LibraryItem(val manga: LibraryManga,
|
class LibraryItem(val manga: LibraryManga,
|
||||||
@ -70,7 +72,9 @@ class LibraryItem(val manga: LibraryManga,
|
|||||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
|
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
)
|
)
|
||||||
cover_thumbnail.maxHeight = (parent.itemWidth / 3f * 3.7f).toInt()
|
cover_thumbnail.maxHeight = (parent.itemWidth / 3f * 3.7f).toInt()
|
||||||
|
cover_thumbnail.minimumHeight = (parent.itemWidth / 3f * 3.7f).toInt()
|
||||||
constraint_layout.minHeight = 0
|
constraint_layout.minHeight = 0
|
||||||
|
cover_thumbnail.scaleType = ImageView.ScaleType.CENTER_CROP
|
||||||
cover_thumbnail.adjustViewBounds = false
|
cover_thumbnail.adjustViewBounds = false
|
||||||
cover_thumbnail.layoutParams = FrameLayout.LayoutParams(
|
cover_thumbnail.layoutParams = FrameLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.ui.main
|
package eu.kanade.tachiyomi.ui.main
|
||||||
|
|
||||||
|
import android.animation.Animator
|
||||||
|
import android.animation.AnimatorSet
|
||||||
|
import android.animation.ValueAnimator
|
||||||
import android.app.SearchManager
|
import android.app.SearchManager
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
@ -7,7 +10,6 @@ import android.graphics.Color
|
|||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
|
||||||
import android.view.GestureDetector
|
import android.view.GestureDetector
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -86,6 +88,10 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
private var extraViewForUndo:View? = null
|
private var extraViewForUndo:View? = null
|
||||||
private var canDismissSnackBar = false
|
private var canDismissSnackBar = false
|
||||||
|
|
||||||
|
private var animationSet: AnimatorSet? = null
|
||||||
|
|
||||||
|
private var bottomNavHeight = 0
|
||||||
|
|
||||||
fun setUndoSnackBar(snackBar: Snackbar?, extraViewToCheck: View? = null) {
|
fun setUndoSnackBar(snackBar: Snackbar?, extraViewToCheck: View? = null) {
|
||||||
this.snackBar = snackBar
|
this.snackBar = snackBar
|
||||||
canDismissSnackBar = false
|
canDismissSnackBar = false
|
||||||
@ -306,11 +312,12 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
navigationView.visibility = if (router.backstackSize > 1) View.GONE else View.VISIBLE
|
navigationView.visibility = if (router.backstackSize > 1) View.GONE else View.VISIBLE
|
||||||
|
navigationView.alpha = if (router.backstackSize > 1) 0f else 1f
|
||||||
router.addChangeListener(object : ControllerChangeHandler.ControllerChangeListener {
|
router.addChangeListener(object : ControllerChangeHandler.ControllerChangeListener {
|
||||||
override fun onChangeStarted(to: Controller?, from: Controller?, isPush: Boolean,
|
override fun onChangeStarted(to: Controller?, from: Controller?, isPush: Boolean,
|
||||||
container: ViewGroup, handler: ControllerChangeHandler) {
|
container: ViewGroup, handler: ControllerChangeHandler) {
|
||||||
|
|
||||||
syncActivityViewWithController(to, from)
|
syncActivityViewWithController(to, from, isPush)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onChangeCompleted(to: Controller?, from: Controller?, isPush: Boolean,
|
override fun onChangeCompleted(to: Controller?, from: Controller?, isPush: Boolean,
|
||||||
@ -360,7 +367,7 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
return super.startSupportActionMode(callback)
|
return super.startSupportActionMode(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSupportActionModeFinished(mode: androidx.appcompat.view.ActionMode) {
|
/* override fun onSupportActionModeFinished(mode: androidx.appcompat.view.ActionMode) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) launchUI {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) launchUI {
|
||||||
val scale = Settings.Global.getFloat(
|
val scale = Settings.Global.getFloat(
|
||||||
contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f
|
contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f
|
||||||
@ -371,7 +378,7 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
window?.statusBarColor = getResourceColor(android.R.attr.statusBarColor)
|
window?.statusBarColor = getResourceColor(android.R.attr.statusBarColor)
|
||||||
}
|
}
|
||||||
super.onSupportActionModeFinished(mode)
|
super.onSupportActionModeFinished(mode)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private fun setExtensionsBadge() {
|
private fun setExtensionsBadge() {
|
||||||
val updates = preferences.extensionUpdatesCount().getOrDefault()
|
val updates = preferences.extensionUpdatesCount().getOrDefault()
|
||||||
@ -542,7 +549,8 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
return super.dispatchTouchEvent(ev)
|
return super.dispatchTouchEvent(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun syncActivityViewWithController(to: Controller?, from: Controller? = null) {
|
protected open fun syncActivityViewWithController(to: Controller?, from: Controller? = null,
|
||||||
|
isPush: Boolean = false) {
|
||||||
if (from is DialogController || to is DialogController) {
|
if (from is DialogController || to is DialogController) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -577,10 +585,37 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
appbar.enableElevation()
|
appbar.enableElevation()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to !is DialogController)
|
if (to !is DialogController) {
|
||||||
|
navigationView.visibility = if (router.backstackSize == 0 ||
|
||||||
|
(router.backstackSize <= 1 && !isPush))
|
||||||
|
View.VISIBLE else navigationView.visibility
|
||||||
|
animationSet?.cancel()
|
||||||
|
animationSet = AnimatorSet()
|
||||||
|
val alphaAnimation = ValueAnimator.ofFloat(
|
||||||
|
navigationView.alpha,
|
||||||
|
if (router.backstackSize > 1) 0f else 1f
|
||||||
|
)
|
||||||
|
alphaAnimation.addUpdateListener { valueAnimator ->
|
||||||
|
navigationView.alpha = valueAnimator.animatedValue as Float
|
||||||
|
}
|
||||||
|
alphaAnimation.addListener(object : Animator.AnimatorListener {
|
||||||
|
override fun onAnimationEnd(animation: Animator?) {
|
||||||
navigationView.visibility = if (router.backstackSize > 1) View.GONE else View.VISIBLE
|
navigationView.visibility = if (router.backstackSize > 1) View.GONE else View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onAnimationCancel(animation: Animator?) { }
|
||||||
|
|
||||||
|
override fun onAnimationRepeat(animation: Animator?) { }
|
||||||
|
|
||||||
|
override fun onAnimationStart(animation: Animator?) { }
|
||||||
|
})
|
||||||
|
alphaAnimation.duration = 200
|
||||||
|
alphaAnimation.startDelay = 50
|
||||||
|
animationSet?.playTogether(alphaAnimation)
|
||||||
|
animationSet?.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun downloadStatusChanged(downloading: Boolean) {
|
override fun downloadStatusChanged(downloading: Boolean) {
|
||||||
val downloadManager = Injekt.get<DownloadManager>()
|
val downloadManager = Injekt.get<DownloadManager>()
|
||||||
val hasQueue = downloading || downloadManager.hasQueue()
|
val hasQueue = downloading || downloadManager.hasQueue()
|
||||||
|
@ -39,7 +39,8 @@ class SearchActivity: MainActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun syncActivityViewWithController(to: Controller?, from: Controller?) {
|
override fun syncActivityViewWithController(to: Controller?, from: Controller?, isPush:
|
||||||
|
Boolean) {
|
||||||
if (from is DialogController || to is DialogController) {
|
if (from is DialogController || to is DialogController) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -6,34 +6,24 @@ import android.os.Bundle
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.CompoundButton
|
import android.widget.CompoundButton
|
||||||
import android.widget.RadioButton
|
|
||||||
import android.widget.RadioGroup
|
|
||||||
import com.f2prateek.rx.preferences.Preference
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.view.setBottomEdge
|
import eu.kanade.tachiyomi.util.view.setBottomEdge
|
||||||
import eu.kanade.tachiyomi.util.view.setEdgeToEdge
|
import eu.kanade.tachiyomi.util.view.setEdgeToEdge
|
||||||
import eu.kanade.tachiyomi.util.view.visibleIf
|
import eu.kanade.tachiyomi.util.view.visibleIf
|
||||||
import kotlinx.android.synthetic.main.chapter_sort_bottom_sheet.*
|
import kotlinx.android.synthetic.main.chapter_sort_bottom_sheet.*
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class ChaptersSortBottomSheet(private val controller: MangaChaptersController) : BottomSheetDialog
|
class ChaptersSortBottomSheet(controller: MangaChaptersController) : BottomSheetDialog
|
||||||
(controller.activity!!, R.style.BottomSheetDialogTheme) {
|
(controller.activity!!, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
val activity = controller.activity!!
|
val activity = controller.activity!!
|
||||||
|
|
||||||
/**
|
|
||||||
* Preferences helper.
|
|
||||||
*/
|
|
||||||
private val preferences by injectLazy<PreferencesHelper>()
|
|
||||||
|
|
||||||
private var sheetBehavior: BottomSheetBehavior<*>
|
private var sheetBehavior: BottomSheetBehavior<*>
|
||||||
|
|
||||||
|
private val presenter = controller.presenter
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Use activity theme for this layout
|
// Use activity theme for this layout
|
||||||
@ -45,7 +35,7 @@ class ChaptersSortBottomSheet(private val controller: MangaChaptersController) :
|
|||||||
val height = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
val height = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
activity.window.decorView.rootWindowInsets.systemWindowInsetBottom
|
activity.window.decorView.rootWindowInsets.systemWindowInsetBottom
|
||||||
} else 0
|
} else 0
|
||||||
sheetBehavior.peekHeight = 220.dpToPx + height
|
sheetBehavior.peekHeight = 380.dpToPx + height
|
||||||
|
|
||||||
sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
||||||
override fun onSlide(bottomSheet: View, progress: Float) { }
|
override fun onSlide(bottomSheet: View, progress: Float) { }
|
||||||
@ -62,7 +52,6 @@ class ChaptersSortBottomSheet(private val controller: MangaChaptersController) :
|
|||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
sheetBehavior.skipCollapsed = true
|
sheetBehavior.skipCollapsed = true
|
||||||
sheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,87 +60,79 @@ class ChaptersSortBottomSheet(private val controller: MangaChaptersController) :
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
initGeneralPreferences()
|
initGeneralPreferences()
|
||||||
setBottomEdge(show_bookmark, activity)
|
setBottomEdge(hide_titles, activity)
|
||||||
close_button.setOnClickListener {
|
close_button.setOnClickListener { dismiss() }
|
||||||
dismiss()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
settings_scroll_view.viewTreeObserver.addOnGlobalLayoutListener {
|
settings_scroll_view.viewTreeObserver.addOnGlobalLayoutListener {
|
||||||
val isScrollable =
|
val isScrollable =
|
||||||
settings_scroll_view!!.height < bottom_sheet.height +
|
settings_scroll_view!!.height < bottom_sheet.height +
|
||||||
settings_scroll_view.paddingTop + settings_scroll_view.paddingBottom
|
settings_scroll_view.paddingTop + settings_scroll_view.paddingBottom
|
||||||
close_button.visibleIf(isScrollable)
|
close_button.visibleIf(isScrollable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setOnDismissListener {
|
||||||
|
presenter.setFilters(
|
||||||
|
show_read.isChecked,
|
||||||
|
show_unread.isChecked,
|
||||||
|
show_download.isChecked,
|
||||||
|
show_bookmark.isChecked
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun initGeneralPreferences() {
|
private fun initGeneralPreferences() {
|
||||||
|
show_read.isChecked = presenter.onlyRead()
|
||||||
show_read.isChecked = controller.presenter.onlyRead()
|
show_unread.isChecked = presenter.onlyUnread()
|
||||||
show_unread.isChecked = controller.presenter.onlyUnread()
|
show_download.isChecked = presenter.onlyDownloaded()
|
||||||
show_download.isChecked = controller.presenter.onlyDownloaded()
|
show_bookmark.isChecked = presenter.onlyBookmarked()
|
||||||
show_bookmark.isChecked = controller.presenter.onlyBookmarked()
|
|
||||||
|
|
||||||
show_all.isChecked = !(show_read.isChecked || show_unread.isChecked ||
|
show_all.isChecked = !(show_read.isChecked || show_unread.isChecked ||
|
||||||
show_download.isChecked || show_bookmark.isChecked)
|
show_download.isChecked || show_bookmark.isChecked)
|
||||||
|
|
||||||
if (controller.presenter.onlyRead())
|
sort_group.check(if (presenter.manga.sortDescending()) R.id.sort_newest else
|
||||||
//Disable unread filter option if read filter is enabled.
|
|
||||||
show_unread.isEnabled = false
|
|
||||||
if (controller.presenter.onlyUnread())
|
|
||||||
//Disable read filter option if unread filter is enabled.
|
|
||||||
show_read.isEnabled = false
|
|
||||||
|
|
||||||
sort_group.check(if (controller.presenter.manga.sortDescending()) R.id.sort_newest else
|
|
||||||
R.id.sort_oldest)
|
R.id.sort_oldest)
|
||||||
|
|
||||||
show_titles.isChecked = controller.presenter.manga.displayMode == Manga.DISPLAY_NAME
|
hide_titles.isChecked = presenter.manga.displayMode != Manga.DISPLAY_NAME
|
||||||
sort_by_source.isChecked = controller.presenter.manga.sorting == Manga.SORTING_SOURCE
|
sort_method_group.check(if (presenter.manga.sorting == Manga.SORTING_SOURCE) R.id.sort_by_source else
|
||||||
|
R.id.sort_by_number)
|
||||||
|
|
||||||
sort_group.setOnCheckedChangeListener { _, checkedId ->
|
sort_group.setOnCheckedChangeListener { _, checkedId ->
|
||||||
controller.presenter.setSortOrder(checkedId == R.id.sort_oldest)
|
presenter.setSortOrder(checkedId == R.id.sort_oldest)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*sort_group.bindToPreference(preferences.libraryLayout()) {
|
sort_method_group.setOnCheckedChangeListener { _, checkedId ->
|
||||||
controller.reattachAdapter()
|
presenter.setSortMethod(checkedId == R.id.sort_by_source)
|
||||||
if (sheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED)
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
uniform_grid.bindToPreference(preferences.uniformGrid()) {
|
|
||||||
controller.reattachAdapter()
|
|
||||||
}
|
|
||||||
grid_size_toggle_group.bindToPreference(preferences.gridSize()) {
|
|
||||||
controller.reattachAdapter()
|
|
||||||
}
|
|
||||||
download_badge.bindToPreference(preferences.downloadBadge()) {
|
|
||||||
controller.presenter.requestDownloadBadgesUpdate()
|
|
||||||
}
|
|
||||||
unread_badge_group.bindToPreference(preferences.unreadBadgeType()) {
|
|
||||||
controller.presenter.requestUnreadBadgesUpdate()
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
hide_titles.setOnCheckedChangeListener { _, isChecked ->
|
||||||
* Binds a checkbox or switch view with a boolean preference.
|
presenter.hideTitle(isChecked)
|
||||||
*/
|
|
||||||
private fun CompoundButton.bindToPreference(pref: Preference<Boolean>, block: () -> Unit) {
|
|
||||||
isChecked = pref.getOrDefault()
|
|
||||||
setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
pref.set(isChecked)
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
show_all.setOnCheckedChangeListener(::checkedFilter)
|
||||||
* Binds a radio group with a int preference.
|
show_read.setOnCheckedChangeListener(::checkedFilter)
|
||||||
*/
|
show_unread.setOnCheckedChangeListener(::checkedFilter)
|
||||||
private fun RadioGroup.bindToPreference(pref: Preference<Int>, block: () -> Unit) {
|
show_download.setOnCheckedChangeListener(::checkedFilter)
|
||||||
(getChildAt(pref.getOrDefault()) as RadioButton).isChecked = true
|
show_bookmark.setOnCheckedChangeListener(::checkedFilter)
|
||||||
setOnCheckedChangeListener { _, checkedId ->
|
}
|
||||||
val index = indexOfChild(findViewById(checkedId))
|
|
||||||
pref.set(index)
|
private fun checkedFilter(checkBox: CompoundButton, isChecked: Boolean) {
|
||||||
block()
|
if (isChecked) {
|
||||||
|
if (show_all == checkBox) {
|
||||||
|
show_read.isChecked = false
|
||||||
|
show_unread.isChecked = false
|
||||||
|
show_download.isChecked = false
|
||||||
|
show_bookmark.isChecked = false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
show_all.isChecked = false
|
||||||
|
if (show_read == checkBox) show_unread.isChecked = false
|
||||||
|
else if (show_unread == checkBox) show_read.isChecked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!show_read.isChecked && !show_unread.isChecked &&
|
||||||
|
!show_download.isChecked && !show_bookmark.isChecked) {
|
||||||
|
show_all.isChecked = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.manga
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog to choose a shape for the icon.
|
||||||
|
*/
|
||||||
|
class ChooseShapeDialog(bundle: Bundle? = null) : DialogController(bundle) {
|
||||||
|
|
||||||
|
constructor(target: MangaInfoController) : this() {
|
||||||
|
targetController = target
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(target: MangaChaptersController) : this() {
|
||||||
|
targetController = target
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
val modes = intArrayOf(
|
||||||
|
R.string.circular_icon,
|
||||||
|
R.string.rounded_icon,
|
||||||
|
R.string.square_icon,
|
||||||
|
R.string.star_icon)
|
||||||
|
|
||||||
|
return MaterialDialog(activity!!)
|
||||||
|
.title(R.string.icon_shape)
|
||||||
|
.negativeButton(android.R.string.cancel)
|
||||||
|
.listItemsSingleChoice (
|
||||||
|
items = modes.map { activity?.getString(it) as CharSequence },
|
||||||
|
waitForPositiveButton = false)
|
||||||
|
{ _, i, _ ->
|
||||||
|
(targetController as? MangaInfoController)?.createShortcutForShape(i)
|
||||||
|
(targetController as? MangaChaptersController)?.createShortcutForShape(i)
|
||||||
|
dismissDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,13 @@ package eu.kanade.tachiyomi.ui.manga
|
|||||||
|
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
@ -16,16 +21,19 @@ import android.view.MenuInflater
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.view.ActionMode
|
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.core.content.pm.ShortcutInfoCompat
|
||||||
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.graphics.ColorUtils
|
import androidx.core.graphics.ColorUtils
|
||||||
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import androidx.palette.graphics.Palette
|
import androidx.palette.graphics.Palette
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.vectordrawable.graphics.drawable.ArgbEvaluator
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||||
import com.bumptech.glide.request.target.CustomTarget
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
import com.bumptech.glide.request.transition.Transition
|
import com.bumptech.glide.request.transition.Transition
|
||||||
import com.bumptech.glide.signature.ObjectKey
|
import com.bumptech.glide.signature.ObjectKey
|
||||||
@ -38,12 +46,15 @@ import eu.kanade.tachiyomi.data.database.models.Category
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
|
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
|
||||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
||||||
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
||||||
@ -54,25 +65,31 @@ import eu.kanade.tachiyomi.ui.manga.MangaController.Companion.FROM_CATALOGUE_EXT
|
|||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterMatHolder
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterMatHolder
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.info.EditMangaDialog
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||||
|
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||||
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
||||||
import eu.kanade.tachiyomi.util.view.getText
|
import eu.kanade.tachiyomi.util.view.getText
|
||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
||||||
|
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
||||||
|
import jp.wasabeef.glide.transformations.MaskTransformation
|
||||||
import kotlinx.android.synthetic.main.big_manga_controller.*
|
import kotlinx.android.synthetic.main.big_manga_controller.*
|
||||||
import kotlinx.android.synthetic.main.big_manga_controller.swipe_refresh
|
import kotlinx.android.synthetic.main.big_manga_controller.swipe_refresh
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import kotlinx.android.synthetic.main.manga_info_controller.*
|
import kotlinx.android.synthetic.main.manga_info_controller.*
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class MangaChaptersController : BaseController,
|
class MangaChaptersController : BaseController,
|
||||||
ActionMode.Callback,
|
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
FlexibleAdapter.OnItemLongClickListener,
|
FlexibleAdapter.OnItemLongClickListener,
|
||||||
ChaptersAdapter.MangaHeaderInterface,
|
ChaptersAdapter.MangaHeaderInterface,
|
||||||
@ -184,7 +201,7 @@ class MangaChaptersController : BaseController,
|
|||||||
)
|
)
|
||||||
colorAnimator?.cancel()
|
colorAnimator?.cancel()
|
||||||
colorAnimator = ValueAnimator.ofObject(
|
colorAnimator = ValueAnimator.ofObject(
|
||||||
ArgbEvaluator(), colorFrom, colorTo
|
android.animation.ArgbEvaluator(), colorFrom, colorTo
|
||||||
)
|
)
|
||||||
colorAnimator?.duration = 250 // milliseconds
|
colorAnimator?.duration = 250 // milliseconds
|
||||||
colorAnimator?.addUpdateListener { animator ->
|
colorAnimator?.addUpdateListener { animator ->
|
||||||
@ -226,7 +243,7 @@ class MangaChaptersController : BaseController,
|
|||||||
colorBack
|
colorBack
|
||||||
)
|
)
|
||||||
else it?.getDarkMutedColor(colorBack)) ?: colorBack
|
else it?.getDarkMutedColor(colorBack)) ?: colorBack
|
||||||
onCoverLoaded(backDropColor)
|
coverColor = backDropColor
|
||||||
(recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder)
|
(recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder)
|
||||||
?.setBackDrop(backDropColor)
|
?.setBackDrop(backDropColor)
|
||||||
if (toolbarIsColored) {
|
if (toolbarIsColored) {
|
||||||
@ -264,11 +281,15 @@ class MangaChaptersController : BaseController,
|
|||||||
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
||||||
super.onChangeStarted(handler, type)
|
super.onChangeStarted(handler, type)
|
||||||
if (type == ControllerChangeType.PUSH_ENTER || type == ControllerChangeType.POP_ENTER) {
|
if (type == ControllerChangeType.PUSH_ENTER || type == ControllerChangeType.POP_ENTER) {
|
||||||
|
if (type == ControllerChangeType.POP_ENTER)
|
||||||
|
return
|
||||||
(activity as MainActivity).appbar.setBackgroundColor(Color.TRANSPARENT)
|
(activity as MainActivity).appbar.setBackgroundColor(Color.TRANSPARENT)
|
||||||
(activity as MainActivity).toolbar.setBackgroundColor(Color.TRANSPARENT)
|
(activity as MainActivity).toolbar.setBackgroundColor(Color.TRANSPARENT)
|
||||||
activity?.window?.statusBarColor = Color.TRANSPARENT
|
activity?.window?.statusBarColor = Color.TRANSPARENT
|
||||||
}
|
}
|
||||||
else if (type == ControllerChangeType.PUSH_EXIT || type == ControllerChangeType.POP_EXIT) {
|
else if (type == ControllerChangeType.PUSH_EXIT || type == ControllerChangeType.POP_EXIT) {
|
||||||
|
if (router.backstack.lastOrNull()?.controller() is DialogController)
|
||||||
|
return
|
||||||
colorAnimator?.cancel()
|
colorAnimator?.cancel()
|
||||||
|
|
||||||
(activity as MainActivity).toolbar.setBackgroundColor(activity?.getResourceColor(
|
(activity as MainActivity).toolbar.setBackgroundColor(activity?.getResourceColor(
|
||||||
@ -295,6 +316,7 @@ class MangaChaptersController : BaseController,
|
|||||||
listOf(ChapterItem(presenter.headerItem, presenter.manga)) + presenter.chapters
|
listOf(ChapterItem(presenter.headerItem, presenter.manga)) + presenter.chapters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
activity?.invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -305,8 +327,11 @@ class MangaChaptersController : BaseController,
|
|||||||
presenter.fetchChaptersFromSource()
|
presenter.fetchChaptersFromSource()
|
||||||
}
|
}
|
||||||
adapter?.updateDataSet(listOf(presenter.headerItem) + chapters)
|
adapter?.updateDataSet(listOf(presenter.headerItem) + chapters)
|
||||||
|
activity?.invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun refreshAdapter() = adapter?.notifyDataSetChanged()
|
||||||
|
|
||||||
override fun onItemClick(view: View?, position: Int): Boolean {
|
override fun onItemClick(view: View?, position: Int): Boolean {
|
||||||
val adapter = adapter ?: return false
|
val adapter = adapter ?: return false
|
||||||
val chapter = adapter.getItem(position)?.chapter ?: return false
|
val chapter = adapter.getItem(position)?.chapter ?: return false
|
||||||
@ -392,43 +417,231 @@ class MangaChaptersController : BaseController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater.inflate(R.menu.chapters, menu)
|
inflater.inflate(R.menu.manga_details, menu)
|
||||||
|
val editItem = menu.findItem(R.id.action_edit)
|
||||||
|
editItem.isVisible = presenter.manga.favorite && !presenter.isLockedFromSearch
|
||||||
|
menu.findItem(R.id.action_download).isVisible = !presenter.isLockedFromSearch
|
||||||
|
menu.findItem(R.id.action_mark_all_as_read).isVisible =
|
||||||
|
presenter.getNextUnreadChapter() != null && !presenter.isLockedFromSearch
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_edit -> EditMangaDialog(this, presenter.manga).showDialog(router)
|
||||||
|
R.id.action_open_in_web_view -> openInWebView()
|
||||||
|
R.id.action_share -> prepareToShareManga()
|
||||||
|
R.id.action_add_to_home_screen -> addToHomeScreen()
|
||||||
|
R.id.action_mark_all_as_read -> {
|
||||||
|
MaterialDialog(view!!.context)
|
||||||
|
.message(R.string.mark_all_as_read_message)
|
||||||
|
.positiveButton(R.string.action_mark_as_read) {
|
||||||
|
markAsRead(presenter.chapters)
|
||||||
|
}
|
||||||
|
.negativeButton(android.R.string.cancel)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
R.id.download_next, R.id.download_next_5, R.id.download_next_10,
|
||||||
|
R.id.download_custom, R.id.download_unread, R.id.download_all
|
||||||
|
-> downloadChapters(item.itemId)
|
||||||
|
else -> return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to run Intent with [Intent.ACTION_SEND], which show share dialog.
|
||||||
|
*/
|
||||||
|
override fun prepareToShareManga() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && manga_cover.drawable != null)
|
||||||
|
GlideApp.with(activity!!).asBitmap().load(presenter.manga).into(object :
|
||||||
|
CustomTarget<Bitmap>() {
|
||||||
|
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
|
||||||
|
presenter.shareManga(resource)
|
||||||
|
}
|
||||||
|
override fun onLoadCleared(placeholder: Drawable?) {}
|
||||||
|
|
||||||
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
|
shareManga()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else shareManga()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to run Intent with [Intent.ACTION_SEND], which show share dialog.
|
||||||
|
*/
|
||||||
|
fun shareManga(cover: File? = null) {
|
||||||
|
val context = view?.context ?: return
|
||||||
|
|
||||||
|
val source = presenter.source as? HttpSource ?: return
|
||||||
|
val stream = cover?.getUriCompat(context)
|
||||||
|
try {
|
||||||
|
val url = source.mangaDetailsRequest(presenter.manga).url.toString()
|
||||||
|
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||||
|
type = "text/*"
|
||||||
|
putExtra(Intent.EXTRA_TEXT, url)
|
||||||
|
putExtra(Intent.EXTRA_TITLE, presenter.manga.currentTitle())
|
||||||
|
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
if (stream != null) {
|
||||||
|
clipData = ClipData.newRawUri(null, stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startActivity(Intent.createChooser(intent, context.getString(R.string.action_share)))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
context.toast(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openInWebView() {
|
||||||
|
val source = presenter.source as? HttpSource ?: return
|
||||||
|
|
||||||
|
val url = try {
|
||||||
|
source.mangaDetailsRequest(presenter.manga).url.toString()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val activity = activity ?: return
|
||||||
|
val intent = WebViewActivity.newIntent(activity.applicationContext, source.id, url, presenter.manga
|
||||||
|
.originalTitle())
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun downloadChapters(choice: Int) {
|
||||||
|
val chaptersToDownload = when (choice) {
|
||||||
|
R.id.download_next -> presenter.getUnreadChaptersSorted().take(1)
|
||||||
|
R.id.download_next_5 -> presenter.getUnreadChaptersSorted().take(5)
|
||||||
|
R.id.download_next_10 -> presenter.getUnreadChaptersSorted().take(10)
|
||||||
|
R.id.download_custom -> {
|
||||||
|
showCustomDownloadDialog()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
R.id.download_unread -> presenter.chapters.filter { !it.read }
|
||||||
|
R.id.download_all -> presenter.chapters
|
||||||
|
else -> emptyList()
|
||||||
|
}
|
||||||
|
if (chaptersToDownload.isNotEmpty()) {
|
||||||
|
downloadChapters(chaptersToDownload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun downloadChapters(chapters: List<ChapterItem>) {
|
||||||
|
val view = view
|
||||||
|
presenter.downloadChapters(chapters)
|
||||||
|
if (view != null && !presenter.manga.favorite && (snack == null ||
|
||||||
|
snack?.getText() != view.context.getString(R.string.snack_add_to_library))) {
|
||||||
|
snack = view.snack(view.context.getString(R.string.snack_add_to_library), Snackbar.LENGTH_INDEFINITE) {
|
||||||
|
setAction(R.string.action_add) {
|
||||||
|
presenter.setFavorite(true)
|
||||||
|
}
|
||||||
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
|
super.onDismissed(transientBottomBar, event)
|
||||||
|
if (snack == transientBottomBar) snack = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a shortcut of the manga to the home screen
|
||||||
|
*/
|
||||||
|
private fun addToHomeScreen() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
// TODO are transformations really unsupported or is it just the Pixel Launcher?
|
||||||
|
createShortcutForShape()
|
||||||
|
} else {
|
||||||
|
ChooseShapeDialog(this).showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the bitmap of the shortcut with the requested shape and calls [createShortcut] when
|
||||||
|
* the resource is available.
|
||||||
|
*
|
||||||
|
* @param i The shape index to apply. Defaults to circle crop transformation.
|
||||||
|
*/
|
||||||
|
fun createShortcutForShape(i: Int = 0) {
|
||||||
|
if (activity == null) return
|
||||||
|
GlideApp.with(activity!!)
|
||||||
|
.asBitmap()
|
||||||
|
.load(presenter.manga)
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
|
.apply {
|
||||||
|
when (i) {
|
||||||
|
0 -> circleCrop()
|
||||||
|
1 -> transform(RoundedCorners(5))
|
||||||
|
2 -> transform(CropSquareTransformation())
|
||||||
|
3 -> centerCrop().transform(MaskTransformation(R.drawable.mask_star))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into(object : CustomTarget<Bitmap>(128, 128) {
|
||||||
|
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
|
||||||
|
createShortcut(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoadCleared(placeholder: Drawable?) { }
|
||||||
|
|
||||||
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
|
activity?.toast(R.string.icon_creation_fail)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create shortcut using ShortcutManager.
|
||||||
|
*
|
||||||
|
* @param icon The image of the shortcut.
|
||||||
|
*/
|
||||||
|
private fun createShortcut(icon: Bitmap) {
|
||||||
|
val activity = activity ?: return
|
||||||
|
|
||||||
|
// Create the shortcut intent.
|
||||||
|
val shortcutIntent = activity.intent
|
||||||
|
.setAction(MainActivity.SHORTCUT_MANGA)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
.putExtra(MangaController.MANGA_EXTRA, presenter.manga.id)
|
||||||
|
|
||||||
|
// Check if shortcut placement is supported
|
||||||
|
if (ShortcutManagerCompat.isRequestPinShortcutSupported(activity)) {
|
||||||
|
val shortcutId = "manga-shortcut-${presenter.manga.originalTitle()}-${presenter.source.name}"
|
||||||
|
|
||||||
|
// Create shortcut info
|
||||||
|
val shortcutInfo = ShortcutInfoCompat.Builder(activity, shortcutId)
|
||||||
|
.setShortLabel(presenter.manga.currentTitle())
|
||||||
|
.setIcon(IconCompat.createWithBitmap(icon))
|
||||||
|
.setIntent(shortcutIntent)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val successCallback = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
// Create the CallbackIntent.
|
||||||
|
val intent = ShortcutManagerCompat.createShortcutResultIntent(activity, shortcutInfo)
|
||||||
|
|
||||||
|
// Configure the intent so that the broadcast receiver gets the callback successfully.
|
||||||
|
PendingIntent.getBroadcast(activity, 0, intent, 0)
|
||||||
|
} else {
|
||||||
|
NotificationReceiver.shortcutCreatedBroadcast(activity)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request shortcut.
|
||||||
|
ShortcutManagerCompat.requestPinShortcut(activity, shortcutInfo,
|
||||||
|
successCallback.intentSender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showCustomDownloadDialog() {
|
||||||
|
// DownloadCustomChaptersDialog(this, presenter.chapters.size).showDialog(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||||
return inflater.inflate(R.layout.big_manga_controller, container, false)
|
return inflater.inflate(R.layout.big_manga_controller, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onCoverLoaded(color: Int) {
|
|
||||||
if (view == null) return
|
|
||||||
coverColor = color
|
|
||||||
//activity?.window?.statusBarColor = color
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun coverColor(): Int? = coverColor
|
override fun coverColor(): Int? = coverColor
|
||||||
override fun topCoverHeight(): Int = headerHeight
|
override fun topCoverHeight(): Int = headerHeight
|
||||||
|
|
||||||
override fun nextChapter(): Chapter? = presenter.getNextUnreadChapter()
|
|
||||||
override fun mangaSource(): Source = presenter.source
|
|
||||||
|
|
||||||
override fun readNextChapter() {
|
override fun readNextChapter() {
|
||||||
if (activity is SearchActivity && presenter.isLockedFromSearch) {
|
if (activity is SearchActivity && presenter.isLockedFromSearch) {
|
||||||
SecureActivityDelegate.promptLockIfNeeded(activity)
|
SecureActivityDelegate.promptLockIfNeeded(activity)
|
||||||
@ -451,17 +664,17 @@ class MangaChaptersController : BaseController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun downloadChapter(position: Int) {
|
override fun downloadChapter(position: Int) {
|
||||||
val adapter = adapter ?: return
|
val view = view ?: return
|
||||||
val chapter = adapter.getItem(position) ?: return
|
val chapter = adapter?.getItem(position) ?: return
|
||||||
if (chapter.isHeader) return
|
if (chapter.isHeader) return
|
||||||
if (chapter.status != Download.NOT_DOWNLOADED && chapter.status != Download.ERROR) {
|
if (chapter.status != Download.NOT_DOWNLOADED && chapter.status != Download.ERROR) {
|
||||||
presenter.deleteChapters(listOf(chapter))
|
presenter.deleteChapters(listOf(chapter))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val isError = chapter.status == Download.ERROR
|
if (chapter.status == Download.ERROR)
|
||||||
presenter.downloadChapters(listOf(chapter))
|
DownloadService.start(view.context)
|
||||||
if (isError)
|
else
|
||||||
presenter.restartDownloads()
|
downloadChapters(listOf(chapter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,8 +690,6 @@ class MangaChaptersController : BaseController,
|
|||||||
ChaptersSortBottomSheet(this).show()
|
ChaptersSortBottomSheet(this).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterCount():Int = presenter.chapters.size
|
|
||||||
|
|
||||||
override fun favoriteManga(longPress: Boolean) {
|
override fun favoriteManga(longPress: Boolean) {
|
||||||
if (presenter.isLockedFromSearch) {
|
if (presenter.isLockedFromSearch) {
|
||||||
SecureActivityDelegate.promptLockIfNeeded(activity)
|
SecureActivityDelegate.promptLockIfNeeded(activity)
|
||||||
@ -560,8 +771,29 @@ class MangaChaptersController : BaseController,
|
|||||||
(activity as? MainActivity)?.setUndoSnackBar(snack, fab_favorite)
|
(activity as? MainActivity)?.setUndoSnackBar(snack, fab_favorite)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun mangaPresenter(): MangaPresenter = presenter
|
||||||
|
|
||||||
override fun updateCategoriesForMangas(mangas: List<Manga>, categories: List<Category>) {
|
override fun updateCategoriesForMangas(mangas: List<Manga>, categories: List<Category>) {
|
||||||
val manga = mangas.firstOrNull() ?: return
|
val manga = mangas.firstOrNull() ?: return
|
||||||
presenter.moveMangaToCategories(manga, categories)
|
presenter.moveMangaToCategories(manga, categories)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a string to clipboard
|
||||||
|
*
|
||||||
|
* @param label Label to show to the user describing the content
|
||||||
|
* @param content the actual text to copy to the board
|
||||||
|
*/
|
||||||
|
private fun copyToClipboard(label: String, content: String, resId: Int) {
|
||||||
|
if (content.isBlank()) return
|
||||||
|
|
||||||
|
val activity = activity ?: return
|
||||||
|
val view = view ?: return
|
||||||
|
|
||||||
|
val clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
clipboard.setPrimaryClip(ClipData.newPlainText(label, content))
|
||||||
|
|
||||||
|
snack = view.snack(view.context.getString(R.string.copied_to_clipboard, view.context
|
||||||
|
.getString(resId)))
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.graphics.ColorUtils
|
import androidx.core.graphics.ColorUtils
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
|
||||||
import com.bumptech.glide.signature.ObjectKey
|
import com.bumptech.glide.signature.ObjectKey
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
@ -44,9 +45,9 @@ class MangaHeaderHolder(
|
|||||||
manga_genres_tags.setOnTagClickListener {
|
manga_genres_tags.setOnTagClickListener {
|
||||||
adapter.coverListener?.tagClicked(it)
|
adapter.coverListener?.tagClicked(it)
|
||||||
}
|
}
|
||||||
filter_button.setOnClickListener {
|
filter_button.setOnClickListener { adapter.coverListener?.showChapterFilter() }
|
||||||
adapter.coverListener?.showChapterFilter()
|
filters_text.setOnClickListener { adapter.coverListener?.showChapterFilter() }
|
||||||
}
|
share_button.setOnClickListener { adapter.coverListener?.prepareToShareManga() }
|
||||||
favorite_button.setOnClickListener {
|
favorite_button.setOnClickListener {
|
||||||
adapter.coverListener?.favoriteManga(false)
|
adapter.coverListener?.favoriteManga(false)
|
||||||
}
|
}
|
||||||
@ -66,6 +67,7 @@ class MangaHeaderHolder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun bind(item: ChapterItem, manga: Manga) {
|
override fun bind(item: ChapterItem, manga: Manga) {
|
||||||
|
val presenter = adapter.coverListener?.mangaPresenter() ?: return
|
||||||
manga_full_title.text = manga.currentTitle()
|
manga_full_title.text = manga.currentTitle()
|
||||||
|
|
||||||
if (manga.currentGenres().isNullOrBlank().not())
|
if (manga.currentGenres().isNullOrBlank().not())
|
||||||
@ -83,7 +85,8 @@ class MangaHeaderHolder(
|
|||||||
.no_description)
|
.no_description)
|
||||||
|
|
||||||
manga_summary.post {
|
manga_summary.post {
|
||||||
if (manga_summary.lineCount < 3 && manga.currentGenres().isNullOrBlank()) {
|
if ((manga_summary.lineCount < 3 && manga.currentGenres().isNullOrBlank())
|
||||||
|
|| less_button.visibility == View.VISIBLE) {
|
||||||
more_button_group.gone()
|
more_button_group.gone()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -127,11 +130,11 @@ class MangaHeaderHolder(
|
|||||||
itemView.context.getResourceColor(R.attr
|
itemView.context.getResourceColor(R.attr
|
||||||
.colorOnSurface), 31))
|
.colorOnSurface), 31))
|
||||||
}
|
}
|
||||||
true_backdrop.setBackgroundColor(adapter.coverListener?.coverColor() ?:
|
true_backdrop.setBackgroundColor(adapter.coverListener.coverColor() ?:
|
||||||
itemView.context.getResourceColor(android.R.attr.colorBackground))
|
itemView.context.getResourceColor(android.R.attr.colorBackground))
|
||||||
|
|
||||||
with(start_reading_button) {
|
with(start_reading_button) {
|
||||||
val nextChapter = adapter.coverListener?.nextChapter()
|
val nextChapter = presenter.getNextUnreadChapter()
|
||||||
visibleIf(nextChapter != null && !item.isLocked)
|
visibleIf(nextChapter != null && !item.isLocked)
|
||||||
if (nextChapter != null) {
|
if (nextChapter != null) {
|
||||||
val number = adapter.decimalFormat.format(nextChapter.chapter_number.toDouble())
|
val number = adapter.decimalFormat.format(nextChapter.chapter_number.toDouble())
|
||||||
@ -147,11 +150,11 @@ class MangaHeaderHolder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val count = adapter.coverListener?.chapterCount() ?: 0
|
val count = presenter.chapters.size
|
||||||
chapters_title.text = itemView.resources.getQuantityString(R.plurals.chapters, count, count)
|
chapters_title.text = itemView.resources.getQuantityString(R.plurals.chapters, count, count)
|
||||||
|
|
||||||
top_view.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
top_view.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||||
height = adapter.coverListener?.topCoverHeight() ?: 0
|
height = adapter.coverListener.topCoverHeight() ?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
manga_status.text = (itemView.context.getString( when (manga.status) {
|
manga_status.text = (itemView.context.getString( when (manga.status) {
|
||||||
@ -160,7 +163,9 @@ class MangaHeaderHolder(
|
|||||||
SManga.LICENSED -> R.string.licensed
|
SManga.LICENSED -> R.string.licensed
|
||||||
else -> R.string.unknown_status
|
else -> R.string.unknown_status
|
||||||
}))
|
}))
|
||||||
manga_source.text = adapter.coverListener?.mangaSource()?.toString()
|
manga_source.text = presenter.source.toString()
|
||||||
|
|
||||||
|
filters_text.text = presenter.currentFilters()
|
||||||
|
|
||||||
if (!manga.initialized) return
|
if (!manga.initialized) return
|
||||||
GlideApp.with(view.context).load(manga)
|
GlideApp.with(view.context).load(manga)
|
||||||
@ -171,6 +176,7 @@ class MangaHeaderHolder(
|
|||||||
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||||
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
|
.transition(DrawableTransitionOptions.withCrossFade())
|
||||||
.into(backdrop)
|
.into(backdrop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga
|
package eu.kanade.tachiyomi.ui.manga
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.net.Uri
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
@ -18,9 +21,11 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -30,6 +35,9 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.OutputStream
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@ -89,22 +97,24 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
val chapters = withContext(Dispatchers.IO) {
|
val chapters = withContext(Dispatchers.IO) {
|
||||||
db.getChapters(manga).executeAsBlocking().map { it.toModel() }
|
db.getChapters(manga).executeAsBlocking().map { it.toModel() }
|
||||||
}
|
}
|
||||||
// Store the last emission
|
|
||||||
this.chapters = applyChapterFilters(chapters)
|
|
||||||
|
|
||||||
// Find downloaded chapters
|
// Find downloaded chapters
|
||||||
setDownloadedChapters(chapters)
|
setDownloadedChapters(chapters)
|
||||||
|
|
||||||
|
// Store the last emission
|
||||||
|
this.chapters = applyChapterFilters(chapters)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateChapters(fetchedChapters: List<Chapter>? = null) {
|
private fun updateChapters(fetchedChapters: List<Chapter>? = null) {
|
||||||
val chapters = (fetchedChapters ?:
|
val chapters = (fetchedChapters ?:
|
||||||
db.getChapters(manga).executeAsBlocking()).map { it.toModel() }
|
db.getChapters(manga).executeAsBlocking()).map { it.toModel() }
|
||||||
|
|
||||||
// Store the last emission
|
|
||||||
this.chapters = applyChapterFilters(chapters)
|
|
||||||
|
|
||||||
// Find downloaded chapters
|
// Find downloaded chapters
|
||||||
setDownloadedChapters(chapters)
|
setDownloadedChapters(chapters)
|
||||||
|
|
||||||
|
// Store the last emission
|
||||||
|
this.chapters = applyChapterFilters(chapters)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,9 +158,10 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
* Sets the active display mode.
|
* Sets the active display mode.
|
||||||
* @param mode the mode to set.
|
* @param mode the mode to set.
|
||||||
*/
|
*/
|
||||||
fun setDisplayMode(mode: Int) {
|
fun hideTitle(hide: Boolean) {
|
||||||
manga.displayMode = mode
|
manga.displayMode = if (hide) Manga.DISPLAY_NUMBER else Manga.DISPLAY_NAME
|
||||||
db.updateFlags(manga).executeAsBlocking()
|
db.updateFlags(manga).executeAsBlocking()
|
||||||
|
controller.refreshAdapter()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -240,6 +251,11 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
return chapters.sortedByDescending { it.source_order }.find { !it.read }
|
return chapters.sortedByDescending { it.source_order }.find { !it.read }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getUnreadChaptersSorted() = chapters
|
||||||
|
.filter { !it.read && it.status == Download.NOT_DOWNLOADED }
|
||||||
|
.distinctBy { it.name }
|
||||||
|
.sortedByDescending { it.source_order }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next unread chapter or null if everything is read.
|
* Returns the next unread chapter or null if everything is read.
|
||||||
*/
|
*/
|
||||||
@ -404,13 +420,50 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reverses the sorting and requests an UI update.
|
* Sets the sorting order and requests an UI update.
|
||||||
*/
|
*/
|
||||||
fun setSortOrder(desend: Boolean) {
|
fun setSortOrder(desend: Boolean) {
|
||||||
manga.setChapterOrder(if (desend) Manga.SORT_ASC else Manga.SORT_DESC)
|
manga.setChapterOrder(if (desend) Manga.SORT_ASC else Manga.SORT_DESC)
|
||||||
db.updateFlags(manga).executeAsBlocking()
|
asyncUpdateMangaAndChapters()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the sorting method and requests an UI update.
|
||||||
|
*/
|
||||||
|
fun setSortMethod(bySource: Boolean) {
|
||||||
|
manga.sorting = if (bySource) Manga.SORTING_SOURCE else Manga.SORTING_NUMBER
|
||||||
|
asyncUpdateMangaAndChapters()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all filters and requests an UI update.
|
||||||
|
*/
|
||||||
|
fun setFilters(read: Boolean, unread: Boolean, downloaded: Boolean, bookmarked: Boolean) {
|
||||||
|
manga.readFilter = when {
|
||||||
|
read -> Manga.SHOW_READ
|
||||||
|
unread -> Manga.SHOW_UNREAD
|
||||||
|
else -> Manga.SHOW_ALL
|
||||||
|
}
|
||||||
|
manga.downloadedFilter = if (downloaded) Manga.SHOW_DOWNLOADED else Manga.SHOW_ALL
|
||||||
|
manga.bookmarkedFilter = if (bookmarked) Manga.SHOW_BOOKMARKED else Manga.SHOW_ALL
|
||||||
|
asyncUpdateMangaAndChapters()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun asyncUpdateMangaAndChapters() {
|
||||||
|
launch {
|
||||||
|
withContext(Dispatchers.IO) { db.updateFlags(manga).executeAsBlocking() }
|
||||||
updateChapters()
|
updateChapters()
|
||||||
controller.updateChapters(chapters)
|
withContext(Dispatchers.Main) { controller.updateChapters(chapters) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun currentFilters(): String {
|
||||||
|
val filtersId = mutableListOf<Int?>()
|
||||||
|
filtersId.add(if (onlyRead()) R.string.action_filter_read else null)
|
||||||
|
filtersId.add(if (onlyUnread()) R.string.action_filter_unread else null)
|
||||||
|
filtersId.add(if (onlyDownloaded()) R.string.action_filter_downloaded else null)
|
||||||
|
filtersId.add(if (onlyBookmarked()) R.string.action_filter_bookmarked else null)
|
||||||
|
return filtersId.filterNotNull().joinToString(", ") { preferences.context.getString(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleFavorite(): Boolean {
|
fun toggleFavorite(): Boolean {
|
||||||
@ -479,4 +532,122 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
fetchChapters()
|
fetchChapters()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun shareManga(cover: Bitmap) {
|
||||||
|
val context = Injekt.get<Application>()
|
||||||
|
|
||||||
|
val destDir = File(context.cacheDir, "shared_image")
|
||||||
|
|
||||||
|
launch(Dispatchers.IO) {
|
||||||
|
destDir.deleteRecursively()
|
||||||
|
try {
|
||||||
|
val image = saveImage(cover, destDir, manga)
|
||||||
|
if (image != null)
|
||||||
|
controller.shareManga(image)
|
||||||
|
else controller.shareManga()
|
||||||
|
}
|
||||||
|
catch (e:java.lang.Exception) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveImage(cover:Bitmap, directory: File, manga: Manga): File? {
|
||||||
|
directory.mkdirs()
|
||||||
|
|
||||||
|
// Build destination file.
|
||||||
|
val filename = DiskUtil.buildValidFilename("${manga.originalTitle()} - Cover.jpg")
|
||||||
|
|
||||||
|
val destFile = File(directory, filename)
|
||||||
|
val stream: OutputStream = FileOutputStream(destFile)
|
||||||
|
cover.compress(Bitmap.CompressFormat.JPEG, 75, stream)
|
||||||
|
stream.flush()
|
||||||
|
stream.close()
|
||||||
|
return destFile
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateManga(title:String?, author:String?, artist: String?, uri: Uri?,
|
||||||
|
description: String?, tags: Array<String>?) {
|
||||||
|
if (manga.source == LocalSource.ID) {
|
||||||
|
manga.title = if (title.isNullOrBlank()) manga.url else title.trim()
|
||||||
|
manga.author = author?.trim()
|
||||||
|
manga.artist = artist?.trim()
|
||||||
|
manga.description = description?.trim()
|
||||||
|
val tagsString = tags?.joinToString(", ") { it.capitalize() }
|
||||||
|
manga.genre = if (tags.isNullOrEmpty()) null else tagsString?.trim()
|
||||||
|
LocalSource(downloadManager.context).updateMangaInfo(manga)
|
||||||
|
db.updateMangaInfo(manga).executeAsBlocking()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var changed = false
|
||||||
|
val title = title?.trim()
|
||||||
|
if (!title.isNullOrBlank() && manga.originalTitle().isBlank()) {
|
||||||
|
manga.title = title
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
else if (title.isNullOrBlank() && manga.currentTitle() != manga.originalTitle()) {
|
||||||
|
manga.title = manga.originalTitle()
|
||||||
|
changed = true
|
||||||
|
} else if (!title.isNullOrBlank() && title != manga.currentTitle()) {
|
||||||
|
manga.title = "${title}${SManga.splitter}${manga.originalTitle()}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val author = author?.trim()
|
||||||
|
if (author.isNullOrBlank() && manga.currentAuthor() != manga.originalAuthor()) {
|
||||||
|
manga.author = manga.originalAuthor()
|
||||||
|
changed = true
|
||||||
|
} else if (!author.isNullOrBlank() && author != manga.currentAuthor()) {
|
||||||
|
manga.author = "${author}${SManga.splitter}${manga.originalAuthor() ?: ""}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val artist = artist?.trim()
|
||||||
|
if (artist.isNullOrBlank() && manga.currentArtist() != manga.originalArtist()) {
|
||||||
|
manga.artist = manga.originalArtist()
|
||||||
|
changed = true
|
||||||
|
} else if (!artist.isNullOrBlank() && artist != manga.currentArtist()) {
|
||||||
|
manga.artist = "${artist}${SManga.splitter}${manga.originalArtist() ?: ""}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val description = description?.trim()
|
||||||
|
if (description.isNullOrBlank() && manga.currentDesc() != manga.originalDesc()) {
|
||||||
|
manga.description = manga.originalDesc()
|
||||||
|
changed = true
|
||||||
|
} else if (!description.isNullOrBlank() && description != manga.currentDesc()) {
|
||||||
|
manga.description = "${description}${SManga.splitter}${manga.originalDesc() ?: ""}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var tagsString = tags?.joinToString(", ")
|
||||||
|
if ((tagsString.isNullOrBlank() && manga.currentGenres() != manga.originalGenres())
|
||||||
|
|| tagsString == manga.originalGenres()) {
|
||||||
|
manga.genre = manga.originalGenres()
|
||||||
|
changed = true
|
||||||
|
} else if (!tagsString.isNullOrBlank() && tagsString != manga.currentGenres()) {
|
||||||
|
tagsString = tags?.joinToString(", ") { it.capitalize() }
|
||||||
|
manga.genre = "${tagsString}${SManga.splitter}${manga.originalGenres() ?: ""}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if (changed) db.updateMangaInfo(manga).executeAsBlocking()
|
||||||
|
}
|
||||||
|
if (uri != null) editCoverWithStream(uri)
|
||||||
|
controller.updateHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun editCoverWithStream(uri: Uri): Boolean {
|
||||||
|
val inputStream = downloadManager.context.contentResolver.openInputStream(uri) ?:
|
||||||
|
return false
|
||||||
|
if (manga.source == LocalSource.ID) {
|
||||||
|
LocalSource.updateCover(downloadManager.context, manga, inputStream)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (manga.thumbnail_url != null && manga.favorite) {
|
||||||
|
Injekt.get<PreferencesHelper>().refreshCoversToo().set(false)
|
||||||
|
coverCache.copyToCache(manga.thumbnail_url!!, inputStream)
|
||||||
|
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,11 +5,10 @@ import android.view.MenuItem
|
|||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.source.Source
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaPresenter
|
||||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -60,13 +59,12 @@ class ChaptersAdapter(
|
|||||||
|
|
||||||
interface MangaHeaderInterface {
|
interface MangaHeaderInterface {
|
||||||
fun coverColor(): Int?
|
fun coverColor(): Int?
|
||||||
fun nextChapter(): Chapter?
|
fun mangaPresenter(): MangaPresenter
|
||||||
|
fun prepareToShareManga()
|
||||||
fun readNextChapter()
|
fun readNextChapter()
|
||||||
fun downloadChapter(position: Int)
|
fun downloadChapter(position: Int)
|
||||||
fun topCoverHeight(): Int
|
fun topCoverHeight(): Int
|
||||||
fun chapterCount(): Int
|
|
||||||
fun tagClicked(text: String)
|
fun tagClicked(text: String)
|
||||||
fun mangaSource(): Source
|
|
||||||
fun showChapterFilter()
|
fun showChapterFilter()
|
||||||
fun favoriteManga(longPress: Boolean)
|
fun favoriteManga(longPress: Boolean)
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
|||||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaChaptersController
|
||||||
import eu.kanade.tachiyomi.util.lang.chop
|
import eu.kanade.tachiyomi.util.lang.chop
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import kotlinx.android.synthetic.main.edit_manga_dialog.view.*
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.*
|
||||||
@ -34,9 +35,9 @@ class EditMangaDialog : DialogController {
|
|||||||
private var customCoverUri:Uri? = null
|
private var customCoverUri:Uri? = null
|
||||||
|
|
||||||
private val infoController
|
private val infoController
|
||||||
get() = targetController as MangaInfoController
|
get() = targetController as MangaChaptersController
|
||||||
|
|
||||||
constructor(target: MangaInfoController, manga: Manga) : super(Bundle()
|
constructor(target: MangaChaptersController, manga: Manga) : super(Bundle()
|
||||||
.apply {
|
.apply {
|
||||||
putLong(KEY_MANGA, manga.id!!)
|
putLong(KEY_MANGA, manga.id!!)
|
||||||
}) {
|
}) {
|
||||||
@ -168,7 +169,6 @@ class EditMangaDialog : DialogController {
|
|||||||
dialogView?.manga_author?.text.toString(), dialogView?.manga_artist?.text.toString(),
|
dialogView?.manga_author?.text.toString(), dialogView?.manga_artist?.text.toString(),
|
||||||
customCoverUri, dialogView?.manga_description?.text.toString(),
|
customCoverUri, dialogView?.manga_description?.text.toString(),
|
||||||
dialogView?.manga_genres_tags?.tags)
|
dialogView?.manga_genres_tags?.tags)
|
||||||
infoController.updateTitle()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
@ -5,7 +5,6 @@ import android.animation.AnimatorListenerAdapter
|
|||||||
import android.animation.AnimatorSet
|
import android.animation.AnimatorSet
|
||||||
import android.animation.ObjectAnimator
|
import android.animation.ObjectAnimator
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Dialog
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
@ -15,7 +14,6 @@ import android.content.res.Configuration
|
|||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
@ -31,8 +29,6 @@ import androidx.transition.ChangeBounds
|
|||||||
import androidx.transition.ChangeImageTransform
|
import androidx.transition.ChangeImageTransform
|
||||||
import androidx.transition.TransitionManager
|
import androidx.transition.TransitionManager
|
||||||
import androidx.transition.TransitionSet
|
import androidx.transition.TransitionSet
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
|
||||||
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
|
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
|
||||||
@ -55,13 +51,13 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
||||||
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryController
|
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.ChooseShapeDialog
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||||
@ -236,7 +232,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_edit -> EditMangaDialog(this, presenter.manga).showDialog(router)
|
//R.id.action_edit -> EditMangaDialog(this, presenter.manga).showDialog(router)
|
||||||
R.id.action_open_in_web_view -> openInWebView()
|
R.id.action_open_in_web_view -> openInWebView()
|
||||||
R.id.action_share -> prepareToShareManga()
|
R.id.action_share -> prepareToShareManga()
|
||||||
R.id.action_add_to_home_screen -> addToHomeScreen()
|
R.id.action_add_to_home_screen -> addToHomeScreen()
|
||||||
@ -608,41 +604,13 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Dialog to choose a shape for the icon.
|
|
||||||
*/
|
|
||||||
private class ChooseShapeDialog(bundle: Bundle? = null) : DialogController(bundle) {
|
|
||||||
|
|
||||||
constructor(target: MangaInfoController) : this() {
|
|
||||||
targetController = target
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
|
||||||
val modes = intArrayOf(R.string.circular_icon,
|
|
||||||
R.string.rounded_icon,
|
|
||||||
R.string.square_icon,
|
|
||||||
R.string.star_icon)
|
|
||||||
|
|
||||||
return MaterialDialog(activity!!)
|
|
||||||
.title(R.string.icon_shape)
|
|
||||||
.negativeButton(android.R.string.cancel)
|
|
||||||
.listItemsSingleChoice (
|
|
||||||
items = modes.map { activity?.getString(it) as CharSequence },
|
|
||||||
waitForPositiveButton = false)
|
|
||||||
{ _, i, _ ->
|
|
||||||
(targetController as? MangaInfoController)?.createShortcutForShape(i)
|
|
||||||
dismissDialog()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the bitmap of the shortcut with the requested shape and calls [createShortcut] when
|
* Retrieves the bitmap of the shortcut with the requested shape and calls [createShortcut] when
|
||||||
* the resource is available.
|
* the resource is available.
|
||||||
*
|
*
|
||||||
* @param i The shape index to apply. Defaults to circle crop transformation.
|
* @param i The shape index to apply. Defaults to circle crop transformation.
|
||||||
*/
|
*/
|
||||||
private fun createShortcutForShape(i: Int = 0) {
|
fun createShortcutForShape(i: Int = 0) {
|
||||||
if (activity == null) return
|
if (activity == null) return
|
||||||
GlideApp.with(activity!!)
|
GlideApp.with(activity!!)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
|
@ -28,7 +28,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaChaptersController
|
|||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
|
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
|
||||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||||
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForController
|
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
|
||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import kotlinx.android.synthetic.main.recent_chapters_controller.*
|
import kotlinx.android.synthetic.main.recent_chapters_controller.*
|
||||||
@ -82,7 +82,8 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
*/
|
*/
|
||||||
override fun onViewCreated(view: View) {
|
override fun onViewCreated(view: View) {
|
||||||
super.onViewCreated(view)
|
super.onViewCreated(view)
|
||||||
view.applyWindowInsetsForController()
|
view.applyWindowInsetsForRootController(activity!!.navigationView)
|
||||||
|
|
||||||
view.context.notificationManager.cancel(Notifications.ID_NEW_CHAPTERS)
|
view.context.notificationManager.cancel(Notifications.ID_NEW_CHAPTERS)
|
||||||
// Init RecyclerView and adapter
|
// Init RecyclerView and adapter
|
||||||
val layoutManager = LinearLayoutManager(view.context)
|
val layoutManager = LinearLayoutManager(view.context)
|
||||||
|
@ -26,8 +26,9 @@ import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
|
|||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
|
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
|
||||||
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForController
|
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
|
||||||
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
||||||
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import kotlinx.android.synthetic.main.recently_read_controller.*
|
import kotlinx.android.synthetic.main.recently_read_controller.*
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -80,16 +81,7 @@ class RecentlyReadController(bundle: Bundle? = null) : BaseController(bundle),
|
|||||||
*/
|
*/
|
||||||
override fun onViewCreated(view: View) {
|
override fun onViewCreated(view: View) {
|
||||||
super.onViewCreated(view)
|
super.onViewCreated(view)
|
||||||
view.applyWindowInsetsForController()
|
view.applyWindowInsetsForRootController(activity!!.navigationView)
|
||||||
/*view.updateLayoutParams<FrameLayout.LayoutParams> {
|
|
||||||
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
|
|
||||||
val array = view.context.obtainStyledAttributes(attrsArray)
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
topMargin = activity!!.window.decorView.rootWindowInsets.systemWindowInsetTop + array
|
|
||||||
.getDimensionPixelSize(0, 0)
|
|
||||||
}
|
|
||||||
array.recycle()
|
|
||||||
}*/
|
|
||||||
// Initialize adapter
|
// Initialize adapter
|
||||||
adapter = RecentlyReadAdapter(this)
|
adapter = RecentlyReadAdapter(this)
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
|
@ -17,6 +17,8 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||||
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
|
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
|
||||||
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForController
|
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForController
|
||||||
|
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
|
||||||
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.subscriptions.CompositeSubscription
|
import rx.subscriptions.CompositeSubscription
|
||||||
@ -35,24 +37,12 @@ abstract class SettingsController : PreferenceController() {
|
|||||||
untilDestroySubscriptions = CompositeSubscription()
|
untilDestroySubscriptions = CompositeSubscription()
|
||||||
}
|
}
|
||||||
val view = super.onCreateView(inflater, container, savedInstanceState)
|
val view = super.onCreateView(inflater, container, savedInstanceState)
|
||||||
/*view.updateLayoutParams<FrameLayout.LayoutParams> {
|
if (this is SettingsMainController)
|
||||||
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
|
view.applyWindowInsetsForRootController(activity!!.navigationView)
|
||||||
val array = view.context.obtainStyledAttributes(attrsArray)
|
else {
|
||||||
topMargin = array.getDimensionPixelSize(0, 0)
|
|
||||||
array.recycle()
|
|
||||||
}*/
|
|
||||||
|
|
||||||
view.applyWindowInsetsForController()
|
view.applyWindowInsetsForController()
|
||||||
/*view.updateLayoutParams<FrameLayout.LayoutParams> {
|
|
||||||
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
|
|
||||||
val array = view.context.obtainStyledAttributes(attrsArray)
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
topMargin = activity!!.window.decorView.rootWindowInsets.systemWindowInsetTop + array
|
|
||||||
.getDimensionPixelSize(0, 0)
|
|
||||||
}
|
|
||||||
array.recycle()
|
|
||||||
}*/
|
|
||||||
listView.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
listView.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
||||||
|
}
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import android.graphics.drawable.GradientDrawable
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.view.ViewTreeObserver
|
||||||
import android.view.WindowInsets
|
import android.view.WindowInsets
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
@ -207,6 +208,28 @@ fun View.applyWindowInsetsForController() {
|
|||||||
requestApplyInsetsWhenAttached()
|
requestApplyInsetsWhenAttached()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun View.applyWindowInsetsForRootController(bottomNav: View) {
|
||||||
|
viewTreeObserver.addOnGlobalLayoutListener(
|
||||||
|
object : ViewTreeObserver.OnGlobalLayoutListener {
|
||||||
|
override fun onGlobalLayout() {
|
||||||
|
if (bottomNav.height > 0) {
|
||||||
|
viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||||
|
setOnApplyWindowInsetsListener { view, insets ->
|
||||||
|
view.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||||
|
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
|
||||||
|
val array = view.context.obtainStyledAttributes(attrsArray)
|
||||||
|
topMargin = insets.systemWindowInsetTop + array.getDimensionPixelSize(0, 0)
|
||||||
|
bottomMargin = bottomNav.height
|
||||||
|
array.recycle()
|
||||||
|
}
|
||||||
|
insets
|
||||||
|
}
|
||||||
|
requestApplyInsetsWhenAttached()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun View.requestApplyInsetsWhenAttached() {
|
fun View.requestApplyInsetsWhenAttached() {
|
||||||
if (isAttachedToWindow) {
|
if (isAttachedToWindow) {
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
android:imeOptions="actionDone"
|
android:imeOptions="actionDone"
|
||||||
android:inputType="none"
|
android:inputType="none"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
|
android:singleLine="true"
|
||||||
android:textColor="@color/textColorPrimary"
|
android:textColor="@color/textColorPrimary"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
app:layout_constraintEnd_toEndOf="@id/title"
|
app:layout_constraintEnd_toEndOf="@id/title"
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
android:id="@+id/sort_group"
|
android:id="@+id/sort_group"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="12dp"
|
android:paddingStart="12dp"
|
||||||
@ -39,34 +39,19 @@
|
|||||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
android:id="@+id/sort_newest"
|
android:id="@+id/sort_newest"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Newest first" />
|
android:text="@string/newest_first" />
|
||||||
|
|
||||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
android:id="@+id/sort_oldest"
|
android:id="@+id/sort_oldest"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="12dp"
|
android:text="@string/oldest_first" />
|
||||||
android:text="Oldest first" />
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
|
||||||
android:id="@+id/sort_by_source"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="12dp"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:text="Sort by source's order" />
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
|
||||||
android:id="@+id/show_titles"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="12dp"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:text="Hide chapter titles" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline6"
|
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -82,7 +67,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
android:layout_marginEnd="12dp"
|
android:layout_marginEnd="12dp"
|
||||||
android:text="Show All" />
|
android:text="@string/show_all" />
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
android:id="@+id/show_read"
|
android:id="@+id/show_read"
|
||||||
@ -90,7 +75,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
android:layout_marginEnd="12dp"
|
android:layout_marginEnd="12dp"
|
||||||
android:text="Show read chapters" />
|
android:text="@string/show_read_chapters" />
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
android:id="@+id/show_unread"
|
android:id="@+id/show_unread"
|
||||||
@ -98,7 +83,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
android:layout_marginEnd="12dp"
|
android:layout_marginEnd="12dp"
|
||||||
android:text="Show unread chapters" />
|
android:text="@string/show_unread_chapters" />
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
android:id="@+id/show_download"
|
android:id="@+id/show_download"
|
||||||
@ -106,7 +91,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
android:layout_marginEnd="12dp"
|
android:layout_marginEnd="12dp"
|
||||||
android:text="Show downloaded chapters" />
|
android:text="@string/show_downloaded_chapters" />
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
android:id="@+id/show_bookmark"
|
android:id="@+id/show_bookmark"
|
||||||
@ -114,7 +99,45 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
android:layout_marginEnd="12dp"
|
android:layout_marginEnd="12dp"
|
||||||
android:text="Show bookmarked chapters" />
|
android:text="@string/show_bookmarked_chapters" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:text="@string/more" />
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/sort_method_group"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp">
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/sort_by_source"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/sort_by_source_s_order" />
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/sort_by_number"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/sort_by_chapter_number" />
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/hide_titles"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:text="@string/hide_chapter_titles" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
android:id="@+id/controller_container"
|
android:id="@+id/controller_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/navigationView"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@
|
|||||||
app:icon="@drawable/ic_sync_black_24dp" />
|
app:icon="@drawable/ic_sync_black_24dp" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/edit_button"
|
android:id="@+id/share_button"
|
||||||
style="@style/Theme.Widget.CustomImageButton"
|
style="@style/Theme.Widget.CustomImageButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -173,8 +173,8 @@
|
|||||||
android:layout_marginStart="6dp"
|
android:layout_marginStart="6dp"
|
||||||
android:layout_marginEnd="6dp"
|
android:layout_marginEnd="6dp"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:src="@drawable/ic_edit_white_24dp"
|
android:contentDescription="@string/action_share"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/chapters_title" />
|
android:src="@drawable/ic_share_white_24dp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
@ -312,16 +312,17 @@
|
|||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/chapters_title"
|
android:id="@+id/chapters_title"
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline6"
|
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="18dp"
|
android:layout_marginTop="18dp"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
|
android:maxLines="1"
|
||||||
android:text="@string/chapters"
|
android:text="@string/chapters"
|
||||||
android:textSize="17sp"
|
android:textSize="17sp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/filters_text"
|
||||||
app:layout_constraintStart_toStartOf="@id/manga_summary_label"
|
app:layout_constraintStart_toStartOf="@id/manga_summary_label"
|
||||||
app:layout_constraintTop_toBottomOf="@id/start_reading_button"
|
app:layout_constraintTop_toBottomOf="@id/start_reading_button" />
|
||||||
app:layout_constraintEnd_toStartOf="@id/filters_text"/>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/filter_button"
|
android:id="@+id/filter_button"
|
||||||
@ -332,17 +333,22 @@
|
|||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:src="@drawable/ic_filter_list_white_24dp"
|
android:src="@drawable/ic_filter_list_white_24dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/chapters_title"
|
app:layout_constraintBottom_toBottomOf="@id/chapters_title"
|
||||||
app:layout_constraintTop_toTopOf="@id/chapters_title"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintTop_toTopOf="@id/chapters_title" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/filters_text"
|
android:id="@+id/filters_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginEnd="6dp"
|
android:layout_marginEnd="6dp"
|
||||||
|
android:maxLines="2"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
tools:text="Read"
|
android:textColor="?android:textColorHint"
|
||||||
app:layout_constraintTop_toTopOf="@id/filter_button"
|
android:textAlignment="textEnd"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/filter_button"
|
app:layout_constraintBottom_toBottomOf="@id/filter_button"
|
||||||
app:layout_constraintEnd_toStartOf="@id/filter_button" />
|
app:layout_constraintEnd_toStartOf="@id/filter_button"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/chapters_title"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/filter_button"
|
||||||
|
tools:text="Read, Unread, Bookmarked, Downloaded, All" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
54
app/src/main/res/menu/manga_details.xml
Normal file
54
app/src/main/res/menu/manga_details.xml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_edit"
|
||||||
|
android:icon="@drawable/ic_edit_white_24dp"
|
||||||
|
android:title="@string/action_edit"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_download"
|
||||||
|
android:icon="@drawable/ic_file_download_white_24dp"
|
||||||
|
android:title="@string/action_share"
|
||||||
|
app:showAsAction="ifRoom">
|
||||||
|
<menu>
|
||||||
|
<item
|
||||||
|
android:id="@+id/download_next"
|
||||||
|
android:title="@string/download_1" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/download_next_5"
|
||||||
|
android:title="@string/download_5" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/download_next_10"
|
||||||
|
android:title="@string/download_10" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/download_custom"
|
||||||
|
android:title="@string/download_custom" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/download_unread"
|
||||||
|
android:title="@string/download_unread" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/download_all"
|
||||||
|
android:title="@string/download_all" />
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_mark_all_as_read"
|
||||||
|
android:icon="@drawable/ic_done_all_white_24dp"
|
||||||
|
android:title="@string/action_mark_all_as_read"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_open_in_web_view"
|
||||||
|
android:title="@string/action_open_in_web_view"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_add_to_home_screen"
|
||||||
|
android:title="@string/action_add_to_home_screen"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
</menu>
|
@ -68,6 +68,7 @@
|
|||||||
<string name="action_skip_manga">Don\'t migrate</string>
|
<string name="action_skip_manga">Don\'t migrate</string>
|
||||||
<string name="action_select_all">Select all</string>
|
<string name="action_select_all">Select all</string>
|
||||||
<string name="action_mark_as_read">Mark as read</string>
|
<string name="action_mark_as_read">Mark as read</string>
|
||||||
|
<string name="action_mark_all_as_read">Mark all as read</string>
|
||||||
<string name="action_mark_as_unread">Mark as unread</string>
|
<string name="action_mark_as_unread">Mark as unread</string>
|
||||||
<string name="action_mark_previous_as_read">Mark previous as read</string>
|
<string name="action_mark_previous_as_read">Mark previous as read</string>
|
||||||
<string name="action_mark_multiple">Mark multiple</string>
|
<string name="action_mark_multiple">Mark multiple</string>
|
||||||
@ -507,6 +508,7 @@
|
|||||||
<item quantity="other">%1$d chapters</item>
|
<item quantity="other">%1$d chapters</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="no_description">No description</string>
|
<string name="no_description">No description</string>
|
||||||
|
<string name="mark_all_as_read_message">Mark all chapters as read?</string>
|
||||||
|
|
||||||
<!-- Manga chapters fragment -->
|
<!-- Manga chapters fragment -->
|
||||||
<string name="start_reading">Start reading</string>
|
<string name="start_reading">Start reading</string>
|
||||||
@ -710,5 +712,16 @@
|
|||||||
<string name="action_auto">Auto</string>
|
<string name="action_auto">Auto</string>
|
||||||
<string name="more">More</string>
|
<string name="more">More</string>
|
||||||
<string name="less">Less</string>
|
<string name="less">Less</string>
|
||||||
|
<string name="more_options">More options</string>
|
||||||
|
<string name="show_bookmarked_chapters">Show bookmarked chapters</string>
|
||||||
|
<string name="show_downloaded_chapters">Show downloaded chapters</string>
|
||||||
|
<string name="show_unread_chapters">Show unread chapters</string>
|
||||||
|
<string name="show_read_chapters">Show read chapters</string>
|
||||||
|
<string name="show_all">Show All</string>
|
||||||
|
<string name="hide_chapter_titles">Hide chapter titles</string>
|
||||||
|
<string name="sort_by_source_s_order">Sort by source\'s order</string>
|
||||||
|
<string name="sort_by_chapter_number">Sort by chapter number</string>
|
||||||
|
<string name="newest_first">Newest to oldest</string>
|
||||||
|
<string name="oldest_first">Oldest to newest</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user