Add migration ability.
Various bug fixes and code cleanup.
This commit is contained in:
parent
e4f2bffbc2
commit
f5c4535cb0
@ -159,6 +159,8 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun thumbnailRows() = rxPrefs.getString("ex_thumb_rows", "tr_2")
|
fun thumbnailRows() = rxPrefs.getString("ex_thumb_rows", "tr_2")
|
||||||
|
|
||||||
|
fun migrateLibraryAsked() = rxPrefs.getBoolean("ex_migrate_library", false)
|
||||||
|
|
||||||
//EH Cookies
|
//EH Cookies
|
||||||
fun memberIdVal() = rxPrefs.getString("eh_ipb_member_id", null)
|
fun memberIdVal() = rxPrefs.getString("eh_ipb_member_id", null)
|
||||||
fun passHashVal() = rxPrefs.getString("eh_ipb_pass_hash", null)
|
fun passHashVal() = rxPrefs.getString("eh_ipb_pass_hash", null)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
@ -17,6 +19,7 @@ import exh.search.SearchEngine
|
|||||||
import kotlinx.android.synthetic.main.item_catalogue_grid.view.*
|
import kotlinx.android.synthetic.main.item_catalogue_grid.view.*
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter storing a list of manga in a certain category.
|
* Adapter storing a list of manga in a certain category.
|
||||||
@ -36,6 +39,8 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) :
|
|||||||
private val searchEngine = SearchEngine()
|
private val searchEngine = SearchEngine()
|
||||||
private val metadataHelper = MetadataHelper()
|
private val metadataHelper = MetadataHelper()
|
||||||
|
|
||||||
|
var asyncSearchText: String? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setHasStableIds(true)
|
setHasStableIds(true)
|
||||||
}
|
}
|
||||||
@ -69,8 +74,17 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) :
|
|||||||
* @param param the filter. Not used.
|
* @param param the filter. Not used.
|
||||||
*/
|
*/
|
||||||
override fun updateDataSet(param: String?) {
|
override fun updateDataSet(param: String?) {
|
||||||
filterItems(mangas)
|
//Async search filter (EH)
|
||||||
notifyDataSetChanged()
|
val filtered = asyncSearchText?.let { search ->
|
||||||
|
mangas.filter {
|
||||||
|
filterObject(it, search)
|
||||||
|
}
|
||||||
|
} ?: mangas
|
||||||
|
//The rest of the filters run on the main loop
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
filterItems(filtered)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,7 +114,7 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) :
|
|||||||
val metadata = metadataHelper.fetchMetadata(manga.url, exh)
|
val metadata = metadataHelper.fetchMetadata(manga.url, exh)
|
||||||
metadata?.let {
|
metadata?.let {
|
||||||
searchEngine.matches(metadata, searchEngine.parseQuery(query))
|
searchEngine.matches(metadata, searchEngine.parseQuery(query))
|
||||||
} ?: title.toLowerCase().contains(query) //Use regular searching when the metadata is not set up for this gallery
|
} ?: title.contains(query, ignoreCase = true) //Use regular searching when the metadata is not set up for this gallery
|
||||||
} ?: false
|
} ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,9 @@ import eu.kanade.tachiyomi.util.toast
|
|||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||||
import kotlinx.android.synthetic.main.item_library_category.view.*
|
import kotlinx.android.synthetic.main.item_library_category.view.*
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fragment containing the library manga for a certain category.
|
* Fragment containing the library manga for a certain category.
|
||||||
@ -114,8 +116,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||||||
|
|
||||||
val presenter = fragment.presenter
|
val presenter = fragment.presenter
|
||||||
|
|
||||||
searchSubscription = presenter.searchSubject.subscribe { text ->
|
searchSubscription = presenter
|
||||||
adapter.searchText = text
|
.searchSubject
|
||||||
|
.debounce(100L, TimeUnit.MILLISECONDS)
|
||||||
|
.subscribe { text -> //Debounce search (EH)
|
||||||
|
adapter.asyncSearchText = text.trim().toLowerCase()
|
||||||
adapter.updateDataSet()
|
adapter.updateDataSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import android.support.v4.app.TaskStackBuilder
|
|||||||
import android.support.v4.view.GravityCompat
|
import android.support.v4.view.GravityCompat
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.ui.backup.BackupFragment
|
import eu.kanade.tachiyomi.ui.backup.BackupFragment
|
||||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||||
@ -17,9 +18,12 @@ import eu.kanade.tachiyomi.ui.library.LibraryFragment
|
|||||||
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersFragment
|
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersFragment
|
||||||
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadFragment
|
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadFragment
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
|
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
|
||||||
|
import exh.ui.MetadataFetchDialog
|
||||||
import exh.ui.batchadd.BatchAddFragment
|
import exh.ui.batchadd.BatchAddFragment
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import kotlinx.android.synthetic.main.toolbar.*
|
import kotlinx.android.synthetic.main.toolbar.*
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class MainActivity : BaseActivity() {
|
class MainActivity : BaseActivity() {
|
||||||
@ -82,6 +86,14 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
// Show changelog if needed
|
// Show changelog if needed
|
||||||
ChangelogDialogFragment.show(this, preferences, supportFragmentManager)
|
ChangelogDialogFragment.show(this, preferences, supportFragmentManager)
|
||||||
|
|
||||||
|
// Migrate library if needed
|
||||||
|
Injekt.get<DatabaseHelper>().getLibraryMangas().asRxSingle().subscribe {
|
||||||
|
if(it.size > 0)
|
||||||
|
runOnUiThread {
|
||||||
|
MetadataFetchDialog().tryAskMigration(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,9 @@ import android.support.v7.preference.XpPreferenceFragment
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.util.plusAssign
|
import eu.kanade.tachiyomi.util.plusAssign
|
||||||
|
import exh.ui.MetadataFetchDialog
|
||||||
import exh.ui.login.LoginActivity
|
import exh.ui.login.LoginActivity
|
||||||
|
import net.xpece.android.support.preference.Preference
|
||||||
import net.xpece.android.support.preference.SwitchPreference
|
import net.xpece.android.support.preference.SwitchPreference
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
@ -29,6 +31,10 @@ class SettingsEhFragment : SettingsFragment() {
|
|||||||
findPreference("enable_exhentai") as SwitchPreference
|
findPreference("enable_exhentai") as SwitchPreference
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val migrateLibraryPref by lazy {
|
||||||
|
findPreference("ex_migrate_library") as Preference
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
override fun onViewCreated(view: View, savedState: Bundle?) {
|
||||||
super.onViewCreated(view, savedState)
|
super.onViewCreated(view, savedState)
|
||||||
|
|
||||||
@ -48,5 +54,10 @@ class SettingsEhFragment : SettingsFragment() {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
migrateLibraryPref.setOnPreferenceClickListener {
|
||||||
|
MetadataFetchDialog().askMigration(activity)
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,15 +9,22 @@ class MetadataHelper {
|
|||||||
= exGalleryBook().write(galleryMetadata.galleryUniqueIdentifier(), galleryMetadata)
|
= exGalleryBook().write(galleryMetadata.galleryUniqueIdentifier(), galleryMetadata)
|
||||||
|
|
||||||
fun fetchMetadata(url: String, exh: Boolean): ExGalleryMetadata?
|
fun fetchMetadata(url: String, exh: Boolean): ExGalleryMetadata?
|
||||||
= ExGalleryMetadata().apply {
|
= ExGalleryMetadata().let {
|
||||||
this.url = url
|
it.url = url
|
||||||
this.exh = exh
|
it.exh = exh
|
||||||
return exGalleryBook().read<ExGalleryMetadata>(galleryUniqueIdentifier())
|
return exGalleryBook().read<ExGalleryMetadata>(it.galleryUniqueIdentifier())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAllGalleries() = exGalleryBook().allKeys.map {
|
fun getAllGalleries() = exGalleryBook().allKeys.map {
|
||||||
exGalleryBook().read<ExGalleryMetadata>(it)
|
exGalleryBook().read<ExGalleryMetadata>(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hasMetadata(url: String, exh: Boolean): Boolean
|
||||||
|
= ExGalleryMetadata().let {
|
||||||
|
it.url = url
|
||||||
|
it.exh = exh
|
||||||
|
return exGalleryBook().exist(it.galleryUniqueIdentifier())
|
||||||
|
}
|
||||||
|
|
||||||
fun exGalleryBook() = Paper.book("gallery-ex")!!
|
fun exGalleryBook() = Paper.book("gallery-ex")!!
|
||||||
}
|
}
|
@ -9,7 +9,7 @@ class SearchEngine {
|
|||||||
|
|
||||||
fun matches(metadata: ExGalleryMetadata, query: List<QueryComponent>): Boolean {
|
fun matches(metadata: ExGalleryMetadata, query: List<QueryComponent>): Boolean {
|
||||||
|
|
||||||
fun matchTagList(tags: List<Tag>,
|
fun matchTagList(tags: Sequence<Tag>,
|
||||||
component: Text): Boolean {
|
component: Text): Boolean {
|
||||||
//Match tags
|
//Match tags
|
||||||
val tagMatcher = if(!component.exact)
|
val tagMatcher = if(!component.exact)
|
||||||
@ -28,15 +28,18 @@ class SearchEngine {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val cachedLowercaseTitle = metadata.title?.toLowerCase()
|
||||||
|
val cachedLowercaseAltTitle = metadata.altTitle?.toLowerCase()
|
||||||
|
|
||||||
for(component in query) {
|
for(component in query) {
|
||||||
if(component is Text) {
|
if(component is Text) {
|
||||||
//Match title
|
//Match title
|
||||||
if (component.asRegex().test(metadata.title?.toLowerCase())
|
if (component.asRegex().test(cachedLowercaseTitle)
|
||||||
|| component.asRegex().test(metadata.altTitle?.toLowerCase())) {
|
|| component.asRegex().test(cachedLowercaseAltTitle)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//Match tags
|
//Match tags
|
||||||
if(!matchTagList(metadata.tags.entries.flatMap { it.value },
|
if(!matchTagList(metadata.tags.entries.asSequence().flatMap { it.value.asSequence() },
|
||||||
component)) return false
|
component)) return false
|
||||||
} else if(component is Namespace) {
|
} else if(component is Namespace) {
|
||||||
if(component.namespace == "uploader") {
|
if(component.namespace == "uploader") {
|
||||||
@ -47,9 +50,9 @@ class SearchEngine {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//Match namespace
|
//Match namespace
|
||||||
val ns = metadata.tags.entries.filter {
|
val ns = metadata.tags.entries.asSequence().filter {
|
||||||
it.key == component.namespace
|
it.key == component.namespace
|
||||||
}.flatMap { it.value }
|
}.flatMap { it.value.asSequence() }
|
||||||
//Match tags
|
//Match tags
|
||||||
if (!matchTagList(ns, component.tag!!))
|
if (!matchTagList(ns, component.tag!!))
|
||||||
return false
|
return false
|
||||||
|
139
app/src/main/java/exh/ui/MetadataFetchDialog.kt
Normal file
139
app/src/main/java/exh/ui/MetadataFetchDialog.kt
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package exh.ui
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.pm.ActivityInfo
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
|
import eu.kanade.tachiyomi.data.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.data.source.online.all.EHentai
|
||||||
|
import exh.metadata.MetadataHelper
|
||||||
|
import exh.metadata.copyTo
|
||||||
|
import timber.log.Timber
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
class MetadataFetchDialog {
|
||||||
|
|
||||||
|
val metadataHelper by lazy { MetadataHelper() }
|
||||||
|
|
||||||
|
val db: DatabaseHelper by injectLazy()
|
||||||
|
|
||||||
|
val sourceManager: SourceManager by injectLazy()
|
||||||
|
|
||||||
|
val preferenceHelper: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
fun show(context: Activity) {
|
||||||
|
//Too lazy to actually deal with orientation changes
|
||||||
|
context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
|
||||||
|
|
||||||
|
val progressDialog = MaterialDialog.Builder(context)
|
||||||
|
.title("Migrating library")
|
||||||
|
.content("Preparing library")
|
||||||
|
.progress(false, 0, true)
|
||||||
|
.cancelable(false)
|
||||||
|
.canceledOnTouchOutside(false)
|
||||||
|
.show()
|
||||||
|
|
||||||
|
thread {
|
||||||
|
db.deleteMangasNotInLibrary().executeAsBlocking()
|
||||||
|
|
||||||
|
val libraryMangas = db.getLibraryMangas()
|
||||||
|
.executeAsBlocking()
|
||||||
|
.filter {
|
||||||
|
it.source <= 2
|
||||||
|
&& !metadataHelper.hasMetadata(it.url, it.source == 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.runOnUiThread {
|
||||||
|
progressDialog.maxProgress = libraryMangas.size
|
||||||
|
}
|
||||||
|
|
||||||
|
//Actual metadata fetch code
|
||||||
|
libraryMangas.forEachIndexed { i, manga ->
|
||||||
|
context.runOnUiThread {
|
||||||
|
progressDialog.setContent("Processing: ${manga.title}")
|
||||||
|
progressDialog.setProgress(i + 1)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val source = sourceManager.get(manga.source)
|
||||||
|
source?.let {
|
||||||
|
it as EHentai
|
||||||
|
manga.copyFrom(it.fetchMangaDetails(manga).toBlocking().first())
|
||||||
|
metadataHelper.fetchMetadata(manga.url, it.exh)?.copyTo(manga)
|
||||||
|
}
|
||||||
|
} catch(t: Throwable) {
|
||||||
|
Timber.e(t, "Could not migrate manga!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.runOnUiThread {
|
||||||
|
progressDialog.dismiss()
|
||||||
|
|
||||||
|
//Enable orientation changes again
|
||||||
|
context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
|
||||||
|
|
||||||
|
displayMigrationComplete(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tryAskMigration(activity: Activity) {
|
||||||
|
if(preferenceHelper.migrateLibraryAsked().getOrDefault()) return
|
||||||
|
|
||||||
|
MaterialDialog.Builder(activity)
|
||||||
|
.title("Migrate library")
|
||||||
|
.content("You need to migrate your library before tag searching in the library will function.\n\n" +
|
||||||
|
"This migration may take a long time depending on your library size and will also use up a significant amount of internet bandwidth.\n\n" +
|
||||||
|
"This process can be done later if required.")
|
||||||
|
.positiveText("Migrate")
|
||||||
|
.negativeText("Later")
|
||||||
|
.onPositive { materialDialog, dialogAction -> show(activity) }
|
||||||
|
.onNegative { materialDialog, dialogAction -> adviseMigrationLater(activity) }
|
||||||
|
.cancelable(false)
|
||||||
|
.canceledOnTouchOutside(false)
|
||||||
|
.dismissListener {
|
||||||
|
preferenceHelper.migrateLibraryAsked().set(true)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun askMigration(activity: Activity) {
|
||||||
|
MaterialDialog.Builder(activity)
|
||||||
|
.title("Migrate library")
|
||||||
|
.content("You need to migrate your library before tag searching in the library will function.\n\n" +
|
||||||
|
"This migration may take a long time depending on your library size and will also use up a significant amount of internet bandwidth.\n\n" +
|
||||||
|
"This process can be done later if required.")
|
||||||
|
.positiveText("Migrate")
|
||||||
|
.negativeText("Later")
|
||||||
|
.onPositive { materialDialog, dialogAction -> show(activity) }
|
||||||
|
.onNegative { materialDialog, dialogAction -> adviseMigrationLater(activity) }
|
||||||
|
.cancelable(false)
|
||||||
|
.canceledOnTouchOutside(false)
|
||||||
|
.dismissListener {
|
||||||
|
preferenceHelper.migrateLibraryAsked().set(true)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun adviseMigrationLater(activity: Activity) {
|
||||||
|
MaterialDialog.Builder(activity)
|
||||||
|
.title("Migration canceled")
|
||||||
|
.content("Library migration has been canceled.\n\n" +
|
||||||
|
"You can run this operation later by going to: Settings > EHentai > Migrate Library")
|
||||||
|
.positiveText("Ok")
|
||||||
|
.cancelable(true)
|
||||||
|
.canceledOnTouchOutside(true)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun displayMigrationComplete(activity: Activity) {
|
||||||
|
MaterialDialog.Builder(activity)
|
||||||
|
.title("Migration complete")
|
||||||
|
.content("${activity.getString(R.string.app_name)} is now ready for use!")
|
||||||
|
.positiveText("Ok")
|
||||||
|
.cancelable(true)
|
||||||
|
.canceledOnTouchOutside(true)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
@ -63,6 +63,16 @@
|
|||||||
android:entries="@array/ehentai_thumbnail_rows"
|
android:entries="@array/ehentai_thumbnail_rows"
|
||||||
android:entryValues="@array/ehentai_thumbnail_rows_values" />
|
android:entryValues="@array/ehentai_thumbnail_rows_values" />
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="Advanced"
|
||||||
|
android:persistent="false">
|
||||||
|
<Preference
|
||||||
|
android:title="Migrate library"
|
||||||
|
android:persistent="false"
|
||||||
|
android:key="ex_migrate_library"
|
||||||
|
android:summary="Migrate your library to enable tag searching in the library. This button will be visible even if you have already migrated your library" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
Loading…
x
Reference in New Issue
Block a user