Image loading optimization
This commit is contained in:
@@ -32,10 +32,13 @@ android {
|
|||||||
versionNameSuffix "-DEBUG"
|
versionNameSuffix "-DEBUG"
|
||||||
|
|
||||||
buildConfigField('Boolean', 'CENSOR', 'false')
|
buildConfigField('Boolean', 'CENSOR', 'false')
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources true
|
shrinkResources true
|
||||||
|
|
||||||
|
buildConfigField('Boolean', 'CENSOR', 'false')
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,16 +74,18 @@ dependencies {
|
|||||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
|
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
|
||||||
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
|
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
|
||||||
implementation 'com.github.clans:fab:1.6.4'
|
implementation 'com.github.clans:fab:1.6.4'
|
||||||
|
|
||||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||||
implementation ("com.github.bumptech.glide:recyclerview-integration:4.10.0") {
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
||||||
|
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
||||||
|
implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation 'net.rdrei.android.dirchooser:library:3.2@aar'
|
implementation 'net.rdrei.android.dirchooser:library:3.2@aar'
|
||||||
implementation 'com.gu:option:1.3'
|
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||||
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
|
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
|
||||||
implementation "ru.noties.markwon:core:${markwonVersion}"
|
implementation "ru.noties.markwon:core:${markwonVersion}"
|
||||||
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
|
||||||
testImplementation 'junit:junit:4.13'
|
testImplementation 'junit:junit:4.13'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||||
|
|||||||
9
app/proguard-rules.pro
vendored
9
app/proguard-rules.pro
vendored
@@ -18,4 +18,11 @@
|
|||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
# If you keep the line number information, uncomment this to
|
||||||
# hide the original source file name.
|
# hide the original source file name.
|
||||||
#-renamesourcefileattribute SourceFile
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
|
-keep public class * implements com.bumptech.glide.module.GlideModule
|
||||||
|
-keep public class * extends com.bumptech.glide.module.AppGlideModule
|
||||||
|
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
|
||||||
|
**[] $VALUES;
|
||||||
|
public *;
|
||||||
|
}
|
||||||
@@ -71,15 +71,15 @@ class GalleryBlockAdapter(context: Context, private val galleries: List<GalleryB
|
|||||||
inner class GalleryViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
inner class GalleryViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||||
var timerTask: TimerTask? = null
|
var timerTask: TimerTask? = null
|
||||||
|
|
||||||
private fun updateProgress(context: Context, galleryID: Int) = CoroutineScope(Dispatchers.IO).launch {
|
private fun updateProgress(context: Context, galleryID: Int) {
|
||||||
val cache = Cache(context).getCachedGallery(galleryID)
|
val cache = Cache(context).getCachedGallery(galleryID)
|
||||||
val reader = Cache(context).getReaderOrNull(galleryID)
|
val reader = Cache(context).getReaderOrNull(galleryID)
|
||||||
|
|
||||||
launch(Dispatchers.Main) main@{
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
if (reader == null) {
|
if (reader == null) {
|
||||||
view.galleryblock_progressbar.visibility = View.GONE
|
view.galleryblock_progressbar.visibility = View.GONE
|
||||||
view.galleryblock_progress_complete.visibility = View.GONE
|
view.galleryblock_progress_complete.visibility = View.GONE
|
||||||
return@main
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
with(view.galleryblock_progressbar) {
|
with(view.galleryblock_progressbar) {
|
||||||
|
|||||||
@@ -48,19 +48,15 @@ import kotlin.math.roundToInt
|
|||||||
class ReaderAdapter(private val context: Context,
|
class ReaderAdapter(private val context: Context,
|
||||||
private val galleryID: Int) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
|
private val galleryID: Int) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
val glide = Glide.with(context)
|
||||||
|
|
||||||
//region Glide.RecyclerView
|
//region Glide.RecyclerView
|
||||||
inner class SizeProvider : ListPreloader.PreloadSizeProvider<File> {
|
val sizeProvider = ListPreloader.PreloadSizeProvider<File> { _, _, position ->
|
||||||
|
Cache(context).getReaderOrNull(galleryID)?.galleryInfo?.getOrNull(position)?.let {
|
||||||
override fun getPreloadSize(item: File, adapterPosition: Int, itemPosition: Int): IntArray? {
|
arrayOf(it.width, it.height).toIntArray()
|
||||||
return Cache(context).getReaderOrNull(galleryID)?.galleryInfo?.getOrNull(itemPosition)?.let {
|
|
||||||
arrayOf(it.width, it.height).toIntArray()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
val modelProvider = object: ListPreloader.PreloadModelProvider<File> {
|
||||||
inner class ModelProvider : ListPreloader.PreloadModelProvider<File> {
|
|
||||||
|
|
||||||
override fun getPreloadItems(position: Int): MutableList<File> {
|
override fun getPreloadItems(position: Int): MutableList<File> {
|
||||||
return listOf(Cache(context).getImages(galleryID)?.get(position)).filterNotNullTo(mutableListOf())
|
return listOf(Cache(context).getImages(galleryID)?.get(position)).filterNotNullTo(mutableListOf())
|
||||||
}
|
}
|
||||||
@@ -76,18 +72,13 @@ class ReaderAdapter(private val context: Context,
|
|||||||
override(5, 8)
|
override(5, 8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
val preloader = RecyclerViewPreloader<File>(glide, modelProvider, sizeProvider, 10)
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
var reader: Reader? = null
|
var reader: Reader? = null
|
||||||
val glide = Glide.with(context)
|
|
||||||
val timer = Timer()
|
val timer = Timer()
|
||||||
|
|
||||||
val sizeProvider = SizeProvider()
|
|
||||||
val modelProvider = ModelProvider()
|
|
||||||
val preloader = RecyclerViewPreloader<File>(glide, modelProvider, sizeProvider, 10)
|
|
||||||
|
|
||||||
var isFullScreen = false
|
var isFullScreen = false
|
||||||
|
|
||||||
var onItemClickListener : ((Int) -> (Unit))? = null
|
var onItemClickListener : ((Int) -> (Unit))? = null
|
||||||
@@ -114,10 +105,13 @@ class ReaderAdapter(private val context: Context,
|
|||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
holder.view as ConstraintLayout
|
holder.view as ConstraintLayout
|
||||||
|
|
||||||
if (isFullScreen)
|
if (isFullScreen) {
|
||||||
holder.view.layoutParams.height = RecyclerView.LayoutParams.MATCH_PARENT
|
holder.view.layoutParams.height = RecyclerView.LayoutParams.MATCH_PARENT
|
||||||
else
|
holder.view.container.layoutParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT
|
||||||
|
} else {
|
||||||
holder.view.layoutParams.height = RecyclerView.LayoutParams.WRAP_CONTENT
|
holder.view.layoutParams.height = RecyclerView.LayoutParams.WRAP_CONTENT
|
||||||
|
holder.view.container.layoutParams.height = 0
|
||||||
|
}
|
||||||
|
|
||||||
holder.view.image.setOnPhotoTapListener { _, _, _ ->
|
holder.view.image.setOnPhotoTapListener { _, _, _ ->
|
||||||
onItemClickListener?.invoke(position)
|
onItemClickListener?.invoke(position)
|
||||||
@@ -127,52 +121,51 @@ class ReaderAdapter(private val context: Context,
|
|||||||
onItemClickListener?.invoke(position)
|
onItemClickListener?.invoke(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
(holder.view.container.layoutParams as ConstraintLayout.LayoutParams)
|
if (!isFullScreen)
|
||||||
.dimensionRatio = "${reader!!.galleryInfo[position].width}:${reader!!.galleryInfo[position].height}"
|
(holder.view.container.layoutParams as ConstraintLayout.LayoutParams)
|
||||||
|
.dimensionRatio = "${reader!!.galleryInfo[position].width}:${reader!!.galleryInfo[position].height}"
|
||||||
|
|
||||||
holder.view.reader_index.text = (position+1).toString()
|
holder.view.reader_index.text = (position+1).toString()
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
val images = Cache(context).getImages(galleryID)
|
||||||
val images = Cache(context).getImages(galleryID)
|
|
||||||
|
|
||||||
launch(Dispatchers.Main) {
|
if (images?.get(position) != null) {
|
||||||
if (images?.get(position) != null) {
|
glide
|
||||||
glide
|
.load(images[position])
|
||||||
.load(images[position])
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
.skipMemoryCache(true)
|
||||||
.skipMemoryCache(true)
|
.error(R.drawable.image_broken_variant)
|
||||||
.error(R.drawable.image_broken_variant)
|
.dontTransform()
|
||||||
.apply {
|
.apply {
|
||||||
if (BuildConfig.CENSOR)
|
if (BuildConfig.CENSOR)
|
||||||
override(5, 8)
|
override(5, 8)
|
||||||
}
|
}
|
||||||
.into(holder.view.image)
|
.into(holder.view.image)
|
||||||
} else {
|
} else {
|
||||||
val progress = DownloadWorker.getInstance(context).progress[galleryID]?.get(position)
|
val progress = DownloadWorker.getInstance(context).progress[galleryID]?.get(position)
|
||||||
|
|
||||||
if (progress?.isNaN() == true) {
|
if (progress?.isNaN() == true) {
|
||||||
|
if (Fabric.isInitialized())
|
||||||
|
Crashlytics.logException(DownloadWorker.getInstance(context).exception[galleryID]?.get(position))
|
||||||
|
|
||||||
if (Fabric.isInitialized())
|
glide
|
||||||
Crashlytics.logException(DownloadWorker.getInstance(context).exception[galleryID]?.get(position))
|
.load(R.drawable.image_broken_variant)
|
||||||
|
.into(holder.view.image)
|
||||||
|
|
||||||
glide
|
return
|
||||||
.load(R.drawable.image_broken_variant)
|
} else {
|
||||||
.into(holder.view.image)
|
holder.view.reader_item_progressbar.progress =
|
||||||
} else {
|
if (progress?.isInfinite() == true)
|
||||||
holder.view.reader_item_progressbar.progress =
|
100
|
||||||
if (progress?.isInfinite() == true)
|
else
|
||||||
100
|
progress?.roundToInt() ?: 0
|
||||||
else
|
|
||||||
progress?.roundToInt() ?: 0
|
|
||||||
|
|
||||||
holder.view.image.setImageDrawable(null)
|
holder.view.image.setImageDrawable(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.schedule(1000) {
|
timer.schedule(1000) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,8 @@
|
|||||||
<com.github.chrisbanes.photoview.PhotoView
|
<com.github.chrisbanes.photoview.PhotoView
|
||||||
android:id="@+id/image"
|
android:id="@+id/image"
|
||||||
android:contentDescription="@string/reader_imageview_description"
|
android:contentDescription="@string/reader_imageview_description"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:paddingBottom="8dp"/>
|
android:paddingBottom="8dp"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user