mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-15 05:27:28 +01:00
Merge branch 'dev' into dev-settings-search
This commit is contained in:
@@ -7,11 +7,11 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||
|
||||
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
|
||||
|
||||
@@ -22,27 +22,29 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
||||
lateinit var binding: VB
|
||||
|
||||
init {
|
||||
addLifecycleListener(object : LifecycleListener() {
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
onViewCreated(view)
|
||||
}
|
||||
addLifecycleListener(
|
||||
object : LifecycleListener() {
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
onViewCreated(view)
|
||||
}
|
||||
|
||||
override fun preCreateView(controller: Controller) {
|
||||
Timber.d("Create view for ${controller.instance()}")
|
||||
}
|
||||
override fun preCreateView(controller: Controller) {
|
||||
Timber.d("Create view for ${controller.instance()}")
|
||||
}
|
||||
|
||||
override fun preAttach(controller: Controller, view: View) {
|
||||
Timber.d("Attach view for ${controller.instance()}")
|
||||
}
|
||||
override fun preAttach(controller: Controller, view: View) {
|
||||
Timber.d("Attach view for ${controller.instance()}")
|
||||
}
|
||||
|
||||
override fun preDetach(controller: Controller, view: View) {
|
||||
Timber.d("Detach view for ${controller.instance()}")
|
||||
}
|
||||
override fun preDetach(controller: Controller, view: View) {
|
||||
Timber.d("Detach view for ${controller.instance()}")
|
||||
}
|
||||
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
Timber.d("Destroy view for ${controller.instance()}")
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
Timber.d("Destroy view for ${controller.instance()}")
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
override val containerView: View?
|
||||
@@ -98,17 +100,19 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
||||
var expandActionViewFromInteraction = false
|
||||
|
||||
fun MenuItem.fixExpand(onExpand: ((MenuItem) -> Boolean)? = null, onCollapse: ((MenuItem) -> Boolean)? = null) {
|
||||
setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||
return onExpand?.invoke(item) ?: true
|
||||
}
|
||||
setOnActionExpandListener(
|
||||
object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||
return onExpand?.invoke(item) ?: true
|
||||
}
|
||||
|
||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||
activity?.invalidateOptionsMenu()
|
||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||
activity?.invalidateOptionsMenu()
|
||||
|
||||
return onCollapse?.invoke(item) ?: true
|
||||
return onCollapse?.invoke(item) ?: true
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
if (expandActionViewFromInteraction) {
|
||||
expandActionViewFromInteraction = false
|
||||
|
||||
@@ -10,12 +10,12 @@ import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import java.util.concurrent.TimeUnit
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
private typealias ExtensionTuple =
|
||||
Triple<List<Extension.Installed>, List<Extension.Untrusted>, List<Extension.Available>>
|
||||
|
||||
@@ -20,8 +20,6 @@ import androidx.preference.PreferenceManager
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore
|
||||
@@ -92,7 +90,6 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
ExtensionDetailsHeaderAdapter(presenter),
|
||||
initPreferencesAdapter(context, extension)
|
||||
)
|
||||
binding.extensionPrefsRecycler.addItemDecoration(DividerItemDecoration(context, VERTICAL))
|
||||
}
|
||||
|
||||
private fun initPreferencesAdapter(context: Context, extension: Extension.Installed): PreferenceGroupAdapter {
|
||||
@@ -112,7 +109,7 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
.forEach {
|
||||
val preferenceBlock = {
|
||||
it.value
|
||||
.sortedWith(compareBy({ !it.isEnabled() }, { it.name }))
|
||||
.sortedWith(compareBy({ !it.isEnabled() }, { it.name.toLowerCase() }))
|
||||
.forEach { source ->
|
||||
val sourcePrefs = mutableListOf<Preference>()
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceGroupAdapter
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore
|
||||
@@ -86,7 +84,6 @@ class SourcePreferencesController(bundle: Bundle? = null) :
|
||||
|
||||
binding.recycler.layoutManager = LinearLayoutManager(context)
|
||||
binding.recycler.adapter = PreferenceGroupAdapter(screen)
|
||||
binding.recycler.addItemDecoration(DividerItemDecoration(context, VERTICAL))
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
|
||||
@@ -13,10 +13,10 @@ import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchCardItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchPresenter
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import java.util.Date
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import java.util.Date
|
||||
|
||||
class SearchPresenter(
|
||||
initialQuery: String? = "",
|
||||
|
||||
@@ -29,7 +29,7 @@ class MigrationSourcesPresenter(
|
||||
val header = SelectionHeader()
|
||||
return library.map { it.source }.toSet()
|
||||
.mapNotNull { if (it != LocalSource.ID) sourceManager.getOrStub(it) else null }
|
||||
.sortedBy { it.name }
|
||||
.sortedBy { it.name.toLowerCase() }
|
||||
.map { SourceItem(it, header) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@ import eu.kanade.tachiyomi.util.preference.onChange
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import java.util.TreeMap
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.TreeMap
|
||||
|
||||
class SourceFilterController : SettingsController() {
|
||||
|
||||
@@ -42,7 +42,7 @@ class SourceFilterController : SettingsController() {
|
||||
)
|
||||
|
||||
orderedLangs.forEach { lang ->
|
||||
val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name }
|
||||
val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name.toLowerCase() }
|
||||
|
||||
// Create a preference group and set initial state and change listener
|
||||
switchPreferenceCategory {
|
||||
|
||||
@@ -6,7 +6,6 @@ import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import java.util.TreeMap
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -21,6 +20,7 @@ import rx.Observable
|
||||
import rx.Subscription
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.TreeMap
|
||||
|
||||
/**
|
||||
* Presenter of [SourceController]
|
||||
@@ -128,7 +128,7 @@ class SourcePresenter(
|
||||
return sourceManager.getCatalogueSources()
|
||||
.filter { it.lang in languages }
|
||||
.filterNot { it.id.toString() in disabledSourceIds }
|
||||
.sortedBy { "(${it.lang}) ${it.name}" } +
|
||||
.sortedBy { "(${it.lang}) ${it.name.toLowerCase()}" } +
|
||||
sourceManager.get(LocalSource.ID) as LocalSource
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -216,7 +215,6 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
id = R.id.recycler
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
layoutParams = RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
|
||||
}
|
||||
} else {
|
||||
(binding.catalogueView.inflate(R.layout.source_recycler_autofit) as AutofitRecyclerView).apply {
|
||||
|
||||
@@ -28,9 +28,8 @@ import eu.kanade.tachiyomi.ui.browse.source.filter.TextItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TextSectionItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem
|
||||
import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import java.util.Date
|
||||
import kotlinx.coroutines.flow.subscribe
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@@ -39,6 +38,7 @@ import rx.subjects.PublishSubject
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
* Presenter of [BrowseSourceController].
|
||||
@@ -268,6 +268,8 @@ open class BrowseSourcePresenter(
|
||||
|
||||
if (!manga.favorite) {
|
||||
manga.removeCovers(coverCache)
|
||||
} else {
|
||||
ChapterSettingsHelper.applySettingDefaults(manga)
|
||||
}
|
||||
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
|
||||
@@ -38,10 +38,13 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
|
||||
val coverHeight = parent.itemWidth / 3 * 4
|
||||
view.apply {
|
||||
card.layoutParams = FrameLayout.LayoutParams(
|
||||
MATCH_PARENT, coverHeight
|
||||
MATCH_PARENT,
|
||||
coverHeight
|
||||
)
|
||||
gradient.layoutParams = FrameLayout.LayoutParams(
|
||||
MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM
|
||||
MATCH_PARENT,
|
||||
coverHeight / 2,
|
||||
Gravity.BOTTOM
|
||||
)
|
||||
}
|
||||
SourceGridHolder(view, adapter)
|
||||
@@ -51,7 +54,8 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
|
||||
val coverHeight = parent.itemWidth / 3 * 4
|
||||
view.apply {
|
||||
card.layoutParams = ConstraintLayout.LayoutParams(
|
||||
MATCH_PARENT, coverHeight
|
||||
MATCH_PARENT,
|
||||
coverHeight
|
||||
)
|
||||
}
|
||||
SourceComfortableGridHolder(view, adapter)
|
||||
|
||||
@@ -30,7 +30,8 @@ open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem<Selec
|
||||
spinner.prompt = filter.name
|
||||
spinner.adapter = ArrayAdapter<Any>(
|
||||
holder.itemView.context,
|
||||
android.R.layout.simple_spinner_item, filter.values
|
||||
android.R.layout.simple_spinner_item,
|
||||
filter.values
|
||||
).apply {
|
||||
setDropDownViewResource(R.layout.common_spinner_item)
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R as TR
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.R as TR
|
||||
|
||||
open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriStateItem.Holder>() {
|
||||
|
||||
|
||||
@@ -108,17 +108,19 @@ open class GlobalSearchController(
|
||||
val searchView = searchItem.actionView as SearchView
|
||||
searchView.maxWidth = Int.MAX_VALUE
|
||||
|
||||
searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
||||
searchView.onActionViewExpanded() // Required to show the query in the view
|
||||
searchView.setQuery(presenter.query, false)
|
||||
return true
|
||||
}
|
||||
searchItem.setOnActionExpandListener(
|
||||
object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
||||
searchView.onActionViewExpanded() // Required to show the query in the view
|
||||
searchView.setQuery(presenter.query, false)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
||||
return true
|
||||
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
searchView.queryTextEvents()
|
||||
.filterIsInstance<QueryTextEvent.QuerySubmitted>()
|
||||
|
||||
@@ -108,7 +108,7 @@ open class GlobalSearchPresenter(
|
||||
return sourceManager.getCatalogueSources()
|
||||
.filter { it.lang in languages }
|
||||
.filterNot { it.id.toString() in disabledSourceIds }
|
||||
.sortedWith(compareBy({ it.id.toString() !in pinnedSourceIds }, { "${it.name} (${it.lang})" }))
|
||||
.sortedWith(compareBy({ it.id.toString() !in pinnedSourceIds }, { "${it.name.toLowerCase()} (${it.lang})" }))
|
||||
}
|
||||
|
||||
private fun getSourcesToQuery(): List<CatalogueSource> {
|
||||
@@ -188,7 +188,7 @@ open class GlobalSearchPresenter(
|
||||
{ it.results.isNullOrEmpty() },
|
||||
// Same as initial sort, i.e. pinned first then alphabetically
|
||||
{ it.source.id.toString() !in pinnedSourceIds },
|
||||
{ "${it.source.name} (${it.source.lang})" }
|
||||
{ "${it.source.name.toLowerCase()} (${it.source.lang})" }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -198,8 +198,11 @@ class CategoryController :
|
||||
R.id.action_delete -> {
|
||||
undoHelper = UndoHelper(adapter, this)
|
||||
undoHelper?.start(
|
||||
adapter.selectedPositions, activity!!.root_coordinator,
|
||||
R.string.snack_categories_deleted, R.string.action_undo, 3000
|
||||
adapter.selectedPositions,
|
||||
activity!!.root_coordinator,
|
||||
R.string.snack_categories_deleted,
|
||||
R.string.action_undo,
|
||||
3000
|
||||
)
|
||||
|
||||
mode.finish()
|
||||
|
||||
@@ -18,13 +18,13 @@ import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.base.controller.FabController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.util.view.shrinkOnScroll
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import reactivecircus.flowbinding.android.view.clicks
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Controller that shows the currently active downloads.
|
||||
|
||||
@@ -183,7 +183,7 @@ class LibraryController(
|
||||
createActionModeIfNeeded()
|
||||
}
|
||||
|
||||
settingsSheet = LibrarySettingsSheet(activity!!) { group ->
|
||||
settingsSheet = LibrarySettingsSheet(router) { group ->
|
||||
when (group) {
|
||||
is LibrarySettingsSheet.Filter.FilterGroup -> onFilterChanged()
|
||||
is LibrarySettingsSheet.Sort.SortGroup -> onSortChanged()
|
||||
|
||||
@@ -45,7 +45,9 @@ class LibraryItem(val manga: LibraryManga, private val libraryDisplayMode: Prefe
|
||||
view.apply {
|
||||
card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
|
||||
gradient.layoutParams = FrameLayout.LayoutParams(
|
||||
MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM
|
||||
MATCH_PARENT,
|
||||
coverHeight / 2,
|
||||
Gravity.BOTTOM
|
||||
)
|
||||
}
|
||||
LibraryCompactGridHolder(view, adapter)
|
||||
@@ -55,7 +57,8 @@ class LibraryItem(val manga: LibraryManga, private val libraryDisplayMode: Prefe
|
||||
val coverHeight = parent.itemWidth / 3 * 4
|
||||
view.apply {
|
||||
card.layoutParams = ConstraintLayout.LayoutParams(
|
||||
MATCH_PARENT, coverHeight
|
||||
MATCH_PARENT,
|
||||
coverHeight
|
||||
)
|
||||
}
|
||||
LibraryComfortableGridHolder(view, adapter)
|
||||
|
||||
@@ -19,14 +19,16 @@ import eu.kanade.tachiyomi.util.lang.combineLatest
|
||||
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import java.util.Collections
|
||||
import java.util.Comparator
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_IGNORE
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_INCLUDE
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Collections
|
||||
import java.util.Comparator
|
||||
|
||||
/**
|
||||
* Class containing library information.
|
||||
@@ -110,34 +112,45 @@ class LibraryPresenter(
|
||||
* @param map the map to filter.
|
||||
*/
|
||||
private fun applyFilters(map: LibraryMap): LibraryMap {
|
||||
val filterDownloaded = preferences.downloadedOnly().get() || preferences.filterDownloaded().get()
|
||||
val downloadedOnly = preferences.downloadedOnly().get()
|
||||
val filterDownloaded = preferences.filterDownloaded().get()
|
||||
val filterUnread = preferences.filterUnread().get()
|
||||
val filterCompleted = preferences.filterCompleted().get()
|
||||
|
||||
val filterFn: (LibraryItem) -> Boolean = f@{ item ->
|
||||
// Filter when there isn't unread chapters.
|
||||
if (filterUnread && item.manga.unread == 0) {
|
||||
return@f false
|
||||
val filterFnUnread: (LibraryItem) -> Boolean = unread@{ item ->
|
||||
if (filterUnread == STATE_IGNORE) return@unread true
|
||||
val isUnread = item.manga.unread != 0
|
||||
|
||||
return@unread if (filterUnread == STATE_INCLUDE) isUnread
|
||||
else !isUnread
|
||||
}
|
||||
|
||||
val filterFnCompleted: (LibraryItem) -> Boolean = completed@{ item ->
|
||||
if (filterCompleted == STATE_IGNORE) return@completed true
|
||||
val isCompleted = item.manga.status == SManga.COMPLETED
|
||||
|
||||
return@completed if (filterCompleted == STATE_INCLUDE) isCompleted
|
||||
else !isCompleted
|
||||
}
|
||||
|
||||
val filterFnDownloaded: (LibraryItem) -> Boolean = downloaded@{ item ->
|
||||
if (!downloadedOnly && filterDownloaded == STATE_IGNORE) return@downloaded true
|
||||
val isDownloaded = when {
|
||||
item.manga.isLocal() -> true
|
||||
item.downloadCount != -1 -> item.downloadCount > 0
|
||||
else -> downloadManager.getDownloadCount(item.manga) > 0
|
||||
}
|
||||
|
||||
if (filterCompleted && item.manga.status != SManga.COMPLETED) {
|
||||
return@f false
|
||||
}
|
||||
return@downloaded if (downloadedOnly || filterDownloaded == STATE_INCLUDE) isDownloaded
|
||||
else !isDownloaded
|
||||
}
|
||||
|
||||
// Filter when there are no downloads.
|
||||
if (filterDownloaded) {
|
||||
// Local manga are always downloaded
|
||||
if (item.manga.isLocal()) {
|
||||
return@f true
|
||||
}
|
||||
// Don't bother with directory checking if download count has been set.
|
||||
if (item.downloadCount != -1) {
|
||||
return@f item.downloadCount > 0
|
||||
}
|
||||
|
||||
return@f downloadManager.getDownloadCount(item.manga) > 0
|
||||
}
|
||||
true
|
||||
val filterFn: (LibraryItem) -> Boolean = filter@{ item ->
|
||||
return@filter !(
|
||||
!filterFnUnread(item) ||
|
||||
!filterFnCompleted(item) ||
|
||||
!filterFnDownloaded(item)
|
||||
)
|
||||
}
|
||||
|
||||
return map.mapValues { entry -> entry.value.filter(filterFn) }
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_EXCLUDE
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_IGNORE
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_INCLUDE
|
||||
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class LibrarySettingsSheet(
|
||||
activity: Activity,
|
||||
router: Router,
|
||||
onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
|
||||
) : TabbedBottomSheetDialog(activity) {
|
||||
) : TabbedBottomSheetDialog(router) {
|
||||
|
||||
val filters: Filter
|
||||
private val sort: Sort
|
||||
private val display: Display
|
||||
|
||||
init {
|
||||
filters = Filter(activity)
|
||||
filters = Filter(router.activity!!)
|
||||
filters.onGroupClicked = onGroupClickListener
|
||||
|
||||
sort = Sort(activity)
|
||||
sort = Sort(router.activity!!)
|
||||
sort.onGroupClicked = onGroupClickListener
|
||||
|
||||
display = Display(activity)
|
||||
display = Display(router.activity!!)
|
||||
display.onGroupClicked = onGroupClickListener
|
||||
}
|
||||
|
||||
@@ -59,33 +62,43 @@ class LibrarySettingsSheet(
|
||||
* Returns true if there's at least one filter from [FilterGroup] active.
|
||||
*/
|
||||
fun hasActiveFilters(): Boolean {
|
||||
return filterGroup.items.any { it.checked }
|
||||
return filterGroup.items.any { it.state != Item.TriStateGroup.STATE_IGNORE }
|
||||
}
|
||||
|
||||
inner class FilterGroup : Group {
|
||||
|
||||
private val downloaded = Item.CheckboxGroup(R.string.action_filter_downloaded, this)
|
||||
private val unread = Item.CheckboxGroup(R.string.action_filter_unread, this)
|
||||
private val completed = Item.CheckboxGroup(R.string.completed, this)
|
||||
private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this)
|
||||
private val unread = Item.TriStateGroup(R.string.action_filter_unread, this)
|
||||
private val completed = Item.TriStateGroup(R.string.completed, this)
|
||||
|
||||
override val header = null
|
||||
override val items = listOf(downloaded, unread, completed)
|
||||
override val footer = null
|
||||
|
||||
override fun initModels() {
|
||||
downloaded.checked = preferences.downloadedOnly().get() || preferences.filterDownloaded().get()
|
||||
downloaded.enabled = !preferences.downloadedOnly().get()
|
||||
unread.checked = preferences.filterUnread().get()
|
||||
completed.checked = preferences.filterCompleted().get()
|
||||
if (preferences.downloadedOnly().get()) {
|
||||
downloaded.state = STATE_INCLUDE
|
||||
downloaded.enabled = false
|
||||
} else {
|
||||
downloaded.state = preferences.filterDownloaded().get()
|
||||
}
|
||||
unread.state = preferences.filterUnread().get()
|
||||
completed.state = preferences.filterCompleted().get()
|
||||
}
|
||||
|
||||
override fun onItemClicked(item: Item) {
|
||||
item as Item.CheckboxGroup
|
||||
item.checked = !item.checked
|
||||
item as Item.TriStateGroup
|
||||
val newState = when (item.state) {
|
||||
STATE_IGNORE -> STATE_INCLUDE
|
||||
STATE_INCLUDE -> STATE_EXCLUDE
|
||||
STATE_EXCLUDE -> STATE_IGNORE
|
||||
else -> throw Exception("Unknown State")
|
||||
}
|
||||
item.state = newState
|
||||
when (item) {
|
||||
downloaded -> preferences.filterDownloaded().set(item.checked)
|
||||
unread -> preferences.filterUnread().set(item.checked)
|
||||
completed -> preferences.filterCompleted().set(item.checked)
|
||||
downloaded -> preferences.filterDownloaded().set(newState)
|
||||
unread -> preferences.filterUnread().set(newState)
|
||||
completed -> preferences.filterCompleted().set(newState)
|
||||
}
|
||||
|
||||
adapter.notifyItemChanged(item)
|
||||
|
||||
@@ -44,13 +44,13 @@ import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlinx.android.synthetic.main.main_activity.appbar
|
||||
import kotlinx.android.synthetic.main.main_activity.tabs
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import timber.log.Timber
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||
|
||||
@@ -126,26 +126,28 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
router.addChangeListener(object : ControllerChangeHandler.ControllerChangeListener {
|
||||
override fun onChangeStarted(
|
||||
to: Controller?,
|
||||
from: Controller?,
|
||||
isPush: Boolean,
|
||||
container: ViewGroup,
|
||||
handler: ControllerChangeHandler
|
||||
) {
|
||||
syncActivityViewWithController(to, from)
|
||||
}
|
||||
router.addChangeListener(
|
||||
object : ControllerChangeHandler.ControllerChangeListener {
|
||||
override fun onChangeStarted(
|
||||
to: Controller?,
|
||||
from: Controller?,
|
||||
isPush: Boolean,
|
||||
container: ViewGroup,
|
||||
handler: ControllerChangeHandler
|
||||
) {
|
||||
syncActivityViewWithController(to, from)
|
||||
}
|
||||
|
||||
override fun onChangeCompleted(
|
||||
to: Controller?,
|
||||
from: Controller?,
|
||||
isPush: Boolean,
|
||||
container: ViewGroup,
|
||||
handler: ControllerChangeHandler
|
||||
) {
|
||||
override fun onChangeCompleted(
|
||||
to: Controller?,
|
||||
from: Controller?,
|
||||
isPush: Boolean,
|
||||
container: ViewGroup,
|
||||
handler: ControllerChangeHandler
|
||||
) {
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
syncActivityViewWithController(router.backstack.lastOrNull()?.controller())
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ import eu.kanade.tachiyomi.ui.library.ChangeMangaCoverDialog
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.main.offsetAppbarHeight
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterDividerItemDecoration
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSettingsSheet
|
||||
@@ -65,13 +64,13 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryController
|
||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import eu.kanade.tachiyomi.util.chapter.NoChaptersException
|
||||
import eu.kanade.tachiyomi.util.hasCustomCover
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.getCoordinates
|
||||
import eu.kanade.tachiyomi.util.view.shrinkOnScroll
|
||||
import eu.kanade.tachiyomi.util.view.snack
|
||||
import kotlin.math.min
|
||||
import kotlinx.android.synthetic.main.main_activity.root_coordinator
|
||||
import kotlinx.android.synthetic.main.main_activity.toolbar
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -83,6 +82,7 @@ import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.math.min
|
||||
|
||||
class MangaController :
|
||||
NucleusController<MangaControllerBinding, MangaPresenter>,
|
||||
@@ -207,7 +207,6 @@ class MangaController :
|
||||
|
||||
binding.recycler.adapter = ConcatAdapter(mangaInfoAdapter, chaptersHeaderAdapter, chaptersAdapter)
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.addItemDecoration(ChapterDividerItemDecoration(view.context))
|
||||
binding.recycler.setHasFixedSize(true)
|
||||
chaptersAdapter?.fastScroller = binding.fastScroller
|
||||
|
||||
@@ -238,7 +237,7 @@ class MangaController :
|
||||
|
||||
binding.actionToolbar.offsetAppbarHeight(activity!!)
|
||||
|
||||
settingsSheet = ChaptersSettingsSheet(activity!!, presenter) { group ->
|
||||
settingsSheet = ChaptersSettingsSheet(router, presenter) { group ->
|
||||
if (group is ChaptersSettingsSheet.Filter.FilterGroup) {
|
||||
updateFilterIconState()
|
||||
chaptersAdapter?.notifyDataSetChanged()
|
||||
@@ -292,10 +291,10 @@ class MangaController :
|
||||
// Get coordinates and start animation
|
||||
actionFab?.getCoordinates()?.let { coordinates ->
|
||||
if (!binding.revealView.showRevealEffect(
|
||||
coordinates.x,
|
||||
coordinates.y,
|
||||
revealAnimationListener
|
||||
)
|
||||
coordinates.x,
|
||||
coordinates.y,
|
||||
revealAnimationListener
|
||||
)
|
||||
) {
|
||||
openChapter(item.chapter)
|
||||
}
|
||||
@@ -343,7 +342,8 @@ class MangaController :
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
// Hide download options for local manga
|
||||
// Hide options for local manga
|
||||
menu.findItem(R.id.action_share).isVisible = !isLocalSource
|
||||
menu.findItem(R.id.download_group).isVisible = !isLocalSource
|
||||
|
||||
// Hide options for non-library manga
|
||||
@@ -354,6 +354,7 @@ class MangaController :
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_share -> shareManga()
|
||||
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)
|
||||
@@ -694,7 +695,11 @@ class MangaController :
|
||||
fun onFetchChaptersError(error: Throwable) {
|
||||
isRefreshingChapters = false
|
||||
updateRefreshing()
|
||||
activity?.toast(error.message)
|
||||
if (error is NoChaptersException) {
|
||||
activity?.toast(activity?.getString(R.string.no_chapters_error))
|
||||
} else {
|
||||
activity?.toast(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
fun onChapterStatusChange(download: Download) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||
import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.isLocal
|
||||
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
||||
@@ -26,7 +27,6 @@ import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
||||
import java.util.Date
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@@ -34,6 +34,7 @@ import rx.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Date
|
||||
|
||||
class MangaPresenter(
|
||||
val manga: Manga,
|
||||
@@ -82,6 +83,10 @@ class MangaPresenter(
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
if (!manga.favorite) {
|
||||
ChapterSettingsHelper.applySettingDefaults(manga)
|
||||
}
|
||||
|
||||
// Manga info - start
|
||||
|
||||
getMangaObservable()
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.marginBottom
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
/**
|
||||
* Mimics a DividerItemDecoration that doesn't draw between the first two items.
|
||||
*
|
||||
* Used in MangaController since the manga info header and chapters header are the first two
|
||||
* items in the list using a ConcatAdapter.
|
||||
*/
|
||||
class ChapterDividerItemDecoration(context: Context) : RecyclerView.ItemDecoration() {
|
||||
|
||||
private val divider: Drawable
|
||||
|
||||
init {
|
||||
val a = context.obtainStyledAttributes(intArrayOf(android.R.attr.listDivider))
|
||||
divider = a.getDrawable(0)!!
|
||||
a.recycle()
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
||||
if (parent.layoutManager == null) {
|
||||
return
|
||||
}
|
||||
|
||||
canvas.save()
|
||||
parent.forEach {
|
||||
val top = it.bottom + it.marginBottom
|
||||
val bottom = top + divider.intrinsicHeight
|
||||
val left = parent.paddingStart
|
||||
val right = parent.width - parent.paddingEnd
|
||||
divider.setBounds(left, top, right, bottom)
|
||||
divider.draw(canvas)
|
||||
}
|
||||
canvas.restore()
|
||||
}
|
||||
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
val position = parent.getChildAdapterPosition(view)
|
||||
|
||||
if (position == 0) {
|
||||
outRect.setEmpty()
|
||||
} else {
|
||||
outRect.set(0, 0, 0, divider.intrinsicHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,11 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
import java.util.Date
|
||||
import kotlinx.android.synthetic.main.chapters_item.bookmark_icon
|
||||
import kotlinx.android.synthetic.main.chapters_item.chapter_description
|
||||
import kotlinx.android.synthetic.main.chapters_item.chapter_title
|
||||
import kotlinx.android.synthetic.main.chapters_item.download_text
|
||||
import java.util.Date
|
||||
|
||||
class ChapterHolder(
|
||||
view: View,
|
||||
|
||||
@@ -6,10 +6,10 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DateFormat
|
||||
import java.text.DecimalFormat
|
||||
import java.text.DecimalFormatSymbols
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class ChaptersAdapter(
|
||||
controller: MangaController,
|
||||
|
||||
@@ -1,34 +1,39 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaPresenter
|
||||
import eu.kanade.tachiyomi.util.view.popupMenu
|
||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
|
||||
|
||||
class ChaptersSettingsSheet(
|
||||
activity: Activity,
|
||||
private val router: Router,
|
||||
private val presenter: MangaPresenter,
|
||||
onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
|
||||
) : TabbedBottomSheetDialog(activity) {
|
||||
) : TabbedBottomSheetDialog(router) {
|
||||
|
||||
val filters: Filter
|
||||
private val sort: Sort
|
||||
private val display: Display
|
||||
|
||||
init {
|
||||
filters = Filter(activity)
|
||||
filters = Filter(router.activity!!)
|
||||
filters.onGroupClicked = onGroupClickListener
|
||||
|
||||
sort = Sort(activity)
|
||||
sort = Sort(router.activity!!)
|
||||
sort.onGroupClicked = onGroupClickListener
|
||||
|
||||
display = Display(activity)
|
||||
display = Display(router.activity!!)
|
||||
display.onGroupClicked = onGroupClickListener
|
||||
|
||||
binding.menu.isVisible = true
|
||||
binding.menu.setOnClickListener { it.post { showPopupMenu(it) } }
|
||||
}
|
||||
|
||||
override fun getTabViews(): List<View> = listOf(
|
||||
@@ -43,6 +48,23 @@ class ChaptersSettingsSheet(
|
||||
R.string.action_display
|
||||
)
|
||||
|
||||
private fun showPopupMenu(view: View) {
|
||||
view.popupMenu(
|
||||
R.menu.default_chapter_filter,
|
||||
{
|
||||
},
|
||||
{
|
||||
when (this.itemId) {
|
||||
R.id.set_as_default -> {
|
||||
SetChapterSettingsDialog(presenter.manga).showDialog(router)
|
||||
true
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters group (unread, downloaded, ...).
|
||||
*/
|
||||
|
||||
@@ -66,7 +66,7 @@ class MangaChaptersHeaderAdapter(
|
||||
} else {
|
||||
view.context.getResourceColor(R.attr.colorOnPrimary)
|
||||
}
|
||||
DrawableCompat.setTint(binding.btnChaptersFilter.icon, filterColor)
|
||||
DrawableCompat.setTint(binding.btnChaptersFilter.drawable, filterColor)
|
||||
|
||||
merge(view.clicks(), binding.btnChaptersFilter.clicks())
|
||||
.onEach { controller.showSettingsSheet() }
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.widget.DialogCheckboxView
|
||||
|
||||
class SetChapterSettingsDialog(bundle: Bundle? = null) : DialogController(bundle) {
|
||||
|
||||
constructor(manga: Manga) : this(
|
||||
Bundle().apply {
|
||||
putSerializable(MANGA_KEY, manga)
|
||||
}
|
||||
)
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val view = DialogCheckboxView(activity!!).apply {
|
||||
setDescription(R.string.confirm_set_chapter_settings)
|
||||
setOptionDescription(R.string.also_set_chapter_settings_for_library)
|
||||
}
|
||||
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.chapter_settings)
|
||||
.customView(
|
||||
view = view,
|
||||
horizontalPadding = true
|
||||
)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
ChapterSettingsHelper.setGlobalSettings(args.getSerializable(MANGA_KEY)!! as Manga)
|
||||
if (view.isChecked()) {
|
||||
ChapterSettingsHelper.updateAllMangasWithGlobalDefaults()
|
||||
}
|
||||
|
||||
activity?.toast(activity!!.getString(R.string.chapter_settings_updated))
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MANGA_KEY = "manga"
|
||||
}
|
||||
}
|
||||
@@ -105,13 +105,27 @@ class MangaInfoHeaderAdapter(
|
||||
isVisible = true
|
||||
|
||||
if (trackCount > 0) {
|
||||
setIconResource(R.drawable.ic_done_24dp)
|
||||
text = view.context.resources.getQuantityString(R.plurals.num_trackers, trackCount, trackCount)
|
||||
isChecked = true
|
||||
setCompoundDrawablesWithIntrinsicBounds(
|
||||
null,
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_done_24dp),
|
||||
null,
|
||||
null
|
||||
)
|
||||
text = view.context.resources.getQuantityString(
|
||||
R.plurals.num_trackers,
|
||||
trackCount,
|
||||
trackCount
|
||||
)
|
||||
isSelected = true
|
||||
} else {
|
||||
setIconResource(R.drawable.ic_sync_24dp)
|
||||
setCompoundDrawablesWithIntrinsicBounds(
|
||||
null,
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_sync_24dp),
|
||||
null,
|
||||
null
|
||||
)
|
||||
text = view.context.getString(R.string.manga_tracking_tab)
|
||||
isChecked = false
|
||||
isSelected = false
|
||||
}
|
||||
|
||||
clicks()
|
||||
@@ -128,12 +142,6 @@ class MangaInfoHeaderAdapter(
|
||||
.onEach { controller.openMangaInWebView() }
|
||||
.launchIn(scope)
|
||||
binding.btnWebview.setTooltip(R.string.action_open_in_web_view)
|
||||
|
||||
binding.btnShare.isVisible = true
|
||||
binding.btnShare.clicks()
|
||||
.onEach { controller.shareManga() }
|
||||
.launchIn(scope)
|
||||
binding.btnShare.setTooltip(R.string.action_share)
|
||||
}
|
||||
|
||||
binding.mangaFullTitle.longClicks()
|
||||
@@ -285,14 +293,24 @@ class MangaInfoHeaderAdapter(
|
||||
|
||||
// Update genres list
|
||||
if (!manga.genre.isNullOrBlank()) {
|
||||
binding.mangaGenresTagsCompactChips.setChips(manga.getGenres(), controller::performSearch)
|
||||
binding.mangaGenresTagsFullChips.setChips(manga.getGenres(), controller::performSearch)
|
||||
binding.mangaGenresTagsCompactChips.setChips(
|
||||
manga.getGenres(),
|
||||
controller::performSearch
|
||||
)
|
||||
binding.mangaGenresTagsFullChips.setChips(
|
||||
manga.getGenres(),
|
||||
controller::performSearch
|
||||
)
|
||||
} else {
|
||||
binding.mangaGenresTagsWrapper.isVisible = false
|
||||
}
|
||||
|
||||
// Handle showing more or less info
|
||||
merge(binding.mangaSummarySection.clicks(), binding.mangaSummaryText.clicks(), binding.mangaInfoToggle.clicks())
|
||||
merge(
|
||||
binding.mangaSummarySection.clicks(),
|
||||
binding.mangaSummaryText.clicks(),
|
||||
binding.mangaInfoToggle.clicks()
|
||||
)
|
||||
.onEach { toggleMangaInfo(view.context) }
|
||||
.launchIn(scope)
|
||||
|
||||
@@ -310,20 +328,22 @@ class MangaInfoHeaderAdapter(
|
||||
|
||||
private fun toggleMangaInfo(context: Context) {
|
||||
val isExpanded =
|
||||
binding.mangaInfoToggle.text == context.getString(R.string.manga_info_collapse)
|
||||
binding.mangaInfoToggle.contentDescription == context.getString(R.string.manga_info_collapse)
|
||||
|
||||
with(binding.mangaInfoToggle) {
|
||||
text = if (isExpanded) {
|
||||
contentDescription = if (isExpanded) {
|
||||
context.getString(R.string.manga_info_expand)
|
||||
} else {
|
||||
context.getString(R.string.manga_info_collapse)
|
||||
}
|
||||
|
||||
icon = if (isExpanded) {
|
||||
context.getDrawable(R.drawable.ic_baseline_expand_more_24dp)
|
||||
} else {
|
||||
context.getDrawable(R.drawable.ic_baseline_expand_less_24dp)
|
||||
}
|
||||
setImageDrawable(
|
||||
if (isExpanded) {
|
||||
context.getDrawable(R.drawable.ic_baseline_expand_more_24dp)
|
||||
} else {
|
||||
context.getDrawable(R.drawable.ic_baseline_expand_less_24dp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
with(binding.mangaSummaryText) {
|
||||
@@ -355,13 +375,18 @@ class MangaInfoHeaderAdapter(
|
||||
// Set the Favorite drawable to the correct one.
|
||||
// Border drawable if false, filled drawable if true.
|
||||
binding.btnFavorite.apply {
|
||||
icon = ContextCompat.getDrawable(
|
||||
context,
|
||||
if (isFavorite) R.drawable.ic_favorite_24dp else R.drawable.ic_favorite_border_24dp
|
||||
setCompoundDrawablesWithIntrinsicBounds(
|
||||
null,
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
if (isFavorite) R.drawable.ic_favorite_24dp else R.drawable.ic_favorite_border_24dp
|
||||
),
|
||||
null,
|
||||
null
|
||||
)
|
||||
text =
|
||||
context.getString(if (isFavorite) R.string.in_library else R.string.add_to_library)
|
||||
isChecked = isFavorite
|
||||
isSelected = isFavorite
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import java.util.Calendar
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Calendar
|
||||
|
||||
class SetTrackReadingDatesDialog<T> : DialogController
|
||||
where T : Controller, T : SetTrackReadingDatesDialog.Listener {
|
||||
|
||||
@@ -5,8 +5,8 @@ import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.TrackItemBinding
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseViewHolder
|
||||
import java.text.DateFormat
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DateFormat
|
||||
|
||||
class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter) : BaseViewHolder(binding.root) {
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlinx.android.synthetic.main.track_search_dialog.view.progress
|
||||
import kotlinx.android.synthetic.main.track_search_dialog.view.track_search
|
||||
import kotlinx.android.synthetic.main.track_search_dialog.view.track_search_list
|
||||
@@ -26,6 +25,7 @@ import reactivecircus.flowbinding.android.widget.itemClicks
|
||||
import reactivecircus.flowbinding.android.widget.textChanges
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class TrackSearchDialog : DialogController {
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.updater.UpdateChecker
|
||||
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
||||
import eu.kanade.tachiyomi.data.updater.UpdaterService
|
||||
import eu.kanade.tachiyomi.data.updater.github.GithubUpdateChecker
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
||||
import eu.kanade.tachiyomi.util.lang.launchNow
|
||||
@@ -23,19 +23,19 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import timber.log.Timber
|
||||
import java.text.DateFormat
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import timber.log.Timber
|
||||
|
||||
class AboutController : SettingsController() {
|
||||
|
||||
/**
|
||||
* Checks for new releases
|
||||
*/
|
||||
private val updateChecker by lazy { UpdateChecker.getUpdateChecker() }
|
||||
private val updateChecker by lazy { GithubUpdateChecker() }
|
||||
|
||||
private val dateFormat: DateFormat = preferences.dateFormat()
|
||||
|
||||
@@ -234,7 +234,9 @@ class AboutController : SettingsController() {
|
||||
val buildTime = inputDf.parse(BuildConfig.BUILD_TIME)
|
||||
|
||||
val outputDf = DateFormat.getDateTimeInstance(
|
||||
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault()
|
||||
DateFormat.MEDIUM,
|
||||
DateFormat.SHORT,
|
||||
Locale.getDefault()
|
||||
)
|
||||
outputDf.timeZone = TimeZone.getDefault()
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
@@ -28,6 +27,7 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class MoreController :
|
||||
SettingsController(),
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.view.animation.Animation
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.SeekBar
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.setPadding
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
@@ -56,8 +57,6 @@ import eu.kanade.tachiyomi.util.view.showBar
|
||||
import eu.kanade.tachiyomi.util.view.snack
|
||||
import eu.kanade.tachiyomi.widget.SimpleAnimationListener
|
||||
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
|
||||
import java.io.File
|
||||
import kotlin.math.abs
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.drop
|
||||
@@ -67,6 +66,8 @@ import kotlinx.coroutines.flow.sample
|
||||
import nucleus.factory.RequiresPresenter
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
* Activity containing the reader of Tachiyomi. This activity is mostly a container of the
|
||||
@@ -290,24 +291,27 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.readerMenu) { _, insets ->
|
||||
if (!window.isDefaultBar()) {
|
||||
val systemInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
binding.readerMenu.setPadding(
|
||||
insets.systemWindowInsetLeft,
|
||||
insets.systemWindowInsetTop,
|
||||
insets.systemWindowInsetRight,
|
||||
insets.systemWindowInsetBottom
|
||||
systemInsets.left,
|
||||
systemInsets.top,
|
||||
systemInsets.right,
|
||||
systemInsets.bottom
|
||||
)
|
||||
}
|
||||
insets
|
||||
}
|
||||
|
||||
// Init listeners on bottom menu
|
||||
binding.pageSeekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (viewer != null && fromUser) {
|
||||
moveToPageIndex(value)
|
||||
binding.pageSeekbar.setOnSeekBarChangeListener(
|
||||
object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (viewer != null && fromUser) {
|
||||
moveToPageIndex(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
binding.leftChapter.setOnClickListener {
|
||||
if (viewer != null) {
|
||||
if (viewer is R2LPagerViewer) {
|
||||
@@ -347,12 +351,14 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
||||
|
||||
if (animate) {
|
||||
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top)
|
||||
toolbarAnimation.setAnimationListener(object : SimpleAnimationListener() {
|
||||
override fun onAnimationStart(animation: Animation) {
|
||||
// Fix status bar being translucent the first time it's opened.
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||
toolbarAnimation.setAnimationListener(
|
||||
object : SimpleAnimationListener() {
|
||||
override fun onAnimationStart(animation: Animation) {
|
||||
// Fix status bar being translucent the first time it's opened.
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
binding.toolbar.startAnimation(toolbarAnimation)
|
||||
|
||||
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_bottom)
|
||||
@@ -371,11 +377,13 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
||||
|
||||
if (animate) {
|
||||
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_top)
|
||||
toolbarAnimation.setAnimationListener(object : SimpleAnimationListener() {
|
||||
override fun onAnimationEnd(animation: Animation) {
|
||||
binding.readerMenu.isVisible = false
|
||||
toolbarAnimation.setAnimationListener(
|
||||
object : SimpleAnimationListener() {
|
||||
override fun onAnimationEnd(animation: Animation) {
|
||||
binding.readerMenu.isVisible = false
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
binding.toolbar.startAnimation(toolbarAnimation)
|
||||
|
||||
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_bottom)
|
||||
@@ -572,9 +580,13 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
||||
* Called from the presenter when a page is ready to be shared. It shows Android's default
|
||||
* sharing tool.
|
||||
*/
|
||||
fun onShareImageResult(file: File) {
|
||||
fun onShareImageResult(file: File, page: ReaderPage) {
|
||||
val manga = presenter.manga ?: return
|
||||
val chapter = page.chapter.chapter
|
||||
|
||||
val stream = file.getUriCompat(this)
|
||||
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||
putExtra(Intent.EXTRA_TEXT, getString(R.string.share_page_info, manga.title, chapter.name, page.number))
|
||||
putExtra(Intent.EXTRA_STREAM, stream)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
type = "image/*"
|
||||
|
||||
@@ -74,45 +74,55 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet
|
||||
}
|
||||
binding.colorFilterMode.setSelection(preferences.colorFilterMode().get(), false)
|
||||
|
||||
binding.seekbarColorFilterAlpha.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
setColorValue(value, ALPHA_MASK, 24)
|
||||
binding.seekbarColorFilterAlpha.setOnSeekBarChangeListener(
|
||||
object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
setColorValue(value, ALPHA_MASK, 24)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
binding.seekbarColorFilterRed.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
setColorValue(value, RED_MASK, 16)
|
||||
binding.seekbarColorFilterRed.setOnSeekBarChangeListener(
|
||||
object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
setColorValue(value, RED_MASK, 16)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
binding.seekbarColorFilterGreen.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
setColorValue(value, GREEN_MASK, 8)
|
||||
binding.seekbarColorFilterGreen.setOnSeekBarChangeListener(
|
||||
object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
setColorValue(value, GREEN_MASK, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
binding.seekbarColorFilterBlue.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
setColorValue(value, BLUE_MASK, 0)
|
||||
binding.seekbarColorFilterBlue.setOnSeekBarChangeListener(
|
||||
object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
setColorValue(value, BLUE_MASK, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
binding.brightnessSeekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
preferences.customBrightnessValue().set(value)
|
||||
binding.brightnessSeekbar.setOnSeekBarChangeListener(
|
||||
object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
preferences.customBrightnessValue().set(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
||||
@@ -27,9 +27,6 @@ import eu.kanade.tachiyomi.util.lang.takeBytes
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
||||
import java.io.File
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
import rx.Completable
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
@@ -38,6 +35,9 @@ import rx.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Presenter used by the activity to perform background operations.
|
||||
@@ -569,7 +569,7 @@ class ReaderPresenter(
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
{ view, file -> view.onShareImageResult(file) },
|
||||
{ view, file -> view.onShareImageResult(file, page) },
|
||||
{ _, _ -> /* Empty */ }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import rx.Observable
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import rx.Observable
|
||||
|
||||
/**
|
||||
* Loader used to load a chapter from a directory given on [file].
|
||||
|
||||
@@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.ui.reader.loader
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.util.storage.EpubFile
|
||||
import java.io.File
|
||||
import rx.Observable
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Loader used to load a chapter from a .epub file.
|
||||
|
||||
@@ -6,9 +6,6 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.util.lang.plusAssign
|
||||
import java.util.concurrent.PriorityBlockingQueue
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.math.min
|
||||
import rx.Completable
|
||||
import rx.Observable
|
||||
import rx.schedulers.Schedulers
|
||||
@@ -18,6 +15,9 @@ import rx.subscriptions.CompositeSubscription
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.concurrent.PriorityBlockingQueue
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Loader used to load chapters from an online source.
|
||||
|
||||
@@ -4,14 +4,14 @@ import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import junrar.Archive
|
||||
import junrar.rarfile.FileHeader
|
||||
import rx.Observable
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.PipedInputStream
|
||||
import java.io.PipedOutputStream
|
||||
import java.util.concurrent.Executors
|
||||
import junrar.Archive
|
||||
import junrar.rarfile.FileHeader
|
||||
import rx.Observable
|
||||
|
||||
/**
|
||||
* Loader used to load a chapter from a .rar or .cbr file.
|
||||
|
||||
@@ -5,11 +5,11 @@ import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import rx.Observable
|
||||
import java.io.File
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import rx.Observable
|
||||
|
||||
/**
|
||||
* Loader used to load a chapter from a .zip or .cbz file.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import kotlin.math.floor
|
||||
|
||||
object MissingChapters {
|
||||
|
||||
fun hasMissingChapters(higher: Chapter, lower: Chapter): Boolean {
|
||||
return hasMissingChapters(higher.chapter_number, lower.chapter_number)
|
||||
}
|
||||
|
||||
fun hasMissingChapters(higherChapterNumber: Float, lowerChapterNumber: Float): Boolean {
|
||||
return floor(higherChapterNumber) - floor(lowerChapterNumber) - 1f > 0f
|
||||
}
|
||||
}
|
||||
@@ -63,9 +63,12 @@ class ReaderProgressBar @JvmOverloads constructor(
|
||||
*/
|
||||
private val rotationAnimation by lazy {
|
||||
RotateAnimation(
|
||||
0f, 360f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f
|
||||
0f,
|
||||
360f,
|
||||
Animation.RELATIVE_TO_SELF,
|
||||
0.5f,
|
||||
Animation.RELATIVE_TO_SELF,
|
||||
0.5f
|
||||
).apply {
|
||||
interpolator = LinearInterpolator()
|
||||
repeatCount = Animation.INFINITE
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.text.bold
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import kotlinx.android.synthetic.main.reader_transition_view.view.lower_text
|
||||
import kotlinx.android.synthetic.main.reader_transition_view.view.upper_text
|
||||
import kotlinx.android.synthetic.main.reader_transition_view.view.warning
|
||||
import kotlinx.android.synthetic.main.reader_transition_view.view.warning_text
|
||||
import kotlin.math.floor
|
||||
|
||||
class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
LinearLayout(context, attrs) {
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.reader_transition_view, this)
|
||||
}
|
||||
|
||||
fun bind(transition: ChapterTransition) {
|
||||
when (transition) {
|
||||
is ChapterTransition.Prev -> bindPrevChapterTransition(transition)
|
||||
is ChapterTransition.Next -> bindNextChapterTransition(transition)
|
||||
}
|
||||
|
||||
missingChapterWarning(transition)
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a previous chapter transition on this view and subscribes to the page load status.
|
||||
*/
|
||||
private fun bindPrevChapterTransition(transition: ChapterTransition) {
|
||||
val prevChapter = transition.to
|
||||
|
||||
val hasPrevChapter = prevChapter != null
|
||||
lower_text.isVisible = hasPrevChapter
|
||||
if (hasPrevChapter) {
|
||||
upper_text.textAlignment = TEXT_ALIGNMENT_TEXT_START
|
||||
upper_text.text = buildSpannedString {
|
||||
bold { append(context.getString(R.string.transition_current)) }
|
||||
append("\n${transition.from.chapter.name}")
|
||||
}
|
||||
lower_text.text = buildSpannedString {
|
||||
bold { append(context.getString(R.string.transition_previous)) }
|
||||
append("\n${prevChapter!!.chapter.name}")
|
||||
}
|
||||
} else {
|
||||
upper_text.textAlignment = TEXT_ALIGNMENT_CENTER
|
||||
upper_text.text = context.getString(R.string.transition_no_previous)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a next chapter transition on this view and subscribes to the load status.
|
||||
*/
|
||||
private fun bindNextChapterTransition(transition: ChapterTransition) {
|
||||
val nextChapter = transition.to
|
||||
|
||||
val hasNextChapter = nextChapter != null
|
||||
lower_text.isVisible = hasNextChapter
|
||||
if (hasNextChapter) {
|
||||
upper_text.textAlignment = TEXT_ALIGNMENT_TEXT_START
|
||||
upper_text.text = buildSpannedString {
|
||||
bold { append(context.getString(R.string.transition_finished)) }
|
||||
append("\n${transition.from.chapter.name}")
|
||||
}
|
||||
lower_text.text = buildSpannedString {
|
||||
bold { append(context.getString(R.string.transition_next)) }
|
||||
append("\n${nextChapter!!.chapter.name}")
|
||||
}
|
||||
} else {
|
||||
upper_text.textAlignment = TEXT_ALIGNMENT_CENTER
|
||||
upper_text.text = context.getString(R.string.transition_no_next)
|
||||
}
|
||||
}
|
||||
|
||||
private fun missingChapterWarning(transition: ChapterTransition) {
|
||||
if (transition.to == null) {
|
||||
warning.isVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
val fromChapterNumber: Float = floor(transition.from.chapter.chapter_number)
|
||||
val toChapterNumber: Float = floor(transition.to!!.chapter.chapter_number)
|
||||
|
||||
val chapterDifference = when (transition) {
|
||||
is ChapterTransition.Prev -> fromChapterNumber - toChapterNumber - 1f
|
||||
is ChapterTransition.Next -> toChapterNumber - fromChapterNumber - 1f
|
||||
}
|
||||
|
||||
val hasMissingChapters = when (transition) {
|
||||
is ChapterTransition.Prev -> MissingChapters.hasMissingChapters(fromChapterNumber, toChapterNumber)
|
||||
is ChapterTransition.Next -> MissingChapters.hasMissingChapters(toChapterNumber, fromChapterNumber)
|
||||
}
|
||||
|
||||
warning_text.text = resources.getQuantityString(R.plurals.missing_chapters_warning, chapterDifference.toInt(), chapterDifference.toInt())
|
||||
warning.isVisible = hasMissingChapters
|
||||
}
|
||||
}
|
||||
@@ -35,12 +35,12 @@ import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||
import java.io.InputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import java.io.InputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* View of the ViewPager that contains a page of a chapter.
|
||||
@@ -307,20 +307,22 @@ class PagerPageHolder(
|
||||
setMinimumDpi(90)
|
||||
setMinimumTileDpi(180)
|
||||
setCropBorders(config.imageCropBorders)
|
||||
setOnImageEventListener(object : SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||
override fun onReady() {
|
||||
when (config.imageZoomType) {
|
||||
ZoomType.Left -> setScaleAndCenter(scale, PointF(0f, 0f))
|
||||
ZoomType.Right -> setScaleAndCenter(scale, PointF(sWidth.toFloat(), 0f))
|
||||
ZoomType.Center -> setScaleAndCenter(scale, center.also { it?.y = 0f })
|
||||
setOnImageEventListener(
|
||||
object : SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||
override fun onReady() {
|
||||
when (config.imageZoomType) {
|
||||
ZoomType.Left -> setScaleAndCenter(scale, PointF(0f, 0f))
|
||||
ZoomType.Right -> setScaleAndCenter(scale, PointF(sWidth.toFloat(), 0f))
|
||||
ZoomType.Center -> setScaleAndCenter(scale, center.also { it?.y = 0f })
|
||||
}
|
||||
onImageDecoded()
|
||||
}
|
||||
onImageDecoded()
|
||||
}
|
||||
|
||||
override fun onImageLoadError(e: Exception) {
|
||||
onImageDecodeError()
|
||||
override fun onImageLoadError(e: Exception) {
|
||||
onImageDecodeError()
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
addView(subsamplingImageView)
|
||||
return subsamplingImageView!!
|
||||
@@ -338,16 +340,18 @@ class PagerPageHolder(
|
||||
setZoomTransitionDuration(viewer.config.doubleTapAnimDuration)
|
||||
setScaleLevels(1f, 2f, 3f)
|
||||
// Force 2 scale levels on double tap
|
||||
setOnDoubleTapListener(object : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
if (scale > 1f) {
|
||||
setScale(1f, e.x, e.y, true)
|
||||
} else {
|
||||
setScale(2f, e.x, e.y, true)
|
||||
setOnDoubleTapListener(
|
||||
object : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
if (scale > 1f) {
|
||||
setScale(1f, e.x, e.y, true)
|
||||
} else {
|
||||
setScale(2f, e.x, e.y, true)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
addView(imageView)
|
||||
return imageView!!
|
||||
@@ -437,31 +441,33 @@ class PagerPageHolder(
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.transition(DrawableTransitionOptions.with(NoTransition.getFactory()))
|
||||
.listener(object : RequestListener<Drawable> {
|
||||
override fun onLoadFailed(
|
||||
e: GlideException?,
|
||||
model: Any?,
|
||||
target: Target<Drawable>?,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
onImageDecodeError()
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onResourceReady(
|
||||
resource: Drawable?,
|
||||
model: Any?,
|
||||
target: Target<Drawable>?,
|
||||
dataSource: DataSource?,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
if (resource is GifDrawable) {
|
||||
resource.setLoopCount(GifDrawable.LOOP_INTRINSIC)
|
||||
.listener(
|
||||
object : RequestListener<Drawable> {
|
||||
override fun onLoadFailed(
|
||||
e: GlideException?,
|
||||
model: Any?,
|
||||
target: Target<Drawable>?,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
onImageDecodeError()
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onResourceReady(
|
||||
resource: Drawable?,
|
||||
model: Any?,
|
||||
target: Target<Drawable>?,
|
||||
dataSource: DataSource?,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
if (resource is GifDrawable) {
|
||||
resource.setLoopCount(GifDrawable.LOOP_INTRINSIC)
|
||||
}
|
||||
onImageDecoded()
|
||||
return false
|
||||
}
|
||||
onImageDecoded()
|
||||
return false
|
||||
}
|
||||
})
|
||||
)
|
||||
.into(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,11 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.core.text.bold
|
||||
import androidx.core.text.buildSpannedString
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderTransitionView
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||
import rx.Subscription
|
||||
@@ -40,14 +38,6 @@ class PagerTransitionHolder(
|
||||
*/
|
||||
private var statusSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* Text view used to display the text of the current and next/prev chapters.
|
||||
*/
|
||||
private var textView = TextView(context).apply {
|
||||
textSize = 17.5F
|
||||
wrapContent()
|
||||
}
|
||||
|
||||
/**
|
||||
* View container of the current status of the transition page. Child views will be added
|
||||
* dynamically.
|
||||
@@ -63,13 +53,14 @@ class PagerTransitionHolder(
|
||||
gravity = Gravity.CENTER
|
||||
val sidePadding = 64.dpToPx
|
||||
setPadding(sidePadding, 0, sidePadding, 0)
|
||||
addView(textView)
|
||||
|
||||
val transitionView = ReaderTransitionView(context)
|
||||
addView(transitionView)
|
||||
addView(pagesContainer)
|
||||
|
||||
when (transition) {
|
||||
is ChapterTransition.Prev -> bindPrevChapterTransition()
|
||||
is ChapterTransition.Next -> bindNextChapterTransition()
|
||||
}
|
||||
transitionView.bind(transition)
|
||||
|
||||
transition.to?.let { observeStatus(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,50 +72,6 @@ class PagerTransitionHolder(
|
||||
statusSubscription = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a next chapter transition on this view and subscribes to the load status.
|
||||
*/
|
||||
private fun bindNextChapterTransition() {
|
||||
val nextChapter = transition.to
|
||||
|
||||
textView.text = if (nextChapter != null) {
|
||||
buildSpannedString {
|
||||
bold { append(context.getString(R.string.transition_finished)) }
|
||||
append("\n${transition.from.chapter.name}\n\n")
|
||||
bold { append(context.getString(R.string.transition_next)) }
|
||||
append("\n${nextChapter.chapter.name}\n\n")
|
||||
}
|
||||
} else {
|
||||
context.getString(R.string.transition_no_next)
|
||||
}
|
||||
|
||||
if (nextChapter != null) {
|
||||
observeStatus(nextChapter)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a previous chapter transition on this view and subscribes to the page load status.
|
||||
*/
|
||||
private fun bindPrevChapterTransition() {
|
||||
val prevChapter = transition.to
|
||||
|
||||
textView.text = if (prevChapter != null) {
|
||||
buildSpannedString {
|
||||
bold { append(context.getString(R.string.transition_current)) }
|
||||
append("\n${transition.from.chapter.name}\n\n")
|
||||
bold { append(context.getString(R.string.transition_previous)) }
|
||||
append("\n${prevChapter.chapter.name}\n\n")
|
||||
}
|
||||
} else {
|
||||
context.getString(R.string.transition_no_previous)
|
||||
}
|
||||
|
||||
if (prevChapter != null) {
|
||||
observeStatus(prevChapter)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Observes the status of the page list of the next/previous chapter. Whenever there's a new
|
||||
* state, the pages container is cleaned up before setting the new state.
|
||||
|
||||
@@ -71,15 +71,17 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
pager.offscreenPageLimit = 1
|
||||
pager.id = R.id.reader_pager
|
||||
pager.adapter = adapter
|
||||
pager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
onPageChange(position)
|
||||
}
|
||||
pager.addOnPageChangeListener(
|
||||
object : ViewPager.SimpleOnPageChangeListener() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
onPageChange(position)
|
||||
}
|
||||
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
isIdle = state == ViewPager.SCROLL_STATE_IDLE
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
isIdle = state == ViewPager.SCROLL_STATE_IDLE
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
pager.tapListener = f@{ event ->
|
||||
if (!config.tappingEnabled) {
|
||||
activity.toggleMenu()
|
||||
|
||||
@@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.MissingChapters
|
||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||
import timber.log.Timber
|
||||
|
||||
@@ -33,6 +34,10 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
|
||||
fun setChapters(chapters: ViewerChapters, forceTransition: Boolean) {
|
||||
val newItems = mutableListOf<Any>()
|
||||
|
||||
// Forces chapter transition if there is missing chapters
|
||||
val prevHasMissingChapters = if (chapters.prevChapter != null) MissingChapters.hasMissingChapters(chapters.currChapter.chapter, chapters.prevChapter.chapter) else false
|
||||
val nextHasMissingChapters = if (chapters.nextChapter != null) MissingChapters.hasMissingChapters(chapters.nextChapter.chapter, chapters.currChapter.chapter) else false
|
||||
|
||||
// Add previous chapter pages and transition.
|
||||
if (chapters.prevChapter != null) {
|
||||
// We only need to add the last few pages of the previous chapter, because it'll be
|
||||
@@ -44,7 +49,7 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
|
||||
}
|
||||
|
||||
// Skip transition page if the chapter is loaded & current page is not a transition page
|
||||
if (forceTransition || chapters.prevChapter?.state !is ReaderChapter.State.Loaded) {
|
||||
if (prevHasMissingChapters || forceTransition || chapters.prevChapter?.state !is ReaderChapter.State.Loaded) {
|
||||
newItems.add(ChapterTransition.Prev(chapters.currChapter, chapters.prevChapter))
|
||||
}
|
||||
|
||||
@@ -59,7 +64,7 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
|
||||
// Add next chapter transition and pages.
|
||||
nextTransition = ChapterTransition.Next(chapters.currChapter, chapters.nextChapter)
|
||||
.also {
|
||||
if (forceTransition ||
|
||||
if (nextHasMissingChapters || forceTransition ||
|
||||
chapters.nextChapter?.state !is ReaderChapter.State.Loaded
|
||||
) {
|
||||
newItems.add(it)
|
||||
|
||||
@@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.MissingChapters
|
||||
|
||||
/**
|
||||
* RecyclerView Adapter used by this [viewer] to where [ViewerChapters] updates are posted.
|
||||
@@ -29,6 +30,10 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter<RecyclerV
|
||||
fun setChapters(chapters: ViewerChapters, forceTransition: Boolean) {
|
||||
val newItems = mutableListOf<Any>()
|
||||
|
||||
// Forces chapter transition if there is missing chapters
|
||||
val prevHasMissingChapters = if (chapters.prevChapter != null) MissingChapters.hasMissingChapters(chapters.currChapter.chapter, chapters.prevChapter.chapter) else false
|
||||
val nextHasMissingChapters = if (chapters.nextChapter != null) MissingChapters.hasMissingChapters(chapters.nextChapter.chapter, chapters.currChapter.chapter) else false
|
||||
|
||||
// Add previous chapter pages and transition.
|
||||
if (chapters.prevChapter != null) {
|
||||
// We only need to add the last few pages of the previous chapter, because it'll be
|
||||
@@ -40,7 +45,7 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter<RecyclerV
|
||||
}
|
||||
|
||||
// Skip transition page if the chapter is loaded & current page is not a transition page
|
||||
if (forceTransition || chapters.prevChapter?.state !is ReaderChapter.State.Loaded) {
|
||||
if (prevHasMissingChapters || forceTransition || chapters.prevChapter?.state !is ReaderChapter.State.Loaded) {
|
||||
newItems.add(ChapterTransition.Prev(chapters.currChapter, chapters.prevChapter))
|
||||
}
|
||||
|
||||
@@ -53,7 +58,7 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter<RecyclerV
|
||||
currentChapter = chapters.currChapter
|
||||
|
||||
// Add next chapter transition and pages.
|
||||
if (forceTransition || chapters.nextChapter?.state !is ReaderChapter.State.Loaded) {
|
||||
if (nextHasMissingChapters || forceTransition || chapters.nextChapter?.state !is ReaderChapter.State.Loaded) {
|
||||
newItems.add(ChapterTransition.Next(chapters.currChapter, chapters.nextChapter))
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,12 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressBar
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import java.io.InputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import java.io.InputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Holder of the webtoon reader for a single page of a chapter.
|
||||
@@ -362,15 +362,17 @@ class WebtoonPageHolder(
|
||||
setMinimumDpi(90)
|
||||
setMinimumTileDpi(180)
|
||||
setCropBorders(config.imageCropBorders)
|
||||
setOnImageEventListener(object : SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||
override fun onReady() {
|
||||
onImageDecoded()
|
||||
}
|
||||
setOnImageEventListener(
|
||||
object : SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||
override fun onReady() {
|
||||
onImageDecoded()
|
||||
}
|
||||
|
||||
override fun onImageLoadError(e: Exception) {
|
||||
onImageDecodeError()
|
||||
override fun onImageLoadError(e: Exception) {
|
||||
onImageDecodeError()
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
frame.addView(subsamplingImageView, MATCH_PARENT, MATCH_PARENT)
|
||||
return subsamplingImageView!!
|
||||
@@ -492,31 +494,33 @@ class WebtoonPageHolder(
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.transition(DrawableTransitionOptions.with(NoTransition.getFactory()))
|
||||
.listener(object : RequestListener<Drawable> {
|
||||
override fun onLoadFailed(
|
||||
e: GlideException?,
|
||||
model: Any?,
|
||||
target: Target<Drawable>?,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
onImageDecodeError()
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onResourceReady(
|
||||
resource: Drawable?,
|
||||
model: Any?,
|
||||
target: Target<Drawable>?,
|
||||
dataSource: DataSource?,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
if (resource is GifDrawable) {
|
||||
resource.setLoopCount(GifDrawable.LOOP_INTRINSIC)
|
||||
.listener(
|
||||
object : RequestListener<Drawable> {
|
||||
override fun onLoadFailed(
|
||||
e: GlideException?,
|
||||
model: Any?,
|
||||
target: Target<Drawable>?,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
onImageDecodeError()
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onResourceReady(
|
||||
resource: Drawable?,
|
||||
model: Any?,
|
||||
target: Target<Drawable>?,
|
||||
dataSource: DataSource?,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
if (resource is GifDrawable) {
|
||||
resource.setLoopCount(GifDrawable.LOOP_INTRINSIC)
|
||||
}
|
||||
onImageDecoded()
|
||||
return false
|
||||
}
|
||||
onImageDecoded()
|
||||
return false
|
||||
}
|
||||
})
|
||||
)
|
||||
.into(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,16 +5,14 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.core.text.bold
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.view.isNotEmpty
|
||||
import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderTransitionView
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@@ -32,13 +30,7 @@ class WebtoonTransitionHolder(
|
||||
*/
|
||||
private var statusSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* Text view used to display the text of the current and next/prev chapters.
|
||||
*/
|
||||
private var textView = TextView(context).apply {
|
||||
textSize = 17.5F
|
||||
wrapContent()
|
||||
}
|
||||
private val transitionView = ReaderTransitionView(context)
|
||||
|
||||
/**
|
||||
* View container of the current status of the transition page. Child views will be added
|
||||
@@ -63,7 +55,7 @@ class WebtoonTransitionHolder(
|
||||
setMargins(0, childMargins, 0, childMargins)
|
||||
}
|
||||
|
||||
layout.addView(textView, childParams)
|
||||
layout.addView(transitionView)
|
||||
layout.addView(pagesContainer, childParams)
|
||||
}
|
||||
|
||||
@@ -71,10 +63,9 @@ class WebtoonTransitionHolder(
|
||||
* Binds the given [transition] with this view holder, subscribing to its state.
|
||||
*/
|
||||
fun bind(transition: ChapterTransition) {
|
||||
when (transition) {
|
||||
is ChapterTransition.Prev -> bindPrevChapterTransition(transition)
|
||||
is ChapterTransition.Next -> bindNextChapterTransition(transition)
|
||||
}
|
||||
transitionView.bind(transition)
|
||||
|
||||
transition.to?.let { observeStatus(it, transition) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,50 +75,6 @@ class WebtoonTransitionHolder(
|
||||
unsubscribeStatus()
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a next chapter transition on this view and subscribes to the load status.
|
||||
*/
|
||||
private fun bindNextChapterTransition(transition: ChapterTransition.Next) {
|
||||
val nextChapter = transition.to
|
||||
|
||||
textView.text = if (nextChapter != null) {
|
||||
buildSpannedString {
|
||||
bold { append(context.getString(R.string.transition_finished)) }
|
||||
append("\n${transition.from.chapter.name}\n\n")
|
||||
bold { append(context.getString(R.string.transition_next)) }
|
||||
append("\n${nextChapter.chapter.name}\n\n")
|
||||
}
|
||||
} else {
|
||||
context.getString(R.string.transition_no_next)
|
||||
}
|
||||
|
||||
if (nextChapter != null) {
|
||||
observeStatus(nextChapter, transition)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a previous chapter transition on this view and subscribes to the page load status.
|
||||
*/
|
||||
private fun bindPrevChapterTransition(transition: ChapterTransition.Prev) {
|
||||
val prevChapter = transition.to
|
||||
|
||||
textView.text = if (prevChapter != null) {
|
||||
buildSpannedString {
|
||||
bold { append(context.getString(R.string.transition_current)) }
|
||||
append("\n${transition.from.chapter.name}\n\n")
|
||||
bold { append(context.getString(R.string.transition_previous)) }
|
||||
append("\n${prevChapter.chapter.name}\n\n")
|
||||
}
|
||||
} else {
|
||||
context.getString(R.string.transition_no_previous)
|
||||
}
|
||||
|
||||
if (prevChapter != null) {
|
||||
observeStatus(prevChapter, transition)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Observes the status of the page list of the next/previous chapter. Whenever there's a new
|
||||
* state, the pages container is cleaned up before setting the new state.
|
||||
|
||||
@@ -15,10 +15,10 @@ import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import rx.subscriptions.CompositeSubscription
|
||||
import timber.log.Timber
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Implementation of a [BaseViewer] to display pages with a [RecyclerView].
|
||||
@@ -71,28 +71,30 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
recycler.itemAnimator = null
|
||||
recycler.layoutManager = layoutManager
|
||||
recycler.adapter = adapter
|
||||
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
val position = layoutManager.findLastEndVisibleItemPosition()
|
||||
val item = adapter.items.getOrNull(position)
|
||||
val allowPreload = checkAllowPreload(item as? ReaderPage)
|
||||
if (item != null && currentPage != item) {
|
||||
currentPage = item
|
||||
when (item) {
|
||||
is ReaderPage -> onPageSelected(item, allowPreload)
|
||||
is ChapterTransition -> onTransitionSelected(item)
|
||||
recycler.addOnScrollListener(
|
||||
object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
val position = layoutManager.findLastEndVisibleItemPosition()
|
||||
val item = adapter.items.getOrNull(position)
|
||||
val allowPreload = checkAllowPreload(item as? ReaderPage)
|
||||
if (item != null && currentPage != item) {
|
||||
currentPage = item
|
||||
when (item) {
|
||||
is ReaderPage -> onPageSelected(item, allowPreload)
|
||||
is ChapterTransition -> onTransitionSelected(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dy < 0) {
|
||||
val firstIndex = layoutManager.findFirstVisibleItemPosition()
|
||||
val firstItem = adapter.items.getOrNull(firstIndex)
|
||||
if (firstItem is ChapterTransition.Prev && firstItem.to != null) {
|
||||
activity.requestPreloadChapter(firstItem.to)
|
||||
if (dy < 0) {
|
||||
val firstIndex = layoutManager.findFirstVisibleItemPosition()
|
||||
val firstItem = adapter.items.getOrNull(firstIndex)
|
||||
if (firstItem is ChapterTransition.Prev && firstItem.to != null) {
|
||||
activity.requestPreloadChapter(firstItem.to)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
recycler.tapListener = f@{ event ->
|
||||
if (!config.tappingEnabled) {
|
||||
activity.toggleMenu()
|
||||
|
||||
@@ -2,9 +2,9 @@ package eu.kanade.tachiyomi.ui.recent.history
|
||||
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DecimalFormat
|
||||
import java.text.DecimalFormatSymbols
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
/**
|
||||
* Adapter of HistoryHolder.
|
||||
|
||||
@@ -8,13 +8,13 @@ import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.util.lang.toTimestampString
|
||||
import java.util.Date
|
||||
import kotlinx.android.synthetic.main.history_item.cover
|
||||
import kotlinx.android.synthetic.main.history_item.holder
|
||||
import kotlinx.android.synthetic.main.history_item.manga_subtitle
|
||||
import kotlinx.android.synthetic.main.history_item.manga_title
|
||||
import kotlinx.android.synthetic.main.history_item.remove
|
||||
import kotlinx.android.synthetic.main.history_item.resume
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
* Holder that contains recent manga item
|
||||
|
||||
@@ -9,13 +9,13 @@ import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
||||
import eu.kanade.tachiyomi.util.lang.toDateKey
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Calendar
|
||||
import java.util.Comparator
|
||||
import java.util.Date
|
||||
import java.util.TreeMap
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
/**
|
||||
* Presenter of HistoryFragment.
|
||||
|
||||
@@ -8,7 +8,6 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
||||
@@ -89,7 +88,6 @@ class UpdatesController :
|
||||
// Init RecyclerView and adapter
|
||||
val layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.layoutManager = layoutManager
|
||||
binding.recycler.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL))
|
||||
binding.recycler.setHasFixedSize(true)
|
||||
adapter = UpdatesAdapter(this@UpdatesController)
|
||||
binding.recycler.adapter = adapter
|
||||
|
||||
@@ -10,15 +10,15 @@ import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
||||
import eu.kanade.tachiyomi.util.lang.toDateKey
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.TreeMap
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.TreeMap
|
||||
|
||||
class UpdatesPresenter(
|
||||
val preferences: PreferencesHelper = Injekt.get(),
|
||||
|
||||
@@ -5,9 +5,9 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Date
|
||||
import java.util.concurrent.Executors
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
/**
|
||||
* Blank activity with a BiometricPrompt.
|
||||
@@ -21,7 +21,8 @@ class BiometricUnlockActivity : AppCompatActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val biometricPrompt = BiometricPrompt(
|
||||
this, executor,
|
||||
this,
|
||||
executor,
|
||||
object : BiometricPrompt.AuthenticationCallback() {
|
||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||
super.onAuthenticationError(errorCode, errString)
|
||||
|
||||
@@ -6,10 +6,10 @@ import androidx.biometric.BiometricManager
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import java.util.Date
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Date
|
||||
|
||||
class SecureActivityDelegate(private val activity: FragmentActivity) {
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
@@ -31,6 +30,7 @@ import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsAdvancedController : SettingsController() {
|
||||
private val network: NetworkHelper by injectLazy()
|
||||
|
||||
@@ -19,7 +19,6 @@ import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
|
||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreValidator
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
|
||||
@@ -36,6 +35,7 @@ import eu.kanade.tachiyomi.util.system.getFilePicker
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsBackupController : SettingsController() {
|
||||
|
||||
@@ -92,9 +92,12 @@ class SettingsBackupController : SettingsController() {
|
||||
key = Keys.backupInterval
|
||||
titleRes = R.string.pref_backup_interval
|
||||
entriesRes = arrayOf(
|
||||
R.string.update_never, R.string.update_6hour,
|
||||
R.string.update_12hour, R.string.update_24hour,
|
||||
R.string.update_48hour, R.string.update_weekly
|
||||
R.string.update_never,
|
||||
R.string.update_6hour,
|
||||
R.string.update_12hour,
|
||||
R.string.update_24hour,
|
||||
R.string.update_48hour,
|
||||
R.string.update_weekly
|
||||
)
|
||||
entryValues = arrayOf("0", "6", "12", "24", "48", "168")
|
||||
defaultValue = "0"
|
||||
@@ -213,8 +216,11 @@ class SettingsBackupController : SettingsController() {
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val activity = activity!!
|
||||
val options = arrayOf(
|
||||
R.string.manga, R.string.categories, R.string.chapters,
|
||||
R.string.track, R.string.history
|
||||
R.string.manga,
|
||||
R.string.categories,
|
||||
R.string.chapters,
|
||||
R.string.track,
|
||||
R.string.history
|
||||
)
|
||||
.map { activity.getString(it) }
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@ package eu.kanade.tachiyomi.ui.setting
|
||||
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.onChange
|
||||
import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsBrowseController : SettingsController() {
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
@@ -29,12 +28,13 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.getFilePicker
|
||||
import java.io.File
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsDownloadController : SettingsController() {
|
||||
|
||||
@@ -76,8 +76,11 @@ class SettingsDownloadController : SettingsController() {
|
||||
key = Keys.removeAfterReadSlots
|
||||
titleRes = R.string.pref_remove_after_read
|
||||
entriesRes = arrayOf(
|
||||
R.string.disabled, R.string.last_read_chapter,
|
||||
R.string.second_to_last, R.string.third_to_last, R.string.fourth_to_last,
|
||||
R.string.disabled,
|
||||
R.string.last_read_chapter,
|
||||
R.string.second_to_last,
|
||||
R.string.third_to_last,
|
||||
R.string.fourth_to_last,
|
||||
R.string.fifth_to_last
|
||||
)
|
||||
entryValues = arrayOf("-1", "0", "1", "2", "3", "4")
|
||||
|
||||
@@ -5,8 +5,6 @@ import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.entriesRes
|
||||
@@ -19,8 +17,10 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import java.util.Date
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import java.util.Date
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||
|
||||
class SettingsGeneralController : SettingsController() {
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
@@ -35,6 +34,7 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsLibraryController : SettingsController() {
|
||||
|
||||
@@ -123,9 +123,14 @@ class SettingsLibraryController : SettingsController() {
|
||||
key = Keys.libraryUpdateInterval
|
||||
titleRes = R.string.pref_library_update_interval
|
||||
entriesRes = arrayOf(
|
||||
R.string.update_never, R.string.update_1hour,
|
||||
R.string.update_2hour, R.string.update_3hour, R.string.update_6hour,
|
||||
R.string.update_12hour, R.string.update_24hour, R.string.update_48hour
|
||||
R.string.update_never,
|
||||
R.string.update_1hour,
|
||||
R.string.update_2hour,
|
||||
R.string.update_3hour,
|
||||
R.string.update_6hour,
|
||||
R.string.update_12hour,
|
||||
R.string.update_24hour,
|
||||
R.string.update_48hour
|
||||
)
|
||||
entryValues = arrayOf("0", "1", "2", "3", "6", "12", "24", "48")
|
||||
defaultValue = "24"
|
||||
|
||||
@@ -2,14 +2,14 @@ package eu.kanade.tachiyomi.ui.setting
|
||||
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.entriesRes
|
||||
import eu.kanade.tachiyomi.util.preference.infoPreference
|
||||
import eu.kanade.tachiyomi.util.preference.listPreference
|
||||
import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||
|
||||
class SettingsParentalControlsController : SettingsController() {
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.setting
|
||||
import android.os.Build
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode
|
||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
@@ -16,6 +15,7 @@ import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsReaderController : SettingsController() {
|
||||
|
||||
@@ -26,8 +26,11 @@ class SettingsReaderController : SettingsController() {
|
||||
key = Keys.defaultViewer
|
||||
titleRes = R.string.pref_viewer_type
|
||||
entriesRes = arrayOf(
|
||||
R.string.left_to_right_viewer, R.string.right_to_left_viewer,
|
||||
R.string.vertical_viewer, R.string.webtoon_viewer, R.string.vertical_plus_viewer
|
||||
R.string.left_to_right_viewer,
|
||||
R.string.right_to_left_viewer,
|
||||
R.string.vertical_viewer,
|
||||
R.string.webtoon_viewer,
|
||||
R.string.vertical_plus_viewer
|
||||
)
|
||||
entryValues = arrayOf("1", "2", "3", "4", "5")
|
||||
defaultValue = "2"
|
||||
@@ -68,8 +71,10 @@ class SettingsReaderController : SettingsController() {
|
||||
key = Keys.rotation
|
||||
titleRes = R.string.pref_rotation_type
|
||||
entriesRes = arrayOf(
|
||||
R.string.rotation_free, R.string.rotation_lock,
|
||||
R.string.rotation_force_portrait, R.string.rotation_force_landscape
|
||||
R.string.rotation_free,
|
||||
R.string.rotation_lock,
|
||||
R.string.rotation_force_portrait,
|
||||
R.string.rotation_force_landscape
|
||||
)
|
||||
entryValues = arrayOf("1", "2", "3", "4")
|
||||
defaultValue = "1"
|
||||
@@ -136,9 +141,12 @@ class SettingsReaderController : SettingsController() {
|
||||
key = Keys.imageScaleType
|
||||
titleRes = R.string.pref_image_scale_type
|
||||
entriesRes = arrayOf(
|
||||
R.string.scale_type_fit_screen, R.string.scale_type_stretch,
|
||||
R.string.scale_type_fit_width, R.string.scale_type_fit_height,
|
||||
R.string.scale_type_original_size, R.string.scale_type_smart_fit
|
||||
R.string.scale_type_fit_screen,
|
||||
R.string.scale_type_stretch,
|
||||
R.string.scale_type_fit_width,
|
||||
R.string.scale_type_fit_height,
|
||||
R.string.scale_type_original_size,
|
||||
R.string.scale_type_smart_fit
|
||||
)
|
||||
entryValues = arrayOf("1", "2", "3", "4", "5", "6")
|
||||
defaultValue = "1"
|
||||
@@ -148,8 +156,10 @@ class SettingsReaderController : SettingsController() {
|
||||
key = Keys.zoomStart
|
||||
titleRes = R.string.pref_zoom_start
|
||||
entriesRes = arrayOf(
|
||||
R.string.zoom_start_automatic, R.string.zoom_start_left,
|
||||
R.string.zoom_start_right, R.string.zoom_start_center
|
||||
R.string.zoom_start_automatic,
|
||||
R.string.zoom_start_left,
|
||||
R.string.zoom_start_right,
|
||||
R.string.zoom_start_center
|
||||
)
|
||||
entryValues = arrayOf("1", "2", "3", "4")
|
||||
defaultValue = "1"
|
||||
|
||||
@@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.setting
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||
import eu.kanade.tachiyomi.util.preference.intListPreference
|
||||
@@ -11,6 +10,7 @@ import eu.kanade.tachiyomi.util.preference.summaryRes
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsSecurityController : SettingsController() {
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.content.Intent
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.track.anilist.AnilistApi
|
||||
@@ -23,6 +22,7 @@ import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.widget.preference.LoginPreference
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsTrackingController :
|
||||
SettingsController(),
|
||||
|
||||
Reference in New Issue
Block a user