mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-26 19:17:51 +02:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
f8a03226ee | |||
32db1e3045 | |||
303e6c0102 | |||
18883f1ba3 | |||
5c31271e91 | |||
00981cf4e8 | |||
968f4a69e8 | |||
e7e1a9bf50 | |||
fe1becb001 | |||
7789171c71 | |||
3fd2222c99 | |||
6de36a88c0 | |||
b37685542d | |||
a2b1b9e746 | |||
8017324033 | |||
7464497c88 | |||
499def3daa | |||
6931b75cc5 | |||
f853610578 | |||
69f51b88bf | |||
e0d680201a | |||
1566b8f8b8 | |||
4bbf78e840 | |||
7ab16a69df | |||
95e60ed775 | |||
d38cd2547a | |||
2159b72e69 | |||
81c23bbf9d |
@ -1,7 +1,7 @@
|
||||
language: android
|
||||
android:
|
||||
components:
|
||||
- build-tools-27.0.2
|
||||
- build-tools-27.0.3
|
||||
- android-27
|
||||
- extra-android-m2repository
|
||||
- extra-google-m2repository
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
git fetch --unshallow #required for commit count
|
||||
|
||||
cp .travis/google-services.json app/
|
||||
|
||||
if [ -z "$TRAVIS_TAG" ]; then
|
||||
./gradlew clean assembleStandardDebug
|
||||
|
||||
|
73
.travis/google-services.json
Normal file
73
.travis/google-services.json
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "777921915939",
|
||||
"firebase_url": "https://tachiyomi-47364.firebaseio.com",
|
||||
"project_id": "tachiyomi-47364",
|
||||
"storage_bucket": "tachiyomi-47364.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:777921915939:android:36544cd2d96c50c7",
|
||||
"android_client_info": {
|
||||
"package_name": "eu.kanade.tachiyomi"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "777921915939-9q25jvgbdtpk91daqlk7sa1cbdcg77o6.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAHr8RxyeiSPC_MxJTnivz-hmdo5oX0QQQ"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:777921915939:android:564fdc1d62efd1de",
|
||||
"android_client_info": {
|
||||
"package_name": "eu.kanade.tachiyomi.debug"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "777921915939-9q25jvgbdtpk91daqlk7sa1cbdcg77o6.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAHr8RxyeiSPC_MxJTnivz-hmdo5oX0QQQ"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
| Build | Download | F-Droid | Contribute | Contact |
|
||||
| Build | Stable | Dev | Contribute | Contact |
|
||||
|-------|----------|---------|------------|---------|
|
||||
| [](https://travis-ci.org/inorichi/tachiyomi) | [](https://github.com/inorichi/tachiyomi/releases) [](http://tachiyomi.kanade.eu/latest) | [](https://f-droid.org/repository/browse/?fdid=eu.kanade.tachiyomi) [](//github.com/inorichi/tachiyomi/wiki/FDroid-for-dev-versions) | [](https://github.com/inorichi/tachiyomi/wiki/Translation) | [](https://discord.gg/2dDQBv2) |
|
||||
| [](https://travis-ci.org/inorichi/tachiyomi) | [)](https://github.com/inorichi/tachiyomi/releases) | [](http://tachiyomi.kanade.eu/latest) [](//github.com/inorichi/tachiyomi/wiki/F-Droid-for-dev-versions) | [](https://hosted.weblate.org/engage/tachiyomi/?utm_source=widget) | [](https://discord.gg/2dDQBv2) |
|
||||
|
||||
|
||||
# Tachiyomi
|
||||
@ -21,9 +21,9 @@ Features include:
|
||||
* Create backups locally or to your cloud service of choice
|
||||
|
||||
## Download
|
||||
Get the app from our [releases page](https://github.com/inorichi/tachiyomi/releases) or from [f-droid](https://f-droid.org/packages/eu.kanade.tachiyomi/).
|
||||
Get the app from our [releases page](https://github.com/inorichi/tachiyomi/releases).
|
||||
|
||||
If you want to try new features before they get to the stable release, you can download the dev version [here](http://tachiyomi.kanade.eu/latest) (auto-updates not included), or add our [F-Droid repo](https://github.com/inorichi/tachiyomi/wiki/FDroid-for-dev-versions).
|
||||
If you want to try new features before they get to the stable release, you can download the dev version [here](http://tachiyomi.kanade.eu/latest) (auto-updates not included), or add our [F-Droid repo](https://github.com/inorichi/tachiyomi/wiki/F-Droid-for-dev-versions).
|
||||
|
||||
## Issues, Feature Requests and Contributing
|
||||
|
||||
|
3
app/.gitignore
vendored
3
app/.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
/build
|
||||
*iml
|
||||
*.iml
|
||||
custom.gradle
|
||||
custom.gradle
|
||||
google-services.json
|
||||
|
@ -30,7 +30,7 @@ ext {
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion "27.0.2"
|
||||
buildToolsVersion '27.0.3'
|
||||
publishNonDefault true
|
||||
|
||||
defaultConfig {
|
||||
@ -38,8 +38,8 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 27
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
versionCode 33
|
||||
versionName "0.7.0"
|
||||
versionCode 36
|
||||
versionName "0.7.3"
|
||||
|
||||
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
|
||||
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
|
||||
@ -116,10 +116,12 @@ dependencies {
|
||||
implementation "com.android.support:support-annotations:$support_library_version"
|
||||
implementation "com.android.support:customtabs:$support_library_version"
|
||||
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.0-beta6'
|
||||
|
||||
implementation 'com.android.support:multidex:1.0.2'
|
||||
|
||||
standardImplementation 'com.google.firebase:firebase-core:12.0.1'
|
||||
|
||||
// ReactiveX
|
||||
implementation 'io.reactivex:rxandroid:1.2.1'
|
||||
implementation 'io.reactivex:rxjava:1.3.6'
|
||||
@ -153,7 +155,7 @@ dependencies {
|
||||
|
||||
// Job scheduling
|
||||
implementation 'com.evernote:android-job:1.2.4'
|
||||
implementation 'com.google.android.gms:play-services-gcm:11.8.0'
|
||||
implementation 'com.google.android.gms:play-services-gcm:12.0.1'
|
||||
|
||||
// Changelog
|
||||
implementation 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0'
|
||||
@ -201,7 +203,7 @@ dependencies {
|
||||
implementation 'me.gujun.android.taggroup:library:1.4@aar'
|
||||
|
||||
// Conductor
|
||||
implementation "com.github.inorichi.Conductor:conductor:05c4d4d"
|
||||
implementation "com.github.inorichi.Conductor:conductor:be8b3c5"
|
||||
implementation ("com.bluelinelabs:conductor-support:2.1.5-SNAPSHOT") {
|
||||
exclude group: "com.bluelinelabs", module: "conductor"
|
||||
}
|
||||
@ -254,3 +256,7 @@ kotlin {
|
||||
androidExtensions {
|
||||
experimental = true
|
||||
}
|
||||
|
||||
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) {
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
}
|
||||
|
@ -1,16 +1,20 @@
|
||||
package eu.kanade.tachiyomi.data.download
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.NetworkInfo.State.CONNECTED
|
||||
import android.net.NetworkInfo.State.DISCONNECTED
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import com.github.pwittchen.reactivenetwork.library.Connectivity
|
||||
import com.github.pwittchen.reactivenetwork.library.ReactiveNetwork
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.util.connectivityManager
|
||||
import eu.kanade.tachiyomi.util.plusAssign
|
||||
@ -41,7 +45,12 @@ class DownloadService : Service() {
|
||||
* @param context the application context.
|
||||
*/
|
||||
fun start(context: Context) {
|
||||
context.startService(Intent(context, DownloadService::class.java))
|
||||
val intent = Intent(context, DownloadService::class.java)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
context.startService(intent)
|
||||
} else {
|
||||
context.startForegroundService(intent)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,6 +90,7 @@ class DownloadService : Service() {
|
||||
*/
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
startForeground(Notifications.ID_DOWNLOAD_CHAPTER, getPlaceholderNotification())
|
||||
runningRelay.call(true)
|
||||
subscriptions = CompositeSubscription()
|
||||
listenDownloaderState()
|
||||
@ -176,4 +186,10 @@ class DownloadService : Service() {
|
||||
if (!isHeld) acquire()
|
||||
}
|
||||
|
||||
private fun getPlaceholderNotification(): Notification {
|
||||
return NotificationCompat.Builder(this, Notifications.CHANNEL_DOWNLOADER)
|
||||
.setContentTitle(getString(R.string.download_notifier_downloader_title))
|
||||
.build()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ object PreferenceKeys {
|
||||
|
||||
const val cropBorders = "crop_borders"
|
||||
|
||||
const val cropBordersWebtoon = "crop_borders_webtoon"
|
||||
|
||||
const val readWithTapping = "reader_tap"
|
||||
|
||||
const val readWithVolumeKeys = "reader_volume_keys"
|
||||
|
@ -67,6 +67,8 @@ class PreferencesHelper(val context: Context) {
|
||||
|
||||
fun cropBorders() = rxPrefs.getBoolean(Keys.cropBorders, false)
|
||||
|
||||
fun cropBordersWebtoon() = rxPrefs.getBoolean(Keys.cropBordersWebtoon, false)
|
||||
|
||||
fun readWithTapping() = rxPrefs.getBoolean(Keys.readWithTapping, true)
|
||||
|
||||
fun readWithVolumeKeys() = rxPrefs.getBoolean(Keys.readWithVolumeKeys, false)
|
||||
|
@ -1,10 +1,13 @@
|
||||
package eu.kanade.tachiyomi.data.updater
|
||||
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import retrofit2.http.GET
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
/**
|
||||
* Used to connect with the Github API.
|
||||
@ -17,6 +20,7 @@ interface GithubService {
|
||||
.baseUrl("https://api.github.com")
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||
.client(Injekt.get<NetworkHelper>().client)
|
||||
.build()
|
||||
|
||||
return restAdapter.create(GithubService::class.java)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package eu.kanade.tachiyomi.network
|
||||
|
||||
import com.squareup.duktape.Duktape
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Request
|
||||
@ -21,7 +22,7 @@ class CloudflareInterceptor : Interceptor {
|
||||
val response = chain.proceed(chain.request())
|
||||
|
||||
// Check if Cloudflare anti-bot is on
|
||||
if (response.code() == 503 && serverCheck.contains(response.header("Server"))) {
|
||||
if (response.code() == 503 && response.header("Server") in serverCheck) {
|
||||
return chain.proceed(resolveChallenge(response))
|
||||
}
|
||||
|
||||
@ -43,32 +44,33 @@ class CloudflareInterceptor : Interceptor {
|
||||
val pass = passPattern.find(content)?.groups?.get(1)?.value
|
||||
|
||||
if (operation == null || challenge == null || pass == null) {
|
||||
throw RuntimeException("Failed resolving Cloudflare challenge")
|
||||
throw Exception("Failed resolving Cloudflare challenge")
|
||||
}
|
||||
|
||||
val js = operation
|
||||
.replace(Regex("""a\.value =(.+?) \+.*"""), "$1")
|
||||
.replace(Regex("""a\.value = (.+ \+ t\.length).+"""), "$1")
|
||||
.replace(Regex("""\s{3,}[a-z](?: = |\.).+"""), "")
|
||||
.replace("t.length", "${domain.length}")
|
||||
.replace("\n", "")
|
||||
|
||||
val result = (duktape.evaluate(js) as Double).toInt()
|
||||
|
||||
val answer = "${result + domain.length}"
|
||||
val result = duktape.evaluate(js) as Double
|
||||
|
||||
val cloudflareUrl = HttpUrl.parse("${url.scheme()}://$domain/cdn-cgi/l/chk_jschl")!!
|
||||
.newBuilder()
|
||||
.addQueryParameter("jschl_vc", challenge)
|
||||
.addQueryParameter("pass", pass)
|
||||
.addQueryParameter("jschl_answer", answer)
|
||||
.addQueryParameter("jschl_answer", "$result")
|
||||
.toString()
|
||||
|
||||
val cloudflareHeaders = originalRequest.headers()
|
||||
.newBuilder()
|
||||
.add("Referer", url.toString())
|
||||
.add("Accept", "text/html,application/xhtml+xml,application/xml")
|
||||
.add("Accept-Language", "en")
|
||||
.build()
|
||||
|
||||
return GET(cloudflareUrl, cloudflareHeaders)
|
||||
return GET(cloudflareUrl, cloudflareHeaders, cache = CacheControl.Builder().build())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,22 @@
|
||||
package eu.kanade.tachiyomi.network
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import okhttp3.Cache
|
||||
import okhttp3.OkHttpClient
|
||||
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.SSLContext
|
||||
import javax.net.ssl.SSLSocket
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
class NetworkHelper(context: Context) {
|
||||
|
||||
@ -16,6 +29,7 @@ class NetworkHelper(context: Context) {
|
||||
val client = OkHttpClient.Builder()
|
||||
.cookieJar(cookieManager)
|
||||
.cache(Cache(cacheDir, cacheSize))
|
||||
.enableTLS12()
|
||||
.build()
|
||||
|
||||
val cloudflareClient = client.newBuilder()
|
||||
@ -25,4 +39,75 @@ class NetworkHelper(context: Context) {
|
||||
val cookies: PersistentCookieStore
|
||||
get() = cookieManager.store
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
@ -24,4 +24,8 @@ class Batoto : Source {
|
||||
return Observable.error(Exception("RIP Batoto"))
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$name (EN)"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -49,8 +49,12 @@ class Mangachan : ParsedHttpSource() {
|
||||
}
|
||||
}
|
||||
}
|
||||
is OrderBy -> { if (filter.state!!.ascending && filter.state!!.index == 0) { statusParam = false } }
|
||||
is Status -> status = arrayOf("", "all_done", "end", "ongoing", "new_ch")[filter.state]
|
||||
is OrderBy -> {
|
||||
if (filter.state!!.ascending && filter.state!!.index == 0) {
|
||||
statusParam = false
|
||||
}
|
||||
}
|
||||
is Status -> status = arrayOf("", "all_done", "end", "ongoing", "new_ch")[filter.state]
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +107,7 @@ class Mangachan : ParsedHttpSource() {
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.thumbnail_url = element.select("div.manga_images img").first().attr("src")
|
||||
element.select("h2 > a").first().let {
|
||||
manga.setUrlWithoutDomain(it.attr("href"))
|
||||
manga.title = it.text()
|
||||
@ -220,32 +225,22 @@ class Mangachan : ParsedHttpSource() {
|
||||
GenreList(getGenreList())
|
||||
)
|
||||
|
||||
// private class StatusList(status: List<Status>) : Filter.Group<Status>("Статус", status)
|
||||
// private class Status(name: String, val id: String) : Filter.CheckBox(name, false)
|
||||
// private fun getStatusList() = listOf(
|
||||
// Status("Перевод завершен", "/all_done"),
|
||||
// Status("Выпуск завершен", "/end"),
|
||||
// Status("Онгоинг", "/ongoing"),
|
||||
// Status("Новые главы", "/new_ch")
|
||||
// )
|
||||
|
||||
|
||||
/* [...document.querySelectorAll("li.sidetag > a:nth-child(1)")].map((el,i) =>
|
||||
* { const link=el.getAttribute('href');const id=link.substr(6,link.length);
|
||||
* return `Genre("${id.replace("_", " ")}")` }).join(',\n')
|
||||
/* [...document.querySelectorAll("li.sidetag > a:nth-child(1)")]
|
||||
* .map(el => `Genre("${el.getAttribute('href').substr(6)}")`).join(',\n')
|
||||
* on http://mangachan.me/
|
||||
*/
|
||||
private fun getGenreList() = listOf(
|
||||
Genre("18 плюс"),
|
||||
Genre("18_плюс"),
|
||||
Genre("bdsm"),
|
||||
Genre("арт"),
|
||||
Genre("боевик"),
|
||||
Genre("боевые искусства"),
|
||||
Genre("боевые_искусства"),
|
||||
Genre("вампиры"),
|
||||
Genre("веб"),
|
||||
Genre("гарем"),
|
||||
Genre("гендерная интрига"),
|
||||
Genre("героическое фэнтези"),
|
||||
Genre("гендерная_интрига"),
|
||||
Genre("героическое_фэнтези"),
|
||||
Genre("детектив"),
|
||||
Genre("дзёсэй"),
|
||||
Genre("додзинси"),
|
||||
@ -262,13 +257,13 @@ class Mangachan : ParsedHttpSource() {
|
||||
Genre("меха"),
|
||||
Genre("мистика"),
|
||||
Genre("музыка"),
|
||||
Genre("научная фантастика"),
|
||||
Genre("научная_фантастика"),
|
||||
Genre("повседневность"),
|
||||
Genre("постапокалиптика"),
|
||||
Genre("приключения"),
|
||||
Genre("психология"),
|
||||
Genre("романтика"),
|
||||
Genre("самурайский боевик"),
|
||||
Genre("самурайский_боевик"),
|
||||
Genre("сборник"),
|
||||
Genre("сверхъестественное"),
|
||||
Genre("сказка"),
|
||||
@ -279,7 +274,6 @@ class Mangachan : ParsedHttpSource() {
|
||||
Genre("сёдзё-ай"),
|
||||
Genre("сёнэн"),
|
||||
Genre("сёнэн-ай"),
|
||||
Genre("темное фэнтези"),
|
||||
Genre("тентакли"),
|
||||
Genre("трагедия"),
|
||||
Genre("триллер"),
|
||||
|
@ -24,23 +24,19 @@ class Mintmanga : ParsedHttpSource() {
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override fun headersBuilder() = Headers.Builder().apply {
|
||||
add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
||||
add("Referer", baseUrl)
|
||||
}
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request =
|
||||
GET("$baseUrl/list?sortType=rate&offset=${70 * (page - 1)}&max=70", headers)
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request =
|
||||
GET("$baseUrl/list?sortType=updated&offset=${70 * (page - 1)}&max=70", headers)
|
||||
|
||||
override fun popularMangaSelector() = "div.desc"
|
||||
override fun popularMangaSelector() = "div.tile"
|
||||
|
||||
override fun latestUpdatesSelector() = "div.desc"
|
||||
override fun latestUpdatesSelector() = "div.tile"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.thumbnail_url = element.select("img.lazy").first().attr("data-original")
|
||||
element.select("h3 > a").first().let {
|
||||
manga.setUrlWithoutDomain(it.attr("href"))
|
||||
manga.title = it.attr("title")
|
||||
@ -90,10 +86,15 @@ class Mintmanga : ParsedHttpSource() {
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val urlElement = element.select("a").first()
|
||||
val urlText = urlElement.text()
|
||||
|
||||
val chapter = SChapter.create()
|
||||
chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mature=1")
|
||||
chapter.name = urlElement.text().replace(" новое", "")
|
||||
chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mtr=1")
|
||||
if (urlText.endsWith(" новое")) {
|
||||
chapter.name = urlText.dropLast(6)
|
||||
} else {
|
||||
chapter.name = urlText
|
||||
}
|
||||
chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let {
|
||||
SimpleDateFormat("dd/MM/yy", Locale.US).parse(it).time
|
||||
} ?: 0
|
||||
@ -143,11 +144,19 @@ class Mintmanga : ParsedHttpSource() {
|
||||
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val imgHeader = Headers.Builder().apply {
|
||||
add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
||||
add("Referer", baseUrl)
|
||||
}.build()
|
||||
return GET(page.imageUrl!!, imgHeader)
|
||||
}
|
||||
|
||||
private class Genre(name: String, val id: String) : Filter.TriState(name)
|
||||
|
||||
/* [...document.querySelectorAll("tr.advanced_option:nth-child(1) > td:nth-child(3) span.js-link")].map((el,i) => {
|
||||
* const onClick=el.getAttribute('onclick');const id=onClick.substr(31,onClick.length-33);
|
||||
* return `Genre("${el.textContent.trim()}", "${id}")` }).join(',\n')
|
||||
/* [...document.querySelectorAll("tr.advanced_option:nth-child(1) > td:nth-child(3) span.js-link")]
|
||||
* .map(el => `Genre("${el.textContent.trim()}", $"{el.getAttribute('onclick')
|
||||
* .substr(31,el.getAttribute('onclick').length-33)"})`).join(',\n')
|
||||
* on http://mintmanga.com/search/advanced
|
||||
*/
|
||||
override fun getFilterList() = FilterList(
|
||||
|
@ -24,14 +24,9 @@ class Readmanga : ParsedHttpSource() {
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override fun headersBuilder() = Headers.Builder().apply {
|
||||
add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
||||
add("Referer", baseUrl)
|
||||
}
|
||||
override fun popularMangaSelector() = "div.tile"
|
||||
|
||||
override fun popularMangaSelector() = "div.desc"
|
||||
|
||||
override fun latestUpdatesSelector() = "div.desc"
|
||||
override fun latestUpdatesSelector() = "div.tile"
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request =
|
||||
GET("$baseUrl/list?sortType=rate&offset=${70 * (page - 1)}&max=70", headers)
|
||||
@ -41,6 +36,7 @@ class Readmanga : ParsedHttpSource() {
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.thumbnail_url = element.select("img.lazy").first().attr("data-original")
|
||||
element.select("h3 > a").first().let {
|
||||
manga.setUrlWithoutDomain(it.attr("href"))
|
||||
manga.title = it.attr("title")
|
||||
@ -90,10 +86,15 @@ class Readmanga : ParsedHttpSource() {
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val urlElement = element.select("a").first()
|
||||
val urlText = urlElement.text()
|
||||
|
||||
val chapter = SChapter.create()
|
||||
chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mature=1")
|
||||
chapter.name = urlElement.text().replace(" новое", "")
|
||||
chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mtr=1")
|
||||
if (urlText.endsWith(" новое")) {
|
||||
chapter.name = urlText.dropLast(6)
|
||||
} else {
|
||||
chapter.name = urlText
|
||||
}
|
||||
chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let {
|
||||
SimpleDateFormat("dd/MM/yy", Locale.US).parse(it).time
|
||||
} ?: 0
|
||||
@ -143,11 +144,19 @@ class Readmanga : ParsedHttpSource() {
|
||||
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val imgHeader = Headers.Builder().apply {
|
||||
add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
||||
add("Referer", baseUrl)
|
||||
}.build()
|
||||
return GET(page.imageUrl!!, imgHeader)
|
||||
}
|
||||
|
||||
private class Genre(name: String, val id: String) : Filter.TriState(name)
|
||||
|
||||
/* [...document.querySelectorAll("tr.advanced_option:nth-child(1) > td:nth-child(3) span.js-link")].map((el,i) => {
|
||||
* const onClick=el.getAttribute('onclick');const id=onClick.substr(31,onClick.length-33);
|
||||
* return `Genre("${el.textContent.trim()}", "${id}")` }).join(',\n')
|
||||
/* [...document.querySelectorAll("tr.advanced_option:nth-child(1) > td:nth-child(3) span.js-link")]
|
||||
* .map(el => `Genre("${el.textContent.trim()}", $"{el.getAttribute('onclick')
|
||||
* .substr(31,el.getAttribute('onclick').length-33)"})`).join(',\n')
|
||||
* on http://readmanga.me/search/advanced
|
||||
*/
|
||||
override fun getFilterList() = FilterList(
|
||||
|
@ -28,7 +28,7 @@ public class NucleusConductorDelegate<P extends Presenter> {
|
||||
|
||||
Bundle onSaveInstanceState() {
|
||||
Bundle bundle = new Bundle();
|
||||
getPresenter();
|
||||
// getPresenter(); // Workaround a crash related to saving instance state with child routers
|
||||
if (presenter != null) {
|
||||
presenter.save(bundle);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) :
|
||||
* @param manga the manga to find.
|
||||
*/
|
||||
fun indexOf(manga: Manga): Int {
|
||||
return mangas.indexOfFirst { it.manga.id == manga.id }
|
||||
return currentItems.indexOfFirst { it.manga.id == manga.id }
|
||||
}
|
||||
|
||||
fun performFilter() {
|
||||
|
@ -73,7 +73,7 @@ class LibraryController(
|
||||
/**
|
||||
* Currently selected mangas.
|
||||
*/
|
||||
val selectedMangas = mutableListOf<Manga>()
|
||||
val selectedMangas = mutableSetOf<Manga>()
|
||||
|
||||
private var selectedCoverManga: Manga? = null
|
||||
|
||||
@ -429,11 +429,13 @@ class LibraryController(
|
||||
*/
|
||||
fun setSelection(manga: Manga, selected: Boolean) {
|
||||
if (selected) {
|
||||
selectedMangas.add(manga)
|
||||
selectionRelay.call(LibrarySelectionEvent.Selected(manga))
|
||||
if (selectedMangas.add(manga)) {
|
||||
selectionRelay.call(LibrarySelectionEvent.Selected(manga))
|
||||
}
|
||||
} else {
|
||||
selectedMangas.remove(manga)
|
||||
selectionRelay.call(LibrarySelectionEvent.Unselected(manga))
|
||||
if (selectedMangas.remove(manga)) {
|
||||
selectionRelay.call(LibrarySelectionEvent.Unselected(manga))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,11 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||
}
|
||||
|
||||
fun setLastUpdateDate(date: Date) {
|
||||
manga_last_update?.text = DateFormat.getDateInstance(DateFormat.SHORT).format(date)
|
||||
if (date.time != 0L) {
|
||||
manga_last_update?.text = DateFormat.getDateInstance(DateFormat.SHORT).format(date)
|
||||
} else {
|
||||
manga_last_update?.text = resources?.getString(R.string.unknown)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,9 +8,9 @@ import com.jakewharton.rxbinding.widget.itemClicks
|
||||
import com.jakewharton.rxbinding.widget.textChanges
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.util.plusAssign
|
||||
import kotlinx.android.synthetic.main.track_search_dialog.view.*
|
||||
@ -114,14 +114,14 @@ class TrackSearchDialog : DialogController {
|
||||
private fun search(query: String) {
|
||||
val view = dialogView ?: return
|
||||
view.progress.visibility = View.VISIBLE
|
||||
view.track_search_list.visibility = View.GONE
|
||||
view.track_search_list.visibility = View.INVISIBLE
|
||||
trackController.presenter.search(query, service)
|
||||
}
|
||||
|
||||
fun onSearchResults(results: List<TrackSearch>) {
|
||||
selectedItem = null
|
||||
val view = dialogView ?: return
|
||||
view.progress.visibility = View.GONE
|
||||
view.progress.visibility = View.INVISIBLE
|
||||
view.track_search_list.visibility = View.VISIBLE
|
||||
adapter?.setItems(results)
|
||||
}
|
||||
@ -129,7 +129,7 @@ class TrackSearchDialog : DialogController {
|
||||
fun onSearchResultsError() {
|
||||
val view = dialogView ?: return
|
||||
view.progress.visibility = View.VISIBLE
|
||||
view.track_search_list.visibility = View.GONE
|
||||
view.track_search_list.visibility = View.INVISIBLE
|
||||
adapter?.setItems(emptyList())
|
||||
}
|
||||
|
||||
@ -141,4 +141,4 @@ class TrackSearchDialog : DialogController {
|
||||
const val KEY_SERVICE = "service_id"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.util.plusAssign
|
||||
import eu.kanade.tachiyomi.util.visibleIf
|
||||
import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
|
||||
import kotlinx.android.synthetic.main.reader_settings_dialog.view.*
|
||||
import rx.Observable
|
||||
@ -91,6 +92,23 @@ class ReaderSettingsDialog : DialogFragment() {
|
||||
crop_borders.setOnCheckedChangeListener { _, isChecked ->
|
||||
preferences.cropBorders().set(isChecked)
|
||||
}
|
||||
|
||||
crop_borders_webtoon.isChecked = preferences.cropBordersWebtoon().getOrDefault()
|
||||
crop_borders_webtoon.setOnCheckedChangeListener { _, isChecked ->
|
||||
preferences.cropBordersWebtoon().set(isChecked)
|
||||
}
|
||||
|
||||
val readerActivity = activity as? ReaderActivity
|
||||
val isWebtoonViewer = if (readerActivity != null) {
|
||||
val mangaViewer = readerActivity.presenter.manga.viewer
|
||||
val viewer = if (mangaViewer == 0) preferences.defaultViewer() else mangaViewer
|
||||
viewer == ReaderActivity.WEBTOON
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
crop_borders.visibleIf { !isWebtoonViewer }
|
||||
crop_borders_webtoon.visibleIf { isWebtoonViewer }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
@ -98,4 +116,4 @@ class ReaderSettingsDialog : DialogFragment() {
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,12 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.*
|
||||
import android.view.Display
|
||||
import android.view.GestureDetector
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
@ -123,7 +128,7 @@ class WebtoonReader : BaseReader() {
|
||||
.distinctUntilChanged()
|
||||
.subscribe { refreshAdapter() })
|
||||
|
||||
subscriptions.add(readerActivity.preferences.cropBorders()
|
||||
subscriptions.add(readerActivity.preferences.cropBordersWebtoon()
|
||||
.asObservable()
|
||||
.doOnNext { cropBorders = it }
|
||||
.skip(1)
|
||||
|
@ -126,6 +126,7 @@ class SettingsAboutController : SettingsController() {
|
||||
}
|
||||
}
|
||||
}, { error ->
|
||||
activity?.toast(error.message)
|
||||
Timber.e(error)
|
||||
})
|
||||
}
|
||||
|
@ -29,8 +29,9 @@ class SettingsGeneralController : SettingsController() {
|
||||
listPreference {
|
||||
key = Keys.lang
|
||||
titleRes = R.string.pref_language
|
||||
entryValues = arrayOf("", "ar", "bg", "bn", "de", "en", "es", "fr", "hi", "hu", "id",
|
||||
"it", "ja", "ko", "lv", "ms", "nl", "pl", "pt", "pt-BR", "ro", "ru", "vi")
|
||||
entryValues = arrayOf("", "ar", "bg", "bn", "de", "en-US", "en-GB", "es", "fr", "hi",
|
||||
"hu", "id", "it", "ja", "ko", "lv", "ms", "nl", "pl", "pt", "pt-BR", "ro",
|
||||
"ru", "vi")
|
||||
entries = entryValues.map { value ->
|
||||
val locale = LocaleHelper.getLocaleFromString(value.toString())
|
||||
locale?.getDisplayName(locale)?.capitalize() ?:
|
||||
|
@ -76,8 +76,8 @@ class SettingsReaderController : SettingsController() {
|
||||
defaultValue = true
|
||||
}
|
||||
switchPreference {
|
||||
key = Keys.enableTransitions
|
||||
titleRes = R.string.pref_page_transitions
|
||||
key = Keys.keepScreenOn
|
||||
titleRes = R.string.pref_keep_screen_on
|
||||
defaultValue = true
|
||||
}
|
||||
switchPreference {
|
||||
@ -85,15 +85,28 @@ class SettingsReaderController : SettingsController() {
|
||||
titleRes = R.string.pref_show_page_number
|
||||
defaultValue = true
|
||||
}
|
||||
switchPreference {
|
||||
key = Keys.cropBorders
|
||||
titleRes = R.string.pref_crop_borders
|
||||
defaultValue = false
|
||||
preferenceCategory {
|
||||
titleRes = R.string.pager_viewer
|
||||
|
||||
switchPreference {
|
||||
key = Keys.enableTransitions
|
||||
titleRes = R.string.pref_page_transitions
|
||||
defaultValue = true
|
||||
}
|
||||
switchPreference {
|
||||
key = Keys.cropBorders
|
||||
titleRes = R.string.pref_crop_borders
|
||||
defaultValue = false
|
||||
}
|
||||
}
|
||||
switchPreference {
|
||||
key = Keys.keepScreenOn
|
||||
titleRes = R.string.pref_keep_screen_on
|
||||
defaultValue = true
|
||||
preferenceCategory {
|
||||
titleRes = R.string.webtoon_viewer
|
||||
|
||||
switchPreference {
|
||||
key = Keys.cropBordersWebtoon
|
||||
titleRes = R.string.pref_crop_borders
|
||||
defaultValue = false
|
||||
}
|
||||
}
|
||||
preferenceCategory {
|
||||
titleRes = R.string.pref_reader_navigation
|
||||
@ -116,4 +129,4 @@ class SettingsReaderController : SettingsController() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT)
|
||||
* @param duration the duration of the toast. Defaults to short.
|
||||
*/
|
||||
fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT) {
|
||||
Toast.makeText(this, text, duration).show()
|
||||
Toast.makeText(this, text.orEmpty(), duration).show()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,6 +47,10 @@ inline fun View.gone() {
|
||||
visibility = View.GONE
|
||||
}
|
||||
|
||||
inline fun View.visibleIf(block: () -> Boolean) {
|
||||
visibility = if (block()) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a TextDrawable determined by input
|
||||
*
|
||||
@ -63,4 +67,4 @@ fun View.getRound(text: String, random : Boolean = true): TextDrawable {
|
||||
.useFont(Typeface.DEFAULT)
|
||||
.endConfig()
|
||||
.buildRound(text, if (random) ColorGenerator.MATERIAL.randomColor else ColorGenerator.MATERIAL.getColor(text))
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@
|
||||
tools:text="122"
|
||||
tools:visibility="visible"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintRight_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
@ -63,7 +63,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_more_vert_black_24dp"
|
||||
app:layout_constraintRight_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="16dp"
|
||||
@ -82,7 +82,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="DOWNLOADED"
|
||||
android:textAllCaps="true"
|
||||
app:layout_constraintRight_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginRight="16dp"/>
|
||||
|
||||
|
@ -27,13 +27,16 @@
|
||||
<TextView
|
||||
android:id="@+id/ext_title"
|
||||
style="@style/TextAppearance.Regular"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.Regular.SubHeading"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintStart_toEndOf="@id/image"
|
||||
app:layout_constraintEnd_toStartOf="@id/ext_button"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/lang"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
|
@ -259,32 +259,38 @@
|
||||
<android.support.v4.widget.NestedScrollView
|
||||
android:id="@+id/description_scrollview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintBottom_toTopOf="@id/manga_genres_tags"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/manga_summary_label"
|
||||
app:layout_constraintBottom_toTopOf="@id/manga_genres_tags">
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintVertical_chainStyle="packed">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_summary"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="false"/>
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
</android.support.v4.widget.NestedScrollView>
|
||||
|
||||
<me.gujun.android.taggroup.TagGroup
|
||||
android:id="@+id/manga_genres_tags"
|
||||
style="@style/TagGroup"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/description_scrollview"
|
||||
|
@ -171,10 +171,16 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pref_crop_borders"/>
|
||||
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:id="@+id/crop_borders_webtoon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pref_crop_borders"/>
|
||||
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:id="@+id/fullscreen"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pref_fullscreen"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout
|
||||
<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="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<EditText
|
||||
@ -14,52 +13,49 @@
|
||||
android:hint="@string/title"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:maxLines="1"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
android:inputType="text"
|
||||
android:maxLines="1"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/divider1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/track_search"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/track_search_list"
|
||||
style="@style/Theme.Widget.CardView"
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="40dp"
|
||||
android:choiceMode="singleChoice"
|
||||
android:clipToPadding="false"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="10dp"
|
||||
android:footerDividersEnabled="true"
|
||||
android:headerDividersEnabled="true"
|
||||
android:listSelector="?attr/selectable_list_drawable"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingTop="4dp"
|
||||
android:scrollbars="none"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/track_search"
|
||||
tools:listitem="@layout/track_search_item"
|
||||
tools:visibility="visible"/>
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/track_search_list"
|
||||
style="@style/Theme.Widget.CardView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:choiceMode="singleChoice"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="10dp"
|
||||
android:footerDividersEnabled="true"
|
||||
android:headerDividersEnabled="true"
|
||||
android:listSelector="?attr/selectable_list_drawable"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingTop="4dp"
|
||||
android:scrollbars="none"
|
||||
android:visibility="invisible"
|
||||
tools:listitem="@layout/track_search_item"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?android:attr/divider"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/track_search_list"/>
|
||||
android:background="?android:attr/divider"/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
@ -12,7 +12,6 @@
|
||||
android:layout_height="216dp"
|
||||
android:background="?attr/selectable_list_drawable"
|
||||
android:orientation="horizontal">
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/track_search_cover"
|
||||
@ -161,4 +160,4 @@
|
||||
app:layout_constraintGuide_begin="150dp"/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
</android.support.v7.widget.CardView>
|
||||
</android.support.v7.widget.CardView>
|
||||
|
@ -1,5 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<changelog bulletedList="true">
|
||||
<changelogversion versionName="v0.7.3" changeDate="">
|
||||
<changelogtext>Fixed the tracking search layout when there are many results.</changelogtext>
|
||||
|
||||
<changelogtext>Separate english language into american and british so that dates are formatted according to that locale.</changelogtext>
|
||||
|
||||
<changelogtext>Added Firebase analytics, for Android API distribution.</changelogtext>
|
||||
|
||||
<changelogtext>Crop borders for webtoons now has a separate setting.</changelogtext>
|
||||
|
||||
<changelogtext>The downloader now runs in a foreground service to prevent it from being killed.</changelogtext>
|
||||
|
||||
<changelogtext>Fixed a few weird crashes.</changelogtext>
|
||||
</changelogversion>
|
||||
|
||||
<changelogversion versionName="v0.7.2" changeDate="">
|
||||
<changelogtext>Fixed missing downloaded label in chapters screen.</changelogtext>
|
||||
|
||||
<changelogtext>Fixed updater in KitKat and lower due to TLS.</changelogtext>
|
||||
</changelogversion>
|
||||
|
||||
<changelogversion versionName="v0.7.1" changeDate="">
|
||||
<changelogtext>Updated Cloudflare bypass.</changelogtext>
|
||||
|
||||
<changelogtext>Enabled TLS 1.1 and TLS 1.2 on Android KitKat and lower.</changelogtext>
|
||||
|
||||
<changelogtext>Minor UI changes.</changelogtext>
|
||||
</changelogversion>
|
||||
|
||||
<changelogversion versionName="v0.7.0" changeDate="">
|
||||
<changelogtext>Added extensions support. You can now install and update extensions within the app.
|
||||
If you installed any extension previously through F-Droid, you'll have to uninstall them first.</changelogtext>
|
||||
|
@ -11,7 +11,7 @@
|
||||
<string name="label_recent_updates">Nouveautés bibliothèque</string>
|
||||
<string name="label_latest_updates">Dernières nouveautés</string>
|
||||
<string name="label_categories">Catégories</string>
|
||||
<string name="label_selected">Sélectionné: %1$d</string>
|
||||
<string name="label_selected">Sélectionné : %1$d</string>
|
||||
<string name="label_backup">Sauvegarde</string>
|
||||
|
||||
<!-- Actions -->
|
||||
@ -57,7 +57,7 @@
|
||||
<string name="action_retry">Réessayer</string>
|
||||
<string name="action_remove">Supprimer</string>
|
||||
<string name="action_resume">Reprendre</string>
|
||||
<string name="action_open_in_browser">Ouvre dans le navigateur</string>
|
||||
<string name="action_open_in_browser">Ouvrir dans le navigateur</string>
|
||||
<string name="action_add_to_home_screen">Ajouter à l\'écran d\'accueil</string>
|
||||
<string name="action_display_mode">Changer le mode d\'affichage</string>
|
||||
<string name="action_display">Affichage</string>
|
||||
@ -152,9 +152,9 @@
|
||||
<string name="rotation_force_portrait">Forcer portrait</string>
|
||||
<string name="rotation_force_landscape">Forcer paysage</string>
|
||||
<string name="color_filter_r_value">R</string>
|
||||
<string name="color_filter_g_value">G</string>
|
||||
<string name="color_filter_g_value">V</string>
|
||||
<string name="color_filter_b_value">B</string>
|
||||
<string name="color_filter_a_value">A</string>
|
||||
<string name="color_filter_a_value">O</string>
|
||||
|
||||
|
||||
<!-- Downloads section -->
|
||||
@ -164,7 +164,7 @@
|
||||
<string name="pref_remove_after_read">Supprimer après avoir lu</string>
|
||||
<string name="disabled">Désactivé</string>
|
||||
<string name="last_read_chapter">Dernier chapitre lu</string>
|
||||
<string name="second_to_last">Avant-dernier chapiture lu</string>
|
||||
<string name="second_to_last">Avant-dernier chapitre lu</string>
|
||||
<string name="third_to_last">Du troisième au dernier chapitre</string>
|
||||
<string name="fourth_to_last">Du quatrième au dernier chapitre</string>
|
||||
<string name="pref_download_new">Télécharger les nouveaux chapitres</string>
|
||||
@ -286,7 +286,7 @@
|
||||
|
||||
<!-- Reader activity -->
|
||||
<string name="custom_filter">Filtre personnalisé</string>
|
||||
<string name="set_as_cover">Mettre comme couverture</string>
|
||||
<string name="set_as_cover">Ajouter comme couverture</string>
|
||||
<string name="cover_updated">Couverture mise à jour</string>
|
||||
<string name="page_downloaded">Page copiée vers %1$s</string>
|
||||
<string name="downloading">En cours de téléchargement…</string>
|
||||
@ -313,7 +313,7 @@
|
||||
<string name="notification_update_progress">Progression mise à jour: %1$d/%2$d</string>
|
||||
<string name="notification_new_chapters">Des nouveaux chapitres ont été trouvés</string>
|
||||
<string name="notification_cover_update_failed">La mise à jour de la couverture a échoué</string>
|
||||
<string name="notification_first_add_to_library">Veuillez ajouter le manga dans votre bibliothèque avant de faire cela</string>
|
||||
<string name="notification_first_add_to_library">Veuillez ajouter le manga dans votre bibliothèque avant</string>
|
||||
<string name="notification_not_connected_to_ac_body">Non branché</string>
|
||||
<string name="notification_no_connection_title">Synchronisation annulée</string>
|
||||
<string name="notification_no_connection_body">Connexion non disponible</string>
|
||||
@ -324,15 +324,15 @@
|
||||
<string name="file_select_icon">Sélectionner une icône de raccourci</string>
|
||||
|
||||
<!--UpdateCheck-->
|
||||
<string name="update_check_title">Nouvelle mise à jour disponible!</string>
|
||||
<string name="update_check_title">Nouvelle mise à jour disponible !</string>
|
||||
<string name="update_check_confirm">Télécharger</string>
|
||||
<string name="update_check_ignore">Ignorer</string>
|
||||
<string name="update_check_no_new_updates">Aucun mise à jour disponible</string>
|
||||
<string name="update_check_no_new_updates">Aucune mise à jour disponible</string>
|
||||
<string name="update_check_download_started">Téléchargement commencé</string>
|
||||
<string name="update_check_look_for_updates">Vérification des mises à jour</string>
|
||||
|
||||
<!--UpdateCheck Notifications-->
|
||||
<string name="update_check_notification_file_download">Télécharger mise à jour</string>
|
||||
<string name="update_check_notification_file_download">Télécharger la mise à jour</string>
|
||||
<string name="update_check_notification_download_in_progress">Téléchargement en cours</string>
|
||||
<string name="update_check_notification_download_complete">Téléchargement terminé</string>
|
||||
<string name="update_check_notification_download_error">Erreur lors du téléchargement</string>
|
||||
@ -400,12 +400,12 @@
|
||||
<string name="pref_backup_directory">Dossier de sauvegarde</string>
|
||||
<string name="pref_backup_service_category">Service</string>
|
||||
<string name="source_not_found">Source introuvable</string>
|
||||
<string name="restore_completed">Restauration terminé</string>
|
||||
<string name="restore_completed">Restauration terminée</string>
|
||||
<string name="error_opening_log">Impossible d\'ouvrir le fichier journal</string>
|
||||
<string name="file_saved">Fichier enregistré dans %1$s</string>
|
||||
<string name="backup_choice">Que voulez-vous sauvegarder?</string>
|
||||
<string name="backup_choice">Que voulez-vous sauvegarder ?</string>
|
||||
<string name="invalid_combination">Le défaut ne peut pas être selectionné avec des autres catégories</string>
|
||||
<string name="delete_downloads_for_manga">Supprimer les chapitres téléchargés?</string>
|
||||
<string name="delete_downloads_for_manga">Supprimer les chapitres téléchargés ?</string>
|
||||
|
||||
<string name="notification_new_chapters_text">Pour %1$s chapitres</string>
|
||||
<string name="track">Suivi</string>
|
||||
@ -439,7 +439,7 @@
|
||||
|
||||
<string name="pref_read_with_volume_keys_inverted">Inverse les boutons de volume</string>
|
||||
<string name="pref_crop_borders">Rogner les bordures</string>
|
||||
<string name="backup_restore_content">La restauration utilise le source pour obtenir des données, des frais de l\'opérateur peuvent s\'appliquer.
|
||||
<string name="backup_restore_content">La restauration utilise la source pour obtenir des données, des frais de l\'opérateur peuvent s\'appliquer.
|
||||
Assurez-vous que vous êtes connecté à des sources qui le demande avant de commencer la restauration.</string>
|
||||
<string name="action_global_search">Recherche globale</string>
|
||||
<string name="action_open">Ouvrir</string>
|
||||
@ -447,7 +447,7 @@ Assurez-vous que vous êtes connecté à des sources qui le demande avant de com
|
||||
|
||||
<string name="other_source">Autre</string>
|
||||
<string name="action_global_search_hint">Recherche globale…</string>
|
||||
<string name="no_results">Aucun résultat!</string>
|
||||
<string name="no_results">Aucun résultat !</string>
|
||||
<string name="latest">Récents</string>
|
||||
<string name="browse">Explorer</string>
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
<!-- 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/colorAmoled</item>
|
||||
<item name="android:navigationBarColor">@color/colorAmoledPrimary</item>
|
||||
</style>
|
||||
|
||||
<!--==============-->
|
||||
|
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Application Colors -->
|
||||
<color name="colorPrimary">#54759e</color>
|
||||
<color name="colorPrimaryDark">#435e7e</color>
|
||||
<color name="colorPrimary">#54759E</color>
|
||||
<color name="colorPrimaryDark">#435E7E</color>
|
||||
<!-- Dark Application Colors -->
|
||||
<color name="colorDarkPrimary">#212121</color>
|
||||
<color name="colorDarkPrimaryDark">#1c1c1d</color>
|
||||
<color name="colorAmoled">@color/md_black_1000</color>
|
||||
<color name="colorDarkPrimaryDark">#1C1C1D</color>
|
||||
<color name="colorAmoledPrimary">@color/md_black_1000</color>
|
||||
|
||||
<!-- Light Theme -->
|
||||
<color name="colorAccentLight">@color/md_blue_A400</color>
|
||||
@ -27,7 +27,7 @@
|
||||
<color name="iconColorLight">@color/md_black_1000</color>
|
||||
|
||||
<!-- Dark Theme -->
|
||||
<color name="colorAccentDark">#3399ff</color>
|
||||
<color name="colorAccentDark">#3399FF</color>
|
||||
<color name="textColorPrimaryDark">@color/md_white_1000</color>
|
||||
<color name="textColorSecondaryDark">@color/md_white_1000_70</color>
|
||||
<color name="textColorHintDark">@color/md_white_1000_50</color>
|
||||
@ -36,7 +36,7 @@
|
||||
|
||||
<color name="statusBarDark">@color/md_black_1000</color>
|
||||
<color name="appBarDark">@color/md_grey_900</color>
|
||||
<color name="backgroundDark">#1c1c1d</color>
|
||||
<color name="backgroundDark">@color/colorDarkPrimaryDark</color>
|
||||
<color name="dialogDark">@color/colorDarkPrimary</color>
|
||||
<color name="dialog_amoled">@color/colorDarkPrimaryDark</color>
|
||||
|
||||
|
@ -190,6 +190,7 @@
|
||||
<string name="right_to_left_viewer">Right to left</string>
|
||||
<string name="vertical_viewer">Vertical</string>
|
||||
<string name="webtoon_viewer">Webtoon</string>
|
||||
<string name="pager_viewer">Pager</string>
|
||||
<string name="pref_image_decoder">Image decoder</string>
|
||||
<string name="pref_image_scale_type">Scale type</string>
|
||||
<string name="scale_type_fit_screen">Fit screen</string>
|
||||
|
@ -66,6 +66,7 @@
|
||||
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
|
||||
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.Material</item>
|
||||
<item name="md_background_color">@color/dialogDark</item>
|
||||
<item name="alertDialogTheme">@style/Theme.AlertDialog.Dark</item>
|
||||
|
||||
|
||||
@ -86,8 +87,8 @@
|
||||
<!-- Amoled Theme -->
|
||||
<!--==============-->
|
||||
<style name="Theme.Base.Amoled" parent="Theme.Base.Dark">
|
||||
<item name="colorPrimary">@color/colorAmoled</item>
|
||||
<item name="colorPrimaryDark">@color/colorAmoled</item>
|
||||
<item name="colorPrimary">@color/colorAmoledPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorAmoledPrimary</item>
|
||||
<item name="android:colorBackground">@color/md_black_1000</item>
|
||||
|
||||
<!-- Custom Attributes-->
|
||||
|
@ -7,9 +7,10 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.17.0'
|
||||
classpath 'com.github.zellius:android-shortcut-gradle-plugin:0.1.2'
|
||||
classpath 'com.google.gms:google-services:3.2.0'
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
#Wed Oct 25 23:17:30 CEST 2017
|
||||
#Thu Apr 05 09:21:32 CEST 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
||||
|
Reference in New Issue
Block a user