diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt index 4b57d19347..99c56dd085 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.data.glide import android.content.Context -import android.graphics.drawable.Drawable import com.bumptech.glide.Glide import com.bumptech.glide.GlideBuilder import com.bumptech.glide.Registry @@ -9,9 +8,7 @@ import com.bumptech.glide.annotation.GlideModule import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader import com.bumptech.glide.load.DecodeFormat import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory -import com.bumptech.glide.load.engine.cache.LruResourceCache import com.bumptech.glide.load.model.GlideUrl -import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.module.AppGlideModule import com.bumptech.glide.request.RequestOptions import eu.kanade.tachiyomi.data.database.models.Manga @@ -27,10 +24,10 @@ import java.io.InputStream class TachiGlideModule : AppGlideModule() { override fun applyOptions(context: Context, builder: GlideBuilder) { - builder.setDiskCache(InternalCacheDiskCacheFactory(context, 100 * 1024 * 1024)) + builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024)) builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565)) - val memoryCacheSizeBytes = 1024 * 1024 * 100 // 100mb - builder.setMemoryCache(LruResourceCache(memoryCacheSizeBytes.toLong())) + //val memoryCacheSizeBytes = 1024 * 1024 * 100 // 100mb + //builder.setMemoryCache(LruResourceCache(memoryCacheSizeBytes.toLong())) /* builder.setDefaultTransitionOptions( Drawable::class.java, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt index 418e47ea35..b1624cc18f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt @@ -35,17 +35,15 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.ui.main.MainActivity -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.system.isServiceRunning import eu.kanade.tachiyomi.util.system.notification import eu.kanade.tachiyomi.util.system.notificationManager +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch import rx.Observable import rx.Subscription import rx.schedulers.Schedulers @@ -296,12 +294,9 @@ class LibraryUpdateService( val target = intent.getSerializableExtra(KEY_TARGET) as? Target ?: return START_NOT_STICKY // Unsubscribe from any previous subscription if needed. + job?.cancel() subscription?.unsubscribe() - val handler = CoroutineExceptionHandler { _, exception -> - Timber.e(exception) - stopSelf(startId) - } val selectedScheme = preferences.libraryUpdatePrioritization().getOrDefault() if (target == Target.CHAPTERS) { updateChapters( @@ -331,13 +326,15 @@ class LibraryUpdateService( private fun updateChapters(mangaToAdd: List, startId: Int) { addManga(mangaToAdd) - if (job == null) { - job = GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT) { - updateChaptersJob() - mangaToUpdate.clear() - categoryIds.clear() - stopSelf(startId) - } + val handler = CoroutineExceptionHandler { _, exception -> + Timber.e(exception) + stopSelf(startId) + } + job = GlobalScope.launch(handler) { + updateChaptersJob() + mangaToUpdate.clear() + categoryIds.clear() + stopSelf(startId) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt index b023934fdc..90c1fa4b41 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt @@ -160,5 +160,7 @@ class LibraryCategoryAdapter(val libraryListener: LibraryListener) : fun startReading(position: Int) fun onItemReleased(position: Int) fun canDrag(): Boolean + fun updateCategory(catId: Int): Boolean + fun sortCategory(catId: Int, sortBy: Int): String } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt index 5c862f86a4..ece03226e3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt @@ -90,7 +90,6 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att } } - recycler.setHasFixedSize(true) recycler.adapter = adapter swipe_refresh.addView(recycler) @@ -392,4 +391,12 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att controller.invalidateActionMode() } + override fun updateCategory(catId: Int): Boolean { + return true + } + + override fun sortCategory(catId: Int, sortBy: Int): String { + return "" + } + } 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 90ef30ce48..e2009a255b 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 @@ -20,8 +20,8 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode import androidx.appcompat.widget.AppCompatSpinner import androidx.appcompat.widget.SearchView -import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.math.MathUtils.clamp import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -67,13 +67,14 @@ import eu.kanade.tachiyomi.util.view.gone import eu.kanade.tachiyomi.util.view.inflate import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener import eu.kanade.tachiyomi.util.view.snack -import eu.kanade.tachiyomi.util.view.updateLayoutParams import eu.kanade.tachiyomi.util.view.updatePaddingRelative import eu.kanade.tachiyomi.util.view.visible import eu.kanade.tachiyomi.widget.AutofitRecyclerView import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener import kotlinx.android.synthetic.main.filter_bottom_sheet.* import kotlinx.android.synthetic.main.library_controller.* +import kotlinx.coroutines.delay +import timber.log.Timber import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -179,7 +180,7 @@ class LibraryController( private var spinnerAdapter: SpinnerAdapter? = null - var scrollLister = object : RecyclerView.OnScrollListener () { + private var scrollListener = object : RecyclerView.OnScrollListener () { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) val position = @@ -197,10 +198,10 @@ class LibraryController( bottom_sheet.lastCategory = category if (preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP) bottom_sheet.updateTitle() - // spinner.onItemSelectedListener = null + updateScroll = true + spinner.setSelection(order + 1) spinnerAdapter?.setCustomText(category?.name) - //spinner.view - //spinner.post { spinner.onItemSelectedListener = listener } + } } } @@ -259,11 +260,11 @@ class LibraryController( else { adapter = LibraryCategoryAdapter(this) recycler = if (preferences.libraryLayout().getOrDefault() == 0) { - (swipe_refresh.inflate(R.layout.library_list_recycler) as RecyclerView).apply { + (recycler_layout.inflate(R.layout.library_list_recycler) as RecyclerView).apply { layoutManager = LinearLayoutManager(context) } } else { - (swipe_refresh.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply { + (recycler_layout.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply { spanCount = mangaPerRow manager.spanSizeLookup = (object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { @@ -280,9 +281,9 @@ class LibraryController( //adapter.setStickyHeaders(true) recycler_layout.addView(recycler) adapter.fastScroller = fast_scroller - recycler.addOnScrollListener(scrollLister) + recycler.addOnScrollListener(scrollListener) - spinner = swipe_refresh.inflate(R.layout.library_spinner) as AppCompatSpinner + spinner = recycler_layout.inflate(R.layout.library_spinner) as AppCompatSpinner (activity as MainActivity).supportActionBar?.setDisplayShowCustomEnabled(true) (activity as MainActivity).supportActionBar?.customView = spinner spinnerAdapter = SpinnerAdapter(view.context, R.layout.library_spinner_textview, @@ -299,7 +300,7 @@ class LibraryController( //bottom_sheet.onCreate(pager_layout) - bottom_sheet.onCreate(if (usePager) pager_layout else swipe_refresh) + bottom_sheet.onCreate(if (usePager) pager_layout else recycler_layout) bottom_sheet.onGroupClicked = { when (it) { @@ -334,9 +335,6 @@ class LibraryController( if (!usePager && !phoneLandscape) { val height = view.context.resources.getDimensionPixelSize(R.dimen.rounder_radius) + 5.dpToPx recycler.updatePaddingRelative(bottom = height) - fast_scroller.updateLayoutParams { - bottomMargin = height - } } if (presenter.isDownloading()) { @@ -350,7 +348,7 @@ class LibraryController( if (library != null) presenter.updateViewBlocking() //onNextLibraryUpdate(presenter.categories, library) else { library_pager.alpha = 0f - swipe_refresh.alpha = 0f + recycler_layout.alpha = 0f presenter.getLibraryBlocking() } } @@ -466,8 +464,8 @@ class LibraryController( spinnerAdapter?.setCustomText(presenter.categories.find { it.order == activeCategory }?.name ?: resources?.getString(R.string.label_library)) justStarted = false - if (swipe_refresh.alpha == 0f) - swipe_refresh.animate().alpha(1f).setDuration(500).start() + if (recycler_layout.alpha == 0f) + recycler_layout.animate().alpha(1f).setDuration(500).start() }else { @@ -475,7 +473,18 @@ class LibraryController( (recycler.layoutManager as LinearLayoutManager) .scrollToPositionWithOffset(position, 0) } + adapter.isLongPressDragEnabled = canDrag() + + bottom_sheet.lastCategory = presenter.categories[clamp(activeCategory, + 0, + presenter.categories.size - 1)] + bottom_sheet.updateTitle() + updateScroll = false spinner.onItemSelectedListener = IgnoreFirstSpinnerListener { pos -> + if (updateScroll) { + updateScroll = false + return@IgnoreFirstSpinnerListener + } val headerPosition = adapter.indexOf(pos - 1) + 1 if (headerPosition > -1) { (recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset( @@ -589,11 +598,11 @@ class LibraryController( recycler !is AutofitRecyclerView && preferences.libraryLayout().getOrDefault() > 0) { recycler_layout.removeView(recycler) recycler = if (preferences.libraryLayout().getOrDefault() == 0) { - (swipe_refresh.inflate(R.layout.library_list_recycler) as RecyclerView).apply { + (recycler_layout.inflate(R.layout.library_list_recycler) as RecyclerView).apply { layoutManager = LinearLayoutManager(context) } } else { - (swipe_refresh.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply { + (recycler_layout.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply { spanCount = mangaPerRow manager.spanSizeLookup = (object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { @@ -605,7 +614,7 @@ class LibraryController( } } recycler.setHasFixedSize(true) - recycler.addOnScrollListener(scrollLister) + recycler.addOnScrollListener(scrollListener) recycler_layout.addView(recycler) } recycler.adapter = adapter @@ -667,6 +676,8 @@ class LibraryController( setOnQueryTextChangeListener(searchView) { query = it ?: "" searchRelay.call(query) + adapter.setFilter(it) + adapter.performFilter() true } searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() }) @@ -800,6 +811,11 @@ class LibraryController( override fun onDestroyActionMode(mode: ActionMode?) { // Clear all the manga selections and notify child views. selectedMangas.clear() + adapter.mode = SelectableAdapter.Mode.SINGLE + adapter.clearSelection() + adapter.notifyDataSetChanged() + lastClickPosition = -1 + adapter.isLongPressDragEnabled = canDrag() selectionRelay.call(LibrarySelectionEvent.Cleared()) actionMode = null } @@ -817,11 +833,33 @@ class LibraryController( fun setSelection(manga: Manga, selected: Boolean) { if (selected) { if (selectedMangas.add(manga)) { - selectionRelay.call(LibrarySelectionEvent.Selected(manga)) + if (usePager) selectionRelay.call(LibrarySelectionEvent.Selected(manga)) + else { + val position = adapter.indexOf(manga) + if (adapter.mode != SelectableAdapter.Mode.MULTI) { + adapter.mode = SelectableAdapter.Mode.MULTI + } + launchUI { + delay(100) + adapter.isLongPressDragEnabled = false + } + adapter.toggleSelection(position) + (recycler.findViewHolderForItemId(manga.id!!) as? LibraryHolder)?.toggleActivation() + } } } else { if (selectedMangas.remove(manga)) { - selectionRelay.call(LibrarySelectionEvent.Unselected(manga)) + if (usePager) selectionRelay.call(LibrarySelectionEvent.Unselected(manga)) + else { + val position = adapter.indexOf(manga) + lastClickPosition = -1 + if (selectedMangas.isEmpty()) { + adapter.mode = SelectableAdapter.Mode.SINGLE + adapter.isLongPressDragEnabled = canDrag() + } + adapter.toggleSelection(position) + (recycler.findViewHolderForItemId(manga.id!!) as? LibraryHolder)?.toggleActivation() + } } } } @@ -876,16 +914,13 @@ class LibraryController( override fun startReading(position: Int) { val activity = activity ?: return val manga = (adapter.getItem(position) as? LibraryItem)?.manga ?: return + if (adapter.mode == SelectableAdapter.Mode.MULTI) toggleSelection(position) val chapter = presenter.getFirstUnread(manga) ?: return val intent = ReaderActivity.newIntent(activity, manga, chapter) destroyActionModeIfNeeded() startActivity(intent) } - override fun onItemReleased(position: Int) { - - } - fun startReading(manga: Manga) { val activity = activity ?: return val chapter = presenter.getFirstUnread(manga) ?: return @@ -953,9 +988,9 @@ class LibraryController( * @param position the position to toggle. */ private fun toggleSelection(position: Int) { - val item = adapter.getItem(position) ?: return + val item = adapter.getItem(position) as? LibraryItem ?: return - setSelection((item as LibraryItem).manga, !adapter.isSelected(position)) + setSelection(item.manga, !adapter.isSelected(position)) invalidateActionMode() } @@ -966,14 +1001,29 @@ class LibraryController( * @param position the position to toggle. */ private fun setSelection(position: Int) { - val item = adapter.getItem(position) ?: return + val item = adapter.getItem(position) as? LibraryItem ?: return - setSelection((item as LibraryItem).manga, true) + setSelection(item.manga, true) invalidateActionMode() } override fun onItemMove(fromPosition: Int, toPosition: Int) { } + override fun onItemReleased(position: Int) { + if (adapter.selectedItemCount > 0) return + val item = adapter.getItem(position) as? LibraryItem ?: return + val newHeader = adapter.getSectionHeader(position) as? LibraryHeaderItem + val libraryItems = adapter.getSectionItems(adapter.getSectionHeader(position)).filterIsInstance() + val mangaIds = libraryItems.mapNotNull { (it as? LibraryItem)?.manga?.id } + if (newHeader?.category?.id == item.manga.category) { + presenter.rearrangeCategory(item.manga.category, mangaIds) + } else { + presenter.moveMangaToCategory(item, newHeader?.category?.id, mangaIds) + Timber.d("Manga has Moved") + } + } + + override fun shouldMoveItem(fromPosition: Int, toPosition: Int): Boolean { if (adapter.selectedItemCount > 1) return false @@ -981,6 +1031,29 @@ class LibraryController( toggleSelection(fromPosition) return true } + + override fun updateCategory(catId: Int): Boolean { + val category = (adapter.getItem(catId) as? LibraryHeaderItem)?.category ?: + return false + val inQueue = LibraryUpdateService.categoryInQueue(category.id) + snack?.dismiss() + snack = snackbar_layout.snack(resources!!.getString( + when { + inQueue -> R.string.category_already_in_queue + LibraryUpdateService.isRunning(view!!.context) -> + R.string.adding_category_to_queue + else -> R.string.updating_category_x + }, category.name)) + if (!inQueue) + LibraryUpdateService.start(view!!.context, category) + return true + + } + + override fun sortCategory(catId: Int, sortBy: Int): String { + presenter.sortCategory(catId, sortBy) + return "" + } } object HeightTopWindowInsetsListener : View.OnApplyWindowInsetsListener { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHeaderItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHeaderItem.kt index 3b531756ba..542a0b6792 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHeaderItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHeaderItem.kt @@ -1,14 +1,25 @@ package eu.kanade.tachiyomi.ui.library +import android.graphics.drawable.Drawable import android.view.View +import android.widget.ProgressBar import android.widget.TextView +import androidx.appcompat.view.menu.MenuBuilder +import androidx.appcompat.widget.PopupMenu +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.button.MaterialButton import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.AbstractHeaderItem import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.viewholders.FlexibleViewHolder import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Category +import eu.kanade.tachiyomi.data.library.LibraryUpdateService +import eu.kanade.tachiyomi.util.system.getResourceColor +import eu.kanade.tachiyomi.util.view.gone +import eu.kanade.tachiyomi.util.view.invisible +import eu.kanade.tachiyomi.util.view.visible class LibraryHeaderItem(val category: Category) : AbstractHeaderItem() { @@ -20,7 +31,7 @@ class LibraryHeaderItem(val category: Category) : AbstractHeaderItem> ): Holder { - return Holder(view, adapter) + return Holder(view, adapter as LibraryCategoryAdapter) } override fun bindViewHolder( @@ -49,16 +60,120 @@ class LibraryHeaderItem(val category: Category) : AbstractHeaderItem>) : + class Holder(view: View, private val adapter: LibraryCategoryAdapter) : FlexibleViewHolder(view, adapter, true) { private val sectionText: TextView = view.findViewById(R.id.category_title) + private val sortText: TextView = view.findViewById(R.id.category_sort) + private val updateButton: MaterialButton = view.findViewById(R.id.update_button) + private val catProgress: ProgressBar = view.findViewById(R.id.cat_progress) + + init { + updateButton.setOnClickListener { addCategoryToUpdate() } + sortText.setOnClickListener { showCatSortOptions() } + } fun bind(item: LibraryHeaderItem) { sectionText.text = item.category.name + sortText.text = itemView.context.getString( + when (item.category.sortingMode()) { + LibrarySort.LAST_UPDATED -> R.string.action_sort_last_updated + LibrarySort.DRAG_AND_DROP -> R.string.action_sort_drag_and_drop + LibrarySort.TOTAL -> R.string.action_sort_total + LibrarySort.UNREAD -> R.string.action_filter_unread + LibrarySort.LAST_READ -> R.string.action_sort_last_read + LibrarySort.ALPHA -> R.string.title + else -> R.string.action_sort_drag_and_drop + } + ) + + if (LibraryUpdateService.categoryInQueue(item.category.id)) { + catProgress.visible() + updateButton.invisible() + } else { + catProgress.gone() + updateButton.visible() + } + } + + private fun addCategoryToUpdate() { + if (adapter.libraryListener.updateCategory(adapterPosition)) { + catProgress.visible() + updateButton.invisible() + } + } + + private fun showCatSortOptions() { + val category = + (adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category ?: return + // Create a PopupMenu, giving it the clicked view for an anchor + val popup = PopupMenu(itemView.context, sortText) + + // Inflate our menu resource into the PopupMenu's Menu + popup.menuInflater.inflate(R.menu.cat_sort, popup.menu) + + // Set a listener so we are notified if a menu item is clicked + popup.setOnMenuItemClickListener { menuItem -> + onCatSortClicked(category, menuItem.itemId) + true + } + + val sortingMode = category.sortingMode() + val currentItem = if (sortingMode == null) null + else popup.menu.findItem( + when (sortingMode) { + LibrarySort.DRAG_AND_DROP -> R.id.action_drag_and_drop + LibrarySort.TOTAL -> R.id.action_total_chaps + LibrarySort.LAST_READ -> R.id.action_last_read + LibrarySort.UNREAD -> R.id.action_unread + LibrarySort.LAST_UPDATED -> R.id.action_update + else -> R.id.action_alpha + } + ) + + if (sortingMode != null && popup.menu is MenuBuilder) { + val m = popup.menu as MenuBuilder + m.setOptionalIconsVisible(true) + } + + currentItem?.icon = tintVector( + if (category.isAscending()) R.drawable.ic_arrow_up_white_24dp + else R.drawable.ic_arrow_down_white_24dp + ) + + // Finally show the PopupMenu + popup.show() + } + + private fun tintVector(resId: Int): Drawable? { + return ContextCompat.getDrawable(itemView.context, resId)?.mutate()?.apply { + setTint(itemView.context.getResourceColor(android.R.attr.colorAccent)) + } + } + + private fun onCatSortClicked(category: Category, menuId: Int?) { + val modType = if (menuId == null) { + val t = (category.mangaSort?.minus('a') ?: 0) + 1 + if (t % 2 != 0) t + 1 + else t - 1 + } + else { + val order = when (menuId) { + R.id.action_last_read -> 3 + R.id.action_unread -> 2 + R.id.action_update -> 1 + else -> 0 + } + if (order == category.catSortingMode()) { + onCatSortClicked(category, null) + return + } + (2 * order + 1) + } + adapter.libraryListener.sortCategory(category.id!!, modType) } } } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 3a99be68e4..71f11d090e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -486,20 +486,12 @@ class LibraryPresenter( suspend fun updateView(categories: List, mangaMap: LibraryMap, freshStart:Boolean = false) { - /* val list = withContext(Dispatchers.IO) { - val showCategories = !preferences.hideCategories().getOrDefault() - val current = mangaMap.values.first() - current.groupBy { - if (showCategories) it.manga.category else 0 - }.flatMap { it.value } - }*/ if (preferences.libraryUsingPager().getOrDefault()) { view.onNextLibraryUpdate(categories, mangaMap, true) } else { val mangaList = withContext(Dispatchers.IO) { val list = mutableListOf() - val many = categories.size > 1 for (element in mangaMap.toSortedMap(compareBy { entry -> categories.find { it.id == entry }?.order ?: -1 })) { @@ -771,8 +763,67 @@ class LibraryPresenter( } + fun sortCategory(catId: Int, order: Int) { + val category = categories.find { catId == it.id } ?: return + category.mangaSort = ('a' + (order - 1)) + if (category.id == 0) + preferences.defaultMangaOrder().set(category.mangaSort.toString()) + else + Injekt.get().insertCategory(category).asRxObservable().subscribe() + requestCatSortUpdate(category.id!!) + } + + fun rearrangeCategory(catId: Int?, mangaIds: List) { + GlobalScope.launch(Dispatchers.IO) { + val category = categories.find { catId == it.id } ?: return@launch + category.mangaSort = null + category.mangaOrder = mangaIds + if (category.id == 0) preferences.defaultMangaOrder().set(mangaIds.joinToString("/")) + else db.insertCategory(category).executeAsBlocking() + requestCatSortUpdate(category.id!!) + } + } + + fun moveMangaToCategory(item: LibraryItem, catId: Int?, mangaIds: List) { + GlobalScope.launch(Dispatchers.IO) { + val categoryId = catId ?: return@launch + val category = categories.find { catId == it.id } ?: return@launch + val manga = item.manga + + val mangaMap = currentMangaMap?.toMutableMap() ?: return@launch + val oldCatId = item.manga.category + val oldCatMap = mangaMap[manga.category]?.toMutableList() ?: return@launch + val newCatMap = mangaMap[catId]?.toMutableList() ?: return@launch + oldCatMap.remove(item) + newCatMap.add(item) + mangaMap[oldCatId] = oldCatMap + mangaMap[catId] = newCatMap + currentMangaMap = mangaMap + + item.manga.category = categoryId + + val mc = ArrayList() + val categories = + db.getCategoriesForManga(manga).executeAsBlocking().filter { it.id != oldCatId } + listOf(category) + + for (cat in categories) { + mc.add(MangaCategory.create(manga, cat)) + } + + db.setMangaCategories(mc, listOf(manga)) + + category.mangaSort = null + val ids = mangaIds.toMutableList() + if (!ids.contains(manga.id!!)) + ids.add(manga.id!!) + category.mangaOrder = ids + if (category.id == 0) preferences.defaultMangaOrder().set(mangaIds.joinToString("/")) + else db.insertCategory(category).executeAsBlocking() + getLibrary() + } + } + private companion object { var currentLibrary:Library? = null - var currentList:List? = null } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/SortFilterBottomSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/SortFilterBottomSheet.kt index 4594d72ab4..db6dd8db32 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/SortFilterBottomSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/SortFilterBottomSheet.kt @@ -10,11 +10,10 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.LinearLayout -import android.widget.RadioButton -import android.widget.RadioGroup import android.widget.Spinner import androidx.appcompat.view.menu.MenuBuilder import androidx.appcompat.widget.PopupMenu +import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.ContextCompat import com.f2prateek.rx.preferences.Preference import com.google.android.material.bottomsheet.BottomSheetBehavior @@ -122,6 +121,7 @@ class SortFilterBottomSheet @JvmOverloads constructor(context: Context, attrs: A updateTitle() val shadow2:View = (pagerView.parent as ViewGroup).findViewById(R.id.shadow2) val shadow:View = (pagerView.parent as ViewGroup).findViewById(R.id.shadow) + val fastScroller:View = (pagerView.parent as ViewGroup).findViewById(R.id.fast_scroller) val coordLayout:View = (pagerView.parent as ViewGroup).findViewById(R.id.snackbar_layout) val phoneLandscape = (isLandscape() && !isTablet()) if (phoneLandscape) @@ -167,6 +167,9 @@ class SortFilterBottomSheet @JvmOverloads constructor(context: Context, attrs: A } if (sheetBehavior?.state == BottomSheetBehavior.STATE_COLLAPSED) { val height = context.resources.getDimensionPixelSize(R.dimen.rounder_radius) + fastScroller.updateLayoutParams { + bottomMargin = if (phoneLandscape) 0 else (top_bar.height - height) + } pager?.setPadding(0, 0, 0, if (phoneLandscape) 0 else (top_bar.height - height)) coordLayout.setPadding(0, 0, 0, peekingHeight) diff --git a/app/src/main/res/layout/catalogue_grid_item.xml b/app/src/main/res/layout/catalogue_grid_item.xml index 13810dad96..16b0316401 100644 --- a/app/src/main/res/layout/catalogue_grid_item.xml +++ b/app/src/main/res/layout/catalogue_grid_item.xml @@ -1,154 +1,161 @@ - + android:layout_gravity="bottom"> - + android:background="@drawable/library_compact_grid_selector" + android:minHeight="200dp" + android:orientation="vertical"> - - + app:layout_constraintVertical_bias="1.0"> - + android:id="@+id/cover_thumbnail" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:adjustViewBounds="true" + android:background="?android:attr/colorBackground" + android:maxHeight="250dp" + app:layout_constrainedHeight="true" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:background="?android:attr/colorBackground" + tools:ignore="ContentDescription" + tools:src="@mipmap/ic_launcher" /> - + + + + + + + + + + + + + + android:layout_height="10dp" + app:layout_constraintTop_toTopOf="@+id/card" /> - - - + + + + + tools:text="Sample artist" /> - - - - - - - - - - - \ No newline at end of file + + \ No newline at end of file diff --git a/app/src/main/res/layout/library_category_header_item.xml b/app/src/main/res/layout/library_category_header_item.xml index ac6a50c740..8b844c138c 100644 --- a/app/src/main/res/layout/library_category_header_item.xml +++ b/app/src/main/res/layout/library_category_header_item.xml @@ -1,27 +1,74 @@ - + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/library_controller.xml b/app/src/main/res/layout/library_controller.xml index ca580fbaa2..e2a9b5b6c9 100644 --- a/app/src/main/res/layout/library_controller.xml +++ b/app/src/main/res/layout/library_controller.xml @@ -6,16 +6,12 @@ android:id="@+id/library_layout" android:layout_height="match_parent"> - - - - + +