From def2d5f49479b205104b86f08d0b24fe48b04027 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 26 Feb 2022 10:14:40 +0200 Subject: [PATCH] Refactor and deprecations fixes --- .../kotatsu/base/domain/MangaIntent.kt | 28 +++++----- .../base/domain/MangaProviderFactory.kt | 24 -------- .../kotatsu/base/domain/MangaUtils.kt | 13 ++--- .../kotatsu/base/ui/AlertDialogFragment.kt | 5 +- .../koitharu/kotatsu/base/ui/BaseActivity.kt | 7 ++- .../kotatsu/base/ui/BaseBottomSheet.kt | 5 +- .../kotatsu/base/ui/BasePreferenceFragment.kt | 6 +- .../kotatsu/core/network/CommonHeaders.kt | 7 ++- .../kotatsu/core/network/NetworkModule.kt | 9 +-- .../core/parser/RemoteMangaRepository.kt | 8 +-- .../kotatsu/core/prefs/AppSettings.kt | 32 +++++++---- .../koitharu/kotatsu/core/prefs/ReaderMode.kt | 2 +- .../kotatsu/details/ui/DetailsActivity.kt | 4 +- .../kotatsu/details/ui/DetailsFragment.kt | 12 ++-- .../download/domain/DownloadManager.kt | 5 +- .../local/data/{Cache.kt => CacheDir.kt} | 4 +- .../kotatsu/local/data/LocalStorageManager.kt | 45 ++++++++++++++- .../koitharu/kotatsu/local/data/PagesCache.kt | 18 ++---- .../koitharu/kotatsu/main/ui/MainViewModel.kt | 5 +- .../kotatsu/reader/domain/PageLoader.kt | 5 +- .../kotatsu/reader/ui/ReaderActivity.kt | 4 +- .../kotatsu/reader/ui/ReaderViewModel.kt | 4 +- .../search/domain/MangaSearchRepository.kt | 5 +- .../kotatsu/settings/AppUpdateChecker.kt | 6 +- .../settings/HistorySettingsFragment.kt | 37 +++++-------- .../kotatsu/settings/MainSettingsFragment.kt | 2 +- .../sources/SourcesSettingsViewModel.kt | 5 +- .../org/koitharu/kotatsu/utils/CacheUtils.kt | 55 ------------------- .../utils/{FileSizeUtils.kt => FileSize.kt} | 21 ++++--- .../kotatsu/utils/PendingIntentCompat.kt | 4 +- .../org/koitharu/kotatsu/utils/anim/Motion.kt | 2 +- .../delegates/ParcelableArgumentDelegate.kt | 14 ----- .../utils/delegates/StringArgumentDelegate.kt | 12 ---- 33 files changed, 168 insertions(+), 247 deletions(-) delete mode 100644 app/src/main/java/org/koitharu/kotatsu/base/domain/MangaProviderFactory.kt rename app/src/main/java/org/koitharu/kotatsu/local/data/{Cache.kt => CacheDir.kt} (66%) delete mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/CacheUtils.kt rename app/src/main/java/org/koitharu/kotatsu/utils/{FileSizeUtils.kt => FileSize.kt} (56%) delete mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/delegates/ParcelableArgumentDelegate.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/delegates/StringArgumentDelegate.kt diff --git a/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaIntent.kt b/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaIntent.kt index f4dc339c9..cfd7d7b4f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaIntent.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaIntent.kt @@ -5,29 +5,29 @@ import android.net.Uri import android.os.Bundle import org.koitharu.kotatsu.core.model.Manga -class MangaIntent( +class MangaIntent private constructor( val manga: Manga?, val mangaId: Long, - val uri: Uri? + val uri: Uri?, ) { - companion object { + constructor(intent: Intent?) : this( + manga = intent?.getParcelableExtra(KEY_MANGA), + mangaId = intent?.getLongExtra(KEY_ID, ID_NONE) ?: ID_NONE, + uri = intent?.data + ) - fun from(intent: Intent?) = MangaIntent( - manga = intent?.getParcelableExtra(KEY_MANGA), - mangaId = intent?.getLongExtra(KEY_ID, ID_NONE) ?: ID_NONE, - uri = intent?.data - ) + constructor(args: Bundle?) : this( + manga = args?.getParcelable(KEY_MANGA), + mangaId = args?.getLong(KEY_ID, ID_NONE) ?: ID_NONE, + uri = null + ) - fun from(args: Bundle?) = MangaIntent( - manga = args?.getParcelable(KEY_MANGA), - mangaId = args?.getLong(KEY_ID, ID_NONE) ?: ID_NONE, - uri = null - ) + companion object { const val ID_NONE = 0L const val KEY_MANGA = "manga" const val KEY_ID = "id" } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaProviderFactory.kt b/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaProviderFactory.kt deleted file mode 100644 index 0223031d9..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaProviderFactory.kt +++ /dev/null @@ -1,24 +0,0 @@ -package org.koitharu.kotatsu.base.domain - -import org.koitharu.kotatsu.core.model.MangaSource -import org.koitharu.kotatsu.core.prefs.AppSettings - -object MangaProviderFactory { - - fun getSources(settings: AppSettings, includeHidden: Boolean): List { - val list = MangaSource.values().toList() - MangaSource.LOCAL - val order = settings.sourcesOrder - val sorted = list.sortedBy { x -> - val e = order.indexOf(x.ordinal) - if (e == -1) order.size + x.ordinal else e - } - return if (includeHidden) { - sorted - } else { - val hidden = settings.hiddenSources - sorted.filterNot { x -> - x.name in hidden - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaUtils.kt b/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaUtils.kt index 25b0ac52f..52956c902 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaUtils.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/domain/MangaUtils.kt @@ -5,7 +5,6 @@ import android.net.Uri import android.util.Size import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runInterruptible -import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import okhttp3.Request import org.koin.core.component.KoinComponent @@ -14,7 +13,6 @@ import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.core.model.MangaPage import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.parser.MangaRepository -import org.koitharu.kotatsu.utils.CacheUtils import org.koitharu.kotatsu.utils.ext.await import org.koitharu.kotatsu.utils.ext.medianOrNull import java.io.InputStream @@ -40,15 +38,14 @@ object MangaUtils : KoinComponent { } } } else { - val client = get() val request = Request.Builder() .url(url) .get() .header(CommonHeaders.REFERER, page.referer) - .cacheControl(CacheUtils.CONTROL_DISABLED) + .cacheControl(CommonHeaders.CACHE_CONTROL_DISABLED) .build() - client.newCall(request).await().use { - withContext(Dispatchers.IO) { + get().newCall(request).await().use { + runInterruptible(Dispatchers.IO) { getBitmapSize(it.body?.byteStream()) } } @@ -66,10 +63,10 @@ object MangaUtils : KoinComponent { val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } - BitmapFactory.decodeStream(input, null, options) + BitmapFactory.decodeStream(input, null, options)?.recycle() val imageHeight: Int = options.outHeight val imageWidth: Int = options.outWidth check(imageHeight > 0 && imageWidth > 0) return Size(imageWidth, imageHeight) } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/AlertDialogFragment.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/AlertDialogFragment.kt index 8077ea928..c364071bf 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/AlertDialogFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/AlertDialogFragment.kt @@ -17,8 +17,7 @@ abstract class AlertDialogFragment : DialogFragment() { get() = checkNotNull(viewBinding) final override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val inflater = activity?.layoutInflater ?: LayoutInflater.from(requireContext()) - val binding = onInflateView(inflater, null) + val binding = onInflateView(layoutInflater, null) viewBinding = binding return MaterialAlertDialogBuilder(requireContext(), theme) .setView(binding.root) @@ -43,4 +42,4 @@ abstract class AlertDialogFragment : DialogFragment() { protected fun bindingOrNull(): B? = viewBinding protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt index 32ff25748..a617cad7e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt @@ -35,9 +35,10 @@ abstract class BaseActivity : AppCompatActivity(), OnApplyWindo private var lastInsets: Insets = Insets.NONE override fun onCreate(savedInstanceState: Bundle?) { + val settings = get() when { - get().isAmoledTheme -> setTheme(R.style.ThemeOverlay_Kotatsu_AMOLED) - get().isDynamicTheme -> setTheme(R.style.Theme_Kotatsu_Monet) + settings.isAmoledTheme -> setTheme(R.style.ThemeOverlay_Kotatsu_AMOLED) + settings.isDynamicTheme -> setTheme(R.style.Theme_Kotatsu_Monet) } super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) @@ -130,4 +131,4 @@ abstract class BaseActivity : AppCompatActivity(), OnApplyWindo super.onBackPressed() } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseBottomSheet.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseBottomSheet.kt index 1a522dfb0..d5d2865c0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseBottomSheet.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseBottomSheet.kt @@ -10,8 +10,7 @@ import androidx.viewbinding.ViewBinding import com.google.android.material.bottomsheet.BottomSheetDialogFragment import org.koitharu.kotatsu.R -abstract class BaseBottomSheet : - BottomSheetDialogFragment() { +abstract class BaseBottomSheet : BottomSheetDialogFragment() { private var viewBinding: B? = null @@ -40,4 +39,4 @@ abstract class BaseBottomSheet : } protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/BasePreferenceFragment.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/BasePreferenceFragment.kt index 3be795aed..4d6a307cb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/BasePreferenceFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/BasePreferenceFragment.kt @@ -11,8 +11,8 @@ import androidx.preference.PreferenceFragmentCompat import org.koin.android.ext.android.inject import org.koitharu.kotatsu.core.prefs.AppSettings -abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : - PreferenceFragmentCompat(), OnApplyWindowInsetsListener { +abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : PreferenceFragmentCompat(), + OnApplyWindowInsetsListener { protected val settings by inject(mode = LazyThreadSafetyMode.NONE) @@ -36,4 +36,4 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : ) return insets } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/network/CommonHeaders.kt b/app/src/main/java/org/koitharu/kotatsu/core/network/CommonHeaders.kt index 18e5bbf55..2f7d73b6b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/network/CommonHeaders.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/network/CommonHeaders.kt @@ -1,5 +1,7 @@ package org.koitharu.kotatsu.core.network +import okhttp3.CacheControl + object CommonHeaders { const val REFERER = "Referer" @@ -7,4 +9,7 @@ object CommonHeaders { const val ACCEPT = "Accept" const val CONTENT_DISPOSITION = "Content-Disposition" const val COOKIE = "Cookie" -} \ No newline at end of file + + val CACHE_CONTROL_DISABLED: CacheControl + get() = CacheControl.Builder().noStore().build() +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/network/NetworkModule.kt b/app/src/main/java/org/koitharu/kotatsu/core/network/NetworkModule.kt index 5627e8637..69e1e411a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/network/NetworkModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/network/NetworkModule.kt @@ -2,27 +2,24 @@ package org.koitharu.kotatsu.core.network import okhttp3.CookieJar import okhttp3.OkHttpClient -import org.koin.android.ext.koin.androidContext -import org.koin.core.qualifier.named import org.koin.dsl.bind import org.koin.dsl.module import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.base.domain.MangaLoaderContext -import org.koitharu.kotatsu.utils.CacheUtils +import org.koitharu.kotatsu.local.data.LocalStorageManager import org.koitharu.kotatsu.utils.DownloadManagerHelper import java.util.concurrent.TimeUnit val networkModule get() = module { single { AndroidCookieJar() } bind CookieJar::class - single(named(CacheUtils.QUALIFIER_HTTP)) { CacheUtils.createHttpCache(androidContext()) } single { OkHttpClient.Builder().apply { connectTimeout(20, TimeUnit.SECONDS) readTimeout(60, TimeUnit.SECONDS) writeTimeout(20, TimeUnit.SECONDS) cookieJar(get()) - cache(get(named(CacheUtils.QUALIFIER_HTTP))) + cache(get().createHttpCache()) addInterceptor(UserAgentInterceptor()) addInterceptor(CloudFlareInterceptor()) if (BuildConfig.DEBUG) { @@ -32,4 +29,4 @@ val networkModule } factory { DownloadManagerHelper(get(), get()) } single { MangaLoaderContext(get(), get()) } - } \ No newline at end of file + } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt index 3505c53b8..4a2c2be82 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt @@ -64,10 +64,10 @@ abstract class RemoteMangaRepository( protected fun generateUid(url: String): Long { var h = 1125899906842597L source.name.forEach { c -> - h = 31 * h + c.toLong() + h = 31 * h + c.code } url.forEach { c -> - h = 31 * h + c.toLong() + h = 31 * h + c.code } return h } @@ -75,7 +75,7 @@ abstract class RemoteMangaRepository( protected fun generateUid(id: Long): Long { var h = 1125899906842597L source.name.forEach { c -> - h = 31 * h + c.toLong() + h = 31 * h + c.code } h = 31 * h + id return h @@ -84,4 +84,4 @@ abstract class RemoteMangaRepository( protected fun parseFailed(message: String? = null): Nothing { throw ParseException(message) } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt index 6defc410a..17b8adeeb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -13,6 +13,7 @@ import com.google.android.material.color.DynamicColors import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.trySendBlocking import kotlinx.coroutines.flow.callbackFlow +import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.ZoomMode import org.koitharu.kotatsu.utils.ext.toUriOrNull import java.io.File @@ -122,22 +123,17 @@ class AppSettings(context: Context) { val isPagesNumbersEnabled: Boolean get() = prefs.getBoolean(KEY_PAGES_NUMBERS, false) - fun getFallbackStorageDir(): File? { - return prefs.getString(KEY_LOCAL_STORAGE, null)?.let { + var mangaStorageDir: File? + get() = prefs.getString(KEY_LOCAL_STORAGE, null)?.let { File(it) }?.takeIf { it.exists() } - } - - @Deprecated("Use LocalStorageManager instead") - fun setStorageDir(file: File?) { - prefs.edit { - if (file == null) { + set(value) = prefs.edit { + if (value == null) { remove(KEY_LOCAL_STORAGE) } else { - putString(KEY_LOCAL_STORAGE, file.path) + putString(KEY_LOCAL_STORAGE, value.path) } } - } fun getDateFormat(format: String = prefs.getString(KEY_DATE_FORMAT, "").orEmpty()): DateFormat = when (format) { @@ -145,7 +141,21 @@ class AppSettings(context: Context) { else -> SimpleDateFormat(format, Locale.getDefault()) } - @Deprecated("Use observe()") + fun getMangaSources(includeHidden: Boolean): List { + val list = MangaSource.values().toMutableList() + list.remove(MangaSource.LOCAL) + val order = sourcesOrder + list.sortBy { x -> + val e = order.indexOf(x.ordinal) + if (e == -1) order.size + x.ordinal else e + } + if (!includeHidden) { + val hidden = hiddenSources + list.removeAll { x -> x.name in hidden } + } + return list + } + fun subscribe(listener: SharedPreferences.OnSharedPreferenceChangeListener) { prefs.registerOnSharedPreferenceChangeListener(listener) } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/ReaderMode.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/ReaderMode.kt index 9ec51d479..bfc8b7b83 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/ReaderMode.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/ReaderMode.kt @@ -10,4 +10,4 @@ enum class ReaderMode(val id: Int) { fun valueOf(id: Int) = values().firstOrNull { it.id == id } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 6b0b78279..d8cb87ecf 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -47,7 +47,7 @@ class DetailsActivity : BaseActivity(), TabLayoutMediator.TabConfigurationStrategy { private val viewModel by viewModel { - parametersOf(MangaIntent.from(intent)) + parametersOf(MangaIntent(intent)) } override fun onCreate(savedInstanceState: Bundle?) { @@ -280,4 +280,4 @@ class DetailsActivity : BaseActivity(), .putExtra(MangaIntent.KEY_ID, mangaId) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index 3d6ce19f0..725cbf950 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -15,9 +15,7 @@ import androidx.core.view.updatePadding import coil.ImageLoader import coil.request.ImageRequest import coil.util.CoilUtils -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koitharu.kotatsu.R @@ -33,7 +31,7 @@ import org.koitharu.kotatsu.image.ui.ImageActivity import org.koitharu.kotatsu.reader.ui.ReaderActivity import org.koitharu.kotatsu.reader.ui.ReaderState import org.koitharu.kotatsu.search.ui.SearchActivity -import org.koitharu.kotatsu.utils.FileSizeUtils +import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.ext.* class DetailsFragment : BaseFragment(), View.OnClickListener, @@ -114,10 +112,8 @@ class DetailsFragment : BaseFragment(), View.OnClickList val file = manga.url.toUri().toFileOrNull() if (file != null) { viewLifecycleScope.launch { - val size = withContext(Dispatchers.IO) { - file.length() - } - textViewSize.text = FileSizeUtils.formatBytes(requireContext(), size) + val size = file.computeSize() + textViewSize.text = FileSize.BYTES.format(requireContext(), size) } sizeContainer.isVisible = true } else { @@ -270,4 +266,4 @@ class DetailsFragment : BaseFragment(), View.OnClickList .lifecycle(viewLifecycleOwner) .enqueueWith(coil) } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/download/domain/DownloadManager.kt b/app/src/main/java/org/koitharu/kotatsu/download/domain/DownloadManager.kt index 849dca7ca..70a8b4db2 100644 --- a/app/src/main/java/org/koitharu/kotatsu/download/domain/DownloadManager.kt +++ b/app/src/main/java/org/koitharu/kotatsu/download/domain/DownloadManager.kt @@ -21,7 +21,6 @@ import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.local.data.MangaZip import org.koitharu.kotatsu.local.data.PagesCache import org.koitharu.kotatsu.local.domain.LocalMangaRepository -import org.koitharu.kotatsu.utils.CacheUtils import org.koitharu.kotatsu.utils.ext.await import org.koitharu.kotatsu.utils.ext.deleteAwait import org.koitharu.kotatsu.utils.ext.waitForNetwork @@ -134,7 +133,7 @@ class DownloadManager( val request = Request.Builder() .url(url) .header(CommonHeaders.REFERER, referer) - .cacheControl(CacheUtils.CONTROL_DISABLED) + .cacheControl(CommonHeaders.CACHE_CONTROL_DISABLED) .get() .build() val call = okHttp.newCall(request) @@ -234,4 +233,4 @@ class DownloadManager( private const val DOWNLOAD_ERROR_DELAY = 500L private const val TEMP_PAGE_FILE = "page.tmp" } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/Cache.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/CacheDir.kt similarity index 66% rename from app/src/main/java/org/koitharu/kotatsu/local/data/Cache.kt rename to app/src/main/java/org/koitharu/kotatsu/local/data/CacheDir.kt index d675fbc2a..1cc562d7b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/Cache.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/CacheDir.kt @@ -1,7 +1,7 @@ package org.koitharu.kotatsu.local.data -enum class Cache(val dir: String) { +enum class CacheDir(val dir: String) { THUMBS("image_cache"), PAGES("pages"); -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/LocalStorageManager.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/LocalStorageManager.kt index b51cb2367..b6859cea4 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/LocalStorageManager.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/LocalStorageManager.kt @@ -1,20 +1,41 @@ package org.koitharu.kotatsu.local.data import android.content.Context +import android.os.StatFs import androidx.annotation.WorkerThread import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runInterruptible +import okhttp3.Cache import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.utils.ext.computeSize import org.koitharu.kotatsu.utils.ext.getStorageName import java.io.File private const val DIR_NAME = "manga" +private const val CACHE_DISK_PERCENTAGE = 0.02 +private const val CACHE_SIZE_MIN: Long = 10 * 1024 * 1024 // 10MB +private const val CACHE_SIZE_MAX: Long = 250 * 1024 * 1024 // 250MB class LocalStorageManager( private val context: Context, private val settings: AppSettings, ) { + fun createHttpCache(): Cache { + val directory = File(context.externalCacheDir ?: context.cacheDir, "http") + directory.mkdirs() + val maxSize = calculateDiskCacheSize(directory) + return Cache(directory, maxSize) + } + + suspend fun computeCacheSize(cache: CacheDir) = runInterruptible(Dispatchers.IO) { + getCacheDirs(cache.dir).sumOf { it.computeSize() } + } + + suspend fun clearCache(cache: CacheDir) = runInterruptible(Dispatchers.IO) { + getCacheDirs(cache.dir).forEach { it.deleteRecursively() } + } + suspend fun getReadableDirs(): List = runInterruptible(Dispatchers.IO) { getConfiguredStorageDirs() .filter { it.isReadable() } @@ -26,7 +47,7 @@ class LocalStorageManager( } suspend fun getDefaultWriteableDir(): File? = runInterruptible(Dispatchers.IO) { - val preferredDir = settings.getFallbackStorageDir()?.takeIf { it.isWriteable() } + val preferredDir = settings.mangaStorageDir?.takeIf { it.isWriteable() } preferredDir ?: getFallbackStorageDir()?.takeIf { it.isWriteable() } } @@ -35,7 +56,7 @@ class LocalStorageManager( @WorkerThread private fun getConfiguredStorageDirs(): MutableSet { val set = getAvailableStorageDirs() - settings.getFallbackStorageDir()?.let { + settings.mangaStorageDir?.let { set.add(it) } return set @@ -57,6 +78,24 @@ class LocalStorageManager( } } + @WorkerThread + private fun getCacheDirs(subDir: String): MutableSet { + val result = LinkedHashSet() + result += File(context.cacheDir, subDir) + result += context.getExternalFilesDirs(subDir) + return result + } + + private fun calculateDiskCacheSize(cacheDirectory: File): Long { + return try { + val cacheDir = StatFs(cacheDirectory.absolutePath) + val size = CACHE_DISK_PERCENTAGE * cacheDir.blockCountLong * cacheDir.blockSizeLong + return size.toLong().coerceIn(CACHE_SIZE_MIN, CACHE_SIZE_MAX) + } catch (_: Exception) { + CACHE_SIZE_MIN + } + } + private fun File.isReadable() = runCatching { canRead() }.getOrDefault(false) @@ -64,4 +103,4 @@ class LocalStorageManager( private fun File.isWriteable() = runCatching { canWrite() }.getOrDefault(false) -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt index 82e70a650..ceed3cd24 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/PagesCache.kt @@ -2,35 +2,25 @@ package org.koitharu.kotatsu.local.data import android.content.Context import com.tomclaw.cache.DiskLruCache -import org.koitharu.kotatsu.utils.FileSizeUtils +import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.ext.longHashCode import org.koitharu.kotatsu.utils.ext.subdir import org.koitharu.kotatsu.utils.ext.takeIfReadable import java.io.File import java.io.InputStream -import java.io.OutputStream class PagesCache(context: Context) { private val cacheDir = context.externalCacheDir ?: context.cacheDir private val lruCache = DiskLruCache.create( - cacheDir.subdir(Cache.PAGES.dir), - FileSizeUtils.mbToBytes(200) + cacheDir.subdir(CacheDir.PAGES.dir), + FileSize.MEGABYTES.convert(200, FileSize.BYTES), ) operator fun get(url: String): File? { return lruCache.get(url)?.takeIfReadable() } - @Deprecated("Useless lambda") - fun put(url: String, writer: (OutputStream) -> Unit): File { - val file = File(cacheDir, url.longHashCode().toString()) - file.outputStream().use(writer) - val res = lruCache.put(url, file) - file.delete() - return res - } - fun put(url: String, inputStream: InputStream): File { val file = File(cacheDir, url.longHashCode().toString()) file.outputStream().use { out -> @@ -40,4 +30,4 @@ class PagesCache(context: Context) { file.delete() return res } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt index 5c9f7a15d..ec9566e68 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt @@ -5,7 +5,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart -import org.koitharu.kotatsu.base.domain.MangaProviderFactory import org.koitharu.kotatsu.base.ui.BaseViewModel import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException import org.koitharu.kotatsu.core.model.Manga @@ -25,7 +24,7 @@ class MainViewModel( val remoteSources = settings.observe() .filter { it == AppSettings.KEY_SOURCES_ORDER || it == AppSettings.KEY_SOURCES_HIDDEN } .onStart { emit("") } - .map { MangaProviderFactory.getSources(settings, includeHidden = false) } + .map { settings.getMangaSources(includeHidden = false) } .asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default) fun openLastReader() { @@ -35,4 +34,4 @@ class MainViewModel( onOpenReader.call(manga) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt b/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt index 8e4e8316d..6eb29088c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt @@ -15,7 +15,6 @@ import org.koitharu.kotatsu.core.model.MangaPage import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.local.data.PagesCache -import org.koitharu.kotatsu.utils.CacheUtils import org.koitharu.kotatsu.utils.ext.await import org.koitharu.kotatsu.utils.ext.mangaRepositoryOf import java.io.File @@ -70,7 +69,7 @@ class PageLoader( .get() .header(CommonHeaders.REFERER, page.referer) .header(CommonHeaders.ACCEPT, "image/webp,image/png;q=0.9,image/jpeg,*/*;q=0.8") - .cacheControl(CacheUtils.CONTROL_DISABLED) + .cacheControl(CommonHeaders.CACHE_CONTROL_DISABLED) .build() okHttp.newCall(request).await().use { response -> check(response.isSuccessful) { @@ -103,4 +102,4 @@ class PageLoader( } private companion object Lock -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index dc57a4fb2..b96a46284 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -56,7 +56,7 @@ class ReaderActivity : BaseFullscreenActivity(), ActivityResultCallback, ReaderControlDelegate.OnInteractionListener { private val viewModel by viewModel { - parametersOf(MangaIntent.from(intent), intent?.getParcelableExtra(EXTRA_STATE)) + parametersOf(MangaIntent(intent), intent?.getParcelableExtra(EXTRA_STATE)) } private lateinit var touchHelper: GridTouchHelper @@ -371,4 +371,4 @@ class ReaderActivity : BaseFullscreenActivity(), .putExtra(EXTRA_STATE, state) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index fa6203f55..201e10262 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -160,7 +160,7 @@ class ReaderViewModel( val downloadId = downloadManagerHelper.downloadPage(page, pageUrl) val uri = downloadManagerHelper.awaitDownload(downloadId) onPageSaved.postCall(uri) - } catch (e: CancellationException) { + } catch (_: CancellationException) { } catch (e: Exception) { onPageSaved.postCall(null) } @@ -267,4 +267,4 @@ class ReaderViewModel( } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/search/domain/MangaSearchRepository.kt b/app/src/main/java/org/koitharu/kotatsu/search/domain/MangaSearchRepository.kt index efb736d7b..fc1f293c9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/search/domain/MangaSearchRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/search/domain/MangaSearchRepository.kt @@ -9,7 +9,6 @@ import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.flow.* import kotlinx.coroutines.isActive import kotlinx.coroutines.withContext -import org.koitharu.kotatsu.base.domain.MangaProviderFactory import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.MangaSource @@ -27,7 +26,7 @@ class MangaSearchRepository( ) { fun globalSearch(query: String, concurrency: Int = DEFAULT_CONCURRENCY): Flow = - MangaProviderFactory.getSources(settings, includeHidden = false).asFlow() + settings.getMangaSources(includeHidden = false).asFlow() .flatMapMerge(concurrency) { source -> runCatching { MangaRepository(source).getList2( @@ -128,4 +127,4 @@ class MangaSearchRepository( return false } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/AppUpdateChecker.kt b/app/src/main/java/org/koitharu/kotatsu/settings/AppUpdateChecker.kt index 90e9f9bbe..61f0e05c0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/AppUpdateChecker.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/AppUpdateChecker.kt @@ -20,7 +20,7 @@ import org.koitharu.kotatsu.core.github.AppVersion import org.koitharu.kotatsu.core.github.GithubRepository import org.koitharu.kotatsu.core.github.VersionId import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.utils.FileSizeUtils +import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.ext.byte2HexFormatted import java.io.ByteArrayInputStream import java.io.InputStream @@ -85,7 +85,7 @@ class AppUpdateChecker(private val activity: ComponentActivity) { append( activity.getString( R.string.size_s, - FileSizeUtils.formatBytes(activity, version.apkSize) + FileSize.BYTES.format(activity, version.apkSize), ) ) appendLine() @@ -144,4 +144,4 @@ class AppUpdateChecker(private val activity: ComponentActivity) { } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt index 82abffced..1ad2af3fd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt @@ -5,20 +5,18 @@ import android.view.View import androidx.preference.Preference import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import org.koin.android.ext.android.get import org.koin.android.ext.android.inject import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BasePreferenceFragment import org.koitharu.kotatsu.core.network.AndroidCookieJar import org.koitharu.kotatsu.core.prefs.AppSettings -import org.koitharu.kotatsu.local.data.Cache +import org.koitharu.kotatsu.local.data.CacheDir +import org.koitharu.kotatsu.local.data.LocalStorageManager import org.koitharu.kotatsu.search.domain.MangaSearchRepository import org.koitharu.kotatsu.tracker.domain.TrackingRepository -import org.koitharu.kotatsu.utils.CacheUtils -import org.koitharu.kotatsu.utils.FileSizeUtils +import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.viewLifecycleScope @@ -26,6 +24,7 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach private val trackerRepo by inject(mode = LazyThreadSafetyMode.NONE) private val searchRepository by inject(mode = LazyThreadSafetyMode.NONE) + private val storageManager by inject(mode = LazyThreadSafetyMode.NONE) override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_history) @@ -35,18 +34,14 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach super.onViewCreated(view, savedInstanceState) findPreference(AppSettings.KEY_PAGES_CACHE_CLEAR)?.let { pref -> viewLifecycleScope.launchWhenResumed { - val size = withContext(Dispatchers.IO) { - CacheUtils.computeCacheSize(pref.context, Cache.PAGES.dir) - } - pref.summary = FileSizeUtils.formatBytes(pref.context, size) + val size = storageManager.computeCacheSize(CacheDir.PAGES) + pref.summary = FileSize.BYTES.format(pref.context, size) } } findPreference(AppSettings.KEY_THUMBS_CACHE_CLEAR)?.let { pref -> viewLifecycleScope.launchWhenResumed { - val size = withContext(Dispatchers.IO) { - CacheUtils.computeCacheSize(pref.context, Cache.THUMBS.dir) - } - pref.summary = FileSizeUtils.formatBytes(pref.context, size) + val size = storageManager.computeCacheSize(CacheDir.THUMBS) + pref.summary = FileSize.BYTES.format(pref.context, size) } } findPreference(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { pref -> @@ -68,11 +63,11 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach override fun onPreferenceTreeClick(preference: Preference): Boolean { return when (preference.key) { AppSettings.KEY_PAGES_CACHE_CLEAR -> { - clearCache(preference, Cache.PAGES) + clearCache(preference, CacheDir.PAGES) true } AppSettings.KEY_THUMBS_CACHE_CLEAR -> { - clearCache(preference, Cache.THUMBS) + clearCache(preference, CacheDir.THUMBS) true } AppSettings.KEY_COOKIES_CLEAR -> { @@ -100,16 +95,14 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach } } - private fun clearCache(preference: Preference, cache: Cache) { + private fun clearCache(preference: Preference, cache: CacheDir) { val ctx = preference.context.applicationContext viewLifecycleScope.launch { try { preference.isEnabled = false - val size = withContext(Dispatchers.IO) { - CacheUtils.clearCache(ctx, cache.dir) - CacheUtils.computeCacheSize(ctx, cache.dir) - } - preference.summary = FileSizeUtils.formatBytes(ctx, size) + storageManager.clearCache(cache) + val size = storageManager.computeCacheSize(cache) + preference.summary = FileSize.BYTES.format(ctx, size) } catch (e: Exception) { preference.summary = e.getDisplayMessage(ctx.resources) } finally { @@ -154,4 +147,4 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach } }.show() } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt index 5b716c75b..17e8b6a93 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt @@ -162,7 +162,7 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings), } override fun onStorageSelected(file: File) { - settings.setStorageDir(file) + settings.mangaStorageDir = file } private fun Preference.bindStorageName() { diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsViewModel.kt index a908ccf4e..05b832038 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsViewModel.kt @@ -3,7 +3,6 @@ package org.koitharu.kotatsu.settings.sources import androidx.core.os.LocaleListCompat import androidx.lifecycle.MutableLiveData import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.base.domain.MangaProviderFactory import org.koitharu.kotatsu.base.ui.BaseViewModel import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.prefs.AppSettings @@ -70,7 +69,7 @@ class SourcesSettingsViewModel( } private fun buildList() { - val sources = MangaProviderFactory.getSources(settings, includeHidden = true) + val sources = settings.getMangaSources(includeHidden = true) val hiddenSources = settings.hiddenSources val query = searchQuery if (!query.isNullOrEmpty()) { @@ -155,4 +154,4 @@ class SourcesSettingsViewModel( } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/CacheUtils.kt b/app/src/main/java/org/koitharu/kotatsu/utils/CacheUtils.kt deleted file mode 100644 index 37487e297..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/utils/CacheUtils.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.koitharu.kotatsu.utils - -import android.content.Context -import android.os.StatFs -import androidx.annotation.WorkerThread -import okhttp3.Cache -import okhttp3.CacheControl -import org.koitharu.kotatsu.utils.ext.computeSize -import org.koitharu.kotatsu.utils.ext.sub -import java.io.File - -object CacheUtils { - - const val QUALIFIER_HTTP = "cache_http" - - val CONTROL_DISABLED = CacheControl.Builder() - .noStore() - .build() - - fun getCacheDirs(context: Context) = (context.externalCacheDirs + context.cacheDir) - .filterNotNull() - .distinctBy { it.absolutePath } - - @WorkerThread - fun computeCacheSize(context: Context, name: String) = getCacheDirs(context) - .map { File(it, name) } - .sumOf { x -> x.computeSize() } - - @WorkerThread - fun clearCache(context: Context, name: String) = getCacheDirs(context) - .map { File(it, name) } - .forEach { it.deleteRecursively() } - - // FIXME need async implementation - fun createHttpCache(context: Context): Cache { - val directory = (context.externalCacheDir ?: context.cacheDir).sub("http") - directory.mkdirs() - val maxSize = calculateDiskCacheSize(directory) // TODO blocking call - return Cache(directory, maxSize) - } - - private fun calculateDiskCacheSize(cacheDirectory: File): Long { - return try { - val cacheDir = StatFs(cacheDirectory.absolutePath) - val size = DISK_CACHE_PERCENTAGE * cacheDir.blockCountLong * cacheDir.blockSizeLong - return size.toLong().coerceIn(MIN_DISK_CACHE_SIZE, MAX_DISK_CACHE_SIZE) - } catch (_: Exception) { - MIN_DISK_CACHE_SIZE - } - } - - private const val DISK_CACHE_PERCENTAGE = 0.02 - private const val MIN_DISK_CACHE_SIZE: Long = 10 * 1024 * 1024 // 10MB - private const val MAX_DISK_CACHE_SIZE: Long = 250 * 1024 * 1024 // 250MB -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/FileSizeUtils.kt b/app/src/main/java/org/koitharu/kotatsu/utils/FileSize.kt similarity index 56% rename from app/src/main/java/org/koitharu/kotatsu/utils/FileSizeUtils.kt rename to app/src/main/java/org/koitharu/kotatsu/utils/FileSize.kt index 2c45c2e22..f06200dbd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/FileSizeUtils.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/FileSize.kt @@ -6,14 +6,14 @@ import java.text.DecimalFormat import kotlin.math.log10 import kotlin.math.pow +enum class FileSize(private val multiplier: Int) { -object FileSizeUtils { + BYTES(1), KILOBYTES(1024), MEGABYTES(1024 * 1024); - fun mbToBytes(mb: Int) = 1024L * 1024L * mb + fun convert(amount: Long, target: FileSize): Long = amount * multiplier / target.multiplier - fun kbToBytes(kb: Int) = 1024L * kb - - fun formatBytes(context: Context, bytes: Long): String { + fun format(context: Context, amount: Long): String { + val bytes = amount * multiplier val units = context.getString(R.string.text_file_sizes).split('|') if (bytes <= 0) { return "0 ${units.first()}" @@ -23,10 +23,13 @@ object FileSizeUtils { append( DecimalFormat("#,##0.#").format( bytes / 1024.0.pow(digitGroups.toDouble()) - ).toString() + ) ) - append(' ') - append(units.getOrNull(digitGroups).orEmpty()) + val unit = units.getOrNull(digitGroups) + if (unit != null) { + append(' ') + append(unit) + } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt b/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt index c99050819..9bdd10971 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt @@ -5,15 +5,17 @@ import android.os.Build object PendingIntentCompat { + @JvmField val FLAG_IMMUTABLE = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PendingIntent.FLAG_IMMUTABLE } else { 0 } + @JvmField val FLAG_MUTABLE = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.FLAG_MUTABLE } else { 0 } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/anim/Motion.kt b/app/src/main/java/org/koitharu/kotatsu/utils/anim/Motion.kt index ba9896400..9f90546fd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/anim/Motion.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/anim/Motion.kt @@ -91,4 +91,4 @@ sealed class Motion { anim.interpolator = DecelerateInterpolator() } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/delegates/ParcelableArgumentDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/utils/delegates/ParcelableArgumentDelegate.kt deleted file mode 100644 index 113637107..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/utils/delegates/ParcelableArgumentDelegate.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.koitharu.kotatsu.utils.delegates - -import android.os.Parcelable -import androidx.fragment.app.Fragment -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KProperty - -class ParcelableArgumentDelegate(private val name: String) : - ReadOnlyProperty { - - override fun getValue(thisRef: Fragment, property: KProperty<*>): T { - return thisRef.requireArguments().getParcelable(name)!! - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/delegates/StringArgumentDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/utils/delegates/StringArgumentDelegate.kt deleted file mode 100644 index 29515feb3..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/utils/delegates/StringArgumentDelegate.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.koitharu.kotatsu.utils.delegates - -import androidx.fragment.app.Fragment -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KProperty - -class StringArgumentDelegate(private val name: String) : ReadOnlyProperty { - - override fun getValue(thisRef: Fragment, property: KProperty<*>): String? { - return thisRef.arguments?.getString(name) - } -} \ No newline at end of file