diff --git a/.idea/dictionaries/admin.xml b/.idea/dictionaries/admin.xml index 07b4b61db..143df12e7 100644 --- a/.idea/dictionaries/admin.xml +++ b/.idea/dictionaries/admin.xml @@ -3,6 +3,7 @@ chucker desu + failsafe koin kotatsu manga diff --git a/app/build.gradle b/app/build.gradle index a5a1c8035..9606fe6d9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,6 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6' implementation 'androidx.core:core-ktx:1.5.0-alpha01' - implementation 'androidx.appcompat:appcompat:1.3.0-alpha01' implementation 'androidx.activity:activity-ktx:1.2.0-alpha06' implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha06' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-alpha05' diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/LocalMangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/LocalMangaRepository.kt index c9eb5190c..725119563 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/LocalMangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/LocalMangaRepository.kt @@ -72,7 +72,6 @@ class LocalMangaRepository : MangaRepository, KoinComponent { } } - fun delete(manga: Manga): Boolean { val file = Uri.parse(manga.url).toFile() return file.delete() diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/MangaProviderFactory.kt b/app/src/main/java/org/koitharu/kotatsu/domain/MangaProviderFactory.kt index d2dc795ab..5cc4a3000 100644 --- a/app/src/main/java/org/koitharu/kotatsu/domain/MangaProviderFactory.kt +++ b/app/src/main/java/org/koitharu/kotatsu/domain/MangaProviderFactory.kt @@ -13,7 +13,8 @@ import java.util.* object MangaProviderFactory : KoinComponent { private val loaderContext by inject() - private val cache = EnumMap>(MangaSource::class.java) + private val cache = + EnumMap>(MangaSource::class.java) fun getSources(includeHidden: Boolean): List { val settings = get() @@ -33,24 +34,37 @@ object MangaProviderFactory : KoinComponent { } } - fun createLocal(): LocalMangaRepository = - (cache[MangaSource.LOCAL]?.get() as? LocalMangaRepository) - ?: LocalMangaRepository().also { - cache[MangaSource.LOCAL] = WeakReference(it) + fun createLocal(): LocalMangaRepository { + var instance = cache[MangaSource.LOCAL]?.get() + if (instance == null) { + synchronized(cache) { + instance = cache[MangaSource.LOCAL]?.get() + if (instance == null) { + instance = LocalMangaRepository() + cache[MangaSource.LOCAL] = WeakReference(instance) + } } + } + return instance as LocalMangaRepository + } @Throws(Throwable::class) fun create(source: MangaSource): MangaRepository { - cache[source]?.get()?.let { - return it + var instance = cache[source]?.get() + if (instance == null) { + synchronized(cache) { + instance = cache[source]?.get() + if (instance == null) { + instance = try { + source.cls.getDeclaredConstructor(MangaLoaderContext::class.java) + .newInstance(loaderContext) + } catch (e: NoSuchMethodException) { + source.cls.newInstance() + } + cache[source] = WeakReference(instance!!) + } + } } - val instance = try { - source.cls.getDeclaredConstructor(MangaLoaderContext::class.java) - .newInstance(loaderContext) - } catch (e: NoSuchMethodException) { - source.cls.newInstance() - } - cache[source] = WeakReference(instance) - return instance + return instance!! } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/download/DownloadNotification.kt b/app/src/main/java/org/koitharu/kotatsu/ui/download/DownloadNotification.kt index 2ec22af54..cc7f37049 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/download/DownloadNotification.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/download/DownloadNotification.kt @@ -92,6 +92,11 @@ class DownloadNotification(private val context: Context) { builder.setCategory(NotificationCompat.CATEGORY_PROGRESS) } + fun setWaitingForNetwork() { + builder.setProgress(0, 0, false) + builder.setContentText(context.getString(R.string.waiting_for_network)) + } + fun setPostProcessing() { builder.setProgress(1, 0, true) builder.setContentText(context.getString(R.string.processing_)) diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/download/DownloadService.kt b/app/src/main/java/org/koitharu/kotatsu/ui/download/DownloadService.kt index 9d9ccb9e8..033d603b4 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/download/DownloadService.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/download/DownloadService.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.* import kotlinx.coroutines.sync.Mutex import okhttp3.OkHttpClient import okhttp3.Request +import okio.IOException import org.koin.android.ext.android.inject import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.R @@ -24,10 +25,7 @@ import org.koitharu.kotatsu.domain.local.MangaZip import org.koitharu.kotatsu.ui.common.BaseService import org.koitharu.kotatsu.ui.common.dialog.CheckBoxAlertDialog import org.koitharu.kotatsu.utils.CacheUtils -import org.koitharu.kotatsu.utils.ext.await -import org.koitharu.kotatsu.utils.ext.retryUntilSuccess -import org.koitharu.kotatsu.utils.ext.safe -import org.koitharu.kotatsu.utils.ext.sub +import org.koitharu.kotatsu.utils.ext.* import java.io.File import java.util.concurrent.TimeUnit import kotlin.collections.set @@ -37,6 +35,7 @@ class DownloadService : BaseService() { private lateinit var notification: DownloadNotification private lateinit var wakeLock: PowerManager.WakeLock + private lateinit var connectivityManager: ConnectivityManager private val okHttp by inject() private val cache by inject() @@ -47,6 +46,7 @@ class DownloadService : BaseService() { override fun onCreate() { super.onCreate() notification = DownloadNotification(this) + connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager) .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "kotatsu:downloading") } @@ -88,9 +88,11 @@ class DownloadService : BaseService() { try { val repo = MangaProviderFactory.create(manga.source) val cover = safe { - Coil.execute(GetRequestBuilder(this@DownloadService) - .data(manga.coverUrl) - .build()).drawable + Coil.execute( + GetRequestBuilder(this@DownloadService) + .data(manga.coverUrl) + .build() + ).drawable } withContext(Dispatchers.Main) { notification.setLargeIcon(cover) @@ -112,23 +114,30 @@ class DownloadService : BaseService() { if (chaptersIds == null || chapter.id in chaptersIds) { val pages = repo.getPages(chapter) for ((pageIndex, page) in pages.withIndex()) { - val url = repo.getPageFullUrl(page) - val file = cache[url] ?: downloadPage(url, destination) - output.addPage( - chapter, - file, - pageIndex, - MimeTypeMap.getFileExtensionFromUrl(url) + failsafe@ do { + try { + val url = repo.getPageFullUrl(page) + val file = cache[url] ?: downloadPage(url, destination) + output.addPage( + chapter, + file, + pageIndex, + MimeTypeMap.getFileExtensionFromUrl(url) + ) + } catch (e: IOException) { + notification.setWaitingForNetwork() + notification.update() + connectivityManager.waitForNetwork() + continue@failsafe + } + } while (false) + notification.setProgress( + chapters.size, + pages.size, + chapterIndex, + pageIndex ) - withContext(Dispatchers.Main) { - notification.setProgress( - chapters.size, - pages.size, - chapterIndex, - pageIndex - ) - notification.update() - } + notification.update() } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/list/local/LocalListPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/list/local/LocalListPresenter.kt index 53cbe4123..62a387803 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/list/local/LocalListPresenter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/list/local/LocalListPresenter.kt @@ -13,7 +13,6 @@ import org.koin.core.get import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException import org.koitharu.kotatsu.core.model.Manga -import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.parser.LocalMangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.domain.MangaProviderFactory @@ -33,7 +32,8 @@ class LocalListPresenter : BasePresenter>() { private lateinit var repository: LocalMangaRepository override fun onFirstViewAttach() { - repository = MangaProviderFactory.create(MangaSource.LOCAL) as LocalMangaRepository + repository = MangaProviderFactory.createLocal() + super.onFirstViewAttach() } diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt new file mode 100644 index 000000000..b9cc851c4 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt @@ -0,0 +1,22 @@ +package org.koitharu.kotatsu.utils.ext + +import android.net.ConnectivityManager +import android.net.Network +import android.net.NetworkRequest +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.resume + +suspend fun ConnectivityManager.waitForNetwork(): Network { + val request = NetworkRequest.Builder().build() + return suspendCancellableCoroutine { cont -> + val callback = object : ConnectivityManager.NetworkCallback() { + override fun onAvailable(network: Network) { + cont.resume(network) + } + } + registerNetworkCallback(request, callback) + cont.invokeOnCancellation { + unregisterNetworkCallback(callback) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index aa40ca4e2..1306bd976 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -139,4 +139,5 @@ Похожие Новая версия: %s Размер: %s + Ожидание подключения… \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dfb998cf5..215a2316c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -140,4 +140,5 @@ Related New version: %s Size: %s + Waiting for network… \ No newline at end of file