From c2b1c3f63f8d6a2ab7787bbe5bb8e3b0c226018f Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 1 Mar 2020 17:44:24 -0800 Subject: [PATCH] Added new Manga controller to library --- app/build.gradle | 1 + .../tachiyomi/ui/download/DownloadButton.kt | 77 ++++ .../tachiyomi/ui/library/LibraryController.kt | 5 +- .../tachiyomi/ui/manga/MangaChapterHolder.kt | 20 + .../ui/manga/MangaChaptersController.kt | 363 ++++++++++++++++++ .../tachiyomi/ui/manga/MangaHeaderHolder.kt | 93 +++++ .../tachiyomi/ui/manga/MangaPresenter.kt | 258 +++++++++++++ .../ui/manga/chapter/ChapterHolder.kt | 6 +- .../tachiyomi/ui/manga/chapter/ChapterItem.kt | 33 +- .../ui/manga/chapter/ChapterMatHolder.kt | 116 ++++++ .../ui/manga/chapter/ChaptersAdapter.kt | 14 +- .../ui/setting/SettingsController.kt | 16 +- app/src/main/res/drawable/border_circle.xml | 13 + app/src/main/res/drawable/circle_progress.xml | 20 + app/src/main/res/drawable/filled_circle.xml | 13 + app/src/main/res/drawable/gradient_shape.xml | 2 +- .../ic_open_in_webview_white_24dp.xml | 9 + app/src/main/res/drawable/round_ripple.xml | 2 +- .../main/res/layout/big_manga_controller.xml | 331 +--------------- .../main/res/layout/catalogue_controller.xml | 1 + .../catalogue_global_search_controller.xml | 1 + .../main/res/layout/catalogue_grid_item.xml | 1 + .../res/layout/catalogue_main_controller.xml | 1 + .../res/layout/catalogue_recycler_autofit.xml | 7 +- .../main/res/layout/categories_controller.xml | 1 + .../main/res/layout/chapters_controller.xml | 1 + app/src/main/res/layout/chapters_mat_item.xml | 44 +++ app/src/main/res/layout/download_button.xml | 49 +++ .../main/res/layout/download_controller.xml | 1 + .../main/res/layout/extension_controller.xml | 1 + .../layout/extension_detail_controller.xml | 1 + .../res/layout/library_list_controller.xml | 1 + app/src/main/res/layout/main_activity.xml | 5 +- app/src/main/res/layout/manga_header_item.xml | 348 +++++++++++++++++ .../main/res/layout/manga_info_controller.xml | 4 +- .../main/res/layout/migration_controller.xml | 1 + .../res/layout/migration_list_controller.xml | 1 + .../res/layout/pre_migration_controller.xml | 1 + .../res/layout/recent_chapters_controller.xml | 1 + .../res/layout/recently_read_controller.xml | 1 + app/src/main/res/menu/chapter_download.xml | 6 + app/src/main/res/values/strings.xml | 5 + app/src/main/res/values/styles.xml | 25 ++ 43 files changed, 1560 insertions(+), 340 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadButton.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChapterHolder.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChaptersController.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaHeaderHolder.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterMatHolder.kt create mode 100644 app/src/main/res/drawable/border_circle.xml create mode 100644 app/src/main/res/drawable/circle_progress.xml create mode 100644 app/src/main/res/drawable/filled_circle.xml create mode 100644 app/src/main/res/drawable/ic_open_in_webview_white_24dp.xml create mode 100644 app/src/main/res/layout/chapters_mat_item.xml create mode 100644 app/src/main/res/layout/download_button.xml create mode 100644 app/src/main/res/layout/manga_header_item.xml create mode 100644 app/src/main/res/menu/chapter_download.xml diff --git a/app/build.gradle b/app/build.gradle index df3fcf40b5..407eb03ad1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -119,6 +119,7 @@ dependencies { implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.browser:browser:1.2.0' implementation 'androidx.biometric:biometric:1.0.1' + implementation 'androidx.palette:palette:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadButton.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadButton.kt new file mode 100644 index 0000000000..eeb22a494c --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadButton.kt @@ -0,0 +1,77 @@ +package eu.kanade.tachiyomi.ui.download + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.widget.FrameLayout +import androidx.core.content.ContextCompat +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.download.model.Download +import eu.kanade.tachiyomi.util.system.getResourceColor +import eu.kanade.tachiyomi.util.view.gone +import eu.kanade.tachiyomi.util.view.visible +import kotlinx.android.synthetic.main.download_button.view.* + +class DownloadButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) + : FrameLayout(context, attrs) { + + private val activeColor = context.getResourceColor(R.attr.colorAccent) + private val disabledColor = ContextCompat.getColor(context, + R.color.material_on_surface_disabled) + private val downloadedColor = ContextCompat.getColor(context, + R.color.material_green_800) + private val errorColor = ContextCompat.getColor(context, + R.color.red_error) + private val filledCircle = ContextCompat.getDrawable(context, + R.drawable.filled_circle)?.mutate() + private val borderCircle = ContextCompat.getDrawable(context, + R.drawable.border_circle)?.mutate() + + + fun setDownoadStatus(state: Int, progress: Int = 0) { + when (state) { + Download.NOT_DOWNLOADED -> { + download_border.visible() + download_progress.gone() + download_progress_indeterminate.gone() + download_border.setImageDrawable(borderCircle) + download_border.drawable.setTint(activeColor) + download_icon.drawable.setTint(activeColor) + } + Download.QUEUE -> { + download_border.gone() + download_progress.gone() + download_progress_indeterminate.visible() + download_progress.isIndeterminate = true + download_icon.drawable.setTint(disabledColor) + } + Download.DOWNLOADING -> { + download_border.visible() + download_progress.visible() + download_progress_indeterminate.gone() + download_border.setImageDrawable(borderCircle) + download_progress.isIndeterminate = false + download_progress.progress = progress + download_border.drawable.setTint(disabledColor) + download_progress.progressDrawable?.setTint(downloadedColor) + download_icon.drawable.setTint(disabledColor) + } + Download.DOWNLOADED -> { + download_progress.gone() + download_border.visible() + download_progress_indeterminate.gone() + download_border.setImageDrawable(filledCircle) + download_border.drawable.setTint(downloadedColor) + download_icon.drawable.setTint(Color.WHITE) + } + Download.ERROR -> { + download_progress.gone() + download_border.visible() + download_progress_indeterminate.gone() + download_border.setImageDrawable(borderCircle) + download_border.drawable.setTint(errorColor) + download_icon.drawable.setTint(errorColor) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 3a38b29a9b..06160b57a2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -43,7 +43,7 @@ import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.download.DownloadController import eu.kanade.tachiyomi.ui.library.filter.SortFilterBottomSheet import eu.kanade.tachiyomi.ui.main.MainActivity -import eu.kanade.tachiyomi.ui.manga.MangaController +import eu.kanade.tachiyomi.ui.manga.MangaChaptersController import eu.kanade.tachiyomi.ui.migration.MigrationInterface import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController @@ -628,7 +628,8 @@ open class LibraryController( } fun openManga(manga: Manga, startY: Float?) { - router.pushController(MangaController(manga, startY).withFadeTransaction()) + router.pushController(MangaChaptersController(manga).withFadeTransaction()) + // router.pushController(MangaController(manga, startY).withFadeTransaction()) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChapterHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChapterHolder.kt new file mode 100644 index 0000000000..785c5453ce --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChapterHolder.kt @@ -0,0 +1,20 @@ +package eu.kanade.tachiyomi.ui.manga + +import android.view.View +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder +import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem +import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter + +abstract class MangaChapterHolder( + private val view: View, + private val adapter: ChaptersAdapter +) : BaseFlexibleViewHolder(view, adapter) { + /** + * Method called from [ChaptersAdapter.onBindViewHolder]. It updates the data for this + * holder with the given manga. + * + * @param item the manga item to bind. + */ + abstract fun bind(item: ChapterItem, manga: Manga) +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChaptersController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChaptersController.kt new file mode 100644 index 0000000000..05407220ba --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaChaptersController.kt @@ -0,0 +1,363 @@ +package eu.kanade.tachiyomi.ui.manga + +import android.animation.ValueAnimator +import android.content.Intent +import android.content.res.Configuration +import android.graphics.Color +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.os.Build +import android.os.Bundle +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.view.ActionMode +import androidx.core.graphics.ColorUtils +import androidx.palette.graphics.Palette +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.vectordrawable.graphics.drawable.ArgbEvaluator +import com.bluelinelabs.conductor.ControllerChangeHandler +import com.bluelinelabs.conductor.ControllerChangeType +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition +import com.bumptech.glide.signature.ObjectKey +import com.google.android.material.snackbar.BaseTransientBottomBar +import com.google.android.material.snackbar.Snackbar +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.database.models.MangaImpl +import eu.kanade.tachiyomi.data.glide.GlideApp +import eu.kanade.tachiyomi.data.notification.NotificationReceiver +import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.ui.base.controller.BaseController +import eu.kanade.tachiyomi.ui.catalogue.CatalogueController +import eu.kanade.tachiyomi.ui.main.MainActivity +import eu.kanade.tachiyomi.ui.main.SearchActivity +import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem +import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter +import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate +import eu.kanade.tachiyomi.util.system.getResourceColor +import eu.kanade.tachiyomi.util.view.getText +import eu.kanade.tachiyomi.util.view.snack +import kotlinx.android.synthetic.main.big_manga_controller.* +import kotlinx.android.synthetic.main.main_activity.* +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +class MangaChaptersController : BaseController, + ActionMode.Callback, + FlexibleAdapter.OnItemClickListener, + ChaptersAdapter.MangaHeaderInterface { + + constructor(manga: Manga?, + fromCatalogue: Boolean = false, + smartSearchConfig: CatalogueController.SmartSearchConfig? = null, + update: Boolean = false) : super(Bundle().apply { + putLong(MangaController.MANGA_EXTRA, manga?.id ?: 0) + putBoolean(MangaController.FROM_CATALOGUE_EXTRA, fromCatalogue) + putParcelable(MangaController.SMART_SEARCH_CONFIG_EXTRA, smartSearchConfig) + putBoolean(MangaController.UPDATE_EXTRA, update) + }) { + this.manga = manga + if (manga != null) { + source = Injekt.get().getOrStub(manga.source) + } + } + + constructor(mangaId: Long) : this( + Injekt.get().getManga(mangaId).executeAsBlocking()) + + constructor(bundle: Bundle) : this(bundle.getLong(MangaController.MANGA_EXTRA)) { + val notificationId = bundle.getInt("notificationId", -1) + val context = applicationContext ?: return + if (notificationId > -1) NotificationReceiver.dismissNotification( + context, notificationId, bundle.getInt("groupId", 0) + ) + } + + private var manga: Manga? = null + private var source: Source? = null + var colorAnimator:ValueAnimator? = null + lateinit var presenter:MangaPresenter + var coverColor:Int? = null + var toolbarIsColored = false + private var snack: Snackbar? = null + + /** + * Adapter containing a list of chapters. + */ + private var adapter: ChaptersAdapter? = null + + init { + setHasOptionsMenu(true) + } + + override fun getTitle(): String? { + return if (toolbarIsColored) manga?.currentTitle() else null + } + + override fun onViewCreated(view: View) { + super.onViewCreated(view) + coverColor = null + if (!::presenter.isInitialized) presenter = MangaPresenter(this, manga!!, source!!) + + // Init RecyclerView and adapter + adapter = ChaptersAdapter(this, view.context) + //setReadingDrawable() + + recycler.adapter = adapter + recycler.layoutManager = LinearLayoutManager(view.context) + recycler.addItemDecoration( + DividerItemDecoration( + view.context, + DividerItemDecoration.VERTICAL + ) + ) + recycler.setHasFixedSize(true) + + presenter.onCreate() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + recycler.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY -> + val atTop = + ((recycler.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() == 0) + if ((!atTop && !toolbarIsColored) || (atTop && toolbarIsColored)) { + toolbarIsColored = !atTop + colorAnimator?.cancel() + val color = + coverColor ?: activity!!.getResourceColor(android.R.attr.colorPrimary) + val colorFrom = ColorUtils.setAlphaComponent( + color, if (toolbarIsColored) 0 else 255 + ) + val colorTo = ColorUtils.setAlphaComponent( + color, if (toolbarIsColored) 255 else 0 + ) + 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() + val isCurrentController = router?.backstack?.lastOrNull()?.controller() == this + if (isCurrentController) setTitle() + } + } + } + GlideApp.with(view.context).load(manga) + .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) + .signature(ObjectKey(MangaImpl.getLastCoverFetch(manga!!.id!!).toString())) + .into(object : CustomTarget() { + override fun onResourceReady(resource: Drawable, + transition: Transition? + ) { + Palette.from( + (resource as BitmapDrawable).bitmap).generate { + if (recycler == null) return@generate + val currentNightMode = + recycler.resources!!.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK + val colorBack = view.context.getResourceColor( + android.R.attr.colorBackground + ) + val backDropColor = + (if (currentNightMode == Configuration.UI_MODE_NIGHT_NO) it?.getLightMutedColor( + colorBack + ) + else it?.getDarkMutedColor(colorBack)) ?: colorBack + onCoverLoaded(backDropColor) + (recycler.findViewHolderForItemId(-1) as? MangaHeaderHolder) + ?.setBackDrop(backDropColor) + if (toolbarIsColored) + (activity as MainActivity).toolbar.setBackgroundColor(backDropColor) + } + } + + override fun onLoadCleared(placeholder: Drawable?) { } + }) + //adapter?.fastScroller = fast_scroller + } + + override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) { + super.onChangeStarted(handler, type) + if (type == ControllerChangeType.PUSH_ENTER || type == ControllerChangeType.POP_ENTER) { + (activity as MainActivity).appbar.setBackgroundColor(Color.TRANSPARENT) + (activity as MainActivity).toolbar.setBackgroundColor(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 { + topMargin = insetTop + } + + (activity)?.navigationView?.updateLayoutParams { + bottomMargin = insetBottom + } + }*/ + + // + //(activity as MainActivity).toolbar.setBackgroundColor(Color.TRANSPARENT) + //(activity as MainActivity).appbar.gone() + } + else if (type == ControllerChangeType.PUSH_EXIT || type == ControllerChangeType.POP_EXIT) { + colorAnimator?.cancel() + + (activity as MainActivity).toolbar.setBackgroundColor(activity?.getResourceColor( + android.R.attr.colorPrimary + ) ?: 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 { + topMargin = 0 + } + (activity as MainActivity).navigationView.updateLayoutParams { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + bottomMargin = 0 + } + }*/ + //(activity as MainActivity).appbar.background = null +// (activity as AppCompatActivity).supportActionBar?.show() + } + } + + + fun updateChapters(chapters: List) { + if (presenter.chapters.isEmpty()) { + //initialFetchChapters() + } + adapter?.updateDataSet(listOf(ChapterItem(Chapter.create(), manga!!)) + chapters) + } + + override fun onItemClick(view: View?, position: Int): Boolean { + val adapter = adapter ?: return false + val chapter = adapter.getItem(position)?.chapter ?: return false + if (!chapter.isRecognizedNumber) return false + /*if (actionMode != null && adapter.mode == SelectableAdapter.Mode.MULTI) { + lastClickPosition = position + toggleSelection(position) + return true + } else {*/ + openChapter(chapter) + return false + //} + } + + fun openChapter(chapter: Chapter, hasAnimation: Boolean = false) { + val activity = activity ?: return + val intent = ReaderActivity.newIntent(activity, manga!!, chapter) + if (hasAnimation) { + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) + } + startActivity(intent) + } + + fun getStatusBarHeight(): Int { + var result = 0 + val resourceId = resources!!.getIdentifier("status_bar_height", "dimen", "android") + if (resourceId > 0) { + result = resources!!.getDimensionPixelSize(resourceId) + } + return result + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + inflater.inflate(R.menu.chapters, menu) + } + + override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View { + return inflater.inflate(R.layout.big_manga_controller, container, false) + } + + override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { + return true + } + + override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean { + return true + + } + + override fun onDestroyActionMode(mode: ActionMode?) { + + } + + override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean { + return true + + } + + fun onCoverLoaded(color: Int) { + if (view == null) return + coverColor = color + activity?.window?.statusBarColor = color + } + + override fun coverColor(): Int? = coverColor + + override fun nextChapter(): Chapter? { + return presenter.getNextUnreadChapter() + } + + override fun readNextChapter() { + if (activity is SearchActivity && presenter.isLockedFromSearch) { + SecureActivityDelegate.promptLockIfNeeded(activity) + return + } + val item = presenter.getNextUnreadChapter() + if (item != null) { + openChapter(item.chapter) + } else if (snack == null || snack?.getText() != view?.context?.getString( + R.string.no_next_chapter)) { + snack = view?.snack(R.string.no_next_chapter, Snackbar.LENGTH_LONG) { + addCallback(object : BaseTransientBottomBar.BaseCallback() { + override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { + super.onDismissed(transientBottomBar, event) + if (snack == transientBottomBar) snack = null + } + }) + } + } + } + + override fun downloadChapter(position: Int) { + val adapter = adapter ?: return + val chapter = adapter.getItem(position) ?: return + if (!chapter.isRecognizedNumber) return + if (chapter.isDownloaded) { + presenter.deleteChapters(listOf(chapter)) + } + else presenter.downloadChapters(listOf(chapter)) + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaHeaderHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaHeaderHolder.kt new file mode 100644 index 0000000000..f3eb985926 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaHeaderHolder.kt @@ -0,0 +1,93 @@ +package eu.kanade.tachiyomi.ui.manga + +import android.content.res.ColorStateList +import android.graphics.Color +import android.view.View +import androidx.core.content.ContextCompat +import androidx.core.graphics.ColorUtils +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.signature.ObjectKey +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.database.models.MangaImpl +import eu.kanade.tachiyomi.data.glide.GlideApp +import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem +import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter +import eu.kanade.tachiyomi.util.system.getResourceColor +import eu.kanade.tachiyomi.util.view.visibleIf +import kotlinx.android.synthetic.main.manga_header_item.* + +class MangaHeaderHolder( + private val view: View, + private val adapter: ChaptersAdapter +) : MangaChapterHolder(view, adapter) { + + init { + start_reading_button.setOnClickListener { adapter.coverListener?.readNextChapter() } + } + + override fun bind(item: ChapterItem, manga: Manga) { + manga_title.text = manga.currentTitle() + if (manga.currentAuthor() == manga.currentArtist() || + manga.currentArtist().isNullOrBlank()) + manga_author.text = manga.currentAuthor() + else { + manga_author.text = "${manga.currentAuthor()?.trim()}, ${manga.currentArtist()}" + } + manga_summary.text = manga.currentDesc() + manga_summary_label.text = "About this ${if (manga.mangaType() == Manga.TYPE_MANGA) "Manga" + else "Manhwa"}" + with(favorite_button) { + icon = ContextCompat.getDrawable( + itemView.context, when { + item.isLocked -> R.drawable.ic_lock_white_24dp + manga.favorite -> R.drawable.ic_bookmark_white_24dp + else -> R.drawable.ic_add_to_library_24dp + } + ) + text = itemView.resources.getString( + when { + item.isLocked -> R.string.unlock + manga.favorite -> R.string.in_library + else -> R.string.add_to_library + } + ) + backgroundTintList = + ContextCompat.getColorStateList(context, android.R.color.transparent) + if (!item.isLocked && manga.favorite) { + backgroundTintList = + ColorStateList.valueOf( + ColorUtils.setAlphaComponent( + context.getResourceColor(R.attr.colorAccent), 75)) + strokeColor = ColorStateList.valueOf(Color.TRANSPARENT) + } + } + true_backdrop.setBackgroundColor(adapter.coverListener?.coverColor() ?: + itemView.context.getResourceColor(android.R.attr.colorBackground)) + + with(start_reading_button) { + val nextChapter = adapter.coverListener?.nextChapter() + visibleIf(nextChapter != null && !item.isLocked) + if (nextChapter != null) { + val number = adapter.decimalFormat.format(nextChapter.chapter_number.toDouble()) + text = resources.getString(if (nextChapter.last_page_read > 0) + R.string.continue_reader_chapter + else R.string.start_reader_chapter, number) + } + } + + GlideApp.with(view.context).load(manga) + .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) + .signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString())) + .into(manga_cover) + GlideApp.with(view.context).load(manga) + .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) + .signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString())) + .centerCrop() + .into(backdrop) + } + + fun setBackDrop(color: Int) { + true_backdrop.setBackgroundColor(color) + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt new file mode 100644 index 0000000000..a0534d832f --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -0,0 +1,258 @@ +package eu.kanade.tachiyomi.ui.manga + +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.download.DownloadManager +import eu.kanade.tachiyomi.data.download.model.Download +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.source.LocalSource +import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem +import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +class MangaPresenter(private val controller: MangaChaptersController, + val manga: Manga, + val source: Source, + val preferences: PreferencesHelper = Injekt.get(), + private val db: DatabaseHelper = Injekt.get(), + private val downloadManager: DownloadManager = Injekt.get()) { + + + var isLockedFromSearch = false + + var chapters:List = emptyList() + private set + fun onCreate() { + isLockedFromSearch = SecureActivityDelegate.shouldBeLocked() + + val chapters = db.getChapters(manga).executeAsBlocking().map { it.toModel() } + + + // Store the last emission + this.chapters = applyChapterFilters(chapters) + + // Find downloaded chapters + setDownloadedChapters(chapters) + + controller.updateChapters(this.chapters) + + // Listen for download status changes + //observeDownloads() + + // 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) + )*/ + + /* // Prepare the relay. + chaptersRelay.flatMap { applyChapterFilters(it) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribeLatestCache( + ChaptersController::onNextChapters + ) { _, error -> Timber.e(error) } + + // Add the subscription that retrieves the chapters from the database, keeps subscribed to + // changes, and sends the list of chapters to the relay. + add(db.getChapters(manga).asRxObservable() + .map { chapters -> + // Convert every chapter to a model. + chapters.map { it.toModel() } + } + .doOnNext { chapters -> + // Find downloaded chapters + setDownloadedChapters(chapters) + + // Store the last emission + this.chapters = chapters + + // Listen for download status changes + observeDownloads() + + // 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) + ) + + } + .subscribe { chaptersRelay.call(it) })*/ + } + + /*private fun observeDownloads() { + observeDownloadsSubscription?.let { remove(it) } + observeDownloadsSubscription = downloadManager.queue.getStatusObservable() + .observeOn(AndroidSchedulers.mainThread()) + .filter { download -> download.manga.id == manga.id } + .doOnNext { onDownloadStatusChange(it) } + .subscribeLatestCache(ChaptersController::onChapterStatusChange) { + _, error -> Timber.e(error) + } + }*/ + /** + * Finds and assigns the list of downloaded chapters. + * + * @param chapters the list of chapter from the database. + */ + private fun setDownloadedChapters(chapters: List) { + for (chapter in chapters) { + if (downloadManager.isChapterDownloaded(chapter, manga)) { + chapter.status = Download.DOWNLOADED + } + } + } + /** + * Converts a chapter from the database to an extended model, allowing to store new fields. + */ + private fun Chapter.toModel(): ChapterItem { + // Create the model object. + val model = ChapterItem(this, manga) + model.isLocked = isLockedFromSearch + + // Find an active download for this chapter. + val download = downloadManager.queue.find { it.chapter.id == id } + + if (download != null) { + // If there's an active download, assign it. + model.download = download + } + return model + } + /** + * Sets the active display mode. + * @param mode the mode to set. + */ + fun setDisplayMode(mode: Int) { + manga.displayMode = mode + db.updateFlags(manga).executeAsBlocking() + } + + /** + * Sets the sorting method and requests an UI update. + * @param sort the sorting mode. + */ + fun setSorting(sort: Int) { + manga.sorting = sort + db.updateFlags(manga).executeAsBlocking() + // refreshChapters() + } + + /** + * Whether the display only downloaded filter is enabled. + */ + fun onlyDownloaded(): Boolean { + return manga.downloadedFilter == Manga.SHOW_DOWNLOADED + } + + /** + * Whether the display only downloaded filter is enabled. + */ + fun onlyBookmarked(): Boolean { + return manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED + } + + /** + * Whether the display only unread filter is enabled. + */ + fun onlyUnread(): Boolean { + return manga.readFilter == Manga.SHOW_UNREAD + } + + /** + * Whether the display only read filter is enabled. + */ + fun onlyRead(): Boolean { + return manga.readFilter == Manga.SHOW_READ + } + + /** + * Whether the sorting method is descending or ascending. + */ + fun sortDescending(): Boolean { + return manga.sortDescending() + } + + /** + * Applies the view filters to the list of chapters obtained from the database. + * @param chapterList the list of chapters from the database + * @return an observable of the list of chapters filtered and sorted. + */ + private fun applyChapterFilters(chapterList: List): List { + var chapters = chapterList + if (onlyUnread()) { + chapters = chapters.filter { !it.read } + } else if (onlyRead()) { + chapters = chapters.filter { it.read } + } + if (onlyDownloaded()) { + chapters = chapters.filter { it.isDownloaded || it.manga.source == LocalSource.ID } + } + if (onlyBookmarked()) { + chapters = chapters.filter { it.bookmark } + } + val sortFunction: (Chapter, Chapter) -> Int = when (manga.sorting) { + Manga.SORTING_SOURCE -> when (sortDescending()) { + true -> { c1, c2 -> c1.source_order.compareTo(c2.source_order) } + false -> { c1, c2 -> c2.source_order.compareTo(c1.source_order) } + } + Manga.SORTING_NUMBER -> when (sortDescending()) { + true -> { c1, c2 -> c2.chapter_number.compareTo(c1.chapter_number) } + false -> { c1, c2 -> c1.chapter_number.compareTo(c2.chapter_number) } + } + else -> throw NotImplementedError("Unimplemented sorting method") + } + chapters = chapters.sortedWith(Comparator(sortFunction)) + //if (sortDescending()) + // chapters = chapters.reversed() + return chapters + } + + /** + * Returns the next unread chapter or null if everything is read. + */ + fun getNextUnreadChapter(): ChapterItem? { + return chapters.sortedByDescending { it.source_order }.find { !it.read } + } + + /** + * Downloads the given list of chapters with the manager. + * @param chapters the list of chapters to download. + */ + fun downloadChapters(chapters: List) { + downloadManager.downloadChapters(manga, chapters) + } + + /** + * Deletes the given list of chapter. + * @param chapters the list of chapters to delete. + */ + fun deleteChapters(chapters: List) { + deleteChaptersInternal(chapters) + + setDownloadedChapters(chapters) + + controller.updateChapters(this.chapters) + // if (onlyDownloaded()) refreshChapters() } + } + + /** + * Deletes a list of chapters from disk. This method is called in a background thread. + * @param chapters the chapters to delete. + */ + private fun deleteChaptersInternal(chapters: List) { + downloadManager.deleteChapters(chapters, manga, source) + chapters.forEach { + it.status = Download.NOT_DOWNLOADED + it.download = null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt index 77624a5598..0c6fff4216 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt @@ -27,7 +27,7 @@ class ChapterHolder( } fun bind(item: ChapterItem, manga: Manga) { - val chapter = item.chapter + val chapter = item.chapter ?: return val isLocked = item.isLocked chapter_title.text = when (manga.displayMode) { Manga.DISPLAY_NUMBER -> { @@ -90,6 +90,7 @@ class ChapterHolder( private fun showPopupMenu(view: View) { val item = adapter.getItem(adapterPosition) ?: return + val chapter = item.chapter ?: return if (item.isLocked) { adapter.unlock() @@ -101,7 +102,6 @@ class ChapterHolder( // Inflate our menu resource into the PopupMenu's Menu popup.menuInflater.inflate(R.menu.chapter_single, popup.menu) - val chapter = item.chapter // Hide download and show delete if the chapter is downloaded if (item.isDownloaded) { @@ -125,7 +125,7 @@ class ChapterHolder( // Set a listener so we are notified if a menu item is clicked popup.setOnMenuItemClickListener { menuItem -> - adapter.menuItemListener.onMenuItemClick(adapterPosition, menuItem) + adapter.menuItemListener?.onMenuItemClick(adapterPosition, menuItem) true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt index c8b3d768ae..0603ef5003 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt @@ -9,11 +9,21 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.download.model.Download +import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.ui.manga.MangaChapterHolder +import eu.kanade.tachiyomi.ui.manga.MangaHeaderHolder -class ChapterItem(val chapter: Chapter, val manga: Manga) : AbstractFlexibleItem(), - Chapter by chapter { +class ChapterItem(val chapter: Chapter, val manga: Manga) : + AbstractFlexibleItem(), + Chapter by chapter { private var _status: Int = 0 + + val progress: Int + get() { + val pages = download?.pages ?: return 0 + return pages.map(Page::progress).average().toInt() + } var isLocked = false var status: Int @@ -26,31 +36,36 @@ class ChapterItem(val chapter: Chapter, val manga: Manga) : AbstractFlexibleItem get() = status == Download.DOWNLOADED override fun getLayoutRes(): Int { - return R.layout.chapters_item + return if (!chapter.isRecognizedNumber) R.layout.manga_header_item + else R.layout.chapters_mat_item } - override fun createViewHolder(view: View, adapter: FlexibleAdapter>): ChapterHolder { - return ChapterHolder(view, adapter as ChaptersAdapter) + override fun isSelectable(): Boolean { + return chapter.isRecognizedNumber + } + + override fun createViewHolder(view: View, adapter: FlexibleAdapter>): MangaChapterHolder { + return if (!chapter.isRecognizedNumber) MangaHeaderHolder(view, adapter as ChaptersAdapter) + else ChapterMatHolder(view, adapter as ChaptersAdapter) } override fun bindViewHolder(adapter: FlexibleAdapter>, - holder: ChapterHolder, + holder: MangaChapterHolder, position: Int, payloads: MutableList?) { - holder.bind(this, manga) } override fun equals(other: Any?): Boolean { if (this === other) return true if (other is ChapterItem) { - return chapter.id!! == other.chapter.id!! + return chapter.id ?: -1 == other.chapter.id ?: -1 } return false } override fun hashCode(): Int { - return chapter.id!!.hashCode() + return chapter.id?.hashCode() ?: -1 } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterMatHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterMatHolder.kt new file mode 100644 index 0000000000..1553ba1bcd --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterMatHolder.kt @@ -0,0 +1,116 @@ +package eu.kanade.tachiyomi.ui.manga.chapter + +import android.view.View +import androidx.appcompat.widget.PopupMenu +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.download.model.Download +import eu.kanade.tachiyomi.ui.manga.MangaChapterHolder +import eu.kanade.tachiyomi.util.view.gone +import eu.kanade.tachiyomi.util.view.invisible +import eu.kanade.tachiyomi.util.view.visible +import kotlinx.android.synthetic.main.chapters_mat_item.* +import kotlinx.android.synthetic.main.download_button.* + +class ChapterMatHolder( + private val view: View, + private val adapter: ChaptersAdapter +) : MangaChapterHolder(view, adapter) { + + init { + // We need to post a Runnable to show the popup to make sure that the PopupMenu is + // correctly positioned. The reason being that the view may change position before the + // PopupMenu is shown. + //chapter_menu.setOnClickListener { it.post { showPopupMenu(it) } } + download_button.setOnClickListener { downloadOrRemoveMenu() } + } + + private fun downloadOrRemoveMenu() { + val chapter = adapter.getItem(adapterPosition) ?: return + if (chapter.status != Download.NOT_DOWNLOADED) { + download_button.post { + // Create a PopupMenu, giving it the clicked view for an anchor + val popup = PopupMenu(download_button.context, download_button) + + // Inflate our menu resource into the PopupMenu's Menu + popup.menuInflater.inflate(R.menu.chapter_download, popup.menu) + + // Hide download and show delete if the chapter is downloaded + if (chapter.status != Download.DOWNLOADED) popup.menu.findItem(R.id.action_delete) + .title = download_button.context.getString( + R.string.action_cancel + ) + + // Set a listener so we are notified if a menu item is clicked + popup.setOnMenuItemClickListener { _ -> + adapter.coverListener?.downloadChapter(adapterPosition) + true + } + + // Finally show the PopupMenu + popup.show() + } + } + else { + adapter.coverListener?.downloadChapter(adapterPosition) + } + } + + override fun bind(item: ChapterItem, manga: Manga) { + val chapter = item.chapter + val isLocked = item.isLocked + chapter_title.text = when (manga.displayMode) { + Manga.DISPLAY_NUMBER -> { + val number = adapter.decimalFormat.format(chapter.chapter_number.toDouble()) + itemView.context.getString(R.string.display_mode_chapter, number) + } + else -> chapter.name + } + + //chapter_menu.visible() + // Set the correct drawable for dropdown and update the tint to match theme. + //chapter_menu.setVectorCompat(R.drawable.ic_more_vert_black_24dp, view.context + // .getResourceColor(R.attr.icon_color)) + + if (isLocked) download_button.invisible() + + // Set correct text color + chapter_title.setTextColor(if (chapter.read && !isLocked) + adapter.readColor else adapter.unreadColor) + if (chapter.bookmark && !isLocked) chapter_title.setTextColor(adapter.bookmarkedColor) + + /*if (chapter.date_upload > 0) { + chapter_date.text = adapter.dateFormat.format(Date(chapter.date_upload)) + chapter_date.setTextColor(if (chapter.read) adapter.readColor else adapter.unreadColor) + } else { + chapter_date.text = "" + }*/ + + //add scanlator if exists + chapter_scanlator.text = chapter.scanlator ?: " " + //allow longer titles if there is no scanlator (most sources) + /*if (chapter_scanlator.text.isNullOrBlank()) { + chapter_title.maxLines = 2 + //chapter_scanlator.gone() + } else { + chapter_title.maxLines = 1 + }*/ + + /* chapter_pages.text = if (!chapter.read && chapter.last_page_read > 0 && !isLocked) { + itemView.context.getString(R.string.chapter_progress, chapter.last_page_read + 1) + } else { + "" + }*/ + + notifyStatus(item.status, item.isLocked, item.progress) + } + + fun notifyStatus(status: Int, locked: Boolean, progress: Int) = with(download_button) { + if (locked) { + gone() + return + } + visible() + setDownoadStatus(status, progress) + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt index 2e06f365da..c252805612 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt @@ -5,8 +5,10 @@ import android.view.MenuItem import androidx.fragment.app.FragmentActivity import eu.davidea.flexibleadapter.FlexibleAdapter import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate import eu.kanade.tachiyomi.util.system.getResourceColor import uy.kohesive.injekt.injectLazy @@ -15,7 +17,7 @@ import java.text.DecimalFormat import java.text.DecimalFormatSymbols class ChaptersAdapter( - val controller: ChaptersController, + val controller: BaseController, context: Context ) : FlexibleAdapter(null, controller, true) { @@ -23,7 +25,8 @@ class ChaptersAdapter( var items: List = emptyList() - val menuItemListener: OnMenuItemClickListener = controller + val menuItemListener: OnMenuItemClickListener? = controller as? OnMenuItemClickListener + val coverListener: MangaHeaderInterface? = controller as? MangaHeaderInterface val readColor = context.getResourceColor(android.R.attr.textColorHint) @@ -53,4 +56,11 @@ class ChaptersAdapter( interface OnMenuItemClickListener { fun onMenuItemClick(position: Int, item: MenuItem) } + + interface MangaHeaderInterface { + fun coverColor(): Int? + fun nextChapter(): Chapter? + fun readNextChapter() + fun downloadChapter(position: Int) + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt index 91c2156ea3..642097fb31 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt @@ -2,22 +2,22 @@ package eu.kanade.tachiyomi.ui.setting import android.content.Context import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import androidx.preference.PreferenceController -import androidx.preference.PreferenceScreen import android.util.TypedValue import android.view.ContextThemeWrapper import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.appcompat.app.AppCompatActivity +import androidx.preference.PreferenceController +import androidx.preference.PreferenceScreen import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeType import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener -import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets -import eu.kanade.tachiyomi.util.view.updatePaddingRelative +import eu.kanade.tachiyomi.util.view.updateLayoutParams import rx.Observable import rx.Subscription import rx.subscriptions.CompositeSubscription @@ -36,6 +36,12 @@ abstract class SettingsController : PreferenceController() { untilDestroySubscriptions = CompositeSubscription() } val view = super.onCreateView(inflater, container, savedInstanceState) + view.updateLayoutParams { + val attrsArray = intArrayOf(android.R.attr.actionBarSize) + val array = view.context.obtainStyledAttributes(attrsArray) + topMargin = array.getDimensionPixelSize(0, 0) + array.recycle() + } listView.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) return view } diff --git a/app/src/main/res/drawable/border_circle.xml b/app/src/main/res/drawable/border_circle.xml new file mode 100644 index 0000000000..31b8ae1e95 --- /dev/null +++ b/app/src/main/res/drawable/border_circle.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/circle_progress.xml b/app/src/main/res/drawable/circle_progress.xml new file mode 100644 index 0000000000..a0644da5c7 --- /dev/null +++ b/app/src/main/res/drawable/circle_progress.xml @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/filled_circle.xml b/app/src/main/res/drawable/filled_circle.xml new file mode 100644 index 0000000000..9111d830c8 --- /dev/null +++ b/app/src/main/res/drawable/filled_circle.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_shape.xml b/app/src/main/res/drawable/gradient_shape.xml index fcea50e567..6646bac6cb 100644 --- a/app/src/main/res/drawable/gradient_shape.xml +++ b/app/src/main/res/drawable/gradient_shape.xml @@ -4,7 +4,7 @@ diff --git a/app/src/main/res/drawable/ic_open_in_webview_white_24dp.xml b/app/src/main/res/drawable/ic_open_in_webview_white_24dp.xml new file mode 100644 index 0000000000..cdaef7b1b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_open_in_webview_white_24dp.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_ripple.xml b/app/src/main/res/drawable/round_ripple.xml index bec0a84b4c..d4c17b310f 100644 --- a/app/src/main/res/drawable/round_ripple.xml +++ b/app/src/main/res/drawable/round_ripple.xml @@ -3,7 +3,7 @@ android:color="@color/gray_button"> - + \ No newline at end of file diff --git a/app/src/main/res/layout/big_manga_controller.xml b/app/src/main/res/layout/big_manga_controller.xml index 3ff9738d63..d4bb5fa94f 100644 --- a/app/src/main/res/layout/big_manga_controller.xml +++ b/app/src/main/res/layout/big_manga_controller.xml @@ -1,320 +1,32 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="match_parent" + android:clipToPadding="false" + android:descendantFocusability="blocksDescendants" + android:nestedScrollingEnabled="false" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/chapters_title" + tools:listitem="@layout/chapters_mat_item"> + - - + diff --git a/app/src/main/res/layout/catalogue_controller.xml b/app/src/main/res/layout/catalogue_controller.xml index e2a0cdb348..cced54f93d 100644 --- a/app/src/main/res/layout/catalogue_controller.xml +++ b/app/src/main/res/layout/catalogue_controller.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:id="@+id/catalouge_layout" + android:layout_marginTop="?attr/actionBarSize" android:layout_height="match_parent"> - \ No newline at end of file + tools:listitem="@layout/catalogue_grid_item" + xmlns:app="http://schemas.android.com/apk/res-auto" /> \ No newline at end of file diff --git a/app/src/main/res/layout/categories_controller.xml b/app/src/main/res/layout/categories_controller.xml index 1339f8c0b7..dde7ff70bb 100644 --- a/app/src/main/res/layout/categories_controller.xml +++ b/app/src/main/res/layout/categories_controller.xml @@ -4,6 +4,7 @@ android:id="@+id/cat_layout" android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_marginTop="?attr/actionBarSize" android:clipToPadding="false" android:orientation="vertical"> diff --git a/app/src/main/res/layout/chapters_controller.xml b/app/src/main/res/layout/chapters_controller.xml index 1edc27f126..4d80afc8a3 100644 --- a/app/src/main/res/layout/chapters_controller.xml +++ b/app/src/main/res/layout/chapters_controller.xml @@ -5,6 +5,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_marginTop="?attr/actionBarSize" android:clipToPadding="false" android:orientation="vertical"> diff --git a/app/src/main/res/layout/chapters_mat_item.xml b/app/src/main/res/layout/chapters_mat_item.xml new file mode 100644 index 0000000000..bf8293dd84 --- /dev/null +++ b/app/src/main/res/layout/chapters_mat_item.xml @@ -0,0 +1,44 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/download_button.xml b/app/src/main/res/layout/download_button.xml new file mode 100644 index 0000000000..a17cc8cc69 --- /dev/null +++ b/app/src/main/res/layout/download_button.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/download_controller.xml b/app/src/main/res/layout/download_controller.xml index 8dea274579..e637344ef4 100644 --- a/app/src/main/res/layout/download_controller.xml +++ b/app/src/main/res/layout/download_controller.xml @@ -3,6 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" + android:layout_marginTop="?attr/actionBarSize" android:layout_height="match_parent"> @@ -65,7 +67,7 @@ app:layout_constraintBottom_toTopOf="@+id/navigationView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/appbar"> + app:layout_constraintTop_toTopOf="parent"> @@ -85,7 +87,6 @@ app:tabBackground="@color/rippleColor" app:tabRippleColor="@color/rippleColor" app:tabTextColor="?attr/tabBarIconColor" /> - diff --git a/app/src/main/res/layout/manga_header_item.xml b/app/src/main/res/layout/manga_header_item.xml new file mode 100644 index 0000000000..2e0f57f086 --- /dev/null +++ b/app/src/main/res/layout/manga_header_item.xml @@ -0,0 +1,348 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/manga_info_controller.xml b/app/src/main/res/layout/manga_info_controller.xml index 8dd5751457..930bcf9588 100644 --- a/app/src/main/res/layout/manga_info_controller.xml +++ b/app/src/main/res/layout/manga_info_controller.xml @@ -87,7 +87,7 @@ android:layout_height="match_parent"> + app:layout_constraintTop_toBottomOf="@+id/manga_title" /> diff --git a/app/src/main/res/layout/migration_list_controller.xml b/app/src/main/res/layout/migration_list_controller.xml index cdaad5b500..88d2189fc1 100644 --- a/app/src/main/res/layout/migration_list_controller.xml +++ b/app/src/main/res/layout/migration_list_controller.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_marginTop="?attr/actionBarSize" android:animateLayoutChanges="true"> + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3168a69b8c..40074e72ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,6 +23,7 @@ Extensions Extension info Help + Unlock Unlock to access Library Update available @@ -71,6 +72,7 @@ Bookmark Remove bookmark Delete + Remove download Update library Edit Add @@ -476,6 +478,7 @@ Licensed Title Added to library + Add to Library Removed from library Author Artist @@ -494,6 +497,8 @@ Source not installed: %1$s + Start Reading Chapter %1$s + Continue Reading Chapter %1$s Chapters Chapter %1$s Downloaded diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 5b9efd8bfb..12da731451 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -234,6 +234,31 @@ 48dip + + + + + +