Browse Source

Add pin icon to sources list (closes #2862)

arkon 4 years ago
parent
commit
a52fbb012a

+ 3 - 14
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceAdapter.kt

@@ -22,26 +22,15 @@ class SourceAdapter(val controller: SourceController) :
     /**
      * Listener for browse item clicks.
      */
-    val browseClickListener: OnBrowseClickListener = controller
-
-    /**
-     * Listener for latest item clicks.
-     */
-    val latestClickListener: OnLatestClickListener = controller
+    val clickListener: OnSourceClickListener = controller
 
     /**
      * Listener which should be called when user clicks browse.
      * Note: Should only be handled by [SourceController]
      */
-    interface OnBrowseClickListener {
+    interface OnSourceClickListener {
         fun onBrowseClick(position: Int)
-    }
-
-    /**
-     * Listener which should be called when user clicks latest.
-     * Note: Should only be handled by [SourceController]
-     */
-    interface OnLatestClickListener {
         fun onLatestClick(position: Int)
+        fun onPinClick(position: Int)
     }
 }

+ 15 - 8
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceController.kt

@@ -41,15 +41,14 @@ import uy.kohesive.injekt.api.get
 /**
  * This controller shows and manages the different catalogues enabled by the user.
  * This controller should only handle UI actions, IO actions should be done by [SourcePresenter]
- * [SourceAdapter.OnBrowseClickListener] call function data on browse item click.
+ * [SourceAdapter.OnSourceClickListener] call function data on browse item click.
  * [SourceAdapter.OnLatestClickListener] call function data on latest item click
  */
 class SourceController :
     NucleusController<SourceMainControllerBinding, SourcePresenter>(),
     FlexibleAdapter.OnItemClickListener,
     FlexibleAdapter.OnItemLongClickListener,
-    SourceAdapter.OnBrowseClickListener,
-    SourceAdapter.OnLatestClickListener {
+    SourceAdapter.OnSourceClickListener {
 
     private val preferences: PreferencesHelper = Injekt.get()
 
@@ -134,7 +133,7 @@ class SourceController :
         val items = mutableListOf(
             Pair(
                 activity.getString(if (isPinned) R.string.action_unpin else R.string.action_pin),
-                { pinSource(item.source, isPinned) }
+                { toggleSourcePin(item.source) }
             )
         )
         if (item.source !is LocalSource) {
@@ -159,12 +158,12 @@ class SourceController :
         presenter.updateSources()
     }
 
-    private fun pinSource(source: Source, isPinned: Boolean) {
-        val current = preferences.pinnedSources().get()
+    private fun toggleSourcePin(source: Source) {
+        val isPinned = source.id.toString() in preferences.pinnedSources().get()
         if (isPinned) {
-            preferences.pinnedSources().set(current - source.id.toString())
+            preferences.pinnedSources() -= source.id.toString()
         } else {
-            preferences.pinnedSources().set(current + source.id.toString())
+            preferences.pinnedSources() += source.id.toString()
         }
 
         presenter.updateSources()
@@ -185,6 +184,14 @@ class SourceController :
         openSource(item.source, LatestUpdatesController(item.source))
     }
 
+    /**
+     * Called when pin icon is clicked in [SourceAdapter]
+     */
+    override fun onPinClick(position: Int) {
+        val item = adapter?.getItem(position) as? SourceItem ?: return
+        toggleSourcePin(item.source)
+    }
+
     /**
      * Opens a catalogue with the given controller.
      */

+ 16 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceHolder.kt

@@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.ui.base.holder.SlicedHolder
 import io.github.mthli.slice.Slice
 import kotlinx.android.synthetic.main.source_main_controller_card_item.card
 import kotlinx.android.synthetic.main.source_main_controller_card_item.image
+import kotlinx.android.synthetic.main.source_main_controller_card_item.pin
 import kotlinx.android.synthetic.main.source_main_controller_card_item.source_browse
 import kotlinx.android.synthetic.main.source_main_controller_card_item.source_latest
 import kotlinx.android.synthetic.main.source_main_controller_card_item.title
@@ -27,11 +28,15 @@ class SourceHolder(view: View, override val adapter: SourceAdapter) :
 
     init {
         source_browse.setOnClickListener {
-            adapter.browseClickListener.onBrowseClick(bindingAdapterPosition)
+            adapter.clickListener.onBrowseClick(bindingAdapterPosition)
         }
 
         source_latest.setOnClickListener {
-            adapter.latestClickListener.onLatestClick(bindingAdapterPosition)
+            adapter.clickListener.onLatestClick(bindingAdapterPosition)
+        }
+
+        pin.setOnClickListener {
+            adapter.clickListener.onPinClick(bindingAdapterPosition)
         }
     }
 
@@ -53,5 +58,14 @@ class SourceHolder(view: View, override val adapter: SourceAdapter) :
 
         source_browse.setText(R.string.browse)
         source_latest.isVisible = source.supportsLatest
+
+        pin.isVisible = true
+        pin.setImageResource(
+            if (item.isPinned) {
+                R.drawable.ic_push_pin_filled_24dp
+            } else {
+                R.drawable.ic_push_pin_24dp
+            }
+        )
     }
 }

+ 5 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceItem.kt

@@ -14,7 +14,11 @@ 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) :
+data class SourceItem(
+    val source: CatalogueSource,
+    val header: LangItem? = null,
+    val isPinned: Boolean = false
+) :
     AbstractSectionableItem<SourceHolder, LangItem>(header) {
 
     /**

+ 4 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt

@@ -72,11 +72,12 @@ class SourcePresenter(
         var sourceItems = byLang.flatMap {
             val langItem = LangItem(it.key)
             it.value.map { source ->
-                if (source.id.toString() in pinnedSourceIds) {
-                    pinnedSources.add(SourceItem(source, LangItem(PINNED_KEY)))
+                val isPinned = source.id.toString() in pinnedSourceIds
+                if (isPinned) {
+                    pinnedSources.add(SourceItem(source, LangItem(PINNED_KEY), isPinned))
                 }
 
-                SourceItem(source, langItem)
+                SourceItem(source, langItem, isPinned)
             }
         }
 

+ 9 - 0
app/src/main/res/drawable/ic_push_pin_24dp.xml

@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M14,4v5c0,1.12 0.37,2.16 1,3H9c0.65,-0.86 1,-1.9 1,-3V4H14M17,2H7C6.45,2 6,2.45 6,3c0,0.55 0.45,1 1,1c0,0 0,0 0,0l1,0v5c0,1.66 -1.34,3 -3,3v2h5.97v7l1,1l1,-1v-7H19v-2c0,0 0,0 0,0c-1.66,0 -3,-1.34 -3,-3V4l1,0c0,0 0,0 0,0c0.55,0 1,-0.45 1,-1C18,2.45 17.55,2 17,2L17,2z" />
+</vector>

+ 10 - 0
app/src/main/res/drawable/ic_push_pin_filled_24dp.xml

@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="#FF000000"
+        android:fillType="evenOdd"
+        android:pathData="M16,9V4l1,0c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H7C6.45,2 6,2.45 6,3v0c0,0.55 0.45,1 1,1l1,0v5c0,1.66 -1.34,3 -3,3h0v2h5.97v7l1,1l1,-1v-7H19v-2h0C17.34,12 16,10.66 16,9z" />
+</vector>

+ 22 - 1
app/src/main/res/layout/source_main_controller_card_item.xml

@@ -20,6 +20,7 @@
             app:layout_constraintDimensionRatio="1:1"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent"
+            tools:ignore="ContentDescription"
             tools:src="@mipmap/ic_launcher_round" />
 
         <TextView
@@ -43,7 +44,10 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:maxHeight="48dp"
+            android:minWidth="0dp"
             android:minHeight="48dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
             android:text="@string/latest"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toStartOf="@+id/source_browse"
@@ -55,12 +59,29 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:maxHeight="48dp"
+            android:minWidth="0dp"
             android:minHeight="48dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
             android:text="@string/browse"
             app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/pin"
             app:layout_constraintTop_toTopOf="parent" />
 
+        <ImageButton
+            android:id="@+id/pin"
+            android:layout_width="44dp"
+            android:layout_height="0dp"
+            android:alpha="0.75"
+            android:background="?selectableItemBackgroundBorderless"
+            android:contentDescription="@string/action_pin"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:srcCompat="@drawable/ic_push_pin_24dp"
+            app:tint="?attr/colorOnSurface" />
+
     </androidx.constraintlayout.widget.ConstraintLayout>
 
 </FrameLayout>