Linting Fixes AZ
This commit is contained in:
@@ -49,66 +49,68 @@ class BatchAddController : NucleusController<EhFragmentBatchAddBinding, BatchAdd
|
||||
val progressSubscriptions = CompositeSubscription()
|
||||
|
||||
presenter.currentlyAddingRelay
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy {
|
||||
progressSubscriptions.clear()
|
||||
if (it == BatchAddPresenter.STATE_INPUT_TO_PROGRESS) {
|
||||
showProgress(this)
|
||||
progressSubscriptions += presenter.progressRelay
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.combineLatest(presenter.progressTotalRelay) { progress, total ->
|
||||
// Show hide dismiss button
|
||||
binding.progressDismissBtn.visibility =
|
||||
if (progress == total)
|
||||
View.VISIBLE
|
||||
else View.GONE
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy {
|
||||
progressSubscriptions.clear()
|
||||
if (it == BatchAddPresenter.STATE_INPUT_TO_PROGRESS) {
|
||||
showProgress(this)
|
||||
progressSubscriptions += presenter.progressRelay
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.combineLatest(presenter.progressTotalRelay) { progress, total ->
|
||||
// Show hide dismiss button
|
||||
binding.progressDismissBtn.visibility =
|
||||
if (progress == total) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
|
||||
formatProgress(progress, total)
|
||||
}.subscribeUntilDestroy {
|
||||
formatProgress(progress, total)
|
||||
}.subscribeUntilDestroy {
|
||||
binding.progressText.text = it
|
||||
}
|
||||
|
||||
progressSubscriptions += presenter.progressTotalRelay
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy {
|
||||
binding.progressBar.max = it
|
||||
}
|
||||
|
||||
progressSubscriptions += presenter.progressRelay
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy {
|
||||
binding.progressBar.progress = it
|
||||
}
|
||||
|
||||
presenter.eventRelay
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribeUntilDestroy {
|
||||
binding.progressLog.append("$it\n")
|
||||
}?.let {
|
||||
progressSubscriptions += it
|
||||
progressSubscriptions += presenter.progressTotalRelay
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy {
|
||||
binding.progressBar.max = it
|
||||
}
|
||||
} else if (it == BatchAddPresenter.STATE_PROGRESS_TO_INPUT) {
|
||||
hideProgress(this)
|
||||
presenter.currentlyAddingRelay.call(BatchAddPresenter.STATE_IDLE)
|
||||
|
||||
progressSubscriptions += presenter.progressRelay
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeUntilDestroy {
|
||||
binding.progressBar.progress = it
|
||||
}
|
||||
|
||||
presenter.eventRelay
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribeUntilDestroy {
|
||||
binding.progressLog.append("$it\n")
|
||||
}?.let {
|
||||
progressSubscriptions += it
|
||||
}
|
||||
} else if (it == BatchAddPresenter.STATE_PROGRESS_TO_INPUT) {
|
||||
hideProgress(this)
|
||||
presenter.currentlyAddingRelay.call(BatchAddPresenter.STATE_IDLE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val View.progressViews
|
||||
get() = listOf(
|
||||
binding.progressTitleView,
|
||||
binding.progressLogWrapper,
|
||||
binding.progressBar,
|
||||
binding.progressText,
|
||||
binding.progressDismissBtn
|
||||
binding.progressTitleView,
|
||||
binding.progressLogWrapper,
|
||||
binding.progressBar,
|
||||
binding.progressText,
|
||||
binding.progressDismissBtn
|
||||
)
|
||||
|
||||
private val View.inputViews
|
||||
get() = listOf(
|
||||
binding.inputTitleView,
|
||||
binding.galleriesBox,
|
||||
binding.btnAddGalleries
|
||||
binding.inputTitleView,
|
||||
binding.galleriesBox,
|
||||
binding.btnAddGalleries
|
||||
)
|
||||
|
||||
private var List<View>.visibility: Int
|
||||
@@ -144,12 +146,12 @@ class BatchAddController : NucleusController<EhFragmentBatchAddBinding, BatchAdd
|
||||
private fun noGalleriesSpecified() {
|
||||
activity?.let {
|
||||
MaterialDialog(it)
|
||||
.title(text = "No galleries to add!")
|
||||
.message(text = "You must specify at least one gallery to add!")
|
||||
.positiveButton(android.R.string.ok) { materialDialog -> materialDialog.dismiss() }
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.show()
|
||||
.title(text = "No galleries to add!")
|
||||
.message(text = "You must specify at least one gallery to add!")
|
||||
.positiveButton(android.R.string.ok) { materialDialog -> materialDialog.dismiss() }
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,10 +40,14 @@ class BatchAddPresenter : BasePresenter<BatchAddController>() {
|
||||
failed.add(s)
|
||||
}
|
||||
progressRelay.call(i + 1)
|
||||
eventRelay?.call((when (result) {
|
||||
is GalleryAddEvent.Success -> "[OK]"
|
||||
is GalleryAddEvent.Fail -> "[ERROR]"
|
||||
}) + " " + result.logMessage)
|
||||
eventRelay?.call(
|
||||
(
|
||||
when (result) {
|
||||
is GalleryAddEvent.Success -> "[OK]"
|
||||
is GalleryAddEvent.Fail -> "[ERROR]"
|
||||
}
|
||||
) + " " + result.logMessage
|
||||
)
|
||||
}
|
||||
|
||||
// Show report
|
||||
|
||||
@@ -26,9 +26,9 @@ class AutoSolvingWebViewClient(
|
||||
val doc = response.asJsoup()
|
||||
doc.body().appendChild(Element("script").appendChild(DataNode(CROSS_WINDOW_SCRIPT_INNER)))
|
||||
return WebResourceResponse(
|
||||
"text/html",
|
||||
"UTF-8",
|
||||
doc.toString().byteInputStream(Charset.forName("UTF-8")).buffered()
|
||||
"text/html",
|
||||
"UTF-8",
|
||||
doc.toString().byteInputStream(Charset.forName("UTF-8")).buffered()
|
||||
)
|
||||
}
|
||||
return super.shouldInterceptRequest(view, request)
|
||||
|
||||
@@ -14,8 +14,9 @@ open class BasicWebViewClient(
|
||||
if (verifyComplete(url)) {
|
||||
activity.finish()
|
||||
} else {
|
||||
if (injectScript != null)
|
||||
if (injectScript != null) {
|
||||
view.evaluateJavascript("(function() {$injectScript})();", null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,24 +62,27 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
val originalSource = if (sourceId != -1L) sourceManager.get(sourceId) else null
|
||||
val source = if (originalSource != null) {
|
||||
originalSource as? ActionCompletionVerifier
|
||||
?: run {
|
||||
(originalSource as? HttpSource)?.let {
|
||||
NoopActionCompletionVerifier(it)
|
||||
}
|
||||
?: run {
|
||||
(originalSource as? HttpSource)?.let {
|
||||
NoopActionCompletionVerifier(it)
|
||||
}
|
||||
}
|
||||
} else null
|
||||
|
||||
val headers = ((source as? HttpSource)?.headers?.toMultimap()?.mapValues {
|
||||
it.value.joinToString(",")
|
||||
} ?: emptyMap()) + (intent.getSerializableExtra(HEADERS_EXTRA) as? HashMap<String, String> ?: emptyMap())
|
||||
val headers = (
|
||||
(source as? HttpSource)?.headers?.toMultimap()?.mapValues {
|
||||
it.value.joinToString(",")
|
||||
} ?: emptyMap()
|
||||
) + (intent.getSerializableExtra(HEADERS_EXTRA) as? HashMap<String, String> ?: emptyMap())
|
||||
|
||||
val cookies: HashMap<String, String>? =
|
||||
intent.getSerializableExtra(COOKIES_EXTRA) as? HashMap<String, String>
|
||||
intent.getSerializableExtra(COOKIES_EXTRA) as? HashMap<String, String>
|
||||
val script: String? = intent.getStringExtra(SCRIPT_EXTRA)
|
||||
val url: String? = intent.getStringExtra(URL_EXTRA)
|
||||
val actionName = intent.getStringExtra(ACTION_NAME_EXTRA)
|
||||
|
||||
@Suppress("NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE") val verifyComplete = if (source != null) {
|
||||
@Suppress("NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE")
|
||||
val verifyComplete = if (source != null) {
|
||||
source::verifyComplete!!
|
||||
} else intent.getSerializableExtra(VERIFY_LAMBDA_EXTRA) as? (String) -> Boolean
|
||||
|
||||
@@ -139,10 +142,12 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
|
||||
webview.webViewClient = if (actionName == null && preferencesHelper.eh_autoSolveCaptchas().getOrDefault()) {
|
||||
// Fetch auto-solve credentials early for speed
|
||||
credentialsObservable = httpClient.newCall(Request.Builder()
|
||||
// Rob demo credentials
|
||||
.url("https://speech-to-text-demo.ng.bluemix.net/api/v1/credentials")
|
||||
.build())
|
||||
credentialsObservable = httpClient.newCall(
|
||||
Request.Builder()
|
||||
// Rob demo credentials
|
||||
.url("https://speech-to-text-demo.ng.bluemix.net/api/v1/credentials")
|
||||
.build()
|
||||
)
|
||||
.asObservableSuccess()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map {
|
||||
@@ -176,12 +181,12 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
runOnUiThread {
|
||||
webview.evaluateJavascript(SOLVE_UI_SCRIPT_HIDE, null)
|
||||
MaterialDialog(this)
|
||||
.title(text = "Captcha solve failure")
|
||||
.message(text = "Failed to auto-solve the captcha!")
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.show()
|
||||
.title(text = "Captcha solve failure")
|
||||
.message(text = "Failed to auto-solve the captcha!")
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,13 +197,19 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
when (stage) {
|
||||
STAGE_CHECKBOX -> {
|
||||
if (result!!.toBoolean()) {
|
||||
webview.postDelayed({
|
||||
getAudioButtonLocation(loopId)
|
||||
}, 250)
|
||||
webview.postDelayed(
|
||||
{
|
||||
getAudioButtonLocation(loopId)
|
||||
},
|
||||
250
|
||||
)
|
||||
} else {
|
||||
webview.postDelayed({
|
||||
doStageCheckbox(loopId)
|
||||
}, 250)
|
||||
webview.postDelayed(
|
||||
{
|
||||
doStageCheckbox(loopId)
|
||||
},
|
||||
250
|
||||
)
|
||||
}
|
||||
}
|
||||
STAGE_GET_AUDIO_BTN_LOCATION -> {
|
||||
@@ -216,31 +227,43 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
doStageDownloadAudio(loopId)
|
||||
}
|
||||
} else {
|
||||
webview.postDelayed({
|
||||
getAudioButtonLocation(loopId)
|
||||
}, 250)
|
||||
webview.postDelayed(
|
||||
{
|
||||
getAudioButtonLocation(loopId)
|
||||
},
|
||||
250
|
||||
)
|
||||
}
|
||||
}
|
||||
STAGE_DOWNLOAD_AUDIO -> {
|
||||
if (result != null) {
|
||||
Timber.d("Got audio URL: $result")
|
||||
performRecognize(result)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(
|
||||
{
|
||||
Timber.d("Got audio transcript: $it")
|
||||
webview.post {
|
||||
typeResult(loopId, it!!
|
||||
typeResult(
|
||||
loopId,
|
||||
it!!
|
||||
.replace(TRANSCRIPT_CLEANER_REGEX, "")
|
||||
.replace(SPACE_DEDUPE_REGEX, " ")
|
||||
.trim())
|
||||
.trim()
|
||||
)
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
captchaSolveFail()
|
||||
})
|
||||
}
|
||||
)
|
||||
} else {
|
||||
webview.postDelayed({
|
||||
doStageDownloadAudio(loopId)
|
||||
}, 250)
|
||||
webview.postDelayed(
|
||||
{
|
||||
doStageDownloadAudio(loopId)
|
||||
},
|
||||
250
|
||||
)
|
||||
}
|
||||
}
|
||||
STAGE_TYPE_RESULT -> {
|
||||
@@ -256,27 +279,37 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
|
||||
fun performRecognize(url: String): Single<String> {
|
||||
return credentialsObservable.flatMap { token ->
|
||||
httpClient.newCall(Request.Builder()
|
||||
httpClient.newCall(
|
||||
Request.Builder()
|
||||
.url(url)
|
||||
.build()).asObservableSuccess().map {
|
||||
.build()
|
||||
).asObservableSuccess().map {
|
||||
token to it
|
||||
}
|
||||
}.flatMap { (token, response) ->
|
||||
val audioFile = response.body!!.bytes()
|
||||
|
||||
httpClient.newCall(Request.Builder()
|
||||
.url("https://stream.watsonplatform.net/speech-to-text/api/v1/recognize".toHttpUrlOrNull()!!
|
||||
httpClient.newCall(
|
||||
Request.Builder()
|
||||
.url(
|
||||
"https://stream.watsonplatform.net/speech-to-text/api/v1/recognize".toHttpUrlOrNull()!!
|
||||
.newBuilder()
|
||||
.addQueryParameter("watson-token", token)
|
||||
.build())
|
||||
.post(MultipartBody.Builder()
|
||||
.build()
|
||||
)
|
||||
.post(
|
||||
MultipartBody.Builder()
|
||||
.setType(MultipartBody.FORM)
|
||||
.addFormDataPart("jsonDescription", RECOGNIZE_JSON)
|
||||
.addFormDataPart("audio.mp3",
|
||||
"audio.mp3",
|
||||
RequestBody.create("audio/mp3".toMediaTypeOrNull(), audioFile))
|
||||
.build())
|
||||
.build()).asObservableSuccess()
|
||||
.addFormDataPart(
|
||||
"audio.mp3",
|
||||
"audio.mp3",
|
||||
RequestBody.create("audio/mp3".toMediaTypeOrNull(), audioFile)
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
).asObservableSuccess()
|
||||
}.map { response ->
|
||||
JsonParser.parseString(response.body!!.string())["results"][0]["alternatives"][0]["transcript"].string.trim()
|
||||
}.toSingle()
|
||||
@@ -285,7 +318,8 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
fun doStageCheckbox(loopId: String) {
|
||||
if (loopId != currentLoopId) return
|
||||
|
||||
webview.evaluateJavascript("""
|
||||
webview.evaluateJavascript(
|
||||
"""
|
||||
(function() {
|
||||
$CROSS_WINDOW_SCRIPT_OUTER
|
||||
|
||||
@@ -307,11 +341,14 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
exh.callback("false", '$loopId', $STAGE_CHECKBOX);
|
||||
}
|
||||
})();
|
||||
""".trimIndent().replace("\n", ""), null)
|
||||
""".trimIndent().replace("\n", ""),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
fun getAudioButtonLocation(loopId: String) {
|
||||
webview.evaluateJavascript("""
|
||||
webview.evaluateJavascript(
|
||||
"""
|
||||
(function() {
|
||||
$CROSS_WINDOW_SCRIPT_OUTER
|
||||
|
||||
@@ -339,11 +376,14 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
exh.callback(null, '$loopId', $STAGE_GET_AUDIO_BTN_LOCATION);
|
||||
}
|
||||
})();
|
||||
""".trimIndent().replace("\n", ""), null)
|
||||
""".trimIndent().replace("\n", ""),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
fun doStageDownloadAudio(loopId: String) {
|
||||
webview.evaluateJavascript("""
|
||||
webview.evaluateJavascript(
|
||||
"""
|
||||
(function() {
|
||||
$CROSS_WINDOW_SCRIPT_OUTER
|
||||
|
||||
@@ -364,11 +404,14 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
exh.callback(null, '$loopId', $STAGE_DOWNLOAD_AUDIO);
|
||||
}
|
||||
})();
|
||||
""".trimIndent().replace("\n", ""), null)
|
||||
""".trimIndent().replace("\n", ""),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
fun typeResult(loopId: String, result: String) {
|
||||
webview.evaluateJavascript("""
|
||||
webview.evaluateJavascript(
|
||||
"""
|
||||
(function() {
|
||||
$CROSS_WINDOW_SCRIPT_OUTER
|
||||
|
||||
@@ -392,7 +435,9 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
exh.callback("false", '$loopId', $STAGE_TYPE_RESULT);
|
||||
}
|
||||
})();
|
||||
""".trimIndent().replace("\n", ""), null)
|
||||
""".trimIndent().replace("\n", ""),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
fun beginSolveLoop() {
|
||||
@@ -419,12 +464,16 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
} else {
|
||||
val savedStrictValidationStartTime = strictValidationStartTime
|
||||
if (savedStrictValidationStartTime != null &&
|
||||
System.currentTimeMillis() > savedStrictValidationStartTime) {
|
||||
System.currentTimeMillis() > savedStrictValidationStartTime
|
||||
) {
|
||||
captchaSolveFail()
|
||||
} else {
|
||||
webview.postDelayed({
|
||||
runValidateCaptcha(loopId)
|
||||
}, 250)
|
||||
webview.postDelayed(
|
||||
{
|
||||
runValidateCaptcha(loopId)
|
||||
},
|
||||
250
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,7 +481,8 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
fun runValidateCaptcha(loopId: String) {
|
||||
if (loopId != validateCurrentLoopId) return
|
||||
|
||||
webview.evaluateJavascript("""
|
||||
webview.evaluateJavascript(
|
||||
"""
|
||||
(function() {
|
||||
$CROSS_WINDOW_SCRIPT_OUTER
|
||||
|
||||
@@ -453,7 +503,9 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
exh.validateCaptchaCallback(false, '$loopId');
|
||||
}
|
||||
})();
|
||||
""".trimIndent().replace("\n", ""), null)
|
||||
""".trimIndent().replace("\n", ""),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
fun beginValidateCaptchaLoop() {
|
||||
@@ -502,7 +554,8 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
const val STAGE_DOWNLOAD_AUDIO = 2
|
||||
const val STAGE_TYPE_RESULT = 3
|
||||
|
||||
val CROSS_WINDOW_SCRIPT_OUTER = """
|
||||
val CROSS_WINDOW_SCRIPT_OUTER =
|
||||
"""
|
||||
function cwmExec(element, code, cb) {
|
||||
console.log(">>> [CWM-Outer] Running: " + code);
|
||||
let runId = Math.random();
|
||||
@@ -523,9 +576,10 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
let runRequest = { id: runId, code: code };
|
||||
element.contentWindow.postMessage("exh-" + JSON.stringify(runRequest), "*");
|
||||
}
|
||||
""".trimIndent().replace("\n", "")
|
||||
""".trimIndent().replace("\n", "")
|
||||
|
||||
val CROSS_WINDOW_SCRIPT_INNER = """
|
||||
val CROSS_WINDOW_SCRIPT_INNER =
|
||||
"""
|
||||
window.addEventListener('message', function(event) {
|
||||
if(typeof event.data === "string" && event.data.startsWith("exh-")) {
|
||||
let request = JSON.parse(event.data.substring(4));
|
||||
@@ -538,9 +592,10 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
}, false);
|
||||
console.log(">>> [CWM-Inner] Loaded!");
|
||||
alert("exh-");
|
||||
""".trimIndent()
|
||||
""".trimIndent()
|
||||
|
||||
val SOLVE_UI_SCRIPT_SHOW = """
|
||||
val SOLVE_UI_SCRIPT_SHOW =
|
||||
"""
|
||||
(function() {
|
||||
let exh_overlay = document.createElement("div");
|
||||
exh_overlay.id = "exh_overlay";
|
||||
@@ -568,18 +623,20 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
exh_otext.textContent = "Solving captcha..."
|
||||
document.body.appendChild(exh_otext);
|
||||
})();
|
||||
""".trimIndent()
|
||||
""".trimIndent()
|
||||
|
||||
val SOLVE_UI_SCRIPT_HIDE = """
|
||||
val SOLVE_UI_SCRIPT_HIDE =
|
||||
"""
|
||||
(function() {
|
||||
let exh_overlay = document.getElementById("exh_overlay");
|
||||
let exh_otext = document.getElementById("exh_otext");
|
||||
if(exh_overlay != null) exh_overlay.remove();
|
||||
if(exh_otext != null) exh_otext.remove();
|
||||
})();
|
||||
""".trimIndent()
|
||||
""".trimIndent()
|
||||
|
||||
val RECOGNIZE_JSON = """
|
||||
val RECOGNIZE_JSON =
|
||||
"""
|
||||
{
|
||||
"part_content_type": "audio/mp3",
|
||||
"keywords": [],
|
||||
@@ -596,15 +653,15 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
"customGrammarWords": [],
|
||||
"action": "recognize"
|
||||
}
|
||||
""".trimIndent()
|
||||
""".trimIndent()
|
||||
|
||||
val TRANSCRIPT_CLEANER_REGEX = Regex("[^0-9a-zA-Z_ -]")
|
||||
val SPACE_DEDUPE_REGEX = Regex(" +")
|
||||
|
||||
private fun baseIntent(context: Context) =
|
||||
Intent(context, BrowserActionActivity::class.java).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
Intent(context, BrowserActionActivity::class.java).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
fun launchCaptcha(
|
||||
context: Context,
|
||||
@@ -689,8 +746,9 @@ class BrowserActionActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
class NoopActionCompletionVerifier(private val source: HttpSource) : DelegatedHttpSource(source),
|
||||
ActionCompletionVerifier {
|
||||
class NoopActionCompletionVerifier(private val source: HttpSource) :
|
||||
DelegatedHttpSource(source),
|
||||
ActionCompletionVerifier {
|
||||
override val versionId get() = source.versionId
|
||||
override val lang: String get() = source.lang
|
||||
|
||||
|
||||
@@ -37,43 +37,43 @@ open class HeadersInjectingWebViewClient(
|
||||
|
||||
companion object {
|
||||
private val FALLBACK_REASON_PHRASES = mapOf(
|
||||
100 to "Continue",
|
||||
101 to "Switching Protocols",
|
||||
200 to "OK",
|
||||
201 to "Created",
|
||||
202 to "Accepted",
|
||||
203 to "Non-Authoritative Information",
|
||||
204 to "No Content",
|
||||
205 to "Reset Content",
|
||||
206 to "Partial Content",
|
||||
300 to "Multiple Choices",
|
||||
301 to "Moved Permanently",
|
||||
302 to "Moved Temporarily",
|
||||
303 to "See Other",
|
||||
304 to "Not Modified",
|
||||
305 to "Use Proxy",
|
||||
400 to "Bad Request",
|
||||
401 to "Unauthorized",
|
||||
402 to "Payment Required",
|
||||
403 to "Forbidden",
|
||||
404 to "Not Found",
|
||||
405 to "Method Not Allowed",
|
||||
406 to "Not Acceptable",
|
||||
407 to "Proxy Authentication Required",
|
||||
408 to "Request Time-out",
|
||||
409 to "Conflict",
|
||||
410 to "Gone",
|
||||
411 to "Length Required",
|
||||
412 to "Precondition Failed",
|
||||
413 to "Request Entity Too Large",
|
||||
414 to "Request-URI Too Large",
|
||||
415 to "Unsupported Media Type",
|
||||
500 to "Internal Server Error",
|
||||
501 to "Not Implemented",
|
||||
502 to "Bad Gateway",
|
||||
503 to "Service Unavailable",
|
||||
504 to "Gateway Time-out",
|
||||
505 to "HTTP Version not supported"
|
||||
100 to "Continue",
|
||||
101 to "Switching Protocols",
|
||||
200 to "OK",
|
||||
201 to "Created",
|
||||
202 to "Accepted",
|
||||
203 to "Non-Authoritative Information",
|
||||
204 to "No Content",
|
||||
205 to "Reset Content",
|
||||
206 to "Partial Content",
|
||||
300 to "Multiple Choices",
|
||||
301 to "Moved Permanently",
|
||||
302 to "Moved Temporarily",
|
||||
303 to "See Other",
|
||||
304 to "Not Modified",
|
||||
305 to "Use Proxy",
|
||||
400 to "Bad Request",
|
||||
401 to "Unauthorized",
|
||||
402 to "Payment Required",
|
||||
403 to "Forbidden",
|
||||
404 to "Not Found",
|
||||
405 to "Method Not Allowed",
|
||||
406 to "Not Acceptable",
|
||||
407 to "Proxy Authentication Required",
|
||||
408 to "Request Time-out",
|
||||
409 to "Conflict",
|
||||
410 to "Gone",
|
||||
411 to "Length Required",
|
||||
412 to "Precondition Failed",
|
||||
413 to "Request Entity Too Large",
|
||||
414 to "Request-URI Too Large",
|
||||
415 to "Unsupported Media Type",
|
||||
500 to "Internal Server Error",
|
||||
501 to "Not Implemented",
|
||||
502 to "Bad Gateway",
|
||||
503 to "Service Unavailable",
|
||||
504 to "Gateway Time-out",
|
||||
505 to "HTTP Version not supported"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import okhttp3.Request
|
||||
|
||||
fun WebResourceRequest.toOkHttpRequest(): Request {
|
||||
val request = Request.Builder()
|
||||
.url(url.toString())
|
||||
.method(method, null)
|
||||
.url(url.toString())
|
||||
.method(method, null)
|
||||
|
||||
requestHeaders.entries.forEach { (t, u) ->
|
||||
request.addHeader(t, u)
|
||||
|
||||
@@ -54,33 +54,35 @@ class InterceptActivity : BaseRxActivity<EhActivityInterceptBinding, InterceptAc
|
||||
super.onStart()
|
||||
statusSubscription?.unsubscribe()
|
||||
statusSubscription = presenter.status
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
when (it) {
|
||||
is InterceptResult.Success -> {
|
||||
binding.interceptProgress.gone()
|
||||
binding.interceptStatus.text = "Launching app..."
|
||||
onBackPressed()
|
||||
startActivity(Intent(this, MainActivity::class.java)
|
||||
.setAction(MainActivity.SHORTCUT_MANGA)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
.putExtra(MangaController.MANGA_EXTRA, it.mangaId))
|
||||
}
|
||||
is InterceptResult.Failure -> {
|
||||
binding.interceptProgress.gone()
|
||||
binding.interceptStatus.text = "Error: ${it.reason}"
|
||||
MaterialDialog(this)
|
||||
.title(text = "Error")
|
||||
.message(text = "Could not open this gallery:\n\n${it.reason}")
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.onCancel { onBackPressed() }
|
||||
.onDismiss { onBackPressed() }
|
||||
.show()
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
when (it) {
|
||||
is InterceptResult.Success -> {
|
||||
binding.interceptProgress.gone()
|
||||
binding.interceptStatus.text = "Launching app..."
|
||||
onBackPressed()
|
||||
startActivity(
|
||||
Intent(this, MainActivity::class.java)
|
||||
.setAction(MainActivity.SHORTCUT_MANGA)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
.putExtra(MangaController.MANGA_EXTRA, it.mangaId)
|
||||
)
|
||||
}
|
||||
is InterceptResult.Failure -> {
|
||||
binding.interceptProgress.gone()
|
||||
binding.interceptStatus.text = "Error: ${it.reason}"
|
||||
MaterialDialog(this)
|
||||
.title(text = "Error")
|
||||
.message(text = "Could not open this gallery:\n\n${it.reason}")
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.onCancel { onBackPressed() }
|
||||
.onDismiss { onBackPressed() }
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
|
||||
@@ -21,12 +21,14 @@ class InterceptActivityPresenter : BasePresenter<InterceptActivity>() {
|
||||
thread {
|
||||
val result = galleryAdder.addGallery(gallery)
|
||||
|
||||
status.onNext(when (result) {
|
||||
is GalleryAddEvent.Success -> result.manga.id?.let {
|
||||
InterceptResult.Success(it)
|
||||
} ?: InterceptResult.Failure("Manga ID is null!")
|
||||
is GalleryAddEvent.Fail -> InterceptResult.Failure(result.logMessage)
|
||||
})
|
||||
status.onNext(
|
||||
when (result) {
|
||||
is GalleryAddEvent.Success -> result.manga.id?.let {
|
||||
InterceptResult.Success(it)
|
||||
} ?: InterceptResult.Failure("Manga ID is null!")
|
||||
is GalleryAddEvent.Fail -> InterceptResult.Failure(result.logMessage)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,18 +25,18 @@ import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
SwitchPreferenceCompat(context, attrs) {
|
||||
SwitchPreferenceCompat(context, attrs) {
|
||||
|
||||
val prefs: PreferencesHelper by injectLazy()
|
||||
|
||||
val fingerprintSupported
|
||||
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||
Reprint.isHardwarePresent() &&
|
||||
Reprint.hasFingerprintRegistered()
|
||||
Reprint.isHardwarePresent() &&
|
||||
Reprint.hasFingerprintRegistered()
|
||||
|
||||
val useFingerprint
|
||||
get() = fingerprintSupported &&
|
||||
prefs.eh_lockUseFingerprint().getOrDefault()
|
||||
prefs.eh_lockUseFingerprint().getOrDefault()
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
override fun onAttached() {
|
||||
@@ -44,29 +44,32 @@ class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: At
|
||||
if (fingerprintSupported) {
|
||||
updateSummary()
|
||||
onChange {
|
||||
if (it as Boolean)
|
||||
if (it as Boolean) {
|
||||
tryChange()
|
||||
else
|
||||
} else {
|
||||
prefs.eh_lockUseFingerprint().set(false)
|
||||
}
|
||||
!it
|
||||
}
|
||||
} else {
|
||||
title = "Fingerprint unsupported"
|
||||
shouldDisableView = true
|
||||
summary = if (!Reprint.hasFingerprintRegistered())
|
||||
summary = if (!Reprint.hasFingerprintRegistered()) {
|
||||
"No fingerprints enrolled!"
|
||||
else
|
||||
} else {
|
||||
"Fingerprint unlock is unsupported on this device!"
|
||||
}
|
||||
onChange { false }
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSummary() {
|
||||
isChecked = useFingerprint
|
||||
title = if (isChecked)
|
||||
title = if (isChecked) {
|
||||
"Fingerprint enabled"
|
||||
else
|
||||
} else {
|
||||
"Fingerprint disabled"
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
@@ -74,9 +77,11 @@ class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: At
|
||||
val statusTextView = TextView(context).apply {
|
||||
text = "Please touch the fingerprint sensor"
|
||||
val size = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
layoutParams = (layoutParams ?: ViewGroup.LayoutParams(
|
||||
layoutParams = (
|
||||
layoutParams ?: ViewGroup.LayoutParams(
|
||||
size, size
|
||||
)).apply {
|
||||
)
|
||||
).apply {
|
||||
width = size
|
||||
height = size
|
||||
setPadding(0, 0, dpToPx(context, 8), 0)
|
||||
@@ -84,9 +89,11 @@ class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: At
|
||||
}
|
||||
val iconView = SwirlView(context).apply {
|
||||
val size = dpToPx(context, 30)
|
||||
layoutParams = (layoutParams ?: ViewGroup.LayoutParams(
|
||||
layoutParams = (
|
||||
layoutParams ?: ViewGroup.LayoutParams(
|
||||
size, size
|
||||
)).apply {
|
||||
)
|
||||
).apply {
|
||||
width = size
|
||||
height = size
|
||||
}
|
||||
@@ -96,9 +103,11 @@ class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: At
|
||||
orientation = LinearLayoutCompat.HORIZONTAL
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
val size = LinearLayoutCompat.LayoutParams.WRAP_CONTENT
|
||||
layoutParams = (layoutParams ?: LinearLayoutCompat.LayoutParams(
|
||||
layoutParams = (
|
||||
layoutParams ?: LinearLayoutCompat.LayoutParams(
|
||||
size, size
|
||||
)).apply {
|
||||
)
|
||||
).apply {
|
||||
width = size
|
||||
height = size
|
||||
val pSize = dpToPx(context, 24)
|
||||
@@ -109,39 +118,39 @@ class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: At
|
||||
addView(iconView)
|
||||
}
|
||||
val dialog = MaterialDialog(context)
|
||||
.title(text = "Fingerprint verification")
|
||||
.customView(view = linearLayout)
|
||||
.negativeButton(R.string.action_cancel)
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.title(text = "Fingerprint verification")
|
||||
.customView(view = linearLayout)
|
||||
.negativeButton(R.string.action_cancel)
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
dialog.show()
|
||||
iconView.setState(SwirlView.State.ON)
|
||||
val subscription = RxReprint.authenticate()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { result ->
|
||||
when (result.status) {
|
||||
AuthenticationResult.Status.SUCCESS -> {
|
||||
iconView.setState(SwirlView.State.ON)
|
||||
prefs.eh_lockUseFingerprint().set(true)
|
||||
dialog.dismiss()
|
||||
updateSummary()
|
||||
}
|
||||
AuthenticationResult.Status.NONFATAL_FAILURE -> {
|
||||
iconView.setState(SwirlView.State.ERROR)
|
||||
statusTextView.text = result.errorMessage
|
||||
}
|
||||
AuthenticationResult.Status.FATAL_FAILURE, null -> {
|
||||
MaterialDialog(context)
|
||||
.title(text = "Fingerprint verification failed!")
|
||||
.message(text = result.errorMessage)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(false)
|
||||
.show()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { result ->
|
||||
when (result.status) {
|
||||
AuthenticationResult.Status.SUCCESS -> {
|
||||
iconView.setState(SwirlView.State.ON)
|
||||
prefs.eh_lockUseFingerprint().set(true)
|
||||
dialog.dismiss()
|
||||
updateSummary()
|
||||
}
|
||||
AuthenticationResult.Status.NONFATAL_FAILURE -> {
|
||||
iconView.setState(SwirlView.State.ERROR)
|
||||
statusTextView.text = result.errorMessage
|
||||
}
|
||||
AuthenticationResult.Status.FATAL_FAILURE, null -> {
|
||||
MaterialDialog(context)
|
||||
.title(text = "Fingerprint verification failed!")
|
||||
.message(text = result.errorMessage)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(false)
|
||||
.show()
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
dialog.setOnDismissListener {
|
||||
subscription.unsubscribe()
|
||||
}
|
||||
|
||||
@@ -20,19 +20,21 @@ object LockActivityDelegate {
|
||||
private val uiScope = CoroutineScope(Dispatchers.Main)
|
||||
|
||||
fun doLock(router: Router, animate: Boolean = false) {
|
||||
router.pushController(RouterTransaction.with(LockController())
|
||||
.popChangeHandler(LockChangeHandler(animate)))
|
||||
router.pushController(
|
||||
RouterTransaction.with(LockController())
|
||||
.popChangeHandler(LockChangeHandler(animate))
|
||||
)
|
||||
}
|
||||
|
||||
fun onCreate(activity: FragmentActivity) {
|
||||
preferences.secureScreen().asFlow()
|
||||
.onEach {
|
||||
if (it) {
|
||||
activity.window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
|
||||
} else {
|
||||
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
}
|
||||
.onEach {
|
||||
if (it) {
|
||||
activity.window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
|
||||
} else {
|
||||
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
}
|
||||
}
|
||||
.launchIn(uiScope)
|
||||
}
|
||||
|
||||
|
||||
@@ -35,5 +35,5 @@ class LockChangeHandler : AnimatorChangeHandler {
|
||||
override fun resetFromView(from: View) {}
|
||||
|
||||
override fun copy(): ControllerChangeHandler =
|
||||
LockChangeHandler(animationDuration, removesFromViewOnPush())
|
||||
LockChangeHandler(animationDuration, removesFromViewOnPush())
|
||||
}
|
||||
|
||||
@@ -53,12 +53,12 @@ class LockController : NucleusController<ActivityLockBinding, LockPresenter>() {
|
||||
closeLock()
|
||||
} else {
|
||||
MaterialDialog(context)
|
||||
.title(text = "PIN code incorrect")
|
||||
.message(text = "The PIN code you entered is incorrect. Please try again.")
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.show()
|
||||
.title(text = "PIN code incorrect")
|
||||
.message(text = "The PIN code you entered is incorrect. Please try again.")
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.show()
|
||||
binding.pinLockView.resetPinLockView()
|
||||
}
|
||||
}
|
||||
@@ -79,9 +79,11 @@ class LockController : NucleusController<ActivityLockBinding, LockPresenter>() {
|
||||
binding.swirlContainer.removeAllViews()
|
||||
val icon = SwirlView(context).apply {
|
||||
val size = dpToPx(context, 60)
|
||||
layoutParams = (layoutParams ?: ViewGroup.LayoutParams(
|
||||
layoutParams = (
|
||||
layoutParams ?: ViewGroup.LayoutParams(
|
||||
size, size
|
||||
)).apply {
|
||||
)
|
||||
).apply {
|
||||
width = size
|
||||
height = size
|
||||
|
||||
@@ -92,29 +94,30 @@ class LockController : NucleusController<ActivityLockBinding, LockPresenter>() {
|
||||
setBackgroundColor(lockColor)
|
||||
val bgColor = resolvColor(android.R.attr.colorBackground)
|
||||
// Disable elevation if lock color is same as background color
|
||||
if (lockColor == bgColor)
|
||||
if (lockColor == bgColor) {
|
||||
this@with.swirl_container.cardElevation = 0f
|
||||
}
|
||||
setState(SwirlView.State.OFF, true)
|
||||
}
|
||||
binding.swirlContainer.addView(icon)
|
||||
icon.setState(SwirlView.State.ON)
|
||||
RxReprint.authenticate()
|
||||
.subscribeUntilDetach {
|
||||
when (it.status) {
|
||||
AuthenticationResult.Status.SUCCESS -> closeLock()
|
||||
AuthenticationResult.Status.NONFATAL_FAILURE -> icon.setState(SwirlView.State.ERROR)
|
||||
AuthenticationResult.Status.FATAL_FAILURE, null -> {
|
||||
MaterialDialog(context)
|
||||
.title(text = "Fingerprint error!")
|
||||
.message(text = it.errorMessage)
|
||||
.cancelable(false)
|
||||
.cancelOnTouchOutside(false)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.show()
|
||||
icon.setState(SwirlView.State.OFF)
|
||||
}
|
||||
.subscribeUntilDetach {
|
||||
when (it.status) {
|
||||
AuthenticationResult.Status.SUCCESS -> closeLock()
|
||||
AuthenticationResult.Status.NONFATAL_FAILURE -> icon.setState(SwirlView.State.ERROR)
|
||||
AuthenticationResult.Status.FATAL_FAILURE, null -> {
|
||||
MaterialDialog(context)
|
||||
.title(text = "Fingerprint error!")
|
||||
.message(text = it.errorMessage)
|
||||
.cancelable(false)
|
||||
.cancelOnTouchOutside(false)
|
||||
.positiveButton(android.R.string.ok)
|
||||
.show()
|
||||
icon.setState(SwirlView.State.OFF)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.swirlContainer.visibility = View.GONE
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class LockPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
SwitchPreferenceCompat(context, attrs) {
|
||||
SwitchPreferenceCompat(context, attrs) {
|
||||
|
||||
private val secureRandom by lazy { SecureRandom() }
|
||||
|
||||
@@ -46,28 +46,28 @@ class LockPreference @JvmOverloads constructor(context: Context, attrs: Attribut
|
||||
fun tryChange() {
|
||||
if (!notifyLockSecurity(context)) {
|
||||
MaterialDialog(context)
|
||||
.title(text = "Lock application")
|
||||
.message(text = "Enter a pin to lock the application. Enter nothing to disable the pin lock.")
|
||||
// .inputRangeRes(0, 10, R.color.material_red_500)
|
||||
// .inputType(InputType.TYPE_CLASS_NUMBER)
|
||||
.input(maxLength = 10, inputType = InputType.TYPE_CLASS_NUMBER, allowEmpty = true) { _, c ->
|
||||
val progressDialog = MaterialDialog(context)
|
||||
.title(text = "Saving password")
|
||||
.cancelable(false)
|
||||
progressDialog.show()
|
||||
Observable.fromCallable {
|
||||
savePassword(c.toString())
|
||||
}.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
progressDialog.dismiss()
|
||||
updateSummary()
|
||||
}
|
||||
}
|
||||
.negativeButton(R.string.action_cancel)
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.show()
|
||||
.title(text = "Lock application")
|
||||
.message(text = "Enter a pin to lock the application. Enter nothing to disable the pin lock.")
|
||||
// .inputRangeRes(0, 10, R.color.material_red_500)
|
||||
// .inputType(InputType.TYPE_CLASS_NUMBER)
|
||||
.input(maxLength = 10, inputType = InputType.TYPE_CLASS_NUMBER, allowEmpty = true) { _, c ->
|
||||
val progressDialog = MaterialDialog(context)
|
||||
.title(text = "Saving password")
|
||||
.cancelable(false)
|
||||
progressDialog.show()
|
||||
Observable.fromCallable {
|
||||
savePassword(c.toString())
|
||||
}.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
progressDialog.dismiss()
|
||||
updateSummary()
|
||||
}
|
||||
}
|
||||
.negativeButton(R.string.action_cancel)
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(true)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class LockPresenter : BasePresenter<LockController>() {
|
||||
|
||||
val useFingerprint
|
||||
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||
Reprint.isHardwarePresent() &&
|
||||
Reprint.hasFingerprintRegistered() &&
|
||||
prefs.eh_lockUseFingerprint().getOrDefault()
|
||||
Reprint.isHardwarePresent() &&
|
||||
Reprint.hasFingerprintRegistered() &&
|
||||
prefs.eh_lockUseFingerprint().getOrDefault()
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ fun sha512(passwordToHash: String, salt: String): String {
|
||||
*/
|
||||
fun lockEnabled(prefs: PreferencesHelper = Injekt.get()) =
|
||||
prefs.eh_lockHash().get() != null &&
|
||||
prefs.eh_lockSalt().get() != null &&
|
||||
prefs.eh_lockLength().getOrDefault() != -1
|
||||
prefs.eh_lockSalt().get() != null &&
|
||||
prefs.eh_lockLength().getOrDefault() != -1
|
||||
|
||||
/**
|
||||
* Check if the lock will function properly
|
||||
@@ -53,30 +53,35 @@ fun notifyLockSecurity(
|
||||
): Boolean {
|
||||
return false
|
||||
if (!prefs.eh_lockManually().getOrDefault() &&
|
||||
!hasAccessToUsageStats(context)) {
|
||||
!hasAccessToUsageStats(context)
|
||||
) {
|
||||
MaterialDialog(context)
|
||||
.title(text = "Permission required")
|
||||
.message(text = "${context.getString(R.string.app_name)} requires the usage stats permission to detect when you leave the app. " +
|
||||
"This is required for the application lock to function properly. " +
|
||||
"Press OK to grant this permission now.")
|
||||
.negativeButton(R.string.action_cancel)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
try {
|
||||
context.startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
XLog.e("Device does not support USAGE_ACCESS_SETTINGS shortcut!")
|
||||
MaterialDialog(context)
|
||||
.title(text = "Grant permission manually")
|
||||
.message(text = "Failed to launch the window used to grant the usage stats permission. " +
|
||||
"You can still grant this permission manually: go to your phone's settings and search for 'usage access'.")
|
||||
.positiveButton(android.R.string.ok) { it.dismiss() }
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(false)
|
||||
.show()
|
||||
}
|
||||
.title(text = "Permission required")
|
||||
.message(
|
||||
text = "${context.getString(R.string.app_name)} requires the usage stats permission to detect when you leave the app. " +
|
||||
"This is required for the application lock to function properly. " +
|
||||
"Press OK to grant this permission now."
|
||||
)
|
||||
.negativeButton(R.string.action_cancel)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
try {
|
||||
context.startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
XLog.e("Device does not support USAGE_ACCESS_SETTINGS shortcut!")
|
||||
MaterialDialog(context)
|
||||
.title(text = "Grant permission manually")
|
||||
.message(
|
||||
text = "Failed to launch the window used to grant the usage stats permission. " +
|
||||
"You can still grant this permission manually: go to your phone's settings and search for 'usage access'."
|
||||
)
|
||||
.positiveButton(android.R.string.ok) { it.dismiss() }
|
||||
.cancelable(true)
|
||||
.cancelOnTouchOutside(false)
|
||||
.show()
|
||||
}
|
||||
.cancelable(false)
|
||||
.show()
|
||||
}
|
||||
.cancelable(false)
|
||||
.show()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
|
||||
@@ -97,10 +97,11 @@ class LoginController : NucleusController<EhActivityLoginBinding, LoginPresenter
|
||||
val parsedUrl = Uri.parse(url)
|
||||
if (parsedUrl.host.equals("forums.e-hentai.org", ignoreCase = true)) {
|
||||
// Hide distracting content
|
||||
if (!parsedUrl.queryParameterNames.contains(PARAM_SKIP_INJECT))
|
||||
if (!parsedUrl.queryParameterNames.contains(PARAM_SKIP_INJECT)) {
|
||||
view.evaluateJavascript(HIDE_JS, null)
|
||||
|
||||
}
|
||||
// Check login result
|
||||
|
||||
if (parsedUrl.getQueryParameter("code")?.toInt() != 0) {
|
||||
if (checkLoginCookies(url)) view.loadUrl("https://exhentai.org/")
|
||||
}
|
||||
@@ -128,9 +129,11 @@ class LoginController : NucleusController<EhActivityLoginBinding, LoginPresenter
|
||||
fun checkLoginCookies(url: String): Boolean {
|
||||
getCookies(url)?.let { parsed ->
|
||||
return parsed.filter {
|
||||
(it.name.equals(MEMBER_ID_COOKIE, ignoreCase = true) ||
|
||||
it.name.equals(PASS_HASH_COOKIE, ignoreCase = true)) &&
|
||||
it.value.isNotBlank()
|
||||
(
|
||||
it.name.equals(MEMBER_ID_COOKIE, ignoreCase = true) ||
|
||||
it.name.equals(PASS_HASH_COOKIE, ignoreCase = true)
|
||||
) &&
|
||||
it.value.isNotBlank()
|
||||
}.count() >= 2
|
||||
}
|
||||
return false
|
||||
@@ -168,11 +171,11 @@ class LoginController : NucleusController<EhActivityLoginBinding, LoginPresenter
|
||||
}
|
||||
|
||||
fun getCookies(url: String): List<HttpCookie>? =
|
||||
CookieManager.getInstance().getCookie(url)?.let {
|
||||
it.split("; ").flatMap {
|
||||
HttpCookie.parse(it)
|
||||
CookieManager.getInstance().getCookie(url)?.let {
|
||||
it.split("; ").flatMap {
|
||||
HttpCookie.parse(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val PARAM_SKIP_INJECT = "TEH_SKIP_INJECT"
|
||||
@@ -181,7 +184,8 @@ class LoginController : NucleusController<EhActivityLoginBinding, LoginPresenter
|
||||
const val PASS_HASH_COOKIE = "ipb_pass_hash"
|
||||
const val IGNEOUS_COOKIE = "igneous"
|
||||
|
||||
const val HIDE_JS = """
|
||||
const val HIDE_JS =
|
||||
"""
|
||||
javascript:(function () {
|
||||
document.getElementsByTagName('body')[0].style.visibility = 'hidden';
|
||||
document.getElementsByName('submit')[0].style.visibility = 'visible';
|
||||
|
||||
@@ -16,7 +16,7 @@ import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SmartSearchPresenter(private val source: CatalogueSource?, private val config: SourceController.SmartSearchConfig?) :
|
||||
BasePresenter<SmartSearchController>(), CoroutineScope {
|
||||
BasePresenter<SmartSearchController>(), CoroutineScope {
|
||||
|
||||
override val coroutineContext = Job() + Dispatchers.Main
|
||||
|
||||
|
||||
Reference in New Issue
Block a user