From 5b9922d5094cb948ecb131ac1ca6369b83e5c67b Mon Sep 17 00:00:00 2001 From: Koitharu Date: Thu, 29 Apr 2021 07:24:26 +0300 Subject: [PATCH] Remove unused code --- .../java/org/koitharu/kotatsu/KotatsuApp.kt | 40 +++++++------- .../kotatsu/download/DownloadNotification.kt | 5 +- .../kotatsu/download/DownloadService.kt | 34 +++++++++--- .../favourites/domain/FavouritesRepository.kt | 35 ------------ .../domain/OnFavouritesChangeListener.kt | 9 --- .../koitharu/kotatsu/history/HistoryModule.kt | 2 +- .../history/domain/HistoryRepository.kt | 26 --------- .../history/domain/OnHistoryChangeListener.kt | 6 -- .../main/ui/protect/AppProtectHelper.kt | 13 +---- .../kotatsu/tracker/work/TrackWorker.kt | 3 +- .../org/koitharu/kotatsu/utils/CacheUtils.kt | 3 +- .../kotatsu/utils/PendingIntentCompat.kt | 13 +++++ .../kotatsu/utils/ext/CollectionExt.kt | 16 ------ .../koitharu/kotatsu/utils/ext/CommonExt.kt | 16 ------ .../kotatsu/utils/ext/CoroutineExt.kt | 19 ------- .../org/koitharu/kotatsu/utils/ext/FileExt.kt | 10 +++- .../koitharu/kotatsu/utils/ext/FragmentExt.kt | 2 +- .../org/koitharu/kotatsu/utils/ext/HttpExt.kt | 25 +++++++++ .../koitharu/kotatsu/utils/ext/TextViewExt.kt | 2 +- .../org/koitharu/kotatsu/utils/ext/ViewExt.kt | 55 +------------------ .../koitharu/kotatsu/widget/WidgetUpdater.kt | 26 ++++++--- .../widget/recent/RecentWidgetProvider.kt | 3 +- .../widget/shelf/ShelfWidgetProvider.kt | 3 +- 23 files changed, 126 insertions(+), 240 deletions(-) delete mode 100644 app/src/main/java/org/koitharu/kotatsu/favourites/domain/OnFavouritesChangeListener.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/history/domain/OnHistoryChangeListener.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt diff --git a/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt b/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt index d0d21eb6f..311a9bdb6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt +++ b/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt @@ -15,9 +15,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.AppCrashHandler import org.koitharu.kotatsu.core.ui.uiModule import org.koitharu.kotatsu.details.detailsModule -import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.favouritesModule -import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.history.historyModule import org.koitharu.kotatsu.local.data.PagesCache import org.koitharu.kotatsu.local.domain.LocalMangaRepository @@ -37,29 +35,15 @@ class KotatsuApp : Application() { override fun onCreate() { super.onCreate() if (BuildConfig.DEBUG) { - StrictMode.setThreadPolicy( - StrictMode.ThreadPolicy.Builder() - .detectAll() - .penaltyLog() - .build() - ) - StrictMode.setVmPolicy( - StrictMode.VmPolicy.Builder() - .detectAll() - .setClassInstanceLimit(LocalMangaRepository::class.java, 1) - .setClassInstanceLimit(PagesCache::class.java, 1) - .setClassInstanceLimit(MangaLoaderContext::class.java, 1) - .penaltyLog() - .build() - ) + enableStrictMode() } initKoin() Thread.setDefaultUncaughtExceptionHandler(AppCrashHandler(applicationContext)) AppCompatDelegate.setDefaultNightMode(get().theme) registerActivityLifecycleCallbacks(get()) val widgetUpdater = WidgetUpdater(applicationContext) - FavouritesRepository.subscribe(widgetUpdater) - HistoryRepository.subscribe(widgetUpdater) + widgetUpdater.subscribeToFavourites(get()) + widgetUpdater.subscribeToHistory(get()) } private fun initKoin() { @@ -85,4 +69,22 @@ class KotatsuApp : Application() { ) } } + + private fun enableStrictMode() { + StrictMode.setThreadPolicy( + StrictMode.ThreadPolicy.Builder() + .detectAll() + .penaltyLog() + .build() + ) + StrictMode.setVmPolicy( + StrictMode.VmPolicy.Builder() + .detectAll() + .setClassInstanceLimit(LocalMangaRepository::class.java, 1) + .setClassInstanceLimit(PagesCache::class.java, 1) + .setClassInstanceLimit(MangaLoaderContext::class.java, 1) + .penaltyLog() + .build() + ) + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/download/DownloadNotification.kt b/app/src/main/java/org/koitharu/kotatsu/download/DownloadNotification.kt index fe7d290b8..10868d5e3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/download/DownloadNotification.kt +++ b/app/src/main/java/org/koitharu/kotatsu/download/DownloadNotification.kt @@ -13,6 +13,7 @@ import androidx.core.graphics.drawable.toBitmap import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.details.ui.DetailsActivity +import org.koitharu.kotatsu.utils.PendingIntentCompat import org.koitharu.kotatsu.utils.ext.getDisplayMessage import kotlin.math.roundToInt @@ -63,7 +64,7 @@ class DownloadNotification(private val context: Context) { context, startId, intent, - PendingIntent.FLAG_CANCEL_CURRENT + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) ) } @@ -146,7 +147,7 @@ class DownloadNotification(private val context: Context) { context, manga.hashCode(), DetailsActivity.newIntent(context, manga), - PendingIntent.FLAG_CANCEL_CURRENT + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/download/DownloadService.kt b/app/src/main/java/org/koitharu/kotatsu/download/DownloadService.kt index f2e2b56a7..2cc0ca30d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/download/DownloadService.kt +++ b/app/src/main/java/org/koitharu/kotatsu/download/DownloadService.kt @@ -85,7 +85,7 @@ class DownloadService : BaseService() { wakeLock.acquire(TimeUnit.HOURS.toMillis(1)) notification.fillFrom(manga) notification.setCancelId(startId) - withContext(Dispatchers.Main.immediate) { + withContext(Dispatchers.Main) { startForeground(DownloadNotification.NOTIFICATION_ID, notification()) } val destination = settings.getStorageDir(this@DownloadService) @@ -174,8 +174,8 @@ class DownloadService : BaseService() { withContext(NonCancellable) { jobs.remove(startId) output?.cleanup() - destination.sub("page.tmp").delete() - withContext(Dispatchers.Main.immediate) { + destination.sub(TEMP_PAGE_FILE).deleteAwait() + withContext(Dispatchers.Main) { stopForeground(true) notification.dismiss() stopSelf(startId) @@ -196,13 +196,25 @@ class DownloadService : BaseService() { .cacheControl(CacheUtils.CONTROL_DISABLED) .get() .build() - return retryUntilSuccess(3) { - okHttp.newCall(request).await().use { response -> - val file = destination.sub("page.tmp") - file.outputStream().use { out -> - response.body!!.byteStream().copyTo(out) + val call = okHttp.newCall(request) + var attempts = MAX_DOWNLOAD_ATTEMPTS + val file = destination.sub(TEMP_PAGE_FILE) + while (true) { + try { + val response = call.clone().await() + withContext(Dispatchers.IO) { + file.outputStream().use { out -> + checkNotNull(response.body).byteStream().copyTo(out) + } + } + return file + } catch (e: IOException) { + attempts-- + if (attempts <= 0) { + throw e + } else { + delay(DOWNLOAD_ERROR_DELAY) } - file } } } @@ -218,6 +230,10 @@ class DownloadService : BaseService() { private const val EXTRA_CHAPTERS_IDS = "chapters_ids" private const val EXTRA_CANCEL_ID = "cancel_id" + private const val MAX_DOWNLOAD_ATTEMPTS = 3 + private const val DOWNLOAD_ERROR_DELAY = 500L + private const val TEMP_PAGE_FILE = "page.tmp" + fun start(context: Context, manga: Manga, chaptersIds: Collection? = null) { confirmDataTransfer(context) { val intent = Intent(context, DownloadService::class.java) diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt index c409bc1ac..15cefac92 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt @@ -1,12 +1,9 @@ package org.koitharu.kotatsu.favourites.domain -import androidx.collection.ArraySet import androidx.room.withTransaction -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map -import kotlinx.coroutines.withContext import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.entity.MangaEntity import org.koitharu.kotatsu.core.db.entity.TagEntity @@ -83,18 +80,15 @@ class FavouritesRepository(private val db: MangaDatabase) { categoryId = 0 ) val id = db.favouriteCategoriesDao.insert(entity) - notifyCategoriesChanged() return entity.toFavouriteCategory(id) } suspend fun renameCategory(id: Long, title: String) { db.favouriteCategoriesDao.update(id, title) - notifyCategoriesChanged() } suspend fun removeCategory(id: Long) { db.favouriteCategoriesDao.delete(id) - notifyCategoriesChanged() } suspend fun reorderCategories(orderedIds: List) { @@ -104,7 +98,6 @@ class FavouritesRepository(private val db: MangaDatabase) { dao.update(id, i) } } - notifyCategoriesChanged() } suspend fun addToCategory(manga: Manga, categoryId: Long) { @@ -115,41 +108,13 @@ class FavouritesRepository(private val db: MangaDatabase) { val entity = FavouriteEntity(manga.id, categoryId, System.currentTimeMillis()) db.favouritesDao.insert(entity) } - notifyFavouritesChanged(manga.id) } suspend fun removeFromCategory(manga: Manga, categoryId: Long) { db.favouritesDao.delete(categoryId, manga.id) - notifyFavouritesChanged(manga.id) } suspend fun removeFromFavourites(manga: Manga) { db.favouritesDao.delete(manga.id) - notifyFavouritesChanged(manga.id) - } - - companion object { - - private val listeners = ArraySet() - - fun subscribe(listener: OnFavouritesChangeListener) { - listeners += listener - } - - fun unsubscribe(listener: OnFavouritesChangeListener) { - listeners -= listener - } - - private suspend fun notifyFavouritesChanged(mangaId: Long) { - withContext(Dispatchers.Main) { - listeners.forEach { x -> x.onFavouritesChanged(mangaId) } - } - } - - private suspend fun notifyCategoriesChanged() { - withContext(Dispatchers.Main) { - listeners.forEach { x -> x.onCategoriesChanged() } - } - } } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/domain/OnFavouritesChangeListener.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/domain/OnFavouritesChangeListener.kt deleted file mode 100644 index 1a9c7b2c1..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/domain/OnFavouritesChangeListener.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.koitharu.kotatsu.favourites.domain - -@Deprecated("Use flow") -fun interface OnFavouritesChangeListener { - - fun onFavouritesChanged(mangaId: Long) - - fun onCategoriesChanged() = Unit -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/history/HistoryModule.kt b/app/src/main/java/org/koitharu/kotatsu/history/HistoryModule.kt index 6ae824d2b..6ca026947 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/HistoryModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/HistoryModule.kt @@ -8,6 +8,6 @@ import org.koitharu.kotatsu.history.ui.HistoryListViewModel val historyModule get() = module { - single { HistoryRepository(get()) } + single { HistoryRepository(get(), get()) } viewModel { HistoryListViewModel(get(), get(), get()) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/history/domain/HistoryRepository.kt b/app/src/main/java/org/koitharu/kotatsu/history/domain/HistoryRepository.kt index f582f9f6c..cece71003 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/domain/HistoryRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/domain/HistoryRepository.kt @@ -1,11 +1,8 @@ package org.koitharu.kotatsu.history.domain -import androidx.collection.ArraySet import androidx.room.withTransaction -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import kotlinx.coroutines.withContext import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.entity.MangaEntity import org.koitharu.kotatsu.core.db.entity.TagEntity @@ -64,7 +61,6 @@ class HistoryRepository( ) trackingRepository.upsert(manga) } - notifyHistoryChanged() } suspend fun getOne(manga: Manga): MangaHistory? { @@ -73,12 +69,10 @@ class HistoryRepository( suspend fun clear() { db.historyDao.clear() - notifyHistoryChanged() } suspend fun delete(manga: Manga) { db.historyDao.delete(manga.id) - notifyHistoryChanged() } /** @@ -88,26 +82,6 @@ class HistoryRepository( suspend fun deleteOrSwap(manga: Manga, alternative: Manga?) { if (alternative == null || db.mangaDao.update(MangaEntity.from(alternative)) <= 0) { db.historyDao.delete(manga.id) - notifyHistoryChanged() - } - } - - companion object { - - private val listeners = ArraySet() - - fun subscribe(listener: OnHistoryChangeListener) { - listeners += listener - } - - fun unsubscribe(listener: OnHistoryChangeListener) { - listeners -= listener - } - - private suspend fun notifyHistoryChanged() { - withContext(Dispatchers.Main) { - listeners.forEach { x -> x.onHistoryChanged() } - } } } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/history/domain/OnHistoryChangeListener.kt b/app/src/main/java/org/koitharu/kotatsu/history/domain/OnHistoryChangeListener.kt deleted file mode 100644 index f612318a3..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/history/domain/OnHistoryChangeListener.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.koitharu.kotatsu.history.domain - -fun interface OnHistoryChangeListener { - - fun onHistoryChanged() -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/protect/AppProtectHelper.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/protect/AppProtectHelper.kt index ac0172d03..35f7321a5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/protect/AppProtectHelper.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/protect/AppProtectHelper.kt @@ -9,14 +9,9 @@ import org.koitharu.kotatsu.core.prefs.AppSettings class AppProtectHelper(private val settings: AppSettings) : Application.ActivityLifecycleCallbacks { private var isUnlocked = settings.appPassword.isNullOrEmpty() - private var activityCounter = 0 override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { - if (activity is ProtectActivity) { - return - } - activityCounter++ - if (!isUnlocked) { + if (activity !is ProtectActivity && !isUnlocked) { val sourceIntent = Intent(activity, activity.javaClass) activity.intent?.let { sourceIntent.putExtras(it) @@ -39,11 +34,7 @@ class AppProtectHelper(private val settings: AppSettings) : Application.Activity override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit override fun onActivityDestroyed(activity: Activity) { - if (activity is ProtectActivity) { - return - } - activityCounter-- - if (activityCounter == 0) { + if (activity !is ProtectActivity && activity.isTaskRoot) { restoreLock() } } diff --git a/app/src/main/java/org/koitharu/kotatsu/tracker/work/TrackWorker.kt b/app/src/main/java/org/koitharu/kotatsu/tracker/work/TrackWorker.kt index c8877066e..45941f448 100644 --- a/app/src/main/java/org/koitharu/kotatsu/tracker/work/TrackWorker.kt +++ b/app/src/main/java/org/koitharu/kotatsu/tracker/work/TrackWorker.kt @@ -23,6 +23,7 @@ import org.koitharu.kotatsu.core.model.MangaChapter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.tracker.domain.TrackingRepository +import org.koitharu.kotatsu.utils.PendingIntentCompat import org.koitharu.kotatsu.utils.ext.mangaRepositoryOf import org.koitharu.kotatsu.utils.ext.toBitmapOrNull import org.koitharu.kotatsu.utils.ext.toUriOrNull @@ -174,7 +175,7 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) : setContentIntent( PendingIntent.getActivity( applicationContext, id, - intent, PendingIntent.FLAG_UPDATE_CURRENT + intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) ) setAutoCancel(true) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/CacheUtils.kt b/app/src/main/java/org/koitharu/kotatsu/utils/CacheUtils.kt index 0c8848086..2760b831e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/CacheUtils.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/CacheUtils.kt @@ -7,7 +7,6 @@ import okhttp3.Cache import okhttp3.CacheControl import org.koitharu.kotatsu.utils.ext.computeSize import org.koitharu.kotatsu.utils.ext.sub -import org.koitharu.kotatsu.utils.ext.sumByLong import java.io.File object CacheUtils { @@ -25,7 +24,7 @@ object CacheUtils { @WorkerThread fun computeCacheSize(context: Context, name: String) = getCacheDirs(context) .map { it.sub(name) } - .sumByLong { x -> x.computeSize() } + .sumOf { x -> x.computeSize() } @WorkerThread fun clearCache(context: Context, name: String) = getCacheDirs(context) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt b/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt new file mode 100644 index 000000000..4169a571d --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt @@ -0,0 +1,13 @@ +package org.koitharu.kotatsu.utils + +import android.app.PendingIntent +import android.os.Build + +object PendingIntentCompat { + + val FLAG_IMMUTABLE = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + PendingIntent.FLAG_IMMUTABLE + } else { + 0 + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CollectionExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CollectionExt.kt index 8a2468f7a..0b1f342d1 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CollectionExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CollectionExt.kt @@ -9,22 +9,6 @@ fun MutableCollection.replaceWith(subject: Iterable) { addAll(subject) } -inline fun Array.sumByLong(selector: (T) -> Long): Long { - var sum = 0L - for (element in this) { - sum += selector(element) - } - return sum -} - -inline fun Iterable.sumByLong(selector: (T) -> Long): Long { - var sum = 0L - for (element in this) { - sum += selector(element) - } - return sum -} - fun List.medianOrNull(): T? = when { isEmpty() -> null else -> get((size / 2).coerceIn(indices)) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt index 81188cbcb..abba7dcb5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt @@ -8,22 +8,6 @@ import org.koitharu.kotatsu.core.exceptions.* import java.io.FileNotFoundException import java.net.SocketTimeoutException -suspend inline fun T.retryUntilSuccess(maxAttempts: Int, action: T.() -> R): R { - var attempts = maxAttempts - while (true) { - try { - return this.action() - } catch (e: Exception) { - attempts-- - if (attempts <= 0) { - throw e - } else { - delay(1000) - } - } - } -} - fun Throwable.getDisplayMessage(resources: Resources) = when (this) { is AuthRequiredException -> resources.getString(R.string.auth_required) is CloudFlareProtectedException -> resources.getString(R.string.captcha_required) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt index d9850010a..f98427092 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt @@ -14,25 +14,6 @@ import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException -suspend fun Call.await() = suspendCancellableCoroutine { cont -> - this.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - if (cont.isActive) { - cont.resumeWithException(e) - } - } - - override fun onResponse(call: Call, response: Response) { - if (cont.isActive) { - cont.resume(response) - } - } - }) - cont.invokeOnCancellation { - this.cancel() - } -} - inline fun CoroutineScope.launchAfter( job: Job?, context: CoroutineContext = EmptyCoroutineContext, diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt index 07fd92743..0c2d9b579 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt @@ -5,6 +5,8 @@ import android.net.Uri import android.os.Build import android.os.Environment import android.os.storage.StorageManager +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.koitharu.kotatsu.R import java.io.File import java.util.zip.ZipEntry @@ -19,7 +21,7 @@ fun ZipFile.readText(entry: ZipEntry) = getInputStream(entry).bufferedReader().u it.readText() } -fun File.computeSize(): Long = listFiles()?.sumByLong { x -> +fun File.computeSize(): Long = listFiles()?.sumOf { x -> if (x.isDirectory) { x.computeSize() } else { @@ -49,4 +51,8 @@ fun File.getStorageName(context: Context): String = runCatching { } }.getOrNull() ?: context.getString(R.string.other_storage) -fun Uri.toFileOrNull() = if (scheme == "file") path?.let(::File) else null \ No newline at end of file +fun Uri.toFileOrNull() = if (scheme == "file") path?.let(::File) else null + +suspend fun File.deleteAwait() = withContext(Dispatchers.IO) { + delete() +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt index 1f50a6013..92dab70d6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt @@ -13,7 +13,7 @@ inline fun T.withArgs(size: Int, block: Bundle.() -> Unit): T { } val Fragment.viewLifecycleScope - get() = viewLifecycleOwner.lifecycle.coroutineScope + inline get() = viewLifecycleOwner.lifecycle.coroutineScope @Suppress("NOTHING_TO_INLINE") inline fun Fragment.parcelableArgument(name: String): Lazy { diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/HttpExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/HttpExt.kt index b5b9d829d..8121de6bb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/HttpExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/HttpExt.kt @@ -1,7 +1,32 @@ package org.koitharu.kotatsu.utils.ext +import kotlinx.coroutines.suspendCancellableCoroutine +import okhttp3.Call +import okhttp3.Callback import okhttp3.Response import org.koitharu.kotatsu.core.network.CommonHeaders +import java.io.IOException +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +suspend fun Call.await() = suspendCancellableCoroutine { cont -> + this.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + if (cont.isActive) { + cont.resumeWithException(e) + } + } + + override fun onResponse(call: Call, response: Response) { + if (cont.isActive) { + cont.resume(response) + } + } + }) + cont.invokeOnCancellation { + this.cancel() + } +} val Response.mimeType: String? get() = body?.contentType()?.run { "$type/$subtype" } diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt index cf3ee97bd..77e71daa5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt @@ -7,7 +7,7 @@ import androidx.core.view.isGone var TextView.textAndVisible: CharSequence? inline get() = text?.takeIf { visibility == View.VISIBLE } - set(value) { + inline set(value) { text = value isGone = value.isNullOrEmpty() } diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt index 43ea9b89d..9a0fe450b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt @@ -2,26 +2,20 @@ package org.koitharu.kotatsu.utils.ext import android.app.Activity import android.graphics.Rect -import android.util.Log import android.view.LayoutInflater import android.view.Menu import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager -import android.widget.TextView import androidx.annotation.LayoutRes import androidx.annotation.MenuRes import androidx.appcompat.widget.PopupMenu import androidx.core.view.children -import androidx.core.view.isGone import androidx.core.view.isVisible -import androidx.core.view.postDelayed import androidx.drawerlayout.widget.DrawerLayout import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 -import com.google.android.material.chip.Chip -import com.google.android.material.chip.ChipGroup fun View.hideKeyboard() { val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager @@ -54,13 +48,6 @@ var RecyclerView.firstItem: Int } } -fun View.disableFor(timeInMillis: Long) { - isEnabled = false - postDelayed(timeInMillis) { - isEnabled = true - } -} - inline fun View.showPopupMenu( @MenuRes menuRes: Int, onPrepare: (Menu) -> Unit = {}, @@ -134,7 +121,7 @@ inline fun ViewPager2.doOnPageChanged(crossinline callback: (Int) -> Unit) { } val ViewPager2.recyclerView: RecyclerView? - get() = children.find { it is RecyclerView } as? RecyclerView + inline get() = children.find { it is RecyclerView } as? RecyclerView fun View.resetTransformations() { alpha = 1f @@ -161,49 +148,9 @@ inline fun RecyclerView.doOnCurrentItemChanged(crossinline callback: (Int) -> Un }) } -@Deprecated("Reflection") -fun RecyclerView.callOnScrollListeners() { - try { - val field = RecyclerView::class.java.getDeclaredField("mScrollListeners") - field.isAccessible = true - val listeners = field.get(this) as List<*> - for (x in listeners) { - (x as RecyclerView.OnScrollListener).onScrolled(this, 0, 0) - } - } catch (e: Throwable) { - Log.e(null, "RecyclerView.callOnScrollListeners() failed", e) - } -} - -@Deprecated("Reflection") -fun ViewPager2.callOnPageChaneListeners() { - try { - val field = ViewPager2::class.java.getDeclaredField("mExternalPageChangeCallbacks") - field.isAccessible = true - val compositeCallback = field.get(this) - val field2 = compositeCallback.javaClass.getDeclaredField("mCallbacks") - field2.isAccessible = true - val listeners = field2.get(compositeCallback) as List<*> - val position = currentItem - for (x in listeners) { - (x as ViewPager2.OnPageChangeCallback).onPageSelected(position) - } - } catch (e: Throwable) { - Log.e(null, "ViewPager2.callOnPageChaneListeners() failed", e) - } -} - fun RecyclerView.findCenterViewPosition(): Int { val centerX = width / 2f val centerY = height / 2f val view = findChildViewUnder(centerX, centerY) ?: return RecyclerView.NO_POSITION return getChildAdapterPosition(view) -} - -fun ViewPager2.swapAdapter(newAdapter: RecyclerView.Adapter<*>?) { - val position = currentItem - adapter = newAdapter - if (adapter != null && position != RecyclerView.NO_POSITION) { - setCurrentItem(position, false) - } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/WidgetUpdater.kt b/app/src/main/java/org/koitharu/kotatsu/widget/WidgetUpdater.kt index 319e7a236..793d0d7c3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/widget/WidgetUpdater.kt +++ b/app/src/main/java/org/koitharu/kotatsu/widget/WidgetUpdater.kt @@ -4,20 +4,30 @@ import android.appwidget.AppWidgetManager import android.content.ComponentName import android.content.Context import android.content.Intent -import org.koitharu.kotatsu.favourites.domain.OnFavouritesChangeListener -import org.koitharu.kotatsu.history.domain.OnHistoryChangeListener +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.retry +import org.koitharu.kotatsu.favourites.domain.FavouritesRepository +import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.utils.ext.processLifecycleScope import org.koitharu.kotatsu.widget.recent.RecentWidgetProvider import org.koitharu.kotatsu.widget.shelf.ShelfWidgetProvider -class WidgetUpdater(private val context: Context) : OnFavouritesChangeListener, - OnHistoryChangeListener { +class WidgetUpdater(private val context: Context) { - override fun onFavouritesChanged(mangaId: Long) { - updateWidget(ShelfWidgetProvider::class.java) + fun subscribeToFavourites(repository: FavouritesRepository) { + repository.observeAll() + .onEach { updateWidget(ShelfWidgetProvider::class.java) } + .retry { error -> error !is CancellationException } + .launchIn(processLifecycleScope) } - override fun onHistoryChanged() { - updateWidget(RecentWidgetProvider::class.java) + fun subscribeToHistory(repository: HistoryRepository) { + repository.observeAll() + .onEach { updateWidget(RecentWidgetProvider::class.java) } + .retry { error -> error !is CancellationException } + .launchIn(processLifecycleScope) } private fun updateWidget(cls: Class<*>) { diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt b/app/src/main/java/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt index bd655b274..63a2816ae 100644 --- a/app/src/main/java/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt +++ b/app/src/main/java/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt @@ -9,6 +9,7 @@ import android.net.Uri import android.widget.RemoteViews import org.koitharu.kotatsu.R import org.koitharu.kotatsu.reader.ui.ReaderActivity +import org.koitharu.kotatsu.utils.PendingIntentCompat class RecentWidgetProvider : AppWidgetProvider() { @@ -30,7 +31,7 @@ class RecentWidgetProvider : AppWidgetProvider() { context, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) ) views.setEmptyView(R.id.stackView, R.id.textView_holder) diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt index 7d7f9f62a..334941d51 100644 --- a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt +++ b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt @@ -9,6 +9,7 @@ import android.net.Uri import android.widget.RemoteViews import org.koitharu.kotatsu.R import org.koitharu.kotatsu.reader.ui.ReaderActivity +import org.koitharu.kotatsu.utils.PendingIntentCompat class ShelfWidgetProvider : AppWidgetProvider() { @@ -30,7 +31,7 @@ class ShelfWidgetProvider : AppWidgetProvider() { context, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) ) views.setEmptyView(R.id.gridView, R.id.textView_holder)