Add manga straight into a category from catalogues (#737)
* Add feature mention in issue #625
This commit is contained in:
parent
bb9e230b35
commit
f6a79bde6f
@ -115,4 +115,6 @@ class PreferenceKeys(context: Context) {
|
||||
|
||||
val lang = context.getString(R.string.pref_language_key)
|
||||
|
||||
val defaultCategory = context.getString(R.string.default_category_key)
|
||||
|
||||
}
|
||||
|
@ -158,4 +158,6 @@ class PreferencesHelper(val context: Context) {
|
||||
|
||||
fun lang() = prefs.getString(keys.lang, "")
|
||||
|
||||
fun defaultCategory() = prefs.getInt(keys.defaultCategory, -1)
|
||||
|
||||
}
|
||||
|
@ -34,6 +34,10 @@ import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.subjects.PublishSubject
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import android.widget.Toast
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
/**
|
||||
* Fragment that shows the manga from the catalogue.
|
||||
@ -45,6 +49,11 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(),
|
||||
FlexibleAdapter.OnItemLongClickListener,
|
||||
FlexibleAdapter.EndlessScrollListener<ProgressItem> {
|
||||
|
||||
/**
|
||||
* Preferences helper.
|
||||
*/
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
/**
|
||||
* Spinner shown in the toolbar to change the selected source.
|
||||
*/
|
||||
@ -530,23 +539,62 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(),
|
||||
/**
|
||||
* Called when a manga is long clicked.
|
||||
*
|
||||
* Adds the manga to the default category if none is set it shows a list of categories for the user to put the manga
|
||||
* in, the list consists of the default category plus the user's categories. The default category is preselected on
|
||||
* new manga, and on already favorited manga the manga's categories are preselected.
|
||||
*
|
||||
* @param position the position of the element clicked.
|
||||
*/
|
||||
override fun onItemLongClick(position: Int) {
|
||||
val manga = (adapter.getItem(position) as? CatalogueItem?)?.manga ?: return
|
||||
val categories = presenter.getCategories()
|
||||
|
||||
val textRes = if (manga.favorite) R.string.remove_from_library else R.string.add_to_library
|
||||
|
||||
MaterialDialog.Builder(activity)
|
||||
.items(getString(textRes))
|
||||
.itemsCallback { dialog, itemView, which, text ->
|
||||
when (which) {
|
||||
0 -> {
|
||||
presenter.changeMangaFavorite(manga)
|
||||
adapter.notifyItemChanged(position)
|
||||
val defaultCategory = categories.find { it.id == preferences.defaultCategory()}
|
||||
if(defaultCategory != null) {
|
||||
if(!manga.favorite) {
|
||||
presenter.changeMangaFavorite(manga)
|
||||
}
|
||||
presenter.moveMangaToCategory(defaultCategory, manga)
|
||||
} else {
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.action_move_category)
|
||||
.items(categories.map { it.name })
|
||||
.itemsCallbackMultiChoice(presenter.getMangaCategoryIds(manga)) { dialog, position, _ ->
|
||||
if (defaultSelectedWithOtherCategory(position)) {
|
||||
// Deselect default category
|
||||
dialog.setSelectedIndices(position.filter {it > 0}.toTypedArray())
|
||||
Toast.makeText(dialog.context, R.string.invalid_combination, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}.show()
|
||||
.alwaysCallMultiChoiceCallback()
|
||||
.positiveText(android.R.string.ok)
|
||||
.negativeText(android.R.string.cancel)
|
||||
.onPositive { dialog, _ ->
|
||||
updateMangaCategories(manga, dialog, categories, position)
|
||||
}
|
||||
.build()
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun defaultSelectedWithOtherCategory(position: Array<Int>): Boolean {
|
||||
return position.contains(0) && position.count() > 1
|
||||
}
|
||||
|
||||
private fun updateMangaCategories(manga: Manga, dialog: MaterialDialog, categories: List<Category>, position: Int) {
|
||||
val selectedCategories = dialog.selectedIndices?.map { categories[it] } ?: emptyList()
|
||||
|
||||
if(!selectedCategories.isEmpty()) {
|
||||
if(!manga.favorite) {
|
||||
presenter.changeMangaFavorite(manga)
|
||||
}
|
||||
presenter.moveMangaToCategories(selectedCategories.filter { it.id != 0}, manga)
|
||||
} else {
|
||||
presenter.changeMangaFavorite(manga)
|
||||
}
|
||||
adapter.notifyItemChanged(position)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.flexibleadapter.items.ISectionable
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
@ -24,6 +26,7 @@ import rx.schedulers.Schedulers
|
||||
import rx.subjects.PublishSubject
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.ArrayList
|
||||
|
||||
/**
|
||||
* Presenter of [CatalogueFragment].
|
||||
@ -396,4 +399,49 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default, and user categories.
|
||||
*
|
||||
* @return List of categories, default plus user categories
|
||||
*/
|
||||
fun getCategories(): List<Category> {
|
||||
return arrayListOf(Category.createDefault()) + db.getCategories().executeAsBlocking()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the category id's the manga is in, if the manga is not in a category, returns the default id.
|
||||
*
|
||||
* @param manga the manga to get categories from.
|
||||
* @return Array of category ids the manga is in, if none returns default id
|
||||
*/
|
||||
fun getMangaCategoryIds(manga: Manga): Array<Int?> {
|
||||
val categories = db.getCategoriesForManga(manga).executeAsBlocking()
|
||||
if(categories.isEmpty()) {
|
||||
return arrayListOf(Category.createDefault().id).toTypedArray()
|
||||
}
|
||||
return categories.map { it.id }.toTypedArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the given manga to categories.
|
||||
*
|
||||
* @param categories the selected categories.
|
||||
* @param manga the manga to move.
|
||||
*/
|
||||
fun moveMangaToCategories(categories: List<Category>, manga: Manga) {
|
||||
val mc = categories.map { MangaCategory.create(manga, it) }
|
||||
|
||||
db.setMangaCategories(mc, arrayListOf(manga))
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the given manga to the category.
|
||||
*
|
||||
* @param category the selected category.
|
||||
* @param manga the manga to move.
|
||||
*/
|
||||
fun moveMangaToCategory(category: Category, manga: Manga) {
|
||||
moveMangaToCategories(arrayListOf(category), manga)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.support.customtabs.CustomTabsIntent
|
||||
import android.view.*
|
||||
import android.widget.Toast
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bumptech.glide.BitmapRequestBuilder
|
||||
import com.bumptech.glide.BitmapTypeRequest
|
||||
@ -14,6 +15,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
@ -31,6 +33,7 @@ import nucleus.factory.RequiresPresenter
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
/**
|
||||
* Fragment that shows manga information.
|
||||
@ -52,6 +55,11 @@ class MangaInfoFragment : BaseRxFragment<MangaInfoPresenter>() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Preferences helper.
|
||||
*/
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
setHasOptionsMenu(true)
|
||||
@ -63,7 +71,19 @@ class MangaInfoFragment : BaseRxFragment<MangaInfoPresenter>() {
|
||||
|
||||
override fun onViewCreated(view: View?, savedState: Bundle?) {
|
||||
// Set onclickListener to toggle favorite when FAB clicked.
|
||||
fab_favorite.setOnClickListener { toggleFavorite() }
|
||||
fab_favorite.setOnClickListener {
|
||||
if(!presenter.manga.favorite) {
|
||||
val defaultCategory = presenter.getCategories().find { it.id == preferences.defaultCategory()}
|
||||
if(defaultCategory == null) {
|
||||
onFabClick()
|
||||
} else {
|
||||
toggleFavorite()
|
||||
presenter.moveMangaToCategory(defaultCategory, presenter.manga)
|
||||
}
|
||||
} else {
|
||||
toggleFavorite()
|
||||
}
|
||||
}
|
||||
|
||||
// Set SwipeRefresh to refresh manga data.
|
||||
swipe_refresh.setOnRefreshListener { fetchMangaFromSource() }
|
||||
@ -334,4 +354,40 @@ class MangaInfoFragment : BaseRxFragment<MangaInfoPresenter>() {
|
||||
swipe_refresh.isRefreshing = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the fab is clicked.
|
||||
*/
|
||||
private fun onFabClick() {
|
||||
val categories = presenter.getCategories()
|
||||
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.action_move_category)
|
||||
.items(categories.map { it.name })
|
||||
.itemsCallbackMultiChoice(presenter.getMangaCategoryIds(presenter.manga)) { dialog, position, text ->
|
||||
if (position.contains(0) && position.count() > 1) {
|
||||
dialog.setSelectedIndices(position.filter {it > 0}.toTypedArray())
|
||||
Toast.makeText(dialog.context, R.string.invalid_combination, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
.alwaysCallMultiChoiceCallback()
|
||||
.positiveText(android.R.string.ok)
|
||||
.negativeText(android.R.string.cancel)
|
||||
.onPositive { dialog, _ ->
|
||||
val selectedCategories = dialog.selectedIndices?.map { categories[it] } ?: emptyList()
|
||||
|
||||
if(!selectedCategories.isEmpty()) {
|
||||
if(!presenter.manga.favorite) {
|
||||
toggleFavorite()
|
||||
}
|
||||
presenter.moveMangaToCategories(selectedCategories.filter { it.id != 0}, presenter.manga)
|
||||
} else {
|
||||
toggleFavorite()
|
||||
}
|
||||
}
|
||||
.build()
|
||||
.show()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ package eu.kanade.tachiyomi.ui.manga.info
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
@ -16,6 +18,7 @@ import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.ArrayList
|
||||
|
||||
/**
|
||||
* Presenter of MangaInfoFragment.
|
||||
@ -148,4 +151,49 @@ class MangaInfoPresenter : BasePresenter<MangaInfoFragment>() {
|
||||
downloadManager.findMangaDir(source, manga)?.delete()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default, and user categories.
|
||||
*
|
||||
* @return List of categories, default plus user categories
|
||||
*/
|
||||
fun getCategories(): List<Category> {
|
||||
return arrayListOf(Category.createDefault()) + db.getCategories().executeAsBlocking()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the category id's the manga is in, if the manga is not in a category, returns the default id.
|
||||
*
|
||||
* @param manga the manga to get categories from.
|
||||
* @return Array of category ids the manga is in, if none returns default id
|
||||
*/
|
||||
fun getMangaCategoryIds(manga: Manga): Array<Int?> {
|
||||
val categories = db.getCategoriesForManga(manga).executeAsBlocking()
|
||||
if(categories.isEmpty()) {
|
||||
return arrayListOf(Category.createDefault().id).toTypedArray()
|
||||
}
|
||||
return categories.map { it.id }.toTypedArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the given manga to categories.
|
||||
*
|
||||
* @param categories the selected categories.
|
||||
* @param manga the manga to move.
|
||||
*/
|
||||
fun moveMangaToCategories(categories: List<Category>, manga: Manga) {
|
||||
val mc = categories.map { MangaCategory.create(manga, it) }
|
||||
|
||||
db.setMangaCategories(mc, arrayListOf(manga))
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the given manga to the category.
|
||||
*
|
||||
* @param category the selected category.
|
||||
* @param manga the manga to move.
|
||||
*/
|
||||
fun moveMangaToCategory(category: Category, manga: Manga) {
|
||||
moveMangaToCategories(arrayListOf(category), manga)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import android.support.v7.preference.XpPreferenceFragment
|
||||
import android.view.View
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.util.LocaleHelper
|
||||
@ -46,6 +47,8 @@ class SettingsGeneralFragment : SettingsFragment(),
|
||||
|
||||
val categoryUpdate: MultiSelectListPreference by bindPref(R.string.pref_library_update_categories_key)
|
||||
|
||||
val defaultCategory: IntListPreference by bindPref(R.string.default_category_key)
|
||||
|
||||
val langPreference: ListPreference by bindPref(R.string.pref_language_key)
|
||||
|
||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
||||
@ -100,6 +103,22 @@ class SettingsGeneralFragment : SettingsFragment(),
|
||||
categoryUpdate.summary = summary
|
||||
}
|
||||
|
||||
defaultCategory.apply {
|
||||
val selectedCategory = dbCategories.find { it.id == preferences.defaultCategory()}
|
||||
value = selectedCategory?.id?.toString() ?: value
|
||||
entries += dbCategories.map { it.name }.toTypedArray()
|
||||
entryValues += dbCategories.map { it.id.toString() }.toTypedArray()
|
||||
summary = selectedCategory?.name ?: summary
|
||||
}
|
||||
|
||||
defaultCategory.setOnPreferenceChangeListener { _, newValue ->
|
||||
defaultCategory.summary = dbCategories.find {
|
||||
it.id == (newValue as String).toInt()
|
||||
}?.name ?: getString(R.string.default_category_summary)
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
themePreference.setOnPreferenceChangeListener { preference, newValue ->
|
||||
(activity as SettingsActivity).parentFlags = SettingsActivity.FLAG_THEME_CHANGED
|
||||
activity.recreate()
|
||||
|
@ -242,4 +242,12 @@
|
||||
<item>vi</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="default_category_entry">
|
||||
<item>@string/default_category_summary</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="default_category_entry_value">
|
||||
<item>-1</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
@ -21,6 +21,7 @@
|
||||
<string name="pref_library_update_restriction_key" translatable="false">library_update_restriction</string>
|
||||
<string name="pref_start_screen_key" translatable="false">start_screen</string>
|
||||
<string name="pref_language_key" translatable="false">app_language</string>
|
||||
<string name="default_category_key" translatable="false">default_category</string>
|
||||
|
||||
<string name="pref_default_viewer_key" translatable="false">pref_default_viewer_key</string>
|
||||
<string name="pref_image_scale_type_key" translatable="false">pref_image_scale_type_key</string>
|
||||
|
@ -134,6 +134,8 @@
|
||||
<string name="pref_start_screen">Start screen</string>
|
||||
<string name="pref_language">Language</string>
|
||||
<string name="system_default">System default</string>
|
||||
<string name="default_category">Default category</string>
|
||||
<string name="default_category_summary">Always ask</string>
|
||||
|
||||
<!-- Reader section -->
|
||||
<string name="pref_fullscreen">Fullscreen</string>
|
||||
@ -269,6 +271,7 @@
|
||||
<string name="no_valid_sources">Please enable at least one valid source</string>
|
||||
<string name="no_more_results">No more results</string>
|
||||
<string name="local_source">Local manga</string>
|
||||
<string name="invalid_combination">Default can\'t be selected with other categories</string>
|
||||
|
||||
<!-- Manga activity -->
|
||||
<string name="manga_not_in_db">This manga was removed from the database!</string>
|
||||
|
@ -63,6 +63,14 @@
|
||||
android:key="@string/pref_update_only_non_completed_key"
|
||||
android:title="@string/pref_update_only_non_completed" />
|
||||
|
||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
||||
android:defaultValue="-1"
|
||||
android:entries="@array/default_category_entry"
|
||||
android:entryValues="@array/default_category_entry_value"
|
||||
android:key="@string/default_category_key"
|
||||
android:title="@string/default_category"
|
||||
android:summary="@string/default_category_summary"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
</PreferenceScreen>
|
Loading…
Reference in New Issue
Block a user