diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e56d2b92a..3964989bb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,8 +60,15 @@
android:windowSoftInputMode="stateAlwaysHidden" />
+ android:label="@string/favourites_categories"
+ android:windowSoftInputMode="stateAlwaysHidden" />
+
+
+
+
+
-
-
-
-
-
diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/FavouritesDao.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/FavouritesDao.kt
index 88f2a6997..b1f93dea3 100644
--- a/app/src/main/java/org/koitharu/kotatsu/core/db/FavouritesDao.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/core/db/FavouritesDao.kt
@@ -9,8 +9,12 @@ import org.koitharu.kotatsu.core.db.entity.MangaEntity
abstract class FavouritesDao {
@Transaction
- @Query("SELECT * FROM favourites GROUP BY manga_id ORDER BY :orderBy LIMIT :limit OFFSET :offset")
- abstract suspend fun findAll(offset: Int, limit: Int, orderBy: String): List
+ @Query("SELECT * FROM favourites GROUP BY manga_id ORDER BY created_at LIMIT :limit OFFSET :offset")
+ abstract suspend fun findAll(offset: Int, limit: Int): List
+
+ @Transaction
+ @Query("SELECT * FROM favourites WHERE category_id = :categoryId GROUP BY manga_id ORDER BY created_at LIMIT :limit OFFSET :offset")
+ abstract suspend fun findAll(categoryId: Long, offset: Int, limit: Int): List
@Query("SELECT * FROM manga WHERE manga_id IN (SELECT manga_id FROM favourites)")
abstract suspend fun findAllManga(): List
diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppWidgetConfig.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppWidgetConfig.kt
new file mode 100644
index 000000000..fa4d577e9
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppWidgetConfig.kt
@@ -0,0 +1,26 @@
+package org.koitharu.kotatsu.core.prefs
+
+import android.content.Context
+import android.content.SharedPreferences
+import org.koitharu.kotatsu.utils.delegates.prefs.LongPreferenceDelegate
+
+class AppWidgetConfig private constructor(
+ private val prefs: SharedPreferences,
+ val widgetId: Int
+) : SharedPreferences by prefs {
+
+ var categoryId by LongPreferenceDelegate(CATEGORY_ID, 0L)
+
+ companion object {
+
+ private const val CATEGORY_ID = "cat_id"
+
+ fun getInstance(context: Context, widgetId: Int) = AppWidgetConfig(
+ context.getSharedPreferences(
+ "appwidget_$widgetId",
+ Context.MODE_PRIVATE
+ ), widgetId
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/favourites/FavouritesRepository.kt b/app/src/main/java/org/koitharu/kotatsu/domain/favourites/FavouritesRepository.kt
index 5a29f4218..56be7dc1a 100644
--- a/app/src/main/java/org/koitharu/kotatsu/domain/favourites/FavouritesRepository.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/domain/favourites/FavouritesRepository.kt
@@ -19,7 +19,12 @@ class FavouritesRepository : KoinComponent {
private val db: MangaDatabase by inject()
suspend fun getAllManga(offset: Int): List {
- val entities = db.favouritesDao.findAll(offset, 20, "created_at")
+ val entities = db.favouritesDao.findAll(offset, 20)
+ return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) }
+ }
+
+ suspend fun getManga(categoryId: Long, offset: Int): List {
+ val entities = db.favouritesDao.findAll(categoryId, offset, 20)
return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) }
}
diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/CategorySelectAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/CategorySelectAdapter.kt
new file mode 100644
index 000000000..16b366fda
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/CategorySelectAdapter.kt
@@ -0,0 +1,35 @@
+package org.koitharu.kotatsu.ui.widget.shelf
+
+import android.view.ViewGroup
+import org.koitharu.kotatsu.core.model.FavouriteCategory
+import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
+import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
+
+class CategorySelectAdapter(onItemClickListener: OnRecyclerItemClickListener? = null) :
+ BaseRecyclerAdapter(onItemClickListener) {
+
+ var checkedItemId = 0L
+ private set
+
+ fun setCheckedId(id: Long) {
+ val oldId = checkedItemId
+ checkedItemId = id
+ val oldPos = findItemPositionById(oldId)
+ val newPos = findItemPositionById(id)
+ if (newPos != -1) {
+ notifyItemChanged(newPos)
+ }
+ if (oldPos != -1) {
+ notifyItemChanged(oldPos)
+ }
+ }
+
+ override fun getExtra(item: FavouriteCategory, position: Int) =
+ checkedItemId == item.id
+
+ override fun onCreateViewHolder(parent: ViewGroup) = CategorySelectHolder(
+ parent
+ )
+
+ override fun onGetItemId(item: FavouriteCategory) = item.id
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/CategorySelectHolder.kt b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/CategorySelectHolder.kt
new file mode 100644
index 000000000..3dc667da9
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/CategorySelectHolder.kt
@@ -0,0 +1,16 @@
+package org.koitharu.kotatsu.ui.widget.shelf
+
+import android.view.ViewGroup
+import kotlinx.android.synthetic.main.item_category_checkable.*
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.core.model.FavouriteCategory
+import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
+
+class CategorySelectHolder(parent: ViewGroup) :
+ BaseViewHolder(parent, R.layout.item_category_checkable_single) {
+
+ override fun onBind(data: FavouriteCategory, extra: Boolean) {
+ checkedTextView.text = data.title
+ checkedTextView.isChecked = extra
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfConfigActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfConfigActivity.kt
new file mode 100644
index 000000000..2aa0964f4
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfConfigActivity.kt
@@ -0,0 +1,102 @@
+package org.koitharu.kotatsu.ui.widget.shelf
+
+import android.app.Activity
+import android.appwidget.AppWidgetManager
+import android.content.Intent
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import androidx.core.view.isVisible
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.snackbar.Snackbar
+import kotlinx.android.synthetic.main.activity_categories.*
+import moxy.ktx.moxyPresenter
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.core.model.FavouriteCategory
+import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
+import org.koitharu.kotatsu.ui.common.BaseActivity
+import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
+import org.koitharu.kotatsu.ui.main.list.favourites.categories.FavouriteCategoriesPresenter
+import org.koitharu.kotatsu.ui.main.list.favourites.categories.FavouriteCategoriesView
+import org.koitharu.kotatsu.utils.ext.getDisplayMessage
+import java.util.*
+import kotlin.collections.ArrayList
+
+class ShelfConfigActivity : BaseActivity(), FavouriteCategoriesView,
+ OnRecyclerItemClickListener {
+
+ private val presenter by moxyPresenter(factory = ::FavouriteCategoriesPresenter)
+
+ private lateinit var adapter: CategorySelectAdapter
+ private lateinit var config: AppWidgetConfig
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_categories)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ fab_add.imageTintList = ColorStateList.valueOf(Color.WHITE)
+ adapter = CategorySelectAdapter(this)
+ recyclerView.addItemDecoration(DividerItemDecoration(this, RecyclerView.VERTICAL))
+ recyclerView.adapter = adapter
+ fab_add.isVisible = false
+ val appWidgetId = intent?.getIntExtra(
+ AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID
+ ) ?: AppWidgetManager.INVALID_APPWIDGET_ID
+ if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ finish()
+ return
+ }
+ config = AppWidgetConfig.getInstance(this, appWidgetId)
+ adapter.setCheckedId(config.categoryId)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.opt_config, menu)
+ return super.onCreateOptionsMenu(menu)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
+ R.id.action_done -> {
+ config.categoryId = adapter.checkedItemId
+ updateWidget()
+ setResult(
+ Activity.RESULT_OK,
+ Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, config.widgetId)
+ )
+ finish()
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+
+ override fun onItemClick(item: FavouriteCategory, position: Int, view: View) {
+ adapter.setCheckedId(item.id)
+ }
+
+ override fun onCategoriesChanged(categories: List) {
+ val data = ArrayList(categories.size + 1)
+ data += FavouriteCategory(0L, getString(R.string.favourites), Date())
+ data += categories
+ adapter.replaceData(data)
+ }
+
+ override fun onCheckedCategoriesChanged(checkedIds: Set) = Unit
+
+ override fun onError(e: Throwable) {
+ Snackbar.make(recyclerView, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG)
+ .show()
+ }
+
+ private fun updateWidget() {
+ val intent = Intent(this, ShelfWidgetProvider::class.java)
+ intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
+ val ids = intArrayOf(config.widgetId)
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
+ sendBroadcast(intent)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfListFactory.kt b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfListFactory.kt
index 7e0aa5d04..429d13816 100644
--- a/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfListFactory.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfListFactory.kt
@@ -9,14 +9,16 @@ import coil.request.GetRequestBuilder
import kotlinx.coroutines.runBlocking
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
+import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
import org.koitharu.kotatsu.utils.ext.requireBitmap
import java.io.IOException
-class ShelfListFactory(private val context: Context) : RemoteViewsService.RemoteViewsFactory {
+class ShelfListFactory(private val context: Context, widgetId: Int) : RemoteViewsService.RemoteViewsFactory {
private val dataSet = ArrayList()
+ private val config = AppWidgetConfig.getInstance(context, widgetId)
override fun onCreate() {
}
@@ -27,7 +29,9 @@ class ShelfListFactory(private val context: Context) : RemoteViewsService.Remote
override fun onDataSetChanged() {
dataSet.clear()
- val data = runBlocking { FavouritesRepository().getAllManga(0) }
+ val data = runBlocking {
+ FavouritesRepository().getManga(config.categoryId, 0)
+ }
dataSet.addAll(data)
}
diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfWidgetService.kt b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfWidgetService.kt
index 945c80d91..f2d6a63de 100644
--- a/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfWidgetService.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/ui/widget/shelf/ShelfWidgetService.kt
@@ -1,11 +1,14 @@
package org.koitharu.kotatsu.ui.widget.shelf
+import android.appwidget.AppWidgetManager
import android.content.Intent
import android.widget.RemoteViewsService
class ShelfWidgetService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
- return ShelfListFactory(this)
+ val widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID)
+ return ShelfListFactory(this, widgetId)
}
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_done.xml b/app/src/main/res/drawable/ic_done.xml
new file mode 100644
index 000000000..b4f50b70c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_done.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/layout/item_category_checkable_single.xml b/app/src/main/res/layout/item_category_checkable_single.xml
new file mode 100644
index 000000000..7bf1ca556
--- /dev/null
+++ b/app/src/main/res/layout/item_category_checkable_single.xml
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_shelf.xml b/app/src/main/res/layout/item_shelf.xml
index e9d5575a9..657613c36 100644
--- a/app/src/main/res/layout/item_shelf.xml
+++ b/app/src/main/res/layout/item_shelf.xml
@@ -28,7 +28,9 @@
android:ellipsize="end"
android:gravity="center"
android:lines="2"
- android:textColor="?android:textColorPrimary" />
+ android:shadowColor="@android:color/black"
+ android:shadowRadius="1"
+ android:textColor="@android:color/white" />
diff --git a/app/src/main/res/layout/widget_shelf.xml b/app/src/main/res/layout/widget_shelf.xml
index 0a5661fba..e4f118684 100644
--- a/app/src/main/res/layout/widget_shelf.xml
+++ b/app/src/main/res/layout/widget_shelf.xml
@@ -21,7 +21,9 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
+ android:shadowColor="@android:color/black"
+ android:shadowRadius="1"
android:text="@string/you_have_not_favourites_yet"
- android:textColor="?android:textColorPrimary" />
+ android:textColor="@android:color/white" />
\ No newline at end of file
diff --git a/app/src/main/res/menu/opt_config.xml b/app/src/main/res/menu/opt_config.xml
new file mode 100644
index 000000000..425f8e7dc
--- /dev/null
+++ b/app/src/main/res/menu/opt_config.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 51f62d15e..9a4a99844 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -131,4 +131,5 @@
Не удалось найти ни одного доступного хранилища
Другое хранилище
Защищённое соединение (HTTPS)
+ Готово
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0dfb3988b..13e7eff61 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -132,4 +132,5 @@
Cannot find any available storage
Other storage
Use secure connection (HTTPS)
+ Done
\ No newline at end of file
diff --git a/app/src/main/res/xml/widget_shelf.xml b/app/src/main/res/xml/widget_shelf.xml
index 2dab58bf4..41c026cac 100644
--- a/app/src/main/res/xml/widget_shelf.xml
+++ b/app/src/main/res/xml/widget_shelf.xml
@@ -1,6 +1,7 @@