Download queue moved to recents

We're at 7 bottom sheets now
Using vibrant color for manga cover background
pull/3117/head
Jay 5 years ago
parent 9a4894ba95
commit 1ce426d1c9

@ -8,6 +8,8 @@ import eu.kanade.tachiyomi.data.database.mappers.MangaGetResolver
import eu.kanade.tachiyomi.data.database.models.ChapterImpl import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.HistoryImpl import eu.kanade.tachiyomi.data.database.models.HistoryImpl
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
class MangaChapterHistoryGetResolver : DefaultGetResolver<MangaChapterHistory>() { class MangaChapterHistoryGetResolver : DefaultGetResolver<MangaChapterHistory>() {
companion object { companion object {
@ -37,19 +39,24 @@ class MangaChapterHistoryGetResolver : DefaultGetResolver<MangaChapterHistory>()
val manga = mangaGetResolver.mapFromCursor(cursor) val manga = mangaGetResolver.mapFromCursor(cursor)
// Get chapter object // Get chapter object
val chapter = try { chapterResolver.mapFromCursor(cursor) } catch (e: Exception) { val chapter =
ChapterImpl() } if (!cursor.isNull(cursor.getColumnIndex(ChapterTable.COL_MANGA_ID))) chapterResolver
.mapFromCursor(
cursor
) else ChapterImpl()
// Get history object // Get history object
val history = try { historyGetResolver.mapFromCursor(cursor) } catch (e: Exception) { HistoryImpl() } val history =
if (!cursor.isNull(cursor.getColumnIndex(HistoryTable.COL_ID))) historyGetResolver.mapFromCursor(
cursor
) else HistoryImpl()
// Make certain column conflicts are dealt with // Make certain column conflicts are dealt with
if (chapter.id != null) { if (chapter.id != null) {
manga.id = chapter.manga_id manga.id = chapter.manga_id
manga.url = cursor.getString(cursor.getColumnIndex("mangaUrl")) manga.url = cursor.getString(cursor.getColumnIndex("mangaUrl"))
} }
if (history.id != null) if (history.id != null) chapter.id = history.chapter_id
chapter.id = history.chapter_id
// Return result // Return result
return MangaChapterHistory(manga, chapter, history) return MangaChapterHistory(manga, chapter, history)

@ -239,6 +239,9 @@ class DownloadManager(val context: Context) {
downloader.start() downloader.start()
} else if (downloader.queue.isEmpty() && DownloadService.isRunning(context)) { } else if (downloader.queue.isEmpty() && DownloadService.isRunning(context)) {
DownloadService.stop(context) DownloadService.stop(context)
} else if (downloader.queue.isEmpty()) {
DownloadService.callListeners(false)
downloader.stop()
} }
queue.remove(chapters) queue.remove(chapters)
val chapterDirs = provider.findChapterDirs(chapters, manga, source) + provider.findTempChapterDirs(chapters, manga, source) val chapterDirs = provider.findChapterDirs(chapters, manga, source) + provider.findTempChapterDirs(chapters, manga, source)

@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import kotlin.math.roundToInt
class Download(val source: HttpSource, val manga: Manga, val chapter: Chapter) { class Download(val source: HttpSource, val manga: Manga, val chapter: Chapter) {
@ -25,10 +26,16 @@ class Download(val source: HttpSource, val manga: Manga, val chapter: Chapter) {
@Transient private var statusCallback: ((Download) -> Unit)? = null @Transient private var statusCallback: ((Download) -> Unit)? = null
val pageProgress: Int
get() {
val pages = pages ?: return 0
return pages.map(Page::progress).sum()
}
val progress: Int val progress: Int
get() { get() {
val pages = pages ?: return 0 val pages = pages ?: return 0
return pages.map(Page::progress).average().toInt() return pages.map(Page::progress).average().roundToInt()
} }
fun setStatusSubject(subject: PublishSubject<Download>?) { fun setStatusSubject(subject: PublishSubject<Download>?) {

@ -28,6 +28,7 @@ import eu.kanade.tachiyomi.ui.catalogue.browse.BrowseCatalogueController
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
import eu.kanade.tachiyomi.ui.catalogue.latest.LatestUpdatesController import eu.kanade.tachiyomi.ui.catalogue.latest.LatestUpdatesController
import eu.kanade.tachiyomi.ui.extension.SettingsExtensionsController import eu.kanade.tachiyomi.ui.extension.SettingsExtensionsController
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
@ -269,6 +270,12 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
router.pushController(controller.withFadeTransaction()) router.pushController(controller.withFadeTransaction())
} }
override fun expandSearch() {
if (showingExtenions)
ext_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
else activity?.toolbar?.menu?.findItem(R.id.action_search)?.expandActionView()
}
/** /**
* Adds items to the options menu. * Adds items to the options menu.
* *
@ -276,6 +283,7 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
* @param inflater used to load the menu xml. * @param inflater used to load the menu xml.
*/ */
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
(activity as? MainActivity)?.setDismissIcon(showingExtenions)
if (showingExtenions) { if (showingExtenions) {
// Inflate menu // Inflate menu
inflater.inflate(R.menu.extension_main, menu) inflater.inflate(R.menu.extension_main, menu)
@ -336,9 +344,6 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
).pushChangeHandler(FadeChangeHandler()) ).pushChangeHandler(FadeChangeHandler())
) )
} }
R.id.action_dismiss -> {
ext_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
}
else -> return super.onOptionsItemSelected(item) else -> return super.onOptionsItemSelected(item)
} }
return true return true

@ -8,7 +8,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
* *
* @param context the context of the fragment containing this adapter. * @param context the context of the fragment containing this adapter.
*/ */
class DownloadAdapter(controller: DownloadController) : FlexibleAdapter<DownloadItem>(null, controller, class DownloadAdapter(controller: DownloadItemListener) : FlexibleAdapter<DownloadItem>(null, controller,
true) { true) {
/** /**
@ -21,6 +21,12 @@ class DownloadAdapter(controller: DownloadController) : FlexibleAdapter<Download
* Called when an item of the list is released. * Called when an item of the list is released.
*/ */
fun onItemReleased(position: Int) fun onItemReleased(position: Int)
fun onItemRemoved(position: Int)
fun onMenuItemClick(position: Int, menuItem: MenuItem) fun onMenuItemClick(position: Int, menuItem: MenuItem)
} }
override fun onItemSwiped(position: Int, direction: Int) {
super.onItemSwiped(position, direction)
downloadItemListener.onItemRemoved(position)
}
} }

@ -0,0 +1,71 @@
package eu.kanade.tachiyomi.ui.download
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import uy.kohesive.injekt.injectLazy
/**
* Presenter of [DownloadBottomSheet].
*/
class DownloadBottomPresenter(val sheet: DownloadBottomSheet) {
/**
* Download manager.
*/
val downloadManager: DownloadManager by injectLazy()
var items = listOf<DownloadItem>()
private var scope = CoroutineScope(Job() + Dispatchers.Default)
/**
* Property to get the queue from the download manager.
*/
val downloadQueue: DownloadQueue
get() = downloadManager.queue
fun getItems() {
scope.launch {
val items = downloadQueue.map(::DownloadItem)
val hasChanged = if (this@DownloadBottomPresenter.items.size != items.size) true
else {
val oldItemsIds = this@DownloadBottomPresenter.items.mapNotNull {
it.download.chapter.id
}.toLongArray()
val newItemsIds = items.mapNotNull { it.download.chapter.id }.toLongArray()
!oldItemsIds.contentEquals(newItemsIds)
}
this@DownloadBottomPresenter.items = items
if (hasChanged) {
withContext(Dispatchers.Main) { sheet.onNextDownloads(items) }
}
}
}
/**
* Pauses the download queue.
*/
fun pauseDownloads() {
downloadManager.pauseDownloads()
}
/**
* Clears the download queue.
*/
fun clearQueue() {
downloadManager.clearQueue()
}
fun reorder(downloads: List<Download>) {
downloadManager.reorderQueue(downloads)
}
fun cancelDownload(download: Download) {
downloadManager.deletePendingDownloads(download)
}
}

@ -0,0 +1,272 @@
package eu.kanade.tachiyomi.ui.download
import android.app.Activity
import android.content.Context
import android.util.AttributeSet
import android.view.Menu
import android.view.MenuItem
import android.widget.LinearLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.ui.extension.ExtensionDividerItemDecoration
import eu.kanade.tachiyomi.ui.recents.RecentsController
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import kotlinx.android.synthetic.main.download_bottom_sheet.view.*
class DownloadBottomSheet @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? =
null
) : LinearLayout(context, attrs),
DownloadAdapter.DownloadItemListener {
lateinit var controller: RecentsController
var sheetBehavior: BottomSheetBehavior<*>? = null
/**
* Adapter containing the active downloads.
*/
private var adapter: DownloadAdapter? = null
private val presenter = DownloadBottomPresenter(this)
/**
* Whether the download queue is running or not.
*/
private var isRunning: Boolean = false
private var activity: Activity? = null
fun onCreate(controller: RecentsController) {
// Initialize adapter, scroll listener and recycler views
adapter = DownloadAdapter(this)
sheetBehavior = BottomSheetBehavior.from(this)
activity = controller.activity
// Create recycler and set adapter.
dl_recycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context)
dl_recycler.adapter = adapter
adapter?.isHandleDragEnabled = true
adapter?.isSwipeEnabled = true
dl_recycler.setHasFixedSize(true)
dl_recycler.addItemDecoration(ExtensionDividerItemDecoration(context))
dl_recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
this.controller = controller
updateDLTitle()
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
val array = context.obtainStyledAttributes(attrsArray)
val headerHeight = array.getDimensionPixelSize(0, 0)
array.recycle()
dl_recycler.doOnApplyWindowInsets { _, windowInsets, _ ->
dl_recycler.updateLayoutParams<MarginLayoutParams> {
topMargin = windowInsets.systemWindowInsetTop + headerHeight - sheet_layout.height
}
}
sheet_layout.setOnClickListener {
if (sheetBehavior?.state != BottomSheetBehavior.STATE_EXPANDED) {
sheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED
} else {
sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
update()
setBottomSheet()
if (sheetBehavior?.state != BottomSheetBehavior.STATE_EXPANDED && sheetBehavior?.isHideable == true) sheetBehavior?.state =
BottomSheetBehavior.STATE_HIDDEN
}
fun update() {
presenter.getItems()
onQueueStatusChange(!presenter.downloadManager.isPaused())
}
private fun updateDLTitle() {
val extCount = presenter.downloadQueue.firstOrNull()
title_text.text = if (extCount != null) resources.getString(
R.string.downloading_x, extCount.chapter.name
)
else ""
}
/**
* Called when the queue's status has changed. Updates the visibility of the buttons.
*
* @param running whether the queue is now running or not.
*/
private fun onQueueStatusChange(running: Boolean) {
val oldRunning = isRunning
isRunning = running
if (oldRunning != running) {
activity?.invalidateOptionsMenu()
// Check if download queue is empty and update information accordingly.
setInformationView()
}
}
/**
* Called from the presenter to assign the downloads for the adapter.
*
* @param downloads the downloads from the queue.
*/
fun onNextDownloads(downloads: List<DownloadItem>) {
activity?.invalidateOptionsMenu()
setInformationView()
adapter?.updateDataSet(downloads)
setBottomSheet()
}
/**
* Called when the progress of a download changes.
*
* @param download the download whose progress has changed.
*/
fun onUpdateProgress(download: Download) {
getHolder(download)?.notifyProgress()
}
/**
* Called when a page of a download is downloaded.
*
* @param download the download whose page has been downloaded.
*/
fun onUpdateDownloadedPages(download: Download) {
getHolder(download)?.notifyDownloadedPages()
}
/**
* Returns the holder for the given download.
*
* @param download the download to find.
* @return the holder of the download or null if it's not bound.
*/
private fun getHolder(download: Download): DownloadHolder? {
return dl_recycler?.findViewHolderForItemId(download.chapter.id!!) as? DownloadHolder
}
/**
* Set information view when queue is empty
*/
private fun setInformationView() {
updateDLTitle()
setBottomSheet()
if (presenter.downloadQueue.isEmpty()) {
empty_view?.show(
R.drawable.ic_file_download_black_128dp,
R.string.nothing_downloading)
} else {
empty_view?.hide()
}
}
fun prepareMenu(menu: Menu) {
// Set start button visibility.
menu.findItem(R.id.start_queue)?.isVisible = !isRunning && !presenter.downloadQueue.isEmpty()
// Set pause button visibility.
menu.findItem(R.id.pause_queue)?.isVisible = isRunning && !presenter.downloadQueue.isEmpty()
// Set clear button visibility.
menu.findItem(R.id.clear_queue)?.isVisible = !presenter.downloadQueue.isEmpty()
// Set reorder button visibility.
menu.findItem(R.id.reorder)?.isVisible = !presenter.downloadQueue.isEmpty()
}
fun onOptionsItemSelected(item: MenuItem): Boolean {
val context = activity ?: return false
when (item.itemId) {
R.id.start_queue -> DownloadService.start(context)
R.id.pause_queue -> {
DownloadService.stop(context)
presenter.pauseDownloads()
}
R.id.clear_queue -> {
DownloadService.stop(context)
presenter.clearQueue()
}
R.id.newest, R.id.oldest -> {
val adapter = adapter ?: return false
val items = adapter.currentItems.sortedBy { it.download.chapter.date_upload }
.toMutableList()
if (item.itemId == R.id.newest)
items.reverse()
adapter.updateDataSet(items)
val downloads = items.mapNotNull { it.download }
presenter.reorder(downloads)
}
}
return true
}
fun dismiss() {
if (sheetBehavior?.isHideable == true) {
sheetBehavior?.state = BottomSheetBehavior.STATE_HIDDEN
} else {
sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
private fun setBottomSheet() {
val hasQueue = presenter.downloadQueue.isNotEmpty()
if (hasQueue) {
sheetBehavior?.skipCollapsed = !hasQueue
if (sheetBehavior?.state == BottomSheetBehavior.STATE_HIDDEN) sheetBehavior?.state =
BottomSheetBehavior.STATE_COLLAPSED
sheetBehavior?.isHideable = !hasQueue
} else {
sheetBehavior?.isHideable = !hasQueue
sheetBehavior?.skipCollapsed = !hasQueue
if (sheetBehavior?.state == BottomSheetBehavior.STATE_COLLAPSED) sheetBehavior?.state =
BottomSheetBehavior.STATE_HIDDEN
}
controller.setPadding(!hasQueue)
}
/**
* Called when an item is released from a drag.
*
* @param position The position of the released item.
*/
override fun onItemReleased(position: Int) {
val adapter = adapter ?: return
val downloads = (0 until adapter.itemCount).mapNotNull { adapter.getItem(it)?.download }
presenter.reorder(downloads)
}
override fun onItemRemoved(position: Int) {
val download = adapter?.getItem(position)?.download ?: return
presenter.cancelDownload(download)
adapter?.removeItem(position)
val adapter = adapter ?: return
val downloads = (0 until adapter.itemCount).mapNotNull { adapter.getItem(it)?.download }
presenter.reorder(downloads)
}
/**
* Called when the menu item of a download is pressed
*
* @param position The position of the item
* @param menuItem The menu Item pressed
*/
override fun onMenuItemClick(position: Int, menuItem: MenuItem) {
when (menuItem.itemId) {
R.id.move_to_top, R.id.move_to_bottom -> {
val items = adapter?.currentItems?.toMutableList() ?: return
val item = items[position]
items.remove(item)
if (menuItem.itemId == R.id.move_to_top)
items.add(0, item)
else
items.add(item)
adapter?.updateDataSet(items)
val downloads = items.mapNotNull { it.download }
presenter.reorder(downloads)
}
}
}
}

@ -299,15 +299,9 @@ class DownloadController : NucleusController<DownloadPresenter>(),
val downloads = items.mapNotNull { it.download } val downloads = items.mapNotNull { it.download }
presenter.reorder(downloads) presenter.reorder(downloads)
} }
R.id.cancel_download -> {
val download = adapter?.getItem(position)?.download ?: return
presenter.cancelDownload(download)
adapter?.removeItem(position)
val adapter = adapter ?: return
val downloads = (0 until adapter.itemCount).mapNotNull { adapter.getItem(it)?.download }
presenter.reorder(downloads)
} }
} }
override fun onItemRemoved(position: Int) {
} }
} }

@ -64,7 +64,7 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) :
if (download_progress.max == 1) { if (download_progress.max == 1) {
download_progress.max = pages.size * 100 download_progress.max = pages.size * 100
} }
download_progress.progress = download.totalProgress download_progress.progress = download.pageProgress
} }
/** /**
@ -104,4 +104,16 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) :
// Finally show the PopupMenu // Finally show the PopupMenu
popup.show() popup.show()
} }
override fun getFrontView(): View {
return front_view
}
override fun getRearRightView(): View {
return right_view
}
override fun getRearLeftView(): View {
return left_view
}
} }

@ -36,7 +36,7 @@ ExtensionAdapter.OnButtonClickListener,
var shouldCallApi = false var shouldCallApi = false
/** /**
* Adapter containing the list of manga from the catalogue. * Adapter containing the list of extensions
*/ */
private var adapter: FlexibleAdapter<IFlexible<*>>? = null private var adapter: FlexibleAdapter<IFlexible<*>>? = null

@ -34,6 +34,7 @@ import com.google.android.material.snackbar.Snackbar
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.Migrations import eu.kanade.tachiyomi.Migrations
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.DownloadServiceListener import eu.kanade.tachiyomi.data.download.DownloadServiceListener
import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.NotificationReceiver
@ -67,6 +68,8 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Date import java.util.Date
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -79,6 +82,7 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
var drawerArrow: DrawerArrowDrawable? = null var drawerArrow: DrawerArrowDrawable? = null
private set private set
private var searchDrawable: Drawable? = null private var searchDrawable: Drawable? = null
private var dismissDrawable: Drawable? = null
private var currentGestureDelegate: SwipeGestureInterface? = null private var currentGestureDelegate: SwipeGestureInterface? = null
private lateinit var gestureDetector: GestureDetectorCompat private lateinit var gestureDetector: GestureDetectorCompat
@ -129,6 +133,9 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
searchDrawable = ContextCompat.getDrawable( searchDrawable = ContextCompat.getDrawable(
this, R.drawable.ic_search_white_24dp this, R.drawable.ic_search_white_24dp
) )
dismissDrawable = ContextCompat.getDrawable(
this, R.drawable.ic_close_white_24dp
)
var continueSwitchingTabs = false var continueSwitchingTabs = false
bottom_nav.setOnNavigationItemSelectedListener { item -> bottom_nav.setOnNavigationItemSelectedListener { item ->
@ -152,12 +159,11 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
} else if (currentRoot.tag()?.toIntOrNull() == id) { } else if (currentRoot.tag()?.toIntOrNull() == id) {
if (router.backstackSize == 1) { if (router.backstackSize == 1) {
when (id) { when (id) {
/*R.id.nav_recents -> { R.id.nav_recents -> {
val showRecents = preferences.showRecentUpdates().getOrDefault() val controller =
if (!showRecents) setRoot(RecentChaptersController(), id) router.getControllerWithTag(id.toString()) as? RecentsController
else setRoot(RecentlyReadController(), id) controller?.toggleDownloads()
preferences.showRecentUpdates().set(!showRecents) }
}*/
R.id.nav_library -> { R.id.nav_library -> {
val controller = val controller =
router.getControllerWithTag(id.toString()) as? LibraryController router.getControllerWithTag(id.toString()) as? LibraryController
@ -215,7 +221,7 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener {
val rootSearchController = router.backstack.lastOrNull()?.controller() val rootSearchController = router.backstack.lastOrNull()?.controller()
if (rootSearchController is RootSearchInterface) { if (rootSearchController is RootSearchInterface) {
toolbar.menu.findItem(R.id.action_search)?.expandActionView() rootSearchController.expandSearch()
} else onBackPressed() } else onBackPressed()
} }
@ -267,6 +273,10 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
setExtensionsBadge() setExtensionsBadge()
} }
fun setDismissIcon(enabled: Boolean) {
toolbar.navigationIcon = if (enabled) dismissDrawable else searchDrawable
}
private fun setNavBarColor(insets: WindowInsets?) { private fun setNavBarColor(insets: WindowInsets?) {
if (insets == null) return if (insets == null) return
window.navigationBarColor = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) { window.navigationBarColor = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) {
@ -554,17 +564,15 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
} }
override fun downloadStatusChanged(downloading: Boolean) { override fun downloadStatusChanged(downloading: Boolean) {
/*val downloadManager = Injekt.get<DownloadManager>() val downloadManager = Injekt.get<DownloadManager>()
val hasQueue = downloading || downloadManager.hasQueue() val hasQueue = downloading || downloadManager.hasQueue()
launchUI { launchUI {
if (hasQueue) { if (hasQueue) {
val badge = navigationView?.getOrCreateBadge(R.id.nav_library) ?: return@launchUI bottom_nav?.getOrCreateBadge(R.id.nav_recents)
badge.clearNumber()
badge.backgroundColor = getResourceColor(R.attr.badgeColor)
} else { } else {
navigationView?.removeBadge(R.id.nav_library) bottom_nav?.removeBadge(R.id.nav_recents)
}
} }
}*/
} }
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
@ -638,7 +646,12 @@ interface BottomNavBarInterface {
fun canChangeTabs(block: () -> Unit): Boolean fun canChangeTabs(block: () -> Unit): Boolean
} }
interface RootSearchInterface interface RootSearchInterface {
fun expandSearch() {
if (this is Controller) activity?.toolbar?.menu?.findItem(R.id.action_search)?.expandActionView()
}
}
interface SpinnerTitleInterface interface SpinnerTitleInterface
interface OnTouchEventInterface { interface OnTouchEventInterface {

@ -16,6 +16,7 @@ class SearchActivity : MainActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
toolbar.navigationIcon = drawerArrow
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener {
popToRoot() popToRoot()
} }

@ -347,10 +347,10 @@ class MangaDetailsController : BaseController,
android.R.attr.colorBackground android.R.attr.colorBackground
) )
val backDropColor = val backDropColor =
(if (currentNightMode == Configuration.UI_MODE_NIGHT_NO) it?.getLightMutedColor( (if (currentNightMode == Configuration.UI_MODE_NIGHT_NO) it?.getLightVibrantColor(
colorBack colorBack
) )
else it?.getDarkMutedColor(colorBack)) ?: colorBack else it?.getDarkVibrantColor(colorBack)) ?: colorBack
coverColor = backDropColor coverColor = backDropColor
(recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder) (recycler.findViewHolderForAdapterPosition(0) as? MangaHeaderHolder)
?.setBackDrop(backDropColor) ?.setBackDrop(backDropColor)

@ -14,6 +14,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType import com.bluelinelabs.conductor.ControllerChangeType
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
@ -29,12 +30,18 @@ import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
import eu.kanade.tachiyomi.util.view.scrollViewWith import eu.kanade.tachiyomi.util.view.scrollViewWith
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
import eu.kanade.tachiyomi.util.view.snack import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
import kotlinx.android.synthetic.main.download_bottom_sheet.*
import kotlinx.android.synthetic.main.main_activity.* import kotlinx.android.synthetic.main.main_activity.*
import kotlinx.android.synthetic.main.recently_read_controller.* import kotlinx.android.synthetic.main.recents_controller.*
import kotlin.math.abs
import kotlin.math.max
/** /**
* Fragment that shows recently read manga. * Fragment that shows recently read manga.
@ -59,13 +66,17 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
private var recentItems: List<RecentMangaItem>? = null private var recentItems: List<RecentMangaItem>? = null
private var snack: Snackbar? = null private var snack: Snackbar? = null
private var lastChapterId: Long? = null private var lastChapterId: Long? = null
private var showingDownloads = false
var headerHeight = 0
override fun getTitle(): String? { override fun getTitle(): String? {
return resources?.getString(R.string.short_recents) return if (showingDownloads)
resources?.getString(R.string.label_download_queue)
else resources?.getString(R.string.short_recents)
} }
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View { override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
return inflater.inflate(R.layout.recently_read_controller, container, false) return inflater.inflate(R.layout.recents_controller, container, false)
} }
/** /**
@ -86,16 +97,90 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
adapter.itemTouchHelperCallback.setSwipeFlags( adapter.itemTouchHelperCallback.setSwipeFlags(
ItemTouchHelper.LEFT ItemTouchHelper.LEFT
) )
scrollViewWith(recycler, skipFirstSnap = true) val attrsArray = intArrayOf(android.R.attr.actionBarSize)
val array = view.context.obtainStyledAttributes(attrsArray)
val appBarHeight = array.getDimensionPixelSize(0, 0)
array.recycle()
scrollViewWith(recycler, skipFirstSnap = true) {
headerHeight = it.systemWindowInsetTop + appBarHeight
}
if (recentItems != null) adapter.updateDataSet(recentItems!!.toList()) if (recentItems != null) adapter.updateDataSet(recentItems!!.toList())
presenter.onCreate() presenter.onCreate()
dl_bottom_sheet.onCreate(this)
shadow2.alpha =
if (dl_bottom_sheet.sheetBehavior?.state == BottomSheetBehavior.STATE_COLLAPSED) 0.25f else 0f
shadow.alpha =
if (dl_bottom_sheet.sheetBehavior?.state == BottomSheetBehavior.STATE_COLLAPSED) 0.5f else 0f
dl_bottom_sheet.sheetBehavior?.addBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, progress: Float) {
shadow2.alpha = (1 - abs(progress)) * 0.25f
shadow.alpha = (1 - abs(progress)) * 0.5f
sheet_layout.alpha = 1 - progress
activity?.appbar?.y = max(activity!!.appbar.y, -headerHeight * (1 - progress))
val oldShow = showingDownloads
showingDownloads = progress > 0.92f
if (oldShow != showingDownloads) {
setTitle()
activity?.invalidateOptionsMenu()
}
}
override fun onStateChanged(p0: View, state: Int) {
if (this@RecentsController.view == null) return
if (state == BottomSheetBehavior.STATE_EXPANDED) activity?.appbar?.y = 0f
if (state == BottomSheetBehavior.STATE_EXPANDED || state == BottomSheetBehavior.STATE_COLLAPSED) {
sheet_layout.alpha =
if (state == BottomSheetBehavior.STATE_COLLAPSED) 1f else 0f
showingDownloads = state == BottomSheetBehavior.STATE_EXPANDED
setTitle()
activity?.invalidateOptionsMenu()
}
if (state == BottomSheetBehavior.STATE_HIDDEN || state == BottomSheetBehavior.STATE_COLLAPSED) {
shadow2.alpha = if (state == BottomSheetBehavior.STATE_COLLAPSED) 0.25f else 0f
shadow.alpha = if (state == BottomSheetBehavior.STATE_COLLAPSED) 0.5f else 0f
}
retainViewMode =
if (state == BottomSheetBehavior.STATE_EXPANDED) RetainViewMode.RETAIN_DETACH else RetainViewMode.RELEASE_DETACH
sheet_layout?.isClickable = state == BottomSheetBehavior.STATE_COLLAPSED
sheet_layout?.isFocusable = state == BottomSheetBehavior.STATE_COLLAPSED
setPadding(dl_bottom_sheet.sheetBehavior?.isHideable == true)
}
})
if (showingDownloads) {
dl_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED
}
setPadding(dl_bottom_sheet.sheetBehavior?.isHideable == true)
}
override fun handleRootBack(): Boolean {
if (dl_bottom_sheet.sheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED) {
dl_bottom_sheet.dismiss()
return true
}
return false
}
fun setPadding(sheetIsHidden: Boolean) {
recycler.updatePaddingRelative(bottom = if (sheetIsHidden) 0 else 20.dpToPx)
recycler.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = if (sheetIsHidden) 0 else 30.dpToPx
}
} }
override fun onActivityResumed(activity: Activity) { override fun onActivityResumed(activity: Activity) {
super.onActivityResumed(activity) super.onActivityResumed(activity)
if (view != null) if (view != null) {
refresh() refresh()
dl_bottom_sheet?.update()
}
} }
override fun onDestroy() { override fun onDestroy() {
@ -118,6 +203,9 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
fun updateChapterDownload(download: Download) { fun updateChapterDownload(download: Download) {
if (view == null) return if (view == null) return
dl_bottom_sheet.update()
dl_bottom_sheet.onUpdateProgress(download)
dl_bottom_sheet.onUpdateDownloadedPages(download)
val id = download.chapter.id ?: return val id = download.chapter.id ?: return
val holder = recycler.findViewHolderForItemId(id) as? RecentMangaHolder ?: return val holder = recycler.findViewHolderForItemId(id) as? RecentMangaHolder ?: return
holder.notifyStatus(download.status, download.progress) holder.notifyStatus(download.status, download.progress)
@ -204,6 +292,10 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
override fun isSearching() = presenter.query.isNotEmpty() override fun isSearching() = presenter.query.isNotEmpty()
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
(activity as? MainActivity)?.setDismissIcon(showingDownloads)
if (showingDownloads) {
inflater.inflate(R.menu.download_queue, menu)
} else {
inflater.inflate(R.menu.recents, menu) inflater.inflate(R.menu.recents, menu)
val searchItem = menu.findItem(R.id.action_search) val searchItem = menu.findItem(R.id.action_search)
val searchView = searchItem.actionView as SearchView val searchView = searchItem.actionView as SearchView
@ -221,13 +313,17 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
true true
} }
} }
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
if (showingDownloads) dl_bottom_sheet.prepareMenu(menu)
}
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) { override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
super.onChangeStarted(handler, type) super.onChangeStarted(handler, type)
if (type.isEnter) { if (type.isEnter) {
if (type == ControllerChangeType.POP_EXIT) { if (type == ControllerChangeType.POP_EXIT) presenter.onCreate()
presenter.onCreate()
}
setHasOptionsMenu(true) setHasOptionsMenu(true)
} else { } else {
snack?.dismiss() snack?.dismiss()
@ -235,7 +331,23 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
} }
} }
fun toggleDownloads() {
if (dl_bottom_sheet.sheetBehavior?.isHideable == false) {
if (showingDownloads) dl_bottom_sheet.dismiss()
else dl_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED
}
}
override fun expandSearch() {
if (showingDownloads) {
dl_bottom_sheet.dismiss()
} else
activity?.toolbar?.menu?.findItem(R.id.action_search)?.expandActionView()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (showingDownloads)
return dl_bottom_sheet.onOptionsItemSelected(item)
when (item.itemId) { when (item.itemId) {
R.id.action_refresh -> { R.id.action_refresh -> {
if (!LibraryUpdateService.isRunning()) { if (!LibraryUpdateService.isRunning()) {

@ -4,6 +4,7 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
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.download.model.DownloadQueue
@ -22,6 +23,8 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.concurrent.TimeUnit
import kotlin.math.abs
class RecentsPresenter( class RecentsPresenter(
val controller: RecentsController, val controller: RecentsController,
@ -87,7 +90,13 @@ class RecentsPresenter(
if (query.isEmpty()) { if (query.isEmpty()) {
val nChaptersItems = val nChaptersItems =
pairs.filter { it.first.history.id == null && it.first.chapter.id != null } pairs.filter { it.first.history.id == null && it.first.chapter.id != null }
.sortedByDescending { it.second.date_upload } .sortedWith(Comparator<Pair<MangaChapterHistory, Chapter>> { f1, f2 ->
if (abs(f1.second.date_fetch - f2.second.date_fetch) <=
TimeUnit.HOURS.toMillis(2))
f2.second.date_upload.compareTo(f1.second.date_upload)
else
f2.second.date_fetch.compareTo(f1.second.date_fetch)
})
.take(4).map { .take(4).map {
RecentMangaItem( RecentMangaItem(
it.first, it.first,

@ -17,8 +17,6 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.download.DownloadController
import eu.kanade.tachiyomi.util.system.getFilePicker import eu.kanade.tachiyomi.util.system.getFilePicker
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -33,13 +31,6 @@ class SettingsDownloadController : SettingsController() {
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) { override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
titleRes = R.string.pref_category_downloads titleRes = R.string.pref_category_downloads
preference {
titleRes = R.string.label_download_queue
onClick {
router.pushController(DownloadController().withFadeTransaction())
}
}
preference { preference {
key = Keys.downloadsDirectory key = Keys.downloadsDirectory
titleRes = R.string.pref_download_directory titleRes = R.string.pref_download_directory

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.ui.download.DownloadBottomSheet xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/dl_bottom_sheet"
style="@style/BottomSheetDialogTheme"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_bottom_sheet_dialog_fragment"
android:backgroundTint="?android:attr/colorBackground"
android:orientation="vertical"
app:behavior_peekHeight="48sp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<LinearLayout
android:id="@+id/sheet_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/bg_bottom_sheet_dialog_fragment"
android:backgroundTint="?attr/colorPrimaryVariant"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/pill"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="5dp"
android:alpha="0.25"
android:contentDescription="@string/drag_handle"
android:src="@drawable/draggable_pill"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title_text"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:layout_marginTop="6dp"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:textAlignment="center"
android:textColor="?actionBarTintColor"
android:textSize="18sp"
tools:text="Downloads" />
</LinearLayout>
<FrameLayout
android:background="?android:attr/colorBackground"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/dl_recycler"
android:clipToPadding="false"
tools:listitem="@layout/download_item"/>
<eu.kanade.tachiyomi.widget.EmptyView
android:id="@+id/empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"/>
</FrameLayout>
</eu.kanade.tachiyomi.ui.download.DownloadBottomSheet>

@ -1,10 +1,48 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools">
<FrameLayout
android:id="@+id/right_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:background="@color/red_error">
<ImageView
android:id="@+id/close_right"
android:layout_width="24dp"
android:layout_height="24dp"
android:tint="@color/md_white_1000"
android:layout_gravity="end|center"
android:layout_marginEnd="21dp"
android:src="@drawable/ic_close_white_24dp" />
</FrameLayout>
<FrameLayout
android:id="@+id/left_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:background="@color/red_error">
<ImageView
android:id="@+id/close_left"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="start|center"
android:layout_marginStart="21dp"
android:tint="@color/md_white_1000"
android:src="@drawable/ic_close_white_24dp" />
</FrameLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:id="@+id/front_view"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingStart="0dp" android:background="?android:attr/colorBackground"
android:paddingTop="@dimen/material_component_lists_padding_above_list"> android:paddingTop="@dimen/material_component_lists_padding_above_list">
<ImageView <ImageView
@ -75,14 +113,15 @@
<ImageView <ImageView
android:id="@+id/migration_menu" android:id="@+id/migration_menu"
android:layout_width="44dp" android:layout_width="44dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:layout_height="@dimen/material_component_lists_single_line_with_avatar_height" android:layout_height="@dimen/material_component_lists_single_line_with_avatar_height"
android:layout_toEndOf="@id/download_progress_text" android:layout_toEndOf="@id/download_progress_text"
android:contentDescription="@string/description_cover" android:contentDescription="@string/description_cover"
android:paddingStart="10dp"
android:paddingEnd="10dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_more_vert_black_24dp" /> app:srcCompat="@drawable/ic_more_vert_black_24dp" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/recents_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:id="@+id/frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/colorBackground">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
tools:listitem="@layout/catalogue_main_controller_card" />
</FrameLayout>
<View
android:id="@+id/shadow"
android:layout_width="match_parent"
android:layout_height="24dp"
android:alpha="0.5"
android:background="@drawable/shape_gradient_top_shadow"
android:paddingBottom="10dp"
app:layout_anchorGravity="top"
app:layout_anchor="@id/dl_bottom_sheet" />
<!-- Adding bottom sheet after main content -->
<include layout="@layout/download_bottom_sheet"/>
<View
android:id="@+id/shadow2"
android:layout_width="match_parent"
android:layout_height="8dp"
android:layout_gravity="bottom"
android:alpha="0.25"
android:background="@drawable/shape_gradient_top_shadow" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -15,6 +15,7 @@
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:layout_marginBottom="12dp" android:layout_marginBottom="12dp"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:fontFamily="sans-serif-medium"
app:layout_constraintStart_toEndOf="@id/arrow" app:layout_constraintStart_toEndOf="@id/arrow"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
android:textColor="?colorAccent" android:textColor="?colorAccent"

@ -5,7 +5,4 @@
<item android:id="@+id/move_to_bottom" <item android:id="@+id/move_to_bottom"
android:title="@string/action_move_to_bottom" /> android:title="@string/action_move_to_bottom" />
<item android:id="@+id/cancel_download"
android:title="@string/action_cancel" />
</menu> </menu>

@ -4,7 +4,6 @@
<item <item
android:id="@+id/action_search" android:id="@+id/action_search"
android:icon="@drawable/ic_search_white_24dp" android:icon="@drawable/ic_search_white_24dp"
android:visible="false"
android:title="@string/action_search" android:title="@string/action_search"
app:actionViewClass="androidx.appcompat.widget.SearchView" app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="collapseActionView|ifRoom" /> app:showAsAction="collapseActionView|ifRoom" />
@ -22,11 +21,4 @@
android:visible="false" android:visible="false"
android:checkable="true" android:checkable="true"
app:showAsAction="never"/> app:showAsAction="never"/>
<item
android:id="@+id/action_dismiss"
android:title="@string/action_dismiss"
android:icon="@drawable/ic_close_white_24dp"
app:showAsAction="always"/>
</menu> </menu>

@ -37,6 +37,7 @@
<item quantity="one">Extension update available</item> <item quantity="one">Extension update available</item>
<item quantity="other">%d extension updates available</item> <item quantity="other">%d extension updates available</item>
</plurals> </plurals>
<string name="downloading_x">Downloading: %1$s</string>
<plurals name="downloads_pending"> <plurals name="downloads_pending">
<item quantity="one">1 in queue</item> <item quantity="one">1 in queue</item>
<item quantity="other">%d in queue</item> <item quantity="other">%d in queue</item>
@ -708,6 +709,7 @@
<!-- Information Text --> <!-- Information Text -->
<string name="information_no_downloads">No downloads</string> <string name="information_no_downloads">No downloads</string>
<string name="nothing_downloading">Nothing currently downloading</string>
<string name="information_no_recent">No recent chapters</string> <string name="information_no_recent">No recent chapters</string>
<string name="information_no_recent_manga">No recently read manga</string> <string name="information_no_recent_manga">No recently read manga</string>
<string name="information_empty_library">Your library is empty, add series to your library from the catalogues.</string> <string name="information_empty_library">Your library is empty, add series to your library from the catalogues.</string>

Loading…
Cancel
Save