diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 72faea00a..0ed841bbf 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -132,6 +132,15 @@
android:scheme="https"/>
+
+
+
+
+
+
+
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
index fab0ba15b..62804132d 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
@@ -9,6 +9,7 @@ import com.f2prateek.rx.preferences.RxSharedPreferences
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.source.Source
import eu.kanade.tachiyomi.data.track.TrackService
+import exh.ui.migration.MigrationStatus
import java.io.File
fun Preference.getOrDefault(): T = get() ?: defaultValue()!!
@@ -161,6 +162,10 @@ class PreferencesHelper(val context: Context) {
fun migrateLibraryAsked() = rxPrefs.getBoolean("ex_migrate_library", false)
+ fun migrationStatus() = rxPrefs.getInteger("migration_status", MigrationStatus.NOT_INITIALIZED)
+
+ fun finishMainActivity() = rxPrefs.getBoolean("finish_main_activity", false)
+
//EH Cookies
fun memberIdVal() = rxPrefs.getString("eh_ipb_member_id", null)
fun passHashVal() = rxPrefs.getString("eh_ipb_pass_hash", null)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
index 9cb52bd6e..ae7e7d62c 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt
@@ -120,7 +120,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
.searchSubject
.debounce(100L, TimeUnit.MILLISECONDS)
.subscribe { text -> //Debounce search (EH)
- adapter.asyncSearchText = text.trim().toLowerCase()
+ adapter.asyncSearchText = text?.trim()?.toLowerCase()
adapter.updateDataSet()
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt
index db7eee11b..e6de71544 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt
@@ -25,7 +25,6 @@ class ChangelogDialogFragment : DialogFragment() {
preferences.lastVersionCode().set(BuildConfig.VERSION_CODE)
ChangelogDialogFragment().show(fm, "changelog")
- // TODO better upgrades management
if (oldVersion == 0) return
if (oldVersion < 14) {
@@ -39,6 +38,7 @@ class ChangelogDialogFragment : DialogFragment() {
// Delete internal chapter cache dir.
File(context.cacheDir, "chapter_disk_cache").deleteRecursively()
}
+ //TODO Review any other changes below
}
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
index b7172f494..f80333ae6 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
@@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.main
+import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.support.v4.app.Fragment
@@ -7,7 +8,6 @@ import android.support.v4.app.TaskStackBuilder
import android.support.v4.view.GravityCompat
import android.view.MenuItem
import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.backup.BackupFragment
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
@@ -18,18 +18,21 @@ import eu.kanade.tachiyomi.ui.library.LibraryFragment
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersFragment
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadFragment
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
-import exh.ui.MetadataFetchDialog
import exh.ui.batchadd.BatchAddFragment
+import exh.ui.migration.LibraryMigrationManager
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.toolbar.*
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
+import rx.Subscription
import uy.kohesive.injekt.injectLazy
class MainActivity : BaseActivity() {
val preferences: PreferencesHelper by injectLazy()
+ var finishSubscription: Subscription? = null
+
+ var dismissQueue = mutableListOf()
+
private val startScreenId by lazy {
when (preferences.startScreen()) {
1 -> R.id.nav_drawer_library
@@ -88,15 +91,25 @@ class MainActivity : BaseActivity() {
ChangelogDialogFragment.show(this, preferences, supportFragmentManager)
// Migrate library if needed
- Injekt.get().getLibraryMangas().asRxSingle().subscribe {
- if(it.size > 0)
- runOnUiThread {
- MetadataFetchDialog().tryAskMigration(this)
- }
+ LibraryMigrationManager(this, dismissQueue).askMigrationIfNecessary()
+
+ //Last part of migration requires finishing this activity
+ finishSubscription?.unsubscribe()
+ preferences.finishMainActivity().set(false)
+ finishSubscription = preferences.finishMainActivity().asObservable().subscribe {
+ if(it)
+ finish()
}
}
}
+ override fun onDestroy() {
+ super.onDestroy()
+ finishSubscription?.unsubscribe()
+ preferences.finishMainActivity().set(false)
+ dismissQueue.forEach { it.dismiss() }
+ }
+
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> drawer.openDrawer(GravityCompat.START)
@@ -155,5 +168,6 @@ class MainActivity : BaseActivity() {
companion object {
private const val REQUEST_OPEN_SETTINGS = 200
+ const val FINALIZE_MIGRATION = "finalize_migration"
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhFragment.kt
index 23d18e5cb..37865619d 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhFragment.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhFragment.kt
@@ -6,7 +6,7 @@ import android.support.v7.preference.XpPreferenceFragment
import android.view.View
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.plusAssign
-import exh.ui.MetadataFetchDialog
+import exh.ui.migration.MetadataFetchDialog
import exh.ui.login.LoginActivity
import net.xpece.android.support.preference.Preference
import net.xpece.android.support.preference.SwitchPreference
diff --git a/app/src/main/java/exh/ui/migration/LibraryMigrationManager.kt b/app/src/main/java/exh/ui/migration/LibraryMigrationManager.kt
new file mode 100644
index 000000000..ac45ace95
--- /dev/null
+++ b/app/src/main/java/exh/ui/migration/LibraryMigrationManager.kt
@@ -0,0 +1,263 @@
+package exh.ui.migration
+
+import android.app.Activity
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.graphics.Color
+import android.net.Uri
+import android.os.Build
+import android.text.Html
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+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.ui.main.MainActivity
+import eu.kanade.tachiyomi.util.toast
+import uy.kohesive.injekt.injectLazy
+
+/**
+ * Guide to migrate thel ibrary between two TachiyomiEH apps
+ */
+
+class LibraryMigrationManager(val context: MainActivity,
+ val dismissQueue: MutableList? = null) {
+ val preferenceHelper: PreferencesHelper by injectLazy()
+
+ val databaseHelper: DatabaseHelper by injectLazy()
+
+ private fun mainTachiyomiEHActivity()
+ = context.packageManager.getLaunchIntentForPackage(TACHIYOMI_EH_PACKAGE)
+
+ fun askMigrationIfNecessary() {
+ //Check already migrated
+ val ms = preferenceHelper.migrationStatus().getOrDefault()
+ if(ms == MigrationStatus.COMPLETED) return
+
+ val ma = mainTachiyomiEHActivity()
+
+ //Old version not installed, migration not required
+ if(ma == null) {
+ preferenceHelper.migrationStatus().set(MigrationStatus.COMPLETED)
+ return
+ }
+
+ context.requestPermissionsOnMarshmallow()
+ if(ms == MigrationStatus.NOT_INITIALIZED) {
+ //We need migration
+ jumpToMigrationStep(MigrationStatus.NOTIFY_USER)
+ } else {
+ //Migration process already started, jump to step
+ jumpToMigrationStep(ms)
+ }
+ }
+
+ fun notifyUserMigration() {
+ redDialog()
+ .title("Migration necessary")
+ .content("Due to an unplanned technical error, this update could not be applied on top of the old app and was instead installed as a separate app!\n\n" +
+ "To keep your library/favorited galleries after this update, you must migrate it over from the old app.\n\n" +
+ "This migration process is not automatic, tap 'CONTINUE' to be guided through it.")
+ .positiveText("Continue")
+ .negativeText("Cancel")
+ .onPositive { materialDialog, dialogAction -> jumpToMigrationStep(MigrationStatus.OPEN_BACKUP_MENU) }
+ .onNegative { materialDialog, dialogAction -> warnUserMigration() }
+ .show()
+ }
+
+ fun warnUserMigration() {
+ redDialog()
+ .title("Are you sure?")
+ .content("You are cancelling the migration process! If you do not migrate your library, you will lose all of your favorited galleries!\n\n" +
+ "Press 'MIGRATE' to restart the migration process, press 'OK' if you still wish to cancel the migration process.")
+ .positiveText("Ok")
+ .negativeText("Migrate")
+ .onPositive { materialDialog, dialogAction -> completeMigration() }
+ .onNegative { materialDialog, dialogAction -> notifyUserMigration() }
+ .show()
+ }
+
+ fun openBackupMenuMigrationStep() {
+ val view = MigrationViewBuilder()
+ .text("1. Use the 'LAUNCH OLD APP' button below to launch the old app.")
+ .text("2. Tap on the 'three-lines' button at the top-left of the screen as shown below:")
+ .image(R.drawable.eh_migration_hamburgers)
+ .text("3. Highlight the 'Backup' item by tapping on it as shown below:")
+ .image(R.drawable.eh_migration_backup)
+ .text("4. Return to this app but do not close the old app.")
+ .text("5. When you have completed the above steps, tap 'CONTINUE'.")
+ .toView(context)
+
+ migrationStepDialog(1, null, MigrationStatus.PERFORM_BACKUP)
+ .customView(view, true)
+ .neutralText("Launch Old App")
+ .onNeutral { materialDialog, dialogAction ->
+ //Auto dismiss messes this up so we have to reopen the dialog manually
+ val ma = mainTachiyomiEHActivity()
+ if(ma != null) {
+ context.startActivity(ma)
+ } else {
+ context.toast("Failed to launch old app! Try launching it manually.")
+ }
+ openBackupMenuMigrationStep()
+ }
+ .show()
+ }
+
+ fun performBackupMigrationStep() {
+ val view = MigrationViewBuilder()
+ .text("6. Return to the old app.")
+ .text("7. Tap on the 'BACKUP' button in the old app (shown below):")
+ .image(R.drawable.eh_migration_backup_button)
+ .text("8. In the menu that appears, tap on 'Complete migration' (shown below):")
+ .image(R.drawable.eh_migration_share_icon)
+ .toView(context)
+
+ migrationStepDialog(2, MigrationStatus.OPEN_BACKUP_MENU, null)
+ .customView(view, true)
+ .show()
+ }
+
+ fun finalizeMigration() {
+ migrationDialog()
+ .title("Migration complete")
+ .content(fromHtmlCompat("Your library has been migrated over to the new app!
" +
+ "You may now uninstall the old app by pressing the 'UNINSTALL OLD APP' button below!
" +
+ "If you were previously using ExHentai, your library may appear blank, just log in again to fix this.
" +
+ "Then tap 'OK' to exit the migration process!"))
+ .positiveText("Ok")
+ .neutralText("Uninstall Old App")
+ .onPositive { materialDialog, dialogAction ->
+ completeMigration()
+ //Check if the metadata needs to be updated
+ databaseHelper.getLibraryMangas().asRxSingle().subscribe {
+ if (it.size > 0)
+ context.runOnUiThread {
+ MetadataFetchDialog().tryAskMigration(context)
+ }
+ }
+ }
+ .onNeutral { materialDialog, dialogAction ->
+ val packageUri = Uri.parse("package:$TACHIYOMI_EH_PACKAGE")
+ val uninstallIntent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri)
+ context.startActivity(uninstallIntent)
+ //Cancel out auto-dismiss
+ finalizeMigration()
+ }
+ .show()
+ }
+
+ fun migrationDialog() = MaterialDialog.Builder(context)
+ .cancelable(false)
+ .canceledOnTouchOutside(false)
+ .showListener { dismissQueue?.add(it) }!!
+
+ fun migrationStepDialog(step: Int, previousStep: Int?, nextStep: Int?) = migrationDialog()
+ .title("Migration part $step of ${MigrationStatus.MAX_MIGRATION_STEPS}")
+ .apply {
+ if(previousStep != null) {
+ negativeText("Back")
+ onNegative { materialDialog, dialogAction -> jumpToMigrationStep(previousStep) }
+ }
+ if(nextStep != null) {
+ positiveText("Continue")
+ onPositive { materialDialog, dialogAction -> jumpToMigrationStep(nextStep) }
+ }
+ }!!
+
+ fun redDialog() = migrationDialog()
+ .backgroundColor(Color.parseColor("#F44336"))
+ .titleColor(Color.WHITE)
+ .contentColor(Color.WHITE)
+ .positiveColor(Color.WHITE)
+ .negativeColor(Color.WHITE)
+ .neutralColor(Color.WHITE)!!
+
+ fun completeMigration() {
+ preferenceHelper.migrationStatus().set(MigrationStatus.COMPLETED)
+
+ //Enable orientation changes again
+ context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
+ }
+
+ fun jumpToMigrationStep(migrationStatus: Int) {
+ preferenceHelper.migrationStatus().set(migrationStatus)
+
+ //Too lazy to actually deal with orientation changes
+ context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
+
+ when(migrationStatus) {
+ MigrationStatus.NOTIFY_USER -> notifyUserMigration()
+ MigrationStatus.OPEN_BACKUP_MENU -> openBackupMenuMigrationStep()
+ MigrationStatus.PERFORM_BACKUP -> performBackupMigrationStep()
+ MigrationStatus.FINALIZE_MIGRATION -> finalizeMigration()
+ }
+ }
+
+ companion object {
+ const val TACHIYOMI_EH_PACKAGE = "eu.kanade.tachiyomi.eh"
+ fun fromHtmlCompat(string: String)
+ = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+ Html.fromHtml(string, Html.FROM_HTML_MODE_LEGACY)
+ else
+ Html.fromHtml(string)
+ }
+
+ class MigrationViewBuilder {
+ val elements = mutableListOf()
+ fun text(text: String) = apply { elements += TextElement(text) }
+ fun image(drawable: Int) = apply { elements += ImageElement(drawable) }
+
+ fun toView(context: Activity): View {
+ val root = LinearLayout(context)
+ val rootParams = root.layoutParams ?: ViewGroup.LayoutParams(0, 0)
+
+ fun ViewGroup.LayoutParams.setup() = apply {
+ height = ViewGroup.LayoutParams.WRAP_CONTENT
+ width = ViewGroup.LayoutParams.MATCH_PARENT
+ }
+
+ fun dpToPx(dp: Float) = (dp * context.resources.displayMetrics.density + 0.5f).toInt()
+
+ rootParams.setup()
+ root.layoutParams = rootParams
+ root.gravity = Gravity.CENTER
+ root.orientation = LinearLayout.VERTICAL
+
+ for(element in elements) {
+ val view: View
+ if(element is TextElement) {
+ view = TextView(context)
+ view.text = fromHtmlCompat(element.value)
+ } else if(element is ImageElement) {
+ view = ImageView(context)
+ view.setImageResource(element.drawable)
+ view.adjustViewBounds = true
+ } else {
+ throw IllegalArgumentException("Unknown migration view!")
+ }
+ val viewParams = view.layoutParams ?: ViewGroup.LayoutParams(0, 0)
+ viewParams.setup()
+ view.layoutParams = viewParams
+ val eightDpAsPx = dpToPx(8f)
+ view.setPadding(0, eightDpAsPx, 0, eightDpAsPx)
+
+ root.addView(view)
+ }
+
+ return root
+ }
+ }
+
+ open class MigrationElement
+ class TextElement(val value: String): MigrationElement()
+ class ImageElement(val drawable: Int): MigrationElement()
+}
+
diff --git a/app/src/main/java/exh/ui/MetadataFetchDialog.kt b/app/src/main/java/exh/ui/migration/MetadataFetchDialog.kt
similarity index 66%
rename from app/src/main/java/exh/ui/MetadataFetchDialog.kt
rename to app/src/main/java/exh/ui/migration/MetadataFetchDialog.kt
index edbc405d5..922bd25be 100644
--- a/app/src/main/java/exh/ui/MetadataFetchDialog.kt
+++ b/app/src/main/java/exh/ui/migration/MetadataFetchDialog.kt
@@ -1,4 +1,4 @@
-package exh.ui
+package exh.ui.migration
import android.app.Activity
import android.content.pm.ActivityInfo
@@ -30,7 +30,7 @@ class MetadataFetchDialog {
context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
val progressDialog = MaterialDialog.Builder(context)
- .title("Migrating library")
+ .title("Fetching library metadata")
.content("Preparing library")
.progress(false, 0, true)
.cancelable(false)
@@ -87,27 +87,40 @@ class MetadataFetchDialog {
}
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()
+ var extra = ""
+ db.getLibraryMangas().asRxSingle().subscribe {
+ //Not logged in but have ExHentai galleries
+ if(!preferenceHelper.enableExhentai().getOrDefault()) {
+ it.find { it.source == 2 }?.let {
+ extra = "If you use ExHentai, please log in first before fetching your library metadata!
"
+ }
+ }
+ activity.runOnUiThread {
+ MaterialDialog.Builder(activity)
+ .title("Fetch library metadata")
+ .content(LibraryMigrationManager.fromHtmlCompat("You need to fetch your library's metadata before tag searching in the library will function.
" +
+ "This process may take a long time depending on your library size and will also use up a significant amount of internet bandwidth.
" +
+ extra +
+ "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")
+ .title("Metadata fetch canceled")
+ .content("Library metadata fetch has been canceled.\n\n" +
+ "You can run this operation later by going to: Settings > E-Hentai > Migrate library metadata")
.positiveText("Ok")
.cancelable(true)
.canceledOnTouchOutside(true)
diff --git a/app/src/main/java/exh/ui/migration/MigrationCompletionActivity.kt b/app/src/main/java/exh/ui/migration/MigrationCompletionActivity.kt
new file mode 100644
index 000000000..f2571835a
--- /dev/null
+++ b/app/src/main/java/exh/ui/migration/MigrationCompletionActivity.kt
@@ -0,0 +1,92 @@
+package exh.ui.migration
+
+import android.content.Intent
+import android.os.Bundle
+import android.support.v4.app.ShareCompat
+import com.afollestad.materialdialogs.MaterialDialog
+import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.backup.BackupManager
+import eu.kanade.tachiyomi.data.preference.PreferencesHelper
+import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
+import eu.kanade.tachiyomi.ui.main.MainActivity
+import kotlinx.android.synthetic.main.toolbar.*
+import timber.log.Timber
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
+import uy.kohesive.injekt.injectLazy
+import kotlin.concurrent.thread
+
+/**
+ * Read backups directly from another Tachiyomi app
+ */
+
+class MigrationCompletionActivity : BaseActivity() {
+
+ private val backupManager by lazy { BackupManager(Injekt.get()) }
+
+ private val preferenceManager: PreferencesHelper by injectLazy()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setAppTheme()
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.eh_activity_finish_migration)
+
+ setup()
+
+ setupToolbar(toolbar, backNavigation = false)
+ supportActionBar?.setDisplayHomeAsUpEnabled(false)
+ }
+
+ fun setup() {
+ try {
+ val sc = ShareCompat.IntentReader.from(this)
+ Timber.i("CP: " + sc.callingPackage)
+ if(sc.isShareIntent) {
+ //Try to restore backup
+ thread {
+ //Finish old MainActivity
+ preferenceManager.finishMainActivity().set(true)
+ try {
+ backupManager.restoreFromStream(contentResolver.openInputStream(sc.stream))
+ } catch(t: Throwable) {
+ Timber.e(t, "Failed to restore manga/galleries!")
+ migrationError("Failed to restore manga/galleries!")
+ return@thread
+ }
+
+ //Go back to MainActivity
+ //Set final steps
+ preferenceManager.migrationStatus().set(MigrationStatus.FINALIZE_MIGRATION)
+ //Wait for MainActivity to finish
+ Thread.sleep(1000)
+ //Start new MainActivity
+ val intent = Intent(this, MainActivity::class.java)
+ intent.putExtra(MainActivity.Companion.FINALIZE_MIGRATION, true)
+ finish()
+ startActivity(intent)
+ }
+ }
+ } catch(t: Throwable) {
+ Timber.e(t, "Failed to migrate manga!")
+ migrationError("An unknown error occurred during migration!")
+ }
+ }
+
+ fun migrationError(message: String) {
+ runOnUiThread {
+ MaterialDialog.Builder(this)
+ .title("Migration error")
+ .content(message)
+ .positiveText("Ok")
+ .cancelable(false)
+ .canceledOnTouchOutside(false)
+ .dismissListener { finish() }
+ .show()
+ }
+ }
+
+ override fun onBackPressed() {
+ //Do not allow finishing this activity
+ }
+}
+
diff --git a/app/src/main/java/exh/ui/migration/MigrationStatus.kt b/app/src/main/java/exh/ui/migration/MigrationStatus.kt
new file mode 100644
index 000000000..1fa3aa5cf
--- /dev/null
+++ b/app/src/main/java/exh/ui/migration/MigrationStatus.kt
@@ -0,0 +1,16 @@
+package exh.ui.migration
+
+class MigrationStatus {
+ companion object {
+ val NOT_INITIALIZED = -1
+ val COMPLETED = 0
+
+ //Migration process
+ val NOTIFY_USER = 1
+ val OPEN_BACKUP_MENU = 2
+ val PERFORM_BACKUP = 3
+ val FINALIZE_MIGRATION = 4
+
+ val MAX_MIGRATION_STEPS = 2
+ }
+}
diff --git a/app/src/main/res/drawable/eh_migration_backup.png b/app/src/main/res/drawable/eh_migration_backup.png
new file mode 100644
index 000000000..9d58af1e3
Binary files /dev/null and b/app/src/main/res/drawable/eh_migration_backup.png differ
diff --git a/app/src/main/res/drawable/eh_migration_backup_button.png b/app/src/main/res/drawable/eh_migration_backup_button.png
new file mode 100644
index 000000000..9903385c9
Binary files /dev/null and b/app/src/main/res/drawable/eh_migration_backup_button.png differ
diff --git a/app/src/main/res/drawable/eh_migration_hamburgers.png b/app/src/main/res/drawable/eh_migration_hamburgers.png
new file mode 100644
index 000000000..8e491b1e5
Binary files /dev/null and b/app/src/main/res/drawable/eh_migration_hamburgers.png differ
diff --git a/app/src/main/res/drawable/eh_migration_share_icon.png b/app/src/main/res/drawable/eh_migration_share_icon.png
new file mode 100644
index 000000000..7749f7797
Binary files /dev/null and b/app/src/main/res/drawable/eh_migration_share_icon.png differ
diff --git a/app/src/main/res/layout/eh_activity_finish_migration.xml b/app/src/main/res/layout/eh_activity_finish_migration.xml
new file mode 100644
index 000000000..e96f46e38
--- /dev/null
+++ b/app/src/main/res/layout/eh_activity_finish_migration.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/raw/changelog_release.xml b/app/src/main/res/raw/changelog_release.xml
index 45567a143..71969b1f5 100644
--- a/app/src/main/res/raw/changelog_release.xml
+++ b/app/src/main/res/raw/changelog_release.xml
@@ -1,123 +1,9 @@
-
-
- Added an app's language selector.
-
- Added options to sort the library and merged them with the filters.
-
- Added an option to automatically download chapters.
-
- Fixed performance issues when using a custom downloads directory, especially in the library updates tab.
-
- Fixed gesture conflicts with the contextual menu and the webtoon reader.
-
- Fixed wrong page direction when using volume keys for the right to left reader.
-
- Fixed many crashes.
-
-
-
- The download manager has been rewritten and it's possible some of your downloads
- aren't recognized anymore. It's recommended to manually delete everything and start over.
-
-
- Now it's possible to download to any folder in a SD card.
-
- The download directory setting has been reset.
-
- Active downloads now persist after restarts.
-
- Allow to bookmark chapters.
-
- Allow to share or save a single page while reading with a long tap.
-
- Added italian translation.
-
- Image is now the default decoder.
-
-
-
- Added a new image decoder. It should be faster than Rapid and more reliable than Skia.
-
- Removed the advanced setting reencode images. Use the new image decoder instead.
-
-
-
- Fixed a crash when opening latest updates. ([a href="https://github.com/inorichi/tachiyomi/issues/495"]#495[/a])
-
-
-
- Added a new tab to show latest manga updates from the catalogues. ([a href="https://github.com/inorichi/tachiyomi/issues/61"]#61[/a])
-
- Added genre filter for catalogues. ([a href="https://github.com/inorichi/tachiyomi/issues/428"]#428[/a])
-
- Added an optional auto updater (not available for F-Droid installs). ([a href="https://github.com/inorichi/tachiyomi/issues/449"]#449[/a])
-
- Added an option to display the library as a list. ([a href="https://github.com/inorichi/tachiyomi/issues/224"]#224[/a])
-
- Added a customizable color filter for the reader. ([a href="https://github.com/inorichi/tachiyomi/issues/432"]#432[/a])
-
- Added share intent in the info tab of a manga. ([a href="https://github.com/inorichi/tachiyomi/issues/340"]#340[/a])
-
- Allow to launcher shortcuts for manga. ([a href="https://github.com/inorichi/tachiyomi/issues/435"]#435[/a])
-
- Allow to select categories to update in global update. ([a href="https://github.com/inorichi/tachiyomi/issues/461"]#461[/a])
-
- Redesigned source tab in preferences, now it allows to hide unwanted sources and languages. ([a href="https://github.com/inorichi/tachiyomi/issues/447"]#447[/a])
-
- Fixed single page chapters not appending the next one. ([a href="https://github.com/inorichi/tachiyomi/issues/468"]#468[/a])
-
- Fixed reader status bar reappearing after focus restore. ([a href="https://github.com/inorichi/tachiyomi/issues/408"]#408[/a])
-
- Fixed various crashes in the webtoon reader.
-
-
-
- Added a history of reading. ([a href="https://github.com/inorichi/tachiyomi/issues/316"]#316[/a])
-
- Added an option to select the initial screen. ([a href="https://github.com/inorichi/tachiyomi/issues/395"]#395[/a])
-
- Added spanish and portuguese translations. ([a href="https://github.com/inorichi/tachiyomi/issues/365"]#365[/a], [a href="https://github.com/inorichi/tachiyomi/issues/375"]#375[/a])
-
- Added sources "Mangasee" and "Wie Manga!" ([a href="https://github.com/inorichi/tachiyomi/issues/355"]#355[/a], [a href="https://github.com/inorichi/tachiyomi/issues/379"]#379[/a])
-
- New design for the reader's menu. ([a href="https://github.com/inorichi/tachiyomi/issues/368"]#368[/a])
-
- When resuming chapters, the new loader starts from the page that was opened, instead of from the beginning. ([a href="https://github.com/inorichi/tachiyomi/issues/268"]#268[/a])
-
- Custom brightness in the reader can be set even lower by applying a black layer on the top. ([a href="https://github.com/inorichi/tachiyomi/issues/362"]#362[/a])
-
- Fixed reader's status bar reappearing in Android versions older than Kit Kat. ([a href="https://github.com/inorichi/tachiyomi/issues/359"]#359[/a])
-
- Fixed UI bugs. ([a href="https://github.com/inorichi/tachiyomi/issues/332"]#332[/a], [a href="https://github.com/inorichi/tachiyomi/issues/333"]#333[/a], [a href="https://github.com/inorichi/tachiyomi/issues/351"]#351[/a], [a href="https://github.com/inorichi/tachiyomi/issues/361"]#361[/a])
-
- Fixed empty library covers.
-
- Fixed some random crashes (most of them when downloading chapters).
-
-
- [b]Important![/b] Now chapters follow the order of the sources. [b]It's required that you update your entire library
- before reading to sync them.[/b] Old behavior can be restored for a manga in the overflow menu of the chapters tab.
+ [b]Important![/b] The application is now signed with a different key, you must migrate over your previous library if you wish to keep it!
- Kissmanga now loads through CloudFlare.
-
- Persistent cookies have been added for a better experience with CloudFlare sites.
-
- Added link to manga website in the info page. [a href="https://github.com/inorichi/tachiyomi/issues/157"]#157[/a]
-
- Added notifications for downloads. [a href="https://github.com/inorichi/tachiyomi/pull/289"]#289[/a]
-
- Added more options to recent updates. [a href="https://github.com/inorichi/tachiyomi/pull/324"]#324[/a]
-
- Remember last active category. [a href="https://github.com/inorichi/tachiyomi/issues/261"]#261[/a]
-
- Fixed a bug with seamless mode for chapters with less than 5 pages. [a href="https://github.com/inorichi/tachiyomi/issues/291"]#291[/a]
-
- Improved chapter recognition.
-
Bugfixes and more improvements.
diff --git a/app/src/main/res/xml/eh_pref_eh.xml b/app/src/main/res/xml/eh_pref_eh.xml
index 3c99fe488..5ec63237a 100644
--- a/app/src/main/res/xml/eh_pref_eh.xml
+++ b/app/src/main/res/xml/eh_pref_eh.xml
@@ -25,8 +25,8 @@
@@ -46,7 +46,7 @@
android:entryValues="@array/ehentai_quality_values" />
+ android:summary="Fetch the library metadata to enable tag searching in the library. This button will be visible even if you have already fetched the metadata" />