Compare commits

...

1 Commits

Author SHA1 Message Date
Koitharu
5fe40ac17e Fix old api compatibility 2020-04-25 21:29:46 +03:00
72 changed files with 229 additions and 151 deletions

View File

@@ -12,13 +12,14 @@ android {
defaultConfig {
applicationId 'org.koitharu.kotatsu'
minSdkVersion 21
minSdkVersion 16
maxSdkVersion 20
targetSdkVersion 29
versionCode gitCommits
versionName '0.3'
buildConfigField 'String', 'GIT_BRANCH', "\"${gitBranch}\""
vectorDrawables.useSupportLibrary = true
kapt {
arguments {
arg('room.schemaLocation', "$projectDir/schemas".toString())
@@ -82,7 +83,7 @@ dependencies {
implementation 'com.github.moxy-community:moxy-ktx:2.1.2'
kapt 'com.github.moxy-community:moxy-compiler:2.1.2'
implementation 'com.squareup.okhttp3:okhttp:4.5.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.10'
implementation 'com.squareup.okio:okio:2.5.0'
implementation 'org.jsoup:jsoup:1.13.1'

View File

@@ -44,6 +44,7 @@ class KotatsuApp : Application() {
override fun onCreate() {
super.onCreate()
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
initKoin()
initCoil()
Thread.setDefaultUncaughtExceptionHandler(AppCrashHandler(applicationContext))

View File

@@ -15,10 +15,10 @@
*/
package org.koitharu.kotatsu.core.local.cookies
import org.koitharu.kotatsu.core.local.cookies.persistence.CookiePersistor
import okhttp3.Cookie
import okhttp3.HttpUrl
import org.koitharu.kotatsu.core.local.cookies.cache.CookieCache
import org.koitharu.kotatsu.core.local.cookies.persistence.CookiePersistor
import java.util.*
class PersistentCookieJar(
@@ -72,7 +72,7 @@ class PersistentCookieJar(
fun filterPersistentCookies(cookies: List<Cookie>): List<Cookie> {
val persistentCookies: MutableList<Cookie> = ArrayList()
for (cookie in cookies) {
if (cookie.persistent) {
if (cookie.persistent()) {
persistentCookies.add(cookie)
}
}
@@ -81,7 +81,7 @@ class PersistentCookieJar(
@JvmStatic
fun isCookieExpired(cookie: Cookie): Boolean {
return cookie.expiresAt < System.currentTimeMillis()
return cookie.expiresAt() < System.currentTimeMillis()
}
}
}

View File

@@ -30,18 +30,18 @@ internal class IdentifiableCookie(val cookie: Cookie) {
override fun equals(other: Any?): Boolean {
if (other !is IdentifiableCookie) return false
return other.cookie.name == cookie.name && other.cookie.domain == cookie.domain
&& other.cookie.path == cookie.path && other.cookie.secure == cookie.secure
&& other.cookie.hostOnly == cookie.hostOnly
return other.cookie.name() == cookie.name() && other.cookie.domain() == cookie.domain()
&& other.cookie.path() == cookie.path() && other.cookie.secure() == cookie.secure()
&& other.cookie.hostOnly() == cookie.hostOnly()
}
override fun hashCode(): Int {
var hash = 17
hash = 31 * hash + cookie.name.hashCode()
hash = 31 * hash + cookie.domain.hashCode()
hash = 31 * hash + cookie.path.hashCode()
hash = 31 * hash + if (cookie.secure) 0 else 1
hash = 31 * hash + if (cookie.hostOnly) 0 else 1
hash = 31 * hash + cookie.name().hashCode()
hash = 31 * hash + cookie.domain().hashCode()
hash = 31 * hash + cookie.path().hashCode()
hash = 31 * hash + if (cookie.secure()) 0 else 1
hash = 31 * hash + if (cookie.hostOnly()) 0 else 1
return hash
}

View File

@@ -73,14 +73,14 @@ class SerializableCookie : Serializable {
@Throws(IOException::class)
private fun writeObject(out: ObjectOutputStream) {
out.writeObject(cookie!!.name)
out.writeObject(cookie!!.value)
out.writeLong(if (cookie!!.persistent) cookie!!.expiresAt else NON_VALID_EXPIRES_AT)
out.writeObject(cookie!!.domain)
out.writeObject(cookie!!.path)
out.writeBoolean(cookie!!.secure)
out.writeBoolean(cookie!!.httpOnly)
out.writeBoolean(cookie!!.hostOnly)
out.writeObject(cookie!!.name())
out.writeObject(cookie!!.value())
out.writeLong(if (cookie!!.persistent()) cookie!!.expiresAt() else NON_VALID_EXPIRES_AT)
out.writeObject(cookie!!.domain())
out.writeObject(cookie!!.path())
out.writeBoolean(cookie!!.secure())
out.writeBoolean(cookie!!.httpOnly())
out.writeBoolean(cookie!!.hostOnly())
}
@Throws(IOException::class, ClassNotFoundException::class)

View File

@@ -64,7 +64,7 @@ class SharedPrefsCookiePersistor(private val sharedPreferences: SharedPreference
private companion object {
fun createCookieKey(cookie: Cookie): String {
return (if (cookie.secure) "https" else "http") + "://" + cookie.domain + cookie.path + "|" + cookie.name
return (if (cookie.secure()) "https" else "http") + "://" + cookie.domain() + cookie.path() + "|" + cookie.name()
}
}

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.parser
import android.content.Context
import android.net.Uri
import android.os.Build
import androidx.core.net.toFile
import androidx.core.net.toUri
import org.koin.core.KoinComponent
@@ -14,6 +15,7 @@ import org.koitharu.kotatsu.utils.AlphanumComparator
import org.koitharu.kotatsu.utils.ext.longHashCode
import org.koitharu.kotatsu.utils.ext.readText
import org.koitharu.kotatsu.utils.ext.safe
import org.koitharu.kotatsu.utils.ext.sub
import java.io.File
import java.util.*
import java.util.zip.ZipEntry
@@ -29,8 +31,11 @@ class LocalMangaRepository : MangaRepository, KoinComponent {
sortOrder: SortOrder?,
tag: MangaTag?
): List<Manga> {
val files = context.getExternalFilesDirs("manga")
.flatMap { x -> x?.listFiles(CbzFilter())?.toList().orEmpty() }
val files = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
context.getExternalFilesDirs("manga") + context.filesDir.sub("manga")
} else {
arrayOf(context.getExternalFilesDir("manga"), context.filesDir.sub("manga"))
}.flatMap { x -> x?.listFiles(CbzFilter())?.toList().orEmpty() }
return files.mapNotNull { x -> safe { getFromFile(x) } }
}

View File

@@ -1,7 +1,7 @@
package org.koitharu.kotatsu.domain
import android.graphics.BitmapFactory
import android.util.Size
import android.graphics.Point
import okhttp3.OkHttpClient
import okhttp3.Request
import org.koin.core.KoinComponent
@@ -29,10 +29,10 @@ object MangaUtils : KoinComponent {
.get()
.build()
val size = client.newCall(request).await().use {
getBitmapSize(it.body?.byteStream())
getBitmapSize(it.body()?.byteStream())
}
return when {
size.width * 2 < size.height -> ReaderMode.WEBTOON
size.x * 2 < size.y -> ReaderMode.WEBTOON
else -> ReaderMode.STANDARD
}
} catch (e: Exception) {
@@ -44,7 +44,7 @@ object MangaUtils : KoinComponent {
}
@JvmStatic
private fun getBitmapSize(input: InputStream?): Size {
private fun getBitmapSize(input: InputStream?): Point {
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
@@ -52,6 +52,6 @@ object MangaUtils : KoinComponent {
val imageHeight: Int = options.outHeight
val imageWidth: Int = options.outWidth
check(imageHeight > 0 && imageWidth > 0)
return Size(imageWidth, imageHeight)
return Point(imageWidth, imageHeight)
}
}

View File

@@ -47,6 +47,9 @@ class MangaZip(val file: File) {
if (!file.exists()) {
return
}
dir.listFiles()?.forEach {
it?.deleteRecursively()
}
ZipInputStream(file.inputStream()).use { input ->
while (true) {
val entry = input.nextEntry ?: return

View File

@@ -1,10 +1,12 @@
package org.koitharu.kotatsu.ui.browser
import android.graphics.Bitmap
import android.os.Build
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.RequiresApi
import okhttp3.OkHttpClient
import okhttp3.Request
import org.koin.core.KoinComponent
@@ -38,6 +40,7 @@ class BrowserClient(private val callback: BrowserCallback) : WebViewClient(), Ko
return url?.let(::doRequest)
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? {
return request?.url?.toString()?.let(::doRequest)
}
@@ -47,11 +50,11 @@ class BrowserClient(private val callback: BrowserCallback) : WebViewClient(), Ko
.url(url)
.build()
val response = okHttp.newCall(request).execute()
val ct = response.body?.contentType()
val ct = response.body()?.contentType()
WebResourceResponse(
"${ct?.type}/${ct?.subtype}",
"${ct?.type()}/${ct?.subtype()}",
ct?.charset()?.name() ?: "utf-8",
response.body?.byteStream()
response.body()?.byteStream()
)
}
}

View File

@@ -62,6 +62,21 @@ abstract class BaseActivity : MvpAppCompatActivity(), KoinComponent {
}
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
val keyCode = event.keyCode
val action = event.action
val isDown = action == KeyEvent.ACTION_DOWN
return if (keyCode == KeyEvent.KEYCODE_MENU) {
if (isDown) {
onKeyDown(keyCode, event)
} else {
onKeyUp(keyCode, event)
}
} else {
super.dispatchKeyEvent(event)
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
//TODO remove. Just for testing
if (BuildConfig.DEBUG && keyCode == KeyEvent.KEYCODE_VOLUME_UP) {

View File

@@ -1,36 +1,37 @@
package org.koitharu.kotatsu.ui.common
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.WindowManager
abstract class BaseFullscreenActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
with(window) {
// addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
statusBarColor = Color.TRANSPARENT
navigationBarColor = Color.TRANSPARENT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
}
}
showSystemUI()
}
protected fun hideSystemUI() {
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // прячем панель навигации
or View.SYSTEM_UI_FLAG_FULLSCREEN // прячем строку состояния
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
)
window.decorView.systemUiVisibility =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // прячем панель навигации
or View.SYSTEM_UI_FLAG_FULLSCREEN // прячем строку состояния
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
)
} else {
(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // прячем панель навигации
or View.SYSTEM_UI_FLAG_FULLSCREEN // прячем строку состояния
)
}
}

View File

@@ -2,10 +2,12 @@ package org.koitharu.kotatsu.ui.common.dialog
import android.content.Context
import android.content.DialogInterface
import android.os.Build
import android.os.Environment
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.item_storage.view.*
@@ -15,6 +17,7 @@ import org.koitharu.kotatsu.utils.ext.inflate
import org.koitharu.kotatsu.utils.ext.longHashCode
import java.io.File
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class StorageSelectDialog private constructor(private val delegate: AlertDialog) :
DialogInterface by delegate {

View File

@@ -2,7 +2,6 @@ package org.koitharu.kotatsu.ui.common.list
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import java.util.*
class AdapterUpdater<T>(oldList: List<T>, newList: List<T>, getId: (T) -> Long) {
@@ -12,7 +11,7 @@ class AdapterUpdater<T>(oldList: List<T>, newList: List<T>, getId: (T) -> Long)
getId(oldList[oldItemPosition]) == getId(newList[newItemPosition])
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
Objects.equals(oldList[oldItemPosition], newList[newItemPosition])
oldList[oldItemPosition]?.equals(newList[newItemPosition]) == true
override fun getOldListSize() = oldList.size

View File

@@ -2,9 +2,10 @@ package org.koitharu.kotatsu.ui.common.list
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import okhttp3.internal.toImmutableList
import org.koin.core.KoinComponent
import org.koitharu.kotatsu.utils.ext.replaceWith
import java.util.*
import kotlin.collections.ArrayList
abstract class BaseRecyclerAdapter<T, E>(private val onItemClickListener: OnRecyclerItemClickListener<T>? = null) :
RecyclerView.Adapter<BaseViewHolder<T, E>>(),
@@ -12,7 +13,8 @@ abstract class BaseRecyclerAdapter<T, E>(private val onItemClickListener: OnRecy
protected val dataSet = ArrayList<T>() //TODO make private
val items get() = dataSet.toImmutableList()
val items: List<T>
get() = Collections.unmodifiableList(dataSet)
val hasItems get() = dataSet.isNotEmpty()

View File

@@ -44,6 +44,7 @@ class DownloadNotification(private val context: Context) {
fun fillFrom(manga: Manga) {
builder.setContentTitle(manga.title)
builder.setContentText(context.getString(R.string.manga_downloading_))
builder.setTicker(context.getString(R.string.manga_downloading_))
builder.setProgress(1, 0, true)
builder.setSmallIcon(android.R.drawable.stat_sys_download)
builder.setLargeIcon(null)
@@ -56,7 +57,7 @@ class DownloadNotification(private val context: Context) {
} else {
val intent = DownloadService.getCancelIntent(context, startId)
builder.addAction(
R.drawable.ic_cross,
R.drawable.ic_cross_compat,
context.getString(android.R.string.cancel),
PendingIntent.getService(
context,

View File

@@ -80,7 +80,10 @@ class DownloadService : BaseService() {
notification.setCancelId(startId)
startForeground(DownloadNotification.NOTIFICATION_ID, notification())
}
val destination = getExternalFilesDir("manga")!!
val destination = getExternalFilesDir("manga") ?: filesDir.sub("manga").takeIf {
it.exists() || it.mkdir()
}
checkNotNull(destination) { "Cannot find place to store file" }
var output: MangaZip? = null
try {
val repo = MangaProviderFactory.create(manga.source)
@@ -146,6 +149,7 @@ class DownloadService : BaseService() {
notification.update()
}
} catch (e: Throwable) {
e.printStackTrace()
withContext(Dispatchers.Main) {
notification.setError(e)
notification.setCancelId(0)
@@ -179,7 +183,7 @@ class DownloadService : BaseService() {
okHttp.newCall(request).await().use { response ->
val file = destination.sub("page.tmp")
file.outputStream().use { out ->
response.body!!.byteStream().copyTo(out)
response.body()!!.byteStream().copyTo(out)
}
file
}

View File

@@ -56,7 +56,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
navigationView.setNavigationItemSelectedListener(this)
settings.subscribe(this)
fab.imageTintList = ColorStateList.valueOf(Color.WHITE)
fab.supportImageTintList = ColorStateList.valueOf(Color.WHITE)
fab.isVisible = true
fab.setOnClickListener {
presenter.openLastReader()

View File

@@ -160,7 +160,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
.show()
} else {
textView_holder.text = e.getDisplayMessage(resources)
textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(
textView_holder.setCompoundDrawablesWithIntrinsicBounds(
0,
R.drawable.ic_error_large,
0,
@@ -221,7 +221,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
}
protected open fun setUpEmptyListHolder() {
textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null)
textView_holder.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
textView_holder.setText(R.string.nothing_found)
}

View File

@@ -55,7 +55,7 @@ abstract class MangaListSheet<E> : BaseBottomSheet(R.layout.sheet_list), MangaLi
if (dialog !is BottomSheetDialog) {
toolbar.isVisible = true
textView_title.isVisible = false
appbar.elevation = resources.getDimension(R.dimen.elevation_large)
// appbar.elevation = resources.getDimension(R.dimen.elevation_large)
}
}
@@ -93,11 +93,11 @@ abstract class MangaListSheet<E> : BaseBottomSheet(R.layout.sheet_list), MangaLi
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
toolbar.isVisible = true
textView_title.isVisible = false
appbar.elevation = elevation
// appbar.elevation = elevation
} else {
toolbar.isVisible = false
textView_title.isVisible = true
appbar.elevation = 0f
// appbar.elevation = 0f
}
}
})

View File

@@ -39,7 +39,7 @@ class FavouritesListFragment : MangaListFragment<Unit>(), MangaListView<Unit> {
override fun setUpEmptyListHolder() {
textView_holder.setText(R.string.you_have_not_favourites_yet)
textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
textView_holder.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
}
companion object {

View File

@@ -33,7 +33,7 @@ class CategoriesActivity : BaseActivity(), OnRecyclerItemClickListener<Favourite
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_categories)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
fab_add.imageTintList = ColorStateList.valueOf(Color.WHITE)
fab_add.supportImageTintList = ColorStateList.valueOf(Color.WHITE)
adapter = CategoriesAdapter(this)
recyclerView.addItemDecoration(DividerItemDecoration(this, RecyclerView.VERTICAL))
recyclerView.adapter = adapter

View File

@@ -49,7 +49,7 @@ class HistoryListFragment : MangaListFragment<MangaHistory>(), MangaListView<Man
override fun setUpEmptyListHolder() {
textView_holder.setText(R.string.text_history_holder)
textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
textView_holder.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
}
override fun onCreatePopupMenu(inflater: MenuInflater, menu: Menu, data: Manga) {

View File

@@ -60,7 +60,7 @@ class LocalListFragment : MangaListFragment<File>() {
override fun setUpEmptyListHolder() {
textView_holder.setText(R.string.text_local_holder)
textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
textView_holder.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

View File

@@ -51,13 +51,13 @@ class PageLoader : KoinComponent, CoroutineScope, DisposableHandle {
.cacheControl(CacheUtils.CONTROL_DISABLED)
.build()
okHttp.newCall(request).await().use { response ->
val body = response.body!!
val body = response.body()!!
val type = body.contentType()
check(type?.type == "image") {
"Unexpected content type ${type?.type}/${type?.subtype}"
check(type?.type() == "image") {
"Unexpected content type ${type?.type()}/${type?.subtype()}"
}
cache.put(url) { out ->
response.body!!.byteStream().copyTo(out)
response.body()!!.byteStream().copyTo(out)
}
}
}

View File

@@ -12,7 +12,6 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.core.view.postDelayed
import androidx.core.view.updatePadding
import androidx.fragment.app.commit
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_reader.*
@@ -79,10 +78,10 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
getString(R.string.chapter_d_of_d, state.chapter?.number ?: 0, size)
}
appbar_bottom.setOnApplyWindowInsetsListener { view, insets ->
/*appbar_bottom.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(bottom = insets.systemWindowInsetBottom)
insets
}
}*/
settings.subscribe(this)
loadSettings()
@@ -286,6 +285,10 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh
setUiIsVisible(!appbar_top.isVisible)
true
}
KeyEvent.KEYCODE_MENU -> {
setUiIsVisible(!appbar_top.isVisible)
true
}
else -> super.onKeyDown(keyCode, event)
}

View File

@@ -83,7 +83,7 @@ class ReaderPresenter : BasePresenter<ReaderView>() {
val fileName =
URLUtil.guessFileName(url, response.contentDisposition, response.mimeType)
MediaStoreCompat.insertImage(resolver, fileName) {
response.body!!.byteStream().copyTo(it)
response.body()!!.byteStream().copyTo(it)
}
}
withContext(Dispatchers.Main) {

View File

@@ -13,14 +13,14 @@ class PageAnimTransformer : ViewPager2.PageTransformer {
position <= 0 -> { // [-1,0]
alpha = 1f
translationX = 0f
translationZ = 0f
// translationZ = 0f
scaleX = 1 + FACTOR * position
scaleY = 1f
}
position <= 1 -> { // (0,1]
alpha = 1f
translationX = pageWidth * -position
translationZ = -1f
// translationZ = -1f
scaleX = 1f
scaleY = 1f
}

View File

@@ -40,7 +40,7 @@ class PagesThumbnailsSheet : BaseBottomSheet(R.layout.sheet_pages),
if (dialog !is BottomSheetDialog) {
toolbar.isVisible = true
textView_title.isVisible = false
appbar.elevation = resources.getDimension(R.dimen.elevation_large)
// appbar.elevation = resources.getDimension(R.dimen.elevation_large)
}
recyclerView.addOnLayoutChangeListener(UiUtils.SpanCountResolver)
}
@@ -57,11 +57,11 @@ class PagesThumbnailsSheet : BaseBottomSheet(R.layout.sheet_pages),
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
toolbar.isVisible = true
textView_title.isVisible = false
appbar.elevation = elevation
// appbar.elevation = elevation
} else {
toolbar.isVisible = false
textView_title.isVisible = true
appbar.elevation = 0f
// appbar.elevation = 0f
}
}
})

View File

@@ -116,9 +116,8 @@ class AppUpdateService : BaseService() {
private const val CHANNEL_ID = "update"
private val PERIOD = TimeUnit.HOURS.toMillis(6)
fun isUpdateSupported(context: Context): Boolean {
return getCertificateSHA1Fingerprint(context) == CERT_SHA1
}
@Suppress("UNUSED_PARAMETER")
fun isUpdateSupported(context: Context) = false
fun startIfRequired(context: Context) {
if (!isUpdateSupported(context)) {

View File

@@ -3,8 +3,6 @@ package org.koitharu.kotatsu.ui.settings
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.transition.Slide
import android.view.Gravity
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import androidx.preference.Preference
@@ -24,7 +22,7 @@ class SettingsActivity : BaseActivity(),
if (supportFragmentManager.findFragmentById(R.id.container) == null) {
supportFragmentManager.commit {
replace(R.id.container, MainSettingsFragment().also {
it.exitTransition = Slide(Gravity.START)
// it.exitTransition = Slide(Gravity.START)
})
}
}
@@ -48,8 +46,8 @@ class SettingsActivity : BaseActivity(),
}
private fun openFragment(fragment: Fragment) {
fragment.enterTransition = Slide(Gravity.END)
fragment.exitTransition = Slide(Gravity.START)
// fragment.enterTransition = Slide(Gravity.END)
// fragment.exitTransition = Slide(Gravity.START)
supportFragmentManager.commit {
replace(R.id.container, fragment)
addToBackStack(null)

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.utils
import android.content.Context
import android.os.Build
import androidx.annotation.WorkerThread
import okhttp3.Cache
import okhttp3.CacheControl
@@ -17,8 +18,11 @@ object CacheUtils {
.build()
@JvmStatic
fun getCacheDirs(context: Context) = (context.externalCacheDirs + context.cacheDir)
.filterNotNull()
fun getCacheDirs(context: Context) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
(context.externalCacheDirs + context.cacheDir)
} else {
arrayOf(context.externalCacheDir, context.cacheDir)
}.filterNotNull()
.distinctBy { it.absolutePath }
@JvmStatic
@@ -35,7 +39,7 @@ object CacheUtils {
@JvmStatic
fun createHttpCache(context: Context) = Cache(
directory = (context.externalCacheDir ?: context.cacheDir).sub("http"),
maxSize = FileSizeUtils.mbToBytes(60)
(context.externalCacheDir ?: context.cacheDir).sub("http"),
FileSizeUtils.mbToBytes(60)
)
}

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.utils.ext
import okhttp3.Response
val Response.mimeType: String?
get() = body?.contentType()?.run { "$type/$subtype" }
get() = body()?.contentType()?.run { "${type()}/${subtype()}" }
val Response.contentDisposition: String?
get() = header("Content-Disposition")

View File

@@ -1,30 +1,30 @@
package org.koitharu.kotatsu.utils.ext
import okhttp3.Response
import okhttp3.internal.closeQuietly
import okhttp3.internal.Util.closeQuietly
import org.json.JSONObject
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
fun Response.parseHtml(): Document {
try {
val stream = body?.byteStream() ?: throw NullPointerException("Response body is null")
val charset = body!!.contentType()?.charset()?.name()
val stream = body()?.byteStream() ?: throw NullPointerException("Response body is null")
val charset = body()!!.contentType()?.charset()?.name()
return Jsoup.parse(
stream,
charset,
request.url.toString()
request().url().toString()
)
} finally {
closeQuietly()
closeQuietly(this)
}
}
fun Response.parseJson(): JSONObject {
try {
val string = body?.string() ?: throw NullPointerException("Response body is null")
val string = body()?.string() ?: throw NullPointerException("Response body is null")
return JSONObject(string)
} finally {
closeQuietly()
closeQuietly(this)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

View File

@@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dp" />
<solid android:color="?colorAccent" />
<solid android:color="@color/red_accent" />
<padding
android:bottom="2dp"
android:left="2dp"

View File

@@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dp" />
<solid android:color="?android:textColorTertiary" />
<solid android:color="@android:color/darker_gray" />
<padding
android:bottom="2dp"
android:left="2dp"

View File

@@ -4,7 +4,7 @@
<corners android:radius="5dp" />
<stroke
android:width="2dp"
android:color="?android:textColorTertiary" />
android:color="@android:color/darker_gray" />
<padding
android:bottom="2dp"
android:left="2dp"

View File

@@ -4,7 +4,7 @@
<corners android:radius="5dp" />
<stroke
android:width="2dp"
android:color="?android:colorAccent" />
android:color="@color/red_accent" />
<padding
android:bottom="2dp"
android:left="2dp"

View File

@@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:textColorPrimary"
android:tint="@android:color/darker_gray"
android:viewportWidth="24"
android:viewportHeight="24">
<path

View File

@@ -2,7 +2,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:tint="?android:textColorPrimary"
android:tint="?attr/android:textColorPrimary"
android:viewportWidth="24"
android:viewportHeight="24">
<path

View File

@@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:tint="?android:textColorPrimary"
android:tint="?attr/android:textColorPrimary"
android:viewportWidth="24"
android:viewportHeight="24">
<path

View File

@@ -2,7 +2,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:textColorPrimary"
android:tint="?attr/android:textColorPrimary"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path

View File

@@ -1,7 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="60dp"
android:height="60dp"
android:tint="?android:textColorTertiary"
android:tint="?attr/android:textColorTertiary"
android:viewportWidth="60"
android:viewportHeight="60">
<path

View File

@@ -2,7 +2,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:colorControlNormal"
android:tint="?attr/android:textColorPrimary"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path

View File

@@ -8,6 +8,6 @@
android:fillColor="?attr/colorAccent"
android:pathData="M12,15.4l-3.76,2.27l1,-4.28l-3.32,-2.88l4.38,-0.38l1.7,-4.03l1.71,4.04l4.38,0.38l-3.32,2.88l1,4.28z" />
<path
android:fillColor="?android:textColorPrimary"
android:fillColor="?attr/android:textColorPrimary"
android:pathData="M22,9.24l-7.19,-0.62L12,2L9.19,8.63L2,9.24l5.46,4.73L5.82,21L12,17.27L18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27l1,-4.28l-3.32,-2.88l4.38,-0.38L12,6.1l1.71,4.04l4.38,0.38l-3.32,2.88l1,4.28L12,15.4z" />
</vector>

View File

@@ -2,7 +2,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:textColorPrimary"
android:tint="?attr/android:textColorPrimary"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path

View File

@@ -20,7 +20,8 @@
app:layout_constraintDimensionRatio="13:18"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.3" />
app:layout_constraintWidth_percent="0.3"
android:layout_marginLeft="8dp" />
<TextView
android:id="@+id/textView_title"
@@ -73,7 +74,8 @@
app:icon="@drawable/ic_read"
app:iconPadding="12dp"
app:layout_constraintEnd_toEndOf="@id/textView_title"
app:layout_constraintTop_toBottomOf="@id/ratingBar" />
app:layout_constraintTop_toBottomOf="@id/ratingBar"
android:layout_marginRight="4dp" />
<ImageView
android:id="@+id/imageView_favourite"
@@ -83,12 +85,13 @@
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/add_to_favourites"
android:scaleType="center"
android:src="@drawable/ic_tag_heart_outline"
app:srcCompat="@drawable/ic_tag_heart_outline"
app:layout_constraintBottom_toBottomOf="@id/button_read"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/button_read"
app:layout_constraintTop_toTopOf="@id/button_read"
app:tint="?colorAccent" />
app:tint="?colorAccent"
android:layout_marginRight="4dp" />
<View
android:id="@+id/divider_top"

View File

@@ -50,7 +50,7 @@
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="@string/add_new_category"
android:src="@drawable/ic_add"
app:srcCompat="@drawable/ic_add"
app:backgroundTint="?colorAccent"
app:fabSize="normal"
app:layout_anchor="@id/recyclerView"

View File

@@ -13,7 +13,9 @@
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp">
android:layout_marginBottom="2dp"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true">
<TextView
android:id="@+id/textView"
@@ -31,7 +33,8 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toStartOf="@id/button_restart"
android:text="@string/close" />
android:text="@string/close"
android:layout_toLeftOf="@id/button_restart" />
<Button
android:id="@+id/button_restart"
@@ -40,6 +43,7 @@
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:text="@string/restart" />
android:text="@string/restart"
android:layout_alignParentRight="true" />
</RelativeLayout>

View File

@@ -39,7 +39,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/ic_read_fill"
app:srcCompat="@drawable/ic_read_fill"
android:visibility="gone"
app:fabSize="normal"
app:backgroundTint="?colorAccent"

View File

@@ -5,7 +5,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:listPreferredItemPaddingStart"
android:paddingEnd="?android:listPreferredItemPaddingEnd">
android:paddingEnd="?android:listPreferredItemPaddingEnd"
android:paddingRight="?android:listPreferredItemPaddingRight"
android:paddingLeft="?android:listPreferredItemPaddingLeft">
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@android:id/checkbox"

View File

@@ -40,12 +40,14 @@
android:layout_width="match_parent"
android:layout_height="?android:listPreferredItemHeightSmall"
android:background="?android:selectableItemBackground"
android:drawableEnd="@drawable/ic_add"
android:gravity="start|center_vertical"
android:paddingStart="?android:listPreferredItemPaddingStart"
android:paddingEnd="?android:listPreferredItemPaddingEnd"
android:text="@string/add_new_category"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="?android:textColorPrimary" />
android:textColor="?android:textColorPrimary"
app:drawableEndCompat="@drawable/ic_add"
android:paddingRight="?android:listPreferredItemPaddingRight"
android:paddingLeft="?android:listPreferredItemPaddingLeft" />
</LinearLayout>

View File

@@ -20,7 +20,8 @@
app:layout_constraintDimensionRatio="13:18"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.3" />
app:layout_constraintWidth_percent="0.3"
android:layout_marginLeft="8dp" />
<TextView
android:id="@+id/textView_title"
@@ -76,7 +77,8 @@
app:layout_constraintBottom_toBottomOf="@id/imageView_cover"
app:layout_constraintEnd_toEndOf="@id/textView_title"
app:layout_constraintTop_toBottomOf="@id/ratingBar"
app:layout_constraintVertical_bias="1" />
app:layout_constraintVertical_bias="1"
android:layout_marginRight="4dp" />
<ImageView
android:id="@+id/imageView_favourite"
@@ -86,14 +88,15 @@
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/add_to_favourites"
android:scaleType="center"
android:src="@drawable/ic_tag_heart_outline"
app:srcCompat="@drawable/ic_tag_heart_outline"
app:layout_constraintBottom_toBottomOf="@id/button_read"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintEnd_toStartOf="@id/button_read"
app:layout_constraintTop_toTopOf="@id/button_read"
app:layout_constraintStart_toStartOf="@id/textView_title"
app:tint="?colorAccent" />
app:tint="?colorAccent"
android:layout_marginRight="4dp" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_title"

View File

@@ -11,4 +11,6 @@
android:paddingEnd="?android:listPreferredItemPaddingEnd"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?android:textColorPrimary"
tools:text="@tools:sample/lorem[4]" />
tools:text="@tools:sample/lorem[4]"
android:paddingLeft="?android:listPreferredItemPaddingLeft"
android:paddingRight="?android:listPreferredItemPaddingRight" />

View File

@@ -13,4 +13,6 @@
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="?android:textColorPrimary"
tools:checked="true"
tools:text="@tools:sample/lorem[4]" />
tools:text="@tools:sample/lorem[4]"
android:paddingLeft="?android:listPreferredItemPaddingLeft"
android:paddingRight="?android:listPreferredItemPaddingRight" />

View File

@@ -28,6 +28,7 @@
android:maxLines="2"
android:text="?android:textColorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="@tools:sample/lorem[15]" />
tools:text="@tools:sample/lorem[15]"
android:layout_marginLeft="10dp" />
</LinearLayout>

View File

@@ -2,6 +2,7 @@
<CheckedTextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/radio"
android:layout_width="match_parent"
android:layout_height="?android:listPreferredItemHeightSmall"
@@ -11,4 +12,7 @@
android:gravity="center_vertical|start"
android:paddingStart="?android:listPreferredItemPaddingStart"
android:paddingEnd="?android:listPreferredItemPaddingEnd"
tools:text="@tools:sample/full_names" />
tools:text="@tools:sample/full_names"
android:drawableLeft="?android:listChoiceIndicatorSingle"
android:paddingLeft="?android:listPreferredItemPaddingLeft"
android:paddingRight="?android:listPreferredItemPaddingRight" />

View File

@@ -12,4 +12,6 @@
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
android:textColor="?android:textColorSecondary"
android:textStyle="bold"
tools:text="@tools:sample/lorem[2]" />
tools:text="@tools:sample/lorem[2]"
android:paddingLeft="?android:listPreferredItemPaddingLeft"
android:paddingRight="?android:listPreferredItemPaddingRight" />

View File

@@ -8,7 +8,7 @@
app:cardBackgroundColor="?android:windowBackground"
app:cardElevation="0dp"
app:cardMaxElevation="0dp"
app:strokeColor="?android:colorControlNormal"
app:strokeColor="?attr/colorControlNormal"
app:strokeWidth="1px">
<LinearLayout

View File

@@ -8,7 +8,7 @@
app:cardBackgroundColor="?android:windowBackground"
app:cardElevation="0dp"
app:cardMaxElevation="0dp"
app:strokeColor="?android:colorControlNormal"
app:strokeColor="?attr/colorControlNormal"
app:strokeWidth="1px">
<LinearLayout
@@ -89,10 +89,10 @@
android:id="@+id/textView_rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_star_rating"
android:drawablePadding="4dp"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
tools:text="10/10" />
tools:text="10/10"
app:drawableStartCompat="@drawable/ic_star_rating" />
</LinearLayout>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="?android:windowBackground"
android:layout_width="match_parent"
@@ -33,11 +34,11 @@
android:id="@+id/textView_error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/ic_error_large"
android:drawablePadding="12dp"
android:gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
tools:text="@tools:sample/lorem[6]" />
tools:text="@tools:sample/lorem[6]"
app:drawableTopCompat="@drawable/ic_error_large" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_retry"

View File

@@ -34,11 +34,11 @@
android:id="@+id/textView_error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/ic_error_large"
android:drawablePadding="12dp"
android:gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
tools:text="@tools:sample/lorem[6]" />
tools:text="@tools:sample/lorem[6]"
app:drawableTopCompat="@drawable/ic_error_large" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_retry"

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="?listPreferredItemHeightSmall"
android:background="?selectableItemBackground"
android:drawableStart="@drawable/ic_history"
android:drawablePadding="20dp"
android:gravity="center_vertical"
android:paddingStart="?listPreferredItemPaddingStart"
@@ -13,4 +13,7 @@
android:textAppearance="?textAppearanceListItemSmall"
android:textColor="?android:textColorPrimary"
android:theme="@style/AppPopupTheme"
tools:text="@tools:sample/full_names" />
tools:text="@tools:sample/full_names"
app:drawableStartCompat="@drawable/ic_history"
android:paddingLeft="?listPreferredItemPaddingLeft"
android:paddingRight="?listPreferredItemPaddingRight" />

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="?android:listPreferredItemHeightSmall"
@@ -14,7 +15,7 @@
android:layout_height="wrap_content"
android:padding="?listPreferredItemPaddingStart"
android:scaleType="center"
android:src="@drawable/ic_reorder_handle" />
app:srcCompat="@drawable/ic_reorder_handle" />
<TextView
android:id="@+id/textView_title"
@@ -44,6 +45,6 @@
android:background="?selectableItemBackgroundBorderless"
android:padding="?listPreferredItemPaddingEnd"
android:scaleType="center"
android:src="@drawable/ic_settings" />
app:srcCompat="@drawable/ic_settings" />
</LinearLayout>

View File

@@ -9,7 +9,9 @@
android:paddingEnd="?listPreferredItemPaddingEnd"
android:gravity="center_vertical"
android:background="?selectableItemBackground"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:paddingLeft="?listPreferredItemPaddingLeft"
android:paddingRight="?listPreferredItemPaddingRight">
<TextView
android:id="@+id/textView_title"

View File

@@ -1,15 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="92dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher_foreground"
app:srcCompat="@drawable/ic_launcher_foreground"
android:layout_alignParentStart="true"
android:layout_centerVertical="true" />
android:layout_centerVertical="true"
android:layout_alignParentLeft="true" />
<View
android:layout_width="match_parent"
@@ -17,6 +19,8 @@
android:background="?android:listDivider"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true" />
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true" />
</RelativeLayout>

View File

@@ -2,7 +2,7 @@
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/widget_recent"
android:minWidth="40dp"
android:minWidth="110dp"
android:minHeight="110dp"
android:minResizeWidth="40dp"
android:minResizeHeight="40dp"