Fix some StrictMode warnings
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 -> {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user