diff --git a/app/src/main/java/org/koitharu/kotatsu/download/ui/service/DownloadService.kt b/app/src/main/java/org/koitharu/kotatsu/download/ui/service/DownloadService.kt index a88562989..05c6df6bd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/download/ui/service/DownloadService.kt +++ b/app/src/main/java/org/koitharu/kotatsu/download/ui/service/DownloadService.kt @@ -44,6 +44,7 @@ class DownloadService : BaseService() { override fun onCreate() { super.onCreate() + isRunning = true notificationSwitcher = ForegroundNotificationSwitcher(this) val wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager) .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "kotatsu:downloading") @@ -81,6 +82,7 @@ class DownloadService : BaseService() { override fun onDestroy() { unregisterReceiver(controlReceiver) binder = null + isRunning = false super.onDestroy() } @@ -162,11 +164,12 @@ class DownloadService : BaseService() { companion object { - const val ACTION_DOWNLOAD_COMPLETE = - "${BuildConfig.APPLICATION_ID}.action.ACTION_DOWNLOAD_COMPLETE" + var isRunning: Boolean = false + private set - private const val ACTION_DOWNLOAD_CANCEL = - "${BuildConfig.APPLICATION_ID}.action.ACTION_DOWNLOAD_CANCEL" + const val ACTION_DOWNLOAD_COMPLETE = "${BuildConfig.APPLICATION_ID}.action.ACTION_DOWNLOAD_COMPLETE" + + private const val ACTION_DOWNLOAD_CANCEL = "${BuildConfig.APPLICATION_ID}.action.ACTION_DOWNLOAD_CANCEL" private const val EXTRA_MANGA = "manga" private const val EXTRA_CHAPTERS_IDS = "chapters_ids" diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/CbzFilter.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/CbzFilter.kt index 106cbaacd..8b8fca986 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/CbzFilter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/CbzFilter.kt @@ -7,6 +7,10 @@ import java.util.* class CbzFilter : FilenameFilter { override fun accept(dir: File, name: String): Boolean { + return isFileSupported(name) + } + + fun isFileSupported(name: String): Boolean { val ext = name.substringAfterLast('.', "").lowercase(Locale.ROOT) return ext == "cbz" || ext == "zip" } diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/TempFileFilter.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/TempFileFilter.kt new file mode 100644 index 000000000..8aef4fead --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/TempFileFilter.kt @@ -0,0 +1,11 @@ +package org.koitharu.kotatsu.local.data + +import java.io.File +import java.io.FilenameFilter + +class TempFileFilter : FilenameFilter { + + override fun accept(dir: File, name: String): Boolean { + return name.endsWith(".tmp", ignoreCase = true) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt index 06b5757bf..43860e451 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/domain/LocalMangaRepository.kt @@ -7,18 +7,13 @@ import androidx.annotation.WorkerThread import androidx.collection.ArraySet import androidx.core.net.toFile import androidx.core.net.toUri -import java.io.File -import java.io.IOException -import java.util.* -import java.util.zip.ZipEntry -import java.util.zip.ZipFile -import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.* import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.local.data.CbzFilter import org.koitharu.kotatsu.local.data.LocalStorageManager import org.koitharu.kotatsu.local.data.MangaIndex +import org.koitharu.kotatsu.local.data.TempFileFilter import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.longHashCode import org.koitharu.kotatsu.parsers.util.toCamelCase @@ -26,6 +21,12 @@ import org.koitharu.kotatsu.utils.AlphanumComparator import org.koitharu.kotatsu.utils.ext.deleteAwait import org.koitharu.kotatsu.utils.ext.readText import org.koitharu.kotatsu.utils.ext.resolveName +import java.io.File +import java.io.IOException +import java.util.* +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import kotlin.coroutines.CoroutineContext private const val MAX_PARALLELISM = 4 @@ -245,7 +246,7 @@ class LocalMangaRepository(private val storageManager: LocalStorageManager) : Ma withContext(Dispatchers.IO) { val name = contentResolver.resolveName(uri) ?: throw IOException("Cannot fetch name from uri: $uri") - if (!isFileSupported(name)) { + if (!filenameFilter.isFileSupported(name)) { throw UnsupportedFileException("Unsupported file on $uri") } val dest = File( @@ -262,15 +263,21 @@ class LocalMangaRepository(private val storageManager: LocalStorageManager) : Ma } } - fun isFileSupported(name: String): Boolean { - val ext = name.substringAfterLast('.').lowercase(Locale.ROOT) - return ext == "cbz" || ext == "zip" - } - suspend fun getOutputDir(): File? { return storageManager.getDefaultWriteableDir() } + suspend fun cleanup() { + val dirs = storageManager.getWriteableDirs() + runInterruptible(Dispatchers.IO) { + dirs.flatMap { dir -> + dir.listFiles(TempFileFilter())?.toList().orEmpty() + }.forEach { file -> + file.delete() + } + } + } + private suspend fun getAllFiles() = storageManager.getReadableDirs().flatMap { dir -> dir.listFiles(filenameFilter)?.toList().orEmpty() } diff --git a/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt index f4568b23f..07dea24b5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt @@ -3,16 +3,18 @@ package org.koitharu.kotatsu.local.ui import android.net.Uri import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import java.io.IOException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.os.ShortcutsRepository import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.download.ui.service.DownloadService import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.* @@ -21,6 +23,7 @@ import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.utils.SingleLiveEvent import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct import org.koitharu.kotatsu.utils.progress.Progress +import java.io.IOException class LocalListViewModel( private val repository: LocalMangaRepository, @@ -64,6 +67,7 @@ class LocalListViewModel( init { onRefresh() + cleanup() } override fun onRefresh() { @@ -116,4 +120,18 @@ class LocalListViewModel( listError.value = e } } + + private fun cleanup() { + if (!DownloadService.isRunning) { + viewModelScope.launch { + runCatching { + repository.cleanup() + }.onFailure { error -> + if (BuildConfig.DEBUG) { + error.printStackTrace() + } + } + } + } + } } \ No newline at end of file