Fix some StrictMode warnings

This commit is contained in:
Koitharu
2020-11-09 20:33:53 +02:00
parent 908baebb62
commit 03dbd86363
10 changed files with 72 additions and 49 deletions

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.core.network
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.core.qualifier.named
import org.koin.dsl.module import org.koin.dsl.module
import org.koitharu.kotatsu.core.network.cookies.PersistentCookieJar import org.koitharu.kotatsu.core.network.cookies.PersistentCookieJar
import org.koitharu.kotatsu.core.network.cookies.cache.SetCookieCache import org.koitharu.kotatsu.core.network.cookies.cache.SetCookieCache
@@ -18,13 +19,14 @@ val networkModule
SharedPrefsCookiePersistor(androidContext()) SharedPrefsCookiePersistor(androidContext())
) )
} }
single(named(CacheUtils.QUALIFIER_HTTP)) { CacheUtils.createHttpCache(androidContext()) }
single { single {
OkHttpClient.Builder().apply { OkHttpClient.Builder().apply {
connectTimeout(20, TimeUnit.SECONDS) connectTimeout(20, TimeUnit.SECONDS)
readTimeout(60, TimeUnit.SECONDS) readTimeout(60, TimeUnit.SECONDS)
writeTimeout(20, TimeUnit.SECONDS) writeTimeout(20, TimeUnit.SECONDS)
cookieJar(get()) cookieJar(get())
cache(CacheUtils.createHttpCache(androidContext())) cache(get(named(CacheUtils.QUALIFIER_HTTP)))
addInterceptor(UserAgentInterceptor()) addInterceptor(UserAgentInterceptor())
addInterceptor(CloudFlareInterceptor()) addInterceptor(CloudFlareInterceptor())
}.build() }.build()

View File

@@ -20,24 +20,29 @@ import okhttp3.HttpUrl
import org.koitharu.kotatsu.core.network.cookies.cache.CookieCache import org.koitharu.kotatsu.core.network.cookies.cache.CookieCache
import org.koitharu.kotatsu.core.network.cookies.persistence.CookiePersistor import org.koitharu.kotatsu.core.network.cookies.persistence.CookiePersistor
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
class PersistentCookieJar( class PersistentCookieJar(
private val cache: CookieCache, private val cache: CookieCache,
private val persistor: CookiePersistor private val persistor: CookiePersistor
) : ClearableCookieJar { ) : ClearableCookieJar {
init { private var isLoaded = AtomicBoolean(false)
cache.addAll(persistor.loadAll())
}
@Synchronized @Synchronized
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) { override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
if (isLoaded.compareAndSet(false, true)) {
cache.addAll(persistor.loadAll())
}
cache.addAll(cookies) cache.addAll(cookies)
persistor.saveAll(filterPersistentCookies(cookies)) persistor.saveAll(filterPersistentCookies(cookies))
} }
@Synchronized @Synchronized
override fun loadForRequest(url: HttpUrl): List<Cookie> { override fun loadForRequest(url: HttpUrl): List<Cookie> {
if (isLoaded.compareAndSet(false, true)) {
cache.addAll(persistor.loadAll())
}
val cookiesToRemove: MutableList<Cookie> = ArrayList() val cookiesToRemove: MutableList<Cookie> = ArrayList()
val validCookies: MutableList<Cookie> = ArrayList() val validCookies: MutableList<Cookie> = ArrayList()
val it = cache.iterator() val it = cache.iterator()

View File

@@ -15,22 +15,15 @@
*/ */
package org.koitharu.kotatsu.core.network.cookies.persistence package org.koitharu.kotatsu.core.network.cookies.persistence
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import okhttp3.Cookie import okhttp3.Cookie
import java.util.* import java.util.*
@SuppressLint("CommitPrefEdits") class SharedPrefsCookiePersistor(context: Context) : CookiePersistor {
class SharedPrefsCookiePersistor(private val sharedPreferences: SharedPreferences) :
CookiePersistor {
constructor(context: Context) : this( private val sharedPreferences by lazy {
context.getSharedPreferences( context.getSharedPreferences("cookies", Context.MODE_PRIVATE)
"cookies", }
Context.MODE_PRIVATE
)
)
override fun loadAll(): List<Cookie> { override fun loadAll(): List<Cookie> {
val cookies: MutableList<Cookie> = ArrayList(sharedPreferences.all.size) val cookies: MutableList<Cookie> = ArrayList(sharedPreferences.all.size)

View File

@@ -16,6 +16,7 @@ import okhttp3.Request
import okio.IOException import okio.IOException
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import org.koin.core.context.GlobalContext
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.local.PagesCache import org.koitharu.kotatsu.core.local.PagesCache
@@ -231,7 +232,7 @@ class DownloadService : BaseService() {
private fun confirmDataTransfer(context: Context, callback: () -> Unit) { private fun confirmDataTransfer(context: Context, callback: () -> Unit) {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val settings = AppSettings(context) val settings = GlobalContext.get().get<AppSettings>()
if (cm.isActiveNetworkMetered && settings.isTrafficWarningEnabled) { if (cm.isActiveNetworkMetered && settings.isTrafficWarningEnabled) {
CheckBoxAlertDialog.Builder(context) CheckBoxAlertDialog.Builder(context)
.setTitle(R.string.warning) .setTitle(R.string.warning)

View File

@@ -12,6 +12,10 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.cursoradapter.widget.CursorAdapter import androidx.cursoradapter.widget.CursorAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@@ -50,27 +54,35 @@ class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.MangaSuggestionsProvider" private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.MangaSuggestionsProvider"
private const val MODE = DATABASE_MODE_QUERIES private const val MODE = DATABASE_MODE_QUERIES
@JvmStatic
private val uri = Uri.Builder() private val uri = Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT) .scheme(ContentResolver.SCHEME_CONTENT)
.authority(AUTHORITY) .authority(AUTHORITY)
.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY) .appendPath(SearchManager.SUGGEST_URI_PATH_QUERY)
.build() .build()
@JvmStatic
private val projection = arrayOf("_id", SearchManager.SUGGEST_COLUMN_QUERY) private val projection = arrayOf("_id", SearchManager.SUGGEST_COLUMN_QUERY)
@JvmStatic fun saveQueryAsync(context: Context, query: String) {
fun saveQuery(context: Context, query: String) { GlobalScope.launch(Dispatchers.IO) {
SearchRecentSuggestions( saveQuery(context, query)
context, }
AUTHORITY,
MODE
).saveRecentQuery(query, null)
} }
@JvmStatic fun saveQuery(context: Context, query: String) {
fun clearHistory(context: Context) { runCatching {
SearchRecentSuggestions(
context,
AUTHORITY,
MODE
).saveRecentQuery(query, null)
}.onFailure {
if (BuildConfig.DEBUG) {
it.printStackTrace()
}
}
}
suspend fun clearHistory(context: Context) = withContext(Dispatchers.IO) {
SearchRecentSuggestions( SearchRecentSuggestions(
context, context,
AUTHORITY, AUTHORITY,
@@ -78,15 +90,15 @@ class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
).clearHistory() ).clearHistory()
} }
@JvmStatic suspend fun getItemsCount(context: Context) = withContext(Dispatchers.IO) {
fun getItemsCount(context: Context) = getCursor(context)?.use { it.count } ?: 0 getCursor(context)?.use { it.count } ?: 0
}
@JvmStatic
private fun getCursor(context: Context): Cursor? { private fun getCursor(context: Context): Cursor? {
return context.contentResolver?.query(uri, projection, null, arrayOf(""), null) return context.contentResolver?.query(uri, projection, null, arrayOf(""), null)
} }
@JvmStatic @Deprecated("Need async implementation")
fun getSuggestionAdapter(context: Context): CursorAdapter? = getCursor( fun getSuggestionAdapter(context: Context): CursorAdapter? = getCursor(
context context
)?.let { cursor -> )?.let { cursor ->
@@ -102,6 +114,5 @@ class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
} }
} }
} }
} }
} }

View File

@@ -50,7 +50,7 @@ class SearchActivity : BaseActivity(), SearchView.OnQueryTextListener {
.replace(R.id.container, SearchFragment.newInstance(source, query)) .replace(R.id.container, SearchFragment.newInstance(source, query))
.commit() .commit()
searchView.clearFocus() searchView.clearFocus()
MangaSuggestionsProvider.saveQuery(this, query) MangaSuggestionsProvider.saveQueryAsync(applicationContext, query)
true true
} else false } else false
} }

View File

@@ -30,7 +30,7 @@ object SearchHelper {
override fun onQueryTextSubmit(query: String?): Boolean { override fun onQueryTextSubmit(query: String?): Boolean {
return if (!query.isNullOrBlank()) { return if (!query.isNullOrBlank()) {
context.startActivity(GlobalSearchActivity.newIntent(context, query.trim())) context.startActivity(GlobalSearchActivity.newIntent(context, query.trim()))
MangaSuggestionsProvider.saveQuery(context, query) MangaSuggestionsProvider.saveQueryAsync(context.applicationContext, query)
true true
} else false } else false
} }

View File

@@ -45,14 +45,18 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
pref.summary = FileSizeUtils.formatBytes(pref.context, size) pref.summary = FileSizeUtils.formatBytes(pref.context, size)
} }
} }
findPreference<Preference>(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { p -> findPreference<Preference>(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { pref ->
val items = MangaSuggestionsProvider.getItemsCount(p.context) viewLifecycleScope.launchWhenResumed {
p.summary = p.context.resources.getQuantityString(R.plurals.items, items, items) val items = MangaSuggestionsProvider.getItemsCount(pref.context)
pref.summary =
pref.context.resources.getQuantityString(R.plurals.items, items, items)
}
} }
findPreference<Preference>(AppSettings.KEY_UPDATES_FEED_CLEAR)?.let { p -> findPreference<Preference>(AppSettings.KEY_UPDATES_FEED_CLEAR)?.let { pref ->
viewLifecycleScope.launchWhenResumed { viewLifecycleScope.launchWhenResumed {
val items = trackerRepo.count() val items = trackerRepo.count()
p.summary = p.context.resources.getQuantityString(R.plurals.items, items, items) pref.summary =
pref.context.resources.getQuantityString(R.plurals.items, items, items)
} }
} }
} }
@@ -68,14 +72,16 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
true true
} }
AppSettings.KEY_SEARCH_HISTORY_CLEAR -> { AppSettings.KEY_SEARCH_HISTORY_CLEAR -> {
MangaSuggestionsProvider.clearHistory(preference.context) viewLifecycleScope.launch {
preference.summary = preference.context.resources MangaSuggestionsProvider.clearHistory(preference.context)
.getQuantityString(R.plurals.items, 0, 0) preference.summary = preference.context.resources
Snackbar.make( .getQuantityString(R.plurals.items, 0, 0)
view ?: return true, Snackbar.make(
R.string.search_history_cleared, view ?: return@launch,
Snackbar.LENGTH_SHORT R.string.search_history_cleared,
).show() Snackbar.LENGTH_SHORT
).show()
}
true true
} }
AppSettings.KEY_UPDATES_FEED_CLEAR -> { AppSettings.KEY_UPDATES_FEED_CLEAR -> {

View File

@@ -12,6 +12,8 @@ import java.io.File
object CacheUtils { object CacheUtils {
const val QUALIFIER_HTTP = "cache_http"
val CONTROL_DISABLED = CacheControl.Builder() val CONTROL_DISABLED = CacheControl.Builder()
.noStore() .noStore()
.build() .build()
@@ -30,6 +32,7 @@ object CacheUtils {
.map { it.sub(name) } .map { it.sub(name) }
.forEach { it.deleteRecursively() } .forEach { it.deleteRecursively() }
// FIXME need async implementation
fun createHttpCache(context: Context): Cache { fun createHttpCache(context: Context): Cache {
val directory = (context.externalCacheDir ?: context.cacheDir).sub("http") val directory = (context.externalCacheDir ?: context.cacheDir).sub("http")
directory.mkdirs() directory.mkdirs()

View File

@@ -4,16 +4,18 @@ import android.content.Context
import android.view.View import android.view.View
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.utils.ext.measureWidth import org.koitharu.kotatsu.utils.ext.measureWidth
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.roundToInt import kotlin.math.roundToInt
object UiUtils { object UiUtils : KoinComponent {
fun resolveGridSpanCount(context: Context, width: Int = 0): Int { fun resolveGridSpanCount(context: Context, width: Int = 0): Int {
val scaleFactor = AppSettings(context).gridSize / 100f val scaleFactor = get<AppSettings>().gridSize / 100f
val cellWidth = context.resources.getDimension(R.dimen.preferred_grid_width) * scaleFactor val cellWidth = context.resources.getDimension(R.dimen.preferred_grid_width) * scaleFactor
val screenWidth = (if (width <= 0) { val screenWidth = (if (width <= 0) {
context.resources.displayMetrics.widthPixels context.resources.displayMetrics.widthPixels