Converted long press for hide and pin into a swipe and button

respectively
This commit is contained in:
Jay 2020-04-19 14:52:22 -04:00
parent 5871572442
commit aef79bafad
10 changed files with 170 additions and 32 deletions

View File

@ -21,6 +21,10 @@ data class LangItem(val code: String) : AbstractHeaderItem<LangHolder>() {
return R.layout.source_header_item
}
override fun isSwipeable(): Boolean {
return false
}
/**
* Creates a new view holder for this item.
*/

View File

@ -29,6 +29,11 @@ class SourceAdapter(val controller: SourceController) :
*/
val latestClickListener: OnLatestClickListener = controller
override fun onItemSwiped(position: Int, direction: Int) {
super.onItemSwiped(position, direction)
controller.hideCatalogue(position)
}
/**
* Listener which should be called when user clicks browse.
* Note: Should only be handled by [SourceController]

View File

@ -10,13 +10,12 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.SearchView
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItems
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.Snackbar
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R
@ -38,6 +37,7 @@ import eu.kanade.tachiyomi.ui.source.latest.LatestUpdatesController
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
import eu.kanade.tachiyomi.util.view.scrollViewWith
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
import eu.kanade.tachiyomi.util.view.snack
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.extensions_bottom_sheet.*
import kotlinx.android.synthetic.main.main_activity.*
@ -54,7 +54,6 @@ import kotlin.math.max
*/
class SourceController : NucleusController<SourcePresenter>(),
FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener,
SourceAdapter.OnBrowseClickListener,
RootSearchInterface,
BottomSheetController,
@ -77,6 +76,8 @@ class SourceController : NucleusController<SourcePresenter>(),
var showingExtensions = false
var snackbar: Snackbar? = null
/**
* Called when controller is initialized.
*/
@ -114,6 +115,7 @@ class SourceController : NucleusController<SourcePresenter>(),
// Create recycler and set adapter.
recycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(view.context)
recycler.adapter = adapter
adapter?.isSwipeEnabled = true
// recycler.addItemDecoration(SourceDividerItemDecoration(view.context))
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
val array = view.context.obtainStyledAttributes(attrsArray)
@ -216,29 +218,22 @@ class SourceController : NucleusController<SourcePresenter>(),
return false
}
override fun onItemLongClick(position: Int) {
val activity = activity ?: return
val item = adapter?.getItem(position) as? SourceItem ?: return
val isPinned = item.header?.code?.equals(SourcePresenter.PINNED_KEY) ?: false
MaterialDialog(activity)
.title(text = item.source.name)
.listItems(items = listOf(
activity.getString(R.string.hide),
activity.getString(if (isPinned) R.string.unpin else R.string.pin)
), waitForPositiveButton = false, selection = { _, index, _ ->
when (index) {
0 -> hideCatalogue(item.source)
1 -> pinCatalogue(item.source, isPinned)
}
}).show()
}
private fun hideCatalogue(source: Source) {
fun hideCatalogue(position: Int) {
val source = (adapter?.getItem(position) as? SourceItem)?.source ?: return
val current = preferences.hiddenSources().getOrDefault()
preferences.hiddenSources().set(current + source.id.toString())
presenter.updateSources()
snackbar = view?.snack(R.string.source_hidden, Snackbar.LENGTH_INDEFINITE) {
anchorView = ext_bottom_sheet
setAction(R.string.undo) {
val newCurrent = preferences.hiddenSources().getOrDefault()
preferences.hiddenSources().set(newCurrent - source.id.toString())
presenter.updateSources()
}
}
(activity as? MainActivity)?.setUndoSnackBar(snackbar)
}
private fun pinCatalogue(source: Source, isPinned: Boolean) {
@ -256,7 +251,10 @@ class SourceController : NucleusController<SourcePresenter>(),
* Called when browse is clicked in [SourceAdapter]
*/
override fun onBrowseClick(position: Int) {
onItemClick(view!!, position)
val item = adapter?.getItem(position) as? SourceItem ?: return
val isPinned = item.isPinned ?: item.header?.code?.equals(SourcePresenter.PINNED_KEY)
?: false
pinCatalogue(item.source, isPinned)
}
/**

View File

@ -1,8 +1,11 @@
package eu.kanade.tachiyomi.ui.source
import android.content.res.ColorStateList
import android.view.View
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.icon
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.roundTextIcon
import eu.kanade.tachiyomi.util.view.visible
@ -19,6 +22,9 @@ class SourceHolder(view: View, val adapter: SourceAdapter) :
get() = card*/
init {
source_pin.setOnClickListener {
adapter.browseClickListener.onBrowseClick(adapterPosition)
}
source_latest.setOnClickListener {
adapter.latestClickListener.onLatestClick(adapterPosition)
}
@ -31,6 +37,20 @@ class SourceHolder(view: View, val adapter: SourceAdapter) :
// Set source name
title.text = source.name
val isPinned = item.isPinned ?: item.header?.code?.equals(SourcePresenter.PINNED_KEY) ?: false
source_pin.apply {
imageTintList = ColorStateList.valueOf(
context.getResourceColor(
if (isPinned) R.attr.colorAccent
else android.R.attr.textColorSecondary
)
)
setImageResource(
if (isPinned) R.drawable.ic_pin_24dp
else R.drawable.ic_pin_outline_24dp
)
}
// Set circle letter image.
itemView.post {
val icon = source.icon()
@ -44,4 +64,16 @@ class SourceHolder(view: View, val adapter: SourceAdapter) :
source_latest.gone()
}
}
override fun getFrontView(): View {
return card
}
override fun getRearLeftView(): View {
return left_view
}
override fun getRearRightView(): View {
return right_view
}
}

View File

@ -7,6 +7,7 @@ import eu.davidea.flexibleadapter.items.AbstractSectionableItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.LocalSource
/**
* Item that contains source information.
@ -14,7 +15,7 @@ import eu.kanade.tachiyomi.source.CatalogueSource
* @param source Instance of [CatalogueSource] containing source information.
* @param header The header for this item.
*/
data class SourceItem(val source: CatalogueSource, val header: LangItem? = null) :
class SourceItem(val source: CatalogueSource, header: LangItem? = null, val isPinned: Boolean? = null) :
AbstractSectionableItem<SourceHolder, LangItem>(header) {
/**
@ -24,17 +25,40 @@ data class SourceItem(val source: CatalogueSource, val header: LangItem? = null)
return R.layout.source_item
}
override fun isSwipeable(): Boolean {
return source.id != LocalSource.ID
}
/**
* Creates a new view holder for this item.
*/
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): SourceHolder {
override fun createViewHolder(
view: View,
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
): SourceHolder {
return SourceHolder(view, adapter as SourceAdapter)
}
/**
* Binds this item to the given view holder.
*/
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: SourceHolder, position: Int, payloads: MutableList<Any>) {
override fun bindViewHolder(
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
holder: SourceHolder,
position: Int,
payloads: MutableList<Any>
) {
holder.bind(this)
}
override fun equals(other: Any?): Boolean {
if (other is SourceItem) {
return source.id == other.source.id && header?.code == other.header?.code
}
return false
}
override fun hashCode(): Int {
return source.id.hashCode() + (header?.code?.hashCode() ?: 0).toInt()
}
}

View File

@ -33,6 +33,7 @@ class SourcePresenter(
* Subscription for retrieving enabled sources.
*/
private var sourceSubscription: Subscription? = null
private var lastUsedSubscription: Subscription? = null
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
@ -63,11 +64,12 @@ class SourcePresenter(
var sourceItems = byLang.flatMap {
val langItem = LangItem(it.key)
it.value.map { source ->
val isPinned = source.id.toString() in pinnedCatalogues
if (source.id.toString() in pinnedCatalogues) {
pinnedSources.add(SourceItem(source, LangItem(PINNED_KEY)))
}
SourceItem(source, langItem)
SourceItem(source, langItem, isPinned)
}
}
@ -80,20 +82,25 @@ class SourcePresenter(
}
private fun loadLastUsedSource() {
lastUsedSubscription?.unsubscribe()
val sharedObs = preferences.lastUsedCatalogueSource().asObservable().share()
// Emit the first item immediately but delay subsequent emissions by 500ms.
Observable.merge(
lastUsedSubscription = Observable.merge(
sharedObs.take(1),
sharedObs.skip(1).delay(500, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()))
.distinctUntilChanged()
.map { (sourceManager.get(it) as? CatalogueSource)?.let { SourceItem(it) } }
.map { (sourceManager.get(it) as? CatalogueSource)?.let { source ->
val pinnedCatalogues = preferences.pinnedCatalogues().getOrDefault()
val isPinned = source.id.toString() in pinnedCatalogues
SourceItem(source, null, isPinned) } }
.subscribeLatestCache(SourceController::setLastUsedSource)
}
fun updateSources() {
sources = getEnabledSources()
loadSources()
loadLastUsedSource()
}
/**

View File

@ -0,0 +1,8 @@
<!-- drawable/pin.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12Z" />
</vector>

View File

@ -0,0 +1,8 @@
<!-- drawable/pin_outline.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12M8.8,14L10,12.8V4H14V12.8L15.2,14H8.8Z" />
</vector>

View File

@ -6,6 +6,45 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:id="@+id/right_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/red_error"
android:visibility="gone">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/close_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end|center"
android:gravity="center"
android:layout_marginEnd="21dp"
android:contentDescription="@string/cancel"
android:src="@drawable/ic_close_white_24dp"
android:text="@string/hide"
android:textColor="@color/md_white_1000" />
</FrameLayout>
<FrameLayout
android:id="@+id/left_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/red_error">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/close_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start|center"
android:layout_marginStart="21dp"
android:gravity="center"
android:src="@drawable/ic_close_white_24dp"
android:text="@string/hide"
android:textColor="@color/md_white_1000" />
</FrameLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/card"
android:layout_width="match_parent"
@ -43,14 +82,26 @@
android:id="@+id/source_latest"
style="@style/Theme.Widget.Button.TextButton"
android:textColor="?colorAccent"
android:layout_marginEnd="12dp"
android:layout_marginEnd="4dp"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:letterSpacing="0.0"
android:text="@string/view_latest"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"/>
app:layout_constraintEnd_toStartOf="@id/source_pin"/>
<ImageButton
android:id="@+id/source_pin"
android:layout_marginEnd="8dp"
style="@style/Theme.Widget.CustomImageButton"
android:src="@drawable/ic_pin_24dp"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="10dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -213,6 +213,7 @@
<string name="search_extensions">Search extensions…</string>
<string name="all_sources">All sources</string>
<string name="sources">Sources</string>
<string name="source_hidden">Source hidden</string>
<!-- Other Screens -->