Linting Fixes AZ

This commit is contained in:
Jobobby04
2020-05-02 00:46:24 -04:00
parent 03e5c5ca10
commit 7e99a9f789
108 changed files with 2962 additions and 2412 deletions
@@ -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())
}
+26 -23
View File
@@ -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
}
+23 -23
View File
@@ -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()
}
+29 -24
View File
@@ -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