mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-09 19:55:11 +01:00
Converted long press for hide and pin into a swipe and button
respectively
This commit is contained in:
parent
5871572442
commit
aef79bafad
@ -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.
|
||||
*/
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
/**
|
||||
|
8
app/src/main/res/drawable/ic_pin_24dp.xml
Normal file
8
app/src/main/res/drawable/ic_pin_24dp.xml
Normal 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>
|
8
app/src/main/res/drawable/ic_pin_outline_24dp.xml
Normal file
8
app/src/main/res/drawable/ic_pin_outline_24dp.xml
Normal 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>
|
@ -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>
|
||||
|
@ -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 -->
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user