diff --git a/.github/workflows/build_on_commit.yml b/.github/workflows/build_on_commit.yml
index fd3fcd8..c7eb8ce 100644
--- a/.github/workflows/build_on_commit.yml
+++ b/.github/workflows/build_on_commit.yml
@@ -12,32 +12,73 @@ jobs:
runs-on: ubuntu-latest
steps:
- - name: Checkout commit
- uses: actions/checkout@v2
+ - uses: actions/checkout@v2
+ - name: Create version and tag
+ id: tag_version
+ run: |
+ echo "::set-output name=new_tag::v$(grep 'version=' gradle.properties | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')" &&
+ echo "::set-output name=new_version::$(grep 'version=' gradle.properties | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')" &&
+ echo "::set-output name=full_tag::v$(grep 'version=' gradle.properties | grep -oE '[0-9]+\.[0-9]+\.[0-9]+*')" &&
+ echo "::set-output name=snapshot_date::$(date -Iseconds)"
- name: Setup signing information
env:
KEY_FILE: ${{ secrets.signingKeyBase64 }}
run: echo "$KEY_FILE" | openssl base64 -d > signingKey.jks
- - name: Build release apk
+ - name: set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Build apk
env:
KEY_STORE_PWD: ${{ secrets.keyStorePassword }}
KEY_ALIAS: ${{ secrets.alias }}
KEY_PWD: ${{ secrets.keyPassword }}
- uses: vgaidarji/android-github-actions-build@v1.0.1
- with:
- args: "./gradlew signingReport && ./gradlew :app:assembleRelease --stacktrace"
+ run: |
+ ./gradlew signingReport &&
+ ./gradlew :app:assembleRelease --stacktrace
- name: Cleanup signing information
run: rm signingKey.jks
- - name: Get version code and name
- run: |
- echo "::set-env name=VER_CODE::$(cat app/build/outputs/apk/release/output.json | tr ',' '\n' | grep versionCode | cut -d: -f2)" && \
- echo "::set-env name=VER_NAME::$(cat app/build/outputs/apk/release/output.json | tr ',' '\n' | grep versionName | cut -d: -f2 | tr -d \")"
- name: Copy release apk and mapping
- run: |
- mkdir -p artifacts${{ env.VER_CODE }}v${{ env.VER_NAME }} && \
- cp -r app/build/outputs/* artifacts${{ env.VER_CODE }}v${{ env.VER_NAME }}/
- - name: Upload artifacts ${{ env.VER_CODE }}v${{ env.VER_NAME }}
+ run: zip -r artifacts_${{ steps.tag_version.outputs.new_tag }}.zip app/build/outputs
+ - name: Export artifacts
+ uses: actions/upload-artifact@v1
+ with:
+ name: artifacts_${{ steps.tag_version.outputs.new_tag }}.zip
+ path: artifacts_${{ steps.tag_version.outputs.new_tag }}.zip
+ - name: Export APK
uses: actions/upload-artifact@v1
with:
- name: artifacts${{ env.VER_CODE }}v${{ env.VER_NAME }}
- path: artifacts${{ env.VER_CODE }}v${{ env.VER_NAME }}
+ name: app-release-${{ steps.tag_version.outputs.new_tag }}.apk
+ path: app/build/outputs/apk/release/app-release.apk
+ - name: Create a GitHub release
+ if: ${{ github.event_name == 'push' }}
+ id: create_release
+ uses: actions/create-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ steps.tag_version.outputs.full_tag }}
+ release_name: Nightly ${{ steps.tag_version.outputs.snapshot_date }} ${{ steps.tag_version.outputs.full_tag }}
+ prerelease: true
+ - name: Upload artifacts
+ if: ${{ github.event_name == 'push' }}
+ id: upload-artifacts
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: ./artifacts_${{ steps.tag_version.outputs.new_tag }}.zip
+ asset_name: artifacts_${{ steps.tag_version.outputs.new_tag }}.zip
+ asset_content_type: application/zip
+ - name: Upload APK
+ if: ${{ github.event_name == 'push' }}
+ id: upload-apk
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: ./app/build/outputs/apk/release/app-release.apk
+ asset_name: app-release-${{ steps.tag_version.outputs.new_tag }}.apk
+ asset_content_type: application/zip
diff --git a/.github/workflows/manual_release.yml b/.github/workflows/manual_release.yml
new file mode 100644
index 0000000..862c312
--- /dev/null
+++ b/.github/workflows/manual_release.yml
@@ -0,0 +1,82 @@
+name: Manual release
+
+on:
+ workflow_dispatch:
+ branches: [ master ]
+
+jobs:
+ build_and_release:
+ name: Build and release
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set version code to release
+ run: |
+ echo "$(grep 'version=' gradle.properties | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')" |\
+ xargs -I % sed -i 's/^version=.*$/version=%/' gradle.properties
+ - name: Create version and tag
+ id: tag_version
+ run: |
+ echo "::set-output name=new_tag::v$(grep 'version=' gradle.properties | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')" &&
+ echo "::set-output name=new_version::$(grep 'version=' gradle.properties | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')"
+ - name: Setup signing information
+ env:
+ KEY_FILE: ${{ secrets.signingKeyBase64 }}
+ run: echo "$KEY_FILE" | openssl base64 -d > signingKey.jks
+ - name: set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Build apk
+ env:
+ KEY_STORE_PWD: ${{ secrets.keyStorePassword }}
+ KEY_ALIAS: ${{ secrets.alias }}
+ KEY_PWD: ${{ secrets.keyPassword }}
+ run: |
+ ./gradlew signingReport &&
+ ./gradlew :app:assembleRelease --stacktrace
+ - name: Cleanup signing information
+ run: rm signingKey.jks
+ - name: Copy release apk and mapping
+ run: zip -r artifacts_${{ steps.tag_version.outputs.new_tag }}.zip app/build/outputs
+ - name: Export artifacts
+ uses: actions/upload-artifact@v1
+ with:
+ name: artifacts_${{ steps.tag_version.outputs.new_tag }}.zip
+ path: artifacts_${{ steps.tag_version.outputs.new_tag }}.zip
+ - name: Export APK
+ uses: actions/upload-artifact@v1
+ with:
+ name: KINTAMAnga-${{ steps.tag_version.outputs.new_tag }}.apk
+ path: app/build/outputs/apk/release/app-release.apk
+ - name: Create a GitHub release
+ id: create_release
+ uses: actions/create-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ steps.tag_version.outputs.new_tag }}
+ release_name: Release ${{ steps.tag_version.outputs.new_tag }}
+ prerelease: false
+ - name: Upload artifacts
+ id: upload-artifacts
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: ./artifacts_${{ steps.tag_version.outputs.new_tag }}.zip
+ asset_name: artifacts_${{ steps.tag_version.outputs.new_tag }}.zip
+ asset_content_type: application/zip
+ - name: Upload APK
+ id: upload-apk
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: ./app/build/outputs/apk/release/app-release.apk
+ asset_name: KINTAMAnga-${{ steps.tag_version.outputs.new_tag }}.apk
+ asset_content_type: application/zip
+
diff --git a/.gitignore b/.gitignore
index 5f45578..aabd240 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,8 @@
*.iml
.gradle
-/local.properties
-/.idea
+.idea
+.settings
+local.properties
.DS_Store
/build
/captures
diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
deleted file mode 100644
index 719bb8b..0000000
--- a/.idea/codeStyleSettings.xml
+++ /dev/null
@@ -1,228 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 96cc43e..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
deleted file mode 100644
index c7d1c5a..0000000
--- a/.idea/copyright/profiles_settings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/.idea/dictionaries/DucVu.xml b/.idea/dictionaries/DucVu.xml
deleted file mode 100644
index 8f2536c..0000000
--- a/.idea/dictionaries/DucVu.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
- favorited
- manga
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 5cd135a..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
deleted file mode 100644
index 1a5e326..0000000
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 6933c1e..0000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
deleted file mode 100644
index 3097f31..0000000
--- a/.idea/kotlinc.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index b5b015c..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index af03757..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 7f68460..0000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 750326c..b723b12 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,12 +1,16 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
-apply plugin: 'io.fabric'
android {
- compileSdkVersion 29
- buildToolsVersion '28.0.3'
+ compileSdkVersion 30
+ buildToolsVersion '30.0.3'
+ ndkVersion '22.0.6917172'
+ buildFeatures {
+ viewBinding true
+ dataBinding true
+ }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@@ -14,15 +18,12 @@ android {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
- dataBinding {
- enabled = true
- }
defaultConfig {
applicationId "io.github.innoobwetrust.kintamanga"
minSdkVersion 16
- targetSdkVersion 29
- versionCode 39
- versionName "1.3.11"
+ targetSdkVersion 30
+ versionCode buildVersionCode()
+ versionName version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@@ -65,7 +66,6 @@ kapt {
}
ext {
- firebaseVersion = '16.0.9'
// Dependency injection
kodeinVersion = '4.1.0'
glideVersion = '4.11.0'
@@ -73,29 +73,24 @@ ext {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
- testImplementation 'junit:junit:4.13'
- androidTestImplementation('androidx.test.espresso:espresso-core:3.2.0', {
+ testImplementation 'junit:junit:4.13.1'
+ androidTestImplementation('androidx.test.espresso:espresso-core:3.3.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'androidx.annotation:annotation:1.1.0'
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'com.google.android.material:material:1.1.0'
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
+ implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.multidex:multidex:2.0.1'
// Kotlin standard library
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- // Crash report
- implementation "com.google.firebase:firebase-core:$firebaseVersion"
- implementation('com.crashlytics.sdk.android:crashlytics:2.10.1@aar') {
- transitive = true
- }
-
// Logging
implementation 'com.jakewharton.timber:timber:4.7.1'
@@ -104,7 +99,7 @@ dependencies {
implementation "com.github.salomonbrys.kodein:kodein-conf:$kodeinVersion"
// Network
- implementation 'com.squareup.okhttp3:okhttp:4.5.0'
+ implementation 'com.squareup.okhttp3:okhttp:4.9.0'
// Persistent cookieJar
implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
@@ -116,14 +111,17 @@ dependencies {
implementation 'com.squareup.duktape:duktape-android:1.3.0'
// Image loading library focused on smooth scrolling
- implementation "com.github.bumptech.glide:glide:$glideVersion"
- implementation "com.github.bumptech.glide:annotations:$glideVersion"
- kapt "com.github.bumptech.glide:compiler:$glideVersion"
- implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion@aar"
+ implementation "com.github.bumptech.glide:glide:4.11.0"
+ implementation "com.github.bumptech.glide:annotations:4.11.0"
+ kapt "com.github.bumptech.glide:compiler:4.11.0"
+ implementation "com.github.bumptech.glide:okhttp3-integration:4.11.0@aar"
+ implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {
+ // Excludes the support library because it's already included by Glide.
+ transitive = false
+ }
// Image view
- implementation 'com.github.piasy:BigImageViewer:1.3.2'
- implementation 'com.github.piasy:ProgressPieIndicator:1.3.2'
+ implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
// ReactiveX
implementation 'io.reactivex:rxandroid:1.2.1'
@@ -141,8 +139,15 @@ dependencies {
// Database
implementation 'com.pushtorefresh.storio:sqlite:1.13.0'
}
-repositories {
- mavenCentral()
-}
-apply plugin: 'com.google.gms.google-services'
+configurations.all {
+ resolutionStrategy.eachDependency { DependencyResolveDetails details ->
+ def requested = details.requested
+ // Strange problem with AndroidX => https://stackoverflow.com/a/63423780
+ if (requested.group == "androidx.appcompat") {
+ if (!requested.name.startsWith("multidex")) {
+ details.useVersion "1.+"
+ }
+ }
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8f50954..166cff2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,6 +13,7 @@
-
-
+ tools:targetApi="q">
("headers") with factory { headers: Headers -> Interceptor { chain ->
+ chain.proceed(chain.request().run {
+ val withCustomHeaders = newBuilder()
+ headers.forEach{ withCustomHeaders.header(it.first, it.second) }
+ withCustomHeaders.build()
+ })
+ }}
bind() with singleton {
CacheControl.Builder()
.maxAge(5, TimeUnit.MINUTES)
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/download/DownloadProvider.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/download/DownloadProvider.kt
index 4066950..8fcdcf6 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/download/DownloadProvider.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/download/DownloadProvider.kt
@@ -1,5 +1,6 @@
package io.github.innoobwetrust.kintamanga.download
+import android.net.Uri
import io.github.innoobwetrust.kintamanga.model.DownloadStatus
import io.github.innoobwetrust.kintamanga.model.Page
import io.github.innoobwetrust.kintamanga.ui.model.MangaBinding
@@ -168,11 +169,11 @@ object DownloadProvider {
val images = findChapterImages(chapterDir = chapterDir)
?: throw Exception("Error occur when indexing offline chapter's images")
val tempMutableList = mutableListOf()
- var maxNum = images.maxBy { it.first }?.first ?: 1
+ var maxNum = images.maxByOrNull { it.first }?.first ?: 1
if (maxNum < 1) maxNum = 1
(1..maxNum).asSequence().map { index -> images.find { it.first == index } }.forEach {
if (null != it)
- tempMutableList.add("file://" + it.second.absolutePath)
+ tempMutableList.add(Uri.fromFile(it.second).toString())
else
tempMutableList.add("")
}
@@ -197,4 +198,4 @@ object DownloadProvider {
false
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/download/Downloader.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/download/Downloader.kt
index 9fd3f31..df7a841 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/download/Downloader.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/download/Downloader.kt
@@ -1,8 +1,8 @@
package io.github.innoobwetrust.kintamanga.download
import android.content.Context
+import android.net.Uri
import android.webkit.MimeTypeMap
-import com.crashlytics.android.Crashlytics
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
import com.github.salomonbrys.kodein.instance
import io.github.innoobwetrust.kintamanga.database.DatabaseHelper
@@ -18,6 +18,7 @@ import io.github.innoobwetrust.kintamanga.util.ImageConverter
import io.github.innoobwetrust.kintamanga.util.RetryWithDelay
import io.github.innoobwetrust.kintamanga.util.Storage
import io.github.innoobwetrust.kintamanga.util.extension.*
+import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Response
import rx.Observable
@@ -85,7 +86,6 @@ class Downloader(private val context: Context) : KodeinGlobalAware {
},
{ error ->
Timber.e(error)
- Crashlytics.logException(error)
})
}
@@ -131,7 +131,6 @@ class Downloader(private val context: Context) : KodeinGlobalAware {
{ error ->
DownloadService.stop(context)
Timber.e(error)
- Crashlytics.logException(error)
notifier.onError(error.message)
}
)
@@ -335,7 +334,7 @@ class Downloader(private val context: Context) : KodeinGlobalAware {
.getChapterInfoProcessorForSourceName(download.manga.mangaSourceName)
?.fetchPageList(download.chapter)
?: throw Exception("Error retrieving processor or fetching page list with source:" +
- " ${download.manga.mangaSourceName}")
+ " ${download.manga.mangaSourceName}")
}.doOnNext { pages ->
if (pages.isEmpty()) {
throw Exception("Page list is empty")
@@ -359,9 +358,18 @@ class Downloader(private val context: Context) : KodeinGlobalAware {
.flatMap { Observable.from(it) }
// Start downloading images, consider we can have downloaded images already
.concatMap { page ->
+ // Adding custom headers to requests
+ val headers = SourceManager
+ .getChapterInfoProcessorForSourceName(download.manga.mangaSourceName)?.headers()
// Allow pausing individual download by changing the download's status
if (DownloadStatus.DOWNLOADING == download.downloadStatus)
- getOrDownloadImage(page, download, tmpDir)
+ getOrDownloadImage(
+ page,
+ download,
+ tmpDir,
+ SourceManager.getChapterInfoProcessorForSourceName(download.manga.mangaSourceName)?.headers()
+ ?: instance()
+ )
else
Observable.just(page)
}
@@ -388,7 +396,7 @@ class Downloader(private val context: Context) : KodeinGlobalAware {
* @param download the download of the page.
* @param tmpDir the temporary directory of the download.
*/
- private fun getOrDownloadImage(page: Page, download: Download, tmpDir: File): Observable {
+ private fun getOrDownloadImage(page: Page, download: Download, tmpDir: File, headers: Headers): Observable {
// If the image URL is empty, do nothing
if (page.imageUrls.all { it.isBlank() })
return Observable.just(page)
@@ -406,12 +414,12 @@ class Downloader(private val context: Context) : KodeinGlobalAware {
val pageObservable = if (null != imageFile)
Observable.just(imageFile)
else
- downloadImage(page, tmpDir, filename)
+ downloadImage(page, tmpDir, filename, headers)
return pageObservable
// When the image is ready, set image path, progress (just in case) and status
.doOnNext { file ->
- page.imageFileUri = "file://" + file.absolutePath
+ page.imageFileUri = Uri.fromFile(file).toString()
download.downloadedImages++
page.pageStatus = DownloadStatus.DOWNLOADED
}
@@ -430,13 +438,13 @@ class Downloader(private val context: Context) : KodeinGlobalAware {
* @param tmpDir the temporary directory of the download.
* @param filename the filename of the image.
*/
- private fun downloadImage(page: Page, tmpDir: File, filename: String): Observable {
+ private fun downloadImage(page: Page, tmpDir: File, filename: String, headers: Headers): Observable {
page.pageStatus = DownloadStatus.DOWNLOADING
return Observable
.from(
page.imageUrls.map {
instance("chapter")
- .newCall(GET(it))
+ .newCall(GET(it, headers = headers))
.asObservableSuccess()
}
)
@@ -453,8 +461,8 @@ class Downloader(private val context: Context) : KodeinGlobalAware {
}
var extension = getImageExtension(response, file)
if (ImageConverter.convertRequiredImageTypes
- .map { imgType -> imgType.substringAfter("image/") }
- .contains(extension)) {
+ .map { imgType -> imgType.substringAfter("image/") }
+ .contains(extension)) {
extension = "png"
ImageConverter.convertToSupportedImage(file)
}
@@ -484,7 +492,7 @@ class Downloader(private val context: Context) : KodeinGlobalAware {
private fun getImageExtension(response: Response, file: File): String {
// Read content type if available.
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.getUriCompat(context))
// Else read magic numbers.
?: ImageConverter.findImageMime { file.inputStream() }
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/model/Page.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/model/Page.kt
index 7cf292c..5d687f3 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/model/Page.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/model/Page.kt
@@ -10,7 +10,7 @@ class Page(
var chapterIndex: Int = -1,
val pageIndex: Int,
var imageUrls: List = listOf(""),
- var imageFileUri: String = ""
+ var imageFileUri: String = "",
) : BaseObservable(), Serializable {
init {
@@ -18,14 +18,17 @@ class Page(
}
@get:Bindable
- @Transient @Volatile var pageStatus: DownloadStatus = DownloadStatus.NOT_DOWNLOADED
+ @Transient
+ @Volatile
+ var pageStatus: DownloadStatus = DownloadStatus.NOT_DOWNLOADED
set(value) {
field = value
statusSubject?.onNext(value)
notifyPropertyChanged(BR.pageStatus)
}
- @Transient private var statusSubject: PublishSubject? = null
+ @Transient
+ private var statusSubject: PublishSubject? = null
fun setStatusSubject(subject: PublishSubject?) {
this.statusSubject = subject
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/service/DownloadService.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/service/DownloadService.kt
index b3b2bbb..c3a961f 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/service/DownloadService.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/service/DownloadService.kt
@@ -8,7 +8,6 @@ import android.net.NetworkInfo.State.DISCONNECTED
import android.os.IBinder
import android.os.PowerManager
import android.widget.Toast
-import com.crashlytics.android.Crashlytics
import com.github.pwittchen.reactivenetwork.library.Connectivity
import com.github.pwittchen.reactivenetwork.library.ReactiveNetwork
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
@@ -123,7 +122,6 @@ class DownloadService : Service(), KodeinGlobalAware {
}, { error ->
toast(R.string.download_service_error, Toast.LENGTH_LONG)
Timber.e(error)
- Crashlytics.logException(error)
stopSelf()
})
)
@@ -176,4 +174,4 @@ class DownloadService : Service(), KodeinGlobalAware {
private fun PowerManager.WakeLock.acquireIfNeeded() {
if (!isHeld) acquire(1800000)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/SourceManager.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/SourceManager.kt
index e8585fd..245a94a 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/SourceManager.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/SourceManager.kt
@@ -32,7 +32,7 @@ object SourceManager {
fun normalizeUri(uri: Uri): String? {
val sourceName = findFirstSourceNameForHost(host = uri.host) ?: return null
val source = getSourceByName(sourceName = sourceName) ?: return null
- val uriString = uri.toString().let { if (!it.isBlank() && it.last() != '/') "$it/" else it }
+ val uriString = uri.toString().let { if (it.isNotBlank() && it.last() != '/') "$it/" else it }
return uriString.replaceFirst(source.aliasRootUri, source.rootUri)
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/dom/parser/DomSegmentParser.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/dom/parser/DomSegmentParser.kt
index 19ee53b..2156973 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/dom/parser/DomSegmentParser.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/dom/parser/DomSegmentParser.kt
@@ -50,12 +50,12 @@ interface DomSegmentParser {
}
fun previousPageUriFromDocument(document: Document): String =
- if (!previousPageSelector.isBlank())
+ if (previousPageSelector.isNotBlank())
document.parseUri(selector = previousPageSelector, attribute = "href")
else ""
fun nextPageUriFromDocument(document: Document): String =
- if (!nextPageSelector.isBlank())
+ if (nextPageSelector.isNotBlank())
document.parseUri(selector = nextPageSelector, attribute = "href")
else ""
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/en/mangahere/MangaHereMangaInfoProcessor.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/en/mangahere/MangaHereMangaInfoProcessor.kt
index 4888114..d5a4e9a 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/en/mangahere/MangaHereMangaInfoProcessor.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/en/mangahere/MangaHereMangaInfoProcessor.kt
@@ -51,7 +51,7 @@ object MangaHereMangaInfoProcessor : DomMangaInfoProcessor {
override fun headers(): Headers = instance()
override fun cacheControl(): CacheControl = instance()
- override fun mangaFromDocument(document: Document): MangaBinding? = MangaBinding().apply {
+ override fun mangaFromDocument(document: Document): MangaBinding = MangaBinding().apply {
mangaSourceName = source.sourceName
mangaUri = document.baseUri()
mangaTitle = titleFromDocument(document)
@@ -105,4 +105,4 @@ object MangaHereMangaInfoProcessor : DomMangaInfoProcessor {
}
}.sortedBy { it.chapterIndex }
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/AllSegment.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/AllSegment.kt
index a49fb8a..34aeb73 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/AllSegment.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/AllSegment.kt
@@ -34,7 +34,7 @@ object AllSegment : DomSegment {
override var isUsable: Boolean = true
override var isRequestByGET: Boolean = true
- override fun headers(): Headers = instance()
+ override fun headers(): Headers = instance().newBuilder().add("Referer", source.rootUri).build()
override fun cacheControl(): CacheControl = instance()
override var urisSelector: String = ".table.table-hover>tbody>tr>td:nth-child(1)>a"
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/HocVienTruyenTranhChapterInfoProcessor.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/HocVienTruyenTranhChapterInfoProcessor.kt
index d6134a9..46e041f 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/HocVienTruyenTranhChapterInfoProcessor.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/HocVienTruyenTranhChapterInfoProcessor.kt
@@ -11,6 +11,6 @@ object HocVienTruyenTranhChapterInfoProcessor : DomChapterInfoProcessor {
override var imagesUriSelector: String = ".manga-container>img"
override var imagesUriAttribute: String = "src"
- override fun headers(): Headers = instance()
+ override fun headers(): Headers = instance().newBuilder().add("Referer", source.rootUri).build()
override fun cacheControl(): CacheControl = instance()
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/HocVienTruyenTranhMangaInfoProcessor.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/HocVienTruyenTranhMangaInfoProcessor.kt
index 0bdd4b3..b5da237 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/HocVienTruyenTranhMangaInfoProcessor.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/hocvientruyentranh/HocVienTruyenTranhMangaInfoProcessor.kt
@@ -44,10 +44,10 @@ object HocVienTruyenTranhMangaInfoProcessor : DomMangaInfoProcessor {
override var chaptersUpdateTimeAttribute: String = "text"
override var chaptersIndexedDescending: Boolean = true
- override fun headers(): Headers = instance()
+ override fun headers(): Headers = instance().newBuilder().add("Referer", source.rootUri).build()
override fun cacheControl(): CacheControl = instance()
- override fun mangaFromDocument(document: Document): MangaBinding? = MangaBinding().apply {
+ override fun mangaFromDocument(document: Document): MangaBinding = MangaBinding().apply {
mangaSourceName = source.sourceName
mangaUri = document.baseUri()
mangaTitle = titleFromDocument(document)
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/truyentranhtuan/TruyenTranhTuanMangaInfoProcessor.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/truyentranhtuan/TruyenTranhTuanMangaInfoProcessor.kt
index 02004d9..a7d68c0 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/truyentranhtuan/TruyenTranhTuanMangaInfoProcessor.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/source/instance/vi/truyentranhtuan/TruyenTranhTuanMangaInfoProcessor.kt
@@ -47,7 +47,7 @@ object TruyenTranhTuanMangaInfoProcessor : DomMangaInfoProcessor {
override fun headers(): Headers = instance()
override fun cacheControl(): CacheControl = instance()
- override fun mangaFromDocument(document: Document): MangaBinding? = MangaBinding().apply {
+ override fun mangaFromDocument(document: Document): MangaBinding = MangaBinding().apply {
mangaSourceName = source.sourceName
mangaUri = document.baseUri()
mangaTitle = titleFromDocument(document)
@@ -63,4 +63,4 @@ object TruyenTranhTuanMangaInfoProcessor : DomMangaInfoProcessor {
mangaWarning = warningFromDocument(document)
chapters = chaptersFromDocument(document)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/downloader/DownloadAdapter.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/downloader/DownloadAdapter.kt
index 117d47c..8fb58a8 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/downloader/DownloadAdapter.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/downloader/DownloadAdapter.kt
@@ -2,10 +2,7 @@ package io.github.innoobwetrust.kintamanga.ui.downloader
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
-import android.view.View
import android.view.ViewGroup
-import androidx.appcompat.widget.AppCompatImageButton
-import androidx.appcompat.widget.AppCompatTextView
import androidx.appcompat.widget.PopupMenu
import androidx.recyclerview.widget.RecyclerView
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
@@ -15,7 +12,6 @@ import io.github.innoobwetrust.kintamanga.databinding.HolderDownloadBinding
import io.github.innoobwetrust.kintamanga.download.Downloader
import io.github.innoobwetrust.kintamanga.model.Download
import io.github.innoobwetrust.kintamanga.model.DownloadStatus
-import kotlinx.android.synthetic.main.holder_download.view.*
class DownloadAdapter(
private var downloaderActivity: DownloaderActivity?
@@ -48,55 +44,57 @@ class DownloadAdapter(
val download = downloads?.getOrNull(position)
holder.bind(download)
download?.let {
- holder.mangaTitle.isSelected = true
- holder.downloadStatus.isSelected = true
- holder.chapterTitle.isSelected = true
- holder.downloadProgressText.isSelected = true
- holder.downloadOption.setOnClickListener {
- val downloadItemOption =
- PopupMenu(contextWrapper!!, holder.downloadOption)
- downloadItemOption.inflate(R.menu.menu_download_item)
- downloadItemOption.menu.apply {
- // Set start button visibility.
- findItem(R.id.download_item_option_resume)?.isVisible =
- download.downloadStatus == DownloadStatus.STOPPED
- // Set pause button visibility.
- findItem(R.id.download_item_option_stop)?.isVisible =
- download.downloadStatus in listOf(DownloadStatus.DOWNLOADING, DownloadStatus.QUEUE)
- }
- downloadItemOption.setOnMenuItemClickListener { item ->
- when (item.itemId) {
- R.id.download_item_option_resume -> {
- if (downloads?.getOrNull(holder.adapterPosition)
- ?.let(instance()::resume) == true) {
- notifyItemChanged(holder.adapterPosition)
- return@setOnMenuItemClickListener true
+ holder.binding.apply {
+ mangaTitle.isSelected = true
+ downloadStatus.isSelected = true
+ chapterTitle.isSelected = true
+ downloadProgressText.isSelected = true
+ downloadOption.setOnClickListener {
+ val downloadItemOption =
+ PopupMenu(contextWrapper!!, downloadOption)
+ downloadItemOption.inflate(R.menu.menu_download_item)
+ downloadItemOption.menu.apply {
+ // Set start button visibility.
+ findItem(R.id.download_item_option_resume)?.isVisible =
+ download.downloadStatus == DownloadStatus.STOPPED
+ // Set pause button visibility.
+ findItem(R.id.download_item_option_stop)?.isVisible =
+ download.downloadStatus in listOf(DownloadStatus.DOWNLOADING, DownloadStatus.QUEUE)
+ }
+ downloadItemOption.setOnMenuItemClickListener { item ->
+ when (item.itemId) {
+ R.id.download_item_option_resume -> {
+ if (downloads?.getOrNull(holder.adapterPosition)
+ ?.let(instance()::resume) == true) {
+ notifyItemChanged(holder.adapterPosition)
+ return@setOnMenuItemClickListener true
+ }
}
- }
- R.id.download_item_option_stop -> {
- if (downloads?.getOrNull(holder.adapterPosition)
- ?.let(instance()::stop) == true) {
- notifyItemChanged(holder.adapterPosition)
- return@setOnMenuItemClickListener true
+ R.id.download_item_option_stop -> {
+ if (downloads?.getOrNull(holder.adapterPosition)
+ ?.let(instance()::stop) == true) {
+ notifyItemChanged(holder.adapterPosition)
+ return@setOnMenuItemClickListener true
+ }
}
- }
- R.id.download_item_option_remove -> {
- if (downloads?.getOrNull(holder.adapterPosition)
- ?.let(instance()::remove) == true) {
- notifyItemRemoved(holder.adapterPosition)
- return@setOnMenuItemClickListener true
+ R.id.download_item_option_remove -> {
+ if (downloads?.getOrNull(holder.adapterPosition)
+ ?.let(instance()::remove) == true) {
+ notifyItemRemoved(holder.adapterPosition)
+ return@setOnMenuItemClickListener true
+ }
}
}
+ return@setOnMenuItemClickListener false
}
- return@setOnMenuItemClickListener false
+ downloadItemOption.show()
}
- downloadItemOption.show()
}
}
}
override fun onViewRecycled(holder: ViewHolder) {
- holder.downloadOption.setOnClickListener(null)
+ holder.binding.downloadOption.setOnClickListener(null)
holder.bind(null)
System.gc()
super.onViewRecycled(holder)
@@ -117,19 +115,6 @@ class DownloadAdapter(
inner class ViewHolder(
val binding: HolderDownloadBinding
) : RecyclerView.ViewHolder(binding.root) {
- val root: View
- get() = binding.root
- val mangaTitle: AppCompatTextView
- get() = binding.root.mangaTitle
- val downloadStatus: AppCompatTextView
- get() = binding.root.downloadStatus
- val chapterTitle: AppCompatTextView
- get() = binding.root.chapterTitle
- val downloadProgressText: AppCompatTextView
- get() = binding.root.downloadProgressText
- val downloadOption: AppCompatImageButton
- get() = binding.root.downloadOption
-
fun bind(download: Download?) {
binding.download = download
binding.executePendingBindings()
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/downloader/DownloaderActivity.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/downloader/DownloaderActivity.kt
index 9305e98..90eda52 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/downloader/DownloaderActivity.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/downloader/DownloaderActivity.kt
@@ -8,9 +8,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
import com.github.salomonbrys.kodein.instance
import io.github.innoobwetrust.kintamanga.R
+import io.github.innoobwetrust.kintamanga.databinding.ActivityDownloaderBinding
import io.github.innoobwetrust.kintamanga.download.Downloader
import io.github.innoobwetrust.kintamanga.service.DownloadService
-import kotlinx.android.synthetic.main.activity_downloader.*
import rx.android.schedulers.AndroidSchedulers
import rx.subscriptions.CompositeSubscription
@@ -24,16 +24,18 @@ class DownloaderActivity : AppCompatActivity(), KodeinGlobalAware {
* Whether the download queue is running or not.
*/
private var isRunning: Boolean = false
+ private lateinit var binding: ActivityDownloaderBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_downloader)
- setSupportActionBar(toolbar)
+ binding = ActivityDownloaderBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setSupportActionBar(binding.toolbar)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setDisplayShowHomeEnabled(true)
}
- downloadList?.apply {
+ binding.downloadList.apply {
layoutManager = LinearLayoutManager(this@DownloaderActivity)
adapter = DownloadAdapter(this@DownloaderActivity)
}
@@ -44,7 +46,7 @@ class DownloaderActivity : AppCompatActivity(), KodeinGlobalAware {
)
subscriptions.add(instance().queue.getUpdatedObservable()
.observeOn(AndroidSchedulers.mainThread())
- .subscribe { downloadList?.adapter?.notifyDataSetChanged() }
+ .subscribe { binding.downloadList.adapter?.notifyDataSetChanged() }
)
}
@@ -67,8 +69,7 @@ class DownloaderActivity : AppCompatActivity(), KodeinGlobalAware {
return true
}
- override fun onOptionsItemSelected(item: MenuItem?): Boolean {
- if (null == item) return false
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.downloader_start -> {
DownloadService.start(this)
@@ -87,7 +88,7 @@ class DownloaderActivity : AppCompatActivity(), KodeinGlobalAware {
R.id.downloader_stop,
R.id.downloader_remove_all
) -> return true.also {
- downloadList?.adapter?.notifyDataSetChanged()
+ binding.downloadList.adapter?.notifyDataSetChanged()
}
}
return false
@@ -99,7 +100,7 @@ class DownloaderActivity : AppCompatActivity(), KodeinGlobalAware {
}
override fun onStop() {
- downloadList?.adapter = null
+ binding.downloadList.adapter = null
super.onStop()
}
@@ -116,6 +117,6 @@ class DownloaderActivity : AppCompatActivity(), KodeinGlobalAware {
private fun onQueueStatusChange(running: Boolean) {
isRunning = running
invalidateOptionsMenu()
- downloadList?.adapter?.notifyDataSetChanged()
+ binding.downloadList.adapter?.notifyDataSetChanged()
}
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterActivity.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterActivity.kt
index 6079d72..5c1161a 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterActivity.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterActivity.kt
@@ -6,17 +6,16 @@ import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
-import com.crashlytics.android.Crashlytics
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
import com.github.salomonbrys.kodein.instance
import com.github.salomonbrys.kotson.fromJson
import com.github.salomonbrys.kotson.typedToJson
import com.google.gson.Gson
import io.github.innoobwetrust.kintamanga.R
+import io.github.innoobwetrust.kintamanga.databinding.ActivityFilterBinding
import io.github.innoobwetrust.kintamanga.source.model.SourceSegment
import io.github.innoobwetrust.kintamanga.ui.main.list.MangaListFragment
import io.github.innoobwetrust.kintamanga.util.extension.toast
-import kotlinx.android.synthetic.main.activity_filter.*
import rx.Subscription
import timber.log.Timber
@@ -32,11 +31,13 @@ class FilterActivity : AppCompatActivity(), KodeinGlobalAware, FilterNetworkLoad
private lateinit var userInput: MutableMap
private lateinit var singleChoice: MutableMap
private lateinit var multipleChoices: MutableSet>
+ private lateinit var binding: ActivityFilterBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_filter)
- setSupportActionBar(toolbar)
+ binding = ActivityFilterBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setSupportActionBar(binding.toolbar)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setDisplayShowHomeEnabled(true)
@@ -46,19 +47,19 @@ class FilterActivity : AppCompatActivity(), KodeinGlobalAware, FilterNetworkLoad
userInput = gson.fromJson(
intent.getStringExtra(
MangaListFragment.Companion.Intents.USER_INPUT.key
- )
+ ) ?: ""
)
singleChoice =
gson.fromJson(
intent.getStringExtra(
MangaListFragment.Companion.Intents.SINGLE_CHOICE.key
- )
+ ) ?: ""
)
multipleChoices =
gson.fromJson(
intent.getStringExtra(
MangaListFragment.Companion.Intents.MULTIPLE_CHOICES.key
- )
+ ) ?: ""
)
}
@@ -87,9 +88,9 @@ class FilterActivity : AppCompatActivity(), KodeinGlobalAware, FilterNetworkLoad
}
private val onRefreshedFilterData: (Boolean) -> Unit = { success ->
- progress?.visibility = View.GONE
+ binding.progress.visibility = View.GONE
if (success) {
- filterButton?.setOnClickListener {
+ binding.filterButton.setOnClickListener {
val resultIntent = Intent()
.putExtra(
MangaListFragment.Companion.Intents.USER_INPUT.key,
@@ -107,8 +108,8 @@ class FilterActivity : AppCompatActivity(), KodeinGlobalAware, FilterNetworkLoad
finish()
}
if (mangaSegment.filterByUserInput.isNotEmpty()) {
- userInputRecyclerView?.visibility = View.VISIBLE
- userInputRecyclerView?.apply {
+ binding.userInputRecyclerView.visibility = View.VISIBLE
+ binding.userInputRecyclerView.apply {
layoutManager = LinearLayoutManager(this@FilterActivity)
adapter = FilterUserInputAdapter(
userInput = this@FilterActivity.userInput,
@@ -118,11 +119,11 @@ class FilterActivity : AppCompatActivity(), KodeinGlobalAware, FilterNetworkLoad
mangaSegment.filterRequiredDefaultUserInput
)
}
- userInputRecyclerView?.isNestedScrollingEnabled = false
+ binding.userInputRecyclerView.isNestedScrollingEnabled = false
}
if (mangaSegment.filterBySingleChoice.isNotEmpty()) {
- singleChoiceRecyclerView?.visibility = View.VISIBLE
- singleChoiceRecyclerView?.apply {
+ binding.singleChoiceRecyclerView.visibility = View.VISIBLE
+ binding.singleChoiceRecyclerView.apply {
layoutManager = LinearLayoutManager(this@FilterActivity)
adapter = FilterSingleChoiceAdapter(
singleChoice = this@FilterActivity.singleChoice,
@@ -132,11 +133,11 @@ class FilterActivity : AppCompatActivity(), KodeinGlobalAware, FilterNetworkLoad
mangaSegment.filterRequiredDefaultSingleChoice
)
}
- singleChoiceRecyclerView?.isNestedScrollingEnabled = false
+ binding.singleChoiceRecyclerView.isNestedScrollingEnabled = false
}
if (mangaSegment.filterByMultipleChoices.isNotEmpty()) {
- multipleChoicesRecyclerView?.visibility = View.VISIBLE
- multipleChoicesRecyclerView?.apply {
+ binding.multipleChoicesRecyclerView.visibility = View.VISIBLE
+ binding.multipleChoicesRecyclerView.apply {
layoutManager = LinearLayoutManager(this@FilterActivity)
adapter = FilterMultipleChoicesAdapter(
multipleChoices = multipleChoices,
@@ -144,39 +145,38 @@ class FilterActivity : AppCompatActivity(), KodeinGlobalAware, FilterNetworkLoad
filterByMultipleChoices = mangaSegment.filterByMultipleChoices
)
}
- multipleChoicesRecyclerView?.isNestedScrollingEnabled = false
+ binding.multipleChoicesRecyclerView.isNestedScrollingEnabled = false
}
} else {
- filterButton?.visibility = View.GONE
+ binding.filterButton.visibility = View.GONE
toast(R.string.filter_activity_load_filter_error_text)
}
- resetButton?.setOnClickListener {
- userInputRecyclerView?.apply {
+ binding.resetButton.setOnClickListener {
+ binding.userInputRecyclerView.apply {
mangaSegment.filterByUserInput.forEachIndexed { index, _ ->
(findViewHolderForAdapterPosition(index)
as? FilterUserInputAdapter.ViewHolder)?.reset()
}
}
- singleChoiceRecyclerView?.apply {
+ binding.singleChoiceRecyclerView.apply {
mangaSegment.filterBySingleChoice.toList().forEachIndexed { index, _ ->
(findViewHolderForAdapterPosition(index)
as? FilterSingleChoiceAdapter.ViewHolder)?.reset()
}
}
- multipleChoicesRecyclerView?.apply {
+ binding.multipleChoicesRecyclerView.apply {
mangaSegment.filterByMultipleChoices.toList().forEachIndexed { index, _ ->
(findViewHolderForAdapterPosition(index)
as? FilterMultipleChoicesAdapter.ViewHolder)?.reset()
}
}
}
- cancelButton?.setOnClickListener { onBackPressed() }
- progress?.visibility = View.GONE
+ binding.cancelButton.setOnClickListener { onBackPressed() }
+ binding.progress.visibility = View.GONE
}
private val onRefreshError: (Throwable) -> Unit = { error ->
toast(R.string.filter_activity_load_filter_error_text)
Timber.e(error)
- Crashlytics.logException(error)
}
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterMultipleChoicesAdapter.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterMultipleChoicesAdapter.kt
index 2cc8849..08837e9 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterMultipleChoicesAdapter.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterMultipleChoicesAdapter.kt
@@ -1,14 +1,11 @@
package io.github.innoobwetrust.kintamanga.ui.filter
import android.view.LayoutInflater
-import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
-import android.widget.LinearLayout
-import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import io.github.innoobwetrust.kintamanga.R
-import kotlinx.android.synthetic.main.holder_filter_multiple_choices.view.*
+import io.github.innoobwetrust.kintamanga.databinding.HolderFilterMultipleChoicesBinding
class FilterMultipleChoicesAdapter(
private val multipleChoices: MutableSet>,
@@ -20,9 +17,8 @@ class FilterMultipleChoicesAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
- return ViewHolder(
- layoutInflater.inflate(R.layout.holder_filter_multiple_choices, parent, false)
- )
+ val binding = HolderFilterMultipleChoicesBinding.inflate(layoutInflater, parent, false)
+ return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@@ -39,11 +35,7 @@ class FilterMultipleChoicesAdapter(
return filterList.size
}
- inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
- private val multipleChoicesOptionLabel: AppCompatTextView =
- view.multipleChoicesOption.multipleChoicesOptionLabel
- private val multipleChoicesOptionValues: LinearLayout =
- view.multipleChoicesOption.multipleChoicesOptionValues
+ inner class ViewHolder(val binding: HolderFilterMultipleChoicesBinding) : RecyclerView.ViewHolder(binding.root) {
private lateinit var dataList: List>
private var checkboxList: MutableList = mutableListOf()
private var key: String = ""
@@ -55,9 +47,9 @@ class FilterMultipleChoicesAdapter(
multipleChoices: MutableSet>
) {
this.key = key
- multipleChoicesOptionLabel.text = label
+ binding.multipleChoicesOptionLabel.text = label
dataList = dataMap.toList()
- multipleChoicesOptionValues.let { linearLayout ->
+ binding.multipleChoicesOptionValues.let { linearLayout ->
dataList.forEach { (label, value) ->
val inflater = LayoutInflater.from(linearLayout.context)
val checkBox = inflater.inflate(
@@ -85,7 +77,7 @@ class FilterMultipleChoicesAdapter(
}
override fun toString(): String {
- return super.toString() + multipleChoicesOptionLabel.text
+ return super.toString() + binding.multipleChoicesOptionLabel.text
}
}
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterSingleChoiceAdapter.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterSingleChoiceAdapter.kt
index 70a2ad4..cc937d9 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterSingleChoiceAdapter.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterSingleChoiceAdapter.kt
@@ -5,11 +5,9 @@ import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
-import androidx.appcompat.widget.AppCompatSpinner
-import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import io.github.innoobwetrust.kintamanga.R
-import kotlinx.android.synthetic.main.holder_filter_single_choice.view.*
+import io.github.innoobwetrust.kintamanga.databinding.HolderFilterSingleChoiceBinding
class FilterSingleChoiceAdapter(
private val singleChoice: MutableMap,
@@ -21,7 +19,8 @@ class FilterSingleChoiceAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
- return ViewHolder(layoutInflater.inflate(R.layout.holder_filter_single_choice, parent, false))
+ val binding = HolderFilterSingleChoiceBinding.inflate(layoutInflater, parent, false)
+ return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@@ -32,7 +31,7 @@ class FilterSingleChoiceAdapter(
dataMap = filterList[position].second,
defaultMap = filterRequiredDefaultSingleChoice
)
- holder.singleChoiceOption.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ holder.binding.singleChoiceOption.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
@@ -51,18 +50,14 @@ class FilterSingleChoiceAdapter(
else -> indexOf(singleChoice[key])
}
}
- if (defaultIndex >= 0) holder.singleChoiceOption.setSelection(defaultIndex)
+ if (defaultIndex >= 0) holder.binding.singleChoiceOption.setSelection(defaultIndex)
}
override fun getItemCount(): Int {
return filterList.size
}
- inner class ViewHolder(var view: View) : RecyclerView.ViewHolder(view) {
- private val singleChoiceLabel: AppCompatTextView
- get() = view.singleChoiceLabel
- val singleChoiceOption: AppCompatSpinner
- get() = view.singleChoiceOption
+ inner class ViewHolder(val binding: HolderFilterSingleChoiceBinding) : RecyclerView.ViewHolder(binding.root) {
// List pair of label-value
lateinit var dataList: List>
private lateinit var defaultMap: Map
@@ -75,14 +70,14 @@ class FilterSingleChoiceAdapter(
defaultMap: Map
) {
this.key = key
- singleChoiceLabel.text = label
+ binding.singleChoiceLabel.text = label
dataList = dataMap.toList()
val singleChoiceDataAdapter: ArrayAdapter = ArrayAdapter(
- view.context,
+ binding.root.context,
R.layout.themed_spinner_item,
dataList.map { it.first }
).also { it.setDropDownViewResource(R.layout.themed_spinner_dropdown_item) }
- singleChoiceOption.adapter = singleChoiceDataAdapter
+ binding.singleChoiceOption.adapter = singleChoiceDataAdapter
this.defaultMap = defaultMap
}
@@ -90,11 +85,11 @@ class FilterSingleChoiceAdapter(
val defaultIndex = dataList
.map { it.second }
.indexOf(defaultMap[key])
- if (defaultIndex >= 0) singleChoiceOption.setSelection(defaultIndex)
+ if (defaultIndex >= 0) binding.singleChoiceOption.setSelection(defaultIndex)
}
override fun toString(): String {
- return super.toString() + singleChoiceLabel.text
+ return super.toString() + binding.singleChoiceLabel.text
}
}
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterUserInputAdapter.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterUserInputAdapter.kt
index 264b8d3..9599b70 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterUserInputAdapter.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/filter/FilterUserInputAdapter.kt
@@ -3,13 +3,9 @@ package io.github.innoobwetrust.kintamanga.ui.filter
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
-import android.view.View
import android.view.ViewGroup
-import androidx.appcompat.widget.AppCompatEditText
-import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
-import io.github.innoobwetrust.kintamanga.R
-import kotlinx.android.synthetic.main.holder_filter_user_input.view.*
+import io.github.innoobwetrust.kintamanga.databinding.HolderFilterUserInputBinding
class FilterUserInputAdapter(
private val userInput: MutableMap,
@@ -20,7 +16,8 @@ class FilterUserInputAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
- return ViewHolder(layoutInflater.inflate(R.layout.holder_filter_user_input, parent, false))
+ val binding = HolderFilterUserInputBinding.inflate(layoutInflater, parent, false)
+ return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@@ -30,7 +27,7 @@ class FilterUserInputAdapter(
label = filterKeyLabel[key] ?: key,
inputValue = userInput[key]
)
- holder.userInputInput.addTextChangedListener(object : TextWatcher {
+ holder.binding.userInputInput.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
@@ -43,28 +40,26 @@ class FilterUserInputAdapter(
return filterByUserInput.size
}
- inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
- private var userInputLabel: AppCompatTextView = view.userInputLabel
- var userInputInput: AppCompatEditText = view.userInputInput
+ inner class ViewHolder(val binding: HolderFilterUserInputBinding) : RecyclerView.ViewHolder(binding.root) {
lateinit var key: String
fun bind(key: String, label: String, inputValue: String?) {
this.key = key
- userInputLabel.text = label
+ binding.userInputLabel.text = label
val defaultInputValue = inputValue ?: filterRequiredDefaultUserInput[label]
- if (null != defaultInputValue) userInputInput.text =
+ if (null != defaultInputValue) binding.userInputInput.text =
Editable.Factory.getInstance().newEditable(defaultInputValue)
}
fun reset() {
val defaultInputValue = filterRequiredDefaultUserInput[key]
- if (null != defaultInputValue) userInputInput.text =
+ if (null != defaultInputValue) binding.userInputInput.text =
Editable.Factory.getInstance().newEditable(defaultInputValue)
- else userInputInput.text = Editable.Factory.getInstance().newEditable("")
+ else binding.userInputInput.text = Editable.Factory.getInstance().newEditable("")
}
override fun toString(): String {
- return super.toString() + userInputLabel.text
+ return super.toString() + binding.userInputLabel.text
}
}
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/MainActivity.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/MainActivity.kt
index f4d6850..9c22a85 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/MainActivity.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/MainActivity.kt
@@ -15,11 +15,10 @@ import com.github.salomonbrys.kodein.instance
import com.google.android.material.navigation.NavigationView
import io.github.innoobwetrust.kintamanga.KINTAMAngaPreferences
import io.github.innoobwetrust.kintamanga.R
+import io.github.innoobwetrust.kintamanga.databinding.ActivityMainBinding
import io.github.innoobwetrust.kintamanga.ui.downloader.DownloaderActivity
import io.github.innoobwetrust.kintamanga.ui.main.favorite.FavoriteFragment
import io.github.innoobwetrust.kintamanga.ui.main.list.MangaListFragment
-import kotlinx.android.synthetic.main.activity_main.*
-import kotlinx.android.synthetic.main.content_main.*
class MainActivity :
AppCompatActivity(),
@@ -36,22 +35,24 @@ class MainActivity :
}
private var currentFragmentIndex: Int = 0
+ lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- setSupportActionBar(toolbar)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setSupportActionBar(binding.contentMain.toolbar)
val toggle = ActionBarDrawerToggle(
this,
- drawer_layout,
- toolbar,
+ binding.drawerLayout,
+ binding.contentMain.toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
)
- drawer_layout.addDrawerListener(toggle)
+ binding.drawerLayout.addDrawerListener(toggle)
toggle.syncState()
- nav_view.setNavigationItemSelectedListener(this)
+ binding.navView.setNavigationItemSelectedListener(this)
}
override fun onPostCreate(savedInstanceState: Bundle?) {
@@ -64,7 +65,7 @@ class MainActivity :
} else {
currentFragmentIndex = savedInstanceState.getInt(Preferences.CURRENT_FRAGMENT.key)
}
- nav_view.menu.getItem(currentFragmentIndex).isChecked = true
+ binding.navView.menu.getItem(currentFragmentIndex).isChecked = true
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -73,8 +74,8 @@ class MainActivity :
}
override fun onBackPressed() {
- if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
- drawer_layout.closeDrawer(GravityCompat.START)
+ if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
+ binding.drawerLayout.closeDrawer(GravityCompat.START)
} else {
finish()
}
@@ -117,12 +118,12 @@ class MainActivity :
startActivity(fanPageIntent)
}
}
- drawer_layout.closeDrawer(GravityCompat.START)
+ binding.drawerLayout.closeDrawer(GravityCompat.START)
return selected
}
private fun switchToFragmentIndex(fragmentIndex: Int): Boolean {
- return if (fragmentIndex in 0 until fragmentTagList.size &&
+ return if (fragmentIndex in fragmentTagList.indices &&
fragmentIndex != currentFragmentIndex) {
currentFragmentIndex = fragmentIndex
doFragmentTransaction()
@@ -131,20 +132,19 @@ class MainActivity :
}
private fun doFragmentTransaction() {
- val toBeAttachedFragment: Fragment? =
- supportFragmentManager.findFragmentByTag(fragmentTagList[currentFragmentIndex])
+ val toBeAttachedFragment: Fragment =
+ supportFragmentManager.findFragmentByTag(fragmentTagList[currentFragmentIndex]) ?: when (currentFragmentIndex) {
+ 1 -> FavoriteFragment.newInstance()
+ else -> MangaListFragment.newInstance()
+ } as Fragment
supportFragmentManager
.beginTransaction()
.replace(
R.id.content,
- toBeAttachedFragment ?: when (currentFragmentIndex) {
- 0 -> MangaListFragment.newInstance()
- 1 -> FavoriteFragment.newInstance()
- else -> MangaListFragment.newInstance()
- } as Fragment,
+ toBeAttachedFragment,
fragmentTagList[currentFragmentIndex]
).commit()
- spinnerPrimary?.visibility = View.GONE
- spinnerSecondary?.visibility = View.GONE
+ binding.contentMain.spinnerPrimary.visibility = View.GONE
+ binding.contentMain.spinnerSecondary.visibility = View.GONE
}
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/favorite/FavoriteFragment.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/favorite/FavoriteFragment.kt
index d1fb6a3..ec7ff1d 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/favorite/FavoriteFragment.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/favorite/FavoriteFragment.kt
@@ -8,19 +8,18 @@ import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
-import androidx.appcompat.widget.AppCompatSpinner
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
import com.bumptech.glide.load.model.GlideUrl
-import com.crashlytics.android.Crashlytics
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
import com.github.salomonbrys.kodein.instance
import io.github.innoobwetrust.kintamanga.R
import io.github.innoobwetrust.kintamanga.database.DatabaseHelper
import io.github.innoobwetrust.kintamanga.database.model.MangaDb
+import io.github.innoobwetrust.kintamanga.databinding.FragmentMangaListBinding
import io.github.innoobwetrust.kintamanga.source.SourceManager
import io.github.innoobwetrust.kintamanga.source.model.CatalogPages
import io.github.innoobwetrust.kintamanga.ui.main.ElementInfoInteractionListener
@@ -31,9 +30,6 @@ import io.github.innoobwetrust.kintamanga.ui.manga.MangaInfoActivity
import io.github.innoobwetrust.kintamanga.ui.model.ElementInfo
import io.github.innoobwetrust.kintamanga.ui.model.MangaBinding
import io.github.innoobwetrust.kintamanga.util.extension.toast
-import kotlinx.android.synthetic.main.content_main.*
-import kotlinx.android.synthetic.main.fragment_manga_list.*
-import kotlinx.android.synthetic.main.fragment_manga_list.view.*
import okhttp3.OkHttpClient
import rx.Subscription
import timber.log.Timber
@@ -58,12 +54,14 @@ class FavoriteFragment :
override var sourceNameFilter: String? = null
+ private lateinit var binding: FragmentMangaListBinding
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?): View? {
- val view = inflater.inflate(R.layout.fragment_manga_list, container, false)
- setupFavoriteListView(view = view)
+ savedInstanceState: Bundle?): View {
+ binding = FragmentMangaListBinding.inflate(inflater, container, false)
+ setupFavoriteListView()
setupToolbar()
- return view
+ return binding.root
}
override fun onResume() {
@@ -72,6 +70,7 @@ class FavoriteFragment :
Glide.get(it.applicationContext).registry.replace(
GlideUrl::class.java,
InputStream::class.java,
+ // FIXME: custom headers per source
OkHttpUrlLoader.Factory(instance("cover"))
)
}
@@ -79,67 +78,59 @@ class FavoriteFragment :
override fun onPause() {
disposeAllLoaderDisposables()
- swipeRefreshLayout?.isRefreshing = false
+ binding.swipeRefreshLayout.isRefreshing = false
super.onPause()
}
override fun onDestroy() {
- listElementInfos?.adapter = null
+ binding.listElementInfos.adapter = null
System.gc()
super.onDestroy()
}
- private fun setupFavoriteListView(view: View) {
- if (view.listElementInfos is RecyclerView) {
- when (activity?.resources?.configuration?.orientation) {
- Configuration.ORIENTATION_PORTRAIT ->
- view.listElementInfos.layoutManager =
- GridLayoutManager(
- view.listElementInfos.context,
- mColumnCount - 2,
- RecyclerView.VERTICAL,
- false
- )
- Configuration.ORIENTATION_LANDSCAPE ->
- view.listElementInfos.layoutManager =
- GridLayoutManager(
- view.listElementInfos.context,
- mColumnCount,
- RecyclerView.VERTICAL,
- false
- )
- }
- view.listElementInfos.adapter = MangaListAdapter(
- catalogPages = catalogPages,
- listType = mListType,
- elementInfoInteractionListener = this
- )
- }
+ private fun setupFavoriteListView() {
+ if (activity?.resources?.configuration?.orientation == Configuration.ORIENTATION_LANDSCAPE) binding.listElementInfos.layoutManager =
+ GridLayoutManager(
+ binding.listElementInfos.context,
+ mColumnCount,
+ RecyclerView.VERTICAL,
+ false
+ )
+ else binding.listElementInfos.layoutManager =
+ GridLayoutManager(
+ binding.listElementInfos.context,
+ mColumnCount - 2,
+ RecyclerView.VERTICAL,
+ false
+ )
+ binding.listElementInfos.adapter = MangaListAdapter(
+ catalogPages = catalogPages,
+ listType = mListType,
+ elementInfoInteractionListener = this
+ )
}
private fun setupToolbar() {
- (activity as? MainActivity)?.supportActionBar?.title = null
- if (activity?.spinnerPrimary is AppCompatSpinner) {
- if (groupSpinnerAdapter != activity?.spinnerPrimary?.adapter)
- setupSpinners()
+ (activity as? MainActivity)?.let {
+ it.supportActionBar?.title = null
+ if (groupSpinnerAdapter != it.binding.contentMain.spinnerPrimary.adapter)
+ setupSpinners(it)
else {
- activity?.spinnerPrimary?.visibility = View.VISIBLE
+ it.binding.contentMain.spinnerPrimary.visibility = View.VISIBLE
}
}
}
- private fun setupSpinners() {
- if (activity?.spinnerPrimary is AppCompatSpinner) {
- activity?.spinnerSecondary?.let {
- it.adapter = sourceSpinnerAdapter
- it.onItemSelectedListener = sourceSpinnerOnItemSelectedListener
- it.visibility = View.VISIBLE
- }
- activity?.spinnerPrimary?.let {
- it.adapter = groupSpinnerAdapter
- it.onItemSelectedListener = groupSpinnerOnItemSelectedListener
- it.visibility = View.VISIBLE
- }
+ private fun setupSpinners(mainActivity: MainActivity) {
+ mainActivity.binding.contentMain.spinnerSecondary.apply {
+ adapter = sourceSpinnerAdapter
+ onItemSelectedListener = sourceSpinnerOnItemSelectedListener
+ visibility = View.VISIBLE
+ }
+ mainActivity.binding.contentMain.spinnerPrimary.apply {
+ adapter = groupSpinnerAdapter
+ onItemSelectedListener = groupSpinnerOnItemSelectedListener
+ visibility = View.VISIBLE
}
}
@@ -164,14 +155,14 @@ class FavoriteFragment :
position: Int,
id: Long
) {
- swipeRefreshLayout?.isRefreshing = false
+ binding.swipeRefreshLayout.isRefreshing = false
disposeAllLoaderDisposables()
observeDataBase(
groupType = position,
onNextDatabaseChange = onNextDatabaseChange,
onDatabaseError = onDatabaseError
)
- swipeRefreshLayout?.setOnRefreshListener {
+ binding.swipeRefreshLayout.setOnRefreshListener {
disposeAllLoaderDisposables()
observeDataBase(
groupType = position,
@@ -179,7 +170,7 @@ class FavoriteFragment :
onDatabaseError = onDatabaseError
)
}
- swipeRefreshLayout?.isRefreshing = true
+ binding.swipeRefreshLayout.isRefreshing = true
}
}
}
@@ -211,7 +202,7 @@ class FavoriteFragment :
0 -> null
else -> sourceSpinnerAdapter.getItem(position)
}
- activity?.spinnerPrimary?.let {
+ (activity as? MainActivity)?.binding?.contentMain?.spinnerPrimary?.let {
it.onItemSelectedListener?.onItemSelected(
null, null, it.selectedItemPosition, it.selectedItemId
)
@@ -230,14 +221,13 @@ class FavoriteFragment :
itemThumbnailUri = mangaDb.mangaThumbnailUri
}
})
- listElementInfos?.adapter?.notifyDataSetChanged()
- swipeRefreshLayout?.isRefreshing = false
+ binding.listElementInfos.adapter?.notifyDataSetChanged()
+ binding.swipeRefreshLayout.isRefreshing = false
}
private val onDatabaseError: (Throwable) -> Unit = { error ->
context?.toast(R.string.refresh_database_manga_list_error)
Timber.e(error)
- Crashlytics.logException(error)
}
override fun onMangaCardClick(mangaBinding: MangaBinding) {
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/list/MangaListFragment.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/list/MangaListFragment.kt
index c764faf..dd04a83 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/list/MangaListFragment.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/list/MangaListFragment.kt
@@ -8,22 +8,21 @@ import android.os.Bundle
import android.view.*
import android.widget.AdapterView
import android.widget.ArrayAdapter
-import androidx.appcompat.widget.AppCompatSpinner
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.bumptech.glide.Glide
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
import com.bumptech.glide.load.model.GlideUrl
-import com.crashlytics.android.Crashlytics
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
+import com.github.salomonbrys.kodein.factory
import com.github.salomonbrys.kodein.instance
import com.github.salomonbrys.kotson.fromJson
import com.github.salomonbrys.kotson.typedToJson
import com.google.gson.Gson
import io.github.innoobwetrust.kintamanga.KINTAMAngaPreferences
import io.github.innoobwetrust.kintamanga.R
+import io.github.innoobwetrust.kintamanga.databinding.FragmentMangaListBinding
import io.github.innoobwetrust.kintamanga.source.SourceManager
import io.github.innoobwetrust.kintamanga.source.model.CatalogPage
import io.github.innoobwetrust.kintamanga.source.model.CatalogPages
@@ -37,9 +36,8 @@ import io.github.innoobwetrust.kintamanga.ui.main.MangaListTypes
import io.github.innoobwetrust.kintamanga.ui.manga.MangaInfoActivity
import io.github.innoobwetrust.kintamanga.ui.model.MangaBinding
import io.github.innoobwetrust.kintamanga.util.extension.toast
-import kotlinx.android.synthetic.main.content_main.*
-import kotlinx.android.synthetic.main.fragment_manga_list.*
-import kotlinx.android.synthetic.main.fragment_manga_list.view.*
+import okhttp3.Headers
+import okhttp3.Interceptor
import okhttp3.OkHttpClient
import rx.Single
import rx.Subscription
@@ -115,7 +113,6 @@ class MangaListFragment :
)!!
} catch (e: Exception) {
Timber.e(e, "source: $mangaSourceName, index: $segmentIndex")
- Crashlytics.logException(e)
throw e
}
}
@@ -145,12 +142,13 @@ class MangaListFragment :
setHasOptionsMenu(true)
}
+ private lateinit var binding: FragmentMangaListBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?): View? {
- val view = inflater.inflate(R.layout.fragment_manga_list, container, false)
- setupMangaListView(view = view)
+ savedInstanceState: Bundle?): View {
+ binding = FragmentMangaListBinding.inflate(inflater, container, false)
+ setupMangaListView()
setupToolbar()
- return view
+ return binding.root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@@ -187,89 +185,85 @@ class MangaListFragment :
override fun onResume() {
super.onResume()
- this.activity?.let {
+ activity?.let {
Glide.get(it.applicationContext).registry.replace(
GlideUrl::class.java,
InputStream::class.java,
- OkHttpUrlLoader.Factory(instance("cover"))
+ OkHttpUrlLoader.Factory(
+ instance("cover")
+ .newBuilder()
+ .addInterceptor(factory("headers")(mangaInfoProcessor.headers()))
+ .build()
+ )
)
}
}
override fun onPause() {
disposeAllLoaderDisposables()
- swipeRefreshLayout?.isRefreshing = false
+ binding.swipeRefreshLayout.isRefreshing = false
super.onPause()
}
override fun onDestroy() {
- listElementInfos?.adapter = null
+ binding.listElementInfos.adapter = null
System.gc()
super.onDestroy()
}
- private fun setupMangaListView(view: View?) {
- if (view?.swipeRefreshLayout is SwipeRefreshLayout) {
- view.swipeRefreshLayout.setOnRefreshListener {
- backgroundRefresh(
- onRefreshedCatalogPage = onRefreshedCatalogPage,
- onRefreshError = onRefreshError
- )
- }
- when (activity?.resources?.configuration?.orientation) {
- Configuration.ORIENTATION_PORTRAIT ->
- view.listElementInfos.layoutManager =
- GridLayoutManager(
- view.listElementInfos.context,
- mColumnCount - 2,
- RecyclerView.VERTICAL,
- false
- )
- Configuration.ORIENTATION_LANDSCAPE ->
- view.listElementInfos.layoutManager =
- GridLayoutManager(
- view.listElementInfos.context,
- mColumnCount,
- RecyclerView.VERTICAL,
- false
- )
- }
- view.listElementInfos.adapter = MangaListAdapter(
- catalogPages = catalogPages,
- listType = mListType,
- elementInfoInteractionListener = this
+ private fun setupMangaListView() {
+ binding.swipeRefreshLayout.setOnRefreshListener {
+ backgroundRefresh(
+ onRefreshedCatalogPage = onRefreshedCatalogPage,
+ onRefreshError = onRefreshError
)
}
+ binding.listElementInfos.layoutManager = if (activity?.resources?.configuration?.orientation == Configuration.ORIENTATION_LANDSCAPE)
+ GridLayoutManager(
+ binding.listElementInfos.context,
+ mColumnCount,
+ RecyclerView.VERTICAL,
+ false
+ )
+ else
+ GridLayoutManager(
+ binding.listElementInfos.context,
+ mColumnCount - 2,
+ RecyclerView.VERTICAL,
+ false
+ )
+ binding.listElementInfos.adapter = MangaListAdapter(
+ catalogPages = catalogPages,
+ listType = mListType,
+ elementInfoInteractionListener = this
+ )
}
private fun setupToolbar() {
- (activity as? MainActivity)?.supportActionBar?.title = null
- if (activity?.spinnerPrimary is AppCompatSpinner &&
- activity?.spinnerSecondary is AppCompatSpinner) {
- if (sourceSpinnerAdapter != activity?.spinnerPrimary?.adapter ||
- segmentSpinnerAdapter != activity?.spinnerSecondary?.adapter)
- setupSpinners()
+ (activity as? MainActivity)?.let {
+ it.supportActionBar?.title = null
+ if (sourceSpinnerAdapter != it.binding.contentMain.spinnerPrimary.adapter ||
+ segmentSpinnerAdapter != it.binding.contentMain.spinnerSecondary.adapter)
+ setupSpinners(it)
else {
- activity?.spinnerPrimary?.visibility = View.VISIBLE
- activity?.spinnerSecondary?.visibility = View.VISIBLE
+ it.binding.contentMain.spinnerPrimary.visibility = View.VISIBLE
+ it.binding.contentMain.spinnerSecondary.visibility = View.VISIBLE
}
}
}
- private fun setupSpinners() {
- if (activity?.spinnerPrimary is AppCompatSpinner) {
- val spinnerSource = activity!!.spinnerPrimary
- spinnerSource.adapter = sourceSpinnerAdapter
- spinnerSource.onItemSelectedListener = sourceSpinnerOnItemSelectedListener
- val sourcePosition = SourceManager.sourceNameList.indexOf(mangaSourceName)
- if (-1 < sourcePosition) spinnerSource?.setSelection(sourcePosition)
- spinnerSource.visibility = View.VISIBLE
- }
+ private fun setupSpinners(mainActivity: MainActivity) {
+ val spinnerSource = mainActivity.binding.contentMain.spinnerPrimary
+ spinnerSource.adapter = sourceSpinnerAdapter
+ spinnerSource.onItemSelectedListener = sourceSpinnerOnItemSelectedListener
+ val sourcePosition = SourceManager.sourceNameList.indexOf(mangaSourceName)
+ if (-1 < sourcePosition) spinnerSource.setSelection(sourcePosition)
+ spinnerSource.visibility = View.VISIBLE
}
private fun setupSegmentSpinner(resetIndex: Boolean) {
- if (activity?.spinnerSecondary is AppCompatSpinner) {
- val spinnerSegment = activity!!.spinnerSecondary
+ (activity as? MainActivity)?.let {
+ val spinnerSegment = it.binding.contentMain.spinnerSecondary
spinnerSegment.adapter = segmentSpinnerAdapter
if (resetIndex) segmentIndex = 0
spinnerSegment.onItemSelectedListener = segmentSpinnerOnItemSelectedListener
@@ -301,7 +295,7 @@ class MangaListFragment :
position: Int,
id: Long
) {
- swipeRefreshLayout?.isRefreshing = false
+ binding.swipeRefreshLayout.isRefreshing = false
disposeAllLoaderDisposables()
val newSourceName =
SourceManager.sourceNameList.getOrElse(
@@ -363,7 +357,7 @@ class MangaListFragment :
mangaSegment.filterByUserInput.isNotEmpty()) {
requestFilter()
} else {
- swipeRefreshLayout?.isRefreshing = true
+ binding.swipeRefreshLayout.isRefreshing = true
backgroundRefresh(
onRefreshedCatalogPage = onRefreshedCatalogPage,
onRefreshError = onRefreshError
@@ -422,10 +416,10 @@ class MangaListFragment :
private val onRefreshedCatalogPage: (CatalogPage) -> Unit = { catalogPage ->
catalogPages.setup(catalogPage = catalogPage)
- listElementInfos?.adapter?.notifyDataSetChanged()
- listElementInfos?.scrollToPosition(0)
+ binding.listElementInfos.adapter?.notifyDataSetChanged()
+ binding.listElementInfos.scrollToPosition(0)
activity?.invalidateOptionsMenu()
- swipeRefreshLayout?.isRefreshing = false
+ binding.swipeRefreshLayout.isRefreshing = false
if (catalogPage.elementInfos.isEmpty())
context?.toast(R.string.refresh_manga_list_empty)
else
@@ -436,7 +430,7 @@ class MangaListFragment :
}
private val onRefreshError: (Throwable) -> Unit = { error ->
- swipeRefreshLayout?.isRefreshing = false
+ binding.swipeRefreshLayout.isRefreshing = false
context?.toast(R.string.refresh_manga_list_error)
Timber.e(error)
}
@@ -444,9 +438,9 @@ class MangaListFragment :
private val onNextCatalogPage: (CatalogPage?) -> Unit = { catalogPage ->
if (null != catalogPage) {
catalogPages.appendNextCatalogPage(catalogPage = catalogPage)
- listElementInfos?.adapter?.notifyDataSetChanged()
+ binding.listElementInfos.adapter?.notifyDataSetChanged()
}
- swipeRefreshLayout?.isRefreshing = false
+ binding.swipeRefreshLayout.isRefreshing = false
backgroundLoadMissingInfo(
onNextMissingMangaInfoLoaded = onNextMissingMangaInfoLoaded,
onMissingMangaInfoError = onMissingMangaInfoError
@@ -460,7 +454,7 @@ class MangaListFragment :
?.let {
it.itemThumbnailUri = info.mangaThumbnailUri
it.itemDescription = info.mangaDescription
- listElementInfos?.adapter
+ binding.listElementInfos.adapter
?.notifyItemChanged(catalogPages.elementInfos.indexOf(it))
}
}
@@ -480,8 +474,8 @@ class MangaListFragment :
)
saveFilter()
catalogPages.elementInfos.clear()
- listElementInfos?.adapter?.notifyDataSetChanged()
- swipeRefreshLayout?.isRefreshing = true
+ binding.listElementInfos.adapter?.notifyDataSetChanged()
+ binding.swipeRefreshLayout.isRefreshing = true
backgroundRefresh(
onRefreshedCatalogPage = onRefreshedCatalogPage,
onRefreshError = onRefreshError
@@ -509,7 +503,7 @@ class MangaListFragment :
override fun onRequestMoreElement() {
if (loadNextPageDisposable?.isUnsubscribed == false) return
- if (swipeRefreshLayout?.isRefreshing == true) return
+ if (binding.swipeRefreshLayout.isRefreshing) return
// Start loading next page when remaining manga is 5 or less
val catalogHasNextPage = try {
catalogPages.hasNextPage()
@@ -517,7 +511,7 @@ class MangaListFragment :
false
}
if (catalogHasNextPage) {
- swipeRefreshLayout?.isRefreshing = true
+ binding.swipeRefreshLayout.isRefreshing = true
backgroundLoadNextCatalogPage(
onNextCatalogPage = onNextCatalogPage,
onNextCatalogPageError = onNextCatalogPageError
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/list/MangaListNetworkLoader.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/list/MangaListNetworkLoader.kt
index 98ca6dc..104a716 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/list/MangaListNetworkLoader.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/main/list/MangaListNetworkLoader.kt
@@ -91,7 +91,7 @@ interface MangaListNetworkLoader {
.parallelMap { elementInfo ->
Observable.fromCallable { networkLoadMissingMangaInfo(elementInfo) }
.onErrorReturn { MangaBinding() }
- .filter { !it.mangaThumbnailUri.isBlank() }
+ .filter { it.mangaThumbnailUri.isNotBlank() }
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@@ -119,4 +119,4 @@ interface MangaListNetworkLoader {
stopLoadingNextPage()
stopLoadingMissingInfo()
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/ChapterListAdapter.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/ChapterListAdapter.kt
index b271f0a..2209eb8 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/ChapterListAdapter.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/ChapterListAdapter.kt
@@ -3,12 +3,8 @@ package io.github.innoobwetrust.kintamanga.ui.manga
import android.graphics.drawable.ColorDrawable
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
-import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
-import androidx.appcompat.widget.AppCompatImageButton
-import androidx.appcompat.widget.AppCompatImageView
-import androidx.cardview.widget.CardView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.afollestad.dragselectrecyclerview.IDragSelectAdapter
@@ -18,7 +14,6 @@ import io.github.innoobwetrust.kintamanga.databinding.HolderChapterBinding
import io.github.innoobwetrust.kintamanga.model.DownloadStatus
import io.github.innoobwetrust.kintamanga.ui.model.ChapterBinding
import io.github.innoobwetrust.kintamanga.ui.model.MangaBinding
-import kotlinx.android.synthetic.main.holder_chapter.view.*
class ChapterListAdapter(
private var mangaInfoActivity: MangaInfoActivity?,
@@ -44,7 +39,7 @@ class ChapterListAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
- val binding: HolderChapterBinding =
+ val binding =
HolderChapterBinding.inflate(layoutInflater, parent, false)
return ViewHolder(binding = binding)
}
@@ -53,72 +48,72 @@ class ChapterListAdapter(
mangaBinding?.apply {
val chapterBinding = chapters[chapters.size - position - 1]
holder.bind(chapterBinding)
- holder.root.chapterInfoLayout.setOnClickListener {
- holder.binding.chapterBinding?.let {
- mangaInfoActivity?.onChapterClick(chapterBinding = it)
+ holder.binding.let { binding ->
+ binding.chapterInfoLayout.setOnClickListener {
+ binding.chapterBinding?.let {
+ mangaInfoActivity?.onChapterClick(chapterBinding = it)
+ }
}
- }
- holder.root.chapterInfoLayout.setOnLongClickListener {
- mangaInfoActivity?.onLongClick(holder.adapterPosition)
- true
- }
- holder.root.let {
- it.chapterTitle.isSelected = true
- it.chapterDescription.isSelected = true
- it.chapterUpdateTime.isSelected = true
- }
- holder.chapterOfflinePin.setOnClickListener {
- toggleSelected(holder.adapterPosition)
- }
- holder.chapterOfflinePin.setOnLongClickListener {
- mangaInfoActivity?.onLongClick(holder.adapterPosition)
- true
- }
- holder.chapterOption.setOnClickListener {
- val chapterItemOption =
- PopupMenu(contextWrapper!!, holder.chapterOption)
- chapterItemOption.inflate(R.menu.menu_chapter_item)
- chapterItemOption.menu.apply {
- findItem(R.id.chapter_item_option_download)?.isVisible =
- chapterBinding.chapterDownloadStatus == DownloadStatus.NOT_DOWNLOADED
- findItem(R.id.chapter_item_option_delete)?.isVisible =
- chapterBinding.chapterDownloadStatus == DownloadStatus.DOWNLOADED
+ binding.chapterInfoLayout.setOnLongClickListener {
+ mangaInfoActivity?.onLongClick(holder.adapterPosition)
+ true
}
- chapterItemOption.setOnMenuItemClickListener { item ->
- when (item.itemId) {
- R.id.chapter_item_option_download -> {
- if (DownloadStatus.NOT_DOWNLOADED == chapterBinding.chapterDownloadStatus) {
- mangaInfoActivity?.onDownloadRequest(listOf(chapterBinding), false)
- return@setOnMenuItemClickListener true
+ binding.chapterTitle.isSelected = true
+ binding.chapterDescription.isSelected = true
+ binding.chapterUpdateTime.isSelected = true
+ binding.chapterOfflinePin.setOnClickListener {
+ toggleSelected(holder.adapterPosition)
+ }
+ binding.chapterOfflinePin.setOnLongClickListener {
+ mangaInfoActivity?.onLongClick(holder.adapterPosition)
+ true
+ }
+ binding.chapterOption.setOnClickListener {
+ val chapterItemOption =
+ PopupMenu(contextWrapper!!, binding.chapterOption)
+ chapterItemOption.inflate(R.menu.menu_chapter_item)
+ chapterItemOption.menu.apply {
+ findItem(R.id.chapter_item_option_download)?.isVisible =
+ chapterBinding.chapterDownloadStatus == DownloadStatus.NOT_DOWNLOADED
+ findItem(R.id.chapter_item_option_delete)?.isVisible =
+ chapterBinding.chapterDownloadStatus == DownloadStatus.DOWNLOADED
+ }
+ chapterItemOption.setOnMenuItemClickListener { item ->
+ when (item.itemId) {
+ R.id.chapter_item_option_download -> {
+ if (DownloadStatus.NOT_DOWNLOADED == chapterBinding.chapterDownloadStatus) {
+ mangaInfoActivity?.onDownloadRequest(listOf(chapterBinding), false)
+ return@setOnMenuItemClickListener true
+ }
}
- }
- R.id.chapter_item_option_delete -> {
- if (DownloadStatus.DOWNLOADED == chapterBinding.chapterDownloadStatus) {
- mangaInfoActivity?.onDeleteRequest(listOf(chapterBinding), false)
+ R.id.chapter_item_option_delete -> {
+ if (DownloadStatus.DOWNLOADED == chapterBinding.chapterDownloadStatus) {
+ mangaInfoActivity?.onDeleteRequest(listOf(chapterBinding), false)
+ return@setOnMenuItemClickListener true
+ }
+ }
+ R.id.chapter_item_option_toggle_read_status -> {
+ chapterBinding.chapterViewed = !chapterBinding.chapterViewed
+ notifyItemChanged(position)
+ mangaInfoActivity?.onReadStatusToggled(listOf(chapterBinding))
return@setOnMenuItemClickListener true
}
}
- R.id.chapter_item_option_toggle_read_status -> {
- chapterBinding.chapterViewed = !chapterBinding.chapterViewed
- notifyItemChanged(position)
- mangaInfoActivity?.onReadStatusToggled(listOf(chapterBinding))
- return@setOnMenuItemClickListener true
- }
+ return@setOnMenuItemClickListener false
}
- return@setOnMenuItemClickListener false
+ chapterItemOption.show()
}
- chapterItemOption.show()
+ binding.chapterCard.foreground =
+ if (position in selectedIndices)
+ ColorDrawable(
+ ContextCompat.getColor(
+ binding.chapterCard.context,
+ R.color.color_overlay
+ )
+ )
+ else
+ null
}
- holder.chapterCard.foreground =
- if (position in selectedIndices)
- ColorDrawable(
- ContextCompat.getColor(
- holder.chapterCard.context,
- R.color.color_overlay
- )
- )
- else
- null
}
}
@@ -135,7 +130,7 @@ class ChapterListAdapter(
}
override fun onViewRecycled(holder: ViewHolder) {
- holder.root.setOnClickListener(null)
+ holder.binding.root.setOnClickListener(null)
holder.binding.chapterOfflinePin.setOnClickListener(null)
holder.bind(null)
System.gc()
@@ -189,15 +184,6 @@ class ChapterListAdapter(
inner class ViewHolder(
val binding: HolderChapterBinding
) : RecyclerView.ViewHolder(binding.root) {
- val root: View
- get() = binding.root
- val chapterCard: CardView
- get() = binding.chapterCard
- val chapterOfflinePin: AppCompatImageView
- get() = binding.chapterOfflinePin
- val chapterOption: AppCompatImageButton
- get() = binding.chapterOption
-
fun bind(chapterBinding: ChapterBinding?) {
binding.chapterBinding = chapterBinding
binding.executePendingBindings()
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/MangaInfoActivity.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/MangaInfoActivity.kt
index 013a42c..a5fb6c9 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/MangaInfoActivity.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/MangaInfoActivity.kt
@@ -17,8 +17,8 @@ import com.afollestad.materialcab.MaterialCab
import com.bumptech.glide.Glide
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
import com.bumptech.glide.load.model.GlideUrl
-import com.crashlytics.android.Crashlytics
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
+import com.github.salomonbrys.kodein.factory
import com.github.salomonbrys.kodein.instance
import com.github.salomonbrys.kotson.fromJson
import com.github.salomonbrys.kotson.typedToJson
@@ -36,7 +36,8 @@ import io.github.innoobwetrust.kintamanga.ui.model.MangaBinding
import io.github.innoobwetrust.kintamanga.ui.reader.ReaderActivity
import io.github.innoobwetrust.kintamanga.util.extension.toast
import io.github.innoobwetrust.kintamanga.util.extension.uriString
-import kotlinx.android.synthetic.main.activity_manga_info.*
+import okhttp3.Headers
+import okhttp3.Interceptor
import okhttp3.OkHttpClient
import rx.Subscription
import timber.log.Timber
@@ -95,23 +96,23 @@ class MangaInfoActivity :
}
binding = DataBindingUtil.setContentView(this, R.layout.activity_manga_info)
bind()
- setSupportActionBar(toolbar)
+ setSupportActionBar(binding.toolbar)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setDisplayShowHomeEnabled(true)
}
- listChapters.let {
+ binding.listChapters.let {
it.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
it.adapter = ChapterListAdapter(
mangaInfoActivity = this,
mangaBinding = mangaBinding,
selectedIndices = savedInstanceState
?.getString(SavedInstanceStates.SELECTED_INDICES.key)
- ?.run { instance().fromJson>(this) }
+ ?.run { instance().fromJson(this) }
?: mutableSetOf()
)
}
- mangaMenuFab.setOnClickListener(menuFabOnClickListener)
+ binding.mangaMenuFab.setOnClickListener(menuFabOnClickListener)
cab = MaterialCab.restoreState(savedInstanceState, this, this)
}
@@ -120,7 +121,12 @@ class MangaInfoActivity :
Glide.get(applicationContext).registry.replace(
GlideUrl::class.java,
InputStream::class.java,
- OkHttpUrlLoader.Factory(instance("cover"))
+ OkHttpUrlLoader.Factory(
+ instance("cover")
+ .newBuilder()
+ .addInterceptor(factory("headers")(mangaInfoProcessor.headers()))
+ .build()
+ )
)
if (mangaBinding.chapters.isEmpty()) {
backgroundRefresh(
@@ -140,7 +146,7 @@ class MangaInfoActivity :
super.onSaveInstanceState(outState)
outState.let {
it.putSerializable(SavedInstanceStates.MANGA.key, mangaBinding)
- (listChapters?.adapter as? ChapterListAdapter)?.selectedIndices?.run {
+ (binding.listChapters.adapter as? ChapterListAdapter)?.selectedIndices?.run {
it.putString(
SavedInstanceStates.SELECTED_INDICES.key,
instance().typedToJson(this)
@@ -168,7 +174,7 @@ class MangaInfoActivity :
}
override fun onBackPressed() {
- (listChapters?.adapter as? ChapterListAdapter)?.let {
+ (binding.listChapters.adapter as? ChapterListAdapter)?.let {
if (it.selectedIndices.isNotEmpty()) {
it.clearSelected()
return
@@ -182,7 +188,7 @@ class MangaInfoActivity :
}
override fun onCabItemClicked(item: MenuItem?): Boolean {
- (listChapters?.adapter as? ChapterListAdapter)?.let {
+ (binding.listChapters.adapter as? ChapterListAdapter)?.let {
// Because chapter index is ordered in revert, we need to fix the list of indices
val size = mangaBinding.chapters.size
val chapterSelectedIndices = it.selectedIndices.map { index -> size - index - 1 }
@@ -213,7 +219,7 @@ class MangaInfoActivity :
}
override fun onCabFinished(cab: MaterialCab?): Boolean {
- (listChapters?.adapter as? ChapterListAdapter)?.clearSelected()
+ (binding.listChapters.adapter as? ChapterListAdapter)?.clearSelected()
return true
}
@@ -225,18 +231,18 @@ class MangaInfoActivity :
private fun showFABMenu() {
isFABOpen = true
- mangaClearFab?.animate()?.translationX(-resources.getDimension(R.dimen.standard_305))
- mangaShareFab?.animate()?.translationX(-resources.getDimension(R.dimen.standard_205))
- mangaFavoriteFab?.animate()?.translationX(-resources.getDimension(R.dimen.standard_105))
- mangaMenuFab?.setImageResource(R.drawable.ic_cancel_white_24dp)
+ binding.mangaClearFab.animate()?.translationX(-resources.getDimension(R.dimen.standard_305))
+ binding.mangaShareFab.animate()?.translationX(-resources.getDimension(R.dimen.standard_205))
+ binding.mangaFavoriteFab.animate()?.translationX(-resources.getDimension(R.dimen.standard_105))
+ binding.mangaMenuFab.setImageResource(R.drawable.ic_cancel_white_24dp)
}
private fun closeFABMenu() {
isFABOpen = false
- mangaClearFab?.animate()?.translationX(0f)
- mangaShareFab?.animate()?.translationX(0f)
- mangaFavoriteFab?.animate()?.translationX(0f)
- mangaMenuFab?.setImageResource(R.drawable.ic_menu_white_24dp)
+ binding.mangaClearFab.animate()?.translationX(0f)
+ binding.mangaShareFab.animate()?.translationX(0f)
+ binding.mangaFavoriteFab.animate()?.translationX(0f)
+ binding.mangaMenuFab.setImageResource(R.drawable.ic_menu_white_24dp)
}
private val menuFabOnClickListener: (View) -> Unit = { _ ->
@@ -300,12 +306,12 @@ class MangaInfoActivity :
}
private val onRefreshSuccess: (Boolean) -> Unit = { success ->
- progress?.visibility = View.GONE
- mangaClearFab?.setOnClickListener(mangaClearFabOnClickListener)
- mangaShareFab?.setOnClickListener(shareFabOnClickListener)
- mangaFavoriteFab?.setOnClickListener(favoriteFabOnClickListener)
+ binding.progress.visibility = View.GONE
+ binding.mangaClearFab.setOnClickListener(mangaClearFabOnClickListener)
+ binding.mangaShareFab.setOnClickListener(shareFabOnClickListener)
+ binding.mangaFavoriteFab.setOnClickListener(favoriteFabOnClickListener)
if (success) {
- listChapters?.adapter?.notifyDataSetChanged()
+ binding.listChapters.adapter?.notifyDataSetChanged()
} else {
toast(R.string.manga_info_refresh_failed_text)
}
@@ -314,7 +320,6 @@ class MangaInfoActivity :
private val onRefreshError: (Throwable) -> Unit = { error ->
toast(R.string.manga_info_refresh_error_text)
Timber.e(error)
- Crashlytics.logException(error)
}
private val onDownloadStatusChange: (Download) -> Unit = { download ->
@@ -329,14 +334,12 @@ class MangaInfoActivity :
}
?: Exception("Can not find chapter: ${download.chapter.chapterUri}").let {
Timber.e(it)
- Crashlytics.logException(it)
}
}
private val onObservableDownloadError: (Throwable) -> Unit = { error ->
toast(R.string.observe_download_failed_text)
Timber.e(error)
- Crashlytics.logException(error)
}
@Throws(Exception::class)
@@ -345,7 +348,12 @@ class MangaInfoActivity :
Glide.get(applicationContext).registry.replace(
GlideUrl::class.java,
InputStream::class.java,
- OkHttpUrlLoader.Factory(instance("cover"))
+ OkHttpUrlLoader.Factory(
+ instance("cover")
+ .newBuilder()
+ .addInterceptor(factory("headers")(mangaInfoProcessor.headers()))
+ .build()
+ )
)
if (0 == requestCode && Activity.RESULT_OK == resultCode && null != data) {
val updatedMangaBinding =
@@ -362,7 +370,7 @@ class MangaInfoActivity :
}
override fun onLongClick(index: Int) {
- listChapters?.setDragSelectActive(true, index)
+ binding.listChapters.setDragSelectActive(true, index)
}
override fun onSelectionChanged(count: Int) {
@@ -388,7 +396,7 @@ class MangaInfoActivity :
}
override fun onChapterClick(chapterBinding: ChapterBinding) {
- if (View.VISIBLE == progress?.visibility) return
+ if (View.VISIBLE == binding.progress.visibility) return
val readerIntent: Intent =
Intent(this, ReaderActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
@@ -409,7 +417,6 @@ class MangaInfoActivity :
onError = { error ->
toast(R.string.download_request_prepare_failed_text)
Timber.e(error)
- Crashlytics.logException(error)
}
)
chapterBindings.forEach { it.chapterDownloadStatus = DownloadStatus.QUEUE }
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/MangaInfoLoader.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/MangaInfoLoader.kt
index 9867af9..8ff54ce 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/MangaInfoLoader.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/manga/MangaInfoLoader.kt
@@ -1,6 +1,5 @@
package io.github.innoobwetrust.kintamanga.ui.manga
-import com.crashlytics.android.Crashlytics
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
import com.github.salomonbrys.kodein.instance
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects
@@ -62,7 +61,6 @@ interface MangaInfoLoader : KodeinGlobalAware {
.fromCallable { putMangaDb() }
.doOnError {
Timber.e(it)
- Crashlytics.logException(it)
}
.subscribeOn(Schedulers.io())
@@ -76,7 +74,6 @@ interface MangaInfoLoader : KodeinGlobalAware {
}
.doOnError {
Timber.e(it)
- Crashlytics.logException(it)
}
.subscribeOn(Schedulers.io())
@@ -140,7 +137,6 @@ interface MangaInfoLoader : KodeinGlobalAware {
}
.doOnError {
Timber.e(it)
- Crashlytics.logException(it)
}
.subscribeOn(Schedulers.io())
@@ -149,7 +145,6 @@ interface MangaInfoLoader : KodeinGlobalAware {
.flatMap { saveChapters() }
.doOnError {
Timber.e(it)
- Crashlytics.logException(it)
}
.subscribeOn(Schedulers.io())
@@ -187,7 +182,6 @@ interface MangaInfoLoader : KodeinGlobalAware {
}
.doOnError {
Timber.e(it)
- Crashlytics.logException(it)
}
.subscribeOn(Schedulers.io())
@@ -223,7 +217,6 @@ interface MangaInfoLoader : KodeinGlobalAware {
.observeOn(AndroidSchedulers.mainThread())
.doOnError {
Timber.e(it)
- Crashlytics.logException(it)
}
.subscribe(
{ download -> onDownloadStatusChange(download) },
@@ -244,7 +237,6 @@ interface MangaInfoLoader : KodeinGlobalAware {
saveMangaObservable
.doOnError {
Timber.e(it)
- Crashlytics.logException(it)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
@@ -281,7 +273,6 @@ interface MangaInfoLoader : KodeinGlobalAware {
}
.doOnError {
Timber.e(it)
- Crashlytics.logException(it)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@@ -310,7 +301,6 @@ interface MangaInfoLoader : KodeinGlobalAware {
}
.doOnError {
Timber.e(it)
- Crashlytics.logException(it)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ChapterInfoLoader.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ChapterInfoLoader.kt
index 9371993..361b046 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ChapterInfoLoader.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ChapterInfoLoader.kt
@@ -1,14 +1,11 @@
package io.github.innoobwetrust.kintamanga.ui.reader
import android.content.Context
-import com.crashlytics.android.Crashlytics
-import com.github.piasy.biv.BigImageViewer
import io.github.innoobwetrust.kintamanga.download.DownloadProvider
import io.github.innoobwetrust.kintamanga.model.DownloadStatus
import io.github.innoobwetrust.kintamanga.source.processor.ChapterInfoProcessor
import io.github.innoobwetrust.kintamanga.ui.model.ChapterBinding
import io.github.innoobwetrust.kintamanga.ui.model.MangaBinding
-import io.github.innoobwetrust.kintamanga.util.GlideBitmapImageLoader
import rx.Single
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
@@ -31,7 +28,6 @@ interface ChapterInfoLoader {
chapterInfoProcessor.fetchPageList(chapterBinding)
} catch (e: Exception) {
Timber.e(e)
- Crashlytics.logException(e)
return false
}
chapterBinding.chapterPages = pages.onEach { it.chapterIndex = chapterBinding.chapterIndex }
@@ -57,7 +53,6 @@ interface ChapterInfoLoader {
onChapterLoadError: (Throwable) -> Unit
) {
// Prevent conflict
- (BigImageViewer.imageLoader() as? GlideBitmapImageLoader)?.cancelPrefetch()
disposeAllLoaderDisposables()
// Real job
loadChapterDisposable = Single.fromCallable {
@@ -73,4 +68,4 @@ interface ChapterInfoLoader {
fun disposeAllLoaderDisposables() {
loadChapterDisposable?.let { if (!it.isUnsubscribed) it.unsubscribe() }
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ImageViewerAdapter.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ImageViewerAdapter.kt
index d74c1d4..07e6b0e 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ImageViewerAdapter.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ImageViewerAdapter.kt
@@ -1,27 +1,28 @@
package io.github.innoobwetrust.kintamanga.ui.reader
+import android.graphics.drawable.Drawable
import android.net.Uri
import android.view.LayoutInflater
-import android.view.View
import android.view.ViewGroup
-import androidx.appcompat.widget.AppCompatButton
-import androidx.appcompat.widget.AppCompatImageView
-import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
+import androidx.swiperefreshlayout.widget.CircularProgressDrawable
import com.bumptech.glide.Glide
+import com.bumptech.glide.load.model.GlideUrl
+import com.bumptech.glide.load.model.Headers
+import com.bumptech.glide.request.target.CustomTarget
+import com.bumptech.glide.request.transition.Transition
+import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
-import com.github.piasy.biv.indicator.progresspie.ProgressPieIndicator
-import com.github.piasy.biv.loader.ImageLoader
-import com.github.piasy.biv.view.BigImageView
import io.github.innoobwetrust.kintamanga.R
+import io.github.innoobwetrust.kintamanga.databinding.HolderImageViewerBinding
import io.github.innoobwetrust.kintamanga.model.Page
import io.github.innoobwetrust.kintamanga.ui.model.ChapterBinding
-import kotlinx.android.synthetic.main.holder_image_viewer.view.*
import java.io.File
class ImageViewerAdapter(
private var viewer: ViewerFragment?,
private var chapterBinding: ChapterBinding?,
+ private val glideHeaders: Headers?,
private val viewerType: ViewerTypes
) : RecyclerView.Adapter() {
@@ -38,33 +39,24 @@ class ImageViewerAdapter(
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val inflatedView = LayoutInflater.from(parent.context)
- .inflate(R.layout.holder_image_viewer, parent, false)
- if (viewerType == ViewerTypes.WEBTOON) {
- inflatedView.imageViewerLayout?.layoutParams?.height =
- ViewGroup.LayoutParams.WRAP_CONTENT
- }
- return ViewHolder(inflatedView = inflatedView)
+ val layoutInflater = LayoutInflater.from(parent.context)
+ val binding = HolderImageViewerBinding.inflate(layoutInflater, parent, false)
+ return ViewHolder(binding = binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
chapterBinding?.let { binding ->
- holder.setImage(binding.chapterPages[position])
- holder.touchOverlay.setOnClickListener {
- (viewer?.activity as? ViewerFragmentListener)
- ?.onViewerToggleControl()
- }
- holder.failureImage.setOnClickListener {
- (viewer?.activity as? ViewerFragmentListener)
- ?.onViewerToggleControl()
+ if (viewerType == ViewerTypes.WEBTOON) {
+ holder.binding.imageViewerLayout.layoutParams.height =
+ ViewGroup.LayoutParams.WRAP_CONTENT
}
- holder.reloadImageButton.setOnClickListener {
- holder.touchOverlay.visibility = View.VISIBLE
- holder.failureView.visibility = View.GONE
- holder.setImage(binding.chapterPages[position])
- }
- holder.chapterImageView.ssiv.setOnTouchListener { _, motionEvent ->
- viewer?.gestureDetector?.onTouchEvent(motionEvent) ?: true
+ holder.bind(binding.chapterPages[position], viewer?.serverIndex
+ ?: 0)
+ holder.binding.chapterImage.apply {
+ setOnTouchListener { _, motionEvent ->
+ viewer?.view?.performClick()
+ viewer?.gestureDetector?.onTouchEvent(motionEvent) ?: true
+ }
}
}
}
@@ -76,81 +68,64 @@ class ImageViewerAdapter(
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
viewer = null
chapterBinding = null
- System.gc()
+// System.gc()
super.onDetachedFromRecyclerView(recyclerView)
}
override fun onViewRecycled(holder: ViewHolder) {
- holder.let {
- it.touchOverlay.setOnClickListener(null)
- it.failureImage.setOnClickListener(null)
- it.reloadImageButton.setOnClickListener(null)
- it.chapterImageView.setOnClickListener(null)
- it.chapterImageView.ssiv.setOnTouchListener(null)
- it.chapterImageView.ssiv.recycle()
+ holder.binding.apply {
+ chapterImage.setOnClickListener(null)
+ chapterImage.recycle()
}
- System.gc()
+// System.gc()
super.onViewRecycled(holder)
}
inner class ViewHolder(
- inflatedView: View
- ) : RecyclerView.ViewHolder(inflatedView) {
- val chapterImageView: BigImageView = inflatedView.chapterImage
- val touchOverlay: View = inflatedView.touchOverlay
- val failureView: ConstraintLayout = inflatedView.failureView
- val failureImage: AppCompatImageView = inflatedView.failureImage
- val reloadImageButton: AppCompatButton = inflatedView.reloadImageButton
+ val binding: HolderImageViewerBinding
+ ) : RecyclerView.ViewHolder(binding.root) {
+ private lateinit var page: Page
- init {
- chapterImageView.apply {
- ssiv.setMinimumDpi(90)
- ssiv.setMinimumTileDpi(180)
- ssiv.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE)
- ssiv.setOnImageEventListener(
- object : SubsamplingScaleImageView.OnImageEventListener {
- override fun onReady() {}
- override fun onTileLoadError(p0: Exception?) {}
- override fun onPreviewReleased() {}
- override fun onPreviewLoadError(p0: Exception?) {}
- override fun onImageLoaded() {
- this@ViewHolder.touchOverlay.visibility = View.GONE
- this@ViewHolder.failureView.visibility = View.GONE
- }
+ fun bind(page: Page, serverIndex: Int) {
+ this.page = page
+ binding.chapterImage.apply {
+ recycle()
+ setMinimumDpi(90)
+ setMinimumTileDpi(180)
+ setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE)
+ setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE)
+ }
+ if (page.imageFileUri.isBlank() && page.imageUrls[serverIndex].isBlank()) {
+ binding.chapterImage.setImage(ImageSource.resource(R.drawable.broken_image_white_192x192))
+ return
+ }
+ var loader = Glide.with(binding.chapterImage).downloadOnly()
+ when {
+ page.imageFileUri.isNotBlank() -> loader = loader.load(page.imageFileUri)
+ page.imageUrls[serverIndex].isNotBlank() -> loader = loader.load(GlideUrl(page.imageUrls[serverIndex], glideHeaders))
+ }
+ val circularProgressDrawable = CircularProgressDrawable(binding.root.context).apply {
+ strokeWidth = 5f
+ centerRadius = 30f
+ start()
+ }
+ loader
+ .placeholder(circularProgressDrawable)
+ .into(object : CustomTarget() {
+ override fun onLoadCleared(placeholder: Drawable?) {
+ circularProgressDrawable.start()
+ }
- override fun onImageLoadError(p0: Exception?) {
- this@ViewHolder.touchOverlay.visibility = View.VISIBLE
- this@ViewHolder.failureView.visibility = View.VISIBLE
- onFail(Exception("Failed to load image from file"))
- }
+ override fun onLoadFailed(errorDrawable: Drawable?) {
+ circularProgressDrawable.stop()
+ binding.chapterImage.setImage(ImageSource.resource(R.drawable.broken_image_white_192x192))
}
- )
- setImageLoaderCallback(object : ImageLoader.Callback {
- override fun onFinish() {}
- override fun onCacheHit(image: File?) {}
- override fun onCacheMiss(image: File?) {}
- override fun onProgress(progress: Int) {}
- override fun onStart() {}
- override fun onSuccess(image: File?) {}
- override fun onFail(error: java.lang.Exception?) {
- this@ViewHolder.touchOverlay.visibility = View.VISIBLE
- this@ViewHolder.failureView.visibility = View.VISIBLE
- }
- })
- setProgressIndicator(ProgressPieIndicator())
- }
- }
- fun setImage(page: Page) {
- chapterImageView.apply {
- Glide.with(this).clear(this)
- ssiv.recycle()
- if (!page.imageFileUri.isBlank()) {
- showImage(Uri.parse(page.imageFileUri))
- } else if (!page.imageUrls[viewer!!.serverIndex!!].isBlank()) {
- showImage(Uri.parse(page.imageUrls[viewer!!.serverIndex!!]))
- }
- }
+ override fun onResourceReady(resource: File, transition: Transition?) {
+ circularProgressDrawable.stop()
+ binding.chapterImage.setImage(ImageSource.uri(Uri.fromFile(resource)))
+ }
+ })
}
}
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ReaderActivity.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ReaderActivity.kt
index 9867140..2b58122 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ReaderActivity.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ReaderActivity.kt
@@ -17,20 +17,14 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
-import com.crashlytics.android.Crashlytics
-import com.github.piasy.biv.BigImageViewer
import com.github.salomonbrys.kodein.conf.KodeinGlobalAware
-import com.github.salomonbrys.kodein.instance
import io.github.innoobwetrust.kintamanga.R
import io.github.innoobwetrust.kintamanga.databinding.ActivityReaderBinding
-import io.github.innoobwetrust.kintamanga.model.DownloadStatus
import io.github.innoobwetrust.kintamanga.source.SourceManager
import io.github.innoobwetrust.kintamanga.source.processor.ChapterInfoProcessor
import io.github.innoobwetrust.kintamanga.ui.manga.MangaInfoActivity
import io.github.innoobwetrust.kintamanga.ui.model.MangaBinding
-import io.github.innoobwetrust.kintamanga.util.GlideBitmapImageLoader
import io.github.innoobwetrust.kintamanga.util.extension.toast
-import kotlinx.android.synthetic.main.activity_reader.*
import rx.Observable
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
@@ -49,13 +43,13 @@ class ReaderActivity :
* If [.AUTO_HIDE] is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
- private const val AUTO_HIDE_DELAY_MILLIS = 3000
+ private const val AUTO_HIDE_DELAY_MILLIS = 3000L
/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
- private const val UI_ANIMATION_DELAY = 300
+ private const val UI_ANIMATION_DELAY = 150L
// Fragment tag
private const val CONTENT_VIEW_FRAGMENT_TAG = "CONTENT_VIEW_FRAGMENT_TAG"
@@ -92,6 +86,8 @@ class ReaderActivity :
private var startPage: Int? = null
private var timerDisposable: Subscription? = null
+ private lateinit var binding: ActivityReaderBinding
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (null == savedInstanceState) {
@@ -109,31 +105,31 @@ class ReaderActivity :
) as? MangaBinding ?: throw Exception("Error! mangaBinding not saved properly")
chapterIndex = savedInstanceState.getInt(SavedInstanceStates.CHAPTER_INDEX.key)
}
- val binding: ActivityReaderBinding =
+ binding =
DataBindingUtil.setContentView(this, R.layout.activity_reader)
binding.mangaBinding = mangaBinding
binding.executePendingBindings()
- setSupportActionBar(toolbar)
+ setSupportActionBar(binding.toolbar)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setDisplayShowHomeEnabled(true)
}
- fullscreen_content.setOnClickListener { toggle() }
+ binding.fullscreenContent.setOnClickListener { toggle() }
mVisible = true
setupChapterNavigationButtons()
- previousChapterButton.setOnClickListener {
+ binding.previousChapterButton.setOnClickListener {
--chapterIndex
reloadViewer()
startPage = -1
- delayHide()
+ hide(AUTO_HIDE_DELAY_MILLIS)
}
- nextChapterButton.setOnClickListener {
+ binding.nextChapterButton.setOnClickListener {
++chapterIndex
reloadViewer()
startPage = 0
- delayHide()
+ hide(AUTO_HIDE_DELAY_MILLIS)
}
- chapterSelectButton.setOnClickListener {
+ binding.chapterSelectButton.setOnClickListener {
AlertDialog.Builder(this, R.style.alertDialogStyle)
.setItems(
mangaBinding.chapters.map { it.chapterTitle }.toTypedArray()
@@ -141,12 +137,12 @@ class ReaderActivity :
chapterIndex = i
reloadViewer()
startPage = 0
- delayHide()
+ hide(AUTO_HIDE_DELAY_MILLIS)
}
.create()
.show()
}
- changeViewerTypeButton.setOnClickListener {
+ binding.changeViewerTypeButton.setOnClickListener {
if ((0..(ViewerTypes.values().size - 2)).contains(mangaBinding.mangaViewer)) {
++mangaBinding.mangaViewer
} else {
@@ -154,9 +150,9 @@ class ReaderActivity :
}
doFragmentTransaction()
onViewerTypeChanged()
- delayHide()
+ hide(AUTO_HIDE_DELAY_MILLIS)
}
- pageSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
+ binding.pageSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(
seekBar: SeekBar?,
progress: Int,
@@ -168,38 +164,10 @@ class ReaderActivity :
newPosition = progress,
progressFeedback = false
)
- delayHide()
+ hide(AUTO_HIDE_DELAY_MILLIS)
}
- pageIndicator.text =
+ binding.pageIndicator.text =
getString(R.string.reader_page_indicator_text, progress + 1, max + 1)
- if (chapterBinding.chapterPages.isNotEmpty() &&
- DownloadStatus.DOWNLOADED != chapterBinding.chapterDownloadStatus) {
- try {
- BigImageViewer.prefetch(
- *chapterBinding.chapterPages
- .map { Uri.parse(it.imageUrls[serverIndex]) }
- .filterIndexed { index, _ ->
- index in ((progress - 2).coerceAtLeast(0))..
- ((progress + 2).coerceAtMost(chapterBinding.chapterPages.size - 1))
- }
- .foldIndexed(
- Array(5) { Uri.EMPTY },
- { i: Int, acc: Array, uri: Uri ->
- acc[when (i) {
- 2 -> 0
- 3 -> 1
- 4 -> 2
- 1 -> 3
- 0 -> 4
- else -> 0
- }] = uri
- acc
- }
- )
- )
- } catch (e: Exception) {
- }
- }
}
}
@@ -211,9 +179,6 @@ class ReaderActivity :
override fun onResume() {
super.onResume()
- BigImageViewer.initialize(
- GlideBitmapImageLoader.with(applicationContext, instance("chapter"))
- )
doFragmentTransaction()
if (chapterBinding.chapterPages.isEmpty()) {
backgroundRefresh(
@@ -257,7 +222,6 @@ class ReaderActivity :
override fun onPause() {
disposeAllLoaderDisposables()
timerDisposable?.run { if (!isUnsubscribed) unsubscribe() }
- (BigImageViewer.imageLoader() as? GlideBitmapImageLoader)?.cancelPrefetch()
mContentFragment?.let {
supportFragmentManager.beginTransaction()
.remove(it)
@@ -269,23 +233,24 @@ class ReaderActivity :
}
private fun doFragmentTransaction() {
- mContentFragment = ViewerFragment.newInstance()
+ val viewerFragment = ViewerFragment.newInstance()
+ mContentFragment = viewerFragment
supportFragmentManager
.beginTransaction()
- .replace(R.id.fullscreen_content, mContentFragment as ViewerFragment, CONTENT_VIEW_FRAGMENT_TAG)
+ .replace(binding.fullscreenContent.id, viewerFragment, CONTENT_VIEW_FRAGMENT_TAG)
.commitNowAllowingStateLoss()
}
private fun setupChapterNavigationButtons() {
if (chapterIndex > 0) {
- previousChapterButton?.visibility = View.VISIBLE
+ binding.previousChapterButton.visibility = View.VISIBLE
} else {
- previousChapterButton?.visibility = View.INVISIBLE
+ binding.previousChapterButton.visibility = View.INVISIBLE
}
if (chapterIndex < mangaBinding.chapters.size - 1) {
- nextChapterButton?.visibility = View.VISIBLE
+ binding.nextChapterButton.visibility = View.VISIBLE
} else {
- nextChapterButton?.visibility = View.INVISIBLE
+ binding.nextChapterButton.visibility = View.INVISIBLE
}
}
@@ -300,8 +265,8 @@ class ReaderActivity :
.toList()
)
chapterServerChooserAdapter.setDropDownViewResource(R.layout.themed_spinner_dropdown_item)
- chapterServerChooser?.adapter = chapterServerChooserAdapter
- chapterServerChooser?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ binding.chapterServerChooser.adapter = chapterServerChooserAdapter
+ binding.chapterServerChooser.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {}
override fun onItemSelected(
parent: AdapterView<*>?,
@@ -315,7 +280,7 @@ class ReaderActivity :
}
private fun onViewerTypeChanged() {
- changeViewerTypeButton?.setImageResource(
+ binding.changeViewerTypeButton.setImageResource(
when (mangaBinding.mangaViewer) {
ViewerTypes.PAGER_HORIZONTAL_LEFT_TO_RIGHT.ordinal,
ViewerTypes.PAGER_HORIZONTAL_RIGHT_TO_LEFT.ordinal ->
@@ -325,18 +290,18 @@ class ReaderActivity :
else -> R.drawable.ic_view_carousel_white_24dp
}
)
- viewerTypeIndicator?.setImageResource(
+ binding.viewerTypeIndicator.setImageResource(
when (mangaBinding.mangaViewer) {
ViewerTypes.PAGER_HORIZONTAL_LEFT_TO_RIGHT.ordinal ->
if (ViewCompat.LAYOUT_DIRECTION_RTL
- == ViewCompat.getLayoutDirection(viewerTypeIndicator)) {
+ == ViewCompat.getLayoutDirection(binding.viewerTypeIndicator)) {
R.drawable.ic_arrow_back_white_24dp
} else {
R.drawable.ic_arrow_forward_white_24dp
}
ViewerTypes.PAGER_HORIZONTAL_RIGHT_TO_LEFT.ordinal ->
if (ViewCompat.LAYOUT_DIRECTION_RTL
- == ViewCompat.getLayoutDirection(viewerTypeIndicator)) {
+ == ViewCompat.getLayoutDirection(binding.viewerTypeIndicator)) {
R.drawable.ic_arrow_forward_white_24dp
} else {
R.drawable.ic_arrow_back_white_24dp
@@ -346,17 +311,17 @@ class ReaderActivity :
else -> R.drawable.ic_arrow_forward_white_24dp
}
)
- viewerTypeIndicatorCard?.visibility = View.VISIBLE
+ binding.viewerTypeIndicatorCard.visibility = View.VISIBLE
timerDisposable?.run { if (!isUnsubscribed) unsubscribe() }
timerDisposable = Observable.timer(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe { viewerTypeIndicatorCard?.visibility = View.GONE }
+ .subscribe { binding.viewerTypeIndicatorCard.visibility = View.GONE }
}
private fun reloadViewer() {
setupChapterNavigationButtons()
- chapterStatusAndTitle?.text = getText(R.string.chapter_loading_text)
+ binding.chapterStatusAndTitle.text = getText(R.string.chapter_loading_text)
backgroundRefresh(
context = this,
onChapterLoaded = onChapterLoaded,
@@ -367,16 +332,16 @@ class ReaderActivity :
private val onChapterLoaded: (Boolean) -> Unit = { success ->
if (success) {
if (chapterBinding.chapterPages.isEmpty()) {
- chapterStatusAndTitle?.text = getText(R.string.chapter_load_empty_text)
+ binding.chapterStatusAndTitle.text = getText(R.string.chapter_load_empty_text)
toast(R.string.chapter_load_empty_text)
} else {
onViewerTypeChanged()
- chapterStatusAndTitle?.text = chapterBinding.chapterTitle
- chapterCommentFab?.setOnClickListener {
+ binding.chapterStatusAndTitle.text = chapterBinding.chapterTitle
+ binding.chapterCommentFab.setOnClickListener {
val commentIntent = Intent(Intent.ACTION_VIEW, Uri.parse(chapterBinding.chapterUri))
startActivity(commentIntent)
}
- pageSeekBar?.max = chapterBinding.chapterPages.size - 1
+ binding.pageSeekBar.max = chapterBinding.chapterPages.size - 1
when (startPage) {
-1 -> chapterBinding.chapterLastPageRead = chapterBinding.chapterPages.size - 1
0 -> chapterBinding.chapterLastPageRead = 0
@@ -389,22 +354,21 @@ class ReaderActivity :
?.size
?: 1
Timber.v("number of servers: $numServer")
- delayedHide(1000)
+ hide(1000)
}
} else {
- chapterStatusAndTitle?.text = getText(R.string.chapter_load_failed_text)
+ binding.chapterStatusAndTitle.text = getText(R.string.chapter_load_failed_text)
toast(R.string.chapter_load_failed_text)
}
}
private val onChapterLoadError: (Throwable) -> Unit = { error ->
- chapterStatusAndTitle?.text = getText(R.string.chapter_load_error_text)
+ binding.chapterStatusAndTitle.text = getText(R.string.chapter_load_error_text)
toast(R.string.chapter_load_error_text)
Timber.e(error)
- Crashlytics.logException(error)
}
override fun onViewerPageChanged(newPagePosition: Int) {
- pageSeekBar?.progress = newPagePosition
+ binding.pageSeekBar.progress = newPagePosition
}
override fun onTapPreviousPage() {
@@ -423,75 +387,54 @@ class ReaderActivity :
private val mHideHandler = Handler()
private val mHidePart2Runnable = Runnable {
- // Delayed removal of status and navigation bar
-
// Note that some of these constants are new as of API 16 (Jelly Bean)
// and API 19 (KitKat). It is safe to use them, as they are inlined
// at compile-time and do nothing on earlier devices.
- fullscreen_content?.systemUiVisibility =
+ binding.fullscreenContent.systemUiVisibility =
View.SYSTEM_UI_FLAG_LOW_PROFILE or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ supportActionBar?.hide()
+ binding.fullscreenStatus.visibility = View.GONE
+ binding.fullscreenContentControls.visibility = View.GONE
+ binding.chapterCommentFab.hide()
}
private val mShowPart2Runnable = Runnable {
// Delayed display of UI elements
+ binding.fullscreenContent.systemUiVisibility =
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
supportActionBar?.show()
- fullscreen_status?.visibility = View.VISIBLE
- mangaTitle?.isSelected = true
- chapterStatusAndTitle?.isSelected = true
- fullscreen_content_controls?.visibility = View.VISIBLE
- chapterCommentFab?.show()
+ binding.fullscreenStatus.visibility = View.VISIBLE
+ binding.mangaTitle.isSelected = true
+ binding.chapterStatusAndTitle.isSelected = true
+ binding.fullscreenContentControls.visibility = View.VISIBLE
+ binding.chapterCommentFab.show()
}
+
private var mVisible: Boolean = false
- private val mHideRunnable = Runnable { hide() }
- /**
- * Delay hiding the system UI. This is to prevent the
- * jarring behavior of controls going away
- * while interacting with activity UI.
- */
- private fun delayHide() {
- delayedHide(AUTO_HIDE_DELAY_MILLIS)
- }
private fun toggle() = when (mVisible) {
true -> hide()
false -> show()
}
- private fun hide() {
- // Hide UI first
- supportActionBar?.hide()
- fullscreen_status?.visibility = View.GONE
- fullscreen_content_controls?.visibility = View.GONE
- chapterCommentFab?.hide()
+ private fun hide(delay: Long = UI_ANIMATION_DELAY) {
mVisible = false
-
// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.removeCallbacks(mShowPart2Runnable)
- mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY.toLong())
+ mHideHandler.postDelayed(mHidePart2Runnable, delay)
}
@SuppressLint("InlinedApi")
- private fun show() {
+ private fun show(delay: Long = UI_ANIMATION_DELAY) {
// Show the system bar
- fullscreen_content?.systemUiVisibility =
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
mVisible = true
// Schedule a runnable to display UI elements after a delay
mHideHandler.removeCallbacks(mHidePart2Runnable)
- mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY.toLong())
- }
-
- /**
- * Schedules a call to hide() in [delayMillis] milliseconds, canceling any
- * previously scheduled calls.
- */
- private fun delayedHide(delayMillis: Int) {
- mHideHandler.removeCallbacks(mHideRunnable)
- mHideHandler.postDelayed(mHideRunnable, delayMillis.toLong())
+ mHideHandler.postDelayed(mShowPart2Runnable, delay)
}
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ViewerFragment.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ViewerFragment.kt
index d9ec8e7..1d9ac59 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ViewerFragment.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/ui/reader/ViewerFragment.kt
@@ -1,16 +1,24 @@
package io.github.innoobwetrust.kintamanga.ui.reader
import android.content.Context
+import android.net.Uri
import android.os.Bundle
import android.view.*
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
-import io.github.innoobwetrust.kintamanga.R
+import com.bumptech.glide.Glide
+import com.bumptech.glide.ListPreloader
+import com.bumptech.glide.RequestBuilder
+import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader
+import com.bumptech.glide.load.model.Headers
+import com.bumptech.glide.load.model.LazyHeaders
+import com.bumptech.glide.util.ViewPreloadSizeProvider
+import io.github.innoobwetrust.kintamanga.databinding.FragmentImageViewerBinding
+import io.github.innoobwetrust.kintamanga.model.Page
import io.github.innoobwetrust.kintamanga.ui.model.ChapterBinding
-import kotlinx.android.synthetic.main.fragment_image_viewer.*
-import kotlinx.android.synthetic.main.fragment_image_viewer.view.*
+import java.io.File
import kotlin.math.abs
class ViewerFragment : Fragment(), ReaderActivityListener {
@@ -24,8 +32,18 @@ class ViewerFragment : Fragment(), ReaderActivityListener {
get() = mReader?.mangaBinding?.mangaViewer
private val chapterBinding: ChapterBinding?
get() = mReader?.chapterBinding
- val serverIndex: Int?
- get() = mReader?.serverIndex
+ private val glideHeaders: Headers?
+ get() = (activity as? ReaderActivity)
+ ?.chapterInfoProcessor
+ ?.headers()
+ ?.fold(
+ LazyHeaders.Builder(),
+ { builder: LazyHeaders.Builder, pair: Pair ->
+ builder.addHeader(pair.first, pair.second)
+ })
+ ?.build()
+ val serverIndex: Int
+ get() = mReader?.serverIndex ?: 0
private val pagerSnapHelper: PagerSnapHelper by lazy {
object : PagerSnapHelper() {
override fun findTargetSnapPosition(
@@ -115,33 +133,12 @@ class ViewerFragment : Fragment(), ReaderActivityListener {
}
}
+ private lateinit var binding: FragmentImageViewerBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?): View? {
- return inflateView(inflater = inflater, container = container)
- }
-
- override fun onResume() {
- super.onResume()
- syncPosition(newPosition = null)
- }
-
- override fun onDestroyView() {
- imageViewerRecyclerView?.adapter = null
- super.onDestroyView()
- System.gc()
- }
-
- override fun onDetach() {
- mReader = null
- imageViewerRecyclerView?.adapter = null
- super.onDetach()
- System.gc()
- }
-
- private fun inflateView(inflater: LayoutInflater?, container: ViewGroup?): View? {
+ savedInstanceState: Bundle?): View {
// Always re-create RecyclerVew to sync position, this won't require much computation
- val view = inflater!!.inflate(R.layout.fragment_image_viewer, container, false)
- view.imageViewerRecyclerView?.apply {
+ binding = FragmentImageViewerBinding.inflate(inflater, container, false)
+ binding.imageViewerRecyclerView.apply {
setHasFixedSize(true)
layoutManager = when (mViewerType) {
ViewerTypes.PAGER_HORIZONTAL_LEFT_TO_RIGHT.ordinal ->
@@ -158,6 +155,7 @@ class ViewerFragment : Fragment(), ReaderActivityListener {
adapter = ImageViewerAdapter(
viewer = this@ViewerFragment,
chapterBinding = chapterBinding!!,
+ glideHeaders = glideHeaders,
viewerType = ViewerTypes.values()[mViewerType ?: 0]
)
// Sync position
@@ -179,9 +177,47 @@ class ViewerFragment : Fragment(), ReaderActivityListener {
}
}
})
+ addOnScrollListener(RecyclerViewPreloader(Glide.with(this), object : ListPreloader.PreloadModelProvider {
+ override fun getPreloadItems(position: Int): List {
+ return chapterBinding?.chapterPages?.get(position)?.run { listOf(this) }
+ ?: emptyList()
+ }
+
+ override fun getPreloadRequestBuilder(page: Page): RequestBuilder {
+ return Glide.with(this@ViewerFragment).downloadOnly().load(when {
+ page.imageFileUri.isNotBlank() -> {
+ Uri.parse(page.imageFileUri)
+ }
+ page.imageUrls[this@ViewerFragment.serverIndex].isNotBlank() -> {
+ Uri.parse(page.imageUrls[this@ViewerFragment.serverIndex])
+ }
+ else -> {
+ Uri.EMPTY
+ }
+ })
+ }
+ }, ViewPreloadSizeProvider(), 10))
}
}
- return view
+ return binding.root
+ }
+
+ override fun onResume() {
+ super.onResume()
+ syncPosition(newPosition = null)
+ }
+
+ override fun onDestroyView() {
+ binding.imageViewerRecyclerView.adapter = null
+ super.onDestroyView()
+ System.gc()
+ }
+
+ override fun onDetach() {
+ mReader = null
+ binding.imageViewerRecyclerView.adapter = null
+ super.onDetach()
+ System.gc()
}
fun syncPosition(newPosition: Int?, progressFeedback: Boolean = true) {
@@ -197,13 +233,13 @@ class ViewerFragment : Fragment(), ReaderActivityListener {
mReader?.onViewerPageChanged(newPagePosition = it.chapterLastPageRead)
}
if (pagesJump == 1)
- imageViewerRecyclerView?.smoothScrollToPosition(it.chapterLastPageRead)
+ binding.imageViewerRecyclerView.smoothScrollToPosition(it.chapterLastPageRead)
else
- imageViewerRecyclerView?.scrollToPosition(it.chapterLastPageRead)
+ binding.imageViewerRecyclerView.scrollToPosition(it.chapterLastPageRead)
}
}
override fun onImageLoaded(position: Int) {
- imageViewerRecyclerView?.adapter?.notifyItemChanged(position)
+ binding.imageViewerRecyclerView.adapter?.notifyItemChanged(position)
}
}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/util/GlideBitmapImageLoader.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/util/GlideBitmapImageLoader.kt
deleted file mode 100644
index 70f30df..0000000
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/util/GlideBitmapImageLoader.kt
+++ /dev/null
@@ -1,286 +0,0 @@
-package io.github.innoobwetrust.kintamanga.util
-
-import android.content.Context
-import android.graphics.drawable.Drawable
-import android.net.Uri
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.ImageView
-import com.bumptech.glide.Glide
-import com.bumptech.glide.RequestManager
-import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
-import com.bumptech.glide.load.model.GlideUrl
-import com.bumptech.glide.request.target.CustomTarget
-import com.bumptech.glide.request.transition.Transition
-import com.crashlytics.android.Crashlytics
-import com.github.piasy.biv.loader.ImageLoader
-import com.github.piasy.biv.view.BigImageView
-import io.github.innoobwetrust.kintamanga.R
-import okhttp3.*
-import okhttp3.ResponseBody.Companion.toResponseBody
-import okio.*
-import rx.Observable
-import rx.android.schedulers.AndroidSchedulers
-import rx.schedulers.Schedulers
-import timber.log.Timber
-import java.io.File
-import java.io.IOException
-import java.io.InputStream
-import java.util.*
-
-class GlideBitmapImageLoader private constructor(
- context: Context,
- okHttpClient: OkHttpClient?
-) : ImageLoader {
- private val mRequestManager: RequestManager
- private val prefetchTargets: MutableList>> = mutableListOf()
-
- init {
- GlideProgressSupport.init(Glide.get(context), okHttpClient)
- mRequestManager = Glide.with(context)
- }
-
- override fun loadImage(uri: Uri, callback: ImageLoader.Callback) {
- mRequestManager
- .downloadOnly()
- .load(uri)
- .into(object : ImageDownloadTarget(uri.toString()) {
- override fun onResourceReady(resource: File, transition: Transition?) {
- resource.let {
- Observable
- .fromCallable {
- ImageConverter.convertToSupportedImage(source = it)
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { success ->
- if (success) {
- callback.onCacheHit(it)
- callback.onSuccess(it)
- } else {
- callback.onFail(Exception("Failed to convert image to bitmap"))
- }
- },
- { error ->
- Timber.e(error)
- Crashlytics.logException(error)
- callback.onFail(Exception("Failed to convert image to bitmap"))
- }
- )
- }
- }
-
- override fun onLoadFailed(errorDrawable: Drawable?) {
- callback.onFail(Exception("Failed to load image"))
- }
-
- override fun onDownloadStart() {
- callback.onStart()
- }
-
- override fun onProgress(progress: Int) {
- callback.onProgress(progress)
- }
-
- override fun onDownloadFinish() {
- callback.onFinish()
- }
- })
- }
-
- override fun showThumbnail(parent: BigImageView, thumbnail: Uri, scaleType: Int): View {
- val thumbnailView = LayoutInflater.from(parent.context)
- .inflate(R.layout.ui_glide_thumbnail, parent, false) as ImageView
- when (scaleType) {
- BigImageView.INIT_SCALE_TYPE_CENTER_CROP ->
- thumbnailView.scaleType = ImageView.ScaleType.CENTER_CROP
- BigImageView.INIT_SCALE_TYPE_CENTER_INSIDE ->
- thumbnailView.scaleType = ImageView.ScaleType.CENTER_INSIDE
- }
- mRequestManager
- .load(thumbnail)
- .into(thumbnailView)
- return thumbnailView
- }
-
- override fun prefetch(uri: Uri) {
- if(prefetchTargets.none { it.first == uri }) {
- mRequestManager
- .downloadOnly()
- .load(uri)
- .into(object : CustomTarget() {
- override fun onResourceReady(resource: File, transition: Transition?) {
- ImageConverter.convertToSupportedImage(resource)
- }
-
- override fun onLoadCleared(placeholder: Drawable?) {}
- }.also {
- if (prefetchTargets.size > 7)
- mRequestManager.clear(prefetchTargets.removeAt(0).second)
- prefetchTargets.add(uri to it)
- })
- }
- }
-
- fun cancelPrefetch() {
- prefetchTargets.forEach {
- mRequestManager.clear(it.second)
- }
- prefetchTargets.clear()
- }
-
- companion object {
- @JvmOverloads
- fun with(
- context: Context,
- okHttpClient: OkHttpClient? = null
- ): GlideBitmapImageLoader {
- return GlideBitmapImageLoader(context, okHttpClient)
- }
- }
-}
-
-object GlideProgressSupport {
- private fun createInterceptor(listener: ResponseProgressListener): Interceptor {
- return Interceptor { chain ->
- val request = chain.request()
- val response = chain.proceed(request)
- response.newBuilder()
- .body(OkHttpProgressResponseBody(
- request.url,
- response.body ?: "".toResponseBody(null),
- listener
- ))
- .build()
- }
- }
-
- fun init(glide: Glide, okHttpClient: OkHttpClient?) {
- val builder: OkHttpClient.Builder = okHttpClient?.newBuilder() ?: OkHttpClient.Builder()
- builder.addNetworkInterceptor(createInterceptor(DispatchingProgressListener()))
- glide.registry.replace(
- GlideUrl::class.java,
- InputStream::class.java,
- OkHttpUrlLoader.Factory(builder.build())
- )
- }
-
- fun forget(url: String) {
- DispatchingProgressListener.forget(url)
- }
-
- fun expect(url: String, listener: ProgressListener) {
- DispatchingProgressListener.expect(url, listener)
- }
-
- interface ProgressListener {
- fun onDownloadStart()
-
- fun onProgress(progress: Int)
-
- fun onDownloadFinish()
- }
-
- private interface ResponseProgressListener {
- fun update(url: HttpUrl, bytesRead: Long, contentLength: Long)
- }
-
- private class DispatchingProgressListener : ResponseProgressListener {
-
- override fun update(url: HttpUrl, bytesRead: Long, contentLength: Long) {
- val key = url.toString()
- val listener = LISTENERS[key] ?: return
-
- val lastProgress = PROGRESSES[key]
- if (lastProgress == null) {
- // ensure `onStart` is called before `onProgress` and `onFinish`
- listener.onDownloadStart()
- }
- if (contentLength <= bytesRead) {
- listener.onDownloadFinish()
- forget(key)
- return
- }
- val progress = (bytesRead.toFloat() / contentLength * 100).toInt()
- if (lastProgress == null || progress != lastProgress) {
- PROGRESSES[key] = progress
- listener.onProgress(progress)
- }
- }
-
- companion object {
- private val LISTENERS = HashMap()
- private val PROGRESSES = HashMap()
-
- internal fun forget(url: String) {
- LISTENERS.remove(url)
- PROGRESSES.remove(url)
- }
-
- internal fun expect(url: String, listener: ProgressListener) {
- LISTENERS[url] = listener
- }
- }
- }
-
- private class OkHttpProgressResponseBody internal constructor(
- private val mUrl: HttpUrl,
- private val mResponseBody: ResponseBody,
- private val mProgressListener: ResponseProgressListener
- ) : ResponseBody() {
- private var mBufferedSource: BufferedSource? = null
-
- override fun contentType(): MediaType? {
- return mResponseBody.contentType()
- }
-
- override fun contentLength(): Long {
- return mResponseBody.contentLength()
- }
-
- override fun source(): BufferedSource {
- return mBufferedSource
- ?: source(mResponseBody.source()).buffer()
- .also { mBufferedSource = it }
- }
-
- private fun source(source: Source): Source {
- return object : ForwardingSource(source) {
- private var mTotalBytesRead = 0L
-
- @Throws(IOException::class)
- override fun read(sink: Buffer, byteCount: Long): Long {
- val bytesRead = super.read(sink, byteCount)
- val fullLength = mResponseBody.contentLength()
- if (bytesRead == -1L) { // this source is exhausted
- mTotalBytesRead = fullLength
- } else {
- mTotalBytesRead += bytesRead
- }
- mProgressListener.update(mUrl, mTotalBytesRead, fullLength)
- return bytesRead
- }
- }
- }
- }
-}
-
-abstract class ImageDownloadTarget protected constructor(private val mUrl: String) :
- CustomTarget(),
- GlideProgressSupport.ProgressListener {
-
- override fun onLoadCleared(placeholder: Drawable?) {
- GlideProgressSupport.forget(mUrl)
- }
-
- override fun onLoadStarted(placeholder: Drawable?) {
- super.onLoadStarted(placeholder)
- GlideProgressSupport.expect(mUrl, this)
- }
-
- override fun onLoadFailed(errorDrawable: Drawable?) {
- super.onLoadFailed(errorDrawable)
- GlideProgressSupport.forget(mUrl)
- }
-}
diff --git a/app/src/main/java/io/github/innoobwetrust/kintamanga/util/extension/StringExtensions.kt b/app/src/main/java/io/github/innoobwetrust/kintamanga/util/extension/StringExtensions.kt
index cd9308c..073a143 100644
--- a/app/src/main/java/io/github/innoobwetrust/kintamanga/util/extension/StringExtensions.kt
+++ b/app/src/main/java/io/github/innoobwetrust/kintamanga/util/extension/StringExtensions.kt
@@ -1,6 +1,5 @@
package io.github.innoobwetrust.kintamanga.util.extension
-import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.net.URI
import java.net.URL
@@ -17,7 +16,6 @@ val String.uriString: String
}
} catch (e: Exception) {
Timber.e("$this: $e")
- Crashlytics.logException(e)
""
}
@@ -32,7 +30,6 @@ fun String.uriString(context: URL): String = if (isBlank()) "" else try {
}
} catch (e: Exception) {
Timber.e("$this: $e")
- Crashlytics.logException(e)
""
}
@@ -47,4 +44,4 @@ fun String.chop(count: Int, replacement: String = "..."): String {
else
this
-}
\ No newline at end of file
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 88cf31e..810c6c7 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -9,7 +9,8 @@
android:fitsSystemWindows="true"
tools:openDrawer="start">
-
+
-
-
-
-
-
-
-
-
-
-
diff --git a/build.gradle b/build.gradle
index 28f4612..d7cb800 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,37 +1,37 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.72'
- ext.gradle_version = '3.6.3'
+ ext.kotlin_version = '1.4.21'
+ ext.gradle_version = '4.1.1'
repositories {
jcenter()
maven { url "https://maven.google.com" }
- maven { url 'https://maven.fabric.io/public' }
google()
}
dependencies {
- classpath "com.android.tools.build:gradle:$gradle_version"
+ classpath "com.android.tools.build:gradle:${gradle_version}"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
- classpath 'com.google.gms:google-services:4.3.3'
- classpath 'com.google.firebase:firebase-plugins:2.0.0'
- classpath 'io.fabric.tools:gradle:1.28.1'
}
}
allprojects {
repositories {
+ // Note: please put this download url at the first of your repositories part, otherwise, gradle may search in wrong place.
+ maven { url "http://dl.bintray.com/piasy/maven" }
jcenter()
+ google()
+ mavenCentral()
maven { url "https://jitpack.io" }
- maven { url "http://dl.bintray.com/piasy/maven" }
maven { url "https://maven.google.com" }
- google()
}
}
+apply from: 'versioning.gradle'
+
task clean(type: Delete) {
delete rootProject.buildDir
}
diff --git a/gradle.properties b/gradle.properties
index 2898ad2..f3f1c4c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -21,3 +21,5 @@ org.gradle.daemon=true
org.gradle.configureondemand=true
android.useAndroidX=true
android.enableJetifier=true
+
+version=1.3.12
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4ec43c0..f44da4b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sat Apr 18 20:24:19 ICT 2020
+#Wed Dec 09 23:32:10 ICT 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
diff --git a/versioning.gradle b/versioning.gradle
new file mode 100644
index 0000000..80ddc88
--- /dev/null
+++ b/versioning.gradle
@@ -0,0 +1,37 @@
+// Source: https://github.com/jayway/AndroidGradleExample/blob/master/versioning.gradle
+ext {
+ /**
+ * Builds an Android version code from the version of the project.
+ * This is designed to handle the -SNAPSHOT and -RC format.
+ *
+ * I.e. during development the version ends with -SNAPSHOT. As the code stabilizes and release nears
+ * one or many Release Candidates are tagged. These all end with "-RC1", "-RC2" etc.
+ * And the final release is without any suffix.
+ * @return
+ */
+ buildVersionCode = {
+ //The rules is as follows:
+ //-SNAPSHOT counts as 0
+ //-RC* counts as the RC number, i.e. 1 to 98
+ //final release counts as 99.
+ //Thus you can only have 98 Release Candidates, which ought to be enough for everyone
+
+ def candidate = "99"
+ def (major, minor, patch) = version.toLowerCase().replaceAll('-', '').tokenize('.')
+ if (patch.endsWith("snapshot")) {
+ candidate = "0"
+ patch = patch.replaceAll("[^0-9]","")
+ } else {
+ def rc
+ (patch, rc) = patch.tokenize("rc")
+ if (rc) {
+ candidate = rc
+ }
+ }
+
+ (major, minor, patch, candidate) = [major, minor, patch, candidate].collect{it.toInteger()}
+
+ (major * 1000000) + (minor * 10000) + (patch * 100) + candidate
+ }
+}
+