More work on new manga controller
Synced download badge for chapters items with downloads Download arrow now pulses while it's downloading Started work on the filter/sort bottom sheet for chapters Expanding description
This commit is contained in:
parent
c3620b74f1
commit
d58923acbf
@ -294,4 +294,6 @@ class DownloadManager(val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addListener(listener: DownloadQueue.DownloadListener) = queue.addListener(listener)
|
||||||
|
fun removeListener(listener: DownloadQueue.DownloadListener) = queue.removeListener(listener)
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,27 @@ class Download(val source: HttpSource, val manga: Manga, val chapter: Chapter) {
|
|||||||
set(status) {
|
set(status) {
|
||||||
field = status
|
field = status
|
||||||
statusSubject?.onNext(this)
|
statusSubject?.onNext(this)
|
||||||
|
statusCallback?.invoke(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transient private var statusSubject: PublishSubject<Download>? = null
|
@Transient private var statusSubject: PublishSubject<Download>? = null
|
||||||
|
|
||||||
|
@Transient private var statusCallback: ((Download) -> Unit)? = null
|
||||||
|
|
||||||
|
val progress: Int
|
||||||
|
get() {
|
||||||
|
val pages = pages ?: return 0
|
||||||
|
return pages.map(Page::progress).average().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
fun setStatusSubject(subject: PublishSubject<Download>?) {
|
fun setStatusSubject(subject: PublishSubject<Download>?) {
|
||||||
statusSubject = subject
|
statusSubject = subject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setStatusCallback(f: ((Download) -> Unit)?) {
|
||||||
|
statusCallback = f
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val NOT_DOWNLOADED = 0
|
const val NOT_DOWNLOADED = 0
|
||||||
|
@ -18,9 +18,12 @@ class DownloadQueue(
|
|||||||
|
|
||||||
private val updatedRelay = PublishRelay.create<Unit>()
|
private val updatedRelay = PublishRelay.create<Unit>()
|
||||||
|
|
||||||
|
private val downloadListeners = mutableListOf<DownloadListener>()
|
||||||
|
|
||||||
fun addAll(downloads: List<Download>) {
|
fun addAll(downloads: List<Download>) {
|
||||||
downloads.forEach { download ->
|
downloads.forEach { download ->
|
||||||
download.setStatusSubject(statusSubject)
|
download.setStatusSubject(statusSubject)
|
||||||
|
download.setStatusCallback(::setPagesFor)
|
||||||
download.status = Download.QUEUE
|
download.status = Download.QUEUE
|
||||||
}
|
}
|
||||||
queue.addAll(downloads)
|
queue.addAll(downloads)
|
||||||
@ -32,6 +35,10 @@ class DownloadQueue(
|
|||||||
val removed = queue.remove(download)
|
val removed = queue.remove(download)
|
||||||
store.remove(download)
|
store.remove(download)
|
||||||
download.setStatusSubject(null)
|
download.setStatusSubject(null)
|
||||||
|
download.setStatusCallback(null)
|
||||||
|
if (download.status == Download.DOWNLOADING || download.status == Download.QUEUE)
|
||||||
|
download.status = Download.NOT_DOWNLOADED
|
||||||
|
downloadListeners.forEach { it.updateDownload(download) }
|
||||||
if (removed) {
|
if (removed) {
|
||||||
updatedRelay.call(Unit)
|
updatedRelay.call(Unit)
|
||||||
}
|
}
|
||||||
@ -52,6 +59,10 @@ class DownloadQueue(
|
|||||||
fun clear() {
|
fun clear() {
|
||||||
queue.forEach { download ->
|
queue.forEach { download ->
|
||||||
download.setStatusSubject(null)
|
download.setStatusSubject(null)
|
||||||
|
download.setStatusCallback(null)
|
||||||
|
if (download.status == Download.DOWNLOADING || download.status == Download.QUEUE)
|
||||||
|
download.status = Download.NOT_DOWNLOADED
|
||||||
|
downloadListeners.forEach { it.updateDownload(download) }
|
||||||
}
|
}
|
||||||
queue.clear()
|
queue.clear()
|
||||||
store.clear()
|
store.clear()
|
||||||
@ -67,6 +78,27 @@ class DownloadQueue(
|
|||||||
.startWith(Unit)
|
.startWith(Unit)
|
||||||
.map { this }
|
.map { this }
|
||||||
|
|
||||||
|
private fun setPagesFor(download: Download) {
|
||||||
|
if (download.status == Download.DOWNLOADING) {
|
||||||
|
if (download.pages != null)
|
||||||
|
for (page in download.pages!!)
|
||||||
|
page.setStatusCallback {
|
||||||
|
callListeners(download)
|
||||||
|
}
|
||||||
|
downloadListeners.forEach { it.updateDownload(download) }
|
||||||
|
} else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
|
||||||
|
setPagesSubject(download.pages, null)
|
||||||
|
downloadListeners.forEach { it.updateDownload(download) }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
downloadListeners.forEach { it.updateDownload(download) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun callListeners(download: Download) {
|
||||||
|
downloadListeners.forEach { it.updateDownload(download) }
|
||||||
|
}
|
||||||
|
|
||||||
fun getProgressObservable(): Observable<Download> {
|
fun getProgressObservable(): Observable<Download> {
|
||||||
return statusSubject.onBackpressureBuffer()
|
return statusSubject.onBackpressureBuffer()
|
||||||
.startWith(getActiveDownloads())
|
.startWith(getActiveDownloads())
|
||||||
@ -74,6 +106,7 @@ class DownloadQueue(
|
|||||||
if (download.status == Download.DOWNLOADING) {
|
if (download.status == Download.DOWNLOADING) {
|
||||||
val pageStatusSubject = PublishSubject.create<Int>()
|
val pageStatusSubject = PublishSubject.create<Int>()
|
||||||
setPagesSubject(download.pages, pageStatusSubject)
|
setPagesSubject(download.pages, pageStatusSubject)
|
||||||
|
downloadListeners.forEach { it.updateDownload(download) }
|
||||||
return@flatMap pageStatusSubject
|
return@flatMap pageStatusSubject
|
||||||
.onBackpressureBuffer()
|
.onBackpressureBuffer()
|
||||||
.filter { it == Page.READY }
|
.filter { it == Page.READY }
|
||||||
@ -81,6 +114,7 @@ class DownloadQueue(
|
|||||||
|
|
||||||
} else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
|
} else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
|
||||||
setPagesSubject(download.pages, null)
|
setPagesSubject(download.pages, null)
|
||||||
|
downloadListeners.forEach { it.updateDownload(download) }
|
||||||
}
|
}
|
||||||
Observable.just(download)
|
Observable.just(download)
|
||||||
}
|
}
|
||||||
@ -95,4 +129,16 @@ class DownloadQueue(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addListener(listener: DownloadListener) {
|
||||||
|
downloadListeners.add(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeListener(listener: DownloadListener) {
|
||||||
|
downloadListeners.remove(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DownloadListener {
|
||||||
|
fun updateDownload(download: Download)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -18,12 +18,19 @@ open class Page(
|
|||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
statusSubject?.onNext(value)
|
statusSubject?.onNext(value)
|
||||||
|
statusCallback?.invoke(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transient @Volatile var progress: Int = 0
|
@Transient @Volatile var progress: Int = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
statusCallback?.invoke(this)
|
||||||
|
}
|
||||||
|
|
||||||
@Transient private var statusSubject: Subject<Int, Int>? = null
|
@Transient private var statusSubject: Subject<Int, Int>? = null
|
||||||
|
|
||||||
|
@Transient private var statusCallback: ((Page) -> Unit)? = null
|
||||||
|
|
||||||
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
|
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
|
||||||
progress = if (contentLength > 0) {
|
progress = if (contentLength > 0) {
|
||||||
(100 * bytesRead / contentLength).toInt()
|
(100 * bytesRead / contentLength).toInt()
|
||||||
@ -36,6 +43,10 @@ open class Page(
|
|||||||
this.statusSubject = subject
|
this.statusSubject = subject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setStatusCallback(f: ((Page) -> Unit)?) {
|
||||||
|
statusCallback = f
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val QUEUE = 0
|
const val QUEUE = 0
|
||||||
const val LOAD_PAGE = 1
|
const val LOAD_PAGE = 1
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.download
|
package eu.kanade.tachiyomi.ui.download
|
||||||
|
|
||||||
|
import android.animation.ObjectAnimator
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
@ -26,9 +27,16 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut
|
|||||||
R.drawable.filled_circle)?.mutate()
|
R.drawable.filled_circle)?.mutate()
|
||||||
private val borderCircle = ContextCompat.getDrawable(context,
|
private val borderCircle = ContextCompat.getDrawable(context,
|
||||||
R.drawable.border_circle)?.mutate()
|
R.drawable.border_circle)?.mutate()
|
||||||
|
private var isAnimating = false
|
||||||
|
private var iconAnimation:ObjectAnimator? = null
|
||||||
|
|
||||||
|
|
||||||
fun setDownoadStatus(state: Int, progress: Int = 0) {
|
fun setDownloadStatus(state: Int, progress: Int = 0) {
|
||||||
|
if (state != Download.DOWNLOADING) {
|
||||||
|
iconAnimation?.cancel()
|
||||||
|
download_icon.alpha = 1f
|
||||||
|
isAnimating = false
|
||||||
|
}
|
||||||
when (state) {
|
when (state) {
|
||||||
Download.NOT_DOWNLOADED -> {
|
Download.NOT_DOWNLOADED -> {
|
||||||
download_border.visible()
|
download_border.visible()
|
||||||
@ -55,6 +63,15 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut
|
|||||||
download_border.drawable.setTint(disabledColor)
|
download_border.drawable.setTint(disabledColor)
|
||||||
download_progress.progressDrawable?.setTint(downloadedColor)
|
download_progress.progressDrawable?.setTint(downloadedColor)
|
||||||
download_icon.drawable.setTint(disabledColor)
|
download_icon.drawable.setTint(disabledColor)
|
||||||
|
if (!isAnimating) {
|
||||||
|
iconAnimation = ObjectAnimator.ofFloat(download_icon, "alpha", 1f, 0f).apply {
|
||||||
|
duration = 1000
|
||||||
|
repeatCount = ObjectAnimator.INFINITE
|
||||||
|
repeatMode = ObjectAnimator.REVERSE
|
||||||
|
}
|
||||||
|
iconAnimation?.start()
|
||||||
|
isAnimating = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Download.DOWNLOADED -> {
|
Download.DOWNLOADED -> {
|
||||||
download_progress.gone()
|
download_progress.gone()
|
||||||
|
@ -86,6 +86,8 @@ open class LibraryController(
|
|||||||
*/
|
*/
|
||||||
protected var query = ""
|
protected var query = ""
|
||||||
|
|
||||||
|
var customQuery = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currently selected mangas.
|
* Currently selected mangas.
|
||||||
*/
|
*/
|
||||||
@ -256,6 +258,24 @@ open class LibraryController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onChangeEnded(
|
||||||
|
changeHandler: ControllerChangeHandler,
|
||||||
|
changeType: ControllerChangeType
|
||||||
|
) {
|
||||||
|
super.onChangeEnded(changeHandler, changeType)
|
||||||
|
if (changeType.isEnter) {
|
||||||
|
if (customQuery.isNotEmpty()) {
|
||||||
|
query = customQuery
|
||||||
|
((activity as MainActivity).toolbar.menu.findItem(
|
||||||
|
R.id.action_search
|
||||||
|
)?.actionView as? SearchView)?.setQuery(
|
||||||
|
customQuery, true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
customQuery = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onActivityResumed(activity: Activity) {
|
override fun onActivityResumed(activity: Activity) {
|
||||||
super.onActivityResumed(activity)
|
super.onActivityResumed(activity)
|
||||||
if (observeLater && ::presenter.isInitialized) {
|
if (observeLater && ::presenter.isInitialized) {
|
||||||
@ -477,15 +497,19 @@ open class LibraryController(
|
|||||||
menu.findItem(R.id.action_library_filter).icon.mutate()
|
menu.findItem(R.id.action_library_filter).icon.mutate()
|
||||||
|
|
||||||
setOnQueryTextChangeListener(searchView) {
|
setOnQueryTextChangeListener(searchView) {
|
||||||
query = it ?: ""
|
onSearch(it)
|
||||||
searchRelay.call(query)
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() })
|
searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun search(query:String) {
|
open fun onSearch(query: String?): Boolean {
|
||||||
this.query = query
|
this.query = query ?: ""
|
||||||
|
searchRelay.call(query)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun search(query: String) {
|
||||||
|
this.customQuery = query
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleRootBack(): Boolean {
|
override fun handleRootBack(): Boolean {
|
||||||
|
@ -5,15 +5,12 @@ import android.os.Bundle
|
|||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.appcompat.widget.SearchView
|
|
||||||
import androidx.core.math.MathUtils.clamp
|
import androidx.core.math.MathUtils.clamp
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
@ -36,10 +33,8 @@ import eu.kanade.tachiyomi.ui.main.SwipeGestureInterface
|
|||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import eu.kanade.tachiyomi.util.view.inflate
|
import eu.kanade.tachiyomi.util.view.inflate
|
||||||
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
|
||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
|
||||||
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
|
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
|
||||||
import kotlinx.android.synthetic.main.library_grid_recycler.*
|
import kotlinx.android.synthetic.main.library_grid_recycler.*
|
||||||
import kotlinx.android.synthetic.main.library_list_controller.*
|
import kotlinx.android.synthetic.main.library_list_controller.*
|
||||||
@ -302,27 +297,21 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun reattachAdapter() {
|
override fun reattachAdapter() {
|
||||||
if (libraryLayout == 0)recycler.spanCount = 1
|
if (libraryLayout == 0) recycler.spanCount = 1
|
||||||
else recycler.columnWidth = (90 + (preferences.gridSize().getOrDefault() * 30)).dpToPx
|
else recycler.columnWidth = (90 + (preferences.gridSize().getOrDefault() * 30)).dpToPx
|
||||||
val position =
|
val position =
|
||||||
(recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
|
(recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
|
||||||
libraryLayout = preferences.libraryLayout().getOrDefault()
|
libraryLayout = preferences.libraryLayout().getOrDefault()
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
(recycler as? AutofitRecyclerView)?.spanCount = if (libraryLayout == 0) 1 else mangaPerRow
|
|
||||||
|
|
||||||
(recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position, 0)
|
(recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onSearch(query: String?): Boolean {
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
this.query = query ?: ""
|
||||||
val searchItem = menu.findItem(R.id.action_search)
|
adapter.setFilter(query)
|
||||||
val searchView = searchItem.actionView as SearchView
|
|
||||||
setOnQueryTextChangeListener(searchView) {
|
|
||||||
query = it ?: ""
|
|
||||||
adapter.setFilter(it)
|
|
||||||
adapter.performFilter()
|
adapter.performFilter()
|
||||||
true
|
return true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||||
|
@ -12,6 +12,7 @@ import android.view.GestureDetector
|
|||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.view.WindowManager
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
|
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
|
||||||
@ -54,8 +55,10 @@ import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
|||||||
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
|
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
|
import eu.kanade.tachiyomi.util.view.gone
|
||||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.util.view.updatePadding
|
import eu.kanade.tachiyomi.util.view.updatePadding
|
||||||
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
@ -198,18 +201,19 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
|||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION*/
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION*/
|
||||||
updateRecentsIcon()
|
updateRecentsIcon()
|
||||||
content.viewTreeObserver.addOnGlobalLayoutListener {
|
content.viewTreeObserver.addOnGlobalLayoutListener {
|
||||||
/*val heightDiff: Int = content.rootView.height - content.height
|
val heightDiff: Int = content.rootView.height - content.height
|
||||||
if (heightDiff > 200 &&
|
if (heightDiff > 200 &&
|
||||||
window.attributes.softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
|
window.attributes.softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
|
||||||
//keyboard is open, hide layout
|
//keyboard is open, hide layout
|
||||||
navigationView.gone()
|
navigationView.gone()
|
||||||
} else if (navigationView.visibility == View.GONE) {
|
} else if (navigationView.visibility == View.GONE
|
||||||
|
&& window.attributes.softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
|
||||||
//keyboard is hidden, show layout
|
//keyboard is hidden, show layout
|
||||||
// use coroutine to delay so the bottom bar doesn't flash on top of the keyboard
|
// use coroutine to delay so the bottom bar doesn't flash on top of the keyboard
|
||||||
launchUI {
|
launchUI {
|
||||||
navigationView.visible()
|
navigationView.visible()
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
supportActionBar?.setDisplayShowCustomEnabled(true)
|
supportActionBar?.setDisplayShowCustomEnabled(true)
|
||||||
|
@ -0,0 +1,157 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.manga
|
||||||
|
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CompoundButton
|
||||||
|
import android.widget.RadioButton
|
||||||
|
import android.widget.RadioGroup
|
||||||
|
import com.f2prateek.rx.preferences.Preference
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
|
import eu.kanade.tachiyomi.util.view.setBottomEdge
|
||||||
|
import eu.kanade.tachiyomi.util.view.setEdgeToEdge
|
||||||
|
import eu.kanade.tachiyomi.util.view.visibleIf
|
||||||
|
import kotlinx.android.synthetic.main.chapter_sort_bottom_sheet.*
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class ChaptersSortBottomSheet(private val controller: MangaChaptersController) : BottomSheetDialog
|
||||||
|
(controller.activity!!, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
val activity = controller.activity!!
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preferences helper.
|
||||||
|
*/
|
||||||
|
private val preferences by injectLazy<PreferencesHelper>()
|
||||||
|
|
||||||
|
private var sheetBehavior: BottomSheetBehavior<*>
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Use activity theme for this layout
|
||||||
|
val view = activity.layoutInflater.inflate(R.layout.chapter_sort_bottom_sheet, null)
|
||||||
|
setContentView(view)
|
||||||
|
|
||||||
|
sheetBehavior = BottomSheetBehavior.from(view.parent as ViewGroup)
|
||||||
|
setEdgeToEdge(activity, bottom_sheet, view, false)
|
||||||
|
val height = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
activity.window.decorView.rootWindowInsets.systemWindowInsetBottom
|
||||||
|
} else 0
|
||||||
|
sheetBehavior.peekHeight = 220.dpToPx + height
|
||||||
|
|
||||||
|
sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
||||||
|
override fun onSlide(bottomSheet: View, progress: Float) { }
|
||||||
|
|
||||||
|
override fun onStateChanged(p0: View, state: Int) {
|
||||||
|
if (state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
|
sheetBehavior.skipCollapsed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
sheetBehavior.skipCollapsed = true
|
||||||
|
sheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the sheet is created. It initializes the listeners and values of the preferences.
|
||||||
|
*/
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
initGeneralPreferences()
|
||||||
|
setBottomEdge(show_bookmark, activity)
|
||||||
|
close_button.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
settings_scroll_view.viewTreeObserver.addOnGlobalLayoutListener {
|
||||||
|
val isScrollable =
|
||||||
|
settings_scroll_view!!.height < bottom_sheet.height +
|
||||||
|
settings_scroll_view.paddingTop + settings_scroll_view.paddingBottom
|
||||||
|
close_button.visibleIf(isScrollable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun initGeneralPreferences() {
|
||||||
|
|
||||||
|
show_read.isChecked = controller.presenter.onlyRead()
|
||||||
|
show_unread.isChecked = controller.presenter.onlyUnread()
|
||||||
|
show_download.isChecked = controller.presenter.onlyDownloaded()
|
||||||
|
show_bookmark.isChecked = controller.presenter.onlyBookmarked()
|
||||||
|
|
||||||
|
show_all.isChecked = !(show_read.isChecked || show_unread.isChecked ||
|
||||||
|
show_download.isChecked || show_bookmark.isChecked)
|
||||||
|
|
||||||
|
if (controller.presenter.onlyRead())
|
||||||
|
//Disable unread filter option if read filter is enabled.
|
||||||
|
show_unread.isEnabled = false
|
||||||
|
if (controller.presenter.onlyUnread())
|
||||||
|
//Disable read filter option if unread filter is enabled.
|
||||||
|
show_read.isEnabled = false
|
||||||
|
|
||||||
|
sort_group.check(if (controller.presenter.manga.sortDescending()) R.id.sort_newest else
|
||||||
|
R.id.sort_oldest)
|
||||||
|
|
||||||
|
show_titles.isChecked = controller.presenter.manga.displayMode == Manga.DISPLAY_NAME
|
||||||
|
sort_by_source.isChecked = controller.presenter.manga.sorting == Manga.SORTING_SOURCE
|
||||||
|
|
||||||
|
sort_group.setOnCheckedChangeListener { _, checkedId ->
|
||||||
|
controller.presenter.setSortOrder(checkedId == R.id.sort_oldest)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*sort_group.bindToPreference(preferences.libraryLayout()) {
|
||||||
|
controller.reattachAdapter()
|
||||||
|
if (sheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
uniform_grid.bindToPreference(preferences.uniformGrid()) {
|
||||||
|
controller.reattachAdapter()
|
||||||
|
}
|
||||||
|
grid_size_toggle_group.bindToPreference(preferences.gridSize()) {
|
||||||
|
controller.reattachAdapter()
|
||||||
|
}
|
||||||
|
download_badge.bindToPreference(preferences.downloadBadge()) {
|
||||||
|
controller.presenter.requestDownloadBadgesUpdate()
|
||||||
|
}
|
||||||
|
unread_badge_group.bindToPreference(preferences.unreadBadgeType()) {
|
||||||
|
controller.presenter.requestUnreadBadgesUpdate()
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a checkbox or switch view with a boolean preference.
|
||||||
|
*/
|
||||||
|
private fun CompoundButton.bindToPreference(pref: Preference<Boolean>, block: () -> Unit) {
|
||||||
|
isChecked = pref.getOrDefault()
|
||||||
|
setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
pref.set(isChecked)
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a radio group with a int preference.
|
||||||
|
*/
|
||||||
|
private fun RadioGroup.bindToPreference(pref: Preference<Int>, block: () -> Unit) {
|
||||||
|
(getChildAt(pref.getOrDefault()) as RadioButton).isChecked = true
|
||||||
|
setOnCheckedChangeListener { _, checkedId ->
|
||||||
|
val index = indexOfChild(findViewById(checkedId))
|
||||||
|
pref.set(index)
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga
|
package eu.kanade.tachiyomi.ui.manga
|
||||||
|
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
@ -8,6 +9,7 @@ import android.graphics.drawable.BitmapDrawable
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.Gravity
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
@ -15,6 +17,7 @@ import android.view.MenuItem
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.core.graphics.ColorUtils
|
import androidx.core.graphics.ColorUtils
|
||||||
import androidx.palette.graphics.Palette
|
import androidx.palette.graphics.Palette
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
@ -31,6 +34,7 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
@ -41,10 +45,13 @@ import eu.kanade.tachiyomi.source.Source
|
|||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
||||||
|
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
||||||
|
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.main.SearchActivity
|
import eu.kanade.tachiyomi.ui.main.SearchActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController.Companion.FROM_CATALOGUE_EXTRA
|
import eu.kanade.tachiyomi.ui.manga.MangaController.Companion.FROM_CATALOGUE_EXTRA
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterMatHolder
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||||
@ -56,14 +63,18 @@ import eu.kanade.tachiyomi.util.view.snack
|
|||||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
||||||
import kotlinx.android.synthetic.main.big_manga_controller.*
|
import kotlinx.android.synthetic.main.big_manga_controller.*
|
||||||
|
import kotlinx.android.synthetic.main.big_manga_controller.swipe_refresh
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
|
import kotlinx.android.synthetic.main.manga_info_controller.*
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class MangaChaptersController : BaseController,
|
class MangaChaptersController : BaseController,
|
||||||
ActionMode.Callback,
|
ActionMode.Callback,
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
ChaptersAdapter.MangaHeaderInterface {
|
FlexibleAdapter.OnItemLongClickListener,
|
||||||
|
ChaptersAdapter.MangaHeaderInterface,
|
||||||
|
ChangeMangaCategoriesDialog.Listener {
|
||||||
|
|
||||||
constructor(manga: Manga?,
|
constructor(manga: Manga?,
|
||||||
fromCatalogue: Boolean = false,
|
fromCatalogue: Boolean = false,
|
||||||
@ -121,7 +132,6 @@ class MangaChaptersController : BaseController,
|
|||||||
|
|
||||||
// Init RecyclerView and adapter
|
// Init RecyclerView and adapter
|
||||||
adapter = ChaptersAdapter(this, view.context)
|
adapter = ChaptersAdapter(this, view.context)
|
||||||
//setReadingDrawable()
|
|
||||||
|
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
recycler.layoutManager = LinearLayoutManager(view.context)
|
recycler.layoutManager = LinearLayoutManager(view.context)
|
||||||
@ -133,9 +143,6 @@ class MangaChaptersController : BaseController,
|
|||||||
)
|
)
|
||||||
recycler.setHasFixedSize(true)
|
recycler.setHasFixedSize(true)
|
||||||
adapter?.fastScroller = fast_scroller
|
adapter?.fastScroller = fast_scroller
|
||||||
/*activity?.controller_container?.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
|
||||||
topMargin = 0
|
|
||||||
}*/
|
|
||||||
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
|
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
|
||||||
val array = view.context.obtainStyledAttributes(attrsArray)
|
val array = view.context.obtainStyledAttributes(attrsArray)
|
||||||
val appbarHeight = array.getDimensionPixelSize(0, 0)
|
val appbarHeight = array.getDimensionPixelSize(0, 0)
|
||||||
@ -144,6 +151,7 @@ class MangaChaptersController : BaseController,
|
|||||||
|
|
||||||
recycler.doOnApplyWindowInsets { v, insets, _ ->
|
recycler.doOnApplyWindowInsets { v, insets, _ ->
|
||||||
headerHeight = appbarHeight + insets.systemWindowInsetTop + offset
|
headerHeight = appbarHeight + insets.systemWindowInsetTop + offset
|
||||||
|
swipe_refresh.setProgressViewOffset(false, (-40).dpToPx, headerHeight)
|
||||||
(recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder)
|
(recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder)
|
||||||
?.setTopHeight(headerHeight)
|
?.setTopHeight(headerHeight)
|
||||||
fast_scroller?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
fast_scroller?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
@ -156,7 +164,7 @@ class MangaChaptersController : BaseController,
|
|||||||
|
|
||||||
presenter.onCreate()
|
presenter.onCreate()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
recycler.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
|
recycler.setOnScrollChangeListener { _, _, _, _, _ ->
|
||||||
val atTop = !recycler.canScrollVertically(-1)
|
val atTop = !recycler.canScrollVertically(-1)
|
||||||
if ((!atTop && !toolbarIsColored) || (atTop && toolbarIsColored)) {
|
if ((!atTop && !toolbarIsColored) || (atTop && toolbarIsColored)) {
|
||||||
toolbarIsColored = !atTop
|
toolbarIsColored = !atTop
|
||||||
@ -173,7 +181,6 @@ class MangaChaptersController : BaseController,
|
|||||||
ArgbEvaluator(), colorFrom, colorTo
|
ArgbEvaluator(), colorFrom, colorTo
|
||||||
)
|
)
|
||||||
colorAnimator?.duration = 250 // milliseconds
|
colorAnimator?.duration = 250 // milliseconds
|
||||||
//colorAnimation.startDelay = 150
|
|
||||||
colorAnimator?.addUpdateListener { animator ->
|
colorAnimator?.addUpdateListener { animator ->
|
||||||
(activity as MainActivity).toolbar.setBackgroundColor(animator.animatedValue as Int)
|
(activity as MainActivity).toolbar.setBackgroundColor(animator.animatedValue as Int)
|
||||||
activity?.window?.statusBarColor = (animator.animatedValue as Int)
|
activity?.window?.statusBarColor = (animator.animatedValue as Int)
|
||||||
@ -184,8 +191,6 @@ class MangaChaptersController : BaseController,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
|
||||||
// recycler.requestApplyInsetsWhenAttached()
|
|
||||||
GlideApp.with(view.context).load(manga)
|
GlideApp.with(view.context).load(manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||||
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga!!.id!!).toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga!!.id!!).toString()))
|
||||||
@ -222,7 +227,11 @@ class MangaChaptersController : BaseController,
|
|||||||
swipe_refresh.setOnRefreshListener {
|
swipe_refresh.setOnRefreshListener {
|
||||||
presenter.refreshAll()
|
presenter.refreshAll()
|
||||||
}
|
}
|
||||||
//adapter?.fastScroller = fast_scroller
|
}
|
||||||
|
|
||||||
|
override fun onActivityResumed(activity: Activity) {
|
||||||
|
super.onActivityResumed(activity)
|
||||||
|
presenter.fetchChapters()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showError(message: String) {
|
fun showError(message: String) {
|
||||||
@ -230,43 +239,21 @@ class MangaChaptersController : BaseController,
|
|||||||
view?.snack(message)
|
view?.snack(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateChapterDownload(download: Download) {
|
||||||
|
getHolder(download.chapter)?.notifyStatus(download.status, presenter.isLockedFromSearch,
|
||||||
|
download.progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getHolder(chapter: Chapter): ChapterMatHolder? {
|
||||||
|
return recycler?.findViewHolderForItemId(chapter.id!!) as? ChapterMatHolder
|
||||||
|
}
|
||||||
|
|
||||||
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
||||||
super.onChangeStarted(handler, type)
|
super.onChangeStarted(handler, type)
|
||||||
if (type == ControllerChangeType.PUSH_ENTER || type == ControllerChangeType.POP_ENTER) {
|
if (type == ControllerChangeType.PUSH_ENTER || type == ControllerChangeType.POP_ENTER) {
|
||||||
(activity as MainActivity).appbar.setBackgroundColor(Color.TRANSPARENT)
|
(activity as MainActivity).appbar.setBackgroundColor(Color.TRANSPARENT)
|
||||||
(activity as MainActivity).toolbar.setBackgroundColor(Color.TRANSPARENT)
|
(activity as MainActivity).toolbar.setBackgroundColor(Color.TRANSPARENT)
|
||||||
activity?.window?.statusBarColor = Color.TRANSPARENT
|
activity?.window?.statusBarColor = Color.TRANSPARENT
|
||||||
/* val colorFrom = ((activity as MainActivity).toolbar.background as ColorDrawable).color
|
|
||||||
val colorTo = Color.TRANSPARENT
|
|
||||||
colorAnimator = ValueAnimator.ofObject(
|
|
||||||
ArgbEvaluator(), colorFrom, colorTo)
|
|
||||||
colorAnimator?.duration = 250 // milliseconds
|
|
||||||
//colorAnimation.startDelay = 150
|
|
||||||
colorAnimator?.addUpdateListener { animator ->
|
|
||||||
(activity as MainActivity).toolbar.setBackgroundColor(animator.animatedValue as Int)
|
|
||||||
//activity?.window?.statusBarColor = (animator.animatedValue as Int)
|
|
||||||
}
|
|
||||||
colorAnimator?.start()*/
|
|
||||||
|
|
||||||
/*activity!!.window.setFlags(
|
|
||||||
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
|
|
||||||
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
val insetTop = activity!!.window.decorView.rootWindowInsets.systemWindowInsetTop
|
|
||||||
val insetBottom = activity!!.window.decorView.rootWindowInsets.stableInsetBottom
|
|
||||||
(activity)?.appbar?.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
|
||||||
topMargin = insetTop
|
|
||||||
}
|
|
||||||
|
|
||||||
(activity)?.navigationView?.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
|
||||||
bottomMargin = insetBottom
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//
|
|
||||||
//(activity as MainActivity).toolbar.setBackgroundColor(Color.TRANSPARENT)
|
|
||||||
//(activity as MainActivity).appbar.gone()
|
|
||||||
}
|
}
|
||||||
else if (type == ControllerChangeType.PUSH_EXIT || type == ControllerChangeType.POP_EXIT) {
|
else if (type == ControllerChangeType.PUSH_EXIT || type == ControllerChangeType.POP_EXIT) {
|
||||||
colorAnimator?.cancel()
|
colorAnimator?.cancel()
|
||||||
@ -278,22 +265,6 @@ class MangaChaptersController : BaseController,
|
|||||||
activity?.window?.statusBarColor = activity?.getResourceColor(
|
activity?.window?.statusBarColor = activity?.getResourceColor(
|
||||||
android.R.attr.colorPrimary
|
android.R.attr.colorPrimary
|
||||||
) ?: Color.BLACK
|
) ?: Color.BLACK
|
||||||
// activity!!.window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
|
||||||
|
|
||||||
/* activity?.window?.statusBarColor = activity?.getResourceColor(
|
|
||||||
android.R.attr.colorPrimary
|
|
||||||
) ?: Color.BLACK*/
|
|
||||||
/*(activity as MainActivity).appbar.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
|
||||||
topMargin = 0
|
|
||||||
}
|
|
||||||
(activity as MainActivity).navigationView.updateLayoutParams<ConstraintLayout
|
|
||||||
.LayoutParams> {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
bottomMargin = 0
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
//(activity as MainActivity).appbar.background = null
|
|
||||||
// (activity as AppCompatActivity).supportActionBar?.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,9 +276,12 @@ class MangaChaptersController : BaseController,
|
|||||||
if (presenter.chapters.isEmpty()) {
|
if (presenter.chapters.isEmpty()) {
|
||||||
adapter?.updateDataSet(listOf(ChapterItem(Chapter.createH(), presenter.manga)))
|
adapter?.updateDataSet(listOf(ChapterItem(Chapter.createH(), presenter.manga)))
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
adapter?.updateDataSet(listOf(ChapterItem(Chapter.createH(), presenter.manga))
|
swipe_refresh.isRefreshing = false
|
||||||
+ presenter.chapters)
|
adapter?.updateDataSet(
|
||||||
|
listOf(ChapterItem(Chapter.createH(), presenter.manga)) + presenter.chapters
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -333,7 +307,62 @@ class MangaChaptersController : BaseController,
|
|||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openChapter(chapter: Chapter, hasAnimation: Boolean = false) {
|
override fun onItemLongClick(position: Int) {
|
||||||
|
val adapter = adapter ?: return
|
||||||
|
val item = adapter.getItem(position) ?: return
|
||||||
|
val itemView = getHolder(item)?.itemView ?: return
|
||||||
|
val popup = PopupMenu(itemView.context, itemView, Gravity.END)
|
||||||
|
|
||||||
|
// Inflate our menu resource into the PopupMenu's Menu
|
||||||
|
popup.menuInflater.inflate(R.menu.chapters_mat_single, popup.menu)
|
||||||
|
|
||||||
|
// Hide bookmark if bookmark
|
||||||
|
popup.menu.findItem(R.id.action_bookmark).isVisible = !item.bookmark
|
||||||
|
popup.menu.findItem(R.id.action_remove_bookmark).isVisible = item.bookmark
|
||||||
|
|
||||||
|
// Hide mark as unread when the chapter is unread
|
||||||
|
if (!item.read && item.last_page_read == 0) {
|
||||||
|
popup.menu.findItem(R.id.action_mark_as_unread).isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide mark as read when the chapter is read
|
||||||
|
if (item.read) {
|
||||||
|
popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a listener so we are notified if a menu item is clicked
|
||||||
|
popup.setOnMenuItemClickListener { menuItem ->
|
||||||
|
val chapters = listOf(item)
|
||||||
|
when (menuItem.itemId) {
|
||||||
|
R.id.action_bookmark -> bookmarkChapters(chapters, true)
|
||||||
|
R.id.action_remove_bookmark -> bookmarkChapters(chapters, false)
|
||||||
|
R.id.action_mark_as_read -> markAsRead(chapters)
|
||||||
|
R.id.action_mark_as_unread -> markAsUnread(chapters)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally show the PopupMenu
|
||||||
|
popup.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bookmarkChapters(chapters: List<ChapterItem>, bookmarked: Boolean) {
|
||||||
|
//destroyActionModeIfNeeded()
|
||||||
|
presenter.bookmarkChapters(chapters, bookmarked)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun markAsRead(chapters: List<ChapterItem>) {
|
||||||
|
presenter.markChaptersRead(chapters, true)
|
||||||
|
if (presenter.preferences.removeAfterMarkedAsRead()) {
|
||||||
|
presenter.deleteChapters(chapters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun markAsUnread(chapters: List<ChapterItem>) {
|
||||||
|
presenter.markChaptersRead(chapters, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openChapter(chapter: Chapter, hasAnimation: Boolean = false) {
|
||||||
val activity = activity ?: return
|
val activity = activity ?: return
|
||||||
val intent = ReaderActivity.newIntent(activity, manga!!, chapter)
|
val intent = ReaderActivity.newIntent(activity, manga!!, chapter)
|
||||||
if (hasAnimation) {
|
if (hasAnimation) {
|
||||||
@ -342,13 +371,10 @@ class MangaChaptersController : BaseController,
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStatusBarHeight(): Int {
|
override fun onDestroyView(view: View) {
|
||||||
var result = 0
|
snack?.dismiss()
|
||||||
val resourceId = resources!!.getIdentifier("status_bar_height", "dimen", "android")
|
presenter.onDestroy()
|
||||||
if (resourceId > 0) {
|
super.onDestroyView(view)
|
||||||
result = resources!!.getDimensionPixelSize(resourceId)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
@ -387,8 +413,6 @@ class MangaChaptersController : BaseController,
|
|||||||
override fun topCoverHeight(): Int = headerHeight
|
override fun topCoverHeight(): Int = headerHeight
|
||||||
|
|
||||||
override fun nextChapter(): Chapter? = presenter.getNextUnreadChapter()
|
override fun nextChapter(): Chapter? = presenter.getNextUnreadChapter()
|
||||||
override fun newestChapterDate(): Long? = presenter.getNewestChapterTime()
|
|
||||||
override fun lastChapter(): Float? = presenter.getLatestChapter()
|
|
||||||
override fun mangaSource(): Source = presenter.source
|
override fun mangaSource(): Source = presenter.source
|
||||||
|
|
||||||
override fun readNextChapter() {
|
override fun readNextChapter() {
|
||||||
@ -421,4 +445,100 @@ class MangaChaptersController : BaseController,
|
|||||||
}
|
}
|
||||||
else presenter.downloadChapters(listOf(chapter))
|
else presenter.downloadChapters(listOf(chapter))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun tagClicked(text: String) {
|
||||||
|
val firstController = router.backstack.first()?.controller()
|
||||||
|
if (firstController is LibraryController && router.backstack.size == 2) {
|
||||||
|
router.handleBack()
|
||||||
|
firstController.search(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showChapterFilter() {
|
||||||
|
ChaptersSortBottomSheet(this).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterCount():Int = presenter.chapters.size
|
||||||
|
|
||||||
|
override fun favoriteManga(longPress: Boolean) {
|
||||||
|
val manga = presenter.manga
|
||||||
|
if (longPress) {
|
||||||
|
if (!manga.favorite) {
|
||||||
|
presenter.toggleFavorite()
|
||||||
|
showAddedSnack()
|
||||||
|
}
|
||||||
|
val categories = presenter.getCategories()
|
||||||
|
if (categories.isEmpty()) {
|
||||||
|
// no categories exist, display a message about adding categories
|
||||||
|
snack = view?.snack(R.string.action_add_category)
|
||||||
|
} else {
|
||||||
|
val ids = presenter.getMangaCategoryIds(manga)
|
||||||
|
val preselected = ids.mapNotNull { id ->
|
||||||
|
categories.indexOfFirst { it.id == id }.takeIf { it != -1 }
|
||||||
|
}.toTypedArray()
|
||||||
|
|
||||||
|
ChangeMangaCategoriesDialog(this, listOf(manga), categories, preselected)
|
||||||
|
.showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (presenter.toggleFavorite()) {
|
||||||
|
val categories = presenter.getCategories()
|
||||||
|
val defaultCategoryId = presenter.preferences.defaultCategory()
|
||||||
|
val defaultCategory = categories.find { it.id == defaultCategoryId }
|
||||||
|
when {
|
||||||
|
defaultCategory != null -> presenter.moveMangaToCategory(manga, defaultCategory)
|
||||||
|
defaultCategoryId == 0 || categories.isEmpty() -> // 'Default' or no category
|
||||||
|
presenter.moveMangaToCategory(manga, null)
|
||||||
|
else -> {
|
||||||
|
val ids = presenter.getMangaCategoryIds(manga)
|
||||||
|
val preselected = ids.mapNotNull { id ->
|
||||||
|
categories.indexOfFirst { it.id == id }.takeIf { it != -1 }
|
||||||
|
}.toTypedArray()
|
||||||
|
|
||||||
|
ChangeMangaCategoriesDialog(
|
||||||
|
this,
|
||||||
|
listOf(manga),
|
||||||
|
categories,
|
||||||
|
preselected
|
||||||
|
).showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showAddedSnack()
|
||||||
|
} else {
|
||||||
|
showRemovedSnack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showAddedSnack() {
|
||||||
|
val view = view ?: return
|
||||||
|
snack?.dismiss()
|
||||||
|
snack = view.snack(view.context.getString(R.string.manga_added_library))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showRemovedSnack() {
|
||||||
|
val view = view ?: return
|
||||||
|
snack?.dismiss()
|
||||||
|
snack = view.snack(
|
||||||
|
view.context.getString(R.string.manga_removed_library),
|
||||||
|
Snackbar.LENGTH_INDEFINITE
|
||||||
|
) {
|
||||||
|
setAction(R.string.action_undo) {
|
||||||
|
presenter.setFavorite(true)
|
||||||
|
}
|
||||||
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
|
super.onDismissed(transientBottomBar, event)
|
||||||
|
if (!presenter.manga.favorite) presenter.confirmDeletion()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(activity as? MainActivity)?.setUndoSnackBar(snack, fab_favorite)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateCategoriesForMangas(mangas: List<Manga>, categories: List<Category>) {
|
||||||
|
val manga = mangas.firstOrNull() ?: return
|
||||||
|
presenter.moveMangaToCategories(manga, categories)
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.manga
|
|||||||
|
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.text.format.DateUtils
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
@ -17,10 +16,11 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
import eu.kanade.tachiyomi.util.view.gone
|
||||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import eu.kanade.tachiyomi.util.view.visibleIf
|
import eu.kanade.tachiyomi.util.view.visibleIf
|
||||||
import kotlinx.android.synthetic.main.manga_header_item.*
|
import kotlinx.android.synthetic.main.manga_header_item.*
|
||||||
import java.util.Date
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class MangaHeaderHolder(
|
class MangaHeaderHolder(
|
||||||
@ -33,17 +33,60 @@ class MangaHeaderHolder(
|
|||||||
top_view.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
top_view.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||||
topMargin = adapter.coverListener?.topCoverHeight() ?: 0
|
topMargin = adapter.coverListener?.topCoverHeight() ?: 0
|
||||||
}
|
}
|
||||||
|
more_button.setOnClickListener { expandDesc() }
|
||||||
|
manga_summary.setOnClickListener { expandDesc() }
|
||||||
|
less_button.setOnClickListener {
|
||||||
|
manga_summary.maxLines = 3
|
||||||
|
manga_genres_tags.gone()
|
||||||
|
less_button.gone()
|
||||||
|
more_button_group.visible()
|
||||||
|
}
|
||||||
|
manga_genres_tags.setOnTagClickListener {
|
||||||
|
adapter.coverListener?.tagClicked(it)
|
||||||
|
}
|
||||||
|
filter_button.setOnClickListener {
|
||||||
|
adapter.coverListener?.showChapterFilter()
|
||||||
|
}
|
||||||
|
favorite_button.setOnClickListener {
|
||||||
|
adapter.coverListener?.favoriteManga(false)
|
||||||
|
}
|
||||||
|
favorite_button.setOnLongClickListener {
|
||||||
|
adapter.coverListener?.favoriteManga(true)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun expandDesc() {
|
||||||
|
if (more_button.visibility == View.VISIBLE) {
|
||||||
|
manga_summary.maxLines = Integer.MAX_VALUE
|
||||||
|
manga_genres_tags.visible()
|
||||||
|
less_button.visible()
|
||||||
|
more_button_group.gone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bind(item: ChapterItem, manga: Manga) {
|
override fun bind(item: ChapterItem, manga: Manga) {
|
||||||
manga_full_title.text = manga.currentTitle()
|
manga_full_title.text = manga.currentTitle()
|
||||||
|
|
||||||
|
if (manga.currentGenres().isNullOrBlank().not())
|
||||||
|
manga_genres_tags.setTags(manga.currentGenres()?.split(", ")?.map(String::trim))
|
||||||
|
else
|
||||||
|
manga_genres_tags.setTags(emptyList())
|
||||||
|
|
||||||
if (manga.currentAuthor() == manga.currentArtist() ||
|
if (manga.currentAuthor() == manga.currentArtist() ||
|
||||||
manga.currentArtist().isNullOrBlank())
|
manga.currentArtist().isNullOrBlank())
|
||||||
manga_author.text = manga.currentAuthor()
|
manga_author.text = manga.currentAuthor()
|
||||||
else {
|
else {
|
||||||
manga_author.text = "${manga.currentAuthor()?.trim()}, ${manga.currentArtist()}"
|
manga_author.text = "${manga.currentAuthor()?.trim()}, ${manga.currentArtist()}"
|
||||||
}
|
}
|
||||||
manga_summary.text = manga.currentDesc()
|
manga_summary.text = manga.currentDesc() ?: itemView.context.getString(R.string
|
||||||
|
.no_description)
|
||||||
|
|
||||||
|
manga_summary.post {
|
||||||
|
if (manga_summary.lineCount < 3 && manga.currentGenres().isNullOrBlank()) {
|
||||||
|
more_button_group.gone()
|
||||||
|
}
|
||||||
|
}
|
||||||
manga_summary_label.text = itemView.context.getString(R.string.about_this,
|
manga_summary_label.text = itemView.context.getString(R.string.about_this,
|
||||||
itemView.context.getString(
|
itemView.context.getString(
|
||||||
when {
|
when {
|
||||||
@ -77,6 +120,10 @@ class MangaHeaderHolder(
|
|||||||
context.getResourceColor(R.attr.colorAccent), 75))
|
context.getResourceColor(R.attr.colorAccent), 75))
|
||||||
strokeColor = ColorStateList.valueOf(Color.TRANSPARENT)
|
strokeColor = ColorStateList.valueOf(Color.TRANSPARENT)
|
||||||
}
|
}
|
||||||
|
else strokeColor = ColorStateList.valueOf(
|
||||||
|
ColorUtils.setAlphaComponent(
|
||||||
|
itemView.context.getResourceColor(R.attr
|
||||||
|
.colorOnSurface), 31))
|
||||||
}
|
}
|
||||||
true_backdrop.setBackgroundColor(adapter.coverListener?.coverColor() ?:
|
true_backdrop.setBackgroundColor(adapter.coverListener?.coverColor() ?:
|
||||||
itemView.context.getResourceColor(android.R.attr.colorBackground))
|
itemView.context.getResourceColor(android.R.attr.colorBackground))
|
||||||
@ -98,31 +145,20 @@ class MangaHeaderHolder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val count = adapter.coverListener?.chapterCount() ?: 0
|
||||||
|
chapters_title.text = itemView.resources.getQuantityString(R.plurals.chapters, count, count)
|
||||||
|
|
||||||
top_view.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
top_view.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||||
topMargin = adapter.coverListener?.topCoverHeight() ?: 0
|
topMargin = adapter.coverListener?.topCoverHeight() ?: 0
|
||||||
}
|
}
|
||||||
val lastUpdated = adapter.coverListener?.newestChapterDate()
|
|
||||||
if (lastUpdated != null) {
|
|
||||||
manga_last_update.text = itemView.context.getString(
|
|
||||||
R.string.last_updated, DateUtils.getRelativeTimeSpanString(
|
|
||||||
lastUpdated, Date().time, DateUtils.HOUR_IN_MILLIS
|
|
||||||
).toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
manga_last_update.text = itemView.context.getString(R.string.last_update_unknown)
|
|
||||||
}
|
|
||||||
|
|
||||||
val sourceAndStatus = mutableListOf<String>()
|
manga_status.text = (itemView.context.getString( when (manga.status) {
|
||||||
sourceAndStatus.add(itemView.context.getString( when (manga.status) {
|
|
||||||
SManga.ONGOING -> R.string.ongoing
|
SManga.ONGOING -> R.string.ongoing
|
||||||
SManga.COMPLETED -> R.string.completed
|
SManga.COMPLETED -> R.string.completed
|
||||||
SManga.LICENSED -> R.string.licensed
|
SManga.LICENSED -> R.string.licensed
|
||||||
else -> R.string.unknown_status
|
else -> R.string.unknown_status
|
||||||
}))
|
}))
|
||||||
val sourceName = adapter.coverListener?.mangaSource()?.toString()
|
manga_source.text = adapter.coverListener?.mangaSource()?.toString()
|
||||||
if (sourceName != null) sourceAndStatus.add(sourceName)
|
|
||||||
manga_status_source.text = sourceAndStatus.joinToString(" • ")
|
|
||||||
|
|
||||||
GlideApp.with(view.context).load(manga)
|
GlideApp.with(view.context).load(manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||||
|
@ -1,46 +1,65 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga
|
package eu.kanade.tachiyomi.ui.manga
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class MangaPresenter(private val controller: MangaChaptersController,
|
class MangaPresenter(private val controller: MangaChaptersController,
|
||||||
val manga: Manga,
|
val manga: Manga,
|
||||||
val source: Source,
|
val source: Source,
|
||||||
val preferences: PreferencesHelper = Injekt.get(),
|
val preferences: PreferencesHelper = Injekt.get(),
|
||||||
|
private val coverCache: CoverCache = Injekt.get(),
|
||||||
private val db: DatabaseHelper = Injekt.get(),
|
private val db: DatabaseHelper = Injekt.get(),
|
||||||
private val downloadManager: DownloadManager = Injekt.get()) {
|
private val downloadManager: DownloadManager = Injekt.get()):
|
||||||
|
CoroutineScope,
|
||||||
|
DownloadQueue.DownloadListener {
|
||||||
|
|
||||||
|
override var coroutineContext:CoroutineContext = Job() + Dispatchers.Default
|
||||||
|
|
||||||
var isLockedFromSearch = false
|
var isLockedFromSearch = false
|
||||||
var hasRequested = false
|
var hasRequested = false
|
||||||
|
|
||||||
var chapters:List<ChapterItem> = emptyList()
|
var chapters:List<ChapterItem> = emptyList()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun onCreate() {
|
fun onCreate() {
|
||||||
isLockedFromSearch = SecureActivityDelegate.shouldBeLocked()
|
isLockedFromSearch = SecureActivityDelegate.shouldBeLocked()
|
||||||
|
downloadManager.addListener(this)
|
||||||
if (!manga.initialized)
|
if (!manga.initialized)
|
||||||
fetchMangaFromSource()
|
fetchMangaFromSource()
|
||||||
updateChapters()
|
updateChapters()
|
||||||
controller.updateChapters(this.chapters)
|
controller.updateChapters(this.chapters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onDestroy() {
|
||||||
|
downloadManager.removeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
fun fetchMangaFromSource() {
|
fun fetchMangaFromSource() {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
@ -66,6 +85,24 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun fetchChapters() {
|
||||||
|
launch {
|
||||||
|
getChapters()
|
||||||
|
withContext(Dispatchers.Main) { controller.updateChapters(chapters) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getChapters() {
|
||||||
|
val chapters = withContext(Dispatchers.IO) {
|
||||||
|
db.getChapters(manga).executeAsBlocking().map { it.toModel() }
|
||||||
|
}
|
||||||
|
// Store the last emission
|
||||||
|
this.chapters = applyChapterFilters(chapters)
|
||||||
|
|
||||||
|
// Find downloaded chapters
|
||||||
|
setDownloadedChapters(chapters)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateChapters(fetchedChapters: List<Chapter>? = null) {
|
private fun updateChapters(fetchedChapters: List<Chapter>? = null) {
|
||||||
val chapters = (fetchedChapters ?:
|
val chapters = (fetchedChapters ?:
|
||||||
db.getChapters(manga).executeAsBlocking()).map { it.toModel() }
|
db.getChapters(manga).executeAsBlocking()).map { it.toModel() }
|
||||||
@ -75,17 +112,6 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
|
|
||||||
// Find downloaded chapters
|
// Find downloaded chapters
|
||||||
setDownloadedChapters(chapters)
|
setDownloadedChapters(chapters)
|
||||||
|
|
||||||
/*
|
|
||||||
// Emit the number of chapters to the info tab.
|
|
||||||
chapterCountRelay.call(chapters.maxBy { it.chapter_number }?.chapter_number
|
|
||||||
?: 0f)
|
|
||||||
|
|
||||||
// Emit the upload date of the most recent chapter
|
|
||||||
lastUpdateRelay.call(
|
|
||||||
Date(chapters.maxBy { it.date_upload }?.date_upload
|
|
||||||
?: 0)
|
|
||||||
)*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,6 +126,14 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateDownload(download: Download) {
|
||||||
|
chapters.find { it.id == download.chapter.id }?.download = download
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
controller.updateChapterDownload(download)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a chapter from the database to an extended model, allowing to store new fields.
|
* Converts a chapter from the database to an extended model, allowing to store new fields.
|
||||||
*/
|
*/
|
||||||
@ -239,7 +273,9 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
fun deleteChapters(chapters: List<ChapterItem>) {
|
fun deleteChapters(chapters: List<ChapterItem>) {
|
||||||
deleteChaptersInternal(chapters)
|
deleteChaptersInternal(chapters)
|
||||||
|
|
||||||
setDownloadedChapters(chapters)
|
chapters.forEach { chapter ->
|
||||||
|
this.chapters.find { it.id == chapter.id }?.download?.status = Download.NOT_DOWNLOADED
|
||||||
|
}
|
||||||
|
|
||||||
controller.updateChapters(this.chapters)
|
controller.updateChapters(this.chapters)
|
||||||
// if (onlyDownloaded()) refreshChapters() }
|
// if (onlyDownloaded()) refreshChapters() }
|
||||||
@ -258,8 +294,46 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun refreshAll() {
|
fun refreshAll() {
|
||||||
fetchMangaFromSource()
|
launch {
|
||||||
fetchChaptersFromSource()
|
var mangaError: java.lang.Exception? = null
|
||||||
|
var chapterError: java.lang.Exception? = null
|
||||||
|
val chapters = async(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
source.fetchChapterList(manga).toBlocking().single()
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
chapterError = e
|
||||||
|
emptyList<SChapter>()
|
||||||
|
} ?: emptyList()
|
||||||
|
}
|
||||||
|
val thumbnailUrl = manga.thumbnail_url
|
||||||
|
val nManga = async(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
source.fetchMangaDetails(manga).toBlocking().single()
|
||||||
|
} catch (e: java.lang.Exception) {
|
||||||
|
mangaError = e
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val networkManga = nManga.await()
|
||||||
|
if (networkManga != null) {
|
||||||
|
manga.copyFrom(networkManga)
|
||||||
|
manga.initialized = true
|
||||||
|
db.insertManga(manga).executeAsBlocking()
|
||||||
|
if (thumbnailUrl != networkManga.thumbnail_url)
|
||||||
|
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
|
||||||
|
}
|
||||||
|
val finChapters = chapters.await()
|
||||||
|
if (finChapters.isNotEmpty()) {
|
||||||
|
syncChaptersWithSource(db, finChapters, manga, source)
|
||||||
|
withContext(Dispatchers.IO) { updateChapters() }
|
||||||
|
}
|
||||||
|
if (chapterError == null)
|
||||||
|
withContext(Dispatchers.Main) { controller.updateChapters(this@MangaPresenter.chapters) }
|
||||||
|
if (mangaError != null)
|
||||||
|
withContext(Dispatchers.Main) { controller.showError(trimException(mangaError!!)) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -268,12 +342,12 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
fun fetchChaptersFromSource() {
|
fun fetchChaptersFromSource() {
|
||||||
hasRequested = true
|
hasRequested = true
|
||||||
|
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
launch(Dispatchers.IO) {
|
||||||
val chapters = try {
|
val chapters = try {
|
||||||
source.fetchChapterList(manga).toBlocking().single()
|
source.fetchChapterList(manga).toBlocking().single()
|
||||||
}
|
}
|
||||||
catch(e: Exception) {
|
catch(e: Exception) {
|
||||||
controller.showError(trimException(e))
|
withContext(Dispatchers.Main) { controller.showError(trimException(e)) }
|
||||||
return@launch
|
return@launch
|
||||||
} ?: listOf()
|
} ?: listOf()
|
||||||
try {
|
try {
|
||||||
@ -291,4 +365,108 @@ class MangaPresenter(private val controller: MangaChaptersController,
|
|||||||
private fun trimException(e: java.lang.Exception): String {
|
private fun trimException(e: java.lang.Exception): String {
|
||||||
return e.message?.split(": ")?.drop(1)?.joinToString(": ") ?: "Error"
|
return e.message?.split(": ")?.drop(1)?.joinToString(": ") ?: "Error"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bookmarks the given list of chapters.
|
||||||
|
* @param selectedChapters the list of chapters to bookmark.
|
||||||
|
*/
|
||||||
|
fun bookmarkChapters(selectedChapters: List<ChapterItem>, bookmarked: Boolean) {
|
||||||
|
launch(Dispatchers.IO) {
|
||||||
|
selectedChapters.forEach {
|
||||||
|
it.bookmark = bookmarked
|
||||||
|
}
|
||||||
|
db.updateChaptersProgress(selectedChapters).executeAsBlocking()
|
||||||
|
withContext(Dispatchers.Main) { controller.updateChapters(chapters) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the selected chapter list as read/unread.
|
||||||
|
* @param selectedChapters the list of selected chapters.
|
||||||
|
* @param read whether to mark chapters as read or unread.
|
||||||
|
*/
|
||||||
|
fun markChaptersRead(selectedChapters: List<ChapterItem>, read: Boolean) {
|
||||||
|
launch(Dispatchers.IO) {
|
||||||
|
selectedChapters.forEach {
|
||||||
|
it.read = read
|
||||||
|
if (!read) {
|
||||||
|
it.last_page_read = 0
|
||||||
|
it.pages_left = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.updateChaptersProgress(selectedChapters).executeAsBlocking()
|
||||||
|
withContext(Dispatchers.Main) { controller.updateChapters(chapters) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverses the sorting and requests an UI update.
|
||||||
|
*/
|
||||||
|
fun setSortOrder(desend: Boolean) {
|
||||||
|
manga.setChapterOrder(if (desend) Manga.SORT_ASC else Manga.SORT_DESC)
|
||||||
|
db.updateFlags(manga).executeAsBlocking()
|
||||||
|
updateChapters()
|
||||||
|
controller.updateChapters(chapters)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleFavorite(): Boolean {
|
||||||
|
manga.favorite = !manga.favorite
|
||||||
|
db.insertManga(manga).executeAsBlocking()
|
||||||
|
controller.updateHeader()
|
||||||
|
return manga.favorite
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user categories.
|
||||||
|
*
|
||||||
|
* @return List of categories, not including the default category
|
||||||
|
*/
|
||||||
|
fun getCategories(): List<Category> {
|
||||||
|
return db.getCategories().executeAsBlocking()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the given manga to the category.
|
||||||
|
*
|
||||||
|
* @param manga the manga to move.
|
||||||
|
* @param category the selected category, or null for default category.
|
||||||
|
*/
|
||||||
|
fun moveMangaToCategory(manga: Manga, category: Category?) {
|
||||||
|
moveMangaToCategories(manga, listOfNotNull(category))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the given manga to categories.
|
||||||
|
*
|
||||||
|
* @param manga the manga to move.
|
||||||
|
* @param categories the selected categories.
|
||||||
|
*/
|
||||||
|
fun moveMangaToCategories(manga: Manga, categories: List<Category>) {
|
||||||
|
val mc = categories.filter { it.id != 0 }.map { MangaCategory.create(manga, it) }
|
||||||
|
db.setMangaCategories(mc, listOf(manga))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the category id's the manga is in, if the manga is not in a category, returns the default id.
|
||||||
|
*
|
||||||
|
* @param manga the manga to get categories from.
|
||||||
|
* @return Array of category ids the manga is in, if none returns default id
|
||||||
|
*/
|
||||||
|
fun getMangaCategoryIds(manga: Manga): Array<Int> {
|
||||||
|
val categories = db.getCategoriesForManga(manga).executeAsBlocking()
|
||||||
|
return categories.mapNotNull { it.id }.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun confirmDeletion() {
|
||||||
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
|
db.resetMangaInfo(manga).executeAsBlocking()
|
||||||
|
downloadManager.deleteManga(manga, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setFavorite(favorite: Boolean) {
|
||||||
|
if (manga.favorite == favorite) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toggleFavorite()
|
||||||
|
}
|
||||||
}
|
}
|
@ -29,7 +29,9 @@ class ChapterMatHolder(
|
|||||||
|
|
||||||
private fun downloadOrRemoveMenu() {
|
private fun downloadOrRemoveMenu() {
|
||||||
val chapter = adapter.getItem(adapterPosition) ?: return
|
val chapter = adapter.getItem(adapterPosition) ?: return
|
||||||
if (chapter.status != Download.NOT_DOWNLOADED) {
|
if (chapter.status == Download.NOT_DOWNLOADED || chapter.status == Download.ERROR) {
|
||||||
|
adapter.coverListener?.downloadChapter(adapterPosition)
|
||||||
|
} else {
|
||||||
download_button.post {
|
download_button.post {
|
||||||
// Create a PopupMenu, giving it the clicked view for an anchor
|
// Create a PopupMenu, giving it the clicked view for an anchor
|
||||||
val popup = PopupMenu(download_button.context, download_button)
|
val popup = PopupMenu(download_button.context, download_button)
|
||||||
@ -38,8 +40,7 @@ class ChapterMatHolder(
|
|||||||
popup.menuInflater.inflate(R.menu.chapter_download, popup.menu)
|
popup.menuInflater.inflate(R.menu.chapter_download, popup.menu)
|
||||||
|
|
||||||
// Hide download and show delete if the chapter is downloaded
|
// Hide download and show delete if the chapter is downloaded
|
||||||
if (chapter.status != Download.DOWNLOADED) popup.menu.findItem(R.id.action_delete)
|
if (chapter.status != Download.DOWNLOADED) popup.menu.findItem(R.id.action_delete).title = download_button.context.getString(
|
||||||
.title = download_button.context.getString(
|
|
||||||
R.string.action_cancel
|
R.string.action_cancel
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -53,9 +54,6 @@ class ChapterMatHolder(
|
|||||||
popup.show()
|
popup.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
adapter.coverListener?.downloadChapter(adapterPosition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bind(item: ChapterItem, manga: Manga) {
|
override fun bind(item: ChapterItem, manga: Manga) {
|
||||||
@ -113,6 +111,6 @@ class ChapterMatHolder(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
visible()
|
visible()
|
||||||
setDownoadStatus(status, progress)
|
setDownloadStatus(status, progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,10 @@ class ChaptersAdapter(
|
|||||||
fun readNextChapter()
|
fun readNextChapter()
|
||||||
fun downloadChapter(position: Int)
|
fun downloadChapter(position: Int)
|
||||||
fun topCoverHeight(): Int
|
fun topCoverHeight(): Int
|
||||||
fun newestChapterDate(): Long?
|
fun chapterCount(): Int
|
||||||
fun lastChapter(): Float?
|
fun tagClicked(text: String)
|
||||||
fun mangaSource(): Source
|
fun mangaSource(): Source
|
||||||
|
fun showChapterFilter()
|
||||||
|
fun favoriteManga(longPress: Boolean)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,9 +386,9 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
|
|
||||||
fun setLastUpdateDate(date: Date) {
|
fun setLastUpdateDate(date: Date) {
|
||||||
if (date.time != 0L) {
|
if (date.time != 0L) {
|
||||||
manga_last_update?.text = dateFormat.format(date)
|
manga_status?.text = dateFormat.format(date)
|
||||||
} else {
|
} else {
|
||||||
manga_last_update?.text = resources?.getString(R.string.unknown)
|
manga_status?.text = resources?.getString(R.string.unknown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_last_update"
|
android:id="@+id/manga_status"
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
style="@style/TextAppearance.Medium.Body2"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -160,7 +160,7 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"/>
|
app:layout_constraintStart_toStartOf="parent"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_last_update"
|
android:id="@+id/manga_status"
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -168,8 +168,8 @@
|
|||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_last_update"
|
app:layout_constraintBaseline_toBaselineOf="@+id/manga_status"
|
||||||
app:layout_constraintStart_toEndOf="@+id/manga_last_update"
|
app:layout_constraintStart_toEndOf="@+id/manga_status"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -179,7 +179,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/manga_info_status_label"
|
android:text="@string/manga_info_status_label"
|
||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_last_update"
|
app:layout_constraintTop_toBottomOf="@+id/manga_status"
|
||||||
app:layout_constraintStart_toStartOf="parent"/>
|
app:layout_constraintStart_toStartOf="parent"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
135
app/src/main/res/layout/chapter_sort_bottom_sheet.xml
Normal file
135
app/src/main/res/layout/chapter_sort_bottom_sheet.xml
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/diplay_bottom_sheet"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/settings_scroll_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/bottom_sheet"
|
||||||
|
style="@style/BottomSheetDialogTheme"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_bottom_sheet_dialog_fragment"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:text="@string/action_sort" />
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/sort_group"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp">
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/sort_newest"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Newest first" />
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/sort_oldest"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:text="Oldest first" />
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/sort_by_source"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:text="Sort by source's order" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/show_titles"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:text="Hide chapter titles" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:text="@string/action_filter" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/show_all"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:text="Show All" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/show_read"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:text="Show read chapters" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/show_unread"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:text="Show unread chapters" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/show_download"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:text="Show downloaded chapters" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/show_bookmark"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:text="Show bookmarked chapters" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/close_button"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:background="@drawable/round_ripple"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/action_close"
|
||||||
|
android:focusable="true"
|
||||||
|
android:src="@drawable/ic_close_white_24dp"
|
||||||
|
android:tint="@color/gray_button" />
|
||||||
|
</FrameLayout>
|
@ -28,6 +28,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/download_button"
|
app:layout_constraintEnd_toStartOf="@id/download_button"
|
||||||
|
@ -25,11 +25,11 @@
|
|||||||
android:id="@+id/true_backdrop"
|
android:id="@+id/true_backdrop"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintHeight_min="200dp"
|
app:layout_constraintBottom_toBottomOf="@id/bottom_line"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHeight_min="200dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/bottom_line"
|
|
||||||
app:layout_constraintVertical_bias="0.0"
|
app:layout_constraintVertical_bias="0.0"
|
||||||
tools:background="@color/material_red_400" />
|
tools:background="@color/material_red_400" />
|
||||||
|
|
||||||
@ -39,10 +39,10 @@
|
|||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:alpha="0.1"
|
android:alpha="0.1"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/true_backdrop"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@+id/true_backdrop"
|
app:layout_constraintTop_toTopOf="@+id/true_backdrop"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/true_backdrop"
|
|
||||||
tools:src="@mipmap/ic_launcher" />
|
tools:src="@mipmap/ic_launcher" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@ -76,9 +76,9 @@
|
|||||||
android:id="@+id/manga_layout"
|
android:id="@+id/manga_layout"
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/guideline"
|
app:layout_constraintBottom_toBottomOf="@id/guideline"
|
||||||
app:layout_constraintDimensionRatio="h,7:10"
|
app:layout_constraintDimensionRatio="h,7:10"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
@ -89,13 +89,13 @@
|
|||||||
android:id="@+id/cover_card"
|
android:id="@+id/cover_card"
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/guideline"
|
app:layout_constraintBottom_toBottomOf="@id/guideline"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/true_backdrop"
|
|
||||||
app:layout_constraintEnd_toEndOf="@id/manga_layout"
|
app:layout_constraintEnd_toEndOf="@id/manga_layout"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/top_view"
|
app:layout_constraintTop_toBottomOf="@id/top_view"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/true_backdrop"
|
||||||
app:layout_constraintVertical_bias="1.0">
|
app:layout_constraintVertical_bias="1.0">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@ -112,7 +112,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_full_title"
|
android:id="@+id/manga_full_title"
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline5"
|
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
@ -129,9 +129,10 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_author"
|
android:id="@+id/manga_author"
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
android:textAppearance="@style/TextAppearance.Regular.Body1.SemiBold"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:text="@string/manga_info_author_label"
|
android:text="@string/manga_info_author_label"
|
||||||
@ -141,19 +142,19 @@
|
|||||||
app:layout_constraintTop_toBottomOf="@+id/manga_full_title" />
|
app:layout_constraintTop_toBottomOf="@+id/manga_full_title" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_last_update"
|
android:id="@+id/manga_status"
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
android:text="@string/manga_info_latest_data_label"
|
android:text="@string/manga_info_latest_data_label"
|
||||||
tools:text="Last updated 3 days ago"
|
|
||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
app:layout_constraintStart_toStartOf="@id/manga_full_title"
|
app:layout_constraintStart_toStartOf="@id/manga_full_title"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_author" />
|
app:layout_constraintTop_toBottomOf="@+id/manga_author"
|
||||||
|
tools:text="Completed" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/manga_status_source"
|
android:id="@+id/manga_source"
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -162,8 +163,8 @@
|
|||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="@id/manga_full_title"
|
app:layout_constraintStart_toStartOf="@id/manga_full_title"
|
||||||
app:layout_constraintTop_toBottomOf="@id/manga_last_update"
|
app:layout_constraintTop_toBottomOf="@id/manga_status"
|
||||||
tools:text="Completed • Mangadex (EN)" />
|
tools:text="Mangadex (EN)" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
<androidx.constraintlayout.widget.Barrier
|
||||||
android:id="@+id/bottom_line"
|
android:id="@+id/bottom_line"
|
||||||
@ -172,7 +173,7 @@
|
|||||||
android:layout_margin="6dp"
|
android:layout_margin="6dp"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:barrierDirection="bottom"
|
app:barrierDirection="bottom"
|
||||||
app:constraint_referenced_ids="manga_status_source,manga_layout,cover_card" />
|
app:constraint_referenced_ids="manga_source,manga_layout,cover_card" />
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -181,26 +182,27 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="14dp"
|
android:layout_marginTop="14dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
app:layout_constraintBottom_toTopOf="@id/manga_summary_label"
|
app:layout_constraintBottom_toTopOf="@id/manga_summary_label"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/bottom_line">
|
app:layout_constraintTop_toBottomOf="@id/bottom_line">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
style="@style/Theme.Widget.Button.RounededOutline"
|
|
||||||
android:id="@+id/favorite_button"
|
android:id="@+id/favorite_button"
|
||||||
|
style="@style/Theme.Widget.Button.RounededOutline"
|
||||||
android:text="@string/add_to_library"
|
android:text="@string/add_to_library"
|
||||||
app:icon="@drawable/ic_add_to_library_24dp" />
|
app:icon="@drawable/ic_add_to_library_24dp" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/track_button"
|
||||||
style="@style/Theme.Widget.Button.RounededOutline"
|
style="@style/Theme.Widget.Button.RounededOutline"
|
||||||
android:layout_marginStart="6dp"
|
android:layout_marginStart="6dp"
|
||||||
android:id="@+id/track_button"
|
|
||||||
android:text="@string/manga_tracking_tab"
|
android:text="@string/manga_tracking_tab"
|
||||||
app:icon="@drawable/ic_sync_black_24dp" />
|
app:icon="@drawable/ic_sync_black_24dp" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/download_button"
|
android:id="@+id/edit_button"
|
||||||
style="@style/Theme.Widget.CustomImageButton"
|
style="@style/Theme.Widget.CustomImageButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -209,8 +211,7 @@
|
|||||||
android:layout_marginEnd="6dp"
|
android:layout_marginEnd="6dp"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:src="@drawable/ic_edit_white_24dp"
|
android:src="@drawable/ic_edit_white_24dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/chapters_title"
|
app:layout_constraintBottom_toBottomOf="@id/chapters_title" />
|
||||||
app:layout_constraintEnd_toStartOf="@id/sort_button" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
@ -235,6 +236,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:maxLines="3"
|
android:maxLines="3"
|
||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
@ -245,7 +248,8 @@
|
|||||||
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." />
|
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="75dp"
|
android:id="@+id/more_bg_gradient"
|
||||||
|
android:layout_width="50dp"
|
||||||
android:layout_height="20dp"
|
android:layout_height="20dp"
|
||||||
android:layout_marginEnd="30dp"
|
android:layout_marginEnd="30dp"
|
||||||
android:background="@drawable/full_gradient"
|
android:background="@drawable/full_gradient"
|
||||||
@ -254,26 +258,39 @@
|
|||||||
app:layout_constraintEnd_toEndOf="@id/more_button" />
|
app:layout_constraintEnd_toEndOf="@id/more_button" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
|
android:id="@+id/more_bg_solid"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="20dp"
|
android:layout_height="20dp"
|
||||||
android:layout_marginStart="20dp"
|
android:layout_marginStart="45dp"
|
||||||
android:background="?android:attr/colorBackground"
|
android:background="?android:attr/colorBackground"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/manga_summary"
|
app:layout_constraintBottom_toBottomOf="@id/manga_summary"
|
||||||
app:layout_constraintEnd_toEndOf="@id/more_button"
|
app:layout_constraintEnd_toEndOf="@id/more_button"
|
||||||
app:layout_constraintStart_toStartOf="@id/more_button" />
|
app:layout_constraintStart_toStartOf="@id/more_button" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/more_guide"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="15sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/manga_summary"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/manga_summary"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/more_button"
|
android:id="@+id/more_button"
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
style="@style/Theme.Widget.Button.TextButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="19.5sp"
|
android:text="@string/more"
|
||||||
android:text="More"
|
android:layout_marginEnd="8dp"
|
||||||
android:textAllCaps="false"
|
android:textAlignment="textEnd"
|
||||||
android:textColor="?colorAccent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="@id/manga_summary"
|
app:layout_constraintBottom_toBottomOf="@id/more_guide"
|
||||||
app:layout_constraintTop_toTopOf="@id/manga_summary"
|
app:rippleColor="@null" />
|
||||||
app:rippleColor="@color/gray_button" />
|
|
||||||
|
<androidx.constraintlayout.widget.Group
|
||||||
|
android:id="@+id/more_button_group"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:constraint_referenced_ids="more_button,more_bg_gradient,more_bg_solid" />
|
||||||
|
|
||||||
<me.gujun.android.taggroup.TagGroup
|
<me.gujun.android.taggroup.TagGroup
|
||||||
android:id="@+id/manga_genres_tags"
|
android:id="@+id/manga_genres_tags"
|
||||||
@ -289,58 +306,74 @@
|
|||||||
app:atg_borderStrokeWidth="1dp"
|
app:atg_borderStrokeWidth="1dp"
|
||||||
app:atg_textColor="@color/md_blue_A400"
|
app:atg_textColor="@color/md_blue_A400"
|
||||||
app:layout_constrainedHeight="true"
|
app:layout_constrainedHeight="true"
|
||||||
app:layout_constraintBottom_toTopOf="@id/start_reading_button"
|
app:layout_constraintBottom_toTopOf="@id/less_button"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/manga_summary" />
|
app:layout_constraintTop_toBottomOf="@id/manga_summary" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/less_button"
|
||||||
|
style="@style/Theme.Widget.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/less"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/start_reading_button"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/manga_genres_tags"
|
||||||
|
app:rippleColor="@null" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/start_reading_button"
|
android:id="@+id/start_reading_button"
|
||||||
style="@style/Theme.Widget.Button.Primary"
|
style="@style/Theme.Widget.Button.Primary"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:text="@string/start_reading"
|
android:text="@string/start_reading"
|
||||||
app:layout_constraintBottom_toTopOf="@id/chapters_title"
|
app:layout_constraintBottom_toTopOf="@id/chapters_title"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_genres_tags"
|
app:layout_constraintTop_toBottomOf="@+id/less_button"
|
||||||
tools:text="Continue Reading Chapter 17.1" />
|
tools:text="Continue Reading Chapter 17.1" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/chapters_title"
|
android:id="@+id/chapters_title"
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline6"
|
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="18dp"
|
android:layout_marginTop="18dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
android:text="@string/chapters"
|
android:text="@string/chapters"
|
||||||
android:textSize="17sp"
|
android:textSize="17sp"
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="@id/manga_summary_label"
|
app:layout_constraintStart_toStartOf="@id/manga_summary_label"
|
||||||
app:layout_constraintTop_toBottomOf="@id/start_reading_button" />
|
app:layout_constraintTop_toBottomOf="@id/start_reading_button"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/filters_text"/>
|
||||||
<ImageView
|
|
||||||
android:id="@+id/sort_button"
|
|
||||||
style="@style/Theme.Widget.CustomImageButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:src="@drawable/ic_swap_vert_white_24dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/chapters_title"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/filter_button"
|
android:id="@+id/filter_button"
|
||||||
style="@style/Theme.Widget.CustomImageButton"
|
style="@style/Theme.Widget.CustomImageButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="6dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:src="@drawable/ic_filter_list_white_24dp"
|
android:src="@drawable/ic_filter_list_white_24dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/chapters_title"
|
app:layout_constraintBottom_toBottomOf="@id/chapters_title"
|
||||||
app:layout_constraintEnd_toStartOf="@id/sort_button" />
|
app:layout_constraintTop_toTopOf="@id/chapters_title"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/filters_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="6dp"
|
||||||
|
android:padding="5dp"
|
||||||
|
tools:text="Read"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/filter_button"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/filter_button"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/filter_button" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -172,7 +172,7 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_last_update"
|
android:id="@+id/manga_status"
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
style="@style/TextAppearance.Medium.Body2"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -182,7 +182,7 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"/>
|
app:layout_constraintStart_toStartOf="parent"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_last_update"
|
android:id="@+id/manga_status"
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -190,8 +190,8 @@
|
|||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_last_update"
|
app:layout_constraintBaseline_toBaselineOf="@+id/manga_status"
|
||||||
app:layout_constraintStart_toEndOf="@+id/manga_last_update"
|
app:layout_constraintStart_toEndOf="@+id/manga_status"
|
||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -201,7 +201,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/manga_info_status_label"
|
android:text="@string/manga_info_status_label"
|
||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_last_update"
|
app:layout_constraintTop_toBottomOf="@+id/manga_status"
|
||||||
app:layout_constraintStart_toStartOf="parent"/>
|
app:layout_constraintStart_toStartOf="parent"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
22
app/src/main/res/menu/chapters_mat_single.xml
Normal file
22
app/src/main/res/menu/chapters_mat_single.xml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:id="@+id/action_bookmark"
|
||||||
|
android:title="@string/action_bookmark"
|
||||||
|
android:visible="true" />
|
||||||
|
|
||||||
|
<item android:id="@+id/action_remove_bookmark"
|
||||||
|
android:title="@string/action_remove_bookmark"
|
||||||
|
android:visible="true" />
|
||||||
|
|
||||||
|
<item android:id="@+id/action_mark_as_read"
|
||||||
|
android:title="@string/action_mark_as_read" />
|
||||||
|
|
||||||
|
<item android:id="@+id/action_mark_as_unread"
|
||||||
|
android:title="@string/action_mark_as_unread" />
|
||||||
|
|
||||||
|
<item android:id="@+id/action_mark_multiple"
|
||||||
|
android:title="@string/action_mark_multiple"/>
|
||||||
|
|
||||||
|
</menu>
|
@ -70,6 +70,7 @@
|
|||||||
<string name="action_mark_as_read">Mark as read</string>
|
<string name="action_mark_as_read">Mark as read</string>
|
||||||
<string name="action_mark_as_unread">Mark as unread</string>
|
<string name="action_mark_as_unread">Mark as unread</string>
|
||||||
<string name="action_mark_previous_as_read">Mark previous as read</string>
|
<string name="action_mark_previous_as_read">Mark previous as read</string>
|
||||||
|
<string name="action_mark_multiple">Mark multiple</string>
|
||||||
<string name="action_download">Download</string>
|
<string name="action_download">Download</string>
|
||||||
<string name="action_bookmark">Bookmark</string>
|
<string name="action_bookmark">Bookmark</string>
|
||||||
<string name="action_remove_bookmark">Remove bookmark</string>
|
<string name="action_remove_bookmark">Remove bookmark</string>
|
||||||
@ -224,7 +225,7 @@
|
|||||||
<string name="lock_always">Always</string>
|
<string name="lock_always">Always</string>
|
||||||
<string name="lock_never">Never</string>
|
<string name="lock_never">Never</string>
|
||||||
<plurals name="lock_after_mins">
|
<plurals name="lock_after_mins">
|
||||||
<item quantity="one">After %1$s minutes</item>
|
<item quantity="one">After %1$s minute</item>
|
||||||
<item quantity="other">After %1$s minutes</item>
|
<item quantity="other">After %1$s minutes</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="search_hint">Search title, tags, source</string>
|
<string name="search_hint">Search title, tags, source</string>
|
||||||
@ -500,6 +501,11 @@
|
|||||||
<string name="copied_to_clipboard">%1$s copied to clipboard</string>
|
<string name="copied_to_clipboard">%1$s copied to clipboard</string>
|
||||||
<string name="source_not_installed">Source not installed: %1$s</string>
|
<string name="source_not_installed">Source not installed: %1$s</string>
|
||||||
<string name="about_this">About this %1$s</string>
|
<string name="about_this">About this %1$s</string>
|
||||||
|
<plurals name="chapters">
|
||||||
|
<item quantity="one">%1$d chapter</item>
|
||||||
|
<item quantity="other">%1$d chapters</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="no_description">No description</string>
|
||||||
|
|
||||||
<!-- Manga chapters fragment -->
|
<!-- Manga chapters fragment -->
|
||||||
<string name="start_reading">Start reading</string>
|
<string name="start_reading">Start reading</string>
|
||||||
@ -697,5 +703,7 @@
|
|||||||
<string name="reset_tags">Reset Tags</string>
|
<string name="reset_tags">Reset Tags</string>
|
||||||
<string name="display_as">Display as</string>
|
<string name="display_as">Display as</string>
|
||||||
<string name="action_auto">Auto</string>
|
<string name="action_auto">Auto</string>
|
||||||
|
<string name="more">More</string>
|
||||||
|
<string name="less">Less</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -252,6 +252,12 @@
|
|||||||
<item name="android:letterSpacing">0.0</item>
|
<item name="android:letterSpacing">0.0</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="Theme.Widget.Button.TextButton" parent="Widget.MaterialComponents.Button.TextButton">
|
||||||
|
<item name="android:textAllCaps">false</item>
|
||||||
|
<item name="rippleColor">@color/fullRippleColor</item>
|
||||||
|
<item name="android:textColor">?colorAccent</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Widget.CustomImageButton">
|
<style name="Theme.Widget.CustomImageButton">
|
||||||
<item name="android:background">@drawable/round_ripple</item>
|
<item name="android:background">@drawable/round_ripple</item>
|
||||||
<item name="android:clickable">true</item>
|
<item name="android:clickable">true</item>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user