mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-24 02:21:51 +01:00
commit
4ac4923d15
@ -29,17 +29,17 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 27
|
compileSdkVersion 29
|
||||||
buildToolsVersion '28.0.3'
|
buildToolsVersion '29.0.2'
|
||||||
publishNonDefault true
|
publishNonDefault true
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "eu.kanade.tachiyomi"
|
applicationId "eu.kanade.tachiyomi"
|
||||||
minSdkVersion 16
|
minSdkVersion 21
|
||||||
targetSdkVersion 27
|
targetSdkVersion 29
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
versionCode 41
|
versionCode 42
|
||||||
versionName "0.8.4"
|
versionName "0.9.0"
|
||||||
|
|
||||||
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
|
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
|
||||||
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
|
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
|
||||||
@ -60,6 +60,9 @@ android {
|
|||||||
versionNameSuffix "-${getCommitCount()}"
|
versionNameSuffix "-${getCommitCount()}"
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".debug"
|
||||||
}
|
}
|
||||||
|
release {
|
||||||
|
applicationIdSuffix = '.j2k'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions "default"
|
flavorDimensions "default"
|
||||||
@ -73,7 +76,6 @@ android {
|
|||||||
dimension "default"
|
dimension "default"
|
||||||
}
|
}
|
||||||
dev {
|
dev {
|
||||||
minSdkVersion 21
|
|
||||||
resConfigs "en", "xxhdpi"
|
resConfigs "en", "xxhdpi"
|
||||||
dimension "default"
|
dimension "default"
|
||||||
}
|
}
|
||||||
@ -92,6 +94,15 @@ android {
|
|||||||
checkReleaseBuilds false
|
checkReleaseBuilds false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
targetCompatibility = 1.8
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -101,35 +112,35 @@ dependencies {
|
|||||||
implementation 'com.github.inorichi:junrar-android:634c1f5'
|
implementation 'com.github.inorichi:junrar-android:634c1f5'
|
||||||
|
|
||||||
// Android support library
|
// Android support library
|
||||||
final support_library_version = '27.0.2'
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
implementation "com.android.support:support-v4:$support_library_version"
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
implementation "com.android.support:appcompat-v7:$support_library_version"
|
implementation 'com.google.android.material:material:1.0.0'
|
||||||
implementation "com.android.support:cardview-v7:$support_library_version"
|
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||||
implementation "com.android.support:design:$support_library_version"
|
implementation 'androidx.preference:preference:1.1.0'
|
||||||
implementation "com.android.support:recyclerview-v7:$support_library_version"
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
implementation "com.android.support:preference-v7:$support_library_version"
|
implementation 'androidx.browser:browser:1.0.0'
|
||||||
implementation "com.android.support:support-annotations:$support_library_version"
|
|
||||||
implementation "com.android.support:customtabs:$support_library_version"
|
|
||||||
|
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
|
|
||||||
implementation 'com.android.support:multidex:1.0.3'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
|
|
||||||
standardImplementation 'com.google.firebase:firebase-core:11.8.0'
|
standardImplementation 'com.google.firebase:firebase-core:17.2.1'
|
||||||
|
|
||||||
// ReactiveX
|
// ReactiveX
|
||||||
implementation 'io.reactivex:rxandroid:1.2.1'
|
implementation 'io.reactivex:rxandroid:1.2.1'
|
||||||
implementation 'io.reactivex:rxjava:1.3.6'
|
implementation 'io.reactivex:rxjava:1.3.8'
|
||||||
implementation 'com.jakewharton.rxrelay:rxrelay:1.2.0'
|
implementation 'com.jakewharton.rxrelay:rxrelay:1.2.0'
|
||||||
implementation 'com.f2prateek.rx.preferences:rx-preferences:1.0.2'
|
implementation 'com.f2prateek.rx.preferences:rx-preferences:1.0.2'
|
||||||
implementation 'com.github.pwittchen:reactivenetwork:0.7.0'
|
implementation 'com.github.pwittchen:reactivenetwork:0.13.0'
|
||||||
|
|
||||||
// Network client
|
// Network client
|
||||||
implementation "com.squareup.okhttp3:okhttp:3.10.0"
|
final okhttp_version = "4.2.1"
|
||||||
implementation 'com.squareup.okio:okio:1.14.0'
|
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
||||||
|
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
|
||||||
|
implementation 'com.squareup.okio:okio:2.4.0'
|
||||||
|
|
||||||
// REST
|
// REST
|
||||||
final retrofit_version = '2.3.0'
|
final retrofit_version = '2.6.2'
|
||||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||||
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
|
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
|
||||||
implementation "com.squareup.retrofit2:adapter-rxjava:$retrofit_version"
|
implementation "com.squareup.retrofit2:adapter-rxjava:$retrofit_version"
|
||||||
@ -146,17 +157,17 @@ dependencies {
|
|||||||
implementation 'com.github.inorichi:unifile:e9ee588'
|
implementation 'com.github.inorichi:unifile:e9ee588'
|
||||||
|
|
||||||
// HTML parser
|
// HTML parser
|
||||||
implementation 'org.jsoup:jsoup:1.10.2'
|
implementation 'org.jsoup:jsoup:1.12.1'
|
||||||
|
|
||||||
// Job scheduling
|
// Job scheduling
|
||||||
implementation 'com.evernote:android-job:1.2.5'
|
implementation 'com.evernote:android-job:1.2.5'
|
||||||
implementation 'com.google.android.gms:play-services-gcm:11.8.0'
|
implementation 'com.google.android.gms:play-services-gcm:17.0.0'
|
||||||
|
|
||||||
// Changelog
|
// Changelog
|
||||||
implementation 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0'
|
implementation 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0'
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
implementation 'android.arch.persistence:db:1.0.0'
|
implementation 'androidx.sqlite:sqlite:2.0.1'
|
||||||
implementation 'com.github.inorichi.storio:storio-common:8be19de@aar'
|
implementation 'com.github.inorichi.storio:storio-common:8be19de@aar'
|
||||||
implementation 'com.github.inorichi.storio:storio-sqlite:8be19de@aar'
|
implementation 'com.github.inorichi.storio:storio-sqlite:8be19de@aar'
|
||||||
implementation 'io.requery:sqlite-android:3.25.2'
|
implementation 'io.requery:sqlite-android:3.25.2'
|
||||||
@ -170,16 +181,16 @@ dependencies {
|
|||||||
implementation "com.github.inorichi.injekt:injekt-core:65b0440"
|
implementation "com.github.inorichi.injekt:injekt-core:65b0440"
|
||||||
|
|
||||||
// Image library
|
// Image library
|
||||||
final glide_version = '4.6.1'
|
final glide_version = '4.10.0'
|
||||||
implementation "com.github.bumptech.glide:glide:$glide_version"
|
implementation "com.github.bumptech.glide:glide:$glide_version"
|
||||||
implementation "com.github.bumptech.glide:okhttp3-integration:$glide_version"
|
implementation "com.github.bumptech.glide:okhttp3-integration:$glide_version"
|
||||||
kapt "com.github.bumptech.glide:compiler:$glide_version"
|
kapt "com.github.bumptech.glide:compiler:$glide_version"
|
||||||
|
|
||||||
// Transformations
|
// Transformations
|
||||||
implementation 'jp.wasabeef:glide-transformations:3.1.1'
|
implementation 'jp.wasabeef:glide-transformations:4.0.0'
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
implementation 'com.jakewharton.timber:timber:4.6.1'
|
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||||
|
|
||||||
// Crash reports
|
// Crash reports
|
||||||
implementation 'ch.acra:acra:4.9.2'
|
implementation 'ch.acra:acra:4.9.2'
|
||||||
@ -190,24 +201,24 @@ dependencies {
|
|||||||
// UI
|
// UI
|
||||||
implementation 'com.dmitrymalkovich.android:material-design-dimens:1.4'
|
implementation 'com.dmitrymalkovich.android:material-design-dimens:1.4'
|
||||||
implementation 'com.github.dmytrodanylyk.android-process-button:library:1.0.4'
|
implementation 'com.github.dmytrodanylyk.android-process-button:library:1.0.4'
|
||||||
implementation 'eu.davidea:flexible-adapter:5.0.0-rc4'
|
implementation 'eu.davidea:flexible-adapter:5.1.0'
|
||||||
implementation 'eu.davidea:flexible-adapter-ui:1.0.0-b1'
|
implementation 'eu.davidea:flexible-adapter-ui:1.0.0'
|
||||||
implementation 'com.nononsenseapps:filepicker:2.5.2'
|
implementation 'com.nononsenseapps:filepicker:2.5.2'
|
||||||
implementation 'com.github.amulyakhare:TextDrawable:558677e'
|
implementation 'com.github.amulyakhare:TextDrawable:558677e'
|
||||||
implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
|
implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
|
||||||
implementation 'me.zhanghai.android.systemuihelper:library:1.0.0'
|
implementation 'me.zhanghai.android.systemuihelper:library:1.0.0'
|
||||||
implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.0.4'
|
implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0'
|
||||||
implementation 'com.github.mthli:Slice:v1.2'
|
implementation 'com.github.mthli:Slice:v1.2'
|
||||||
implementation 'me.gujun.android.taggroup:library:1.4@aar'
|
implementation 'me.gujun.android.taggroup:library:1.4@aar'
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.1.3'
|
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||||
implementation 'com.github.inorichi:DirectionalViewPager:3acc51a'
|
implementation 'com.github.carlosesco:DirectionalViewPager:a844dbca0a'
|
||||||
|
|
||||||
// Conductor
|
// Conductor
|
||||||
implementation 'com.bluelinelabs:conductor:2.1.5'
|
implementation 'com.bluelinelabs:conductor:2.1.5'
|
||||||
implementation ("com.bluelinelabs:conductor-support:2.1.5") {
|
implementation ("com.bluelinelabs:conductor-support:2.1.5") {
|
||||||
exclude group: "com.android.support"
|
exclude group: "com.android.support"
|
||||||
}
|
}
|
||||||
implementation 'com.github.inorichi:conductor-support-preference:27.0.2'
|
implementation project(":j2k-preference")
|
||||||
|
|
||||||
// RxBindings
|
// RxBindings
|
||||||
final rxbindings_version = '1.0.1'
|
final rxbindings_version = '1.0.1'
|
||||||
@ -228,18 +239,19 @@ dependencies {
|
|||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
|
||||||
final coroutines_version = '0.22.2'
|
final coroutines_version = '1.3.2'
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.2.71'
|
ext.kotlin_version = '1.3.50'
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,12 +259,6 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
|
||||||
experimental {
|
|
||||||
coroutines 'enable'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
androidExtensions {
|
androidExtensions {
|
||||||
experimental = true
|
experimental = true
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,10 @@
|
|||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".App"
|
android:name=".App"
|
||||||
@ -20,7 +23,8 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:largeHeap="true"
|
android:largeHeap="true"
|
||||||
android:theme="@style/Theme.Tachiyomi">
|
android:theme="@style/Theme.Tachiyomi"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config">
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.main.MainActivity"
|
android:name=".ui.main.MainActivity"
|
||||||
android:launchMode="singleTask">
|
android:launchMode="singleTask">
|
||||||
@ -43,6 +47,9 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.reader.ReaderActivity" />
|
android:name=".ui.reader.ReaderActivity" />
|
||||||
|
<activity
|
||||||
|
android:name=".ui.manga.info.WebViewActivity"
|
||||||
|
android:configChanges="uiMode|orientation|screenSize"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".widget.CustomLayoutPickerActivity"
|
android:name=".widget.CustomLayoutPickerActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
@ -95,7 +102,7 @@
|
|||||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
|
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="android.support.v4.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.provider"
|
android:authorities="${applicationId}.provider"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
|
@ -3,7 +3,7 @@ package eu.kanade.tachiyomi
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.support.multidex.MultiDex
|
import androidx.multidex.MultiDex
|
||||||
import com.evernote.android.job.JobManager
|
import com.evernote.android.job.JobManager
|
||||||
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
|
||||||
|
@ -39,7 +39,7 @@ object Migrations {
|
|||||||
if (oldDir.exists()) {
|
if (oldDir.exists()) {
|
||||||
val destDir = context.getExternalFilesDir("covers")
|
val destDir = context.getExternalFilesDir("covers")
|
||||||
if (destDir != null) {
|
if (destDir != null) {
|
||||||
oldDir.listFiles().forEach {
|
oldDir.listFiles()?.forEach {
|
||||||
it.renameTo(File(destDir, it.name))
|
it.renameTo(File(destDir, it.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,8 @@ class BackupCreateService : IntentService(NAME) {
|
|||||||
val uri = intent.getParcelableExtra<Uri>(BackupConst.EXTRA_URI)
|
val uri = intent.getParcelableExtra<Uri>(BackupConst.EXTRA_URI)
|
||||||
val flags = intent.getIntExtra(EXTRA_FLAGS, 0)
|
val flags = intent.getIntExtra(EXTRA_FLAGS, 0)
|
||||||
// Create backup
|
// Create backup
|
||||||
backupManager.createBackup(uri, flags, false)
|
if (uri != null)
|
||||||
|
backupManager.createBackup(uri, flags, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -160,9 +160,9 @@ class BackupRestoreService : Service() {
|
|||||||
* @return the start value of the command.
|
* @return the start value of the command.
|
||||||
*/
|
*/
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
if (intent == null) return Service.START_NOT_STICKY
|
if (intent == null) return START_NOT_STICKY
|
||||||
|
|
||||||
val uri = intent.getParcelableExtra<Uri>(BackupConst.EXTRA_URI)
|
val uri = intent.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY
|
||||||
|
|
||||||
// Unsubscribe from any previous subscription if needed.
|
// Unsubscribe from any previous subscription if needed.
|
||||||
subscription?.unsubscribe()
|
subscription?.unsubscribe()
|
||||||
@ -175,7 +175,7 @@ class BackupRestoreService : Service() {
|
|||||||
.subscribeOn(Schedulers.from(executor))
|
.subscribeOn(Schedulers.from(executor))
|
||||||
.subscribe()
|
.subscribe()
|
||||||
|
|
||||||
return Service.START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,7 +189,7 @@ class BackupRestoreService : Service() {
|
|||||||
|
|
||||||
return Observable.just(Unit)
|
return Observable.just(Unit)
|
||||||
.map {
|
.map {
|
||||||
val reader = JsonReader(contentResolver.openInputStream(uri).bufferedReader())
|
val reader = JsonReader(contentResolver.openInputStream(uri)!!.bufferedReader())
|
||||||
val json = JsonParser().parse(reader).asJsonObject
|
val json = JsonParser().parse(reader).asJsonObject
|
||||||
|
|
||||||
// Get parser version
|
// Get parser version
|
||||||
|
@ -11,6 +11,8 @@ import eu.kanade.tachiyomi.util.DiskUtil
|
|||||||
import eu.kanade.tachiyomi.util.saveTo
|
import eu.kanade.tachiyomi.util.saveTo
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okio.Okio
|
import okio.Okio
|
||||||
|
import okio.buffer
|
||||||
|
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.File
|
||||||
@ -126,7 +128,7 @@ class ChapterCache(private val context: Context) {
|
|||||||
editor = diskCache.edit(key) ?: return
|
editor = diskCache.edit(key) ?: return
|
||||||
|
|
||||||
// Write chapter urls to cache.
|
// Write chapter urls to cache.
|
||||||
Okio.buffer(Okio.sink(editor.newOutputStream(0))).use {
|
editor.newOutputStream(0).sink().buffer().use {
|
||||||
it.write(cachedValue.toByteArray())
|
it.write(cachedValue.toByteArray())
|
||||||
it.flush()
|
it.flush()
|
||||||
}
|
}
|
||||||
@ -186,12 +188,12 @@ class ChapterCache(private val context: Context) {
|
|||||||
editor = diskCache.edit(key) ?: throw IOException("Unable to edit key")
|
editor = diskCache.edit(key) ?: throw IOException("Unable to edit key")
|
||||||
|
|
||||||
// Get OutputStream and write image with Okio.
|
// Get OutputStream and write image with Okio.
|
||||||
response.body()!!.source().saveTo(editor.newOutputStream(0))
|
response.body!!.source().saveTo(editor.newOutputStream(0))
|
||||||
|
|
||||||
diskCache.flush()
|
diskCache.flush()
|
||||||
editor.commit()
|
editor.commit()
|
||||||
} finally {
|
} finally {
|
||||||
response.body()?.close()
|
response.body?.close()
|
||||||
editor?.abortUnlessCommitted()
|
editor?.abortUnlessCommitted()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package eu.kanade.tachiyomi.data.cache
|
package eu.kanade.tachiyomi.data.cache
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.util.DiskUtil
|
import eu.kanade.tachiyomi.util.DiskUtil
|
||||||
|
import eu.kanade.tachiyomi.util.launchUI
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -60,8 +64,7 @@ class CoverCache(private val context: Context) {
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
// Remove file.
|
// Remove file.
|
||||||
val file = getCoverFile(thumbnailUrl!!)
|
val file = getCoverFile(thumbnailUrl)
|
||||||
return file.exists() && file.delete()
|
return file.exists() && file.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.data.database
|
package eu.kanade.tachiyomi.data.database
|
||||||
|
|
||||||
import android.arch.persistence.db.SupportSQLiteOpenHelper
|
import androidx.sqlite.db.SupportSQLiteOpenHelper
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite
|
import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite
|
||||||
import eu.kanade.tachiyomi.data.database.mappers.*
|
import eu.kanade.tachiyomi.data.database.mappers.*
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.database
|
package eu.kanade.tachiyomi.data.database
|
||||||
|
|
||||||
import android.arch.persistence.db.SupportSQLiteDatabase
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import android.arch.persistence.db.SupportSQLiteOpenHelper
|
import androidx.sqlite.db.SupportSQLiteOpenHelper
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import android.database.sqlite.SQLiteOpenHelper
|
import android.database.sqlite.SQLiteOpenHelper
|
||||||
@ -18,7 +18,7 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
|
|||||||
/**
|
/**
|
||||||
* Version of the database.
|
* Version of the database.
|
||||||
*/
|
*/
|
||||||
const val DATABASE_VERSION = 8
|
const val DATABASE_VERSION = 9
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(db: SupportSQLiteDatabase) = with(db) {
|
override fun onCreate(db: SupportSQLiteDatabase) = with(db) {
|
||||||
@ -67,6 +67,9 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
|
|||||||
db.execSQL(MangaTable.createLibraryIndexQuery)
|
db.execSQL(MangaTable.createLibraryIndexQuery)
|
||||||
db.execSQL(ChapterTable.createUnreadChaptersIndexQuery)
|
db.execSQL(ChapterTable.createUnreadChaptersIndexQuery)
|
||||||
}
|
}
|
||||||
|
if (oldVersion < 9) {
|
||||||
|
db.execSQL(MangaTable.addHideTitle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigure(db: SupportSQLiteDatabase) {
|
override fun onConfigure(db: SupportSQLiteDatabase) {
|
||||||
|
@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_CHAPTER_FLAGS
|
|||||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DESCRIPTION
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DESCRIPTION
|
||||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FAVORITE
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FAVORITE
|
||||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_GENRE
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_GENRE
|
||||||
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_HIDE_TITLE
|
||||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ID
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ID
|
||||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_INITIALIZED
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_INITIALIZED
|
||||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_LAST_UPDATE
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_LAST_UPDATE
|
||||||
@ -61,6 +62,7 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
|
|||||||
put(COL_LAST_UPDATE, obj.last_update)
|
put(COL_LAST_UPDATE, obj.last_update)
|
||||||
put(COL_INITIALIZED, obj.initialized)
|
put(COL_INITIALIZED, obj.initialized)
|
||||||
put(COL_VIEWER, obj.viewer)
|
put(COL_VIEWER, obj.viewer)
|
||||||
|
put(COL_HIDE_TITLE, obj.hide_title)
|
||||||
put(COL_CHAPTER_FLAGS, obj.chapter_flags)
|
put(COL_CHAPTER_FLAGS, obj.chapter_flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,6 +84,7 @@ interface BaseMangaGetResolver {
|
|||||||
initialized = cursor.getInt(cursor.getColumnIndex(COL_INITIALIZED)) == 1
|
initialized = cursor.getInt(cursor.getColumnIndex(COL_INITIALIZED)) == 1
|
||||||
viewer = cursor.getInt(cursor.getColumnIndex(COL_VIEWER))
|
viewer = cursor.getInt(cursor.getColumnIndex(COL_VIEWER))
|
||||||
chapter_flags = cursor.getInt(cursor.getColumnIndex(COL_CHAPTER_FLAGS))
|
chapter_flags = cursor.getInt(cursor.getColumnIndex(COL_CHAPTER_FLAGS))
|
||||||
|
hide_title = cursor.getInt(cursor.getColumnIndex(COL_HIDE_TITLE)) == 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ interface Manga : SManga {
|
|||||||
|
|
||||||
var chapter_flags: Int
|
var chapter_flags: Int
|
||||||
|
|
||||||
|
var hide_title: Boolean
|
||||||
|
|
||||||
fun setChapterOrder(order: Int) {
|
fun setChapterOrder(order: Int) {
|
||||||
setFlags(order, SORT_MASK)
|
setFlags(order, SORT_MASK)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.database.models
|
package eu.kanade.tachiyomi.data.database.models
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
|
||||||
open class MangaImpl : Manga {
|
open class MangaImpl : Manga {
|
||||||
|
|
||||||
override var id: Long? = null
|
override var id: Long? = null
|
||||||
@ -32,6 +34,14 @@ open class MangaImpl : Manga {
|
|||||||
|
|
||||||
override var chapter_flags: Int = 0
|
override var chapter_flags: Int = 0
|
||||||
|
|
||||||
|
override var hide_title: Boolean = false
|
||||||
|
|
||||||
|
override fun copyFrom(other: SManga) {
|
||||||
|
if (other is MangaImpl && (other as MangaImpl)::title.isInitialized && other.title != title)
|
||||||
|
title = other.title
|
||||||
|
super.copyFrom(other)
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other == null || javaClass != other.javaClass) return false
|
if (other == null || javaClass != other.javaClass) return false
|
||||||
|
@ -52,6 +52,14 @@ interface ChapterQueries : DbProvider {
|
|||||||
.build())
|
.build())
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
|
fun getChapter(url: String, mangaId: Long) = db.get()
|
||||||
|
.`object`(Chapter::class.java)
|
||||||
|
.withQuery(Query.builder()
|
||||||
|
.table(ChapterTable.TABLE)
|
||||||
|
.where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
|
||||||
|
.whereArgs(url, mangaId)
|
||||||
|
.build())
|
||||||
|
.prepare()
|
||||||
|
|
||||||
fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
|
fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ interface HistoryQueries : DbProvider {
|
|||||||
* Returns history of recent manga containing last read chapter
|
* Returns history of recent manga containing last read chapter
|
||||||
* @param date recent date range
|
* @param date recent date range
|
||||||
*/
|
*/
|
||||||
fun getRecentManga(date: Date) = db.get()
|
fun getRecentManga(date: Date, offset: Int = 0) = db.get()
|
||||||
.listOfObjects(MangaChapterHistory::class.java)
|
.listOfObjects(MangaChapterHistory::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(RawQuery.builder()
|
||||||
.query(getRecentMangasQuery())
|
.query(getRecentMangasQuery(offset))
|
||||||
.args(date.time)
|
.args(date.time)
|
||||||
.observesTables(HistoryTable.TABLE)
|
.observesTables(HistoryTable.TABLE)
|
||||||
.build())
|
.build())
|
||||||
|
@ -82,6 +82,11 @@ interface MangaQueries : DbProvider {
|
|||||||
.withPutResolver(MangaViewerPutResolver())
|
.withPutResolver(MangaViewerPutResolver())
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
|
fun updateMangaHideTitle(manga: Manga) = db.put()
|
||||||
|
.`object`(manga)
|
||||||
|
.withPutResolver(MangaHideTitlePutResolver())
|
||||||
|
.prepare()
|
||||||
|
|
||||||
fun updateMangaTitle(manga: Manga) = db.put()
|
fun updateMangaTitle(manga: Manga) = db.put()
|
||||||
.`object`(manga)
|
.`object`(manga)
|
||||||
.withPutResolver(MangaTitlePutResolver())
|
.withPutResolver(MangaTitlePutResolver())
|
||||||
|
@ -47,7 +47,7 @@ fun getRecentsQuery() = """
|
|||||||
* and are read after the given time period
|
* and are read after the given time period
|
||||||
* @return return limit is 25
|
* @return return limit is 25
|
||||||
*/
|
*/
|
||||||
fun getRecentMangasQuery() = """
|
fun getRecentMangasQuery(offset: Int = 0) = """
|
||||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
|
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
|
||||||
FROM ${Manga.TABLE}
|
FROM ${Manga.TABLE}
|
||||||
JOIN ${Chapter.TABLE}
|
JOIN ${Chapter.TABLE}
|
||||||
@ -62,7 +62,7 @@ fun getRecentMangasQuery() = """
|
|||||||
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
|
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
|
||||||
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
|
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
|
||||||
ORDER BY max_last_read.${History.COL_LAST_READ} DESC
|
ORDER BY max_last_read.${History.COL_LAST_READ} DESC
|
||||||
LIMIT 25
|
LIMIT 25 OFFSET $offset
|
||||||
"""
|
"""
|
||||||
|
|
||||||
fun getHistoryByMangaId() = """
|
fun getHistoryByMangaId() = """
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.database.resolvers
|
package eu.kanade.tachiyomi.data.database.resolvers
|
||||||
|
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.support.annotation.NonNull
|
import androidx.annotation.NonNull
|
||||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite
|
import com.pushtorefresh.storio.sqlite.StorIOSQLite
|
||||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
||||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.database.resolvers
|
||||||
|
|
||||||
|
import android.content.ContentValues
|
||||||
|
import com.pushtorefresh.storio.sqlite.StorIOSQLite
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
|
||||||
|
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
||||||
|
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||||
|
import eu.kanade.tachiyomi.data.database.inTransactionReturn
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||||
|
|
||||||
|
class MangaHideTitlePutResolver : PutResolver<Manga>() {
|
||||||
|
|
||||||
|
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||||
|
val updateQuery = mapToUpdateQuery(manga)
|
||||||
|
val contentValues = mapToContentValues(manga)
|
||||||
|
|
||||||
|
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||||
|
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
||||||
|
.table(MangaTable.TABLE)
|
||||||
|
.where("${MangaTable.COL_ID} = ?")
|
||||||
|
.whereArgs(manga.id)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||||
|
put(MangaTable.COL_HIDE_TITLE, manga.hide_title)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -38,6 +38,8 @@ object MangaTable {
|
|||||||
|
|
||||||
const val COL_CATEGORY = "category"
|
const val COL_CATEGORY = "category"
|
||||||
|
|
||||||
|
const val COL_HIDE_TITLE = "hideTitle"
|
||||||
|
|
||||||
val createTableQuery: String
|
val createTableQuery: String
|
||||||
get() = """CREATE TABLE $TABLE(
|
get() = """CREATE TABLE $TABLE(
|
||||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||||
@ -54,6 +56,7 @@ object MangaTable {
|
|||||||
$COL_LAST_UPDATE LONG,
|
$COL_LAST_UPDATE LONG,
|
||||||
$COL_INITIALIZED BOOLEAN NOT NULL,
|
$COL_INITIALIZED BOOLEAN NOT NULL,
|
||||||
$COL_VIEWER INTEGER NOT NULL,
|
$COL_VIEWER INTEGER NOT NULL,
|
||||||
|
$COL_HIDE_TITLE INTEGER NOT NULL,
|
||||||
$COL_CHAPTER_FLAGS INTEGER NOT NULL
|
$COL_CHAPTER_FLAGS INTEGER NOT NULL
|
||||||
)"""
|
)"""
|
||||||
|
|
||||||
@ -63,4 +66,7 @@ object MangaTable {
|
|||||||
val createLibraryIndexQuery: String
|
val createLibraryIndexQuery: String
|
||||||
get() = "CREATE INDEX library_${COL_FAVORITE}_index ON $TABLE($COL_FAVORITE) " +
|
get() = "CREATE INDEX library_${COL_FAVORITE}_index ON $TABLE($COL_FAVORITE) " +
|
||||||
"WHERE $COL_FAVORITE = 1"
|
"WHERE $COL_FAVORITE = 1"
|
||||||
|
|
||||||
|
val addHideTitle: String
|
||||||
|
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_HIDE_TITLE INTEGER DEFAULT 0"
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,9 @@ import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
|||||||
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.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.util.launchNow
|
||||||
|
import eu.kanade.tachiyomi.util.launchUI
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
@ -181,6 +184,7 @@ class DownloadManager(context: Context) {
|
|||||||
* @param source the source of the manga.
|
* @param source the source of the manga.
|
||||||
*/
|
*/
|
||||||
fun deleteManga(manga: Manga, source: Source) {
|
fun deleteManga(manga: Manga, source: Source) {
|
||||||
|
downloader.clearQueue(manga, true)
|
||||||
queue.remove(manga)
|
queue.remove(manga)
|
||||||
provider.findMangaDir(manga, source)?.delete()
|
provider.findMangaDir(manga, source)?.delete()
|
||||||
cache.removeManga(manga)
|
cache.removeManga(manga)
|
||||||
|
@ -2,7 +2,8 @@ package eu.kanade.tachiyomi.data.download
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.support.v4.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
||||||
@ -168,7 +169,8 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||||
setAutoCancel(true)
|
setAutoCancel(true)
|
||||||
clearActions()
|
clearActions()
|
||||||
setContentIntent(NotificationReceiver.openChapterPendingBroadcast(context, download.manga, download.chapter))
|
setContentIntent(NotificationReceiver.openChapterPendingActivity(context, download
|
||||||
|
.manga, download.chapter))
|
||||||
setProgress(0, 0, false)
|
setProgress(0, 0, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,9 +216,11 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
setContentTitle(chapter ?: context.getString(R.string.download_notifier_downloader_title))
|
setContentTitle(chapter ?: context.getString(R.string.download_notifier_downloader_title))
|
||||||
setContentText(error ?: context.getString(R.string.download_notifier_unkown_error))
|
setContentText(error ?: context.getString(R.string.download_notifier_unkown_error))
|
||||||
setSmallIcon(android.R.drawable.stat_sys_warning)
|
setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||||
|
setCategory(NotificationCompat.CATEGORY_ERROR)
|
||||||
clearActions()
|
clearActions()
|
||||||
setAutoCancel(false)
|
setAutoCancel(true)
|
||||||
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
||||||
|
color = ContextCompat.getColor(context, R.color.colorAccentLight)
|
||||||
setProgress(0, 0, false)
|
setProgress(0, 0, false)
|
||||||
}
|
}
|
||||||
notification.show(Notifications.ID_DOWNLOAD_CHAPTER_ERROR)
|
notification.show(Notifications.ID_DOWNLOAD_CHAPTER_ERROR)
|
||||||
|
@ -90,6 +90,22 @@ class DownloadPendingDeleter(context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of chapters to be deleted grouped by its manga.
|
||||||
|
*
|
||||||
|
* Note: the returned list of manga and chapters only contain basic information needed by the
|
||||||
|
* downloader, so don't use them for anything else.
|
||||||
|
*/
|
||||||
|
@Synchronized
|
||||||
|
fun getPendingChapters(manga: Manga): List<Chapter>? {
|
||||||
|
val entries = decodeAll()
|
||||||
|
prefs.edit().clear().apply()
|
||||||
|
lastAddedEntry = null
|
||||||
|
|
||||||
|
val entry = entries.find { it.manga.id == manga.id }
|
||||||
|
return entry?.chapters?.map { it.toModel() }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes all the chapters from preferences.
|
* Decodes all the chapters from preferences.
|
||||||
*/
|
*/
|
||||||
|
@ -9,7 +9,7 @@ import android.net.NetworkInfo.State.DISCONNECTED
|
|||||||
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 android.support.v4.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import com.github.pwittchen.reactivenetwork.library.Connectivity
|
import com.github.pwittchen.reactivenetwork.library.Connectivity
|
||||||
import com.github.pwittchen.reactivenetwork.library.ReactiveNetwork
|
import com.github.pwittchen.reactivenetwork.library.ReactiveNetwork
|
||||||
import com.jakewharton.rxrelay.BehaviorRelay
|
import com.jakewharton.rxrelay.BehaviorRelay
|
||||||
|
@ -14,7 +14,7 @@ import eu.kanade.tachiyomi.source.model.Page
|
|||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.source.online.fetchAllImageUrlsFromPageList
|
import eu.kanade.tachiyomi.source.online.fetchAllImageUrlsFromPageList
|
||||||
import eu.kanade.tachiyomi.util.*
|
import eu.kanade.tachiyomi.util.*
|
||||||
import kotlinx.coroutines.experimental.async
|
import kotlinx.coroutines.async
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
@ -157,6 +157,26 @@ class Downloader(
|
|||||||
notifier.dismiss()
|
notifier.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes everything from the queue for a certain manga
|
||||||
|
*
|
||||||
|
* @param isNotification value that determines if status is set (needed for view updates)
|
||||||
|
*/
|
||||||
|
fun clearQueue(manga: Manga, isNotification: Boolean = false) {
|
||||||
|
//Needed to update the chapter view
|
||||||
|
if (isNotification) {
|
||||||
|
queue
|
||||||
|
.filter { it.status == Download.QUEUE && it.manga.id == manga.id }
|
||||||
|
.forEach { it.status = Download.NOT_DOWNLOADED }
|
||||||
|
}
|
||||||
|
queue.remove(manga)
|
||||||
|
if (queue.isEmpty()) {
|
||||||
|
DownloadService.stop(context)
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
notifier.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares the subscriptions to start downloading.
|
* Prepares the subscriptions to start downloading.
|
||||||
*/
|
*/
|
||||||
@ -351,7 +371,7 @@ class Downloader(
|
|||||||
.map { response ->
|
.map { response ->
|
||||||
val file = tmpDir.createFile("$filename.tmp")
|
val file = tmpDir.createFile("$filename.tmp")
|
||||||
try {
|
try {
|
||||||
response.body()!!.source().saveTo(file.openOutputStream())
|
response.body!!.source().saveTo(file.openOutputStream())
|
||||||
val extension = getImageExtension(response, file)
|
val extension = getImageExtension(response, file)
|
||||||
file.renameTo("$filename.$extension")
|
file.renameTo("$filename.$extension")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@ -374,7 +394,7 @@ class Downloader(
|
|||||||
*/
|
*/
|
||||||
private fun getImageExtension(response: Response, file: UniFile): String {
|
private fun getImageExtension(response: Response, file: UniFile): String {
|
||||||
// Read content type if available.
|
// Read content type if available.
|
||||||
val mime = response.body()?.contentType()?.let { ct -> "${ct.type()}/${ct.subtype()}" }
|
val mime = response.body?.contentType()?.let { ct -> "${ct.type}/${ct.subtype}" }
|
||||||
// Else guess from the uri.
|
// Else guess from the uri.
|
||||||
?: context.contentResolver.getType(file.uri)
|
?: context.contentResolver.getType(file.uri)
|
||||||
// Else read magic numbers.
|
// Else read magic numbers.
|
||||||
|
@ -22,7 +22,7 @@ class LibraryUpdateJob : Job() {
|
|||||||
val preferences = Injekt.get<PreferencesHelper>()
|
val preferences = Injekt.get<PreferencesHelper>()
|
||||||
val interval = prefInterval ?: preferences.libraryUpdateInterval().getOrDefault()
|
val interval = prefInterval ?: preferences.libraryUpdateInterval().getOrDefault()
|
||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
val restrictions = preferences.libraryUpdateRestriction()
|
val restrictions = preferences.libraryUpdateRestriction()!!
|
||||||
val acRestriction = "ac" in restrictions
|
val acRestriction = "ac" in restrictions
|
||||||
val wifiRestriction = if ("wifi" in restrictions)
|
val wifiRestriction = if ("wifi" in restrictions)
|
||||||
JobRequest.NetworkType.UNMETERED
|
JobRequest.NetworkType.UNMETERED
|
||||||
|
@ -9,7 +9,9 @@ import android.graphics.BitmapFactory
|
|||||||
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 android.support.v4.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
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
|
||||||
@ -18,6 +20,7 @@ import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
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.glide.GlideApp
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateRanker.rankingScheme
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateRanker.rankingScheme
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
@ -29,14 +32,18 @@ import eu.kanade.tachiyomi.source.SourceManager
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.util.*
|
import eu.kanade.tachiyomi.util.chop
|
||||||
|
import eu.kanade.tachiyomi.util.isServiceRunning
|
||||||
|
import eu.kanade.tachiyomi.util.notification
|
||||||
|
import eu.kanade.tachiyomi.util.notificationManager
|
||||||
|
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||||
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.util.*
|
import java.util.ArrayList
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,6 +95,7 @@ class LibraryUpdateService(
|
|||||||
.setLargeIcon(notificationBitmap)
|
.setLargeIcon(notificationBitmap)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setOnlyAlertOnce(true)
|
.setOnlyAlertOnce(true)
|
||||||
|
.setColor(ContextCompat.getColor(this, R.color.colorAccentLight))
|
||||||
.addAction(R.drawable.ic_clear_grey_24dp_img, getString(android.R.string.cancel), cancelIntent)
|
.addAction(R.drawable.ic_clear_grey_24dp_img, getString(android.R.string.cancel), cancelIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +278,7 @@ class LibraryUpdateService(
|
|||||||
// Initialize the variables holding the progress of the updates.
|
// Initialize the variables holding the progress of the updates.
|
||||||
val count = AtomicInteger(0)
|
val count = AtomicInteger(0)
|
||||||
// List containing new updates
|
// List containing new updates
|
||||||
val newUpdates = ArrayList<Manga>()
|
val newUpdates = ArrayList<Pair<Manga, Array<Chapter>>>()
|
||||||
// list containing failed updates
|
// list containing failed updates
|
||||||
val failedUpdates = ArrayList<Manga>()
|
val failedUpdates = ArrayList<Manga>()
|
||||||
// List containing categories that get included in downloads.
|
// List containing categories that get included in downloads.
|
||||||
@ -303,7 +311,8 @@ class LibraryUpdateService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Convert to the manga that contains new chapters.
|
// Convert to the manga that contains new chapters.
|
||||||
.map { manga }
|
.map { Pair(manga, (it.first.sortedByDescending { ch -> ch
|
||||||
|
.source_order }.toTypedArray())) }
|
||||||
}
|
}
|
||||||
// Add manga with new chapters to the list.
|
// Add manga with new chapters to the list.
|
||||||
.doOnNext { manga ->
|
.doOnNext { manga ->
|
||||||
@ -325,6 +334,7 @@ class LibraryUpdateService(
|
|||||||
|
|
||||||
cancelProgressNotification()
|
cancelProgressNotification()
|
||||||
}
|
}
|
||||||
|
.map { manga -> manga.first }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
|
fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
|
||||||
@ -438,39 +448,64 @@ class LibraryUpdateService(
|
|||||||
*
|
*
|
||||||
* @param updates a list of manga with new updates.
|
* @param updates a list of manga with new updates.
|
||||||
*/
|
*/
|
||||||
private fun showResultNotification(updates: List<Manga>) {
|
private fun showResultNotification(updates: List<Pair<Manga, Array<Chapter>>>) {
|
||||||
val newUpdates = updates.map { it.title.chop(45) }.toMutableSet()
|
val notifications = ArrayList<Pair<Notification, Int>>()
|
||||||
|
updates.forEach {
|
||||||
// Append new chapters from a previous, existing notification
|
val manga = it.first
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
val chapters = it.second
|
||||||
val previousNotification = notificationManager.activeNotifications
|
val chapterNames = chapters.map { chapter -> chapter.name.chop(45) }.toSet()
|
||||||
.find { it.id == Notifications.ID_LIBRARY_RESULT }
|
notifications.add(Pair(notification(Notifications.CHANNEL_NEW_CHAPTERS) {
|
||||||
|
setSmallIcon(R.drawable.ic_tachiyomi_icon)
|
||||||
if (previousNotification != null) {
|
try {
|
||||||
val oldUpdates = previousNotification.notification.extras
|
val icon = GlideApp.with(this@LibraryUpdateService)
|
||||||
.getString(Notification.EXTRA_BIG_TEXT)
|
.asBitmap().load(manga).dontTransform().centerCrop().circleCrop()
|
||||||
|
.override(256, 256).submit().get()
|
||||||
if (!oldUpdates.isNullOrEmpty()) {
|
setLargeIcon(icon)
|
||||||
newUpdates += oldUpdates.split("\n")
|
|
||||||
}
|
}
|
||||||
}
|
catch (e: Exception) { }
|
||||||
|
setContentTitle(manga.title.chop(45))
|
||||||
|
color = ContextCompat.getColor(this@LibraryUpdateService, R.color.colorAccentLight)
|
||||||
|
setContentText(chapterNames.first())
|
||||||
|
setStyle(NotificationCompat.BigTextStyle().bigText(
|
||||||
|
if (chapterNames.size > 5) {
|
||||||
|
"${chapterNames.take(4).joinToString(", ")}, " +
|
||||||
|
getString(R.string.notification_and_n_more, (chapterNames.size - 4))
|
||||||
|
} else chapterNames.joinToString(", ")))
|
||||||
|
priority = NotificationCompat.PRIORITY_HIGH
|
||||||
|
setGroup(Notifications.GROUP_NEW_CHAPTERS)
|
||||||
|
setContentIntent(
|
||||||
|
NotificationReceiver.openChapterPendingActivity(
|
||||||
|
this@LibraryUpdateService, manga, chapters.first()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
addAction(R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read),
|
||||||
|
NotificationReceiver.markAsReadPendingBroadcast(this@LibraryUpdateService,
|
||||||
|
manga, chapters, Notifications.ID_NEW_CHAPTERS))
|
||||||
|
addAction(R.drawable.ic_book_white_24dp, getString(R.string.action_view_chapters),
|
||||||
|
NotificationReceiver.openChapterPendingActivity(this@LibraryUpdateService,
|
||||||
|
manga, Notifications.ID_NEW_CHAPTERS))
|
||||||
|
setAutoCancel(true)
|
||||||
|
}, manga.id.hashCode()))
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationManager.notify(Notifications.ID_LIBRARY_RESULT, notification(Notifications.CHANNEL_LIBRARY) {
|
NotificationManagerCompat.from(this).apply {
|
||||||
setSmallIcon(R.drawable.ic_book_white_24dp)
|
notifications.forEach {
|
||||||
setLargeIcon(notificationBitmap)
|
notify(it.second, it.first)
|
||||||
setContentTitle(getString(R.string.notification_new_chapters))
|
|
||||||
if (newUpdates.size > 1) {
|
|
||||||
setContentText(getString(R.string.notification_new_chapters_text, newUpdates.size))
|
|
||||||
setStyle(NotificationCompat.BigTextStyle().bigText(newUpdates.joinToString("\n")))
|
|
||||||
setNumber(newUpdates.size)
|
|
||||||
} else {
|
|
||||||
setContentText(newUpdates.first())
|
|
||||||
}
|
}
|
||||||
priority = NotificationCompat.PRIORITY_HIGH
|
|
||||||
setContentIntent(getNotificationIntent())
|
notify(Notifications.ID_NEW_CHAPTERS, notification(Notifications.CHANNEL_NEW_CHAPTERS) {
|
||||||
setAutoCancel(true)
|
setSmallIcon(R.drawable.ic_tachiyomi_icon)
|
||||||
})
|
setLargeIcon(notificationBitmap)
|
||||||
|
setContentTitle(getString(R.string.notification_new_chapters))
|
||||||
|
color = ContextCompat.getColor(applicationContext, R.color.colorAccentLight)
|
||||||
|
setContentText(getString(R.string.notification_new_chapters_text, updates.size))
|
||||||
|
priority = NotificationCompat.PRIORITY_HIGH
|
||||||
|
setGroup(Notifications.GROUP_NEW_CHAPTERS)
|
||||||
|
setGroupSummary(true)
|
||||||
|
setContentIntent(getNotificationIntent())
|
||||||
|
setAutoCancel(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package eu.kanade.tachiyomi.data.notification
|
package eu.kanade.tachiyomi.data.notification
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.KeyguardManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.ClipData
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
@ -12,11 +16,17 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
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.library.LibraryUpdateService
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.util.DiskUtil
|
import eu.kanade.tachiyomi.util.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.getUriCompat
|
import eu.kanade.tachiyomi.util.getUriCompat
|
||||||
import eu.kanade.tachiyomi.util.notificationManager
|
import eu.kanade.tachiyomi.util.notificationManager
|
||||||
import eu.kanade.tachiyomi.util.toast
|
import eu.kanade.tachiyomi.util.toast
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||||
@ -54,12 +64,21 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
||||||
// Cancel library update and dismiss notification
|
// Cancel library update and dismiss notification
|
||||||
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context, Notifications.ID_LIBRARY_PROGRESS)
|
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context)
|
||||||
// Open reader activity
|
// Open reader activity
|
||||||
ACTION_OPEN_CHAPTER -> {
|
ACTION_OPEN_CHAPTER -> {
|
||||||
openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
||||||
intent.getLongExtra(EXTRA_CHAPTER_ID, -1))
|
intent.getLongExtra(EXTRA_CHAPTER_ID, -1))
|
||||||
}
|
}
|
||||||
|
ACTION_MARK_AS_READ -> {
|
||||||
|
val notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||||
|
if (notificationId > -1) dismissNotification(
|
||||||
|
context, notificationId, intent.getIntExtra(EXTRA_GROUP_ID, 0)
|
||||||
|
)
|
||||||
|
val urls = intent.getStringArrayExtra(EXTRA_CHAPTER_URL) ?: return
|
||||||
|
val mangaId = intent.getLongExtra(EXTRA_MANGA_ID, -1)
|
||||||
|
markAsRead(urls, mangaId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,17 +99,17 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
* @param notificationId id of notification
|
* @param notificationId id of notification
|
||||||
*/
|
*/
|
||||||
private fun shareImage(context: Context, path: String, notificationId: Int) {
|
private fun shareImage(context: Context, path: String, notificationId: Int) {
|
||||||
|
val km = context.getSystemService(Activity.KEYGUARD_SERVICE) as KeyguardManager
|
||||||
// Create intent
|
// Create intent
|
||||||
val intent = Intent(Intent.ACTION_SEND).apply {
|
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||||
val uri = File(path).getUriCompat(context)
|
val uri = File(path).getUriCompat(context)
|
||||||
putExtra(Intent.EXTRA_STREAM, uri)
|
putExtra(Intent.EXTRA_STREAM, uri)
|
||||||
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
|
||||||
|
clipData = ClipData.newRawUri(null, uri)
|
||||||
type = "image/*"
|
type = "image/*"
|
||||||
}
|
}
|
||||||
// Dismiss notification
|
// Close Navigation Shade
|
||||||
dismissNotification(context, notificationId)
|
|
||||||
// Launch share activity
|
|
||||||
context.startActivity(intent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,17 +120,18 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
* @param chapterId id of chapter
|
* @param chapterId id of chapter
|
||||||
*/
|
*/
|
||||||
internal fun openChapter(context: Context, mangaId: Long, chapterId: Long) {
|
internal fun openChapter(context: Context, mangaId: Long, chapterId: Long) {
|
||||||
|
dismissNotification(context, Notifications.ID_NEW_CHAPTERS)
|
||||||
val db = DatabaseHelper(context)
|
val db = DatabaseHelper(context)
|
||||||
val manga = db.getManga(mangaId).executeAsBlocking()
|
val manga = db.getManga(mangaId).executeAsBlocking()
|
||||||
val chapter = db.getChapter(chapterId).executeAsBlocking()
|
val chapter = db.getChapter(chapterId).executeAsBlocking()
|
||||||
|
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
||||||
if (manga != null && chapter != null) {
|
if (manga != null && chapter != null) {
|
||||||
val intent = ReaderActivity.newIntent(context, manga, chapter).apply {
|
val intent = ReaderActivity.newIntent(context, manga, chapter).apply {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
}
|
}
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
} else {
|
} else {
|
||||||
context.toast(context.getString(R.string.chapter_error))
|
context.toast(context.getString(R.string.no_next_chapter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,9 +158,31 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
* @param context context of application
|
* @param context context of application
|
||||||
* @param notificationId id of notification
|
* @param notificationId id of notification
|
||||||
*/
|
*/
|
||||||
private fun cancelLibraryUpdate(context: Context, notificationId: Int) {
|
private fun cancelLibraryUpdate(context: Context) {
|
||||||
LibraryUpdateService.stop(context)
|
LibraryUpdateService.stop(context)
|
||||||
Handler().post { dismissNotification(context, notificationId) }
|
Handler().post { dismissNotification(context, Notifications.ID_LIBRARY_PROGRESS) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when user wants to stop a library update
|
||||||
|
*
|
||||||
|
* @param context context of application
|
||||||
|
* @param notificationId id of notification
|
||||||
|
*/
|
||||||
|
private fun markAsRead(chapterUrls: Array<String>, mangaId: Long) {
|
||||||
|
val db: DatabaseHelper = Injekt.get()
|
||||||
|
chapterUrls.forEach {
|
||||||
|
val chapter = db.getChapter(it, mangaId).executeAsBlocking() ?: return
|
||||||
|
chapter.read = true
|
||||||
|
db.updateChapterProgress(chapter).executeAsBlocking()
|
||||||
|
val preferences: PreferencesHelper = Injekt.get()
|
||||||
|
if (preferences.removeAfterMarkedAsRead()) {
|
||||||
|
val manga = db.getManga(mangaId).executeAsBlocking() ?: return
|
||||||
|
val sourceManager: SourceManager = Injekt.get()
|
||||||
|
val source = sourceManager.get(manga.source) ?: return
|
||||||
|
downloadManager.deleteChapters(listOf(chapter), manga, source)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -155,6 +197,9 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
// Called to cancel library update.
|
// Called to cancel library update.
|
||||||
private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE"
|
private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE"
|
||||||
|
|
||||||
|
// Called to cancel library update.
|
||||||
|
private const val ACTION_MARK_AS_READ = "$ID.$NAME.MARK_AS_READ"
|
||||||
|
|
||||||
// Called to open chapter
|
// Called to open chapter
|
||||||
private const val ACTION_OPEN_CHAPTER = "$ID.$NAME.ACTION_OPEN_CHAPTER"
|
private const val ACTION_OPEN_CHAPTER = "$ID.$NAME.ACTION_OPEN_CHAPTER"
|
||||||
|
|
||||||
@ -179,12 +224,18 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
// Value containing notification id.
|
// Value containing notification id.
|
||||||
private const val EXTRA_NOTIFICATION_ID = "$ID.$NAME.NOTIFICATION_ID"
|
private const val EXTRA_NOTIFICATION_ID = "$ID.$NAME.NOTIFICATION_ID"
|
||||||
|
|
||||||
|
// Value containing group id.
|
||||||
|
private const val EXTRA_GROUP_ID = "$ID.$NAME.EXTRA_GROUP_ID"
|
||||||
|
|
||||||
// Value containing manga id.
|
// Value containing manga id.
|
||||||
private const val EXTRA_MANGA_ID = "$ID.$NAME.EXTRA_MANGA_ID"
|
private const val EXTRA_MANGA_ID = "$ID.$NAME.EXTRA_MANGA_ID"
|
||||||
|
|
||||||
// Value containing chapter id.
|
// Value containing chapter id.
|
||||||
private const val EXTRA_CHAPTER_ID = "$ID.$NAME.EXTRA_CHAPTER_ID"
|
private const val EXTRA_CHAPTER_ID = "$ID.$NAME.EXTRA_CHAPTER_ID"
|
||||||
|
|
||||||
|
// Value containing chapter url.
|
||||||
|
private const val EXTRA_CHAPTER_URL = "$ID.$NAME.EXTRA_CHAPTER_URL"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [PendingIntent] that resumes the download of a chapter
|
* Returns a [PendingIntent] that resumes the download of a chapter
|
||||||
*
|
*
|
||||||
@ -246,6 +297,32 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [PendingIntent] that starts a service which dismissed the notification
|
||||||
|
*
|
||||||
|
* @param context context of application
|
||||||
|
* @param notificationId id of notification
|
||||||
|
* @return [PendingIntent]
|
||||||
|
*/
|
||||||
|
internal fun dismissNotification(context: Context, notificationId: Int, groupId: Int? =
|
||||||
|
null) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
val groupKey = context.notificationManager.activeNotifications.find {
|
||||||
|
it.id == notificationId
|
||||||
|
}?.groupKey
|
||||||
|
if (groupId != null && groupId != 0 && groupKey != null && groupKey.isNotEmpty()) {
|
||||||
|
val notifications = context.notificationManager.activeNotifications.filter {
|
||||||
|
it.groupKey == groupKey
|
||||||
|
}
|
||||||
|
if (notifications.size == 2) {
|
||||||
|
context.notificationManager.cancel(groupId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.notificationManager.cancel(notificationId)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns [PendingIntent] that starts a service which cancels the notification and starts a share activity
|
* Returns [PendingIntent] that starts a service which cancels the notification and starts a share activity
|
||||||
*
|
*
|
||||||
@ -255,12 +332,17 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
* @return [PendingIntent]
|
* @return [PendingIntent]
|
||||||
*/
|
*/
|
||||||
internal fun shareImagePendingBroadcast(context: Context, path: String, notificationId: Int): PendingIntent {
|
internal fun shareImagePendingBroadcast(context: Context, path: String, notificationId: Int): PendingIntent {
|
||||||
val intent = Intent(context, NotificationReceiver::class.java).apply {
|
//val shareIntent = ShareStartingActivity.newIntent(context, path)
|
||||||
action = ACTION_SHARE_IMAGE
|
val shareIntent = Intent(Intent.ACTION_SEND).apply {
|
||||||
putExtra(EXTRA_FILE_LOCATION, path)
|
val uri = File(path).getUriCompat(context)
|
||||||
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
|
putExtra(Intent.EXTRA_STREAM, uri)
|
||||||
|
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
|
clipData = ClipData.newRawUri(null, uri)
|
||||||
|
type = "image/*"
|
||||||
}
|
}
|
||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
//val shareIntent2 = Intent.createChooser(shareIntent, context.getString(R.string.action_share))
|
||||||
|
return PendingIntent.getActivity(context, 0, shareIntent, PendingIntent
|
||||||
|
.FLAG_CANCEL_CURRENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -281,19 +363,55 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns [PendingIntent] that start a reader activity containing chapter.
|
* Returns [PendingIntent] that starts a reader activity containing chapter.
|
||||||
*
|
*
|
||||||
* @param context context of application
|
* @param context context of application
|
||||||
* @param manga manga of chapter
|
* @param manga manga of chapter
|
||||||
* @param chapter chapter that needs to be opened
|
* @param chapter chapter that needs to be opened
|
||||||
*/
|
*/
|
||||||
internal fun openChapterPendingBroadcast(context: Context, manga: Manga, chapter: Chapter): PendingIntent {
|
internal fun openChapterPendingActivity(context: Context, manga: Manga, chapter:
|
||||||
val intent = Intent(context, NotificationReceiver::class.java).apply {
|
Chapter): PendingIntent {
|
||||||
action = ACTION_OPEN_CHAPTER
|
val newIntent = ReaderActivity.newIntent(context, manga, chapter)
|
||||||
|
return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent
|
||||||
|
.FLAG_UPDATE_CURRENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [PendingIntent] that opens the manga info controller.
|
||||||
|
*
|
||||||
|
* @param context context of application
|
||||||
|
* @param manga manga of chapter
|
||||||
|
*/
|
||||||
|
internal fun openChapterPendingActivity(context: Context, manga: Manga, groupId: Int):
|
||||||
|
PendingIntent {
|
||||||
|
val newIntent =
|
||||||
|
Intent(context, MainActivity::class.java).setAction(MainActivity.SHORTCUT_MANGA)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
.putExtra(MangaController.MANGA_EXTRA, manga.id)
|
||||||
|
.putExtra("notificationId", manga.id.hashCode())
|
||||||
|
.putExtra("groupId", groupId)
|
||||||
|
return PendingIntent.getActivity(
|
||||||
|
context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [PendingIntent] that marks a chapter as read and deletes it if preferred
|
||||||
|
*
|
||||||
|
* @param context context of application
|
||||||
|
* @param manga manga of chapter
|
||||||
|
*/
|
||||||
|
internal fun markAsReadPendingBroadcast(context: Context, manga: Manga, chapters:
|
||||||
|
Array<Chapter>, groupId: Int):
|
||||||
|
PendingIntent {
|
||||||
|
val newIntent = Intent(context, NotificationReceiver::class.java).apply {
|
||||||
|
action = ACTION_MARK_AS_READ
|
||||||
|
putExtra(EXTRA_CHAPTER_URL, chapters.map { it.url }.toTypedArray())
|
||||||
putExtra(EXTRA_MANGA_ID, manga.id)
|
putExtra(EXTRA_MANGA_ID, manga.id)
|
||||||
putExtra(EXTRA_CHAPTER_ID, chapter.id)
|
putExtra(EXTRA_NOTIFICATION_ID, manga.id.hashCode())
|
||||||
|
putExtra(EXTRA_GROUP_ID, groupId)
|
||||||
}
|
}
|
||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
return PendingIntent.getBroadcast(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,15 +23,21 @@ object Notifications {
|
|||||||
* Notification channel and ids used by the library updater.
|
* Notification channel and ids used by the library updater.
|
||||||
*/
|
*/
|
||||||
const val CHANNEL_LIBRARY = "library_channel"
|
const val CHANNEL_LIBRARY = "library_channel"
|
||||||
const val ID_LIBRARY_PROGRESS = 101
|
const val ID_LIBRARY_PROGRESS = -101
|
||||||
const val ID_LIBRARY_RESULT = 102
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notification channel and ids used by the downloader.
|
* Notification channel and ids used by the downloader.
|
||||||
*/
|
*/
|
||||||
const val CHANNEL_DOWNLOADER = "downloader_channel"
|
const val CHANNEL_DOWNLOADER = "downloader_channel"
|
||||||
const val ID_DOWNLOAD_CHAPTER = 201
|
const val ID_DOWNLOAD_CHAPTER = -201
|
||||||
const val ID_DOWNLOAD_CHAPTER_ERROR = 202
|
const val ID_DOWNLOAD_CHAPTER_ERROR = -202
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification channel and ids used by the library updater.
|
||||||
|
*/
|
||||||
|
const val CHANNEL_NEW_CHAPTERS = "new_chapters_channel"
|
||||||
|
const val ID_NEW_CHAPTERS = -301
|
||||||
|
const val GROUP_NEW_CHAPTERS = "eu.kanade.tachiyomi.NEW_CHAPTERS"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the notification channels introduced in Android Oreo.
|
* Creates the notification channels introduced in Android Oreo.
|
||||||
@ -44,10 +50,16 @@ object Notifications {
|
|||||||
val channels = listOf(
|
val channels = listOf(
|
||||||
NotificationChannel(CHANNEL_COMMON, context.getString(R.string.channel_common),
|
NotificationChannel(CHANNEL_COMMON, context.getString(R.string.channel_common),
|
||||||
NotificationManager.IMPORTANCE_LOW),
|
NotificationManager.IMPORTANCE_LOW),
|
||||||
NotificationChannel(CHANNEL_LIBRARY, context.getString(R.string.channel_library),
|
NotificationChannel(CHANNEL_LIBRARY, context.getString(R.string.channel_library_updates),
|
||||||
NotificationManager.IMPORTANCE_LOW),
|
NotificationManager.IMPORTANCE_LOW).apply {
|
||||||
|
setShowBadge(false)
|
||||||
|
},
|
||||||
NotificationChannel(CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader),
|
NotificationChannel(CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader),
|
||||||
NotificationManager.IMPORTANCE_LOW)
|
NotificationManager.IMPORTANCE_LOW).apply {
|
||||||
|
setShowBadge(false)
|
||||||
|
},
|
||||||
|
NotificationChannel(CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters),
|
||||||
|
NotificationManager.IMPORTANCE_DEFAULT)
|
||||||
)
|
)
|
||||||
context.notificationManager.createNotificationChannels(channels)
|
context.notificationManager.createNotificationChannels(channels)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.data.preference
|
package eu.kanade.tachiyomi.data.preference
|
||||||
|
|
||||||
import android.support.v7.preference.PreferenceDataStore
|
import androidx.preference.PreferenceDataStore
|
||||||
|
|
||||||
class EmptyPreferenceDataStore : PreferenceDataStore() {
|
class EmptyPreferenceDataStore : PreferenceDataStore() {
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun clear() = prefs.edit().clear().apply()
|
fun clear() = prefs.edit().clear().apply()
|
||||||
|
|
||||||
fun theme() = prefs.getInt(Keys.theme, 1)
|
fun theme() = prefs.getInt(Keys.theme, 5)
|
||||||
|
|
||||||
fun rotation() = rxPrefs.getInteger(Keys.rotation, 1)
|
fun rotation() = rxPrefs.getInteger(Keys.rotation, 1)
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun zoomStart() = rxPrefs.getInteger(Keys.zoomStart, 1)
|
fun zoomStart() = rxPrefs.getInteger(Keys.zoomStart, 1)
|
||||||
|
|
||||||
fun readerTheme() = rxPrefs.getInteger(Keys.readerTheme, 0)
|
fun readerTheme() = rxPrefs.getInteger(Keys.readerTheme, 2)
|
||||||
|
|
||||||
fun cropBorders() = rxPrefs.getBoolean(Keys.cropBorders, false)
|
fun cropBorders() = rxPrefs.getBoolean(Keys.cropBorders, false)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.preference
|
package eu.kanade.tachiyomi.data.preference
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.support.v7.preference.PreferenceDataStore
|
import androidx.preference.PreferenceDataStore
|
||||||
|
|
||||||
class SharedPreferencesDataStore(private val prefs: SharedPreferences) : PreferenceDataStore() {
|
class SharedPreferencesDataStore(private val prefs: SharedPreferences) : PreferenceDataStore() {
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ class SharedPreferencesDataStore(private val prefs: SharedPreferences) : Prefere
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getStringSet(key: String?, defValues: MutableSet<String>?): MutableSet<String> {
|
override fun getStringSet(key: String?, defValues: MutableSet<String>?): MutableSet<String> {
|
||||||
return prefs.getStringSet(key, defValues)
|
return prefs.getStringSet(key, defValues)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun putStringSet(key: String?, values: MutableSet<String>?) {
|
override fun putStringSet(key: String?, values: MutableSet<String>?) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.data.track
|
package eu.kanade.tachiyomi.data.track
|
||||||
|
|
||||||
import android.support.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import android.support.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
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.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
@ -8,6 +8,7 @@ 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 okhttp3.MediaType
|
import okhttp3.MediaType
|
||||||
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody
|
import okhttp3.RequestBody
|
||||||
@ -18,7 +19,7 @@ import java.util.Calendar
|
|||||||
class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||||
|
|
||||||
private val parser = JsonParser()
|
private val parser = JsonParser()
|
||||||
private val jsonMime = MediaType.parse("application/json; charset=utf-8")
|
private val jsonMime = "application/json; charset=utf-8".toMediaTypeOrNull()
|
||||||
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
||||||
|
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
return authClient.newCall(request)
|
return authClient.newCall(request)
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
netResponse.close()
|
netResponse.close()
|
||||||
if (responseBody.isEmpty()) {
|
if (responseBody.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
@ -128,7 +129,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
return authClient.newCall(request)
|
return authClient.newCall(request)
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
if (responseBody.isEmpty()) {
|
if (responseBody.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
@ -189,7 +190,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
return authClient.newCall(request)
|
return authClient.newCall(request)
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
if (responseBody.isEmpty()) {
|
if (responseBody.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
@ -235,7 +236,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
return authClient.newCall(request)
|
return authClient.newCall(request)
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
if (responseBody.isEmpty()) {
|
if (responseBody.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
return authClient.newCall(request)
|
return authClient.newCall(request)
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
if (responseBody.isEmpty()) {
|
if (responseBody.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
// get comic info
|
// get comic info
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
jsonToTrack(parser.parse(responseBody).obj)
|
jsonToTrack(parser.parse(responseBody).obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
return authClient.newCall(requestUserRead)
|
return authClient.newCall(requestUserRead)
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
val resp = netResponse.body()?.string()
|
val resp = netResponse.body?.string()
|
||||||
val coll = gson.fromJson(resp, Collection::class.java)
|
val coll = gson.fromJson(resp, Collection::class.java)
|
||||||
track.status = coll.status?.id!!
|
track.status = coll.status?.id!!
|
||||||
track.last_chapter_read = coll.ep_status!!
|
track.last_chapter_read = coll.ep_status!!
|
||||||
@ -154,7 +154,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
|
|
||||||
fun accessToken(code: String): Observable<OAuth> {
|
fun accessToken(code: String): Observable<OAuth> {
|
||||||
return client.newCall(accessTokenRequest(code)).asObservableSuccess().map { netResponse ->
|
return client.newCall(accessTokenRequest(code)).asObservableSuccess().map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
if (responseBody.isEmpty()) {
|
if (responseBody.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
|
|||||||
|
|
||||||
fun addTocken(tocken: String, oidFormBody: FormBody): FormBody {
|
fun addTocken(tocken: String, oidFormBody: FormBody): FormBody {
|
||||||
val newFormBody = FormBody.Builder()
|
val newFormBody = FormBody.Builder()
|
||||||
for (i in 0 until oidFormBody.size()) {
|
for (i in 0 until oidFormBody.size) {
|
||||||
newFormBody.add(oidFormBody.name(i), oidFormBody.value(i))
|
newFormBody.add(oidFormBody.name(i), oidFormBody.value(i))
|
||||||
}
|
}
|
||||||
newFormBody.add("access_token", tocken)
|
newFormBody.add("access_token", tocken)
|
||||||
@ -29,18 +29,18 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
|
|||||||
if (currAuth.isExpired()) {
|
if (currAuth.isExpired()) {
|
||||||
val response = chain.proceed(BangumiApi.refreshTokenRequest(currAuth.refresh_token!!))
|
val response = chain.proceed(BangumiApi.refreshTokenRequest(currAuth.refresh_token!!))
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
newAuth(gson.fromJson(response.body()!!.string(), OAuth::class.java))
|
newAuth(gson.fromJson(response.body!!.string(), OAuth::class.java))
|
||||||
} else {
|
} else {
|
||||||
response.close()
|
response.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var authRequest = if (originalRequest.method() == "GET") originalRequest.newBuilder()
|
var authRequest = if (originalRequest.method == "GET") originalRequest.newBuilder()
|
||||||
.header("User-Agent", "Tachiyomi")
|
.header("User-Agent", "Tachiyomi")
|
||||||
.url(originalRequest.url().newBuilder()
|
.url(originalRequest.url.newBuilder()
|
||||||
.addQueryParameter("access_token", currAuth.access_token).build())
|
.addQueryParameter("access_token", currAuth.access_token).build())
|
||||||
.build() else originalRequest.newBuilder()
|
.build() else originalRequest.newBuilder()
|
||||||
.post(addTocken(currAuth.access_token, originalRequest.body() as FormBody))
|
.post(addTocken(currAuth.access_token, originalRequest.body as FormBody))
|
||||||
.header("User-Agent", "Tachiyomi")
|
.header("User-Agent", "Tachiyomi")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class KitsuInterceptor(val kitsu: Kitsu, val gson: Gson) : Interceptor {
|
|||||||
if (currAuth.isExpired()) {
|
if (currAuth.isExpired()) {
|
||||||
val response = chain.proceed(KitsuApi.refreshTokenRequest(refreshToken))
|
val response = chain.proceed(KitsuApi.refreshTokenRequest(refreshToken))
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
newAuth(gson.fromJson(response.body()!!.string(), OAuth::class.java))
|
newAuth(gson.fromJson(response.body!!.string(), OAuth::class.java))
|
||||||
} else {
|
} else {
|
||||||
response.close()
|
response.close()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.data.track.kitsu
|
package eu.kanade.tachiyomi.data.track.kitsu
|
||||||
|
|
||||||
import android.support.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import com.github.salomonbrys.kotson.*
|
import com.github.salomonbrys.kotson.*
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
|
@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|||||||
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 okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
@ -134,7 +135,7 @@ class Myanimelist(private val context: Context, id: Int) : TrackService(id) {
|
|||||||
override fun logout() {
|
override fun logout() {
|
||||||
super.logout()
|
super.logout()
|
||||||
preferences.trackToken(this).delete()
|
preferences.trackToken(this).delete()
|
||||||
networkService.cookieManager.remove(HttpUrl.parse(BASE_URL)!!)
|
networkService.cookieManager.remove(BASE_URL.toHttpUrlOrNull()!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isAuthorized: Boolean
|
val isAuthorized: Boolean
|
||||||
@ -148,9 +149,9 @@ class Myanimelist(private val context: Context, id: Int) : TrackService(id) {
|
|||||||
|
|
||||||
private fun checkCookies(): Boolean {
|
private fun checkCookies(): Boolean {
|
||||||
var ckCount = 0
|
var ckCount = 0
|
||||||
val url = HttpUrl.parse(BASE_URL)!!
|
val url = BASE_URL.toHttpUrlOrNull()!!
|
||||||
for (ck in networkService.cookieManager.get(url)) {
|
for (ck in networkService.cookieManager.get(url)) {
|
||||||
if (ck.name() == USER_SESSION_COOKIE || ck.name() == LOGGED_IN_COOKIE)
|
if (ck.name == USER_SESSION_COOKIE || ck.name == LOGGED_IN_COOKIE)
|
||||||
ckCount++
|
ckCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ class MyAnimeListInterceptor(private val myanimelist: Myanimelist): Interceptor
|
|||||||
myanimelist.ensureLoggedIn()
|
myanimelist.ensureLoggedIn()
|
||||||
|
|
||||||
var request = chain.request()
|
var request = chain.request()
|
||||||
request.body()?.let {
|
request.body?.let {
|
||||||
val contentType = it.contentType().toString()
|
val contentType = it.contentType().toString()
|
||||||
val updatedBody = when {
|
val updatedBody = when {
|
||||||
contentType.contains("x-www-form-urlencoded") -> updateFormBody(it)
|
contentType.contains("x-www-form-urlencoded") -> updateFormBody(it)
|
||||||
|
@ -11,6 +11,8 @@ import eu.kanade.tachiyomi.network.asObservableSuccess
|
|||||||
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 okhttp3.*
|
import okhttp3.*
|
||||||
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
@ -85,7 +87,7 @@ class MyanimelistApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||||||
.map {response ->
|
.map {response ->
|
||||||
var libTrack: Track? = null
|
var libTrack: Track? = null
|
||||||
response.use {
|
response.use {
|
||||||
if (it.priorResponse()?.isRedirect != true) {
|
if (it.priorResponse?.isRedirect != true) {
|
||||||
val trackForm = Jsoup.parse(it.consumeBody())
|
val trackForm = Jsoup.parse(it.consumeBody())
|
||||||
|
|
||||||
libTrack = Track.create(TrackManager.MYANIMELIST).apply {
|
libTrack = Track.create(TrackManager.MYANIMELIST).apply {
|
||||||
@ -125,7 +127,7 @@ class MyanimelistApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||||||
val response = client.newCall(POST(url = loginUrl(), body = loginPostBody(username, password, csrf))).execute()
|
val response = client.newCall(POST(url = loginUrl(), body = loginPostBody(username, password, csrf))).execute()
|
||||||
|
|
||||||
response.use {
|
response.use {
|
||||||
if (response.priorResponse()?.code() != 302) throw Exception("Authentication error")
|
if (response.priorResponse?.code != 302) throw Exception("Authentication error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,15 +174,15 @@ class MyanimelistApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||||||
|
|
||||||
private fun Response.consumeBody(): String? {
|
private fun Response.consumeBody(): String? {
|
||||||
use {
|
use {
|
||||||
if (it.code() != 200) throw Exception("HTTP error ${it.code()}")
|
if (it.code != 200) throw Exception("HTTP error ${it.code}")
|
||||||
return it.body()?.string()
|
return it.body?.string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Response.consumeXmlBody(): String? {
|
private fun Response.consumeXmlBody(): String? {
|
||||||
use { res ->
|
use { res ->
|
||||||
if (res.code() != 200) throw Exception("Export list error")
|
if (res.code != 200) throw Exception("Export list error")
|
||||||
BufferedReader(InputStreamReader(GZIPInputStream(res.body()?.source()?.inputStream()))).use { reader ->
|
BufferedReader(InputStreamReader(GZIPInputStream(res.body?.source()?.inputStream()))).use { reader ->
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
reader.forEachLine { line ->
|
reader.forEachLine { line ->
|
||||||
sb.append(line)
|
sb.append(line)
|
||||||
@ -262,7 +264,7 @@ class MyanimelistApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||||||
.put("score", track.score)
|
.put("score", track.score)
|
||||||
.put("num_read_chapters", track.last_chapter_read)
|
.put("num_read_chapters", track.last_chapter_read)
|
||||||
|
|
||||||
return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), body.toString())
|
return body.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Element.searchTitle() = select("strong").text()!!
|
private fun Element.searchTitle() = select("strong").text()!!
|
||||||
|
@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.network.GET
|
|||||||
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 okhttp3.*
|
import okhttp3.*
|
||||||
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
|
|
||||||
private val gson: Gson by injectLazy()
|
private val gson: Gson by injectLazy()
|
||||||
private val parser = JsonParser()
|
private val parser = JsonParser()
|
||||||
private val jsonime = MediaType.parse("application/json; charset=utf-8")
|
private val jsonime = "application/json; charset=utf-8".toMediaTypeOrNull()
|
||||||
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
||||||
|
|
||||||
fun addLibManga(track: Track, user_id: String): Observable<Track> {
|
fun addLibManga(track: Track, user_id: String): Observable<Track> {
|
||||||
@ -63,7 +64,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
return authClient.newCall(request)
|
return authClient.newCall(request)
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
if (responseBody.isEmpty()) {
|
if (responseBody.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
@ -120,13 +121,13 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
return authClient.newCall(requestMangas)
|
return authClient.newCall(requestMangas)
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
parser.parse(responseBody).obj
|
parser.parse(responseBody).obj
|
||||||
}.flatMap { mangas ->
|
}.flatMap { mangas ->
|
||||||
authClient.newCall(request)
|
authClient.newCall(request)
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { netResponse ->
|
.map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
if (responseBody.isEmpty()) {
|
if (responseBody.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
@ -143,13 +144,13 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getCurrentUser(): Int {
|
fun getCurrentUser(): Int {
|
||||||
val user = authClient.newCall(GET("$apiUrl/users/whoami")).execute().body()?.string()
|
val user = authClient.newCall(GET("$apiUrl/users/whoami")).execute().body?.string()
|
||||||
return parser.parse(user).obj["id"].asInt
|
return parser.parse(user).obj["id"].asInt
|
||||||
}
|
}
|
||||||
|
|
||||||
fun accessToken(code: String): Observable<OAuth> {
|
fun accessToken(code: String): Observable<OAuth> {
|
||||||
return client.newCall(accessTokenRequest(code)).asObservableSuccess().map { netResponse ->
|
return client.newCall(accessTokenRequest(code)).asObservableSuccess().map { netResponse ->
|
||||||
val responseBody = netResponse.body()?.string().orEmpty()
|
val responseBody = netResponse.body?.string().orEmpty()
|
||||||
if (responseBody.isEmpty()) {
|
if (responseBody.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ class ShikimoriInterceptor(val shikimori: Shikimori, val gson: Gson) : Intercept
|
|||||||
if (currAuth.isExpired()) {
|
if (currAuth.isExpired()) {
|
||||||
val response = chain.proceed(ShikimoriApi.refreshTokenRequest(refreshToken))
|
val response = chain.proceed(ShikimoriApi.refreshTokenRequest(refreshToken))
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
newAuth(gson.fromJson(response.body()!!.string(), OAuth::class.java))
|
newAuth(gson.fromJson(response.body!!.string(), OAuth::class.java))
|
||||||
} else {
|
} else {
|
||||||
response.close()
|
response.close()
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,14 @@ package eu.kanade.tachiyomi.data.updater
|
|||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.support.v4.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import com.evernote.android.job.Job
|
import com.evernote.android.job.Job
|
||||||
import com.evernote.android.job.JobManager
|
import com.evernote.android.job.JobManager
|
||||||
import com.evernote.android.job.JobRequest
|
import com.evernote.android.job.JobRequest
|
||||||
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.util.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.notificationManager
|
import eu.kanade.tachiyomi.util.notificationManager
|
||||||
|
|
||||||
class UpdaterJob : Job() {
|
class UpdaterJob : Job() {
|
||||||
@ -27,6 +29,7 @@ class UpdaterJob : Job() {
|
|||||||
setContentTitle(context.getString(R.string.app_name))
|
setContentTitle(context.getString(R.string.app_name))
|
||||||
setContentText(context.getString(R.string.update_check_notification_update_available))
|
setContentText(context.getString(R.string.update_check_notification_update_available))
|
||||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||||
|
color = ContextCompat.getColor(context, R.color.colorAccentLight)
|
||||||
// Download action
|
// Download action
|
||||||
addAction(android.R.drawable.stat_sys_download_done,
|
addAction(android.R.drawable.stat_sys_download_done,
|
||||||
context.getString(R.string.action_download),
|
context.getString(R.string.action_download),
|
||||||
|
@ -2,11 +2,13 @@ package eu.kanade.tachiyomi.data.updater
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.support.v4.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationHandler
|
import eu.kanade.tachiyomi.data.notification.NotificationHandler
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
|
import eu.kanade.tachiyomi.util.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.notificationManager
|
import eu.kanade.tachiyomi.util.notificationManager
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,6 +97,7 @@ internal class UpdaterNotifier(private val context: Context) {
|
|||||||
setSmallIcon(android.R.drawable.stat_sys_warning)
|
setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||||
setOnlyAlertOnce(false)
|
setOnlyAlertOnce(false)
|
||||||
setProgress(0, 0, false)
|
setProgress(0, 0, false)
|
||||||
|
color = ContextCompat.getColor(context, R.color.colorAccentLight)
|
||||||
// Retry action
|
// Retry action
|
||||||
addAction(R.drawable.ic_refresh_grey_24dp_img,
|
addAction(R.drawable.ic_refresh_grey_24dp_img,
|
||||||
context.getString(R.string.action_retry),
|
context.getString(R.string.action_retry),
|
||||||
|
@ -71,7 +71,7 @@ class UpdaterService : IntentService(UpdaterService::class.java.name) {
|
|||||||
val apkFile = File(externalCacheDir, "update.apk")
|
val apkFile = File(externalCacheDir, "update.apk")
|
||||||
|
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
response.body()!!.source().saveTo(apkFile)
|
response.body!!.source().saveTo(apkFile)
|
||||||
} else {
|
} else {
|
||||||
response.close()
|
response.close()
|
||||||
throw Exception("Unsuccessful response")
|
throw Exception("Unsuccessful response")
|
||||||
|
@ -27,7 +27,7 @@ interface GithubService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET("/repos/inorichi/tachiyomi/releases/latest")
|
@GET("/repos/Jays2Kings/tachiyomi/releases/latest")
|
||||||
fun getLatestVersion(): Observable<GithubRelease>
|
fun getLatestVersion(): Observable<GithubRelease>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
|||||||
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.util.launchNow
|
import eu.kanade.tachiyomi.util.launchNow
|
||||||
import kotlinx.coroutines.experimental.async
|
import kotlinx.coroutines.async
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
|
@ -32,7 +32,7 @@ internal class ExtensionGithubApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun parseResponse(response: Response): List<Extension.Available> {
|
private fun parseResponse(response: Response): List<Extension.Available> {
|
||||||
val text = response.body()?.use { it.string() } ?: return emptyList()
|
val text = response.body?.use { it.string() } ?: return emptyList()
|
||||||
|
|
||||||
val json = gson.fromJson<JsonArray>(text)
|
val json = gson.fromJson<JsonArray>(text)
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class ExtensionInstallActivity : Activity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkInstallationResult(resultCode: Int) {
|
private fun checkInstallationResult(resultCode: Int) {
|
||||||
val downloadId = intent.extras.getLong(ExtensionInstaller.EXTRA_DOWNLOAD_ID)
|
val downloadId = intent.extras!!.getLong(ExtensionInstaller.EXTRA_DOWNLOAD_ID)
|
||||||
val success = resultCode == RESULT_OK
|
val success = resultCode == RESULT_OK
|
||||||
|
|
||||||
val extensionManager = Injekt.get<ExtensionManager>()
|
val extensionManager = Injekt.get<ExtensionManager>()
|
||||||
|
@ -7,7 +7,6 @@ import android.content.IntentFilter
|
|||||||
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.util.launchNow
|
import eu.kanade.tachiyomi.util.launchNow
|
||||||
import kotlinx.coroutines.experimental.async
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast receiver that listens for the system's packages installed, updated or removed, and only
|
* Broadcast receiver that listens for the system's packages installed, updated or removed, and only
|
||||||
@ -91,7 +90,7 @@ internal class ExtensionInstallReceiver(private val listener: Listener) :
|
|||||||
private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): LoadResult {
|
private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): LoadResult {
|
||||||
val pkgName = getPackageNameFromIntent(intent) ?:
|
val pkgName = getPackageNameFromIntent(intent) ?:
|
||||||
return LoadResult.Error("Package name not found")
|
return LoadResult.Error("Package name not found")
|
||||||
return async { ExtensionLoader.loadExtensionFromPkgName(context, pkgName) }.await()
|
return ExtensionLoader.loadExtensionFromPkgName(context, pkgName)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,8 +13,8 @@ import eu.kanade.tachiyomi.source.CatalogueSource
|
|||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
import eu.kanade.tachiyomi.util.Hash
|
import eu.kanade.tachiyomi.util.Hash
|
||||||
import kotlinx.coroutines.experimental.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.experimental.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
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
|
||||||
@ -121,7 +121,7 @@ internal object ExtensionLoader {
|
|||||||
|
|
||||||
val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
|
val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
|
||||||
|
|
||||||
val sources = appInfo.metaData.getString(METADATA_SOURCE_CLASS)
|
val sources = appInfo.metaData.getString(METADATA_SOURCE_CLASS)!!
|
||||||
.split(";")
|
.split(";")
|
||||||
.map {
|
.map {
|
||||||
val sourceClass = it.trim()
|
val sourceClass = it.trim()
|
||||||
|
@ -14,22 +14,12 @@ class AndroidCookieJar(context: Context) : CookieJar {
|
|||||||
|
|
||||||
private val syncManager by lazy { CookieSyncManager.createInstance(context) }
|
private val syncManager by lazy { CookieSyncManager.createInstance(context) }
|
||||||
|
|
||||||
init {
|
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
|
||||||
// Init sync manager when using anything below L
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
syncManager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveFromResponse(url: HttpUrl, cookies: MutableList<Cookie>) {
|
|
||||||
val urlString = url.toString()
|
val urlString = url.toString()
|
||||||
|
|
||||||
for (cookie in cookies) {
|
for (cookie in cookies) {
|
||||||
manager.setCookie(urlString, cookie.toString())
|
manager.setCookie(urlString, cookie.toString())
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
syncManager.sync()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadForRequest(url: HttpUrl): List<Cookie> {
|
override fun loadForRequest(url: HttpUrl): List<Cookie> {
|
||||||
|
@ -42,7 +42,7 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
|||||||
val response = chain.proceed(chain.request())
|
val response = chain.proceed(chain.request())
|
||||||
|
|
||||||
// Check if Cloudflare anti-bot is on
|
// Check if Cloudflare anti-bot is on
|
||||||
if (response.code() == 503 && response.header("Server") in serverCheck) {
|
if (response.code == 503 && response.header("Server") in serverCheck) {
|
||||||
try {
|
try {
|
||||||
response.close()
|
response.close()
|
||||||
val solutionRequest = resolveWithWebView(chain.request())
|
val solutionRequest = resolveWithWebView(chain.request())
|
||||||
@ -71,8 +71,8 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
|||||||
var solutionUrl: String? = null
|
var solutionUrl: String? = null
|
||||||
var challengeFound = false
|
var challengeFound = false
|
||||||
|
|
||||||
val origRequestUrl = request.url().toString()
|
val origRequestUrl = request.url.toString()
|
||||||
val headers = request.headers().toMultimap().mapValues { it.value.getOrNull(0) ?: "" }
|
val headers = request.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }
|
||||||
|
|
||||||
handler.post {
|
handler.post {
|
||||||
val view = WebView(context)
|
val view = WebView(context)
|
||||||
@ -144,7 +144,7 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
|||||||
|
|
||||||
return Request.Builder().get()
|
return Request.Builder().get()
|
||||||
.url(solution)
|
.url(solution)
|
||||||
.headers(request.headers())
|
.headers(request.headers)
|
||||||
.addHeader("Referer", origRequestUrl)
|
.addHeader("Referer", origRequestUrl)
|
||||||
.addHeader("Accept", "text/html,application/xhtml+xml,application/xml")
|
.addHeader("Accept", "text/html,application/xhtml+xml,application/xml")
|
||||||
.addHeader("Accept-Language", "en")
|
.addHeader("Accept-Language", "en")
|
||||||
|
@ -103,7 +103,7 @@ class NetworkHelper(context: Context) {
|
|||||||
val specCompat = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
val specCompat = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||||
.tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
|
.tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
|
||||||
.cipherSuites(
|
.cipherSuites(
|
||||||
*ConnectionSpec.MODERN_TLS.cipherSuites().orEmpty().toTypedArray(),
|
*ConnectionSpec.MODERN_TLS.cipherSuites.orEmpty().toTypedArray(),
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||||
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
||||||
)
|
)
|
||||||
|
@ -37,7 +37,7 @@ fun Call.asObservable(): Observable<Response> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isUnsubscribed(): Boolean {
|
override fun isUnsubscribed(): Boolean {
|
||||||
return call.isCanceled
|
return call.isCanceled()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ fun Call.asObservableSuccess(): Observable<Response> {
|
|||||||
return asObservable().doOnNext { response ->
|
return asObservable().doOnNext { response ->
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
response.close()
|
response.close()
|
||||||
throw Exception("HTTP error ${response.code()}")
|
throw Exception("HTTP error ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListene
|
|||||||
.addNetworkInterceptor { chain ->
|
.addNetworkInterceptor { chain ->
|
||||||
val originalResponse = chain.proceed(chain.request())
|
val originalResponse = chain.proceed(chain.request())
|
||||||
originalResponse.newBuilder()
|
originalResponse.newBuilder()
|
||||||
.body(ProgressResponseBody(originalResponse.body()!!, listener))
|
.body(ProgressResponseBody(originalResponse.body!!, listener))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
|
@ -8,7 +8,7 @@ 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() {
|
||||||
|
|
||||||
private val bufferedSource: BufferedSource by lazy {
|
private val bufferedSource: BufferedSource by lazy {
|
||||||
Okio.buffer(source(responseBody.source()))
|
source(responseBody.source()).buffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun contentType(): MediaType {
|
override fun contentType(): MediaType {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.source
|
package eu.kanade.tachiyomi.source
|
||||||
|
|
||||||
import android.support.v7.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
|
|
||||||
interface ConfigurableSource : Source {
|
interface ConfigurableSource : Source {
|
||||||
|
|
||||||
fun setupPreferenceScreen(screen: PreferenceScreen)
|
fun setupPreferenceScreen(screen: PreferenceScreen)
|
||||||
}
|
}
|
@ -23,6 +23,7 @@ interface SManga : Serializable {
|
|||||||
var initialized: Boolean
|
var initialized: Boolean
|
||||||
|
|
||||||
fun copyFrom(other: SManga) {
|
fun copyFrom(other: SManga) {
|
||||||
|
|
||||||
if (other.author != null)
|
if (other.author != null)
|
||||||
author = other.author
|
author = other.author
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.activity
|
package eu.kanade.tachiyomi.ui.base.activity
|
||||||
|
|
||||||
import android.support.v7.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import eu.kanade.tachiyomi.util.LocaleHelper
|
import eu.kanade.tachiyomi.util.LocaleHelper
|
||||||
|
|
||||||
abstract class BaseActivity : AppCompatActivity() {
|
abstract class BaseActivity : AppCompatActivity() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.controller
|
package eu.kanade.tachiyomi.ui.base.controller
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v7.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.base.controller
|
|||||||
|
|
||||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.support.v4.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.bluelinelabs.conductor.Controller
|
import com.bluelinelabs.conductor.Controller
|
||||||
import com.bluelinelabs.conductor.Router
|
import com.bluelinelabs.conductor.Router
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.ui.base.controller;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.controller
|
package eu.kanade.tachiyomi.ui.base.controller
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.controller
|
package eu.kanade.tachiyomi.ui.base.controller
|
||||||
|
|
||||||
import android.support.v4.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
|
||||||
interface SecondaryDrawerController {
|
interface SecondaryDrawerController {
|
||||||
|
|
||||||
fun createSecondaryDrawer(drawer: DrawerLayout): ViewGroup?
|
fun createSecondaryDrawer(drawer: androidx.drawerlayout.widget.DrawerLayout): ViewGroup?
|
||||||
|
|
||||||
fun cleanupSecondaryDrawer(drawer: DrawerLayout)
|
fun cleanupSecondaryDrawer(drawer: androidx.drawerlayout.widget.DrawerLayout)
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.controller
|
package eu.kanade.tachiyomi.ui.base.controller
|
||||||
|
|
||||||
import android.support.design.widget.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
|
|
||||||
interface TabbedController {
|
interface TabbedController {
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.holder
|
package eu.kanade.tachiyomi.ui.base.holder
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.holder
|
package eu.kanade.tachiyomi.ui.base.holder
|
||||||
|
|
||||||
import android.support.v7.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
|
||||||
abstract class BaseViewHolder(view: View) : RecyclerView.ViewHolder(view), LayoutContainer {
|
abstract class BaseViewHolder(view: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(view), LayoutContainer {
|
||||||
|
|
||||||
override val containerView: View?
|
override val containerView: View?
|
||||||
get() = itemView
|
get() = itemView
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.presenter;
|
package eu.kanade.tachiyomi.ui.base.presenter;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import nucleus.factory.PresenterFactory;
|
import nucleus.factory.PresenterFactory;
|
||||||
import nucleus.presenter.Presenter;
|
import nucleus.presenter.Presenter;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.base.presenter;
|
package eu.kanade.tachiyomi.ui.base.presenter;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.bluelinelabs.conductor.Controller;
|
import com.bluelinelabs.conductor.Controller;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue
|
package eu.kanade.tachiyomi.ui.catalogue
|
||||||
|
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
import android.support.v7.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import android.support.v7.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.ui.catalogue.browse.BrowseCatalogueController
|
|||||||
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
||||||
import eu.kanade.tachiyomi.ui.catalogue.latest.LatestUpdatesController
|
import eu.kanade.tachiyomi.ui.catalogue.latest.LatestUpdatesController
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController
|
import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController
|
||||||
|
import eu.kanade.tachiyomi.util.RecyclerWindowInsetsListener
|
||||||
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
|
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
|
||||||
import kotlinx.android.synthetic.main.catalogue_main_controller.*
|
import kotlinx.android.synthetic.main.catalogue_main_controller.*
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
@ -98,9 +99,10 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
|
|||||||
adapter = CatalogueAdapter(this)
|
adapter = CatalogueAdapter(this)
|
||||||
|
|
||||||
// Create recycler and set adapter.
|
// Create recycler and set adapter.
|
||||||
recycler.layoutManager = LinearLayoutManager(view.context)
|
recycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(view.context)
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
recycler.addItemDecoration(SourceDividerItemDecoration(view.context))
|
recycler.addItemDecoration(SourceDividerItemDecoration(view.context))
|
||||||
|
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
||||||
|
|
||||||
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
|
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
|
||||||
}
|
}
|
||||||
@ -132,7 +134,7 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
|
|||||||
/**
|
/**
|
||||||
* Called when item is clicked
|
* Called when item is clicked
|
||||||
*/
|
*/
|
||||||
override fun onItemClick(position: Int): Boolean {
|
override fun onItemClick(view: View, position: Int): Boolean {
|
||||||
val item = adapter?.getItem(position) as? SourceItem ?: return false
|
val item = adapter?.getItem(position) as? SourceItem ?: return false
|
||||||
val source = item.source
|
val source = item.source
|
||||||
if (source is LoginSource && !source.isLogged()) {
|
if (source is LoginSource && !source.isLogged()) {
|
||||||
@ -150,7 +152,7 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
|
|||||||
* Called when browse is clicked in [CatalogueAdapter]
|
* Called when browse is clicked in [CatalogueAdapter]
|
||||||
*/
|
*/
|
||||||
override fun onBrowseClick(position: Int) {
|
override fun onBrowseClick(position: Int) {
|
||||||
onItemClick(position)
|
onItemClick(view!!, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,8 +5,10 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||||
import eu.kanade.tachiyomi.util.LocaleHelper
|
import eu.kanade.tachiyomi.util.LocaleHelper
|
||||||
import kotlinx.android.synthetic.main.catalogue_main_controller_card.*
|
import kotlinx.android.synthetic.main.catalogue_main_controller_card.*
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
class LangHolder(view: View, adapter: FlexibleAdapter<*>) :
|
class LangHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) :
|
||||||
BaseFlexibleViewHolder(view, adapter) {
|
BaseFlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
fun bind(item: LangItem) {
|
fun bind(item: LangItem) {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue
|
package eu.kanade.tachiyomi.ui.catalogue
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,16 +24,14 @@ data class LangItem(val code: String) : AbstractHeaderItem<LangHolder>() {
|
|||||||
/**
|
/**
|
||||||
* Creates a new view holder for this item.
|
* Creates a new view holder for this item.
|
||||||
*/
|
*/
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): LangHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LangHolder {
|
||||||
return LangHolder(view, adapter)
|
return LangHolder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds this item to the given view holder.
|
* Binds this item to the given view holder.
|
||||||
*/
|
*/
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: LangHolder,
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: LangHolder, position: Int, payloads: MutableList<Any>) {
|
||||||
position: Int, payloads: List<Any?>?) {
|
|
||||||
|
|
||||||
holder.bind(this)
|
holder.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,27 +4,27 @@ import android.content.Context
|
|||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.support.v7.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
||||||
class SourceDividerItemDecoration(context: Context) : RecyclerView.ItemDecoration() {
|
class SourceDividerItemDecoration(context: Context) : androidx.recyclerview.widget.RecyclerView.ItemDecoration() {
|
||||||
|
|
||||||
private val divider: Drawable
|
private val divider: Drawable
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val a = context.obtainStyledAttributes(intArrayOf(android.R.attr.listDivider))
|
val a = context.obtainStyledAttributes(intArrayOf(android.R.attr.listDivider))
|
||||||
divider = a.getDrawable(0)
|
divider = a.getDrawable(0)!!
|
||||||
a.recycle()
|
a.recycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
override fun onDraw(c: Canvas, parent: androidx.recyclerview.widget.RecyclerView, state: androidx.recyclerview.widget.RecyclerView.State) {
|
||||||
val childCount = parent.childCount
|
val childCount = parent.childCount
|
||||||
for (i in 0 until childCount - 1) {
|
for (i in 0 until childCount - 1) {
|
||||||
val child = parent.getChildAt(i)
|
val child = parent.getChildAt(i)
|
||||||
val holder = parent.getChildViewHolder(child)
|
val holder = parent.getChildViewHolder(child)
|
||||||
if (holder is SourceHolder &&
|
if (holder is SourceHolder &&
|
||||||
parent.getChildViewHolder(parent.getChildAt(i + 1)) is SourceHolder) {
|
parent.getChildViewHolder(parent.getChildAt(i + 1)) is SourceHolder) {
|
||||||
val params = child.layoutParams as RecyclerView.LayoutParams
|
val params = child.layoutParams as androidx.recyclerview.widget.RecyclerView.LayoutParams
|
||||||
val top = child.bottom + params.bottomMargin
|
val top = child.bottom + params.bottomMargin
|
||||||
val bottom = top + divider.intrinsicHeight
|
val bottom = top + divider.intrinsicHeight
|
||||||
val left = parent.paddingLeft + holder.margin
|
val left = parent.paddingLeft + holder.margin
|
||||||
@ -36,8 +36,8 @@ class SourceDividerItemDecoration(context: Context) : RecyclerView.ItemDecoratio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView,
|
override fun getItemOffsets(outRect: Rect, view: View, parent: androidx.recyclerview.widget.RecyclerView,
|
||||||
state: RecyclerView.State) {
|
state: androidx.recyclerview.widget.RecyclerView.State) {
|
||||||
outRect.set(0, 0, 0, divider.intrinsicHeight)
|
outRect.set(0, 0, 0, divider.intrinsicHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue
|
package eu.kanade.tachiyomi.ui.catalogue
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
|
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
|
|
||||||
@ -25,16 +27,14 @@ data class SourceItem(val source: CatalogueSource, val header: LangItem? = null)
|
|||||||
/**
|
/**
|
||||||
* Creates a new view holder for this item.
|
* Creates a new view holder for this item.
|
||||||
*/
|
*/
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): SourceHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): SourceHolder {
|
||||||
return SourceHolder(view, adapter as CatalogueAdapter)
|
return SourceHolder(view, adapter as CatalogueAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds this item to the given view holder.
|
* Binds this item to the given view holder.
|
||||||
*/
|
*/
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: SourceHolder,
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: SourceHolder, position: Int, payloads: MutableList<Any>) {
|
||||||
position: Int, payloads: List<Any?>?) {
|
|
||||||
|
|
||||||
holder.bind(this)
|
holder.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,18 @@ package eu.kanade.tachiyomi.ui.catalogue.browse
|
|||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.design.widget.Snackbar
|
import android.view.LayoutInflater
|
||||||
import android.support.v4.widget.DrawerLayout
|
import android.view.Menu
|
||||||
import android.support.v7.widget.*
|
import android.view.MenuInflater
|
||||||
import android.view.*
|
import android.view.MenuItem
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.core.view.GravityCompat
|
||||||
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import com.f2prateek.rx.preferences.Preference
|
import com.f2prateek.rx.preferences.Preference
|
||||||
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.jakewharton.rxbinding.support.v7.widget.queryTextChangeEvents
|
import com.jakewharton.rxbinding.support.v7.widget.queryTextChangeEvents
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
@ -22,9 +28,21 @@ import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
|
import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
||||||
|
import eu.kanade.tachiyomi.ui.library.HeightTopWindowInsetsListener
|
||||||
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.manga.info.MangaWebViewController
|
import eu.kanade.tachiyomi.ui.manga.info.WebViewActivity
|
||||||
import eu.kanade.tachiyomi.util.*
|
import eu.kanade.tachiyomi.util.RecyclerWindowInsetsListener
|
||||||
|
import eu.kanade.tachiyomi.util.connectivityManager
|
||||||
|
import eu.kanade.tachiyomi.util.doOnApplyWindowInsets
|
||||||
|
import eu.kanade.tachiyomi.util.gone
|
||||||
|
import eu.kanade.tachiyomi.util.inflate
|
||||||
|
import eu.kanade.tachiyomi.util.marginTop
|
||||||
|
import eu.kanade.tachiyomi.util.openInBrowser
|
||||||
|
import eu.kanade.tachiyomi.util.snack
|
||||||
|
import eu.kanade.tachiyomi.util.updateLayoutParams
|
||||||
|
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
||||||
|
import eu.kanade.tachiyomi.util.visible
|
||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||||
import kotlinx.android.synthetic.main.catalogue_controller.*
|
import kotlinx.android.synthetic.main.catalogue_controller.*
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
@ -74,7 +92,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
/**
|
/**
|
||||||
* Recycler view with the list of results.
|
* Recycler view with the list of results.
|
||||||
*/
|
*/
|
||||||
private var recycler: RecyclerView? = null
|
private var recycler: androidx.recyclerview.widget.RecyclerView? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscription for the search view.
|
* Subscription for the search view.
|
||||||
@ -130,19 +148,19 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
super.onDestroyView(view)
|
super.onDestroyView(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createSecondaryDrawer(drawer: DrawerLayout): ViewGroup? {
|
override fun createSecondaryDrawer(drawer: androidx.drawerlayout.widget.DrawerLayout): ViewGroup? {
|
||||||
// Inflate and prepare drawer
|
// Inflate and prepare drawer
|
||||||
val navView = drawer.inflate(R.layout.catalogue_drawer) as CatalogueNavigationView
|
val navView = drawer.inflate(R.layout.catalogue_drawer) as CatalogueNavigationView
|
||||||
this.navView = navView
|
this.navView = navView
|
||||||
navView.setFilters(presenter.filterItems)
|
navView.setFilters(presenter.filterItems)
|
||||||
|
|
||||||
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.END)
|
drawer.setDrawerLockMode(androidx.drawerlayout.widget.DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.END)
|
||||||
|
|
||||||
navView.onSearchClicked = {
|
navView.onSearchClicked = {
|
||||||
val allDefault = presenter.sourceFilters == presenter.source.getFilterList()
|
val allDefault = presenter.sourceFilters == presenter.source.getFilterList()
|
||||||
showProgressBar()
|
showProgressBar()
|
||||||
adapter?.clear()
|
adapter?.clear()
|
||||||
drawer.closeDrawer(Gravity.END)
|
drawer.closeDrawer(GravityCompat.END)
|
||||||
presenter.setSourceFilter(if (allDefault) FilterList() else presenter.sourceFilters)
|
presenter.setSourceFilter(if (allDefault) FilterList() else presenter.sourceFilters)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,30 +170,47 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
presenter.sourceFilters = newFilters
|
presenter.sourceFilters = newFilters
|
||||||
navView.setFilters(presenter.filterItems)
|
navView.setFilters(presenter.filterItems)
|
||||||
}
|
}
|
||||||
|
drawer.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||||
|
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
||||||
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||||
|
|
||||||
|
val statusScrim = navView.findViewById(R.id.status_bar_scrim) as View
|
||||||
|
statusScrim.setOnApplyWindowInsetsListener(HeightTopWindowInsetsListener)
|
||||||
|
val titleView = navView.findViewById(R.id.title_background) as View
|
||||||
|
val titleMarginTop = titleView.marginTop
|
||||||
|
navView.doOnApplyWindowInsets { v, insets, padding ->
|
||||||
|
v.updatePaddingRelative(
|
||||||
|
bottom = padding.bottom + insets.systemWindowInsetBottom,
|
||||||
|
end = padding.right + insets.systemWindowInsetRight
|
||||||
|
)
|
||||||
|
titleView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
topMargin = titleMarginTop + insets.systemWindowInsetTop
|
||||||
|
}
|
||||||
|
}
|
||||||
return navView
|
return navView
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cleanupSecondaryDrawer(drawer: DrawerLayout) {
|
override fun cleanupSecondaryDrawer(drawer: androidx.drawerlayout.widget.DrawerLayout) {
|
||||||
navView = null
|
navView = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecycler(view: View) {
|
private fun setupRecycler(view: View) {
|
||||||
numColumnsSubscription?.unsubscribe()
|
numColumnsSubscription?.unsubscribe()
|
||||||
|
|
||||||
var oldPosition = RecyclerView.NO_POSITION
|
var oldPosition = androidx.recyclerview.widget.RecyclerView.NO_POSITION
|
||||||
val oldRecycler = catalogue_view?.getChildAt(1)
|
val oldRecycler = catalogue_view?.getChildAt(1)
|
||||||
if (oldRecycler is RecyclerView) {
|
if (oldRecycler is androidx.recyclerview.widget.RecyclerView) {
|
||||||
oldPosition = (oldRecycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
|
oldPosition = (oldRecycler.layoutManager as androidx.recyclerview.widget.LinearLayoutManager).findFirstVisibleItemPosition()
|
||||||
oldRecycler.adapter = null
|
oldRecycler.adapter = null
|
||||||
|
|
||||||
catalogue_view?.removeView(oldRecycler)
|
catalogue_view?.removeView(oldRecycler)
|
||||||
}
|
}
|
||||||
|
|
||||||
val recycler = if (presenter.isListMode) {
|
val recycler = if (presenter.isListMode) {
|
||||||
RecyclerView(view.context).apply {
|
androidx.recyclerview.widget.RecyclerView(view.context).apply {
|
||||||
id = R.id.recycler
|
id = R.id.recycler
|
||||||
layoutManager = LinearLayoutManager(context)
|
layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context)
|
||||||
addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
|
addItemDecoration(androidx.recyclerview.widget.DividerItemDecoration(context, androidx.recyclerview.widget.DividerItemDecoration.VERTICAL))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(catalogue_view.inflate(R.layout.catalogue_recycler_autofit) as AutofitRecyclerView).apply {
|
(catalogue_view.inflate(R.layout.catalogue_recycler_autofit) as AutofitRecyclerView).apply {
|
||||||
@ -185,7 +220,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
// Set again the adapter to recalculate the covers height
|
// Set again the adapter to recalculate the covers height
|
||||||
.subscribe { adapter = this@BrowseCatalogueController.adapter }
|
.subscribe { adapter = this@BrowseCatalogueController.adapter }
|
||||||
|
|
||||||
(layoutManager as GridLayoutManager).spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
(layoutManager as androidx.recyclerview.widget.GridLayoutManager).spanSizeLookup = object : androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup() {
|
||||||
override fun getSpanSize(position: Int): Int {
|
override fun getSpanSize(position: Int): Int {
|
||||||
return when (adapter?.getItemViewType(position)) {
|
return when (adapter?.getItemViewType(position)) {
|
||||||
R.layout.catalogue_grid_item, null -> 1
|
R.layout.catalogue_grid_item, null -> 1
|
||||||
@ -199,9 +234,9 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
|
|
||||||
catalogue_view.addView(recycler, 1)
|
catalogue_view.addView(recycler, 1)
|
||||||
|
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
||||||
if (oldPosition != RecyclerView.NO_POSITION) {
|
if (oldPosition != androidx.recyclerview.widget.RecyclerView.NO_POSITION) {
|
||||||
recycler.layoutManager.scrollToPosition(oldPosition)
|
recycler.layoutManager?.scrollToPosition(oldPosition)
|
||||||
}
|
}
|
||||||
this.recycler = recycler
|
this.recycler = recycler
|
||||||
}
|
}
|
||||||
@ -272,7 +307,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_display_mode -> swapDisplayMode()
|
R.id.action_display_mode -> swapDisplayMode()
|
||||||
R.id.action_set_filter -> navView?.let { activity?.drawer?.openDrawer(Gravity.END) }
|
R.id.action_set_filter -> navView?.let { activity?.drawer?.openDrawer(GravityCompat.END) }
|
||||||
R.id.action_open_in_browser -> openInBrowser()
|
R.id.action_open_in_browser -> openInBrowser()
|
||||||
R.id.action_open_in_web_view -> openInWebView()
|
R.id.action_open_in_web_view -> openInWebView()
|
||||||
else -> return super.onOptionsItemSelected(item)
|
else -> return super.onOptionsItemSelected(item)
|
||||||
@ -288,9 +323,10 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
|
|
||||||
private fun openInWebView() {
|
private fun openInWebView() {
|
||||||
val source = presenter.source as? HttpSource ?: return
|
val source = presenter.source as? HttpSource ?: return
|
||||||
|
val activity = activity ?: return
|
||||||
router.pushController(MangaWebViewController(source.id, source.baseUrl)
|
val intent = WebViewActivity.newIntent(activity, source.id, source.baseUrl, presenter
|
||||||
.withFadeTransaction())
|
.source.name)
|
||||||
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -344,7 +380,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
val message = if (error is NoResultsException) "No results found" else (error.message ?: "")
|
val message = if (error is NoResultsException) "No results found" else (error.message ?: "")
|
||||||
|
|
||||||
snack?.dismiss()
|
snack?.dismiss()
|
||||||
snack = catalogue_view?.snack(message, Snackbar.LENGTH_INDEFINITE) {
|
snack = catalouge_layout?.snack(message, Snackbar.LENGTH_INDEFINITE) {
|
||||||
setAction(R.string.action_retry) {
|
setAction(R.string.action_retry) {
|
||||||
// If not the first page, show bottom progress bar.
|
// If not the first page, show bottom progress bar.
|
||||||
if (adapter.mainItemCount > 0) {
|
if (adapter.mainItemCount > 0) {
|
||||||
@ -464,7 +500,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
* @param position the position of the element clicked.
|
* @param position the position of the element clicked.
|
||||||
* @return true if the item should be selected, false otherwise.
|
* @return true if the item should be selected, false otherwise.
|
||||||
*/
|
*/
|
||||||
override fun onItemClick(position: Int): Boolean {
|
override fun onItemClick(view: View?, position: Int): Boolean {
|
||||||
val item = adapter?.getItem(position) as? CatalogueItem ?: return false
|
val item = adapter?.getItem(position) as? CatalogueItem ?: return false
|
||||||
router.pushController(MangaController(item.manga, true).withFadeTransaction())
|
router.pushController(MangaController(item.manga, true).withFadeTransaction())
|
||||||
|
|
||||||
@ -481,31 +517,41 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
* @param position the position of the element clicked.
|
* @param position the position of the element clicked.
|
||||||
*/
|
*/
|
||||||
override fun onItemLongClick(position: Int) {
|
override fun onItemLongClick(position: Int) {
|
||||||
val activity = activity ?: return
|
|
||||||
val manga = (adapter?.getItem(position) as? CatalogueItem?)?.manga ?: return
|
val manga = (adapter?.getItem(position) as? CatalogueItem?)?.manga ?: return
|
||||||
|
snack?.dismiss()
|
||||||
if (manga.favorite) {
|
if (manga.favorite) {
|
||||||
MaterialDialog.Builder(activity)
|
|
||||||
.items(activity.getString(R.string.remove_from_library))
|
|
||||||
.itemsCallback { _, _, which, _ ->
|
|
||||||
when (which) {
|
|
||||||
0 -> {
|
|
||||||
presenter.changeMangaFavorite(manga)
|
|
||||||
adapter?.notifyItemChanged(position)
|
|
||||||
activity?.toast(activity?.getString(R.string.manga_removed_library))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
} else {
|
|
||||||
presenter.changeMangaFavorite(manga)
|
presenter.changeMangaFavorite(manga)
|
||||||
adapter?.notifyItemChanged(position)
|
adapter?.notifyItemChanged(position)
|
||||||
|
snack = catalouge_layout?.snack(R.string.manga_removed_library, Snackbar.LENGTH_INDEFINITE) {
|
||||||
|
setAction(R.string.action_undo) {
|
||||||
|
if (!manga.favorite) addManga(manga, position)
|
||||||
|
}
|
||||||
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
|
super.onDismissed(transientBottomBar, event)
|
||||||
|
if (!manga.favorite) presenter.confirmDeletion(manga)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||||
|
} else {
|
||||||
|
addManga(manga, position)
|
||||||
|
snack = catalouge_layout?.snack(R.string.manga_added_library)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val categories = presenter.getCategories()
|
private fun addManga(manga: Manga, position: Int) {
|
||||||
val defaultCategory = categories.find { it.id == preferences.defaultCategory() }
|
presenter.changeMangaFavorite(manga)
|
||||||
if (defaultCategory != null) {
|
adapter?.notifyItemChanged(position)
|
||||||
presenter.moveMangaToCategory(manga, defaultCategory)
|
|
||||||
} else if (categories.size <= 1) { // default or the one from the user
|
val categories = presenter.getCategories()
|
||||||
presenter.moveMangaToCategory(manga, categories.firstOrNull())
|
val defaultCategoryId = preferences.defaultCategory()
|
||||||
} else {
|
val defaultCategory = categories.find { it.id == defaultCategoryId }
|
||||||
|
when {
|
||||||
|
defaultCategory != null -> presenter.moveMangaToCategory(manga, defaultCategory)
|
||||||
|
defaultCategoryId == 0 || categories.isEmpty() -> // 'Default' or no category
|
||||||
|
presenter.moveMangaToCategory(manga, null)
|
||||||
|
else -> {
|
||||||
val ids = presenter.getMangaCategoryIds(manga)
|
val ids = presenter.getMangaCategoryIds(manga)
|
||||||
val preselected = ids.mapNotNull { id ->
|
val preselected = ids.mapNotNull { id ->
|
||||||
categories.indexOfFirst { it.id == id }.takeIf { it != -1 }
|
categories.indexOfFirst { it.id == id }.takeIf { it != -1 }
|
||||||
@ -514,9 +560,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
ChangeMangaCategoriesDialog(this, listOf(manga), categories, preselected)
|
ChangeMangaCategoriesDialog(this, listOf(manga), categories, preselected)
|
||||||
.showDialog(router)
|
.showDialog(router)
|
||||||
}
|
}
|
||||||
activity?.toast(activity?.getString(R.string.manga_added_library))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Category
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
@ -253,12 +254,15 @@ open class BrowseCataloguePresenter(
|
|||||||
*/
|
*/
|
||||||
fun changeMangaFavorite(manga: Manga) {
|
fun changeMangaFavorite(manga: Manga) {
|
||||||
manga.favorite = !manga.favorite
|
manga.favorite = !manga.favorite
|
||||||
if (!manga.favorite) {
|
|
||||||
coverCache.deleteFromCache(manga.thumbnail_url)
|
|
||||||
}
|
|
||||||
db.insertManga(manga).executeAsBlocking()
|
db.insertManga(manga).executeAsBlocking()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun confirmDeletion(manga: Manga) {
|
||||||
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
|
val downloadManager: DownloadManager = Injekt.get()
|
||||||
|
downloadManager.deleteManga(manga,source)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the active display mode.
|
* Changes the active display mode.
|
||||||
*/
|
*/
|
||||||
@ -316,9 +320,9 @@ open class BrowseCataloguePresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default, and user categories.
|
* Get user categories.
|
||||||
*
|
*
|
||||||
* @return List of categories, default plus user categories
|
* @return List of categories, not including the default category
|
||||||
*/
|
*/
|
||||||
fun getCategories(): List<Category> {
|
fun getCategories(): List<Category> {
|
||||||
return db.getCategories().executeAsBlocking()
|
return db.getCategories().executeAsBlocking()
|
||||||
|
@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
import eu.kanade.tachiyomi.widget.StateImageViewTarget
|
import eu.kanade.tachiyomi.widget.StateImageViewTarget
|
||||||
import kotlinx.android.synthetic.main.catalogue_grid_item.*
|
import kotlinx.android.synthetic.main.catalogue_grid_item.*
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class used to hold the displayed data of a manga in the catalogue, like the cover or the title.
|
* Class used to hold the displayed data of a manga in the catalogue, like the cover or the title.
|
||||||
@ -16,7 +18,7 @@ import kotlinx.android.synthetic.main.catalogue_grid_item.*
|
|||||||
* @param adapter the adapter handling this holder.
|
* @param adapter the adapter handling this holder.
|
||||||
* @constructor creates a new catalogue holder.
|
* @constructor creates a new catalogue holder.
|
||||||
*/
|
*/
|
||||||
class CatalogueGridHolder(private val view: View, private val adapter: FlexibleAdapter<*>) :
|
class CatalogueGridHolder(private val view: View, private val adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) :
|
||||||
CatalogueHolder(view, adapter) {
|
CatalogueHolder(view, adapter) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,6 +4,8 @@ import android.view.View
|
|||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic class used to hold the displayed data of a manga in the catalogue.
|
* Generic class used to hold the displayed data of a manga in the catalogue.
|
||||||
@ -11,7 +13,7 @@ import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
|||||||
* @param view the inflated view for this holder.
|
* @param view the inflated view for this holder.
|
||||||
* @param adapter the adapter handling this holder.
|
* @param adapter the adapter handling this holder.
|
||||||
*/
|
*/
|
||||||
abstract class CatalogueHolder(view: View, adapter: FlexibleAdapter<*>) :
|
abstract class CatalogueHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) :
|
||||||
BaseFlexibleViewHolder(view, adapter) {
|
BaseFlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||||
import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
|
import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference<Boolean>) :
|
class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference<Boolean>) :
|
||||||
AbstractFlexibleItem<CatalogueHolder>() {
|
AbstractFlexibleItem<CatalogueHolder>() {
|
||||||
@ -23,7 +25,7 @@ class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference<Bo
|
|||||||
R.layout.catalogue_grid_item
|
R.layout.catalogue_grid_item
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): CatalogueHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): CatalogueHolder {
|
||||||
val parent = adapter.recyclerView
|
val parent = adapter.recyclerView
|
||||||
return if (parent is AutofitRecyclerView) {
|
return if (parent is AutofitRecyclerView) {
|
||||||
view.apply {
|
view.apply {
|
||||||
@ -38,10 +40,10 @@ class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference<Bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>,
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
|
||||||
holder: CatalogueHolder,
|
holder: CatalogueHolder,
|
||||||
position: Int,
|
position: Int,
|
||||||
payloads: List<Any?>?) {
|
payloads: MutableList<Any?>?) {
|
||||||
|
|
||||||
holder.onSetValues(manga)
|
holder.onSetValues(manga)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
import eu.kanade.tachiyomi.util.getResourceColor
|
import eu.kanade.tachiyomi.util.getResourceColor
|
||||||
import kotlinx.android.synthetic.main.catalogue_list_item.*
|
import kotlinx.android.synthetic.main.catalogue_list_item.*
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class used to hold the displayed data of a manga in the catalogue, like the cover or the title.
|
* Class used to hold the displayed data of a manga in the catalogue, like the cover or the title.
|
||||||
@ -16,7 +18,7 @@ import kotlinx.android.synthetic.main.catalogue_list_item.*
|
|||||||
* @param adapter the adapter handling this holder.
|
* @param adapter the adapter handling this holder.
|
||||||
* @constructor creates a new catalogue holder.
|
* @constructor creates a new catalogue holder.
|
||||||
*/
|
*/
|
||||||
class CatalogueListHolder(private val view: View, adapter: FlexibleAdapter<*>) :
|
class CatalogueListHolder(private val view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) :
|
||||||
CatalogueHolder(view, adapter) {
|
CatalogueHolder(view, adapter) {
|
||||||
|
|
||||||
private val favoriteColor = view.context.getResourceColor(android.R.attr.textColorHint)
|
private val favoriteColor = view.context.getResourceColor(android.R.attr.textColorHint)
|
||||||
|
@ -3,8 +3,10 @@ package eu.kanade.tachiyomi.ui.catalogue.browse
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
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.viewholders.FlexibleViewHolder
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
@ -17,11 +19,11 @@ class ProgressItem : AbstractFlexibleItem<ProgressItem.Holder>() {
|
|||||||
return R.layout.catalogue_progress_item
|
return R.layout.catalogue_progress_item
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: MutableList<Any>) {
|
||||||
holder.progressBar.visibility = View.GONE
|
holder.progressBar.visibility = View.GONE
|
||||||
holder.progressMessage.visibility = View.GONE
|
holder.progressMessage.visibility = View.GONE
|
||||||
|
|
||||||
@ -40,7 +42,7 @@ class ProgressItem : AbstractFlexibleItem<ProgressItem.Holder>() {
|
|||||||
return this === other
|
return this === other
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : FlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
val progressBar: ProgressBar = view.findViewById(R.id.progress_bar)
|
val progressBar: ProgressBar = view.findViewById(R.id.progress_bar)
|
||||||
val progressMessage: TextView = view.findViewById(R.id.progress_message)
|
val progressMessage: TextView = view.findViewById(R.id.progress_message)
|
||||||
|
@ -2,8 +2,10 @@ package eu.kanade.tachiyomi.ui.catalogue.filter
|
|||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.CheckBox
|
import android.widget.CheckBox
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
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.viewholders.FlexibleViewHolder
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
@ -14,11 +16,11 @@ open class CheckboxItem(val filter: Filter.CheckBox) : AbstractFlexibleItem<Chec
|
|||||||
return R.layout.navigation_view_checkbox
|
return R.layout.navigation_view_checkbox
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: MutableList<Any>) {
|
||||||
val view = holder.check
|
val view = holder.check
|
||||||
view.text = filter.name
|
view.text = filter.name
|
||||||
view.isChecked = filter.state
|
view.isChecked = filter.state
|
||||||
@ -38,7 +40,7 @@ open class CheckboxItem(val filter: Filter.CheckBox) : AbstractFlexibleItem<Chec
|
|||||||
return filter.hashCode()
|
return filter.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : FlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
val check: CheckBox = itemView.findViewById(R.id.nav_view_item)
|
val check: CheckBox = itemView.findViewById(R.id.nav_view_item)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import eu.davidea.viewholders.ExpandableViewHolder
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.util.setVectorCompat
|
import eu.kanade.tachiyomi.util.setVectorCompat
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
class GroupItem(val filter: Filter.Group<*>) : AbstractExpandableHeaderItem<GroupItem.Holder, ISectionable<*, *>>() {
|
class GroupItem(val filter: Filter.Group<*>) : AbstractExpandableHeaderItem<GroupItem.Holder, ISectionable<*, *>>() {
|
||||||
|
|
||||||
@ -25,11 +27,11 @@ class GroupItem(val filter: Filter.Group<*>) : AbstractExpandableHeaderItem<Grou
|
|||||||
return 101
|
return 101
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: MutableList<Any?>?) {
|
||||||
holder.title.text = filter.name
|
holder.title.text = filter.name
|
||||||
|
|
||||||
holder.icon.setVectorCompat(if (isExpanded)
|
holder.icon.setVectorCompat(if (isExpanded)
|
||||||
@ -52,7 +54,7 @@ class GroupItem(val filter: Filter.Group<*>) : AbstractExpandableHeaderItem<Grou
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open class Holder(view: View, adapter: FlexibleAdapter<*>) : ExpandableViewHolder(view, adapter, true) {
|
open class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : ExpandableViewHolder(view, adapter, true) {
|
||||||
|
|
||||||
val title: TextView = itemView.findViewById(R.id.title)
|
val title: TextView = itemView.findViewById(R.id.title)
|
||||||
val icon: ImageView = itemView.findViewById(R.id.expand_icon)
|
val icon: ImageView = itemView.findViewById(R.id.expand_icon)
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.support.design.R
|
import com.google.android.material.R
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
class HeaderItem(val filter: Filter.Header) : AbstractHeaderItem<HeaderItem.Holder>() {
|
class HeaderItem(val filter: Filter.Header) : AbstractHeaderItem<HeaderItem.Holder>() {
|
||||||
|
|
||||||
@ -16,11 +18,11 @@ class HeaderItem(val filter: Filter.Header) : AbstractHeaderItem<HeaderItem.Hold
|
|||||||
return R.layout.design_navigation_item_subheader
|
return R.layout.design_navigation_item_subheader
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: MutableList<Any?>?) {
|
||||||
val view = holder.itemView as TextView
|
val view = holder.itemView as TextView
|
||||||
view.text = filter.name
|
view.text = filter.name
|
||||||
}
|
}
|
||||||
@ -35,5 +37,5 @@ class HeaderItem(val filter: Filter.Header) : AbstractHeaderItem<HeaderItem.Hold
|
|||||||
return filter.hashCode()
|
return filter.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter)
|
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : FlexibleViewHolder(view, adapter)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import eu.davidea.viewholders.FlexibleViewHolder
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
|
import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem<SelectItem.Holder>() {
|
open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem<SelectItem.Holder>() {
|
||||||
|
|
||||||
@ -17,11 +19,11 @@ open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem<Selec
|
|||||||
return R.layout.navigation_view_spinner
|
return R.layout.navigation_view_spinner
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: MutableList<Any?>?) {
|
||||||
holder.text.text = filter.name + ": "
|
holder.text.text = filter.name + ": "
|
||||||
|
|
||||||
val spinner = holder.spinner
|
val spinner = holder.spinner
|
||||||
@ -46,7 +48,7 @@ open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem<Selec
|
|||||||
return filter.hashCode()
|
return filter.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : FlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
val text: TextView = itemView.findViewById(R.id.nav_view_item_text)
|
val text: TextView = itemView.findViewById(R.id.nav_view_item_text)
|
||||||
val spinner: Spinner = itemView.findViewById(R.id.nav_view_item)
|
val spinner: Spinner = itemView.findViewById(R.id.nav_view_item)
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.support.design.R
|
import com.google.android.material.R
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
|
||||||
@ -15,11 +17,12 @@ class SeparatorItem(val filter: Filter.Separator) : AbstractHeaderItem<Separator
|
|||||||
return R.layout.design_navigation_item_separator
|
return R.layout.design_navigation_item_separator
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
|
||||||
|
holder: Holder, position: Int, payloads: MutableList<Any?>?) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,5 +36,5 @@ class SeparatorItem(val filter: Filter.Separator) : AbstractHeaderItem<Separator
|
|||||||
return filter.hashCode()
|
return filter.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter)
|
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : FlexibleViewHolder(view, adapter)
|
||||||
}
|
}
|
@ -1,8 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem
|
import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.davidea.flexibleadapter.items.ISectionable
|
import eu.davidea.flexibleadapter.items.ISectionable
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
@ -22,11 +24,11 @@ class SortGroup(val filter: Filter.Sort) : AbstractExpandableHeaderItem<SortGrou
|
|||||||
return 100
|
return 100
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: MutableList<Any?>?) {
|
||||||
holder.title.text = filter.name
|
holder.title.text = filter.name
|
||||||
|
|
||||||
holder.icon.setVectorCompat(if (isExpanded)
|
holder.icon.setVectorCompat(if (isExpanded)
|
||||||
@ -48,5 +50,5 @@ class SortGroup(val filter: Filter.Sort) : AbstractExpandableHeaderItem<SortGrou
|
|||||||
return filter.hashCode()
|
return filter.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : GroupItem.Holder(view, adapter)
|
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : GroupItem.Holder(view, adapter)
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||||
|
|
||||||
import android.support.graphics.drawable.VectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
||||||
import android.support.v4.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.CheckedTextView
|
import android.widget.CheckedTextView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
@ -10,6 +10,8 @@ import eu.davidea.viewholders.FlexibleViewHolder
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.util.getResourceColor
|
import eu.kanade.tachiyomi.util.getResourceColor
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
class SortItem(val name: String, val group: SortGroup) : AbstractSectionableItem<SortItem.Holder, SortGroup>(group) {
|
class SortItem(val name: String, val group: SortGroup) : AbstractSectionableItem<SortItem.Holder, SortGroup>(group) {
|
||||||
|
|
||||||
@ -21,11 +23,11 @@ class SortItem(val name: String, val group: SortGroup) : AbstractSectionableItem
|
|||||||
return 102
|
return 102
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: MutableList<Any?>?) {
|
||||||
val view = holder.text
|
val view = holder.text
|
||||||
view.text = name
|
view.text = name
|
||||||
val filter = group.filter
|
val filter = group.filter
|
||||||
@ -66,7 +68,7 @@ class SortItem(val name: String, val group: SortGroup) : AbstractSectionableItem
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : FlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
val text: CheckedTextView = itemView.findViewById(R.id.nav_view_item)
|
val text: CheckedTextView = itemView.findViewById(R.id.nav_view_item)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||||
|
|
||||||
import android.support.design.widget.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
@ -9,6 +9,8 @@ import eu.davidea.viewholders.FlexibleViewHolder
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
open class TextItem(val filter: Filter.Text) : AbstractFlexibleItem<TextItem.Holder>() {
|
open class TextItem(val filter: Filter.Text) : AbstractFlexibleItem<TextItem.Holder>() {
|
||||||
|
|
||||||
@ -16,11 +18,11 @@ open class TextItem(val filter: Filter.Text) : AbstractFlexibleItem<TextItem.Hol
|
|||||||
return R.layout.navigation_view_text
|
return R.layout.navigation_view_text
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: MutableList<Any?>?) {
|
||||||
holder.wrapper.hint = filter.name
|
holder.wrapper.hint = filter.name
|
||||||
holder.edit.setText(filter.state)
|
holder.edit.setText(filter.state)
|
||||||
holder.edit.addTextChangedListener(object : SimpleTextWatcher() {
|
holder.edit.addTextChangedListener(object : SimpleTextWatcher() {
|
||||||
@ -40,7 +42,7 @@ open class TextItem(val filter: Filter.Text) : AbstractFlexibleItem<TextItem.Hol
|
|||||||
return filter.hashCode()
|
return filter.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : FlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
val wrapper: TextInputLayout = itemView.findViewById(R.id.nav_view_item_wrapper)
|
val wrapper: TextInputLayout = itemView.findViewById(R.id.nav_view_item_wrapper)
|
||||||
val edit: EditText = itemView.findViewById(R.id.nav_view_item)
|
val edit: EditText = itemView.findViewById(R.id.nav_view_item)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||||
|
|
||||||
import android.support.design.R
|
import com.google.android.material.R
|
||||||
import android.support.graphics.drawable.VectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.CheckedTextView
|
import android.widget.CheckedTextView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
@ -11,6 +11,8 @@ import eu.kanade.tachiyomi.source.model.Filter
|
|||||||
import eu.kanade.tachiyomi.util.dpToPx
|
import eu.kanade.tachiyomi.util.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.getResourceColor
|
import eu.kanade.tachiyomi.util.getResourceColor
|
||||||
import eu.kanade.tachiyomi.R as TR
|
import eu.kanade.tachiyomi.R as TR
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriStateItem.Holder>() {
|
open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriStateItem.Holder>() {
|
||||||
|
|
||||||
@ -22,11 +24,11 @@ open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriS
|
|||||||
return 103
|
return 103
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
return Holder(view, adapter)
|
return Holder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: MutableList<Any?>?) {
|
||||||
val view = holder.text
|
val view = holder.text
|
||||||
view.text = filter.name
|
view.text = filter.name
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriS
|
|||||||
return filter.hashCode()
|
return filter.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : FlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
val text: CheckedTextView = itemView.findViewById(TR.id.nav_view_item)
|
val text: CheckedTextView = itemView.findViewById(TR.id.nav_view_item)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.catalogue.global_search
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.support.v7.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
|
||||||
@ -19,12 +19,12 @@ class CatalogueSearchAdapter(val controller: CatalogueSearchController) :
|
|||||||
*/
|
*/
|
||||||
private var bundle = Bundle()
|
private var bundle = Bundle()
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: List<Any?>?) {
|
override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) {
|
||||||
super.onBindViewHolder(holder, position, payloads)
|
super.onBindViewHolder(holder, position)
|
||||||
restoreHolderState(holder)
|
restoreHolderState(holder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
|
override fun onViewRecycled(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder) {
|
||||||
super.onViewRecycled(holder)
|
super.onViewRecycled(holder)
|
||||||
saveHolderState(holder, bundle)
|
saveHolderState(holder, bundle)
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ class CatalogueSearchAdapter(val controller: CatalogueSearchController) :
|
|||||||
|
|
||||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||||
super.onRestoreInstanceState(savedInstanceState)
|
super.onRestoreInstanceState(savedInstanceState)
|
||||||
bundle = savedInstanceState.getBundle(HOLDER_BUNDLE_KEY)
|
bundle = savedInstanceState.getBundle(HOLDER_BUNDLE_KEY)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,7 +47,7 @@ class CatalogueSearchAdapter(val controller: CatalogueSearchController) :
|
|||||||
* @param holder The holder to save.
|
* @param holder The holder to save.
|
||||||
* @param outState The bundle where the state is saved.
|
* @param outState The bundle where the state is saved.
|
||||||
*/
|
*/
|
||||||
private fun saveHolderState(holder: RecyclerView.ViewHolder, outState: Bundle) {
|
private fun saveHolderState(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, outState: Bundle) {
|
||||||
val key = "holder_${holder.adapterPosition}"
|
val key = "holder_${holder.adapterPosition}"
|
||||||
val holderState = SparseArray<Parcelable>()
|
val holderState = SparseArray<Parcelable>()
|
||||||
holder.itemView.saveHierarchyState(holderState)
|
holder.itemView.saveHierarchyState(holderState)
|
||||||
@ -59,7 +59,7 @@ class CatalogueSearchAdapter(val controller: CatalogueSearchController) :
|
|||||||
*
|
*
|
||||||
* @param holder The holder to restore.
|
* @param holder The holder to restore.
|
||||||
*/
|
*/
|
||||||
private fun restoreHolderState(holder: RecyclerView.ViewHolder) {
|
private fun restoreHolderState(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder) {
|
||||||
val key = "holder_${holder.adapterPosition}"
|
val key = "holder_${holder.adapterPosition}"
|
||||||
val holderState = bundle.getSparseParcelableArray<Parcelable>(key)
|
val holderState = bundle.getSparseParcelableArray<Parcelable>(key)
|
||||||
if (holderState != null) {
|
if (holderState != null) {
|
||||||
|
@ -5,6 +5,8 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
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 androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
class CatalogueSearchCardItem(val manga: Manga) : AbstractFlexibleItem<CatalogueSearchCardHolder>() {
|
class CatalogueSearchCardItem(val manga: Manga) : AbstractFlexibleItem<CatalogueSearchCardHolder>() {
|
||||||
|
|
||||||
@ -12,12 +14,12 @@ class CatalogueSearchCardItem(val manga: Manga) : AbstractFlexibleItem<Catalogue
|
|||||||
return R.layout.catalogue_global_search_controller_card_item
|
return R.layout.catalogue_global_search_controller_card_item
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): CatalogueSearchCardHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): CatalogueSearchCardHolder {
|
||||||
return CatalogueSearchCardHolder(view, adapter as CatalogueSearchCardAdapter)
|
return CatalogueSearchCardHolder(view, adapter as CatalogueSearchCardAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: CatalogueSearchCardHolder,
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: CatalogueSearchCardHolder,
|
||||||
position: Int, payloads: List<Any?>?) {
|
position: Int, payloads: MutableList<Any?>?) {
|
||||||
holder.bind(manga)
|
holder.bind(manga)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.global_search
|
package eu.kanade.tachiyomi.ui.catalogue.global_search
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v7.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import android.support.v7.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import com.jakewharton.rxbinding.support.v7.widget.queryTextChangeEvents
|
import com.jakewharton.rxbinding.support.v7.widget.queryTextChangeEvents
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.source.CatalogueSource
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import eu.kanade.tachiyomi.util.RecyclerWindowInsetsListener
|
||||||
import kotlinx.android.synthetic.main.catalogue_global_search_controller.*
|
import kotlinx.android.synthetic.main.catalogue_global_search_controller.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,8 +132,9 @@ open class CatalogueSearchController(
|
|||||||
adapter = CatalogueSearchAdapter(this)
|
adapter = CatalogueSearchAdapter(this)
|
||||||
|
|
||||||
// Create recycler and set adapter.
|
// Create recycler and set adapter.
|
||||||
recycler.layoutManager = LinearLayoutManager(view.context)
|
recycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(view.context)
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
|
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView(view: View) {
|
override fun onDestroyView(view: View) {
|
||||||
@ -169,12 +171,29 @@ open class CatalogueSearchController(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun handleBack(): Boolean {
|
||||||
|
return if (extensionFilter != null) {
|
||||||
|
activity?.finishAffinity()
|
||||||
|
true
|
||||||
|
} else super.handleBack()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add search result to adapter.
|
* Add search result to adapter.
|
||||||
*
|
*
|
||||||
* @param searchResult result of search.
|
* @param searchResult result of search.
|
||||||
*/
|
*/
|
||||||
fun setItems(searchResult: List<CatalogueSearchItem>) {
|
fun setItems(searchResult: List<CatalogueSearchItem>) {
|
||||||
|
if (extensionFilter != null) {
|
||||||
|
val results = searchResult.first().results
|
||||||
|
if (results != null && results.size == 1) {
|
||||||
|
val manga = results.first().manga
|
||||||
|
router.pushController(MangaController(manga,true,fromExtension = true)
|
||||||
|
.withFadeTransaction()
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
adapter?.updateDataSet(searchResult)
|
adapter?.updateDataSet(searchResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.global_search
|
package eu.kanade.tachiyomi.ui.catalogue.global_search
|
||||||
|
|
||||||
import android.support.v7.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import android.view.View
|
import android.view.View
|
||||||
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
|
||||||
@ -29,7 +29,8 @@ class CatalogueSearchHolder(view: View, val adapter: CatalogueSearchAdapter) :
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
// Set layout horizontal.
|
// Set layout horizontal.
|
||||||
recycler.layoutManager = LinearLayoutManager(view.context, LinearLayoutManager.HORIZONTAL, false)
|
recycler.layoutManager =
|
||||||
|
androidx.recyclerview.widget.LinearLayoutManager(view.context, androidx.recyclerview.widget.LinearLayoutManager.HORIZONTAL, false)
|
||||||
recycler.adapter = mangaAdapter
|
recycler.adapter = mangaAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Item that contains search result information.
|
* Item that contains search result information.
|
||||||
@ -30,15 +32,15 @@ class CatalogueSearchItem(val source: CatalogueSource, val results: List<Catalog
|
|||||||
*
|
*
|
||||||
* @return holder of view.
|
* @return holder of view.
|
||||||
*/
|
*/
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): CatalogueSearchHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): CatalogueSearchHolder {
|
||||||
return CatalogueSearchHolder(view, adapter as CatalogueSearchAdapter)
|
return CatalogueSearchHolder(view, adapter as CatalogueSearchAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind item to view.
|
* Bind item to view.
|
||||||
*/
|
*/
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: CatalogueSearchHolder,
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: CatalogueSearchHolder,
|
||||||
position: Int, payloads: List<Any?>?) {
|
position: Int, payloads: MutableList<Any?>?) {
|
||||||
holder.bind(this)
|
holder.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.latest
|
package eu.kanade.tachiyomi.ui.catalogue.latest
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v4.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -28,11 +28,11 @@ class LatestUpdatesController(bundle: Bundle) : BrowseCatalogueController(bundle
|
|||||||
menu.findItem(R.id.action_set_filter).isVisible = false
|
menu.findItem(R.id.action_set_filter).isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createSecondaryDrawer(drawer: DrawerLayout): ViewGroup? {
|
override fun createSecondaryDrawer(drawer: androidx.drawerlayout.widget.DrawerLayout): ViewGroup? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cleanupSecondaryDrawer(drawer: DrawerLayout) {
|
override fun cleanupSecondaryDrawer(drawer: androidx.drawerlayout.widget.DrawerLayout) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.ui.category
|
package eu.kanade.tachiyomi.ui.category
|
||||||
|
|
||||||
import android.support.design.widget.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import android.support.v7.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import android.support.v7.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import android.support.v7.widget.LinearLayoutManager
|
|
||||||
import android.support.v7.widget.RecyclerView
|
|
||||||
import android.view.*
|
import android.view.*
|
||||||
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
import com.jakewharton.rxbinding.view.clicks
|
import com.jakewharton.rxbinding.view.clicks
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
import eu.davidea.flexibleadapter.SelectableAdapter
|
||||||
@ -13,7 +12,13 @@ import eu.davidea.flexibleadapter.helpers.UndoHelper
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Category
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
|
import eu.kanade.tachiyomi.util.doOnApplyWindowInsets
|
||||||
|
import eu.kanade.tachiyomi.util.marginBottom
|
||||||
|
import eu.kanade.tachiyomi.util.snack
|
||||||
import eu.kanade.tachiyomi.util.toast
|
import eu.kanade.tachiyomi.util.toast
|
||||||
|
import eu.kanade.tachiyomi.util.updateLayoutParams
|
||||||
|
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
||||||
import kotlinx.android.synthetic.main.categories_controller.*
|
import kotlinx.android.synthetic.main.categories_controller.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +46,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
|
|||||||
/**
|
/**
|
||||||
* Undo helper used for restoring a deleted category.
|
* Undo helper used for restoring a deleted category.
|
||||||
*/
|
*/
|
||||||
private var undoHelper: UndoHelper? = null
|
private var snack: Snackbar? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the presenter for this controller. Not to be manually called.
|
* Creates the presenter for this controller. Not to be manually called.
|
||||||
@ -74,7 +79,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
|
|||||||
super.onViewCreated(view)
|
super.onViewCreated(view)
|
||||||
|
|
||||||
adapter = CategoryAdapter(this@CategoryController)
|
adapter = CategoryAdapter(this@CategoryController)
|
||||||
recycler.layoutManager = LinearLayoutManager(view.context)
|
recycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(view.context)
|
||||||
recycler.setHasFixedSize(true)
|
recycler.setHasFixedSize(true)
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
adapter?.isHandleDragEnabled = true
|
adapter?.isHandleDragEnabled = true
|
||||||
@ -83,6 +88,14 @@ class CategoryController : NucleusController<CategoryPresenter>(),
|
|||||||
fab.clicks().subscribeUntilDestroy {
|
fab.clicks().subscribeUntilDestroy {
|
||||||
CategoryCreateDialog(this@CategoryController).showDialog(router, null)
|
CategoryCreateDialog(this@CategoryController).showDialog(router, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val fabBaseMarginBottom = fab?.marginBottom ?: 0
|
||||||
|
recycler.doOnApplyWindowInsets { v, insets, padding ->
|
||||||
|
v.updatePaddingRelative(bottom = padding.bottom + insets.systemWindowInsetBottom)
|
||||||
|
fab?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
bottomMargin = fabBaseMarginBottom + insets.systemWindowInsetBottom
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,8 +105,9 @@ class CategoryController : NucleusController<CategoryPresenter>(),
|
|||||||
*/
|
*/
|
||||||
override fun onDestroyView(view: View) {
|
override fun onDestroyView(view: View) {
|
||||||
// Manually call callback to delete categories if required
|
// Manually call callback to delete categories if required
|
||||||
undoHelper?.onDeleteConfirmed(Snackbar.Callback.DISMISS_EVENT_MANUAL)
|
snack?.dismiss()
|
||||||
undoHelper = null
|
confirmDelete()
|
||||||
|
snack = null
|
||||||
actionMode = null
|
actionMode = null
|
||||||
adapter = null
|
adapter = null
|
||||||
super.onDestroyView(view)
|
super.onDestroyView(view)
|
||||||
@ -166,10 +180,22 @@ class CategoryController : NucleusController<CategoryPresenter>(),
|
|||||||
|
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_delete -> {
|
R.id.action_delete -> {
|
||||||
undoHelper = UndoHelper(adapter, this)
|
adapter.removeItems(adapter.selectedPositions)
|
||||||
undoHelper?.start(adapter.selectedPositions, view!!,
|
snack =
|
||||||
R.string.snack_categories_deleted, R.string.action_undo, 3000)
|
view?.snack(R.string.snack_categories_deleted, Snackbar.LENGTH_INDEFINITE) {
|
||||||
|
var undoing = false
|
||||||
|
setAction(R.string.action_undo) {
|
||||||
|
adapter.restoreDeletedItems()
|
||||||
|
undoing = true
|
||||||
|
}
|
||||||
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
|
super.onDismissed(transientBottomBar, event)
|
||||||
|
if (!undoing) confirmDelete()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||||
mode.finish()
|
mode.finish()
|
||||||
}
|
}
|
||||||
R.id.action_edit -> {
|
R.id.action_edit -> {
|
||||||
@ -205,9 +231,9 @@ class CategoryController : NucleusController<CategoryPresenter>(),
|
|||||||
* @param position The position of the clicked item.
|
* @param position The position of the clicked item.
|
||||||
* @return true if this click should enable selection mode.
|
* @return true if this click should enable selection mode.
|
||||||
*/
|
*/
|
||||||
override fun onItemClick(position: Int): Boolean {
|
override fun onItemClick(view: View?, position: Int): Boolean {
|
||||||
// Check if action mode is initialized and selected item exist.
|
// Check if action mode is initialized and selected item exist.
|
||||||
if (actionMode != null && position != RecyclerView.NO_POSITION) {
|
if (actionMode != null && position != androidx.recyclerview.widget.RecyclerView.NO_POSITION) {
|
||||||
toggleSelection(position)
|
toggleSelection(position)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
@ -270,7 +296,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
|
|||||||
*/
|
*/
|
||||||
override fun onActionCanceled(action: Int, positions: MutableList<Int>?) {
|
override fun onActionCanceled(action: Int, positions: MutableList<Int>?) {
|
||||||
adapter?.restoreDeletedItems()
|
adapter?.restoreDeletedItems()
|
||||||
undoHelper = null
|
snack = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -282,7 +308,13 @@ class CategoryController : NucleusController<CategoryPresenter>(),
|
|||||||
override fun onActionConfirmed(action: Int, event: Int) {
|
override fun onActionConfirmed(action: Int, event: Int) {
|
||||||
val adapter = adapter ?: return
|
val adapter = adapter ?: return
|
||||||
presenter.deleteCategories(adapter.deletedItems.map { it.category })
|
presenter.deleteCategories(adapter.deletedItems.map { it.category })
|
||||||
undoHelper = null
|
snack = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun confirmDelete() {
|
||||||
|
val adapter = adapter ?: return
|
||||||
|
presenter.deleteCategories(adapter.deletedItems.map { it.category })
|
||||||
|
snack = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.ui.category
|
package eu.kanade.tachiyomi.ui.category
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
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.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Category
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
|
|
||||||
@ -29,7 +31,7 @@ class CategoryItem(val category: Category) : AbstractFlexibleItem<CategoryHolder
|
|||||||
* @param view The view of this item.
|
* @param view The view of this item.
|
||||||
* @param adapter The adapter of this item.
|
* @param adapter The adapter of this item.
|
||||||
*/
|
*/
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): CategoryHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): CategoryHolder {
|
||||||
return CategoryHolder(view, adapter as CategoryAdapter)
|
return CategoryHolder(view, adapter as CategoryAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,11 +43,7 @@ class CategoryItem(val category: Category) : AbstractFlexibleItem<CategoryHolder
|
|||||||
* @param position The position of this item in the adapter.
|
* @param position The position of this item in the adapter.
|
||||||
* @param payloads List of partial changes.
|
* @param payloads List of partial changes.
|
||||||
*/
|
*/
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>,
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: CategoryHolder, position: Int, payloads: MutableList<Any>) {
|
||||||
holder: CategoryHolder,
|
|
||||||
position: Int,
|
|
||||||
payloads: List<Any?>?) {
|
|
||||||
|
|
||||||
holder.bind(category)
|
holder.bind(category)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.download
|
package eu.kanade.tachiyomi.ui.download
|
||||||
|
|
||||||
import android.support.v7.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.util.inflate
|
|||||||
*
|
*
|
||||||
* @param context the context of the fragment containing this adapter.
|
* @param context the context of the fragment containing this adapter.
|
||||||
*/
|
*/
|
||||||
class DownloadAdapter : RecyclerView.Adapter<DownloadHolder>() {
|
class DownloadAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<DownloadHolder>() {
|
||||||
|
|
||||||
private var items = emptyList<Download>()
|
private var items = emptyList<Download>()
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user