Drop support for Android 4.x (#2440)
* Bump minSdkVersion * Remove Android 4.x specific logic * Consolidate res assets * Add note about minimum Android version to README * Restore incorrectly removed method, remove unneeded Lollipop TargetApi annotations
This commit is contained in:
parent
b55814a1c0
commit
0d5099f230
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
|
|
||||||
# ![app icon](./.github/readme-images/app-icon.png)Tachiyomi
|
# ![app icon](./.github/readme-images/app-icon.png)Tachiyomi
|
||||||
Tachiyomi is a free and open source manga reader for Android.
|
Tachiyomi is a free and open source manga reader for Android 5.0 and above.
|
||||||
|
|
||||||
![screenshots of app](./.github/readme-images/screens.png)
|
![screenshots of app](./.github/readme-images/screens.png)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "eu.kanade.tachiyomi"
|
applicationId "eu.kanade.tachiyomi"
|
||||||
minSdkVersion 16
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
versionCode 41
|
versionCode 41
|
||||||
|
@ -1,35 +1,20 @@
|
|||||||
package eu.kanade.tachiyomi.network
|
package eu.kanade.tachiyomi.network
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import android.webkit.CookieManager
|
import android.webkit.CookieManager
|
||||||
import android.webkit.CookieSyncManager
|
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import okhttp3.CookieJar
|
import okhttp3.CookieJar
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
|
|
||||||
class AndroidCookieJar(context: Context) : CookieJar {
|
class AndroidCookieJar : CookieJar {
|
||||||
|
|
||||||
private val manager = CookieManager.getInstance()
|
private val manager = CookieManager.getInstance()
|
||||||
|
|
||||||
private val syncManager by lazy { CookieSyncManager.createInstance(context) }
|
|
||||||
|
|
||||||
init {
|
|
||||||
// Init sync manager when using anything below L
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
syncManager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
|
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
|
||||||
val urlString = url.toString()
|
val urlString = url.toString()
|
||||||
|
|
||||||
for (cookie in cookies) {
|
for (cookie in cookies) {
|
||||||
manager.setCookie(urlString, cookie.toString())
|
manager.setCookie(urlString, cookie.toString())
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
syncManager.sync()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadForRequest(url: HttpUrl): List<Cookie> {
|
override fun loadForRequest(url: HttpUrl): List<Cookie> {
|
||||||
@ -39,7 +24,7 @@ class AndroidCookieJar(context: Context) : CookieJar {
|
|||||||
fun get(url: HttpUrl): List<Cookie> {
|
fun get(url: HttpUrl): List<Cookie> {
|
||||||
val cookies = manager.getCookie(url.toString())
|
val cookies = manager.getCookie(url.toString())
|
||||||
|
|
||||||
return if (cookies != null && !cookies.isEmpty()) {
|
return if (cookies != null && cookies.isNotEmpty()) {
|
||||||
cookies.split(";").mapNotNull { Cookie.parse(url, it) }
|
cookies.split(";").mapNotNull { Cookie.parse(url, it) }
|
||||||
} else {
|
} else {
|
||||||
emptyList()
|
emptyList()
|
||||||
@ -53,19 +38,10 @@ class AndroidCookieJar(context: Context) : CookieJar {
|
|||||||
cookies.split(";")
|
cookies.split(";")
|
||||||
.map { it.substringBefore("=") }
|
.map { it.substringBefore("=") }
|
||||||
.onEach { manager.setCookie(urlString, "$it=;Max-Age=-1") }
|
.onEach { manager.setCookie(urlString, "$it=;Max-Age=-1") }
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
syncManager.sync()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeAll() {
|
fun removeAll() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
manager.removeAllCookies {}
|
||||||
manager.removeAllCookies {}
|
|
||||||
} else {
|
|
||||||
manager.removeAllCookie()
|
|
||||||
syncManager.sync()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,7 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
|||||||
* Application class.
|
* Application class.
|
||||||
*/
|
*/
|
||||||
private val initWebView by lazy {
|
private val initWebView by lazy {
|
||||||
if (Build.VERSION.SDK_INT >= 17) {
|
WebSettings.getDefaultUserAgent(context)
|
||||||
WebSettings.getDefaultUserAgent(context)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
package eu.kanade.tachiyomi.network
|
package eu.kanade.tachiyomi.network
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import okhttp3.Cache
|
||||||
import okhttp3.*
|
import okhttp3.OkHttpClient
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
|
||||||
import java.net.InetAddress
|
|
||||||
import java.net.Socket
|
|
||||||
import java.net.UnknownHostException
|
|
||||||
import java.security.KeyManagementException
|
|
||||||
import java.security.KeyStore
|
|
||||||
import java.security.NoSuchAlgorithmException
|
|
||||||
import javax.net.ssl.*
|
|
||||||
|
|
||||||
class NetworkHelper(context: Context) {
|
class NetworkHelper(context: Context) {
|
||||||
|
|
||||||
@ -19,99 +11,15 @@ class NetworkHelper(context: Context) {
|
|||||||
|
|
||||||
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
||||||
|
|
||||||
val cookieManager = AndroidCookieJar(context)
|
val cookieManager = AndroidCookieJar()
|
||||||
|
|
||||||
val client = OkHttpClient.Builder()
|
val client = OkHttpClient.Builder()
|
||||||
.cookieJar(cookieManager)
|
.cookieJar(cookieManager)
|
||||||
.cache(Cache(cacheDir, cacheSize))
|
.cache(Cache(cacheDir, cacheSize))
|
||||||
.enableTLS12()
|
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val cloudflareClient = client.newBuilder()
|
val cloudflareClient = client.newBuilder()
|
||||||
.addInterceptor(CloudflareInterceptor(context))
|
.addInterceptor(CloudflareInterceptor(context))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
private fun OkHttpClient.Builder.enableTLS12(): OkHttpClient.Builder {
|
|
||||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
|
||||||
trustManagerFactory.init(null as KeyStore?)
|
|
||||||
val trustManagers = trustManagerFactory.trustManagers
|
|
||||||
if (trustManagers.size == 1 && trustManagers[0] is X509TrustManager) {
|
|
||||||
class TLSSocketFactory @Throws(KeyManagementException::class, NoSuchAlgorithmException::class)
|
|
||||||
constructor() : SSLSocketFactory() {
|
|
||||||
|
|
||||||
private val internalSSLSocketFactory: SSLSocketFactory
|
|
||||||
|
|
||||||
init {
|
|
||||||
val context = SSLContext.getInstance("TLS")
|
|
||||||
context.init(null, null, null)
|
|
||||||
internalSSLSocketFactory = context.socketFactory
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getDefaultCipherSuites(): Array<String> {
|
|
||||||
return internalSSLSocketFactory.defaultCipherSuites
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSupportedCipherSuites(): Array<String> {
|
|
||||||
return internalSSLSocketFactory.supportedCipherSuites
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createSocket(): Socket? {
|
|
||||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket? {
|
|
||||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class, UnknownHostException::class)
|
|
||||||
override fun createSocket(host: String, port: Int): Socket? {
|
|
||||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class, UnknownHostException::class)
|
|
||||||
override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket? {
|
|
||||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createSocket(host: InetAddress, port: Int): Socket? {
|
|
||||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket? {
|
|
||||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun enableTLSOnSocket(socket: Socket?): Socket? {
|
|
||||||
if (socket != null && socket is SSLSocket) {
|
|
||||||
socket.enabledProtocols = socket.supportedProtocols
|
|
||||||
}
|
|
||||||
return socket
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sslSocketFactory(TLSSocketFactory(), trustManagers[0] as X509TrustManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
val specCompat = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
|
||||||
.tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
|
|
||||||
.cipherSuites(
|
|
||||||
*ConnectionSpec.MODERN_TLS.cipherSuites.orEmpty().toTypedArray(),
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
val specs = listOf(specCompat, ConnectionSpec.CLEARTEXT)
|
|
||||||
connectionSpecs(specs)
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.holder
|
package eu.kanade.tachiyomi.ui.base.holder
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
@ -51,10 +50,6 @@ interface SlicedHolder {
|
|||||||
slice.showRightTopRect(topRect)
|
slice.showRightTopRect(topRect)
|
||||||
slice.showLeftBottomRect(bottomRect)
|
slice.showLeftBottomRect(bottomRect)
|
||||||
slice.showRightBottomRect(bottomRect)
|
slice.showRightBottomRect(bottomRect)
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
slice.showTopEdgeShadow(topShadow)
|
|
||||||
slice.showBottomEdgeShadow(bottomShadow)
|
|
||||||
}
|
|
||||||
setMargins(margin, if (topShadow) margin else 0, margin, if (bottomShadow) margin else 0)
|
setMargins(margin, if (topShadow) margin else 0, margin, if (bottomShadow) margin else 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import android.content.pm.ActivityInfo
|
|||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
@ -21,9 +20,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
|
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst
|
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.*
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.Error
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.Success
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||||
@ -276,10 +273,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
|||||||
toolbarAnimation.setAnimationListener(object : SimpleAnimationListener() {
|
toolbarAnimation.setAnimationListener(object : SimpleAnimationListener() {
|
||||||
override fun onAnimationStart(animation: Animation) {
|
override fun onAnimationStart(animation: Animation) {
|
||||||
// Fix status bar being translucent the first time it's opened.
|
// Fix status bar being translucent the first time it's opened.
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||||
window.addFlags(
|
|
||||||
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
toolbar.startAnimation(toolbarAnimation)
|
toolbar.startAnimation(toolbarAnimation)
|
||||||
@ -637,11 +631,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
|||||||
*/
|
*/
|
||||||
private fun setFullscreen(enabled: Boolean) {
|
private fun setFullscreen(enabled: Boolean) {
|
||||||
systemUi = if (enabled) {
|
systemUi = if (enabled) {
|
||||||
val level = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
val level = SystemUiHelper.LEVEL_IMMERSIVE
|
||||||
SystemUiHelper.LEVEL_IMMERSIVE
|
|
||||||
} else {
|
|
||||||
SystemUiHelper.LEVEL_HIDE_STATUS_BAR
|
|
||||||
}
|
|
||||||
val flags = SystemUiHelper.FLAG_IMMERSIVE_STICKY or
|
val flags = SystemUiHelper.FLAG_IMMERSIVE_STICKY or
|
||||||
SystemUiHelper.FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES
|
SystemUiHelper.FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES
|
||||||
|
|
||||||
|
@ -3,16 +3,14 @@ package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
|
|||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorSet
|
import android.animation.AnimatorSet
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.annotation.TargetApi
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.HapticFeedbackConstants
|
import android.view.HapticFeedbackConstants
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.ViewConfiguration
|
import android.view.ViewConfiguration
|
||||||
import android.view.animation.DecelerateInterpolator
|
import android.view.animation.DecelerateInterpolator
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.GestureDetectorWithLongTap
|
import eu.kanade.tachiyomi.ui.reader.viewer.GestureDetectorWithLongTap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,7 +56,6 @@ open class WebtoonRecyclerView @JvmOverloads constructor(
|
|||||||
firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
|
firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
|
||||||
override fun onScrollStateChanged(state: Int) {
|
override fun onScrollStateChanged(state: Int) {
|
||||||
super.onScrollStateChanged(state)
|
super.onScrollStateChanged(state)
|
||||||
val layoutManager = layoutManager
|
val layoutManager = layoutManager
|
||||||
|
@ -5,10 +5,9 @@ import android.app.Activity
|
|||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.preference.PreferenceScreen
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.preference.PreferenceScreen
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -106,21 +105,12 @@ class SettingsBackupController : SettingsController() {
|
|||||||
onClick {
|
onClick {
|
||||||
val currentDir = preferences.backupsDirectory().getOrDefault()
|
val currentDir = preferences.backupsDirectory().getOrDefault()
|
||||||
try{
|
try{
|
||||||
val intent = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
// Custom dir selected, open directory selector
|
|
||||||
preferences.context.getFilePicker(currentDir)
|
|
||||||
} else {
|
|
||||||
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
|
||||||
}
|
|
||||||
|
|
||||||
startActivityForResult(intent, CODE_BACKUP_DIR)
|
startActivityForResult(intent, CODE_BACKUP_DIR)
|
||||||
} catch (e: ActivityNotFoundException){
|
} catch (e: ActivityNotFoundException){
|
||||||
//Fall back to custom picker on error
|
// Fall back to custom picker on error
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
|
startActivityForResult(preferences.context.getFilePicker(currentDir), CODE_BACKUP_DIR)
|
||||||
startActivityForResult(preferences.context.getFilePicker(currentDir), CODE_BACKUP_DIR)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.backupsDirectory().asObservable()
|
preferences.backupsDirectory().asObservable()
|
||||||
@ -154,37 +144,27 @@ class SettingsBackupController : SettingsController() {
|
|||||||
// Get uri of backup folder.
|
// Get uri of backup folder.
|
||||||
val uri = data.data
|
val uri = data.data
|
||||||
|
|
||||||
// Get UriPermission so it's possible to write files post kitkat.
|
// Get UriPermission so it's possible to write files
|
||||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
|
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
|
||||||
|
|
||||||
activity.contentResolver.takePersistableUriPermission(uri, flags)
|
activity.contentResolver.takePersistableUriPermission(uri, flags)
|
||||||
}
|
|
||||||
|
|
||||||
// Set backup Uri.
|
// Set backup Uri
|
||||||
preferences.backupsDirectory().set(uri.toString())
|
preferences.backupsDirectory().set(uri.toString())
|
||||||
}
|
}
|
||||||
CODE_BACKUP_CREATE -> if (data != null && resultCode == Activity.RESULT_OK) {
|
CODE_BACKUP_CREATE -> if (data != null && resultCode == Activity.RESULT_OK) {
|
||||||
val activity = activity ?: return
|
val activity = activity ?: return
|
||||||
val uri = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
val dir = data.data.path
|
|
||||||
val file = File(dir, Backup.getDefaultFilename())
|
|
||||||
|
|
||||||
Uri.fromFile(file)
|
val uri = data.data
|
||||||
} else {
|
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||||
val uri = data.data
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
|
||||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
|
||||||
|
|
||||||
activity.contentResolver.takePersistableUriPermission(uri, flags)
|
activity.contentResolver.takePersistableUriPermission(uri, flags)
|
||||||
val file = UniFile.fromUri(activity, uri)
|
val file = UniFile.fromUri(activity, uri)
|
||||||
|
|
||||||
file.uri
|
|
||||||
}
|
|
||||||
|
|
||||||
CreatingBackupDialog().showDialog(router, TAG_CREATING_BACKUP_DIALOG)
|
CreatingBackupDialog().showDialog(router, TAG_CREATING_BACKUP_DIALOG)
|
||||||
BackupCreateService.makeBackup(activity, uri, backupFlags)
|
BackupCreateService.makeBackup(activity, file.uri, backupFlags)
|
||||||
}
|
}
|
||||||
CODE_BACKUP_RESTORE -> if (data != null && resultCode == Activity.RESULT_OK) {
|
CODE_BACKUP_RESTORE -> if (data != null && resultCode == Activity.RESULT_OK) {
|
||||||
val uri = data.data
|
val uri = data.data
|
||||||
@ -201,25 +181,17 @@ class SettingsBackupController : SettingsController() {
|
|||||||
val currentDir = preferences.backupsDirectory().getOrDefault()
|
val currentDir = preferences.backupsDirectory().getOrDefault()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// If API is lower than Lollipop use custom picker
|
// Use Android's built-in file creator
|
||||||
val intent = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
|
||||||
preferences.context.getFilePicker(currentDir)
|
|
||||||
} else {
|
|
||||||
// Use Androids build in file creator
|
|
||||||
Intent(Intent.ACTION_CREATE_DOCUMENT)
|
|
||||||
.addCategory(Intent.CATEGORY_OPENABLE)
|
.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
.setType("application/*")
|
.setType("application/*")
|
||||||
.putExtra(Intent.EXTRA_TITLE, Backup.getDefaultFilename())
|
.putExtra(Intent.EXTRA_TITLE, Backup.getDefaultFilename())
|
||||||
}
|
|
||||||
|
|
||||||
startActivityForResult(intent, CODE_BACKUP_CREATE)
|
startActivityForResult(intent, CODE_BACKUP_CREATE)
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (e: ActivityNotFoundException) {
|
||||||
// Handle errors where the android ROM doesn't support the built in picker
|
// Handle errors where the android ROM doesn't support the built in picker
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
|
startActivityForResult(preferences.context.getFilePicker(currentDir), CODE_BACKUP_CREATE)
|
||||||
startActivityForResult(preferences.context.getFilePicker(currentDir), CODE_BACKUP_CREATE)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateBackupDialog : DialogController() {
|
class CreateBackupDialog : DialogController() {
|
||||||
|
@ -5,7 +5,6 @@ import android.app.Dialog
|
|||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
@ -107,11 +106,7 @@ class SettingsDownloadController : SettingsController() {
|
|||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
DOWNLOAD_DIR_PRE_L -> if (data != null && resultCode == Activity.RESULT_OK) {
|
DOWNLOAD_DIR -> if (data != null && resultCode == Activity.RESULT_OK) {
|
||||||
val uri = Uri.fromFile(File(data.data.path))
|
|
||||||
preferences.downloadsDirectory().set(uri.toString())
|
|
||||||
}
|
|
||||||
DOWNLOAD_DIR_L -> if (data != null && resultCode == Activity.RESULT_OK) {
|
|
||||||
val context = applicationContext ?: return
|
val context = applicationContext ?: return
|
||||||
val uri = data.data
|
val uri = data.data
|
||||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||||
@ -132,19 +127,11 @@ class SettingsDownloadController : SettingsController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun customDirectorySelected(currentDir: String) {
|
fun customDirectorySelected(currentDir: String) {
|
||||||
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
try {
|
||||||
startActivityForResult(preferences.context.getFilePicker(currentDir), DOWNLOAD_DIR_PRE_L)
|
startActivityForResult(intent, DOWNLOAD_DIR)
|
||||||
} else {
|
} catch (e: ActivityNotFoundException) {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
startActivityForResult(preferences.context.getFilePicker(currentDir), DOWNLOAD_DIR)
|
||||||
try {
|
|
||||||
startActivityForResult(intent, DOWNLOAD_DIR_L)
|
|
||||||
} catch (e: ActivityNotFoundException) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
startActivityForResult(preferences.context.getFilePicker(currentDir), DOWNLOAD_DIR_L)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +170,6 @@ class SettingsDownloadController : SettingsController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val DOWNLOAD_DIR_PRE_L = 103
|
const val DOWNLOAD_DIR = 104
|
||||||
const val DOWNLOAD_DIR_L = 104
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.util
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.os.EnvironmentCompat
|
import androidx.core.os.EnvironmentCompat
|
||||||
@ -45,13 +44,6 @@ object DiskUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < 21) {
|
|
||||||
val extStorages = System.getenv("SECONDARY_STORAGE")
|
|
||||||
if (extStorages != null) {
|
|
||||||
directories += extStorages.split(":").map(::File)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return directories
|
return directories
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,11 +71,7 @@ object DiskUtil {
|
|||||||
* Scans the given file so that it can be shown in gallery apps, for example.
|
* Scans the given file so that it can be shown in gallery apps, for example.
|
||||||
*/
|
*/
|
||||||
fun scanMedia(context: Context, uri: Uri) {
|
fun scanMedia(context: Context, uri: Uri) {
|
||||||
val action = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
val action = Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
|
||||||
Intent.ACTION_MEDIA_MOUNTED
|
|
||||||
} else {
|
|
||||||
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
|
|
||||||
}
|
|
||||||
val mediaScanIntent = Intent(action)
|
val mediaScanIntent = Intent(action)
|
||||||
mediaScanIntent.data = uri
|
mediaScanIntent.data = uri
|
||||||
context.sendBroadcast(mediaScanIntent)
|
context.sendBroadcast(mediaScanIntent)
|
||||||
|
@ -36,7 +36,6 @@ abstract class WebViewClientCompat : WebViewClient() {
|
|||||||
return shouldOverrideUrlCompat(view, url)
|
return shouldOverrideUrlCompat(view, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
final override fun shouldInterceptRequest(
|
final override fun shouldInterceptRequest(
|
||||||
view: WebView,
|
view: WebView,
|
||||||
request: WebResourceRequest
|
request: WebResourceRequest
|
||||||
|
@ -16,32 +16,26 @@ class ElevationAppBarLayout @JvmOverloads constructor(
|
|||||||
private var origStateAnimator: StateListAnimator? = null
|
private var origStateAnimator: StateListAnimator? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
origStateAnimator = stateListAnimator
|
||||||
origStateAnimator = stateListAnimator
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun enableElevation() {
|
fun enableElevation() {
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
stateListAnimator = origStateAnimator
|
||||||
stateListAnimator = origStateAnimator
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disableElevation() {
|
fun disableElevation() {
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
stateListAnimator = StateListAnimator().apply {
|
||||||
stateListAnimator = StateListAnimator().apply {
|
val objAnimator = ObjectAnimator.ofFloat(this, "elevation", 0f)
|
||||||
val objAnimator = ObjectAnimator.ofFloat(this, "elevation", 0f)
|
|
||||||
|
|
||||||
// Enabled and collapsible, but not collapsed means not elevated
|
// Enabled and collapsible, but not collapsed means not elevated
|
||||||
addState(intArrayOf(android.R.attr.enabled, R.attr.state_collapsible, -R.attr.state_collapsed),
|
addState(intArrayOf(android.R.attr.enabled, R.attr.state_collapsible, -R.attr.state_collapsed),
|
||||||
objAnimator)
|
objAnimator)
|
||||||
|
|
||||||
// Default enabled state
|
// Default enabled state
|
||||||
addState(intArrayOf(android.R.attr.enabled), objAnimator)
|
addState(intArrayOf(android.R.attr.enabled), objAnimator)
|
||||||
|
|
||||||
// Disabled state
|
// Disabled state
|
||||||
addState(IntArray(0), objAnimator)
|
addState(IntArray(0), objAnimator)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,14 +2,11 @@ package eu.kanade.tachiyomi.widget
|
|||||||
|
|
||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.annotation.TargetApi
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewAnimationUtils
|
import android.view.ViewAnimationUtils
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
class RevealAnimationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
class RevealAnimationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
View(context, attrs) {
|
View(context, attrs) {
|
||||||
|
|
||||||
@ -21,28 +18,25 @@ class RevealAnimationView @JvmOverloads constructor(context: Context, attrs: Att
|
|||||||
* @param initialRadius size of radius of animation
|
* @param initialRadius size of radius of animation
|
||||||
*/
|
*/
|
||||||
fun hideRevealEffect(centerX: Int, centerY: Int, initialRadius: Int) {
|
fun hideRevealEffect(centerX: Int, centerY: Int, initialRadius: Int) {
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
// Make the view visible.
|
||||||
|
this.visibility = View.VISIBLE
|
||||||
|
|
||||||
// Make the view visible.
|
// Create the animation (the final radius is zero).
|
||||||
this.visibility = View.VISIBLE
|
val anim = ViewAnimationUtils.createCircularReveal(
|
||||||
|
this, centerX, centerY, initialRadius.toFloat(), 0f)
|
||||||
|
|
||||||
// Create the animation (the final radius is zero).
|
// Set duration of animation.
|
||||||
val anim = ViewAnimationUtils.createCircularReveal(
|
anim.duration = 500
|
||||||
this, centerX, centerY, initialRadius.toFloat(), 0f)
|
|
||||||
|
|
||||||
// Set duration of animation.
|
// make the view invisible when the animation is done
|
||||||
anim.duration = 500
|
anim.addListener(object : AnimatorListenerAdapter() {
|
||||||
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
|
super.onAnimationEnd(animation)
|
||||||
|
this@RevealAnimationView.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// make the view invisible when the animation is done
|
anim.start()
|
||||||
anim.addListener(object : AnimatorListenerAdapter() {
|
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
|
||||||
super.onAnimationEnd(animation)
|
|
||||||
this@RevealAnimationView.visibility = View.INVISIBLE
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
anim.start()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,25 +49,20 @@ class RevealAnimationView @JvmOverloads constructor(context: Context, attrs: Att
|
|||||||
* @return sdk version lower then 21
|
* @return sdk version lower then 21
|
||||||
*/
|
*/
|
||||||
fun showRevealEffect(centerX: Int, centerY: Int, listener: Animator.AnimatorListener): Boolean {
|
fun showRevealEffect(centerX: Int, centerY: Int, listener: Animator.AnimatorListener): Boolean {
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
this.visibility = View.VISIBLE
|
||||||
|
|
||||||
this.visibility = View.VISIBLE
|
val height = this.height
|
||||||
|
|
||||||
val height = this.height
|
// Create animation
|
||||||
|
val anim = ViewAnimationUtils.createCircularReveal(
|
||||||
|
this, centerX, centerY, 0f, height.toFloat())
|
||||||
|
|
||||||
// Create animation
|
// Set duration of animation
|
||||||
val anim = ViewAnimationUtils.createCircularReveal(
|
anim.duration = 350
|
||||||
this, centerX, centerY, 0f, height.toFloat())
|
|
||||||
|
|
||||||
// Set duration of animation
|
anim.addListener(listener)
|
||||||
anim.duration = 350
|
anim.start()
|
||||||
|
return true
|
||||||
anim.addListener(listener)
|
|
||||||
anim.start()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ripple
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:color="@color/selectorColorDark"
|
|
||||||
>
|
|
||||||
<item>
|
|
||||||
<selector>
|
|
||||||
<item android:state_selected="true">
|
|
||||||
<color android:color="@color/selectorColorDark"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item android:state_activated="true">
|
|
||||||
<color android:color="@color/selectorColorDark"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item>
|
|
||||||
<color android:color="@color/md_black_1000"/>
|
|
||||||
</item>
|
|
||||||
</selector>
|
|
||||||
</item>
|
|
||||||
</ripple>
|
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ripple
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:color="@color/colorAccentDark"
|
|
||||||
>
|
|
||||||
<item>
|
|
||||||
<selector>
|
|
||||||
<item android:state_selected="true">
|
|
||||||
<color android:color="@color/selectorColorDark"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item android:state_activated="true">
|
|
||||||
<color android:color="@color/selectorColorDark"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item>
|
|
||||||
<color android:color="@color/backgroundDark"/>
|
|
||||||
</item>
|
|
||||||
</selector>
|
|
||||||
</item>
|
|
||||||
</ripple>
|
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ripple
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:color="@color/colorAccentLight"
|
|
||||||
>
|
|
||||||
<item>
|
|
||||||
<selector>
|
|
||||||
<item android:state_selected="true">
|
|
||||||
<color android:color="@color/selectorColorLight"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item android:state_activated="true">
|
|
||||||
<color android:color="@color/selectorColorLight"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item>
|
|
||||||
<color android:color="@color/backgroundLight"/>
|
|
||||||
</item>
|
|
||||||
</selector>
|
|
||||||
</item>
|
|
||||||
</ripple>
|
|
@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:color="@color/rippleColorDark">
|
|
||||||
<item>
|
|
||||||
<selector>
|
|
||||||
<item android:state_selected="true">
|
|
||||||
<color android:color="@color/rippleColorDark"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item android:state_activated="true">
|
|
||||||
<color android:color="@color/rippleColorDark"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item>
|
|
||||||
<color android:color="@color/md_black_1000"/>
|
|
||||||
</item>
|
|
||||||
</selector>
|
|
||||||
</item>
|
|
||||||
</ripple>
|
|
@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:color="@color/rippleColorDark">
|
|
||||||
<item>
|
|
||||||
<selector>
|
|
||||||
<item android:state_selected="true">
|
|
||||||
<color android:color="@color/rippleColorDark"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item android:state_activated="true">
|
|
||||||
<color android:color="@color/rippleColorDark"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item>
|
|
||||||
<color android:color="@color/dialogDark"/>
|
|
||||||
</item>
|
|
||||||
</selector>
|
|
||||||
</item>
|
|
||||||
</ripple>
|
|
@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:color="@color/rippleColorLight">
|
|
||||||
<item>
|
|
||||||
<selector>
|
|
||||||
<item android:state_selected="true">
|
|
||||||
<color android:color="@color/rippleColorLight"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item android:state_activated="true">
|
|
||||||
<color android:color="@color/rippleColorLight"/>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item>
|
|
||||||
<color android:color="@color/dialogLight"/>
|
|
||||||
</item>
|
|
||||||
</selector>
|
|
||||||
</item>
|
|
||||||
</ripple>
|
|
@ -1,10 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector android:exitFadeDuration="@android:integer/config_longAnimTime"
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
android:color="@color/selectorColorDark">
|
||||||
|
<item>
|
||||||
|
<selector>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<color android:color="@color/selectorColorDark" />
|
||||||
|
</item>
|
||||||
|
|
||||||
<item android:state_focused="true" android:drawable="@color/selectorColorDark"/>
|
<item android:state_activated="true">
|
||||||
<item android:state_pressed="true" android:drawable="@color/selectorColorDark"/>
|
<color android:color="@color/selectorColorDark" />
|
||||||
<item android:state_activated="true" android:drawable="@color/selectorColorDark"/>
|
</item>
|
||||||
<item android:drawable="@color/md_black_1000"/>
|
|
||||||
|
|
||||||
</selector>
|
<item>
|
||||||
|
<color android:color="@color/md_black_1000" />
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector android:exitFadeDuration="@android:integer/config_longAnimTime"
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
android:color="@color/colorAccentDark">
|
||||||
|
<item>
|
||||||
|
<selector>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<color android:color="@color/selectorColorDark" />
|
||||||
|
</item>
|
||||||
|
|
||||||
<item android:state_focused="true" android:drawable="@color/selectorColorDark"/>
|
<item android:state_activated="true">
|
||||||
<item android:state_pressed="true" android:drawable="@color/selectorColorDark"/>
|
<color android:color="@color/selectorColorDark" />
|
||||||
<item android:state_activated="true" android:drawable="@color/selectorColorDark"/>
|
</item>
|
||||||
<item android:drawable="@color/backgroundDark"/>
|
|
||||||
|
|
||||||
</selector>
|
<item>
|
||||||
|
<color android:color="@color/backgroundDark" />
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector android:exitFadeDuration="@android:integer/config_longAnimTime"
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
android:color="@color/colorAccentLight">
|
||||||
|
<item>
|
||||||
|
<selector>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<color android:color="@color/selectorColorLight" />
|
||||||
|
</item>
|
||||||
|
|
||||||
<item android:state_focused="true" android:drawable="@color/selectorColorLight"/>
|
<item android:state_activated="true">
|
||||||
<item android:state_pressed="true" android:drawable="@color/selectorColorLight"/>
|
<color android:color="@color/selectorColorLight" />
|
||||||
<item android:state_activated="true" android:drawable="@color/selectorColorLight"/>
|
</item>
|
||||||
<item android:drawable="@color/backgroundLight"/>
|
|
||||||
|
|
||||||
</selector>
|
<item>
|
||||||
|
<color android:color="@color/backgroundLight" />
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:exitFadeDuration="@android:integer/config_longAnimTime">
|
android:color="@color/rippleColorDark">
|
||||||
|
<item>
|
||||||
|
<selector>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<color android:color="@color/rippleColorDark" />
|
||||||
|
</item>
|
||||||
|
|
||||||
<item android:drawable="@color/rippleColorDark" android:state_focused="true"/>
|
<item android:state_activated="true">
|
||||||
<item android:drawable="@color/rippleColorDark" android:state_pressed="true"/>
|
<color android:color="@color/rippleColorDark" />
|
||||||
<item android:drawable="@color/rippleColorDark" android:state_activated="true"/>
|
</item>
|
||||||
<item android:drawable="@color/md_black_1000"/>
|
|
||||||
|
|
||||||
</selector>
|
<item>
|
||||||
|
<color android:color="@color/md_black_1000" />
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:exitFadeDuration="@android:integer/config_longAnimTime">
|
android:color="@color/rippleColorDark">
|
||||||
|
<item>
|
||||||
|
<selector>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<color android:color="@color/rippleColorDark" />
|
||||||
|
</item>
|
||||||
|
|
||||||
<item android:drawable="@color/rippleColorDark" android:state_focused="true"/>
|
<item android:state_activated="true">
|
||||||
<item android:drawable="@color/rippleColorDark" android:state_pressed="true"/>
|
<color android:color="@color/rippleColorDark" />
|
||||||
<item android:drawable="@color/rippleColorDark" android:state_activated="true"/>
|
</item>
|
||||||
<item android:drawable="@color/dialogDark"/>
|
|
||||||
|
|
||||||
</selector>
|
<item>
|
||||||
|
<color android:color="@color/dialogDark" />
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:exitFadeDuration="@android:integer/config_longAnimTime">
|
android:color="@color/rippleColorLight">
|
||||||
|
<item>
|
||||||
|
<selector>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<color android:color="@color/rippleColorLight" />
|
||||||
|
</item>
|
||||||
|
|
||||||
<item android:drawable="@color/rippleColorLight" android:state_focused="true"/>
|
<item android:state_activated="true">
|
||||||
<item android:drawable="@color/rippleColorLight" android:state_pressed="true"/>
|
<color android:color="@color/rippleColorLight" />
|
||||||
<item android:drawable="@color/rippleColorLight" android:state_activated="true"/>
|
</item>
|
||||||
<item android:drawable="@color/dialogLight"/>
|
|
||||||
|
|
||||||
</selector>
|
<item>
|
||||||
|
<color android:color="@color/dialogLight" />
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!--Nav header-->
|
|
||||||
<dimen name="navigation_drawer_header_margin">41dp</dimen>
|
|
||||||
</resources>
|
|
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- String Fonts -->
|
|
||||||
<string name="font_roboto_medium" translatable="false">sans-serif-medium</string>
|
|
||||||
<string name="font_roboto_regular" translatable="false">sans-serif-regular</string>
|
|
||||||
</resources>
|
|
@ -1,58 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!--===========-->
|
|
||||||
<!-- Main Theme-->
|
|
||||||
<!--===========-->
|
|
||||||
<style name="Theme.Tachiyomi" parent="Theme.Base">
|
|
||||||
<!-- Attributes specific for SDK 21 and up -->
|
|
||||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
|
||||||
<item name="android:navigationBarColor">@color/colorPrimaryDark</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!--=============-->
|
|
||||||
<!-- Dark Themes -->
|
|
||||||
<!--=============-->
|
|
||||||
<style name="Theme.Tachiyomi.Dark" parent="Theme.Base.Dark">
|
|
||||||
<!-- Attributes specific for SDK 21 and up -->
|
|
||||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
|
||||||
<item name="android:navigationBarColor">@color/colorDarkPrimaryDark</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="Theme.Tachiyomi.DarkBlue" parent="Theme.Base.Dark">
|
|
||||||
<item name="colorPrimary">@color/colorPrimary</item>
|
|
||||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
|
||||||
|
|
||||||
<!-- Attributes specific for SDK 21 and up -->
|
|
||||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
|
||||||
<item name="android:navigationBarColor">@color/colorDarkPrimaryDark</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!--==============-->
|
|
||||||
<!-- Amoled Theme -->
|
|
||||||
<!--==============-->
|
|
||||||
<style name="Theme.Tachiyomi.Amoled" parent="Theme.Base.Amoled">
|
|
||||||
<!-- Attributes specific for SDK 21 and up -->
|
|
||||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!--==============-->
|
|
||||||
<!-- Reader Theme -->
|
|
||||||
<!--==============-->
|
|
||||||
<style name="Theme.Reader" parent="Theme.Base.Reader.Dark">
|
|
||||||
<!-- Attributes specific for SDK 21 and up -->
|
|
||||||
<item name="android:statusBarColor">?colorPrimaryDark</item>
|
|
||||||
<item name="android:navigationBarColor">?colorPrimaryDark</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="Theme.Reader.Light" parent="Theme.Base.Reader.Light">
|
|
||||||
<!-- Attributes specific for SDK 21 and up -->
|
|
||||||
<item name="android:statusBarColor">?colorPrimaryDark</item>
|
|
||||||
<item name="android:navigationBarColor">?colorPrimaryDark</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
@ -20,10 +20,9 @@
|
|||||||
<dimen name="text_body">16sp</dimen>
|
<dimen name="text_body">16sp</dimen>
|
||||||
<dimen name="text_small_body">14sp</dimen>
|
<dimen name="text_small_body">14sp</dimen>
|
||||||
|
|
||||||
|
|
||||||
<!--Nav header-->
|
<!--Nav header-->
|
||||||
<dimen name="navigation_drawer_header_height">158dp</dimen>
|
<dimen name="navigation_drawer_header_height">158dp</dimen>
|
||||||
<dimen name="navigation_drawer_header_margin">16dp</dimen>
|
<dimen name="navigation_drawer_header_margin">41dp</dimen>
|
||||||
|
|
||||||
<dimen name="bottom_sheet_width">0dp</dimen>
|
<dimen name="bottom_sheet_width">0dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- String Fonts -->
|
|
||||||
<string name="font_roboto_medium" translatable="false">sans-serif</string>
|
|
||||||
<string name="font_roboto_regular" translatable="false">sans-serif</string>
|
|
||||||
</resources>
|
|
@ -50,7 +50,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.Regular">
|
<style name="TextAppearance.Regular">
|
||||||
<item name="android:fontFamily">@string/font_roboto_regular</item>
|
<item name="android:fontFamily">sans-serif-regular</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.Regular.Body1">
|
<style name="TextAppearance.Regular.Body1">
|
||||||
@ -102,7 +102,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.Medium">
|
<style name="TextAppearance.Medium">
|
||||||
<item name="android:fontFamily">@string/font_roboto_medium</item>
|
<item name="android:fontFamily">sans-serif-medium</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.Medium.Title">
|
<style name="TextAppearance.Medium.Title">
|
||||||
|
@ -39,8 +39,13 @@
|
|||||||
<item name="icon_color">@color/iconColorLight</item>
|
<item name="icon_color">@color/iconColorLight</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!--===========-->
|
||||||
|
<!-- Main Theme-->
|
||||||
|
<!--===========-->
|
||||||
<style name="Theme.Tachiyomi" parent="Theme.Base">
|
<style name="Theme.Tachiyomi" parent="Theme.Base">
|
||||||
<!-- Attributes specific for SDK 16 to SDK 20 -->
|
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||||
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
|
<item name="android:navigationBarColor">@color/colorPrimaryDark</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!--=============-->
|
<!--=============-->
|
||||||
@ -61,6 +66,10 @@
|
|||||||
<item name="android:divider">@color/dividerDark</item>
|
<item name="android:divider">@color/dividerDark</item>
|
||||||
<item name="android:listDivider">@drawable/line_divider_dark</item>
|
<item name="android:listDivider">@drawable/line_divider_dark</item>
|
||||||
|
|
||||||
|
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||||
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
|
<item name="android:navigationBarColor">@color/colorDarkPrimaryDark</item>
|
||||||
|
|
||||||
<!-- Themes -->
|
<!-- Themes -->
|
||||||
<item name="windowActionModeOverlay">true</item>
|
<item name="windowActionModeOverlay">true</item>
|
||||||
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
|
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
|
||||||
@ -86,6 +95,10 @@
|
|||||||
<style name="Theme.Tachiyomi.DarkBlue" parent="Theme.Base.Dark">
|
<style name="Theme.Tachiyomi.DarkBlue" parent="Theme.Base.Dark">
|
||||||
<item name="colorPrimary">@color/colorPrimary</item>
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
|
||||||
|
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||||
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
|
<item name="android:navigationBarColor">@color/colorDarkPrimaryDark</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!--==============-->
|
<!--==============-->
|
||||||
@ -96,6 +109,10 @@
|
|||||||
<item name="colorPrimaryDark">@color/colorAmoledPrimary</item>
|
<item name="colorPrimaryDark">@color/colorAmoledPrimary</item>
|
||||||
<item name="android:colorBackground">@color/md_black_1000</item>
|
<item name="android:colorBackground">@color/md_black_1000</item>
|
||||||
|
|
||||||
|
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||||
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
|
|
||||||
<!-- Custom Attributes-->
|
<!-- Custom Attributes-->
|
||||||
<item name="selectable_list_drawable">@drawable/list_item_selector_amoled</item>
|
<item name="selectable_list_drawable">@drawable/list_item_selector_amoled</item>
|
||||||
<item name="selectable_library_drawable">@drawable/library_item_selector_amoled</item>
|
<item name="selectable_library_drawable">@drawable/library_item_selector_amoled</item>
|
||||||
@ -113,12 +130,18 @@
|
|||||||
<item name="colorPrimary">@color/colorDarkPrimary</item>
|
<item name="colorPrimary">@color/colorDarkPrimary</item>
|
||||||
<item name="colorPrimaryDark">@color/colorDarkPrimaryDark</item>
|
<item name="colorPrimaryDark">@color/colorDarkPrimaryDark</item>
|
||||||
<item name="android:colorBackground">@android:color/black</item>
|
<item name="android:colorBackground">@android:color/black</item>
|
||||||
|
|
||||||
|
<item name="android:statusBarColor">?colorPrimaryDark</item>
|
||||||
|
<item name="android:navigationBarColor">?colorPrimaryDark</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Base.Reader.Light" parent="Theme.Base">
|
<style name="Theme.Base.Reader.Light" parent="Theme.Base">
|
||||||
<item name="colorPrimary">@color/colorDarkPrimary</item>
|
<item name="colorPrimary">@color/colorDarkPrimary</item>
|
||||||
<item name="colorPrimaryDark">@color/colorDarkPrimaryDark</item>
|
<item name="colorPrimaryDark">@color/colorDarkPrimaryDark</item>
|
||||||
<item name="android:colorBackground">@android:color/white</item>
|
<item name="android:colorBackground">@android:color/white</item>
|
||||||
|
|
||||||
|
<item name="android:statusBarColor">?colorPrimaryDark</item>
|
||||||
|
<item name="android:navigationBarColor">?colorPrimaryDark</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Reader" parent="Theme.Base.Reader.Dark">
|
<style name="Theme.Reader" parent="Theme.Base.Reader.Dark">
|
||||||
|
Loading…
Reference in New Issue
Block a user