mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-19 01:39:19 +01:00
Merge branch 'dev' into dev-settings-search
This commit is contained in:
commit
528c1b90c2
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
I acknowledge that:
|
I acknowledge that:
|
||||||
|
|
||||||
- I have updated to the latest version of the app (stable is v0.10.4)
|
- I have updated to the latest version of the app (stable is v0.10.5)
|
||||||
- I have updated all extensions
|
- I have updated all extensions
|
||||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
|
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
|
||||||
|
|
||||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -9,7 +9,7 @@ labels: "bug"
|
|||||||
|
|
||||||
I acknowledge that:
|
I acknowledge that:
|
||||||
|
|
||||||
- I have updated to the latest version of the app (stable is v0.10.4)
|
- I have updated to the latest version of the app (stable is v0.10.5)
|
||||||
- I have updated all extensions
|
- I have updated all extensions
|
||||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
|
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
|
||||||
|
|
||||||
|
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -9,7 +9,7 @@ labels: "feature"
|
|||||||
|
|
||||||
I acknowledge that:
|
I acknowledge that:
|
||||||
|
|
||||||
- I have updated to the latest version of the app (stable is v0.10.4)
|
- I have updated to the latest version of the app (stable is v0.10.5)
|
||||||
- I have updated all extensions
|
- I have updated all extensions
|
||||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
|
- If this is an issue with an extension, that I should be opening an issue in https://github.com/inorichi/tachiyomi-extensions
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
| Build | Stable | Weekly Preview | Contribute | Support Server |
|
| Build | Stable | Weekly Preview | Contribute | Support Server |
|
||||||
|-------|----------|---------|------------|---------|
|
|-------|----------|---------|------------|---------|
|
||||||
| [![Travis](https://img.shields.io/travis/inorichi/tachiyomi.svg)](https://travis-ci.org/inorichi/tachiyomi) | [![stable release](https://img.shields.io/github/release/inorichi/tachiyomi.svg?maxAge=3600&label=download)](https://github.com/inorichi/tachiyomi/releases) | [![latest weekly build](https://img.shields.io/badge/download-latest%20build-blue.svg)](http://tachiyomi.kanade.eu/latest) | [![Translation status](https://hosted.weblate.org/widgets/tachiyomi/-/svg-badge.svg)](https://hosted.weblate.org/engage/tachiyomi/?utm_source=widget) | [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) |
|
| [![Travis](https://img.shields.io/travis/inorichi/tachiyomi.svg)](https://travis-ci.org/inorichi/tachiyomi) | [![stable release](https://img.shields.io/github/release/inorichi/tachiyomi.svg?maxAge=3600&label=download)](https://github.com/inorichi/tachiyomi/releases) | [![latest weekly build](https://img.shields.io/github/v/release/tachiyomiorg/android-app-preview.svg?maxAge=3600&label=download)](https://github.com/tachiyomiorg/android-app-preview/releases) | [![Translation status](https://hosted.weblate.org/widgets/tachiyomi/-/svg-badge.svg)](https://hosted.weblate.org/engage/tachiyomi/?utm_source=widget) | [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) |
|
||||||
|
|
||||||
|
|
||||||
# ![app icon](./.github/readme-images/app-icon.png)Tachiyomi
|
# ![app icon](./.github/readme-images/app-icon.png)Tachiyomi
|
||||||
@ -23,7 +23,7 @@ Features include:
|
|||||||
## Download
|
## Download
|
||||||
Get the app from our [releases page](https://github.com/inorichi/tachiyomi/releases).
|
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 preview version [here](http://tachiyomi.kanade.eu/latest).
|
If you want to try new features before they get to the stable release, you can download the preview version [here](https://github.com/tachiyomiorg/android-app-preview/releases).
|
||||||
|
|
||||||
## Issues, Feature Requests and Contributing
|
## Issues, Feature Requests and Contributing
|
||||||
|
|
||||||
|
@ -40,8 +40,8 @@ android {
|
|||||||
minSdkVersion AndroidConfig.minSdk
|
minSdkVersion AndroidConfig.minSdk
|
||||||
targetSdkVersion AndroidConfig.targetSdk
|
targetSdkVersion AndroidConfig.targetSdk
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
versionCode 50
|
versionCode 51
|
||||||
versionName "0.10.4"
|
versionName "0.10.5"
|
||||||
|
|
||||||
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
|
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
|
||||||
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
|
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
|
||||||
@ -133,7 +133,7 @@ dependencies {
|
|||||||
implementation 'androidx.biometric:biometric:1.1.0-alpha02'
|
implementation 'androidx.biometric:biometric:1.1.0-alpha02'
|
||||||
implementation 'androidx.browser:browser:1.2.0'
|
implementation 'androidx.browser:browser:1.2.0'
|
||||||
implementation 'androidx.cardview:cardview:1.0.0'
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||||
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
|
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
|
||||||
implementation 'androidx.core:core-ktx:1.4.0-alpha01'
|
implementation 'androidx.core:core-ktx:1.4.0-alpha01'
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
@ -163,14 +163,14 @@ dependencies {
|
|||||||
implementation 'com.github.pwittchen:reactivenetwork:0.13.0'
|
implementation 'com.github.pwittchen:reactivenetwork:0.13.0'
|
||||||
|
|
||||||
// Network client
|
// Network client
|
||||||
final okhttp_version = '4.8.1'
|
final okhttp_version = '4.9.0'
|
||||||
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
||||||
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
|
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
|
||||||
implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:$okhttp_version"
|
implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:$okhttp_version"
|
||||||
implementation 'com.squareup.okio:okio:2.7.0'
|
implementation 'com.squareup.okio:okio:2.8.0'
|
||||||
|
|
||||||
// TLS 1.3 support for Android < 10
|
// TLS 1.3 support for Android < 10
|
||||||
implementation 'org.conscrypt:conscrypt-android:2.4.0'
|
implementation 'org.conscrypt:conscrypt-android:2.5.1'
|
||||||
|
|
||||||
// REST
|
// REST
|
||||||
final retrofit_version = '2.9.0'
|
final retrofit_version = '2.9.0'
|
||||||
@ -281,10 +281,6 @@ dependencies {
|
|||||||
|
|
||||||
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
||||||
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
|
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
|
||||||
|
|
||||||
// Debug tool; see https://fbflipper.com/
|
|
||||||
// debugImplementation 'com.facebook.flipper:flipper:0.50.0'
|
|
||||||
// debugImplementation 'com.facebook.soloader:soloader:0.9.0'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
@ -312,7 +308,7 @@ task copyResources(type: Copy) {
|
|||||||
include '**/*'
|
include '**/*'
|
||||||
}
|
}
|
||||||
|
|
||||||
preBuild.dependsOn(ktlintFormat, copyResources)
|
preBuild.dependsOn(formatKotlin, copyResources)
|
||||||
|
|
||||||
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) {
|
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) {
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
|
@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.data.notification.Notifications
|
|||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import java.security.Security
|
|
||||||
import org.acra.ACRA
|
import org.acra.ACRA
|
||||||
import org.acra.annotation.AcraCore
|
import org.acra.annotation.AcraCore
|
||||||
import org.acra.annotation.AcraHttpSender
|
import org.acra.annotation.AcraHttpSender
|
||||||
@ -24,6 +23,7 @@ import uy.kohesive.injekt.Injekt
|
|||||||
import uy.kohesive.injekt.api.InjektScope
|
import uy.kohesive.injekt.api.InjektScope
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import uy.kohesive.injekt.registry.default.DefaultRegistrar
|
import uy.kohesive.injekt.registry.default.DefaultRegistrar
|
||||||
|
import java.security.Security
|
||||||
|
|
||||||
@AcraCore(
|
@AcraCore(
|
||||||
buildConfigClass = BuildConfig::class,
|
buildConfigClass = BuildConfig::class,
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package eu.kanade.tachiyomi
|
package eu.kanade.tachiyomi
|
||||||
|
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdaterJob
|
import eu.kanade.tachiyomi.data.updater.UpdaterJob
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||||
import eu.kanade.tachiyomi.ui.library.LibrarySort
|
import eu.kanade.tachiyomi.ui.library.LibrarySort
|
||||||
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object Migrations {
|
object Migrations {
|
||||||
@ -89,6 +93,25 @@ object Migrations {
|
|||||||
preferences.librarySortingMode().set(LibrarySort.ALPHA)
|
preferences.librarySortingMode().set(LibrarySort.ALPHA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (oldVersion < 52) {
|
||||||
|
// Migrate library filters to tri-state versions
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
fun convertBooleanPrefToTriState(key: String): Int {
|
||||||
|
val oldPrefValue = prefs.getBoolean(key, false)
|
||||||
|
return if (oldPrefValue) ExtendedNavigationView.Item.TriStateGroup.STATE_INCLUDE
|
||||||
|
else ExtendedNavigationView.Item.TriStateGroup.STATE_IGNORE
|
||||||
|
}
|
||||||
|
prefs.edit {
|
||||||
|
putInt(PreferenceKeys.filterDownloaded, convertBooleanPrefToTriState("pref_filter_downloaded_key"))
|
||||||
|
remove("pref_filter_downloaded_key")
|
||||||
|
|
||||||
|
putInt(PreferenceKeys.filterUnread, convertBooleanPrefToTriState("pref_filter_unread_key"))
|
||||||
|
remove("pref_filter_unread_key")
|
||||||
|
|
||||||
|
putInt(PreferenceKeys.filterCompleted, convertBooleanPrefToTriState("pref_filter_completed_key"))
|
||||||
|
remove("pref_filter_completed_key")
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -8,9 +8,9 @@ import androidx.work.WorkManager
|
|||||||
import androidx.work.Worker
|
import androidx.work.Worker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class BackupCreatorJob(private val context: Context, workerParams: WorkerParameters) :
|
class BackupCreatorJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
Worker(context, workerParams) {
|
Worker(context, workerParams) {
|
||||||
@ -36,8 +36,10 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
val interval = prefInterval ?: preferences.backupInterval().get()
|
val interval = prefInterval ?: preferences.backupInterval().get()
|
||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
val request = PeriodicWorkRequestBuilder<BackupCreatorJob>(
|
val request = PeriodicWorkRequestBuilder<BackupCreatorJob>(
|
||||||
interval.toLong(), TimeUnit.HOURS,
|
interval.toLong(),
|
||||||
10, TimeUnit.MINUTES
|
TimeUnit.HOURS,
|
||||||
|
10,
|
||||||
|
TimeUnit.MINUTES
|
||||||
)
|
)
|
||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.build()
|
.build()
|
||||||
|
@ -50,10 +50,10 @@ import eu.kanade.tachiyomi.source.LocalSource
|
|||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import kotlin.math.max
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
internal class BackupNotifier(private val context: Context) {
|
internal class BackupNotifier(private val context: Context) {
|
||||||
|
|
||||||
|
@ -32,12 +32,9 @@ import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
|||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.NoChaptersException
|
||||||
import eu.kanade.tachiyomi.util.system.acquireWakeLock
|
import eu.kanade.tachiyomi.util.system.acquireWakeLock
|
||||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
||||||
import java.io.File
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Date
|
|
||||||
import java.util.Locale
|
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
@ -45,6 +42,10 @@ import kotlinx.coroutines.launch
|
|||||||
import rx.Observable
|
import rx.Observable
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.File
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores backup from a JSON file.
|
* Restores backup from a JSON file.
|
||||||
@ -398,7 +399,12 @@ class BackupRestoreService : Service() {
|
|||||||
return backupManager.restoreChapterFetchObservable(source, manga, chapters)
|
return backupManager.restoreChapterFetchObservable(source, manga, chapters)
|
||||||
// If there's any error, return empty update and continue.
|
// If there's any error, return empty update and continue.
|
||||||
.onErrorReturn {
|
.onErrorReturn {
|
||||||
errors.add(Date() to "${manga.title} - ${it.message}")
|
val errorMessage = if (it is NoChaptersException) {
|
||||||
|
getString(R.string.no_chapters_error)
|
||||||
|
} else {
|
||||||
|
it.message
|
||||||
|
}
|
||||||
|
errors.add(Date() to "${manga.title} - $errorMessage")
|
||||||
Pair(emptyList(), emptyList())
|
Pair(emptyList(), emptyList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,13 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
|||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.sink
|
import okio.sink
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class used to create chapter cache
|
* Class used to create chapter cache
|
||||||
|
@ -83,6 +83,11 @@ interface MangaQueries : DbProvider {
|
|||||||
.withPutResolver(MangaFlagsPutResolver())
|
.withPutResolver(MangaFlagsPutResolver())
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
|
fun updateFlags(mangas: List<Manga>) = db.put()
|
||||||
|
.objects(mangas)
|
||||||
|
.withPutResolver(MangaFlagsPutResolver(true))
|
||||||
|
.prepare()
|
||||||
|
|
||||||
fun updateLastUpdated(manga: Manga) = db.put()
|
fun updateLastUpdated(manga: Manga) = db.put()
|
||||||
.`object`(manga)
|
.`object`(manga)
|
||||||
.withPutResolver(MangaLastUpdatedPutResolver())
|
.withPutResolver(MangaLastUpdatedPutResolver())
|
||||||
|
@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.data.database.inTransactionReturn
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||||
|
|
||||||
class MangaFlagsPutResolver : PutResolver<Manga>() {
|
class MangaFlagsPutResolver(private val updateAll: Boolean = false) : PutResolver<Manga>() {
|
||||||
|
|
||||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||||
val updateQuery = mapToUpdateQuery(manga)
|
val updateQuery = mapToUpdateQuery(manga)
|
||||||
@ -19,11 +19,21 @@ class MangaFlagsPutResolver : PutResolver<Manga>() {
|
|||||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
fun mapToUpdateQuery(manga: Manga): UpdateQuery {
|
||||||
|
val builder = UpdateQuery.builder()
|
||||||
|
|
||||||
|
return if (updateAll) {
|
||||||
|
builder
|
||||||
|
.table(MangaTable.TABLE)
|
||||||
|
.build()
|
||||||
|
} else {
|
||||||
|
builder
|
||||||
.table(MangaTable.TABLE)
|
.table(MangaTable.TABLE)
|
||||||
.where("${MangaTable.COL_ID} = ?")
|
.where("${MangaTable.COL_ID} = ?")
|
||||||
.whereArgs(manga.id)
|
.whereArgs(manga.id)
|
||||||
.build()
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||||
put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags)
|
put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags)
|
||||||
|
@ -7,10 +7,10 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
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.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache where we dump the downloads directory from the filesystem. This class is needed because
|
* Cache where we dump the downloads directory from the filesystem. This class is needed because
|
||||||
|
@ -12,8 +12,8 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||||||
import eu.kanade.tachiyomi.util.lang.chop
|
import eu.kanade.tachiyomi.util.lang.chop
|
||||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||||
import java.util.regex.Pattern
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DownloadNotifier is used to show notifications when downloading one or multiple chapters.
|
* DownloadNotifier is used to show notifications when downloading one or multiple chapters.
|
||||||
@ -107,7 +107,9 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val downloadingProgressText = context.getString(
|
val downloadingProgressText = context.getString(
|
||||||
R.string.chapter_downloading_progress, download.downloadedImages, download.pages!!.size
|
R.string.chapter_downloading_progress,
|
||||||
|
download.downloadedImages,
|
||||||
|
download.pages!!.size
|
||||||
)
|
)
|
||||||
|
|
||||||
if (preferences.hideNotificationContent()) {
|
if (preferences.hideNotificationContent()) {
|
||||||
|
@ -22,7 +22,6 @@ import eu.kanade.tachiyomi.util.lang.plusAssign
|
|||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
import java.io.File
|
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
@ -31,6 +30,7 @@ import rx.schedulers.Schedulers
|
|||||||
import rx.subscriptions.CompositeSubscription
|
import rx.subscriptions.CompositeSubscription
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is the one in charge of downloading chapters.
|
* This class is the one in charge of downloading chapters.
|
||||||
|
@ -5,9 +5,9 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadStore
|
import eu.kanade.tachiyomi.data.download.DownloadStore
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
|
|
||||||
class DownloadQueue(
|
class DownloadQueue(
|
||||||
private val store: DownloadStore,
|
private val store: DownloadStore,
|
||||||
|
@ -5,12 +5,12 @@ import android.util.Log
|
|||||||
import com.bumptech.glide.Priority
|
import com.bumptech.glide.Priority
|
||||||
import com.bumptech.glide.load.DataSource
|
import com.bumptech.glide.load.DataSource
|
||||||
import com.bumptech.glide.load.data.DataFetcher
|
import com.bumptech.glide.load.data.DataFetcher
|
||||||
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
open class FileFetcher(private val filePath: String = "") : DataFetcher<InputStream> {
|
open class FileFetcher(private val filePath: String = "") : DataFetcher<InputStream> {
|
||||||
|
|
||||||
|
@ -14,10 +14,10 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
|||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.util.isLocal
|
import eu.kanade.tachiyomi.util.isLocal
|
||||||
import java.io.InputStream
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class for loading a cover associated with a [Manga] that can be present in our own cache.
|
* A class for loading a cover associated with a [Manga] that can be present in our own cache.
|
||||||
|
@ -14,9 +14,9 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
|
|||||||
import com.bumptech.glide.module.AppGlideModule
|
import com.bumptech.glide.module.AppGlideModule
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import java.io.InputStream
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class used to update Glide module settings
|
* Class used to update Glide module settings
|
||||||
|
@ -9,9 +9,9 @@ import androidx.work.WorkManager
|
|||||||
import androidx.work.Worker
|
import androidx.work.Worker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class LibraryUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
class LibraryUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
Worker(context, workerParams) {
|
Worker(context, workerParams) {
|
||||||
@ -45,8 +45,10 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
.build()
|
.build()
|
||||||
|
|
||||||
val request = PeriodicWorkRequestBuilder<LibraryUpdateJob>(
|
val request = PeriodicWorkRequestBuilder<LibraryUpdateJob>(
|
||||||
interval.toLong(), TimeUnit.HOURS,
|
interval.toLong(),
|
||||||
10, TimeUnit.MINUTES
|
TimeUnit.HOURS,
|
||||||
|
10,
|
||||||
|
TimeUnit.MINUTES
|
||||||
)
|
)
|
||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
|
@ -22,9 +22,9 @@ import eu.kanade.tachiyomi.util.lang.chop
|
|||||||
import eu.kanade.tachiyomi.util.system.notification
|
import eu.kanade.tachiyomi.util.system.notification
|
||||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.text.DecimalFormatSymbols
|
import java.text.DecimalFormatSymbols
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class LibraryUpdateNotifier(private val context: Context) {
|
class LibraryUpdateNotifier(private val context: Context) {
|
||||||
|
|
||||||
@ -198,18 +198,23 @@ class LibraryUpdateNotifier(private val context: Context) {
|
|||||||
|
|
||||||
// Mark chapters as read action
|
// Mark chapters as read action
|
||||||
addAction(
|
addAction(
|
||||||
R.drawable.ic_glasses_black_24dp, context.getString(R.string.action_mark_as_read),
|
R.drawable.ic_glasses_black_24dp,
|
||||||
|
context.getString(R.string.action_mark_as_read),
|
||||||
NotificationReceiver.markAsReadPendingBroadcast(
|
NotificationReceiver.markAsReadPendingBroadcast(
|
||||||
context,
|
context,
|
||||||
manga, chapters, Notifications.ID_NEW_CHAPTERS
|
manga,
|
||||||
|
chapters,
|
||||||
|
Notifications.ID_NEW_CHAPTERS
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
// View chapters action
|
// View chapters action
|
||||||
addAction(
|
addAction(
|
||||||
R.drawable.ic_book_24dp, context.getString(R.string.action_view_chapters),
|
R.drawable.ic_book_24dp,
|
||||||
|
context.getString(R.string.action_view_chapters),
|
||||||
NotificationReceiver.openChapterPendingActivity(
|
NotificationReceiver.openChapterPendingActivity(
|
||||||
context,
|
context,
|
||||||
manga, Notifications.ID_NEW_CHAPTERS
|
manga,
|
||||||
|
Notifications.ID_NEW_CHAPTERS
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import android.content.Intent
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Category
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
@ -21,20 +22,21 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.NoChaptersException
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import eu.kanade.tachiyomi.util.prepUpdateCover
|
import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import eu.kanade.tachiyomi.util.system.acquireWakeLock
|
import eu.kanade.tachiyomi.util.system.acquireWakeLock
|
||||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
||||||
import java.io.File
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.File
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class will take care of updating the chapters of the manga from the library. It can be
|
* This class will take care of updating the chapters of the manga from the library. It can be
|
||||||
@ -268,7 +270,12 @@ class LibraryUpdateService(
|
|||||||
updateManga(manga)
|
updateManga(manga)
|
||||||
// If there's any error, return empty update and continue.
|
// If there's any error, return empty update and continue.
|
||||||
.onErrorReturn {
|
.onErrorReturn {
|
||||||
failedUpdates.add(Pair(manga, it.message))
|
val errorMessage = if (it is NoChaptersException) {
|
||||||
|
getString(R.string.no_chapters_error)
|
||||||
|
} else {
|
||||||
|
it.message
|
||||||
|
}
|
||||||
|
failedUpdates.add(Pair(manga, errorMessage))
|
||||||
Pair(emptyList(), emptyList())
|
Pair(emptyList(), emptyList())
|
||||||
}
|
}
|
||||||
// Filter out mangas without new chapters (or failed).
|
// Filter out mangas without new chapters (or failed).
|
||||||
|
@ -7,7 +7,6 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
|
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
@ -26,10 +25,11 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
|
|||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import java.io.File
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.File
|
||||||
|
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global [BroadcastReceiver] that runs on UI thread
|
* Global [BroadcastReceiver] that runs on UI thread
|
||||||
@ -56,19 +56,22 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
// Launch share activity and dismiss notification
|
// Launch share activity and dismiss notification
|
||||||
ACTION_SHARE_IMAGE ->
|
ACTION_SHARE_IMAGE ->
|
||||||
shareImage(
|
shareImage(
|
||||||
context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
context,
|
||||||
|
intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||||
)
|
)
|
||||||
// Delete image from path and dismiss notification
|
// Delete image from path and dismiss notification
|
||||||
ACTION_DELETE_IMAGE ->
|
ACTION_DELETE_IMAGE ->
|
||||||
deleteImage(
|
deleteImage(
|
||||||
context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
context,
|
||||||
|
intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||||
)
|
)
|
||||||
// Share backup file
|
// Share backup file
|
||||||
ACTION_SHARE_BACKUP ->
|
ACTION_SHARE_BACKUP ->
|
||||||
shareBackup(
|
shareBackup(
|
||||||
context, intent.getParcelableExtra(EXTRA_URI),
|
context,
|
||||||
|
intent.getParcelableExtra(EXTRA_URI),
|
||||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||||
)
|
)
|
||||||
ACTION_CANCEL_RESTORE -> cancelRestore(
|
ACTION_CANCEL_RESTORE -> cancelRestore(
|
||||||
@ -80,7 +83,8 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
// Open reader activity
|
// Open reader activity
|
||||||
ACTION_OPEN_CHAPTER -> {
|
ACTION_OPEN_CHAPTER -> {
|
||||||
openChapter(
|
openChapter(
|
||||||
context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
context,
|
||||||
|
intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
||||||
intent.getLongExtra(EXTRA_CHAPTER_ID, -1)
|
intent.getLongExtra(EXTRA_CHAPTER_ID, -1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -82,53 +82,62 @@ object Notifications {
|
|||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_COMMON, context.getString(R.string.channel_common),
|
CHANNEL_COMMON,
|
||||||
|
context.getString(R.string.channel_common),
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_LOW
|
||||||
),
|
),
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_LIBRARY, context.getString(R.string.channel_library),
|
CHANNEL_LIBRARY,
|
||||||
|
context.getString(R.string.channel_library),
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_LOW
|
||||||
).apply {
|
).apply {
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
},
|
},
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_DOWNLOADER_PROGRESS, context.getString(R.string.channel_progress),
|
CHANNEL_DOWNLOADER_PROGRESS,
|
||||||
|
context.getString(R.string.channel_progress),
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_LOW
|
||||||
).apply {
|
).apply {
|
||||||
group = GROUP_DOWNLOADER
|
group = GROUP_DOWNLOADER
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
},
|
},
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_DOWNLOADER_COMPLETE, context.getString(R.string.channel_complete),
|
CHANNEL_DOWNLOADER_COMPLETE,
|
||||||
|
context.getString(R.string.channel_complete),
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_LOW
|
||||||
).apply {
|
).apply {
|
||||||
group = GROUP_DOWNLOADER
|
group = GROUP_DOWNLOADER
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
},
|
},
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_DOWNLOADER_ERROR, context.getString(R.string.channel_errors),
|
CHANNEL_DOWNLOADER_ERROR,
|
||||||
|
context.getString(R.string.channel_errors),
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_LOW
|
||||||
).apply {
|
).apply {
|
||||||
group = GROUP_DOWNLOADER
|
group = GROUP_DOWNLOADER
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
},
|
},
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters),
|
CHANNEL_NEW_CHAPTERS,
|
||||||
|
context.getString(R.string.channel_new_chapters),
|
||||||
NotificationManager.IMPORTANCE_DEFAULT
|
NotificationManager.IMPORTANCE_DEFAULT
|
||||||
),
|
),
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_UPDATES_TO_EXTS, context.getString(R.string.channel_ext_updates),
|
CHANNEL_UPDATES_TO_EXTS,
|
||||||
|
context.getString(R.string.channel_ext_updates),
|
||||||
NotificationManager.IMPORTANCE_DEFAULT
|
NotificationManager.IMPORTANCE_DEFAULT
|
||||||
),
|
),
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_BACKUP_RESTORE_PROGRESS, context.getString(R.string.channel_progress),
|
CHANNEL_BACKUP_RESTORE_PROGRESS,
|
||||||
|
context.getString(R.string.channel_progress),
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_LOW
|
||||||
).apply {
|
).apply {
|
||||||
group = GROUP_BACKUP_RESTORE
|
group = GROUP_BACKUP_RESTORE
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
},
|
},
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_BACKUP_RESTORE_COMPLETE, context.getString(R.string.channel_complete),
|
CHANNEL_BACKUP_RESTORE_COMPLETE,
|
||||||
|
context.getString(R.string.channel_complete),
|
||||||
NotificationManager.IMPORTANCE_HIGH
|
NotificationManager.IMPORTANCE_HIGH
|
||||||
).apply {
|
).apply {
|
||||||
group = GROUP_BACKUP_RESTORE
|
group = GROUP_BACKUP_RESTORE
|
||||||
|
@ -109,11 +109,11 @@ object PreferenceKeys {
|
|||||||
|
|
||||||
const val downloadedOnly = "pref_downloaded_only"
|
const val downloadedOnly = "pref_downloaded_only"
|
||||||
|
|
||||||
const val filterDownloaded = "pref_filter_downloaded_key"
|
const val filterDownloaded = "pref_filter_library_downloaded"
|
||||||
|
|
||||||
const val filterUnread = "pref_filter_unread_key"
|
const val filterUnread = "pref_filter_library_unread"
|
||||||
|
|
||||||
const val filterCompleted = "pref_filter_completed_key"
|
const val filterCompleted = "pref_filter_library_completed"
|
||||||
|
|
||||||
const val librarySortingMode = "library_sorting_mode"
|
const val librarySortingMode = "library_sorting_mode"
|
||||||
|
|
||||||
@ -165,6 +165,18 @@ object PreferenceKeys {
|
|||||||
|
|
||||||
const val enableDoh = "enable_doh"
|
const val enableDoh = "enable_doh"
|
||||||
|
|
||||||
|
const val defaultChapterFilterByRead = "default_chapter_filter_by_read"
|
||||||
|
|
||||||
|
const val defaultChapterFilterByDownloaded = "default_chapter_filter_by_downloaded"
|
||||||
|
|
||||||
|
const val defaultChapterFilterByBookmarked = "default_chapter_filter_by_bookmarked"
|
||||||
|
|
||||||
|
const val defaultChapterSortBySourceOrNumber = "default_chapter_sort_by_source_or_number" // and upload date
|
||||||
|
|
||||||
|
const val defaultChapterSortByAscendingOrDescending = "default_chapter_sort_by_ascending_or_descending"
|
||||||
|
|
||||||
|
const val defaultChapterDisplayByNameOrNumber = "default_chapter_display_by_name_or_number"
|
||||||
|
|
||||||
fun trackUsername(syncId: Int) = "pref_mangasync_username_$syncId"
|
fun trackUsername(syncId: Int) = "pref_mangasync_username_$syncId"
|
||||||
|
|
||||||
fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId"
|
fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId"
|
||||||
|
@ -8,19 +8,21 @@ import androidx.preference.PreferenceManager
|
|||||||
import com.tfcporciuncula.flow.FlowSharedPreferences
|
import com.tfcporciuncula.flow.FlowSharedPreferences
|
||||||
import com.tfcporciuncula.flow.Preference
|
import com.tfcporciuncula.flow.Preference
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.NsfwAllowance
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues.NsfwAllowance
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
||||||
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
import kotlinx.coroutines.flow.Flow
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
fun <T> Preference<T>.asImmediateFlow(block: (value: T) -> Unit): Flow<T> {
|
fun <T> Preference<T>.asImmediateFlow(block: (value: T) -> Unit): Flow<T> {
|
||||||
@ -209,11 +211,11 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun categoryTabs() = flowPrefs.getBoolean(Keys.categoryTabs, true)
|
fun categoryTabs() = flowPrefs.getBoolean(Keys.categoryTabs, true)
|
||||||
|
|
||||||
fun filterDownloaded() = flowPrefs.getBoolean(Keys.filterDownloaded, false)
|
fun filterDownloaded() = flowPrefs.getInt(Keys.filterDownloaded, ExtendedNavigationView.Item.TriStateGroup.STATE_IGNORE)
|
||||||
|
|
||||||
fun filterUnread() = flowPrefs.getBoolean(Keys.filterUnread, false)
|
fun filterUnread() = flowPrefs.getInt(Keys.filterUnread, ExtendedNavigationView.Item.TriStateGroup.STATE_IGNORE)
|
||||||
|
|
||||||
fun filterCompleted() = flowPrefs.getBoolean(Keys.filterCompleted, false)
|
fun filterCompleted() = flowPrefs.getInt(Keys.filterCompleted, ExtendedNavigationView.Item.TriStateGroup.STATE_IGNORE)
|
||||||
|
|
||||||
fun librarySortingMode() = flowPrefs.getInt(Keys.librarySortingMode, 0)
|
fun librarySortingMode() = flowPrefs.getInt(Keys.librarySortingMode, 0)
|
||||||
|
|
||||||
@ -254,4 +256,27 @@ class PreferencesHelper(val context: Context) {
|
|||||||
fun lastSearchQuerySearchSettings() = prefs.getString("last_search_query", "")
|
fun lastSearchQuerySearchSettings() = prefs.getString("last_search_query", "")
|
||||||
|
|
||||||
fun lastSearchQuerySearchSettings(query: String) = prefs.edit { putString("last_search_query", query) }
|
fun lastSearchQuerySearchSettings(query: String) = prefs.edit { putString("last_search_query", query) }
|
||||||
|
|
||||||
|
fun filterChapterByRead() = prefs.getInt(Keys.defaultChapterFilterByRead, Manga.SHOW_ALL)
|
||||||
|
|
||||||
|
fun filterChapterByDownloaded() = prefs.getInt(Keys.defaultChapterFilterByDownloaded, Manga.SHOW_ALL)
|
||||||
|
|
||||||
|
fun filterChapterByBookmarked() = prefs.getInt(Keys.defaultChapterFilterByBookmarked, Manga.SHOW_ALL)
|
||||||
|
|
||||||
|
fun sortChapterBySourceOrNumber() = prefs.getInt(Keys.defaultChapterSortBySourceOrNumber, Manga.SORTING_SOURCE)
|
||||||
|
|
||||||
|
fun displayChapterByNameOrNumber() = prefs.getInt(Keys.defaultChapterDisplayByNameOrNumber, Manga.DISPLAY_NAME)
|
||||||
|
|
||||||
|
fun sortChapterByAscendingOrDescending() = prefs.getInt(Keys.defaultChapterSortByAscendingOrDescending, Manga.SORT_DESC)
|
||||||
|
|
||||||
|
fun setChapterSettingsDefault(manga: Manga) {
|
||||||
|
prefs.edit {
|
||||||
|
putInt(Keys.defaultChapterFilterByRead, manga.readFilter)
|
||||||
|
putInt(Keys.defaultChapterFilterByDownloaded, manga.downloadedFilter)
|
||||||
|
putInt(Keys.defaultChapterFilterByBookmarked, manga.bookmarkedFilter)
|
||||||
|
putInt(Keys.defaultChapterSortBySourceOrNumber, manga.sorting)
|
||||||
|
putInt(Keys.defaultChapterDisplayByNameOrNumber, manga.displayMode)
|
||||||
|
putInt(Keys.defaultChapterSortByAscendingOrDescending, if (manga.sortDescending()) Manga.SORT_DESC else Manga.SORT_ASC)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,12 @@ import com.google.gson.JsonParser
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import java.util.Calendar
|
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||||
|
|
||||||
@ -271,9 +271,14 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ALManga(
|
return ALManga(
|
||||||
struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString,
|
struct["id"].asInt,
|
||||||
struct["description"].nullString.orEmpty(), struct["type"].asString, struct["status"].nullString.orEmpty(),
|
struct["title"]["romaji"].asString,
|
||||||
date, struct["chapters"].nullInt ?: 0
|
struct["coverImage"]["large"].asString,
|
||||||
|
struct["description"].nullString.orEmpty(),
|
||||||
|
struct["type"].asString,
|
||||||
|
struct["status"].nullString.orEmpty(),
|
||||||
|
date,
|
||||||
|
struct["chapters"].nullInt ?: 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ import eu.kanade.tachiyomi.data.database.models.Track
|
|||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
data class ALManga(
|
data class ALManga(
|
||||||
val media_id: Int,
|
val media_id: Int,
|
||||||
|
@ -12,13 +12,13 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
|||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import java.net.URLEncoder
|
|
||||||
import okhttp3.CacheControl
|
import okhttp3.CacheControl
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.net.URLEncoder
|
||||||
|
|
||||||
class BangumiApi(private val client: OkHttpClient, interceptor: BangumiInterceptor) {
|
class BangumiApi(private val client: OkHttpClient, interceptor: BangumiInterceptor) {
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import java.text.DecimalFormat
|
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
|
||||||
class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
||||||
|
|
||||||
|
@ -11,13 +11,6 @@ import eu.kanade.tachiyomi.network.asObservableSuccess
|
|||||||
import eu.kanade.tachiyomi.util.lang.toCalendar
|
import eu.kanade.tachiyomi.util.lang.toCalendar
|
||||||
import eu.kanade.tachiyomi.util.selectInt
|
import eu.kanade.tachiyomi.util.selectInt
|
||||||
import eu.kanade.tachiyomi.util.selectText
|
import eu.kanade.tachiyomi.util.selectText
|
||||||
import java.io.BufferedReader
|
|
||||||
import java.io.InputStreamReader
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Calendar
|
|
||||||
import java.util.GregorianCalendar
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.zip.GZIPInputStream
|
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -30,6 +23,13 @@ import org.jsoup.nodes.Document
|
|||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import org.jsoup.parser.Parser
|
import org.jsoup.parser.Parser
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.GregorianCalendar
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.zip.GZIPInputStream
|
||||||
|
|
||||||
class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListInterceptor) {
|
class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListInterceptor) {
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.updater
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
|
||||||
import eu.kanade.tachiyomi.data.updater.devrepo.DevRepoUpdateChecker
|
|
||||||
import eu.kanade.tachiyomi.data.updater.github.GithubUpdateChecker
|
|
||||||
|
|
||||||
abstract class UpdateChecker {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun getUpdateChecker(): UpdateChecker {
|
|
||||||
return if (BuildConfig.DEBUG) {
|
|
||||||
DevRepoUpdateChecker()
|
|
||||||
} else {
|
|
||||||
GithubUpdateChecker()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns observable containing release information
|
|
||||||
*/
|
|
||||||
abstract suspend fun checkForUpdate(): UpdateResult
|
|
||||||
}
|
|
@ -13,9 +13,10 @@ import androidx.work.Worker
|
|||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
|
import eu.kanade.tachiyomi.data.updater.github.GithubUpdateChecker
|
||||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
|
class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
Worker(context, workerParams) {
|
Worker(context, workerParams) {
|
||||||
@ -23,7 +24,7 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
|
|||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
return runBlocking {
|
return runBlocking {
|
||||||
try {
|
try {
|
||||||
val result = UpdateChecker.getUpdateChecker().checkForUpdate()
|
val result = GithubUpdateChecker().checkForUpdate()
|
||||||
|
|
||||||
if (result is UpdateResult.NewUpdate<*>) {
|
if (result is UpdateResult.NewUpdate<*>) {
|
||||||
val url = result.release.downloadLink
|
val url = result.release.downloadLink
|
||||||
@ -65,8 +66,10 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
|
|||||||
.build()
|
.build()
|
||||||
|
|
||||||
val request = PeriodicWorkRequestBuilder<UpdaterJob>(
|
val request = PeriodicWorkRequestBuilder<UpdaterJob>(
|
||||||
3, TimeUnit.DAYS,
|
3,
|
||||||
3, TimeUnit.HOURS
|
TimeUnit.DAYS,
|
||||||
|
3,
|
||||||
|
TimeUnit.HOURS
|
||||||
)
|
)
|
||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
|
@ -20,9 +20,9 @@ import eu.kanade.tachiyomi.util.storage.getUriCompat
|
|||||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||||
import eu.kanade.tachiyomi.util.system.acquireWakeLock
|
import eu.kanade.tachiyomi.util.system.acquireWakeLock
|
||||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
||||||
import java.io.File
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class UpdaterService : Service() {
|
class UpdaterService : Service() {
|
||||||
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.updater.devrepo
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.updater.Release
|
|
||||||
|
|
||||||
class DevRepoRelease(override val info: String) : Release {
|
|
||||||
|
|
||||||
override val downloadLink: String
|
|
||||||
get() = LATEST_URL
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val LATEST_URL = "https://tachiyomi.kanade.eu/latest"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.updater.devrepo
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateChecker
|
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
|
||||||
import eu.kanade.tachiyomi.network.await
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
class DevRepoUpdateChecker : UpdateChecker() {
|
|
||||||
|
|
||||||
private val client: OkHttpClient by lazy {
|
|
||||||
Injekt.get<NetworkHelper>().client.newBuilder()
|
|
||||||
.followRedirects(false)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val versionRegex: Regex by lazy {
|
|
||||||
Regex("tachiyomi-r(\\d+).apk")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun checkForUpdate(): UpdateResult {
|
|
||||||
val response = withContext(Dispatchers.IO) {
|
|
||||||
client.newCall(GET(DevRepoRelease.LATEST_URL)).await()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get latest repo version number from header in format "Location: tachiyomi-r1512.apk"
|
|
||||||
val latestVersionNumber: String = versionRegex.find(response.header("Location")!!)!!.groupValues[1]
|
|
||||||
|
|
||||||
return if (latestVersionNumber.toInt() > BuildConfig.COMMIT_COUNT.toInt()) {
|
|
||||||
DevRepoUpdateResult.NewUpdate(DevRepoRelease("v$latestVersionNumber"))
|
|
||||||
} else {
|
|
||||||
DevRepoUpdateResult.NoNewUpdate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.updater.devrepo
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
|
||||||
|
|
||||||
sealed class DevRepoUpdateResult : UpdateResult() {
|
|
||||||
|
|
||||||
class NewUpdate(release: DevRepoRelease) : UpdateResult.NewUpdate<DevRepoRelease>(release)
|
|
||||||
class NoNewUpdate : UpdateResult.NoNewUpdate()
|
|
||||||
}
|
|
@ -28,5 +28,5 @@ class GithubRelease(
|
|||||||
* Assets class containing download url.
|
* Assets class containing download url.
|
||||||
* @param downloadLink download url.
|
* @param downloadLink download url.
|
||||||
*/
|
*/
|
||||||
inner class Assets(@SerializedName("browser_download_url") val downloadLink: String)
|
class Assets(@SerializedName("browser_download_url") val downloadLink: String)
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,12 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
|||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Path
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to connect with the GitHub API.
|
* Used to connect with the GitHub API to get the latest release version from a repo.
|
||||||
*/
|
*/
|
||||||
interface GithubService {
|
interface GithubService {
|
||||||
|
|
||||||
@ -24,6 +25,6 @@ interface GithubService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET("/repos/inorichi/tachiyomi/releases/latest")
|
@GET("/repos/{repo}/releases/latest")
|
||||||
suspend fun getLatestVersion(): GithubRelease
|
suspend fun getLatestVersion(@Path("repo", encoded = true) repo: String): GithubRelease
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,43 @@
|
|||||||
package eu.kanade.tachiyomi.data.updater.github
|
package eu.kanade.tachiyomi.data.updater.github
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateChecker
|
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
||||||
|
|
||||||
class GithubUpdateChecker : UpdateChecker() {
|
class GithubUpdateChecker {
|
||||||
|
|
||||||
private val service: GithubService = GithubService.create()
|
private val service: GithubService = GithubService.create()
|
||||||
|
|
||||||
override suspend fun checkForUpdate(): UpdateResult {
|
private val repo: String by lazy {
|
||||||
val release = service.getLatestVersion()
|
if (BuildConfig.DEBUG) {
|
||||||
|
"tachiyomiorg/android-app-preview"
|
||||||
|
} else {
|
||||||
|
"inorichi/tachiyomi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val newVersion = release.version.replace("[^\\d.]".toRegex(), "")
|
suspend fun checkForUpdate(): UpdateResult {
|
||||||
|
val release = service.getLatestVersion(repo)
|
||||||
|
|
||||||
// Check if latest version is different from current version
|
// Check if latest version is different from current version
|
||||||
return if (newVersion != BuildConfig.VERSION_NAME) {
|
return if (isNewVersion(release.version)) {
|
||||||
GithubUpdateResult.NewUpdate(release)
|
GithubUpdateResult.NewUpdate(release)
|
||||||
} else {
|
} else {
|
||||||
GithubUpdateResult.NoNewUpdate()
|
GithubUpdateResult.NoNewUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isNewVersion(versionTag: String): Boolean {
|
||||||
|
// Removes prefixes like "r" or "v"
|
||||||
|
val newVersion = versionTag.replace("[^\\d.]".toRegex(), "")
|
||||||
|
|
||||||
|
return if (BuildConfig.DEBUG) {
|
||||||
|
// Preview builds: based on releases in "tachiyomiorg/android-app-preview" repo
|
||||||
|
// tagged as something like "r1234"
|
||||||
|
newVersion.toInt() > BuildConfig.COMMIT_COUNT.toInt()
|
||||||
|
} else {
|
||||||
|
// Release builds: based on releases in "inorichi/tachiyomi" repo
|
||||||
|
// tagged as something like "v0.1.2"
|
||||||
|
newVersion != BuildConfig.VERSION_NAME
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ import eu.kanade.tachiyomi.data.notification.Notifications
|
|||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
|
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
|
||||||
import eu.kanade.tachiyomi.util.system.notification
|
import eu.kanade.tachiyomi.util.system.notification
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
CoroutineWorker(context, workerParams) {
|
CoroutineWorker(context, workerParams) {
|
||||||
@ -73,8 +73,10 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
|
|||||||
.build()
|
.build()
|
||||||
|
|
||||||
val request = PeriodicWorkRequestBuilder<ExtensionUpdateJob>(
|
val request = PeriodicWorkRequestBuilder<ExtensionUpdateJob>(
|
||||||
12, TimeUnit.HOURS,
|
12,
|
||||||
1, TimeUnit.HOURS
|
TimeUnit.HOURS,
|
||||||
|
1,
|
||||||
|
TimeUnit.HOURS
|
||||||
)
|
)
|
||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
|
@ -9,10 +9,10 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.extension.model.LoadResult
|
import eu.kanade.tachiyomi.extension.model.LoadResult
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
||||||
import java.util.Date
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
internal class ExtensionGithubApi {
|
internal class ExtensionGithubApi {
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ import com.jakewharton.rxrelay.PublishRelay
|
|||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import java.io.File
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.io.File
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The installer which installs, updates and uninstalls the extensions.
|
* The installer which installs, updates and uninstalls the extensions.
|
||||||
|
@ -178,7 +178,13 @@ internal object ExtensionLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val extension = Extension.Installed(
|
val extension = Extension.Installed(
|
||||||
extName, pkgName, versionName, versionCode, lang, isNsfw, sources,
|
extName,
|
||||||
|
pkgName,
|
||||||
|
versionName,
|
||||||
|
versionCode,
|
||||||
|
lang,
|
||||||
|
isNsfw,
|
||||||
|
sources,
|
||||||
isUnofficial = signatureHash != officialSignature
|
isUnofficial = signatureHash != officialSignature
|
||||||
)
|
)
|
||||||
return LoadResult.Success(extension)
|
return LoadResult.Success(extension)
|
||||||
|
@ -16,15 +16,15 @@ import eu.kanade.tachiyomi.util.system.WebViewUtil
|
|||||||
import eu.kanade.tachiyomi.util.system.isOutdated
|
import eu.kanade.tachiyomi.util.system.isOutdated
|
||||||
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import java.io.IOException
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class CloudflareInterceptor(private val context: Context) : Interceptor {
|
class CloudflareInterceptor(private val context: Context) : Interceptor {
|
||||||
|
|
||||||
|
@ -3,15 +3,15 @@ package eu.kanade.tachiyomi.network
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import java.io.File
|
|
||||||
import java.net.InetAddress
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import okhttp3.Cache
|
import okhttp3.Cache
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.dnsoverhttps.DnsOverHttps
|
import okhttp3.dnsoverhttps.DnsOverHttps
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.File
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class NetworkHelper(context: Context) {
|
class NetworkHelper(context: Context) {
|
||||||
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.network
|
package eu.kanade.tachiyomi.network
|
||||||
|
|
||||||
import java.io.IOException
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
|
||||||
import kotlin.coroutines.resume
|
|
||||||
import kotlin.coroutines.resumeWithException
|
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import okhttp3.Call
|
import okhttp3.Call
|
||||||
import okhttp3.Callback
|
import okhttp3.Callback
|
||||||
@ -13,6 +9,10 @@ import okhttp3.Response
|
|||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Producer
|
import rx.Producer
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
fun Call.asObservable(): Observable<Response> {
|
fun Call.asObservable(): Observable<Response> {
|
||||||
return Observable.unsafeCreate { subscriber ->
|
return Observable.unsafeCreate { subscriber ->
|
||||||
@ -54,7 +54,8 @@ fun Call.asObservable(): Observable<Response> {
|
|||||||
// Based on https://github.com/gildor/kotlin-coroutines-okhttp
|
// Based on https://github.com/gildor/kotlin-coroutines-okhttp
|
||||||
suspend fun Call.await(assertSuccess: Boolean = false): Response {
|
suspend fun Call.await(assertSuccess: Boolean = false): Response {
|
||||||
return suspendCancellableCoroutine { continuation ->
|
return suspendCancellableCoroutine { continuation ->
|
||||||
enqueue(object : Callback {
|
enqueue(
|
||||||
|
object : Callback {
|
||||||
override fun onResponse(call: Call, response: Response) {
|
override fun onResponse(call: Call, response: Response) {
|
||||||
if (assertSuccess && !response.isSuccessful) {
|
if (assertSuccess && !response.isSuccessful) {
|
||||||
continuation.resumeWithException(Exception("HTTP error ${response.code}"))
|
continuation.resumeWithException(Exception("HTTP error ${response.code}"))
|
||||||
@ -69,7 +70,8 @@ suspend fun Call.await(assertSuccess: Boolean = false): Response {
|
|||||||
if (continuation.isCancelled) return
|
if (continuation.isCancelled) return
|
||||||
continuation.resumeWithException(e)
|
continuation.resumeWithException(e)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
continuation.invokeOnCancellation {
|
continuation.invokeOnCancellation {
|
||||||
try {
|
try {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.network
|
package eu.kanade.tachiyomi.network
|
||||||
|
|
||||||
import java.io.IOException
|
|
||||||
import okhttp3.MediaType
|
import okhttp3.MediaType
|
||||||
import okhttp3.ResponseBody
|
import okhttp3.ResponseBody
|
||||||
import okio.Buffer
|
import okio.Buffer
|
||||||
@ -8,6 +7,7 @@ import okio.BufferedSource
|
|||||||
import okio.ForwardingSource
|
import okio.ForwardingSource
|
||||||
import okio.Source
|
import okio.Source
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
class ProgressResponseBody(private val responseBody: ResponseBody, private val progressListener: ProgressListener) : ResponseBody() {
|
class ProgressResponseBody(private val responseBody: ResponseBody, private val progressListener: ProgressListener) : ResponseBody() {
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package eu.kanade.tachiyomi.network
|
package eu.kanade.tachiyomi.network
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit.MINUTES
|
|
||||||
import okhttp3.CacheControl
|
import okhttp3.CacheControl
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody
|
import okhttp3.RequestBody
|
||||||
|
import java.util.concurrent.TimeUnit.MINUTES
|
||||||
|
|
||||||
private val DEFAULT_CACHE_CONTROL = CacheControl.Builder().maxAge(10, MINUTES).build()
|
private val DEFAULT_CACHE_CONTROL = CacheControl.Builder().maxAge(10, MINUTES).build()
|
||||||
private val DEFAULT_HEADERS = Headers.Builder().build()
|
private val DEFAULT_HEADERS = Headers.Builder().build()
|
||||||
|
@ -14,6 +14,10 @@ import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
|||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.storage.EpubFile
|
import eu.kanade.tachiyomi.util.storage.EpubFile
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
|
import junrar.Archive
|
||||||
|
import junrar.rarfile.FileHeader
|
||||||
|
import rx.Observable
|
||||||
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -21,10 +25,6 @@ import java.util.Locale
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipFile
|
import java.util.zip.ZipFile
|
||||||
import junrar.Archive
|
|
||||||
import junrar.rarfile.FileHeader
|
|
||||||
import rx.Observable
|
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
class LocalSource(private val context: Context) : CatalogueSource {
|
class LocalSource(private val context: Context) : CatalogueSource {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -10,15 +10,15 @@ import eu.kanade.tachiyomi.source.model.MangasPage
|
|||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import java.net.URI
|
|
||||||
import java.net.URISyntaxException
|
|
||||||
import java.security.MessageDigest
|
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.net.URI
|
||||||
|
import java.net.URISyntaxException
|
||||||
|
import java.security.MessageDigest
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple implementation for sources from a website.
|
* A simple implementation for sources from a website.
|
||||||
|
@ -7,11 +7,11 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
|
||||||
|
|
||||||
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
|||||||
lateinit var binding: VB
|
lateinit var binding: VB
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addLifecycleListener(object : LifecycleListener() {
|
addLifecycleListener(
|
||||||
|
object : LifecycleListener() {
|
||||||
override fun postCreateView(controller: Controller, view: View) {
|
override fun postCreateView(controller: Controller, view: View) {
|
||||||
onViewCreated(view)
|
onViewCreated(view)
|
||||||
}
|
}
|
||||||
@ -42,7 +43,8 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
|||||||
override fun preDestroyView(controller: Controller, view: View) {
|
override fun preDestroyView(controller: Controller, view: View) {
|
||||||
Timber.d("Destroy view for ${controller.instance()}")
|
Timber.d("Destroy view for ${controller.instance()}")
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val containerView: View?
|
override val containerView: View?
|
||||||
@ -98,7 +100,8 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
|||||||
var expandActionViewFromInteraction = false
|
var expandActionViewFromInteraction = false
|
||||||
|
|
||||||
fun MenuItem.fixExpand(onExpand: ((MenuItem) -> Boolean)? = null, onCollapse: ((MenuItem) -> Boolean)? = null) {
|
fun MenuItem.fixExpand(onExpand: ((MenuItem) -> Boolean)? = null, onCollapse: ((MenuItem) -> Boolean)? = null) {
|
||||||
setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
setOnActionExpandListener(
|
||||||
|
object : MenuItem.OnActionExpandListener {
|
||||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||||
return onExpand?.invoke(item) ?: true
|
return onExpand?.invoke(item) ?: true
|
||||||
}
|
}
|
||||||
@ -108,7 +111,8 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
|||||||
|
|
||||||
return onCollapse?.invoke(item) ?: true
|
return onCollapse?.invoke(item) ?: true
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if (expandActionViewFromInteraction) {
|
if (expandActionViewFromInteraction) {
|
||||||
expandActionViewFromInteraction = false
|
expandActionViewFromInteraction = false
|
||||||
|
@ -10,12 +10,12 @@ import eu.kanade.tachiyomi.extension.model.Extension
|
|||||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
private typealias ExtensionTuple =
|
private typealias ExtensionTuple =
|
||||||
Triple<List<Extension.Installed>, List<Extension.Untrusted>, List<Extension.Available>>
|
Triple<List<Extension.Installed>, List<Extension.Untrusted>, List<Extension.Available>>
|
||||||
|
@ -20,8 +20,6 @@ import androidx.preference.PreferenceManager
|
|||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
import androidx.recyclerview.widget.ConcatAdapter
|
import androidx.recyclerview.widget.ConcatAdapter
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore
|
import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore
|
||||||
@ -92,7 +90,6 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
|||||||
ExtensionDetailsHeaderAdapter(presenter),
|
ExtensionDetailsHeaderAdapter(presenter),
|
||||||
initPreferencesAdapter(context, extension)
|
initPreferencesAdapter(context, extension)
|
||||||
)
|
)
|
||||||
binding.extensionPrefsRecycler.addItemDecoration(DividerItemDecoration(context, VERTICAL))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initPreferencesAdapter(context: Context, extension: Extension.Installed): PreferenceGroupAdapter {
|
private fun initPreferencesAdapter(context: Context, extension: Extension.Installed): PreferenceGroupAdapter {
|
||||||
@ -112,7 +109,7 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
|||||||
.forEach {
|
.forEach {
|
||||||
val preferenceBlock = {
|
val preferenceBlock = {
|
||||||
it.value
|
it.value
|
||||||
.sortedWith(compareBy({ !it.isEnabled() }, { it.name }))
|
.sortedWith(compareBy({ !it.isEnabled() }, { it.name.toLowerCase() }))
|
||||||
.forEach { source ->
|
.forEach { source ->
|
||||||
val sourcePrefs = mutableListOf<Preference>()
|
val sourcePrefs = mutableListOf<Preference>()
|
||||||
|
|
||||||
|
@ -19,8 +19,6 @@ import androidx.preference.Preference
|
|||||||
import androidx.preference.PreferenceGroupAdapter
|
import androidx.preference.PreferenceGroupAdapter
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore
|
import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore
|
||||||
@ -86,7 +84,6 @@ class SourcePreferencesController(bundle: Bundle? = null) :
|
|||||||
|
|
||||||
binding.recycler.layoutManager = LinearLayoutManager(context)
|
binding.recycler.layoutManager = LinearLayoutManager(context)
|
||||||
binding.recycler.adapter = PreferenceGroupAdapter(screen)
|
binding.recycler.adapter = PreferenceGroupAdapter(screen)
|
||||||
binding.recycler.addItemDecoration(DividerItemDecoration(context, VERTICAL))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView(view: View) {
|
override fun onDestroyView(view: View) {
|
||||||
|
@ -13,10 +13,10 @@ import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchCardItem
|
|||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchItem
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchItem
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchPresenter
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchPresenter
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import java.util.Date
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
class SearchPresenter(
|
class SearchPresenter(
|
||||||
initialQuery: String? = "",
|
initialQuery: String? = "",
|
||||||
|
@ -29,7 +29,7 @@ class MigrationSourcesPresenter(
|
|||||||
val header = SelectionHeader()
|
val header = SelectionHeader()
|
||||||
return library.map { it.source }.toSet()
|
return library.map { it.source }.toSet()
|
||||||
.mapNotNull { if (it != LocalSource.ID) sourceManager.getOrStub(it) else null }
|
.mapNotNull { if (it != LocalSource.ID) sourceManager.getOrStub(it) else null }
|
||||||
.sortedBy { it.name }
|
.sortedBy { it.name.toLowerCase() }
|
||||||
.map { SourceItem(it, header) }
|
.map { SourceItem(it, header) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@ import eu.kanade.tachiyomi.util.preference.onChange
|
|||||||
import eu.kanade.tachiyomi.util.preference.switchPreferenceCategory
|
import eu.kanade.tachiyomi.util.preference.switchPreferenceCategory
|
||||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import java.util.TreeMap
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.TreeMap
|
||||||
|
|
||||||
class SourceFilterController : SettingsController() {
|
class SourceFilterController : SettingsController() {
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class SourceFilterController : SettingsController() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
orderedLangs.forEach { lang ->
|
orderedLangs.forEach { lang ->
|
||||||
val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name }
|
val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name.toLowerCase() }
|
||||||
|
|
||||||
// Create a preference group and set initial state and change listener
|
// Create a preference group and set initial state and change listener
|
||||||
switchPreferenceCategory {
|
switchPreferenceCategory {
|
||||||
|
@ -6,7 +6,6 @@ import eu.kanade.tachiyomi.source.CatalogueSource
|
|||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
import java.util.TreeMap
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
@ -21,6 +20,7 @@ import rx.Observable
|
|||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.TreeMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presenter of [SourceController]
|
* Presenter of [SourceController]
|
||||||
@ -128,7 +128,7 @@ class SourcePresenter(
|
|||||||
return sourceManager.getCatalogueSources()
|
return sourceManager.getCatalogueSources()
|
||||||
.filter { it.lang in languages }
|
.filter { it.lang in languages }
|
||||||
.filterNot { it.id.toString() in disabledSourceIds }
|
.filterNot { it.id.toString() in disabledSourceIds }
|
||||||
.sortedBy { "(${it.lang}) ${it.name}" } +
|
.sortedBy { "(${it.lang}) ${it.name.toLowerCase()}" } +
|
||||||
sourceManager.get(LocalSource.ID) as LocalSource
|
sourceManager.get(LocalSource.ID) as LocalSource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -216,7 +215,6 @@ open class BrowseSourceController(bundle: Bundle) :
|
|||||||
id = R.id.recycler
|
id = R.id.recycler
|
||||||
layoutManager = LinearLayoutManager(context)
|
layoutManager = LinearLayoutManager(context)
|
||||||
layoutParams = RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
layoutParams = RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||||
addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(binding.catalogueView.inflate(R.layout.source_recycler_autofit) as AutofitRecyclerView).apply {
|
(binding.catalogueView.inflate(R.layout.source_recycler_autofit) as AutofitRecyclerView).apply {
|
||||||
|
@ -28,9 +28,8 @@ import eu.kanade.tachiyomi.ui.browse.source.filter.TextItem
|
|||||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TextSectionItem
|
import eu.kanade.tachiyomi.ui.browse.source.filter.TextSectionItem
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateItem
|
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateItem
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem
|
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
|
||||||
import eu.kanade.tachiyomi.util.removeCovers
|
import eu.kanade.tachiyomi.util.removeCovers
|
||||||
import java.util.Date
|
|
||||||
import kotlinx.coroutines.flow.subscribe
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
@ -39,6 +38,7 @@ import rx.subjects.PublishSubject
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presenter of [BrowseSourceController].
|
* Presenter of [BrowseSourceController].
|
||||||
@ -268,6 +268,8 @@ open class BrowseSourcePresenter(
|
|||||||
|
|
||||||
if (!manga.favorite) {
|
if (!manga.favorite) {
|
||||||
manga.removeCovers(coverCache)
|
manga.removeCovers(coverCache)
|
||||||
|
} else {
|
||||||
|
ChapterSettingsHelper.applySettingDefaults(manga)
|
||||||
}
|
}
|
||||||
|
|
||||||
db.insertManga(manga).executeAsBlocking()
|
db.insertManga(manga).executeAsBlocking()
|
||||||
|
@ -38,10 +38,13 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
|
|||||||
val coverHeight = parent.itemWidth / 3 * 4
|
val coverHeight = parent.itemWidth / 3 * 4
|
||||||
view.apply {
|
view.apply {
|
||||||
card.layoutParams = FrameLayout.LayoutParams(
|
card.layoutParams = FrameLayout.LayoutParams(
|
||||||
MATCH_PARENT, coverHeight
|
MATCH_PARENT,
|
||||||
|
coverHeight
|
||||||
)
|
)
|
||||||
gradient.layoutParams = FrameLayout.LayoutParams(
|
gradient.layoutParams = FrameLayout.LayoutParams(
|
||||||
MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM
|
MATCH_PARENT,
|
||||||
|
coverHeight / 2,
|
||||||
|
Gravity.BOTTOM
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
SourceGridHolder(view, adapter)
|
SourceGridHolder(view, adapter)
|
||||||
@ -51,7 +54,8 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
|
|||||||
val coverHeight = parent.itemWidth / 3 * 4
|
val coverHeight = parent.itemWidth / 3 * 4
|
||||||
view.apply {
|
view.apply {
|
||||||
card.layoutParams = ConstraintLayout.LayoutParams(
|
card.layoutParams = ConstraintLayout.LayoutParams(
|
||||||
MATCH_PARENT, coverHeight
|
MATCH_PARENT,
|
||||||
|
coverHeight
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
SourceComfortableGridHolder(view, adapter)
|
SourceComfortableGridHolder(view, adapter)
|
||||||
|
@ -30,7 +30,8 @@ open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem<Selec
|
|||||||
spinner.prompt = filter.name
|
spinner.prompt = filter.name
|
||||||
spinner.adapter = ArrayAdapter<Any>(
|
spinner.adapter = ArrayAdapter<Any>(
|
||||||
holder.itemView.context,
|
holder.itemView.context,
|
||||||
android.R.layout.simple_spinner_item, filter.values
|
android.R.layout.simple_spinner_item,
|
||||||
|
filter.values
|
||||||
).apply {
|
).apply {
|
||||||
setDropDownViewResource(R.layout.common_spinner_item)
|
setDropDownViewResource(R.layout.common_spinner_item)
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,10 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
import eu.kanade.tachiyomi.R as TR
|
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
import eu.kanade.tachiyomi.R as TR
|
||||||
|
|
||||||
open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriStateItem.Holder>() {
|
open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriStateItem.Holder>() {
|
||||||
|
|
||||||
|
@ -108,7 +108,8 @@ open class GlobalSearchController(
|
|||||||
val searchView = searchItem.actionView as SearchView
|
val searchView = searchItem.actionView as SearchView
|
||||||
searchView.maxWidth = Int.MAX_VALUE
|
searchView.maxWidth = Int.MAX_VALUE
|
||||||
|
|
||||||
searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
searchItem.setOnActionExpandListener(
|
||||||
|
object : MenuItem.OnActionExpandListener {
|
||||||
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
||||||
searchView.onActionViewExpanded() // Required to show the query in the view
|
searchView.onActionViewExpanded() // Required to show the query in the view
|
||||||
searchView.setQuery(presenter.query, false)
|
searchView.setQuery(presenter.query, false)
|
||||||
@ -118,7 +119,8 @@ open class GlobalSearchController(
|
|||||||
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
searchView.queryTextEvents()
|
searchView.queryTextEvents()
|
||||||
.filterIsInstance<QueryTextEvent.QuerySubmitted>()
|
.filterIsInstance<QueryTextEvent.QuerySubmitted>()
|
||||||
|
@ -108,7 +108,7 @@ open class GlobalSearchPresenter(
|
|||||||
return sourceManager.getCatalogueSources()
|
return sourceManager.getCatalogueSources()
|
||||||
.filter { it.lang in languages }
|
.filter { it.lang in languages }
|
||||||
.filterNot { it.id.toString() in disabledSourceIds }
|
.filterNot { it.id.toString() in disabledSourceIds }
|
||||||
.sortedWith(compareBy({ it.id.toString() !in pinnedSourceIds }, { "${it.name} (${it.lang})" }))
|
.sortedWith(compareBy({ it.id.toString() !in pinnedSourceIds }, { "${it.name.toLowerCase()} (${it.lang})" }))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSourcesToQuery(): List<CatalogueSource> {
|
private fun getSourcesToQuery(): List<CatalogueSource> {
|
||||||
@ -188,7 +188,7 @@ open class GlobalSearchPresenter(
|
|||||||
{ it.results.isNullOrEmpty() },
|
{ it.results.isNullOrEmpty() },
|
||||||
// Same as initial sort, i.e. pinned first then alphabetically
|
// Same as initial sort, i.e. pinned first then alphabetically
|
||||||
{ it.source.id.toString() !in pinnedSourceIds },
|
{ it.source.id.toString() !in pinnedSourceIds },
|
||||||
{ "${it.source.name} (${it.source.lang})" }
|
{ "${it.source.name.toLowerCase()} (${it.source.lang})" }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -198,8 +198,11 @@ class CategoryController :
|
|||||||
R.id.action_delete -> {
|
R.id.action_delete -> {
|
||||||
undoHelper = UndoHelper(adapter, this)
|
undoHelper = UndoHelper(adapter, this)
|
||||||
undoHelper?.start(
|
undoHelper?.start(
|
||||||
adapter.selectedPositions, activity!!.root_coordinator,
|
adapter.selectedPositions,
|
||||||
R.string.snack_categories_deleted, R.string.action_undo, 3000
|
activity!!.root_coordinator,
|
||||||
|
R.string.snack_categories_deleted,
|
||||||
|
R.string.action_undo,
|
||||||
|
3000
|
||||||
)
|
)
|
||||||
|
|
||||||
mode.finish()
|
mode.finish()
|
||||||
|
@ -18,13 +18,13 @@ import eu.kanade.tachiyomi.source.model.Page
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.FabController
|
import eu.kanade.tachiyomi.ui.base.controller.FabController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
import eu.kanade.tachiyomi.util.view.shrinkOnScroll
|
import eu.kanade.tachiyomi.util.view.shrinkOnScroll
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller that shows the currently active downloads.
|
* Controller that shows the currently active downloads.
|
||||||
|
@ -183,7 +183,7 @@ class LibraryController(
|
|||||||
createActionModeIfNeeded()
|
createActionModeIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
settingsSheet = LibrarySettingsSheet(activity!!) { group ->
|
settingsSheet = LibrarySettingsSheet(router) { group ->
|
||||||
when (group) {
|
when (group) {
|
||||||
is LibrarySettingsSheet.Filter.FilterGroup -> onFilterChanged()
|
is LibrarySettingsSheet.Filter.FilterGroup -> onFilterChanged()
|
||||||
is LibrarySettingsSheet.Sort.SortGroup -> onSortChanged()
|
is LibrarySettingsSheet.Sort.SortGroup -> onSortChanged()
|
||||||
|
@ -45,7 +45,9 @@ class LibraryItem(val manga: LibraryManga, private val libraryDisplayMode: Prefe
|
|||||||
view.apply {
|
view.apply {
|
||||||
card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
|
card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
|
||||||
gradient.layoutParams = FrameLayout.LayoutParams(
|
gradient.layoutParams = FrameLayout.LayoutParams(
|
||||||
MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM
|
MATCH_PARENT,
|
||||||
|
coverHeight / 2,
|
||||||
|
Gravity.BOTTOM
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
LibraryCompactGridHolder(view, adapter)
|
LibraryCompactGridHolder(view, adapter)
|
||||||
@ -55,7 +57,8 @@ class LibraryItem(val manga: LibraryManga, private val libraryDisplayMode: Prefe
|
|||||||
val coverHeight = parent.itemWidth / 3 * 4
|
val coverHeight = parent.itemWidth / 3 * 4
|
||||||
view.apply {
|
view.apply {
|
||||||
card.layoutParams = ConstraintLayout.LayoutParams(
|
card.layoutParams = ConstraintLayout.LayoutParams(
|
||||||
MATCH_PARENT, coverHeight
|
MATCH_PARENT,
|
||||||
|
coverHeight
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
LibraryComfortableGridHolder(view, adapter)
|
LibraryComfortableGridHolder(view, adapter)
|
||||||
|
@ -19,14 +19,16 @@ import eu.kanade.tachiyomi.util.lang.combineLatest
|
|||||||
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
||||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
import eu.kanade.tachiyomi.util.removeCovers
|
import eu.kanade.tachiyomi.util.removeCovers
|
||||||
import java.util.Collections
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_IGNORE
|
||||||
import java.util.Comparator
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_INCLUDE
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.Collections
|
||||||
|
import java.util.Comparator
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class containing library information.
|
* Class containing library information.
|
||||||
@ -110,34 +112,45 @@ class LibraryPresenter(
|
|||||||
* @param map the map to filter.
|
* @param map the map to filter.
|
||||||
*/
|
*/
|
||||||
private fun applyFilters(map: LibraryMap): LibraryMap {
|
private fun applyFilters(map: LibraryMap): LibraryMap {
|
||||||
val filterDownloaded = preferences.downloadedOnly().get() || preferences.filterDownloaded().get()
|
val downloadedOnly = preferences.downloadedOnly().get()
|
||||||
|
val filterDownloaded = preferences.filterDownloaded().get()
|
||||||
val filterUnread = preferences.filterUnread().get()
|
val filterUnread = preferences.filterUnread().get()
|
||||||
val filterCompleted = preferences.filterCompleted().get()
|
val filterCompleted = preferences.filterCompleted().get()
|
||||||
|
|
||||||
val filterFn: (LibraryItem) -> Boolean = f@{ item ->
|
val filterFnUnread: (LibraryItem) -> Boolean = unread@{ item ->
|
||||||
// Filter when there isn't unread chapters.
|
if (filterUnread == STATE_IGNORE) return@unread true
|
||||||
if (filterUnread && item.manga.unread == 0) {
|
val isUnread = item.manga.unread != 0
|
||||||
return@f false
|
|
||||||
|
return@unread if (filterUnread == STATE_INCLUDE) isUnread
|
||||||
|
else !isUnread
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterCompleted && item.manga.status != SManga.COMPLETED) {
|
val filterFnCompleted: (LibraryItem) -> Boolean = completed@{ item ->
|
||||||
return@f false
|
if (filterCompleted == STATE_IGNORE) return@completed true
|
||||||
|
val isCompleted = item.manga.status == SManga.COMPLETED
|
||||||
|
|
||||||
|
return@completed if (filterCompleted == STATE_INCLUDE) isCompleted
|
||||||
|
else !isCompleted
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter when there are no downloads.
|
val filterFnDownloaded: (LibraryItem) -> Boolean = downloaded@{ item ->
|
||||||
if (filterDownloaded) {
|
if (!downloadedOnly && filterDownloaded == STATE_IGNORE) return@downloaded true
|
||||||
// Local manga are always downloaded
|
val isDownloaded = when {
|
||||||
if (item.manga.isLocal()) {
|
item.manga.isLocal() -> true
|
||||||
return@f true
|
item.downloadCount != -1 -> item.downloadCount > 0
|
||||||
}
|
else -> downloadManager.getDownloadCount(item.manga) > 0
|
||||||
// Don't bother with directory checking if download count has been set.
|
|
||||||
if (item.downloadCount != -1) {
|
|
||||||
return@f item.downloadCount > 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return@f downloadManager.getDownloadCount(item.manga) > 0
|
return@downloaded if (downloadedOnly || filterDownloaded == STATE_INCLUDE) isDownloaded
|
||||||
|
else !isDownloaded
|
||||||
}
|
}
|
||||||
true
|
|
||||||
|
val filterFn: (LibraryItem) -> Boolean = filter@{ item ->
|
||||||
|
return@filter !(
|
||||||
|
!filterFnUnread(item) ||
|
||||||
|
!filterFnCompleted(item) ||
|
||||||
|
!filterFnDownloaded(item)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return map.mapValues { entry -> entry.value.filter(filterFn) }
|
return map.mapValues { entry -> entry.value.filter(filterFn) }
|
||||||
|
@ -1,33 +1,36 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import com.bluelinelabs.conductor.Router
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||||
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_EXCLUDE
|
||||||
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_IGNORE
|
||||||
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_INCLUDE
|
||||||
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
|
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class LibrarySettingsSheet(
|
class LibrarySettingsSheet(
|
||||||
activity: Activity,
|
router: Router,
|
||||||
onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
|
onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
|
||||||
) : TabbedBottomSheetDialog(activity) {
|
) : TabbedBottomSheetDialog(router) {
|
||||||
|
|
||||||
val filters: Filter
|
val filters: Filter
|
||||||
private val sort: Sort
|
private val sort: Sort
|
||||||
private val display: Display
|
private val display: Display
|
||||||
|
|
||||||
init {
|
init {
|
||||||
filters = Filter(activity)
|
filters = Filter(router.activity!!)
|
||||||
filters.onGroupClicked = onGroupClickListener
|
filters.onGroupClicked = onGroupClickListener
|
||||||
|
|
||||||
sort = Sort(activity)
|
sort = Sort(router.activity!!)
|
||||||
sort.onGroupClicked = onGroupClickListener
|
sort.onGroupClicked = onGroupClickListener
|
||||||
|
|
||||||
display = Display(activity)
|
display = Display(router.activity!!)
|
||||||
display.onGroupClicked = onGroupClickListener
|
display.onGroupClicked = onGroupClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,33 +62,43 @@ class LibrarySettingsSheet(
|
|||||||
* Returns true if there's at least one filter from [FilterGroup] active.
|
* Returns true if there's at least one filter from [FilterGroup] active.
|
||||||
*/
|
*/
|
||||||
fun hasActiveFilters(): Boolean {
|
fun hasActiveFilters(): Boolean {
|
||||||
return filterGroup.items.any { it.checked }
|
return filterGroup.items.any { it.state != Item.TriStateGroup.STATE_IGNORE }
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class FilterGroup : Group {
|
inner class FilterGroup : Group {
|
||||||
|
|
||||||
private val downloaded = Item.CheckboxGroup(R.string.action_filter_downloaded, this)
|
private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this)
|
||||||
private val unread = Item.CheckboxGroup(R.string.action_filter_unread, this)
|
private val unread = Item.TriStateGroup(R.string.action_filter_unread, this)
|
||||||
private val completed = Item.CheckboxGroup(R.string.completed, this)
|
private val completed = Item.TriStateGroup(R.string.completed, this)
|
||||||
|
|
||||||
override val header = null
|
override val header = null
|
||||||
override val items = listOf(downloaded, unread, completed)
|
override val items = listOf(downloaded, unread, completed)
|
||||||
override val footer = null
|
override val footer = null
|
||||||
|
|
||||||
override fun initModels() {
|
override fun initModels() {
|
||||||
downloaded.checked = preferences.downloadedOnly().get() || preferences.filterDownloaded().get()
|
if (preferences.downloadedOnly().get()) {
|
||||||
downloaded.enabled = !preferences.downloadedOnly().get()
|
downloaded.state = STATE_INCLUDE
|
||||||
unread.checked = preferences.filterUnread().get()
|
downloaded.enabled = false
|
||||||
completed.checked = preferences.filterCompleted().get()
|
} else {
|
||||||
|
downloaded.state = preferences.filterDownloaded().get()
|
||||||
|
}
|
||||||
|
unread.state = preferences.filterUnread().get()
|
||||||
|
completed.state = preferences.filterCompleted().get()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClicked(item: Item) {
|
override fun onItemClicked(item: Item) {
|
||||||
item as Item.CheckboxGroup
|
item as Item.TriStateGroup
|
||||||
item.checked = !item.checked
|
val newState = when (item.state) {
|
||||||
|
STATE_IGNORE -> STATE_INCLUDE
|
||||||
|
STATE_INCLUDE -> STATE_EXCLUDE
|
||||||
|
STATE_EXCLUDE -> STATE_IGNORE
|
||||||
|
else -> throw Exception("Unknown State")
|
||||||
|
}
|
||||||
|
item.state = newState
|
||||||
when (item) {
|
when (item) {
|
||||||
downloaded -> preferences.filterDownloaded().set(item.checked)
|
downloaded -> preferences.filterDownloaded().set(newState)
|
||||||
unread -> preferences.filterUnread().set(item.checked)
|
unread -> preferences.filterUnread().set(newState)
|
||||||
completed -> preferences.filterCompleted().set(item.checked)
|
completed -> preferences.filterCompleted().set(newState)
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter.notifyItemChanged(item)
|
adapter.notifyItemChanged(item)
|
||||||
|
@ -44,13 +44,13 @@ import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
|||||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import java.util.Date
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import kotlinx.android.synthetic.main.main_activity.appbar
|
import kotlinx.android.synthetic.main.main_activity.appbar
|
||||||
import kotlinx.android.synthetic.main.main_activity.tabs
|
import kotlinx.android.synthetic.main.main_activity.tabs
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class MainActivity : BaseActivity<MainActivityBinding>() {
|
class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||||
|
|
||||||
@ -126,7 +126,8 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
|||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
router.addChangeListener(object : ControllerChangeHandler.ControllerChangeListener {
|
router.addChangeListener(
|
||||||
|
object : ControllerChangeHandler.ControllerChangeListener {
|
||||||
override fun onChangeStarted(
|
override fun onChangeStarted(
|
||||||
to: Controller?,
|
to: Controller?,
|
||||||
from: Controller?,
|
from: Controller?,
|
||||||
@ -145,7 +146,8 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
|||||||
handler: ControllerChangeHandler
|
handler: ControllerChangeHandler
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
syncActivityViewWithController(router.backstack.lastOrNull()?.controller())
|
syncActivityViewWithController(router.backstack.lastOrNull()?.controller())
|
||||||
|
|
||||||
|
@ -52,7 +52,6 @@ import eu.kanade.tachiyomi.ui.library.ChangeMangaCoverDialog
|
|||||||
import eu.kanade.tachiyomi.ui.library.LibraryController
|
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.main.offsetAppbarHeight
|
import eu.kanade.tachiyomi.ui.main.offsetAppbarHeight
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterDividerItemDecoration
|
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSettingsSheet
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSettingsSheet
|
||||||
@ -65,13 +64,13 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
|||||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryController
|
import eu.kanade.tachiyomi.ui.recent.history.HistoryController
|
||||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
||||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.NoChaptersException
|
||||||
import eu.kanade.tachiyomi.util.hasCustomCover
|
import eu.kanade.tachiyomi.util.hasCustomCover
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.getCoordinates
|
import eu.kanade.tachiyomi.util.view.getCoordinates
|
||||||
import eu.kanade.tachiyomi.util.view.shrinkOnScroll
|
import eu.kanade.tachiyomi.util.view.shrinkOnScroll
|
||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
import kotlin.math.min
|
|
||||||
import kotlinx.android.synthetic.main.main_activity.root_coordinator
|
import kotlinx.android.synthetic.main.main_activity.root_coordinator
|
||||||
import kotlinx.android.synthetic.main.main_activity.toolbar
|
import kotlinx.android.synthetic.main.main_activity.toolbar
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@ -83,6 +82,7 @@ import timber.log.Timber
|
|||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
class MangaController :
|
class MangaController :
|
||||||
NucleusController<MangaControllerBinding, MangaPresenter>,
|
NucleusController<MangaControllerBinding, MangaPresenter>,
|
||||||
@ -207,7 +207,6 @@ class MangaController :
|
|||||||
|
|
||||||
binding.recycler.adapter = ConcatAdapter(mangaInfoAdapter, chaptersHeaderAdapter, chaptersAdapter)
|
binding.recycler.adapter = ConcatAdapter(mangaInfoAdapter, chaptersHeaderAdapter, chaptersAdapter)
|
||||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||||
binding.recycler.addItemDecoration(ChapterDividerItemDecoration(view.context))
|
|
||||||
binding.recycler.setHasFixedSize(true)
|
binding.recycler.setHasFixedSize(true)
|
||||||
chaptersAdapter?.fastScroller = binding.fastScroller
|
chaptersAdapter?.fastScroller = binding.fastScroller
|
||||||
|
|
||||||
@ -238,7 +237,7 @@ class MangaController :
|
|||||||
|
|
||||||
binding.actionToolbar.offsetAppbarHeight(activity!!)
|
binding.actionToolbar.offsetAppbarHeight(activity!!)
|
||||||
|
|
||||||
settingsSheet = ChaptersSettingsSheet(activity!!, presenter) { group ->
|
settingsSheet = ChaptersSettingsSheet(router, presenter) { group ->
|
||||||
if (group is ChaptersSettingsSheet.Filter.FilterGroup) {
|
if (group is ChaptersSettingsSheet.Filter.FilterGroup) {
|
||||||
updateFilterIconState()
|
updateFilterIconState()
|
||||||
chaptersAdapter?.notifyDataSetChanged()
|
chaptersAdapter?.notifyDataSetChanged()
|
||||||
@ -343,7 +342,8 @@ class MangaController :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
// Hide download options for local manga
|
// Hide options for local manga
|
||||||
|
menu.findItem(R.id.action_share).isVisible = !isLocalSource
|
||||||
menu.findItem(R.id.download_group).isVisible = !isLocalSource
|
menu.findItem(R.id.download_group).isVisible = !isLocalSource
|
||||||
|
|
||||||
// Hide options for non-library manga
|
// Hide options for non-library manga
|
||||||
@ -354,6 +354,7 @@ class MangaController :
|
|||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
|
R.id.action_share -> shareManga()
|
||||||
R.id.download_next, R.id.download_next_5, R.id.download_next_10,
|
R.id.download_next, R.id.download_next_5, R.id.download_next_10,
|
||||||
R.id.download_custom, R.id.download_unread, R.id.download_all
|
R.id.download_custom, R.id.download_unread, R.id.download_all
|
||||||
-> downloadChapters(item.itemId)
|
-> downloadChapters(item.itemId)
|
||||||
@ -694,8 +695,12 @@ class MangaController :
|
|||||||
fun onFetchChaptersError(error: Throwable) {
|
fun onFetchChaptersError(error: Throwable) {
|
||||||
isRefreshingChapters = false
|
isRefreshingChapters = false
|
||||||
updateRefreshing()
|
updateRefreshing()
|
||||||
|
if (error is NoChaptersException) {
|
||||||
|
activity?.toast(activity?.getString(R.string.no_chapters_error))
|
||||||
|
} else {
|
||||||
activity?.toast(error.message)
|
activity?.toast(error.message)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onChapterStatusChange(download: Download) {
|
fun onChapterStatusChange(download: Download) {
|
||||||
chaptersAdapter?.currentItems?.find { it.id == download.chapter.id }?.let {
|
chaptersAdapter?.currentItems?.find { it.id == download.chapter.id }?.let {
|
||||||
|
@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.source.LocalSource
|
|||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import eu.kanade.tachiyomi.util.isLocal
|
import eu.kanade.tachiyomi.util.isLocal
|
||||||
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
||||||
@ -26,7 +27,6 @@ import eu.kanade.tachiyomi.util.prepUpdateCover
|
|||||||
import eu.kanade.tachiyomi.util.removeCovers
|
import eu.kanade.tachiyomi.util.removeCovers
|
||||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||||
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
||||||
import java.util.Date
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
@ -34,6 +34,7 @@ import rx.schedulers.Schedulers
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
class MangaPresenter(
|
class MangaPresenter(
|
||||||
val manga: Manga,
|
val manga: Manga,
|
||||||
@ -82,6 +83,10 @@ class MangaPresenter(
|
|||||||
override fun onCreate(savedState: Bundle?) {
|
override fun onCreate(savedState: Bundle?) {
|
||||||
super.onCreate(savedState)
|
super.onCreate(savedState)
|
||||||
|
|
||||||
|
if (!manga.favorite) {
|
||||||
|
ChapterSettingsHelper.applySettingDefaults(manga)
|
||||||
|
}
|
||||||
|
|
||||||
// Manga info - start
|
// Manga info - start
|
||||||
|
|
||||||
getMangaObservable()
|
getMangaObservable()
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Canvas
|
|
||||||
import android.graphics.Rect
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.view.View
|
|
||||||
import androidx.core.view.forEach
|
|
||||||
import androidx.core.view.marginBottom
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mimics a DividerItemDecoration that doesn't draw between the first two items.
|
|
||||||
*
|
|
||||||
* Used in MangaController since the manga info header and chapters header are the first two
|
|
||||||
* items in the list using a ConcatAdapter.
|
|
||||||
*/
|
|
||||||
class ChapterDividerItemDecoration(context: Context) : RecyclerView.ItemDecoration() {
|
|
||||||
|
|
||||||
private val divider: Drawable
|
|
||||||
|
|
||||||
init {
|
|
||||||
val a = context.obtainStyledAttributes(intArrayOf(android.R.attr.listDivider))
|
|
||||||
divider = a.getDrawable(0)!!
|
|
||||||
a.recycle()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
|
||||||
if (parent.layoutManager == null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.save()
|
|
||||||
parent.forEach {
|
|
||||||
val top = it.bottom + it.marginBottom
|
|
||||||
val bottom = top + divider.intrinsicHeight
|
|
||||||
val left = parent.paddingStart
|
|
||||||
val right = parent.width - parent.paddingEnd
|
|
||||||
divider.setBounds(left, top, right, bottom)
|
|
||||||
divider.draw(canvas)
|
|
||||||
}
|
|
||||||
canvas.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemOffsets(
|
|
||||||
outRect: Rect,
|
|
||||||
view: View,
|
|
||||||
parent: RecyclerView,
|
|
||||||
state: RecyclerView.State
|
|
||||||
) {
|
|
||||||
val position = parent.getChildAdapterPosition(view)
|
|
||||||
|
|
||||||
if (position == 0) {
|
|
||||||
outRect.setEmpty()
|
|
||||||
} else {
|
|
||||||
outRect.set(0, 0, 0, divider.intrinsicHeight)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,11 +9,11 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||||
import java.util.Date
|
|
||||||
import kotlinx.android.synthetic.main.chapters_item.bookmark_icon
|
import kotlinx.android.synthetic.main.chapters_item.bookmark_icon
|
||||||
import kotlinx.android.synthetic.main.chapters_item.chapter_description
|
import kotlinx.android.synthetic.main.chapters_item.chapter_description
|
||||||
import kotlinx.android.synthetic.main.chapters_item.chapter_title
|
import kotlinx.android.synthetic.main.chapters_item.chapter_title
|
||||||
import kotlinx.android.synthetic.main.chapters_item.download_text
|
import kotlinx.android.synthetic.main.chapters_item.download_text
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
class ChapterHolder(
|
class ChapterHolder(
|
||||||
view: View,
|
view: View,
|
||||||
|
@ -6,10 +6,10 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.text.DecimalFormatSymbols
|
import java.text.DecimalFormatSymbols
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class ChaptersAdapter(
|
class ChaptersAdapter(
|
||||||
controller: MangaController,
|
controller: MangaController,
|
||||||
|
@ -1,34 +1,39 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga.chapter
|
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.bluelinelabs.conductor.Router
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaPresenter
|
import eu.kanade.tachiyomi.ui.manga.MangaPresenter
|
||||||
|
import eu.kanade.tachiyomi.util.view.popupMenu
|
||||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||||
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
|
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
|
||||||
|
|
||||||
class ChaptersSettingsSheet(
|
class ChaptersSettingsSheet(
|
||||||
activity: Activity,
|
private val router: Router,
|
||||||
private val presenter: MangaPresenter,
|
private val presenter: MangaPresenter,
|
||||||
onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
|
onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
|
||||||
) : TabbedBottomSheetDialog(activity) {
|
) : TabbedBottomSheetDialog(router) {
|
||||||
|
|
||||||
val filters: Filter
|
val filters: Filter
|
||||||
private val sort: Sort
|
private val sort: Sort
|
||||||
private val display: Display
|
private val display: Display
|
||||||
|
|
||||||
init {
|
init {
|
||||||
filters = Filter(activity)
|
filters = Filter(router.activity!!)
|
||||||
filters.onGroupClicked = onGroupClickListener
|
filters.onGroupClicked = onGroupClickListener
|
||||||
|
|
||||||
sort = Sort(activity)
|
sort = Sort(router.activity!!)
|
||||||
sort.onGroupClicked = onGroupClickListener
|
sort.onGroupClicked = onGroupClickListener
|
||||||
|
|
||||||
display = Display(activity)
|
display = Display(router.activity!!)
|
||||||
display.onGroupClicked = onGroupClickListener
|
display.onGroupClicked = onGroupClickListener
|
||||||
|
|
||||||
|
binding.menu.isVisible = true
|
||||||
|
binding.menu.setOnClickListener { it.post { showPopupMenu(it) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTabViews(): List<View> = listOf(
|
override fun getTabViews(): List<View> = listOf(
|
||||||
@ -43,6 +48,23 @@ class ChaptersSettingsSheet(
|
|||||||
R.string.action_display
|
R.string.action_display
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun showPopupMenu(view: View) {
|
||||||
|
view.popupMenu(
|
||||||
|
R.menu.default_chapter_filter,
|
||||||
|
{
|
||||||
|
},
|
||||||
|
{
|
||||||
|
when (this.itemId) {
|
||||||
|
R.id.set_as_default -> {
|
||||||
|
SetChapterSettingsDialog(presenter.manga).showDialog(router)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters group (unread, downloaded, ...).
|
* Filters group (unread, downloaded, ...).
|
||||||
*/
|
*/
|
||||||
|
@ -66,7 +66,7 @@ class MangaChaptersHeaderAdapter(
|
|||||||
} else {
|
} else {
|
||||||
view.context.getResourceColor(R.attr.colorOnPrimary)
|
view.context.getResourceColor(R.attr.colorOnPrimary)
|
||||||
}
|
}
|
||||||
DrawableCompat.setTint(binding.btnChaptersFilter.icon, filterColor)
|
DrawableCompat.setTint(binding.btnChaptersFilter.drawable, filterColor)
|
||||||
|
|
||||||
merge(view.clicks(), binding.btnChaptersFilter.clicks())
|
merge(view.clicks(), binding.btnChaptersFilter.clicks())
|
||||||
.onEach { controller.showSettingsSheet() }
|
.onEach { controller.showSettingsSheet() }
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.manga.chapter
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import com.afollestad.materialdialogs.customview.customView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
|
||||||
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import eu.kanade.tachiyomi.widget.DialogCheckboxView
|
||||||
|
|
||||||
|
class SetChapterSettingsDialog(bundle: Bundle? = null) : DialogController(bundle) {
|
||||||
|
|
||||||
|
constructor(manga: Manga) : this(
|
||||||
|
Bundle().apply {
|
||||||
|
putSerializable(MANGA_KEY, manga)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
val view = DialogCheckboxView(activity!!).apply {
|
||||||
|
setDescription(R.string.confirm_set_chapter_settings)
|
||||||
|
setOptionDescription(R.string.also_set_chapter_settings_for_library)
|
||||||
|
}
|
||||||
|
|
||||||
|
return MaterialDialog(activity!!)
|
||||||
|
.title(R.string.chapter_settings)
|
||||||
|
.customView(
|
||||||
|
view = view,
|
||||||
|
horizontalPadding = true
|
||||||
|
)
|
||||||
|
.positiveButton(android.R.string.ok) {
|
||||||
|
ChapterSettingsHelper.setGlobalSettings(args.getSerializable(MANGA_KEY)!! as Manga)
|
||||||
|
if (view.isChecked()) {
|
||||||
|
ChapterSettingsHelper.updateAllMangasWithGlobalDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
activity?.toast(activity!!.getString(R.string.chapter_settings_updated))
|
||||||
|
}
|
||||||
|
.negativeButton(android.R.string.cancel)
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val MANGA_KEY = "manga"
|
||||||
|
}
|
||||||
|
}
|
@ -105,13 +105,27 @@ class MangaInfoHeaderAdapter(
|
|||||||
isVisible = true
|
isVisible = true
|
||||||
|
|
||||||
if (trackCount > 0) {
|
if (trackCount > 0) {
|
||||||
setIconResource(R.drawable.ic_done_24dp)
|
setCompoundDrawablesWithIntrinsicBounds(
|
||||||
text = view.context.resources.getQuantityString(R.plurals.num_trackers, trackCount, trackCount)
|
null,
|
||||||
isChecked = true
|
ContextCompat.getDrawable(context, R.drawable.ic_done_24dp),
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
text = view.context.resources.getQuantityString(
|
||||||
|
R.plurals.num_trackers,
|
||||||
|
trackCount,
|
||||||
|
trackCount
|
||||||
|
)
|
||||||
|
isSelected = true
|
||||||
} else {
|
} else {
|
||||||
setIconResource(R.drawable.ic_sync_24dp)
|
setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
null,
|
||||||
|
ContextCompat.getDrawable(context, R.drawable.ic_sync_24dp),
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
text = view.context.getString(R.string.manga_tracking_tab)
|
text = view.context.getString(R.string.manga_tracking_tab)
|
||||||
isChecked = false
|
isSelected = false
|
||||||
}
|
}
|
||||||
|
|
||||||
clicks()
|
clicks()
|
||||||
@ -128,12 +142,6 @@ class MangaInfoHeaderAdapter(
|
|||||||
.onEach { controller.openMangaInWebView() }
|
.onEach { controller.openMangaInWebView() }
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
binding.btnWebview.setTooltip(R.string.action_open_in_web_view)
|
binding.btnWebview.setTooltip(R.string.action_open_in_web_view)
|
||||||
|
|
||||||
binding.btnShare.isVisible = true
|
|
||||||
binding.btnShare.clicks()
|
|
||||||
.onEach { controller.shareManga() }
|
|
||||||
.launchIn(scope)
|
|
||||||
binding.btnShare.setTooltip(R.string.action_share)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.mangaFullTitle.longClicks()
|
binding.mangaFullTitle.longClicks()
|
||||||
@ -285,14 +293,24 @@ class MangaInfoHeaderAdapter(
|
|||||||
|
|
||||||
// Update genres list
|
// Update genres list
|
||||||
if (!manga.genre.isNullOrBlank()) {
|
if (!manga.genre.isNullOrBlank()) {
|
||||||
binding.mangaGenresTagsCompactChips.setChips(manga.getGenres(), controller::performSearch)
|
binding.mangaGenresTagsCompactChips.setChips(
|
||||||
binding.mangaGenresTagsFullChips.setChips(manga.getGenres(), controller::performSearch)
|
manga.getGenres(),
|
||||||
|
controller::performSearch
|
||||||
|
)
|
||||||
|
binding.mangaGenresTagsFullChips.setChips(
|
||||||
|
manga.getGenres(),
|
||||||
|
controller::performSearch
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.mangaGenresTagsWrapper.isVisible = false
|
binding.mangaGenresTagsWrapper.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle showing more or less info
|
// Handle showing more or less info
|
||||||
merge(binding.mangaSummarySection.clicks(), binding.mangaSummaryText.clicks(), binding.mangaInfoToggle.clicks())
|
merge(
|
||||||
|
binding.mangaSummarySection.clicks(),
|
||||||
|
binding.mangaSummaryText.clicks(),
|
||||||
|
binding.mangaInfoToggle.clicks()
|
||||||
|
)
|
||||||
.onEach { toggleMangaInfo(view.context) }
|
.onEach { toggleMangaInfo(view.context) }
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
||||||
@ -310,20 +328,22 @@ class MangaInfoHeaderAdapter(
|
|||||||
|
|
||||||
private fun toggleMangaInfo(context: Context) {
|
private fun toggleMangaInfo(context: Context) {
|
||||||
val isExpanded =
|
val isExpanded =
|
||||||
binding.mangaInfoToggle.text == context.getString(R.string.manga_info_collapse)
|
binding.mangaInfoToggle.contentDescription == context.getString(R.string.manga_info_collapse)
|
||||||
|
|
||||||
with(binding.mangaInfoToggle) {
|
with(binding.mangaInfoToggle) {
|
||||||
text = if (isExpanded) {
|
contentDescription = if (isExpanded) {
|
||||||
context.getString(R.string.manga_info_expand)
|
context.getString(R.string.manga_info_expand)
|
||||||
} else {
|
} else {
|
||||||
context.getString(R.string.manga_info_collapse)
|
context.getString(R.string.manga_info_collapse)
|
||||||
}
|
}
|
||||||
|
|
||||||
icon = if (isExpanded) {
|
setImageDrawable(
|
||||||
|
if (isExpanded) {
|
||||||
context.getDrawable(R.drawable.ic_baseline_expand_more_24dp)
|
context.getDrawable(R.drawable.ic_baseline_expand_more_24dp)
|
||||||
} else {
|
} else {
|
||||||
context.getDrawable(R.drawable.ic_baseline_expand_less_24dp)
|
context.getDrawable(R.drawable.ic_baseline_expand_less_24dp)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.mangaSummaryText) {
|
with(binding.mangaSummaryText) {
|
||||||
@ -355,13 +375,18 @@ class MangaInfoHeaderAdapter(
|
|||||||
// Set the Favorite drawable to the correct one.
|
// Set the Favorite drawable to the correct one.
|
||||||
// Border drawable if false, filled drawable if true.
|
// Border drawable if false, filled drawable if true.
|
||||||
binding.btnFavorite.apply {
|
binding.btnFavorite.apply {
|
||||||
icon = ContextCompat.getDrawable(
|
setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
null,
|
||||||
|
ContextCompat.getDrawable(
|
||||||
context,
|
context,
|
||||||
if (isFavorite) R.drawable.ic_favorite_24dp else R.drawable.ic_favorite_border_24dp
|
if (isFavorite) R.drawable.ic_favorite_24dp else R.drawable.ic_favorite_border_24dp
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
null
|
||||||
)
|
)
|
||||||
text =
|
text =
|
||||||
context.getString(if (isFavorite) R.string.in_library else R.string.add_to_library)
|
context.getString(if (isFavorite) R.string.in_library else R.string.add_to_library)
|
||||||
isChecked = isFavorite
|
isSelected = isFavorite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
import java.util.Calendar
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
class SetTrackReadingDatesDialog<T> : DialogController
|
class SetTrackReadingDatesDialog<T> : DialogController
|
||||||
where T : Controller, T : SetTrackReadingDatesDialog.Listener {
|
where T : Controller, T : SetTrackReadingDatesDialog.Listener {
|
||||||
|
@ -5,8 +5,8 @@ import androidx.core.view.isVisible
|
|||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.databinding.TrackItemBinding
|
import eu.kanade.tachiyomi.databinding.TrackItemBinding
|
||||||
import eu.kanade.tachiyomi.ui.base.holder.BaseViewHolder
|
import eu.kanade.tachiyomi.ui.base.holder.BaseViewHolder
|
||||||
import java.text.DateFormat
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.text.DateFormat
|
||||||
|
|
||||||
class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter) : BaseViewHolder(binding.root) {
|
class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter) : BaseViewHolder(binding.root) {
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
|||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import kotlinx.android.synthetic.main.track_search_dialog.view.progress
|
import kotlinx.android.synthetic.main.track_search_dialog.view.progress
|
||||||
import kotlinx.android.synthetic.main.track_search_dialog.view.track_search
|
import kotlinx.android.synthetic.main.track_search_dialog.view.track_search
|
||||||
import kotlinx.android.synthetic.main.track_search_dialog.view.track_search_list
|
import kotlinx.android.synthetic.main.track_search_dialog.view.track_search_list
|
||||||
@ -26,6 +25,7 @@ import reactivecircus.flowbinding.android.widget.itemClicks
|
|||||||
import reactivecircus.flowbinding.android.widget.textChanges
|
import reactivecircus.flowbinding.android.widget.textChanges
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class TrackSearchDialog : DialogController {
|
class TrackSearchDialog : DialogController {
|
||||||
|
|
||||||
|
@ -10,9 +10,9 @@ import com.afollestad.materialdialogs.MaterialDialog
|
|||||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateChecker
|
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdaterService
|
import eu.kanade.tachiyomi.data.updater.UpdaterService
|
||||||
|
import eu.kanade.tachiyomi.data.updater.github.GithubUpdateChecker
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
||||||
import eu.kanade.tachiyomi.util.lang.launchNow
|
import eu.kanade.tachiyomi.util.lang.launchNow
|
||||||
@ -23,19 +23,19 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
|||||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import timber.log.Timber
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
class AboutController : SettingsController() {
|
class AboutController : SettingsController() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for new releases
|
* Checks for new releases
|
||||||
*/
|
*/
|
||||||
private val updateChecker by lazy { UpdateChecker.getUpdateChecker() }
|
private val updateChecker by lazy { GithubUpdateChecker() }
|
||||||
|
|
||||||
private val dateFormat: DateFormat = preferences.dateFormat()
|
private val dateFormat: DateFormat = preferences.dateFormat()
|
||||||
|
|
||||||
@ -234,7 +234,9 @@ class AboutController : SettingsController() {
|
|||||||
val buildTime = inputDf.parse(BuildConfig.BUILD_TIME)
|
val buildTime = inputDf.parse(BuildConfig.BUILD_TIME)
|
||||||
|
|
||||||
val outputDf = DateFormat.getDateTimeInstance(
|
val outputDf = DateFormat.getDateTimeInstance(
|
||||||
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault()
|
DateFormat.MEDIUM,
|
||||||
|
DateFormat.SHORT,
|
||||||
|
Locale.getDefault()
|
||||||
)
|
)
|
||||||
outputDf.timeZone = TimeZone.getDefault()
|
outputDf.timeZone = TimeZone.getDefault()
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import androidx.preference.PreferenceScreen
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
|
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
@ -28,6 +27,7 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
|
|||||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
|
|
||||||
class MoreController :
|
class MoreController :
|
||||||
SettingsController(),
|
SettingsController(),
|
||||||
|
@ -21,6 +21,7 @@ import android.view.animation.Animation
|
|||||||
import android.view.animation.AnimationUtils
|
import android.view.animation.AnimationUtils
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.view.setPadding
|
import androidx.core.view.setPadding
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
@ -56,8 +57,6 @@ import eu.kanade.tachiyomi.util.view.showBar
|
|||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
import eu.kanade.tachiyomi.widget.SimpleAnimationListener
|
import eu.kanade.tachiyomi.widget.SimpleAnimationListener
|
||||||
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
|
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
|
||||||
import java.io.File
|
|
||||||
import kotlin.math.abs
|
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
@ -67,6 +66,8 @@ import kotlinx.coroutines.flow.sample
|
|||||||
import nucleus.factory.RequiresPresenter
|
import nucleus.factory.RequiresPresenter
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity containing the reader of Tachiyomi. This activity is mostly a container of the
|
* Activity containing the reader of Tachiyomi. This activity is mostly a container of the
|
||||||
@ -290,24 +291,27 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(binding.readerMenu) { _, insets ->
|
ViewCompat.setOnApplyWindowInsetsListener(binding.readerMenu) { _, insets ->
|
||||||
if (!window.isDefaultBar()) {
|
if (!window.isDefaultBar()) {
|
||||||
|
val systemInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
binding.readerMenu.setPadding(
|
binding.readerMenu.setPadding(
|
||||||
insets.systemWindowInsetLeft,
|
systemInsets.left,
|
||||||
insets.systemWindowInsetTop,
|
systemInsets.top,
|
||||||
insets.systemWindowInsetRight,
|
systemInsets.right,
|
||||||
insets.systemWindowInsetBottom
|
systemInsets.bottom
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init listeners on bottom menu
|
// Init listeners on bottom menu
|
||||||
binding.pageSeekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
binding.pageSeekbar.setOnSeekBarChangeListener(
|
||||||
|
object : SimpleSeekBarListener() {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||||
if (viewer != null && fromUser) {
|
if (viewer != null && fromUser) {
|
||||||
moveToPageIndex(value)
|
moveToPageIndex(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
binding.leftChapter.setOnClickListener {
|
binding.leftChapter.setOnClickListener {
|
||||||
if (viewer != null) {
|
if (viewer != null) {
|
||||||
if (viewer is R2LPagerViewer) {
|
if (viewer is R2LPagerViewer) {
|
||||||
@ -347,12 +351,14 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
|
|
||||||
if (animate) {
|
if (animate) {
|
||||||
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top)
|
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top)
|
||||||
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.
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
binding.toolbar.startAnimation(toolbarAnimation)
|
binding.toolbar.startAnimation(toolbarAnimation)
|
||||||
|
|
||||||
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_bottom)
|
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_bottom)
|
||||||
@ -371,11 +377,13 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
|
|
||||||
if (animate) {
|
if (animate) {
|
||||||
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_top)
|
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_top)
|
||||||
toolbarAnimation.setAnimationListener(object : SimpleAnimationListener() {
|
toolbarAnimation.setAnimationListener(
|
||||||
|
object : SimpleAnimationListener() {
|
||||||
override fun onAnimationEnd(animation: Animation) {
|
override fun onAnimationEnd(animation: Animation) {
|
||||||
binding.readerMenu.isVisible = false
|
binding.readerMenu.isVisible = false
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
binding.toolbar.startAnimation(toolbarAnimation)
|
binding.toolbar.startAnimation(toolbarAnimation)
|
||||||
|
|
||||||
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_bottom)
|
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_bottom)
|
||||||
@ -572,9 +580,13 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
* Called from the presenter when a page is ready to be shared. It shows Android's default
|
* Called from the presenter when a page is ready to be shared. It shows Android's default
|
||||||
* sharing tool.
|
* sharing tool.
|
||||||
*/
|
*/
|
||||||
fun onShareImageResult(file: File) {
|
fun onShareImageResult(file: File, page: ReaderPage) {
|
||||||
|
val manga = presenter.manga ?: return
|
||||||
|
val chapter = page.chapter.chapter
|
||||||
|
|
||||||
val stream = file.getUriCompat(this)
|
val stream = file.getUriCompat(this)
|
||||||
val intent = Intent(Intent.ACTION_SEND).apply {
|
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||||
|
putExtra(Intent.EXTRA_TEXT, getString(R.string.share_page_info, manga.title, chapter.name, page.number))
|
||||||
putExtra(Intent.EXTRA_STREAM, stream)
|
putExtra(Intent.EXTRA_STREAM, stream)
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
type = "image/*"
|
type = "image/*"
|
||||||
|
@ -74,45 +74,55 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet
|
|||||||
}
|
}
|
||||||
binding.colorFilterMode.setSelection(preferences.colorFilterMode().get(), false)
|
binding.colorFilterMode.setSelection(preferences.colorFilterMode().get(), false)
|
||||||
|
|
||||||
binding.seekbarColorFilterAlpha.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
binding.seekbarColorFilterAlpha.setOnSeekBarChangeListener(
|
||||||
|
object : SimpleSeekBarListener() {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
setColorValue(value, ALPHA_MASK, 24)
|
setColorValue(value, ALPHA_MASK, 24)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
binding.seekbarColorFilterRed.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
binding.seekbarColorFilterRed.setOnSeekBarChangeListener(
|
||||||
|
object : SimpleSeekBarListener() {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
setColorValue(value, RED_MASK, 16)
|
setColorValue(value, RED_MASK, 16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
binding.seekbarColorFilterGreen.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
binding.seekbarColorFilterGreen.setOnSeekBarChangeListener(
|
||||||
|
object : SimpleSeekBarListener() {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
setColorValue(value, GREEN_MASK, 8)
|
setColorValue(value, GREEN_MASK, 8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
binding.seekbarColorFilterBlue.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
binding.seekbarColorFilterBlue.setOnSeekBarChangeListener(
|
||||||
|
object : SimpleSeekBarListener() {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
setColorValue(value, BLUE_MASK, 0)
|
setColorValue(value, BLUE_MASK, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
binding.brightnessSeekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
binding.brightnessSeekbar.setOnSeekBarChangeListener(
|
||||||
|
object : SimpleSeekBarListener() {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
preferences.customBrightnessValue().set(value)
|
preferences.customBrightnessValue().set(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
|
@ -27,9 +27,6 @@ import eu.kanade.tachiyomi.util.lang.takeBytes
|
|||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
||||||
import java.io.File
|
|
||||||
import java.util.Date
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
@ -38,6 +35,9 @@ import rx.schedulers.Schedulers
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.File
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presenter used by the activity to perform background operations.
|
* Presenter used by the activity to perform background operations.
|
||||||
@ -569,7 +569,7 @@ class ReaderPresenter(
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeFirst(
|
.subscribeFirst(
|
||||||
{ view, file -> view.onShareImageResult(file) },
|
{ view, file -> view.onShareImageResult(file, page) },
|
||||||
{ _, _ -> /* Empty */ }
|
{ _, _ -> /* Empty */ }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ import eu.kanade.tachiyomi.source.model.Page
|
|||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
|
import rx.Observable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader used to load a chapter from a directory given on [file].
|
* Loader used to load a chapter from a directory given on [file].
|
||||||
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.ui.reader.loader
|
|||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||||
import eu.kanade.tachiyomi.util.storage.EpubFile
|
import eu.kanade.tachiyomi.util.storage.EpubFile
|
||||||
import java.io.File
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader used to load a chapter from a .epub file.
|
* Loader used to load a chapter from a .epub file.
|
||||||
|
@ -6,9 +6,6 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||||||
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.util.lang.plusAssign
|
import eu.kanade.tachiyomi.util.lang.plusAssign
|
||||||
import java.util.concurrent.PriorityBlockingQueue
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
import kotlin.math.min
|
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
@ -18,6 +15,9 @@ import rx.subscriptions.CompositeSubscription
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.concurrent.PriorityBlockingQueue
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader used to load chapters from an online source.
|
* Loader used to load chapters from an online source.
|
||||||
|
@ -4,14 +4,14 @@ import eu.kanade.tachiyomi.source.model.Page
|
|||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
|
import junrar.Archive
|
||||||
|
import junrar.rarfile.FileHeader
|
||||||
|
import rx.Observable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.PipedInputStream
|
import java.io.PipedInputStream
|
||||||
import java.io.PipedOutputStream
|
import java.io.PipedOutputStream
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import junrar.Archive
|
|
||||||
import junrar.rarfile.FileHeader
|
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader used to load a chapter from a .rar or .cbr file.
|
* Loader used to load a chapter from a .rar or .cbr file.
|
||||||
|
@ -5,11 +5,11 @@ import eu.kanade.tachiyomi.source.model.Page
|
|||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
|
import rx.Observable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipFile
|
import java.util.zip.ZipFile
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader used to load a chapter from a .zip or .cbz file.
|
* Loader used to load a chapter from a .zip or .cbz file.
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader.viewer
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import kotlin.math.floor
|
||||||
|
|
||||||
|
object MissingChapters {
|
||||||
|
|
||||||
|
fun hasMissingChapters(higher: Chapter, lower: Chapter): Boolean {
|
||||||
|
return hasMissingChapters(higher.chapter_number, lower.chapter_number)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasMissingChapters(higherChapterNumber: Float, lowerChapterNumber: Float): Boolean {
|
||||||
|
return floor(higherChapterNumber) - floor(lowerChapterNumber) - 1f > 0f
|
||||||
|
}
|
||||||
|
}
|
@ -63,9 +63,12 @@ class ReaderProgressBar @JvmOverloads constructor(
|
|||||||
*/
|
*/
|
||||||
private val rotationAnimation by lazy {
|
private val rotationAnimation by lazy {
|
||||||
RotateAnimation(
|
RotateAnimation(
|
||||||
0f, 360f,
|
0f,
|
||||||
Animation.RELATIVE_TO_SELF, 0.5f,
|
360f,
|
||||||
Animation.RELATIVE_TO_SELF, 0.5f
|
Animation.RELATIVE_TO_SELF,
|
||||||
|
0.5f,
|
||||||
|
Animation.RELATIVE_TO_SELF,
|
||||||
|
0.5f
|
||||||
).apply {
|
).apply {
|
||||||
interpolator = LinearInterpolator()
|
interpolator = LinearInterpolator()
|
||||||
repeatCount = Animation.INFINITE
|
repeatCount = Animation.INFINITE
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user