mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Migrate to Tachiyomi 6.1
Rewrite batch add UI Rewrite lock UI
This commit is contained in:
		@@ -56,68 +56,75 @@ class GalleryAdder {
 | 
			
		||||
        val outJson = JsonParser().parse(networkHelper.client.newCall(Request.Builder()
 | 
			
		||||
                .url(API_BASE)
 | 
			
		||||
                .post(RequestBody.create(JSON, json.toString()))
 | 
			
		||||
                .build()).execute().body().string()).obj
 | 
			
		||||
                .build()).execute().body()!!.string()).obj
 | 
			
		||||
 | 
			
		||||
        val obj = outJson["tokenlist"].array.first()
 | 
			
		||||
        return "${uri.scheme}://${uri.host}/g/${obj["gid"].int}/${obj["token"].string}/"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addGallery(url: String, fav: Boolean = false): Manga {
 | 
			
		||||
        val urlObj = Uri.parse(url)
 | 
			
		||||
        val source = when(urlObj.host) {
 | 
			
		||||
            "g.e-hentai.org", "e-hentai.org" -> EH_SOURCE_ID
 | 
			
		||||
            "exhentai.org" -> EXH_SOURCE_ID
 | 
			
		||||
            else -> throw MalformedURLException("Not a valid gallery URL!")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val realUrl = when (urlObj.pathSegments.first().toLowerCase()) {
 | 
			
		||||
            "g" -> {
 | 
			
		||||
                //Is already gallery page, do nothing
 | 
			
		||||
                url
 | 
			
		||||
            }
 | 
			
		||||
            "s" -> {
 | 
			
		||||
                //Is page, fetch gallery token and use that
 | 
			
		||||
                getGalleryUrlFromPage(url)
 | 
			
		||||
            }
 | 
			
		||||
            else -> {
 | 
			
		||||
                throw MalformedURLException("Not a valid gallery URL!")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val sourceObj = sourceManager.get(source)
 | 
			
		||||
                ?: throw IllegalStateException("Could not find EH source!")
 | 
			
		||||
 | 
			
		||||
        val pathOnlyUrl = getUrlWithoutDomain(realUrl)
 | 
			
		||||
 | 
			
		||||
        //Use manga in DB if possible, otherwise, make a new manga
 | 
			
		||||
        val manga = db.getManga(pathOnlyUrl, source).executeAsBlocking()
 | 
			
		||||
                ?: Manga.create(source).apply {
 | 
			
		||||
            this.url = pathOnlyUrl
 | 
			
		||||
            title = realUrl
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Copy basics
 | 
			
		||||
        manga.copyFrom(sourceObj.fetchMangaDetails(manga).toBlocking().first())
 | 
			
		||||
 | 
			
		||||
        //Apply metadata
 | 
			
		||||
        metadataHelper.fetchEhMetadata(realUrl, isExSource(source))?.copyTo(manga)
 | 
			
		||||
 | 
			
		||||
        if(fav) manga.favorite = true
 | 
			
		||||
 | 
			
		||||
        db.insertManga(manga).executeAsBlocking().insertedId()?.let {
 | 
			
		||||
            manga.id = it
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Fetch and copy chapters
 | 
			
		||||
    fun addGallery(url: String, fav: Boolean = false): GalleryAddEvent {
 | 
			
		||||
        try {
 | 
			
		||||
            sourceObj.fetchChapterList(manga).map {
 | 
			
		||||
                syncChaptersWithSource(db, it, manga, sourceObj)
 | 
			
		||||
            }.toBlocking().first()
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
            Timber.w(e, "Failed to update chapters for gallery: ${manga.title}!")
 | 
			
		||||
        }
 | 
			
		||||
            val urlObj = Uri.parse(url)
 | 
			
		||||
            val source = when (urlObj.host) {
 | 
			
		||||
                "g.e-hentai.org", "e-hentai.org" -> EH_SOURCE_ID
 | 
			
		||||
                "exhentai.org" -> EXH_SOURCE_ID
 | 
			
		||||
                else -> return GalleryAddEvent.Fail.UnknownType(url)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        return manga
 | 
			
		||||
            val realUrl = when (urlObj.pathSegments.first().toLowerCase()) {
 | 
			
		||||
                "g" -> {
 | 
			
		||||
                    //Is already gallery page, do nothing
 | 
			
		||||
                    url
 | 
			
		||||
                }
 | 
			
		||||
                "s" -> {
 | 
			
		||||
                    //Is page, fetch gallery token and use that
 | 
			
		||||
                    getGalleryUrlFromPage(url)
 | 
			
		||||
                }
 | 
			
		||||
                else -> {
 | 
			
		||||
                    return GalleryAddEvent.Fail.UnknownType(url)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val sourceObj = sourceManager.get(source)
 | 
			
		||||
                    ?: return GalleryAddEvent.Fail.Error(url, "Could not find EH source!")
 | 
			
		||||
 | 
			
		||||
            val pathOnlyUrl = getUrlWithoutDomain(realUrl)
 | 
			
		||||
 | 
			
		||||
            //Use manga in DB if possible, otherwise, make a new manga
 | 
			
		||||
            val manga = db.getManga(pathOnlyUrl, source).executeAsBlocking()
 | 
			
		||||
                    ?: Manga.create(source).apply {
 | 
			
		||||
                this.url = pathOnlyUrl
 | 
			
		||||
                title = realUrl
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Copy basics
 | 
			
		||||
            manga.copyFrom(sourceObj.fetchMangaDetails(manga).toBlocking().first())
 | 
			
		||||
 | 
			
		||||
            //Apply metadata
 | 
			
		||||
            metadataHelper.fetchEhMetadata(realUrl, isExSource(source))?.copyTo(manga)
 | 
			
		||||
 | 
			
		||||
            if (fav) manga.favorite = true
 | 
			
		||||
 | 
			
		||||
            db.insertManga(manga).executeAsBlocking().insertedId()?.let {
 | 
			
		||||
                manga.id = it
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Fetch and copy chapters
 | 
			
		||||
            try {
 | 
			
		||||
                sourceObj.fetchChapterList(manga).map {
 | 
			
		||||
                    syncChaptersWithSource(db, it, manga, sourceObj)
 | 
			
		||||
                }.toBlocking().first()
 | 
			
		||||
            } catch (e: Exception) {
 | 
			
		||||
                Timber.e(e, "Failed to update chapters for gallery: ${manga.title}!")
 | 
			
		||||
                return GalleryAddEvent.Fail.Error(url, "Failed to update chapters for gallery: $url")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return GalleryAddEvent.Success(url, manga)
 | 
			
		||||
        } catch(e: Exception) {
 | 
			
		||||
            Timber.e(e, "Could not add gallery!")
 | 
			
		||||
            return GalleryAddEvent.Fail.Error(url,
 | 
			
		||||
                    ((e.message ?: "Unknown error!") + " (Gallery: $url)").trim())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getUrlWithoutDomain(orig: String): String {
 | 
			
		||||
@@ -133,4 +140,28 @@ class GalleryAdder {
 | 
			
		||||
            return orig
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sealed class GalleryAddEvent {
 | 
			
		||||
    abstract val logMessage: String
 | 
			
		||||
    abstract val galleryUrl: String
 | 
			
		||||
    open val galleryTitle: String? = null
 | 
			
		||||
 | 
			
		||||
    class Success(override val galleryUrl: String,
 | 
			
		||||
                  val manga: Manga): GalleryAddEvent() {
 | 
			
		||||
        override val logMessage = "[OK] Added gallery: $galleryTitle"
 | 
			
		||||
        override val galleryTitle: String
 | 
			
		||||
            get() = manga.title
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sealed class Fail: GalleryAddEvent() {
 | 
			
		||||
        class UnknownType(override val galleryUrl: String): Fail() {
 | 
			
		||||
            override val logMessage = "[ERROR] Unknown gallery type for gallery: $galleryUrl"
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        class Error(override val galleryUrl: String,
 | 
			
		||||
                    val message: String): Fail() {
 | 
			
		||||
            override val logMessage = "[ERROR] $message"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,131 +1,145 @@
 | 
			
		||||
package exh.ui.batchadd
 | 
			
		||||
 | 
			
		||||
import android.content.pm.ActivityInfo
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import com.afollestad.materialdialogs.MaterialDialog
 | 
			
		||||
import com.jakewharton.rxbinding.view.clicks
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseFragment
 | 
			
		||||
import exh.GalleryAdder
 | 
			
		||||
import exh.metadata.nullIfBlank
 | 
			
		||||
import kotlinx.android.synthetic.main.eh_fragment_batch_add.*
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
import kotlin.concurrent.thread
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 | 
			
		||||
import eu.kanade.tachiyomi.util.combineLatest
 | 
			
		||||
import eu.kanade.tachiyomi.util.plusAssign
 | 
			
		||||
import kotlinx.android.synthetic.main.eh_fragment_batch_add.view.*
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
import rx.subscriptions.CompositeSubscription
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * LoginActivity
 | 
			
		||||
 * Batch add screen
 | 
			
		||||
 */
 | 
			
		||||
class BatchAddController : NucleusController<BatchAddPresenter>() {
 | 
			
		||||
    override fun inflateView(inflater: LayoutInflater, container: ViewGroup) =
 | 
			
		||||
            inflater.inflate(R.layout.eh_fragment_batch_add, container, false)!!
 | 
			
		||||
 | 
			
		||||
class BatchAddFragment : BaseFragment() {
 | 
			
		||||
    override fun getTitle() = "Batch add"
 | 
			
		||||
 | 
			
		||||
    private val galleryAdder by lazy { GalleryAdder() }
 | 
			
		||||
    override fun createPresenter() = BatchAddPresenter()
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?)
 | 
			
		||||
        = inflater.inflate(R.layout.eh_fragment_batch_add, container, false)!!
 | 
			
		||||
    override fun onViewCreated(view: View, savedViewState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedViewState)
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
 | 
			
		||||
        setToolbarTitle("Batch add")
 | 
			
		||||
 | 
			
		||||
        setup()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setup() {
 | 
			
		||||
        btn_add_galleries.setOnClickListener {
 | 
			
		||||
            val galleries = galleries_box.text.toString()
 | 
			
		||||
            //Check text box has content
 | 
			
		||||
            if(galleries.isNullOrBlank()) {
 | 
			
		||||
                noGalleriesSpecified()
 | 
			
		||||
                return@setOnClickListener
 | 
			
		||||
        with(view) {
 | 
			
		||||
            btn_add_galleries.clicks().subscribeUntilDestroy {
 | 
			
		||||
                addGalleries(galleries_box.text.toString())
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Too lazy to actually deal with orientation changes
 | 
			
		||||
            activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
 | 
			
		||||
            progress_dismiss_btn.clicks().subscribeUntilDestroy {
 | 
			
		||||
                presenter.currentlyAddingRelay.call(false)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val splitGalleries = galleries.split("\n").map {
 | 
			
		||||
                it.trim().nullIfBlank()
 | 
			
		||||
            }.filterNotNull()
 | 
			
		||||
            val progressSubscriptions = CompositeSubscription()
 | 
			
		||||
 | 
			
		||||
            val dialog = MaterialDialog.Builder(context)
 | 
			
		||||
                    .title("Adding galleries...")
 | 
			
		||||
                    .progress(false, splitGalleries.size, true)
 | 
			
		||||
                    .cancelable(false)
 | 
			
		||||
                    .canceledOnTouchOutside(false)
 | 
			
		||||
            presenter.currentlyAddingRelay
 | 
			
		||||
                    .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                    .subscribeUntilDestroy {
 | 
			
		||||
                        progressSubscriptions.clear()
 | 
			
		||||
                        if(it) {
 | 
			
		||||
                            showProgress(this)
 | 
			
		||||
                            progressSubscriptions += presenter.progressRelay
 | 
			
		||||
                                    .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                                    .combineLatest(presenter.progressTotalRelay, { progress, total ->
 | 
			
		||||
                                        //Show hide dismiss button
 | 
			
		||||
                                        progress_dismiss_btn.visibility =
 | 
			
		||||
                                                if(progress == total)
 | 
			
		||||
                                                    View.VISIBLE
 | 
			
		||||
                                                else View.GONE
 | 
			
		||||
 | 
			
		||||
                                        formatProgress(progress, total)
 | 
			
		||||
                                    }).subscribeUntilDestroy {
 | 
			
		||||
                                progress_text.text = it
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            progressSubscriptions += presenter.progressTotalRelay
 | 
			
		||||
                                    .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                                    .subscribeUntilDestroy {
 | 
			
		||||
                                        progress_bar.max = it
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                            progressSubscriptions += presenter.progressRelay
 | 
			
		||||
                                    .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                                    .subscribeUntilDestroy {
 | 
			
		||||
                                        progress_bar.progress = it
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                            presenter.eventRelay
 | 
			
		||||
                                    ?.observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
                                    ?.subscribeUntilDestroy {
 | 
			
		||||
                                        progress_log.append("$it\n")
 | 
			
		||||
                                    }?.let {
 | 
			
		||||
                                progressSubscriptions += it
 | 
			
		||||
                            }
 | 
			
		||||
                        } else hideProgress(this)
 | 
			
		||||
                    }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val View.progressViews
 | 
			
		||||
        get() = listOf(
 | 
			
		||||
                progress_title_view,
 | 
			
		||||
                progress_log_wrapper,
 | 
			
		||||
                progress_bar,
 | 
			
		||||
                progress_text,
 | 
			
		||||
                progress_dismiss_btn
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    private val View.inputViews
 | 
			
		||||
        get() = listOf(
 | 
			
		||||
                input_title_view,
 | 
			
		||||
                galleries_box,
 | 
			
		||||
                btn_add_galleries
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    private var List<View>.visibility: Int
 | 
			
		||||
        get() = throw UnsupportedOperationException()
 | 
			
		||||
        set(v) { forEach { it.visibility = v } }
 | 
			
		||||
 | 
			
		||||
    private fun showProgress(target: View? = view) {
 | 
			
		||||
        target?.apply {
 | 
			
		||||
            progressViews.visibility = View.VISIBLE
 | 
			
		||||
            inputViews.visibility = View.GONE
 | 
			
		||||
        }?.progress_log?.text = ""
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun hideProgress(target: View? = view) {
 | 
			
		||||
        target?.apply {
 | 
			
		||||
            progressViews.visibility = View.GONE
 | 
			
		||||
            inputViews.visibility = View.VISIBLE
 | 
			
		||||
        }?.galleries_box?.setText("", TextView.BufferType.EDITABLE)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun formatProgress(progress: Int, total: Int) = "$progress/$total"
 | 
			
		||||
 | 
			
		||||
    private fun addGalleries(galleries: String) {
 | 
			
		||||
        //Check text box has content
 | 
			
		||||
        if(galleries.isBlank()) {
 | 
			
		||||
            noGalleriesSpecified()
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        presenter.addGalleries(galleries)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun noGalleriesSpecified() {
 | 
			
		||||
        activity?.let {
 | 
			
		||||
            MaterialDialog.Builder(it)
 | 
			
		||||
                    .title("No galleries to add!")
 | 
			
		||||
                    .content("You must specify at least one gallery to add!")
 | 
			
		||||
                    .positiveText("Ok")
 | 
			
		||||
                    .onPositive { materialDialog, _ -> materialDialog.dismiss() }
 | 
			
		||||
                    .cancelable(true)
 | 
			
		||||
                    .canceledOnTouchOutside(true)
 | 
			
		||||
                    .show()
 | 
			
		||||
 | 
			
		||||
            val succeeded = mutableListOf<String>()
 | 
			
		||||
            val failed = mutableListOf<String>()
 | 
			
		||||
 | 
			
		||||
            thread {
 | 
			
		||||
                splitGalleries.forEachIndexed { i, s ->
 | 
			
		||||
                    activity.runOnUiThread {
 | 
			
		||||
                        dialog.setContent("Processing: $s")
 | 
			
		||||
                    }
 | 
			
		||||
                    if(addGallery(s)) {
 | 
			
		||||
                        succeeded.add(s)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        failed.add(s)
 | 
			
		||||
                    }
 | 
			
		||||
                    activity.runOnUiThread {
 | 
			
		||||
                        dialog.setProgress(i + 1)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //Show report
 | 
			
		||||
                val succeededCount = succeeded.size
 | 
			
		||||
                val failedCount = failed.size
 | 
			
		||||
 | 
			
		||||
                if(succeeded.isEmpty()) succeeded += "None"
 | 
			
		||||
                if(failed.isEmpty()) failed += "None"
 | 
			
		||||
                val succeededReport = succeeded.joinToString(separator = "\n", prefix = "Added:\n")
 | 
			
		||||
                val failedReport = failed.joinToString(separator = "\n", prefix = "Failed:\n")
 | 
			
		||||
 | 
			
		||||
                val summary = "Summary:\nAdded: $succeededCount gallerie(s)\nFailed: $failedCount gallerie(s)"
 | 
			
		||||
 | 
			
		||||
                val report = listOf(succeededReport, failedReport, summary).joinToString(separator = "\n\n")
 | 
			
		||||
 | 
			
		||||
                activity.runOnUiThread {
 | 
			
		||||
                    //Enable orientation changes again
 | 
			
		||||
                    activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
 | 
			
		||||
 | 
			
		||||
                    dialog.dismiss()
 | 
			
		||||
 | 
			
		||||
                    MaterialDialog.Builder(context)
 | 
			
		||||
                            .title("Batch add report")
 | 
			
		||||
                            .content(report)
 | 
			
		||||
                            .positiveText("Ok")
 | 
			
		||||
                            .cancelable(true)
 | 
			
		||||
                            .canceledOnTouchOutside(true)
 | 
			
		||||
                            .show()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addGallery(url: String): Boolean {
 | 
			
		||||
        try {
 | 
			
		||||
            galleryAdder.addGallery(url, true)
 | 
			
		||||
        } catch(t: Throwable) {
 | 
			
		||||
            Timber.e(t, "Could not add gallery!")
 | 
			
		||||
            return false
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun noGalleriesSpecified() {
 | 
			
		||||
        MaterialDialog.Builder(context)
 | 
			
		||||
                .title("No galleries to add!")
 | 
			
		||||
                .content("You must specify at least one gallery to add!")
 | 
			
		||||
                .positiveText("Ok")
 | 
			
		||||
                .onPositive { materialDialog, _ -> materialDialog.dismiss() }
 | 
			
		||||
                .cancelable(true)
 | 
			
		||||
                .canceledOnTouchOutside(true)
 | 
			
		||||
                .show()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        fun newInstance() = BatchAddFragment()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,51 @@
 | 
			
		||||
package exh.ui.batchadd
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by nulldev on 8/23/17.
 | 
			
		||||
 */
 | 
			
		||||
import com.jakewharton.rxrelay.BehaviorRelay
 | 
			
		||||
import com.jakewharton.rxrelay.ReplayRelay
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 | 
			
		||||
import exh.GalleryAddEvent
 | 
			
		||||
import exh.GalleryAdder
 | 
			
		||||
import exh.metadata.nullIfBlank
 | 
			
		||||
import kotlin.concurrent.thread
 | 
			
		||||
 | 
			
		||||
class BatchAddPresenter: BasePresenter<BatchAddController>() {
 | 
			
		||||
 | 
			
		||||
    private val galleryAdder by lazy { GalleryAdder() }
 | 
			
		||||
 | 
			
		||||
    val progressTotalRelay = BehaviorRelay.create(0)!!
 | 
			
		||||
    val progressRelay = BehaviorRelay.create(0)!!
 | 
			
		||||
    var eventRelay: ReplayRelay<String>? = null
 | 
			
		||||
    val currentlyAddingRelay = BehaviorRelay.create(false)!!
 | 
			
		||||
 | 
			
		||||
    fun addGalleries(galleries: String) {
 | 
			
		||||
        eventRelay = ReplayRelay.create()
 | 
			
		||||
        val splitGalleries = galleries.split("\n").map {
 | 
			
		||||
            it.trim().nullIfBlank()
 | 
			
		||||
        }.filterNotNull()
 | 
			
		||||
 | 
			
		||||
        progressRelay.call(0)
 | 
			
		||||
        progressTotalRelay.call(splitGalleries.size)
 | 
			
		||||
 | 
			
		||||
        currentlyAddingRelay.call(true)
 | 
			
		||||
 | 
			
		||||
        thread {
 | 
			
		||||
            val succeeded = mutableListOf<String>()
 | 
			
		||||
            val failed = mutableListOf<String>()
 | 
			
		||||
 | 
			
		||||
            splitGalleries.forEachIndexed { i, s ->
 | 
			
		||||
                val result = galleryAdder.addGallery(s, true)
 | 
			
		||||
                if(result is GalleryAddEvent.Success) {
 | 
			
		||||
                    succeeded.add(s)
 | 
			
		||||
                } else {
 | 
			
		||||
                    failed.add(s)
 | 
			
		||||
                }
 | 
			
		||||
                progressRelay.call(i + 1)
 | 
			
		||||
                eventRelay?.call(result.logMessage)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Show report
 | 
			
		||||
            val summary = "\nSummary:\nAdded: ${succeeded.size} gallerie(s)\nFailed: ${failed.size} gallerie(s)"
 | 
			
		||||
            eventRelay?.call(summary)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,11 @@ import android.view.MenuItem
 | 
			
		||||
import com.afollestad.materialdialogs.MaterialDialog
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaActivity
 | 
			
		||||
import exh.GalleryAdder
 | 
			
		||||
import kotlinx.android.synthetic.main.toolbar.*
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
import kotlin.concurrent.thread
 | 
			
		||||
 | 
			
		||||
//TODO :(
 | 
			
		||||
class InterceptActivity : BaseActivity() {
 | 
			
		||||
 | 
			
		||||
    private val galleryAdder = GalleryAdder()
 | 
			
		||||
@@ -19,12 +18,9 @@ class InterceptActivity : BaseActivity() {
 | 
			
		||||
    var finished = false
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        setAppTheme()
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        setContentView(R.layout.eh_activity_intercept)
 | 
			
		||||
 | 
			
		||||
        setupToolbar(toolbar, backNavigation = false)
 | 
			
		||||
 | 
			
		||||
        if(savedInstanceState == null)
 | 
			
		||||
            thread { setup() }
 | 
			
		||||
    }
 | 
			
		||||
@@ -54,8 +50,9 @@ class InterceptActivity : BaseActivity() {
 | 
			
		||||
        if(Intent.ACTION_VIEW == intent.action) {
 | 
			
		||||
            val manga = galleryAdder.addGallery(intent.dataString)
 | 
			
		||||
 | 
			
		||||
            if(!finished)
 | 
			
		||||
                startActivity(MangaActivity.newIntent(this, manga, true))
 | 
			
		||||
            //TODO
 | 
			
		||||
//            if(!finished)
 | 
			
		||||
//                startActivity(MangaActivity.newIntent(this, manga, true))
 | 
			
		||||
            onBackPressed()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,60 +0,0 @@
 | 
			
		||||
package exh.ui.lock
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import com.afollestad.materialdialogs.MaterialDialog
 | 
			
		||||
import com.andrognito.pinlockview.PinLockListener
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
 | 
			
		||||
import kotlinx.android.synthetic.main.activity_lock.*
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
class LockActivity : BaseActivity() {
 | 
			
		||||
 | 
			
		||||
    val prefs: PreferencesHelper by injectLazy()
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        disableLock = true
 | 
			
		||||
 | 
			
		||||
        setTheme(R.style.Theme_Tachiyomi_Dark)
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
 | 
			
		||||
        if(!lockEnabled(prefs)) {
 | 
			
		||||
            finish()
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setContentView(R.layout.activity_lock)
 | 
			
		||||
 | 
			
		||||
        pin_lock_view.attachIndicatorDots(indicator_dots)
 | 
			
		||||
 | 
			
		||||
        pin_lock_view.pinLength = prefs.lockLength().getOrDefault()
 | 
			
		||||
        pin_lock_view.setPinLockListener(object : PinLockListener {
 | 
			
		||||
            override fun onEmpty() {}
 | 
			
		||||
 | 
			
		||||
            override fun onComplete(pin: String) {
 | 
			
		||||
                if(sha512(pin, prefs.lockSalt().get()!!) == prefs.lockHash().get()) {
 | 
			
		||||
                    //Yay!
 | 
			
		||||
                    finish()
 | 
			
		||||
                } else {
 | 
			
		||||
                    MaterialDialog.Builder(this@LockActivity)
 | 
			
		||||
                            .title("PIN code incorrect")
 | 
			
		||||
                            .content("The PIN code you entered is incorrect. Please try again.")
 | 
			
		||||
                            .cancelable(true)
 | 
			
		||||
                            .canceledOnTouchOutside(true)
 | 
			
		||||
                            .positiveText("Ok")
 | 
			
		||||
                            .autoDismiss(true)
 | 
			
		||||
                            .show()
 | 
			
		||||
                    pin_lock_view.resetPinLockView()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun onPinChange(pinLength: Int, intermediatePin: String?) {}
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onBackPressed() {
 | 
			
		||||
        moveTaskToBack(true)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								app/src/main/java/exh/ui/lock/LockChangeHandler.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								app/src/main/java/exh/ui/lock/LockChangeHandler.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
package exh.ui.lock
 | 
			
		||||
 | 
			
		||||
import android.animation.Animator
 | 
			
		||||
import android.animation.AnimatorSet
 | 
			
		||||
import android.animation.ObjectAnimator
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import com.bluelinelabs.conductor.ControllerChangeHandler
 | 
			
		||||
import com.bluelinelabs.conductor.changehandler.AnimatorChangeHandler
 | 
			
		||||
import java.util.ArrayList
 | 
			
		||||
 | 
			
		||||
class LockChangeHandler : AnimatorChangeHandler {
 | 
			
		||||
    constructor(): super()
 | 
			
		||||
 | 
			
		||||
    constructor(removesFromViewOnPush: Boolean) : super(removesFromViewOnPush)
 | 
			
		||||
 | 
			
		||||
    constructor(duration: Long) : super(duration)
 | 
			
		||||
 | 
			
		||||
    constructor(duration: Long, removesFromViewOnPush: Boolean) : super(duration, removesFromViewOnPush)
 | 
			
		||||
 | 
			
		||||
    override fun getAnimator(container: ViewGroup, from: View?, to: View?, isPush: Boolean, toAddedToContainer: Boolean): Animator {
 | 
			
		||||
        val animator = AnimatorSet()
 | 
			
		||||
        val viewAnimators = ArrayList<Animator>()
 | 
			
		||||
 | 
			
		||||
        if (!isPush && from != null) {
 | 
			
		||||
            viewAnimators.add(ObjectAnimator.ofFloat(from, View.SCALE_X, 5f))
 | 
			
		||||
            viewAnimators.add(ObjectAnimator.ofFloat(from, View.SCALE_Y, 5f))
 | 
			
		||||
            viewAnimators.add(ObjectAnimator.ofFloat(from, View.ALPHA, 0f))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        animator.playTogether(viewAnimators)
 | 
			
		||||
        return animator
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun resetFromView(from: View) {}
 | 
			
		||||
 | 
			
		||||
    override fun copy(): ControllerChangeHandler =
 | 
			
		||||
            LockChangeHandler(animationDuration, removesFromViewOnPush())
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										68
									
								
								app/src/main/java/exh/ui/lock/LockController.kt
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								app/src/main/java/exh/ui/lock/LockController.kt
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
package exh.ui.lock
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import com.afollestad.materialdialogs.MaterialDialog
 | 
			
		||||
import com.andrognito.pinlockview.PinLockListener
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 | 
			
		||||
import kotlinx.android.synthetic.main.activity_lock.view.*
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
class LockController : NucleusController<LockPresenter>() {
 | 
			
		||||
    override fun inflateView(inflater: LayoutInflater, container: ViewGroup)
 | 
			
		||||
        = inflater.inflate(R.layout.activity_lock, container, false)!!
 | 
			
		||||
 | 
			
		||||
    override fun createPresenter() = LockPresenter()
 | 
			
		||||
 | 
			
		||||
    override fun getTitle() = "Application locked"
 | 
			
		||||
 | 
			
		||||
    val prefs: PreferencesHelper by injectLazy()
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedViewState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedViewState)
 | 
			
		||||
 | 
			
		||||
        if(!lockEnabled(prefs)) {
 | 
			
		||||
            closeLock()
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        with(view) {
 | 
			
		||||
            pin_lock_view.attachIndicatorDots(indicator_dots)
 | 
			
		||||
 | 
			
		||||
            pin_lock_view.pinLength = prefs.lockLength().getOrDefault()
 | 
			
		||||
            pin_lock_view.setPinLockListener(object : PinLockListener {
 | 
			
		||||
                override fun onEmpty() {}
 | 
			
		||||
 | 
			
		||||
                override fun onComplete(pin: String) {
 | 
			
		||||
                    if (sha512(pin, prefs.lockSalt().get()!!) == prefs.lockHash().get()) {
 | 
			
		||||
                        //Yay!
 | 
			
		||||
                        closeLock()
 | 
			
		||||
                    } else {
 | 
			
		||||
                        MaterialDialog.Builder(context)
 | 
			
		||||
                                .title("PIN code incorrect")
 | 
			
		||||
                                .content("The PIN code you entered is incorrect. Please try again.")
 | 
			
		||||
                                .cancelable(true)
 | 
			
		||||
                                .canceledOnTouchOutside(true)
 | 
			
		||||
                                .positiveText("Ok")
 | 
			
		||||
                                .autoDismiss(true)
 | 
			
		||||
                                .show()
 | 
			
		||||
                        pin_lock_view.resetPinLockView()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                override fun onPinChange(pinLength: Int, intermediatePin: String?) {}
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun closeLock() {
 | 
			
		||||
        router.popCurrentController()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun handleBack() = true
 | 
			
		||||
}
 | 
			
		||||
@@ -17,7 +17,7 @@ import java.security.SecureRandom
 | 
			
		||||
class LockPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
 | 
			
		||||
        Preference(context, attrs) {
 | 
			
		||||
 | 
			
		||||
    val secureRandom by lazy { SecureRandom() }
 | 
			
		||||
    private val secureRandom by lazy { SecureRandom() }
 | 
			
		||||
 | 
			
		||||
    val prefs: PreferencesHelper by injectLazy()
 | 
			
		||||
 | 
			
		||||
@@ -26,12 +26,11 @@ class LockPreference @JvmOverloads constructor(context: Context, attrs: Attribut
 | 
			
		||||
        updateSummary()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun updateSummary() {
 | 
			
		||||
        if(lockEnabled(prefs)) {
 | 
			
		||||
            summary = "Application is locked"
 | 
			
		||||
        } else {
 | 
			
		||||
            summary = "Application is not locked, tap to lock"
 | 
			
		||||
        }
 | 
			
		||||
    private fun updateSummary() {
 | 
			
		||||
        summary = if(lockEnabled(prefs))
 | 
			
		||||
            "Application is locked"
 | 
			
		||||
        else
 | 
			
		||||
            "Application is not locked, tap to lock"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onClick() {
 | 
			
		||||
@@ -65,7 +64,7 @@ class LockPreference @JvmOverloads constructor(context: Context, attrs: Attribut
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun savePassword(password: String) {
 | 
			
		||||
    private fun savePassword(password: String) {
 | 
			
		||||
        val salt: String?
 | 
			
		||||
        val hash: String?
 | 
			
		||||
        val length: Int
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								app/src/main/java/exh/ui/lock/LockPresenter.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/src/main/java/exh/ui/lock/LockPresenter.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
package exh.ui.lock
 | 
			
		||||
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 | 
			
		||||
 | 
			
		||||
class LockPresenter: BasePresenter<LockController>()
 | 
			
		||||
 | 
			
		||||
@@ -44,13 +44,6 @@ fun lockEnabled(prefs: PreferencesHelper = Injekt.get())
 | 
			
		||||
            && prefs.lockSalt().get() != null
 | 
			
		||||
            && prefs.lockLength().getOrDefault() != -1
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Lock the screen
 | 
			
		||||
 */
 | 
			
		||||
fun showLockActivity(activity: Activity) {
 | 
			
		||||
    activity.startActivity(Intent(activity, LockActivity::class.java))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check if the lock will function properly
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.source.online.all.EHentai
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
 | 
			
		||||
import exh.EXH_SOURCE_ID
 | 
			
		||||
import kotlinx.android.synthetic.main.eh_activity_login.*
 | 
			
		||||
import kotlinx.android.synthetic.main.toolbar.*
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
import rx.schedulers.Schedulers
 | 
			
		||||
@@ -34,13 +33,10 @@ class LoginActivity : BaseActivity() {
 | 
			
		||||
    val sourceManager: SourceManager by injectLazy()
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        setAppTheme()
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        setContentView(R.layout.eh_activity_login)
 | 
			
		||||
 | 
			
		||||
        setup()
 | 
			
		||||
 | 
			
		||||
        setupToolbar(toolbar, backNavigation = false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setup() {
 | 
			
		||||
@@ -187,7 +183,7 @@ class LoginActivity : BaseActivity() {
 | 
			
		||||
                        document.getElementsByName('submit')[0].style.visibility = 'visible';
 | 
			
		||||
                        document.querySelector('td[width="60%"][valign="top"]').style.visibility = 'visible';
 | 
			
		||||
 | 
			
		||||
                        function hide(e) {if(e !== null && e !== undefined) e.style.display = 'none';}
 | 
			
		||||
                        function hide(e) {if(e != null) e.style.display = 'none';}
 | 
			
		||||
 | 
			
		||||
                        hide(document.querySelector(".errorwrap"));
 | 
			
		||||
                        hide(document.querySelector('td[width="40%"][valign="top"]'));
 | 
			
		||||
@@ -202,7 +198,7 @@ class LoginActivity : BaseActivity() {
 | 
			
		||||
                        hide(fd[2]);
 | 
			
		||||
                        hide(child.querySelector('br'));
 | 
			
		||||
                        var error = document.querySelector(".page > div > .borderwrap");
 | 
			
		||||
                        if(error !== null) error.style.visibility = 'visible';
 | 
			
		||||
                        if(error != null) error.style.visibility = 'visible';
 | 
			
		||||
                        hide(fh[0]);
 | 
			
		||||
                        hide(fh[1]);
 | 
			
		||||
                        hide(document.querySelector("#gfooter"));
 | 
			
		||||
@@ -211,7 +207,7 @@ class LoginActivity : BaseActivity() {
 | 
			
		||||
                            e.style.color = "white";
 | 
			
		||||
                        });
 | 
			
		||||
                        var pc = document.querySelector(".postcolor");
 | 
			
		||||
                        if(pc !== null) pc.style.color = "#26353F";
 | 
			
		||||
                        if(pc != null) pc.style.color = "#26353F";
 | 
			
		||||
                    })()
 | 
			
		||||
                    """
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user