Favourites
parent
738d1cb50e
commit
bbe28f769d
@ -0,0 +1,69 @@
|
|||||||
|
package org.koitharu.kotatsu.ui.common
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import kotlinx.android.synthetic.main.dialog_input.view.*
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.utils.ext.hideKeyboard
|
||||||
|
import org.koitharu.kotatsu.utils.ext.showKeyboard
|
||||||
|
|
||||||
|
class TextInputDialog private constructor(private val delegate: AlertDialog) :
|
||||||
|
DialogInterface by delegate {
|
||||||
|
|
||||||
|
init {
|
||||||
|
delegate.setOnShowListener {
|
||||||
|
delegate.currentFocus?.showKeyboard()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show() = delegate.show()
|
||||||
|
|
||||||
|
class Builder(context: Context) {
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
|
private val view = LayoutInflater.from(context).inflate(R.layout.dialog_input, null, false)
|
||||||
|
|
||||||
|
private val delegate = AlertDialog.Builder(context)
|
||||||
|
.setView(view)
|
||||||
|
|
||||||
|
fun setTitle(@StringRes titleResId: Int): Builder {
|
||||||
|
delegate.setTitle(titleResId)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTitle(title: CharSequence): Builder {
|
||||||
|
delegate.setTitle(title)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setHint(@StringRes hintResId: Int): Builder {
|
||||||
|
view.inputLayout.hint = view.context.getString(hintResId)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setInputType(inputType: Int): Builder {
|
||||||
|
view.inputEdit.inputType = inputType
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPositiveButton(@StringRes textId: Int, listener: (DialogInterface, String) -> Unit): Builder {
|
||||||
|
delegate.setPositiveButton(textId) { dialog, _ ->
|
||||||
|
view.hideKeyboard()
|
||||||
|
listener(dialog, view.inputEdit.text?.toString().orEmpty())
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setNegativeButton(@StringRes textId: Int, listener: DialogInterface.OnClickListener? = null): Builder {
|
||||||
|
delegate.setNegativeButton(textId, listener)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create() = TextInputDialog(delegate.create())
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.ui.main.list.favourites
|
|
||||||
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.ui.common.AlertDialogFragment
|
|
||||||
|
|
||||||
class FavouriteCategoriesDialog() : AlertDialogFragment(R.layout.dialog_favorite_categories) {
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package org.koitharu.kotatsu.ui.main.list.favourites
|
package org.koitharu.kotatsu.ui.main.list.favourites.categories
|
||||||
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import kotlinx.android.synthetic.main.item_caegory_checkable.*
|
import kotlinx.android.synthetic.main.item_caegory_checkable.*
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package org.koitharu.kotatsu.ui.main.list.favourites.categories
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.InputType
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import kotlinx.android.synthetic.main.dialog_favorite_categories.*
|
||||||
|
import moxy.ktx.moxyPresenter
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
import org.koitharu.kotatsu.ui.common.AlertDialogFragment
|
||||||
|
import org.koitharu.kotatsu.ui.common.TextInputDialog
|
||||||
|
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||||
|
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||||
|
|
||||||
|
class FavouriteCategoriesDialog() : AlertDialogFragment(R.layout.dialog_favorite_categories),
|
||||||
|
FavouriteCategoriesView,
|
||||||
|
OnCategoryCheckListener {
|
||||||
|
|
||||||
|
private val presenter by moxyPresenter(factory = ::FavouriteCategoriesPresenter)
|
||||||
|
|
||||||
|
private val manga get() = arguments?.getParcelable<Manga>(ARG_MANGA)
|
||||||
|
|
||||||
|
private var adapter: CategoriesAdapter? = null
|
||||||
|
|
||||||
|
override fun onBuildDialog(builder: AlertDialog.Builder) {
|
||||||
|
builder.setTitle(R.string.add_to_favourites)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
adapter = CategoriesAdapter(this)
|
||||||
|
recyclerView_categories.adapter = adapter
|
||||||
|
textView_add.setOnClickListener {
|
||||||
|
createCategory()
|
||||||
|
}
|
||||||
|
manga?.let {
|
||||||
|
presenter.loadMangaCategories(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
adapter = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||||
|
adapter?.replaceData(categories)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCheckedCategoriesChanged(checkedIds: Set<Int>) {
|
||||||
|
adapter?.setCheckedIds(checkedIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCategoryChecked(category: FavouriteCategory) {
|
||||||
|
presenter.addToCategory(manga ?: return, category.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCategoryUnchecked(category: FavouriteCategory) {
|
||||||
|
presenter.removeFromCategory(manga ?: return, category.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Exception) {
|
||||||
|
Toast.makeText(context ?: return, e.getDisplayMessage(resources), Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCategory() {
|
||||||
|
TextInputDialog.Builder(context ?: return)
|
||||||
|
.setTitle(R.string.add_new_category)
|
||||||
|
.setHint(R.string.enter_category_name)
|
||||||
|
.setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)
|
||||||
|
.setNegativeButton(android.R.string.cancel)
|
||||||
|
.setPositiveButton(R.string.add) { _, name ->
|
||||||
|
presenter.createCategory(name)
|
||||||
|
}.create()
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val ARG_MANGA = "manga"
|
||||||
|
private const val TAG = "FavouriteCategoriesDialog"
|
||||||
|
|
||||||
|
fun show(fm: FragmentManager, manga: Manga) = FavouriteCategoriesDialog().withArgs(1) {
|
||||||
|
putParcelable(ARG_MANGA, manga)
|
||||||
|
}.show(fm, TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
package org.koitharu.kotatsu.ui.main.list.favourites.categories
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import moxy.InjectViewState
|
||||||
|
import org.koitharu.kotatsu.BuildConfig
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
|
||||||
|
import org.koitharu.kotatsu.ui.common.BasePresenter
|
||||||
|
|
||||||
|
@InjectViewState
|
||||||
|
class FavouriteCategoriesPresenter : BasePresenter<FavouriteCategoriesView>() {
|
||||||
|
|
||||||
|
private lateinit var repository: FavouritesRepository
|
||||||
|
|
||||||
|
override fun onFirstViewAttach() {
|
||||||
|
repository = FavouritesRepository()
|
||||||
|
super.onFirstViewAttach()
|
||||||
|
loadAllCategories()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadAllCategories() {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val categories = withContext(Dispatchers.IO) {
|
||||||
|
repository.getAllCategories()
|
||||||
|
}
|
||||||
|
viewState.onCategoriesChanged(categories)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
viewState.onError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadMangaCategories(manga: Manga) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val categories = withContext(Dispatchers.IO) {
|
||||||
|
repository.getCategories(manga.id)
|
||||||
|
}
|
||||||
|
viewState.onCheckedCategoriesChanged(categories.map { it.id.toInt() }.toSet())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
viewState.onError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createCategory(name: String) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val categories = withContext(Dispatchers.IO) {
|
||||||
|
repository.addCategory(name)
|
||||||
|
repository.getAllCategories()
|
||||||
|
}
|
||||||
|
viewState.onCategoriesChanged(categories)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
viewState.onError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addToCategory(manga: Manga, categoryId: Long) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val categories = withContext(Dispatchers.IO) {
|
||||||
|
repository.addToCategory(manga,categoryId)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
viewState.onError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeFromCategory(manga: Manga, categoryId: Long) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val categories = withContext(Dispatchers.IO) {
|
||||||
|
repository.removeFromCategory(manga, categoryId)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
viewState.onError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package org.koitharu.kotatsu.ui.main.list.favourites.categories
|
||||||
|
|
||||||
|
import moxy.MvpView
|
||||||
|
import moxy.viewstate.strategy.AddToEndSingleStrategy
|
||||||
|
import moxy.viewstate.strategy.OneExecutionStateStrategy
|
||||||
|
import moxy.viewstate.strategy.StateStrategyType
|
||||||
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
|
|
||||||
|
interface FavouriteCategoriesView : MvpView {
|
||||||
|
|
||||||
|
@StateStrategyType(AddToEndSingleStrategy::class)
|
||||||
|
fun onCategoriesChanged(categories: List<FavouriteCategory>)
|
||||||
|
|
||||||
|
@StateStrategyType(AddToEndSingleStrategy::class)
|
||||||
|
fun onCheckedCategoriesChanged(checkedIds: Set<Int>)
|
||||||
|
|
||||||
|
@StateStrategyType(OneExecutionStateStrategy::class)
|
||||||
|
fun onError(e: Exception)
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package org.koitharu.kotatsu.ui.main.list.favourites
|
package org.koitharu.kotatsu.ui.main.list.favourites.categories
|
||||||
|
|
||||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
|
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="14dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingEnd="14dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/inputLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:boxBackgroundMode="filled">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/inputEdit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:maxLines="1"
|
||||||
|
tools:text="@tools:sample/lorem[2]" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
Loading…
Reference in New Issue