Rewrite ArchivePageLoader with modern kotlin coroutine and flows
This commit is contained in:
1 parent
d9c55a284b
commit
8690f8aa8d
2 files changed
+187
-387
No files matched your search
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 Hippo Seven
|
||||
* Copyright 2023 Tarsin Norbin
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,344 +13,154 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.hippo.ehviewer.gallery
|
||||
|
||||
package com.hippo.ehviewer.gallery;
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.hippo.Native.getFd
|
||||
import com.hippo.UriArchiveAccessor
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.image.Image
|
||||
import com.hippo.unifile.UniFile
|
||||
import com.hippo.yorozuya.FileUtils
|
||||
import eu.kanade.tachiyomi.util.lang.launchNonCancellable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.joinAll
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
class ArchivePageLoader(context: Context, uri: Uri, passwdFlow: Flow<String>) : PageLoader2(),
|
||||
CoroutineScope {
|
||||
override val coroutineContext = Dispatchers.IO + Job()
|
||||
private val archiveAccessor by lazy { UriArchiveAccessor(context, uri) }
|
||||
private val hostJob = launch(start = CoroutineStart.LAZY) {
|
||||
size = archiveAccessor.open()
|
||||
if (size == 0) {
|
||||
return@launch
|
||||
}
|
||||
archiveAccessor.run {
|
||||
if (needPassword()) {
|
||||
Settings.getArchivePasswds()?.forEach {
|
||||
if (providePassword(it)) return@launch
|
||||
}
|
||||
passwdFlow.collect {
|
||||
if (providePassword(it)) {
|
||||
Settings.putPasswdToArchivePasswds(it)
|
||||
currentCoroutineContext().cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
override var size = 0
|
||||
private set
|
||||
|
||||
import com.hippo.Native;
|
||||
import com.hippo.UriArchiveAccessor;
|
||||
import com.hippo.ehviewer.GetText;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.image.Image;
|
||||
import com.hippo.unifile.UniFile;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
import com.hippo.yorozuya.SimpleHandler;
|
||||
import com.hippo.yorozuya.thread.PVLock;
|
||||
import com.hippo.yorozuya.thread.PriorityThread;
|
||||
override fun start() {
|
||||
hostJob.start()
|
||||
}
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
override fun stop() {
|
||||
cancel()
|
||||
launchNonCancellable {
|
||||
mJobMap.values.joinAll()
|
||||
archiveAccessor.close()
|
||||
}
|
||||
super.stop()
|
||||
}
|
||||
|
||||
import kotlin.Pair;
|
||||
import kotlin.coroutines.Continuation;
|
||||
import kotlin.coroutines.intrinsics.CoroutineSingletons;
|
||||
private val mJobMap = hashMapOf<Int, Job>()
|
||||
private val mSemaphore = Semaphore(4)
|
||||
|
||||
public class ArchivePageLoader extends PageLoader2 {
|
||||
private static final AtomicInteger sIdGenerator = new AtomicInteger();
|
||||
public static Handler showPasswd;
|
||||
public static String passwd;
|
||||
public static PVLock pv = new PVLock(0);
|
||||
private final UriArchiveAccessor archiveAccessor;
|
||||
private final Stack<Integer> requests = new Stack<>();
|
||||
private final LinkedHashMap<Integer, Image.CloseableSource> streams = new LinkedHashMap<>();
|
||||
private final Thread[] decodeThread = new Thread[]{
|
||||
new Thread(new DecodeTask()),
|
||||
new Thread(new DecodeTask()),
|
||||
new Thread(new DecodeTask()),
|
||||
new Thread(new DecodeTask())
|
||||
};
|
||||
private Thread archiveThread;
|
||||
private volatile int size = 0;
|
||||
private String error;
|
||||
override fun onRequest(index: Int) {
|
||||
notifyPageWait(index)
|
||||
synchronized(mJobMap) {
|
||||
val current = mJobMap[index]
|
||||
if (current?.isActive != true) {
|
||||
mJobMap[index] = launch {
|
||||
mSemaphore.withPermit {
|
||||
doRealWork(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ArchivePageLoader(Context context, Uri uri) {
|
||||
UriArchiveAccessor archiveAccessor1;
|
||||
private suspend fun doRealWork(index: Int) {
|
||||
val src = archiveAccessor.getImageSource(index) ?: return
|
||||
runCatching {
|
||||
currentCoroutineContext().ensureActive()
|
||||
}.onFailure {
|
||||
src.close()
|
||||
throw it
|
||||
}
|
||||
val image = Image.decode(src) ?: return notifyPageFailed(index, null)
|
||||
runCatching {
|
||||
currentCoroutineContext().ensureActive()
|
||||
}.onFailure {
|
||||
image.recycle()
|
||||
throw it
|
||||
}
|
||||
notifyPageSucceed(index, image)
|
||||
}
|
||||
|
||||
override fun onForceRequest(index: Int) {
|
||||
onRequest(index)
|
||||
}
|
||||
|
||||
override suspend fun awaitReady(): Boolean {
|
||||
hostJob.join()
|
||||
return size != 0
|
||||
}
|
||||
|
||||
override fun onCancelRequest(index: Int) {
|
||||
mJobMap[index]?.cancel()
|
||||
}
|
||||
|
||||
override fun getImageFilename(index: Int): String {
|
||||
return FileUtils.getNameFromFilename(getImageFilenameWithExtension(index))
|
||||
}
|
||||
|
||||
override fun getImageFilenameWithExtension(index: Int): String {
|
||||
return FileUtils.sanitizeFilename(archiveAccessor.getFilename(index))
|
||||
}
|
||||
|
||||
override fun save(index: Int, file: UniFile): Boolean {
|
||||
val fd: Int
|
||||
val stream: FileOutputStream
|
||||
try {
|
||||
archiveAccessor1 = new UriArchiveAccessor(context, uri);
|
||||
} catch (Exception e) {
|
||||
archiveAccessor1 = null;
|
||||
e.printStackTrace();
|
||||
}
|
||||
archiveAccessor = archiveAccessor1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
int id = sIdGenerator.incrementAndGet();
|
||||
|
||||
archiveThread = new PriorityThread(
|
||||
new ArchiveHostTask(), "ArchiveTask" + '-' + id, Process.THREAD_PRIORITY_BACKGROUND);
|
||||
archiveThread.start();
|
||||
for (Thread i : decodeThread) {
|
||||
i.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
super.stop();
|
||||
if (archiveThread != null) {
|
||||
archiveThread.interrupt();
|
||||
archiveThread = null;
|
||||
}
|
||||
for (Thread i : decodeThread) {
|
||||
i.interrupt();
|
||||
stream = file.openOutputStream() as FileOutputStream
|
||||
fd = getFd(stream.fd)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
archiveAccessor.extractToFd(index, fd)
|
||||
try {
|
||||
archiveAccessor.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
stream.close()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return size;
|
||||
override fun save(index: Int, dir: UniFile, filename: String): UniFile {
|
||||
val extension = FileUtils.getExtensionFromFilename(getImageFilenameWithExtension(index))
|
||||
val dst = dir.subFile(if (null != extension) "$filename.$extension" else filename)
|
||||
save(index, dst!!)
|
||||
return dst
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequest(int index) {
|
||||
boolean inDecodeTask;
|
||||
synchronized (streams) {
|
||||
inDecodeTask = streams.containsKey(index);
|
||||
}
|
||||
|
||||
synchronized (requests) {
|
||||
boolean inArchiveTask = requests.contains(index);
|
||||
if (!inArchiveTask && !inDecodeTask) {
|
||||
requests.add(index);
|
||||
requests.notify();
|
||||
}
|
||||
}
|
||||
notifyPageWait(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onForceRequest(int index) {
|
||||
onRequest(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelRequest(int index) {
|
||||
synchronized (requests) {
|
||||
requests.remove(Integer.valueOf(index));
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getImageFilename(int index) {
|
||||
return FileUtils.getNameFromFilename(getImageFilenameWithExtension(index));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getImageFilenameWithExtension(int index) {
|
||||
return FileUtils.sanitizeFilename(archiveAccessor.getFilename(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(int index, @NonNull UniFile file) {
|
||||
int fd;
|
||||
FileOutputStream stream;
|
||||
try {
|
||||
stream = (FileOutputStream) file.openOutputStream();
|
||||
fd = Native.getFd(stream.getFD());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
archiveAccessor.extractToFd(index, fd);
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public UniFile save(int index, @NonNull UniFile dir, @NonNull String filename) {
|
||||
String extension = FileUtils.getExtensionFromFilename(getImageFilenameWithExtension(index));
|
||||
UniFile dst = dir.subFile(null != extension ? filename + "." + extension : filename);
|
||||
save(index, dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preloadPages(@NonNull List<Integer> pages, @NonNull Pair<Integer, Integer> pair) {
|
||||
|
||||
}
|
||||
|
||||
private Continuation<? super Boolean> continuation = null;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object awaitReady(@NonNull Continuation<? super Boolean> $completion) {
|
||||
continuation = $completion;
|
||||
return CoroutineSingletons.COROUTINE_SUSPENDED;
|
||||
}
|
||||
|
||||
private class ArchiveHostTask implements Runnable {
|
||||
public final Thread[] archiveThreads = new Thread[]{
|
||||
new Thread(new ArchiveTask()),
|
||||
new Thread(new ArchiveTask()),
|
||||
new Thread(new ArchiveTask()),
|
||||
new Thread(new ArchiveTask())
|
||||
};
|
||||
|
||||
private void waitPasswd() throws InterruptedException {
|
||||
showPasswd.sendEmptyMessage(0);
|
||||
pv.p();
|
||||
}
|
||||
|
||||
private void notifyError() {
|
||||
showPasswd.sendEmptyMessage(1);
|
||||
}
|
||||
|
||||
private void notifyDismiss() {
|
||||
showPasswd.sendEmptyMessage(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
size = archiveAccessor.open();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
size = 0;
|
||||
}
|
||||
if (size <= 0) {
|
||||
error = GetText.getString(R.string.error_reading_failed);
|
||||
return;
|
||||
}
|
||||
SimpleHandler.getInstance().post(() -> continuation.resumeWith(true));
|
||||
|
||||
|
||||
if (archiveAccessor.needPassword()) {
|
||||
boolean need_request = true;
|
||||
Set<String> set = Settings.getArchivePasswds();
|
||||
if (set != null) {
|
||||
for (String passwd : set) {
|
||||
if (archiveAccessor.providePassword(passwd)) {
|
||||
need_request = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!Thread.currentThread().isInterrupted() && need_request) {
|
||||
try {
|
||||
waitPasswd();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
if (!archiveAccessor.providePassword(passwd))
|
||||
notifyError();
|
||||
else {
|
||||
Settings.putPasswdToArchivePasswds(passwd);
|
||||
notifyDismiss();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Thread i : archiveThreads) {
|
||||
i.start();
|
||||
}
|
||||
|
||||
Object o = new Object();
|
||||
synchronized (o) {
|
||||
try {
|
||||
o.wait();
|
||||
} catch (InterruptedException e) {
|
||||
for (Thread i : archiveThreads) {
|
||||
i.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ArchiveTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
int index;
|
||||
synchronized (requests) {
|
||||
if (requests.isEmpty()) {
|
||||
try {
|
||||
requests.wait();
|
||||
} catch (InterruptedException e) {
|
||||
// Interrupted
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
index = requests.pop();
|
||||
}
|
||||
|
||||
// Check index valid
|
||||
if (index < 0 || index >= size) {
|
||||
notifyPageFailed(index, null);
|
||||
continue;
|
||||
}
|
||||
|
||||
synchronized (streams) {
|
||||
if (streams.get(index) != null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Image.CloseableSource src = archiveAccessor.getImageSource(index);
|
||||
|
||||
synchronized (streams) {
|
||||
streams.put(index, src);
|
||||
streams.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DecodeTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
int index;
|
||||
Image.CloseableSource src;
|
||||
synchronized (streams) {
|
||||
if (streams.isEmpty()) {
|
||||
try {
|
||||
streams.wait();
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator<Map.Entry<Integer, Image.CloseableSource>> iterator = streams.entrySet().iterator();
|
||||
Map.Entry<Integer, Image.CloseableSource> entry = iterator.next();
|
||||
iterator.remove();
|
||||
index = entry.getKey();
|
||||
src = entry.getValue();
|
||||
}
|
||||
|
||||
Image image = null;
|
||||
if (src != null) {
|
||||
image = Image.decode(src);
|
||||
}
|
||||
if (image != null) {
|
||||
notifyPageSucceed(index, image);
|
||||
} else {
|
||||
notifyPageFailed(index, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun preloadPages(pages: List<Int>, pair: Pair<Int, Int>) {}
|
||||
}
|
||||
@@ -33,8 +33,6 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
import android.provider.MediaStore
|
||||
import android.text.TextUtils
|
||||
import android.view.HapticFeedbackConstants
|
||||
@@ -88,6 +86,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.preference.toggle
|
||||
import eu.kanade.tachiyomi.util.system.applySystemAnimatorScale
|
||||
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
||||
@@ -97,16 +96,22 @@ import eu.kanade.tachiyomi.util.view.popupMenu
|
||||
import eu.kanade.tachiyomi.util.view.setTooltip
|
||||
import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.sample
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
|
||||
@@ -161,9 +166,9 @@ class ReaderActivity : EhActivity() {
|
||||
private var mSize: Int = 0
|
||||
private var mCurrentIndex: Int = 0
|
||||
private var mSavingPage = -1
|
||||
private var builder: EditTextDialogBuilder? = null
|
||||
private lateinit var builder: EditTextDialogBuilder
|
||||
private var dialogShown = false
|
||||
private var dialog: AlertDialog? = null
|
||||
private lateinit var dialog: AlertDialog
|
||||
private var requestStoragePermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { result ->
|
||||
@@ -207,8 +212,41 @@ class ReaderActivity : EhActivity() {
|
||||
Toast.makeText(this, R.string.error_reading_failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
mGalleryProvider =
|
||||
ArchivePageLoader(this, mUri)
|
||||
val continuation: AtomicReference<Continuation<String>?> = AtomicReference(null)
|
||||
mGalleryProvider = ArchivePageLoader(this, mUri!!,
|
||||
flow {
|
||||
if (!dialogShown) {
|
||||
withUIContext {
|
||||
dialogShown = true
|
||||
dialog.run {
|
||||
show()
|
||||
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||
val passwd = builder.text
|
||||
if (passwd.isEmpty())
|
||||
builder.setError(getString(R.string.passwd_cannot_be_empty))
|
||||
else {
|
||||
continuation.get()?.resume(passwd)
|
||||
}
|
||||
}
|
||||
setOnCancelListener {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
currentCoroutineContext().ensureActive()
|
||||
val r = suspendCancellableCoroutine {
|
||||
continuation.set(it)
|
||||
it.invokeOnCancellation { dialog.dismiss() }
|
||||
}
|
||||
emit(r)
|
||||
withUIContext {
|
||||
builder.setError(getString(R.string.passwd_wrong))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,15 +296,14 @@ class ReaderActivity : EhActivity() {
|
||||
binding = ReaderActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
builder = EditTextDialogBuilder(this, null, getString(R.string.archive_passwd))
|
||||
builder!!.setTitle(getString(R.string.archive_need_passwd))
|
||||
builder!!.setPositiveButton(getString(android.R.string.ok), null)
|
||||
dialog = builder!!.create()
|
||||
dialog!!.setCanceledOnTouchOutside(false)
|
||||
builder.setTitle(getString(R.string.archive_need_passwd))
|
||||
builder.setPositiveButton(getString(android.R.string.ok), null)
|
||||
dialog = builder.create()
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
if (mGalleryProvider == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
ArchivePageLoader.showPasswd = ShowPasswdDialogHandler(this)
|
||||
|
||||
mGalleryProvider!!.start()
|
||||
|
||||
@@ -279,6 +316,9 @@ class ReaderActivity : EhActivity() {
|
||||
}
|
||||
|
||||
fun setGallery() {
|
||||
// TODO: Not well place to call it
|
||||
dialog.dismiss()
|
||||
|
||||
// Get start page
|
||||
if (mCurrentIndex == 0) mCurrentIndex = if (mPage >= 0) mPage else mGalleryProvider!!.startPage
|
||||
mSize = mGalleryProvider!!.size
|
||||
@@ -520,56 +560,6 @@ class ReaderActivity : EhActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun showPasswdDialog() {
|
||||
if (!dialogShown) {
|
||||
dialogShown = true
|
||||
dialog!!.show()
|
||||
if (dialog!!.getButton(AlertDialog.BUTTON_POSITIVE) != null) {
|
||||
dialog!!.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
.setOnClickListener { this@ReaderActivity.onProvidePasswd() }
|
||||
}
|
||||
dialog!!.setOnCancelListener { finish() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun onProvidePasswd() {
|
||||
val passwd = builder!!.text
|
||||
if (passwd.isEmpty())
|
||||
builder!!.setError(getString(R.string.passwd_cannot_be_empty))
|
||||
else {
|
||||
ArchivePageLoader.passwd = passwd
|
||||
ArchivePageLoader.pv.v()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onPasswdWrong() {
|
||||
builder!!.setError(getString(R.string.passwd_wrong))
|
||||
}
|
||||
|
||||
private fun onPasswdCorrect() {
|
||||
dialog!!.dismiss()
|
||||
}
|
||||
|
||||
private class ShowPasswdDialogHandler(activity: ReaderActivity) : Handler() {
|
||||
private val weakReference: WeakReference<ReaderActivity>
|
||||
|
||||
init {
|
||||
this.weakReference = WeakReference(activity)
|
||||
}
|
||||
|
||||
override fun handleMessage(msg: Message) {
|
||||
val activity = weakReference.get()
|
||||
super.handleMessage(msg)
|
||||
if (null != activity) {
|
||||
when (msg.what) {
|
||||
0 -> activity.showPasswdDialog()
|
||||
1 -> activity.onPasswdWrong()
|
||||
2 -> activity.onPasswdCorrect()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ACTION_EH = "eh"
|
||||
const val KEY_ACTION = "action"
|
||||
|
||||
Reference in new issue
Block a user