/
ImageRequest.kt
1176 lines (1055 loc) · 44.3 KB
/
ImageRequest.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (C) 2022 panpf <panpfpanpf@outlook.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.panpf.sketch.request
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ColorSpace
import android.graphics.drawable.Drawable
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.widget.ImageView
import android.widget.ImageView.ScaleType
import androidx.annotation.DrawableRes
import androidx.annotation.Px
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Stable
import androidx.lifecycle.Lifecycle
import com.github.panpf.sketch.ComponentRegistry
import com.github.panpf.sketch.cache.CachePolicy
import com.github.panpf.sketch.decode.BitmapConfig
import com.github.panpf.sketch.decode.BitmapDecoder
import com.github.panpf.sketch.decode.DrawableDecoder
import com.github.panpf.sketch.drawable.internal.CrossfadeDrawable
import com.github.panpf.sketch.drawable.internal.ResizeDrawable
import com.github.panpf.sketch.fetch.Fetcher
import com.github.panpf.sketch.http.HttpHeaders
import com.github.panpf.sketch.request.internal.CombinedListener
import com.github.panpf.sketch.request.internal.CombinedProgressListener
import com.github.panpf.sketch.resize.Precision
import com.github.panpf.sketch.resize.PrecisionDecider
import com.github.panpf.sketch.resize.Scale
import com.github.panpf.sketch.resize.ScaleDecider
import com.github.panpf.sketch.resize.SizeResolver
import com.github.panpf.sketch.resize.internal.DisplaySizeResolver
import com.github.panpf.sketch.resize.internal.ViewSizeResolver
import com.github.panpf.sketch.stateimage.ErrorStateImage
import com.github.panpf.sketch.stateimage.StateImage
import com.github.panpf.sketch.target.Target
import com.github.panpf.sketch.target.ViewDisplayTarget
import com.github.panpf.sketch.transform.Transformation
import com.github.panpf.sketch.transition.Transition
import com.github.panpf.sketch.util.Size
import com.github.panpf.sketch.util.asOrNull
import com.github.panpf.sketch.util.findLifecycle
import com.github.panpf.sketch.util.ifOrNull
/**
* An immutable image request that contains all the required parameters,
* you need to use its three concrete implementations [DisplayRequest], [LoadRequest], [DownloadRequest]
*/
@Stable
interface ImageRequest {
/** App Context */
val context: Context
/** The uri of the image to be loaded. */
val uriString: String
/**
* The [Lifecycle] resolver for this request.
* The request will be started when Lifecycle is in [Lifecycle.State.STARTED]
* and canceled when Lifecycle is in [Lifecycle.State.DESTROYED].
*
* When [Lifecycle] is not actively set,
* Sketch first obtains the Lifecycle at the nearest location through `view.findViewTreeLifecycleOwner()` and `LocalLifecycleOwner.current.lifecycle` APIs
* Secondly, get the [Lifecycle] of Activity through context, and finally use [GlobalLifecycle]
*/
val lifecycleResolver: LifecycleResolver
/** [Target] is used to receive Drawable and draw it */
val target: Target?
/** [Listener] is used to receive the state and result of the request */
val listener: Listener<ImageRequest, ImageResult.Success, ImageResult.Error>?
/** [ProgressListener] is used to receive the download progress of the request */
val progressListener: ProgressListener<ImageRequest>?
/** User-provided ImageOptions */
val definedOptions: ImageOptions
/** Default ImageOptions */
val defaultOptions: ImageOptions?
/** The processing depth of the request. */
val depth: Depth
/** where does this depth come from */
val depthFrom: String?
get() = parameters?.value(DEPTH_FROM_KEY)
/** A map of generic values that can be used to pass custom data to [Fetcher] and [BitmapDecoder] and [DrawableDecoder]. */
val parameters: Parameters?
/**
* Set headers for http requests
*
* @see com.github.panpf.sketch.http.HurlStack.getResponse
*/
val httpHeaders: HttpHeaders?
/**
* Http download cache policy
*
* @see com.github.panpf.sketch.fetch.HttpUriFetcher
*/
val downloadCachePolicy: CachePolicy
/**
* Specify [Bitmap.Config] to use when creating the bitmap.
* KITKAT and above [Bitmap.Config.ARGB_4444] will be forced to be replaced with [Bitmap.Config.ARGB_8888].
*
* Applied to [android.graphics.BitmapFactory.Options.inPreferredConfig]
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
val bitmapConfig: BitmapConfig?
/**
* [Bitmap]'s [ColorSpace]
*
* Applied to [android.graphics.BitmapFactory.Options.inPreferredColorSpace]
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
@get:RequiresApi(VERSION_CODES.O)
val colorSpace: ColorSpace?
/**
* From Android N (API 24), this is ignored. The output will always be high quality.
*
* In [android.os.Build.VERSION_CODES.M] and below, if
* inPreferQualityOverSpeed is set to true, the decoder will try to
* decode the reconstructed image to a higher quality even at the
* expense of the decoding speed. Currently the field only affects JPEG
* decode, in the case of which a more accurate, but slightly slower,
* IDCT method will be used instead.
*
* Applied to [android.graphics.BitmapFactory.Options.inPreferQualityOverSpeed]
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
@Deprecated("From Android N (API 24), this is ignored. The output will always be high quality.")
val preferQualityOverSpeed: Boolean
/**
* Lazy calculation of resize size. If resizeSize is null at runtime, size is calculated and assigned to resizeSize
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
val resizeSizeResolver: SizeResolver
/**
* Decide what Precision to use with [resizeSizeResolver] to calculate the size of the final Bitmap
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
val resizePrecisionDecider: PrecisionDecider
/**
* Which part of the original image to keep when [resizePrecisionDecider] returns [Precision.EXACTLY] or [Precision.SAME_ASPECT_RATIO]
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
val resizeScaleDecider: ScaleDecider
/**
* The list of [Transformation]s to be applied to this request
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
val transformations: List<Transformation>?
/**
* Disallow the use of [BitmapFactory.Options.inBitmap] to reuse Bitmap
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
val disallowReuseBitmap: Boolean
/**
* Ignore Orientation property in file Exif info
*
* Only works on [LoadRequest] and [DisplayRequest]
*
* @see com.github.panpf.sketch.decode.internal.appliedExifOrientation
*/
val ignoreExifOrientation: Boolean
/**
* Disk caching policy for Bitmaps affected by [resizeSizeResolver] or [transformations]
*
* Only works on [LoadRequest] and [DisplayRequest]
*
* @see com.github.panpf.sketch.decode.internal.BitmapResultCacheDecodeInterceptor
*/
val resultCachePolicy: CachePolicy
/**
* Placeholder image when loading
*
* Only works on [DisplayRequest]
*/
val placeholder: StateImage?
/**
* Image to display when uri is empty
*
* Only works on [DisplayRequest]
*/
val uriEmpty: StateImage?
/**
* Image to display when loading fails
*
* Only works on [DisplayRequest]
*/
val error: ErrorStateImage?
/**
* How the current image and the new image transition
*
* Only works on [DisplayRequest]
*/
val transitionFactory: Transition.Factory?
/**
* Disallow decode animation image, animations such as gif will only decode their first frame and return BitmapDrawable
*
* Only works on [DisplayRequest]
*/
val disallowAnimatedImage: Boolean
/**
* Wrap the final [Drawable] use [ResizeDrawable] and resize, the size of [ResizeDrawable] is the same as [resizeSizeResolver]
*
* Only works on [DisplayRequest]
*/
val resizeApplyToDrawable: Boolean
/**
* Bitmap memory caching policy
*
* Only works on [DisplayRequest]
*
* @see com.github.panpf.sketch.request.internal.MemoryCacheRequestInterceptor
*/
val memoryCachePolicy: CachePolicy
/** Components that are only valid for the current request */
val componentRegistry: ComponentRegistry?
/**
* Create a new [ImageRequest.Builder] based on the current [ImageRequest].
*
* You can extend it with a trailing lambda function [configBlock]
*/
fun newBuilder(
configBlock: (Builder.() -> Unit)? = null
): Builder
/**
* Create a new [ImageRequest] based on the current [ImageRequest].
*
* You can extend it with a trailing lambda function [configBlock]
*/
fun newRequest(
configBlock: (Builder.() -> Unit)? = null
): ImageRequest
abstract class Builder {
private val context: Context
private val uriString: String
private var listeners: MutableSet<Listener<ImageRequest, ImageResult.Success, ImageResult.Error>>? =
null
private var listener: Listener<ImageRequest, ImageResult.Success, ImageResult.Error>? = null
private var providerListener: Listener<ImageRequest, ImageResult.Success, ImageResult.Error>? =
null
private var progressListeners: MutableSet<ProgressListener<ImageRequest>>? = null
private var progressListener: ProgressListener<ImageRequest>? = null
private var providerProgressListener: ProgressListener<ImageRequest>? = null
private var target: Target? = null
private var lifecycleResolver: LifecycleResolver? = null
private var defaultOptions: ImageOptions? = null
private var viewTargetOptions: ImageOptions? = null
private val definedOptionsBuilder: ImageOptions.Builder
protected constructor(context: Context, uriString: String?) {
this.context = context
this.uriString = uriString.orEmpty()
this.definedOptionsBuilder = ImageOptions.Builder()
}
protected constructor(request: ImageRequest) {
this.context = request.context
this.uriString = request.uriString
val oldListener = request.listener
if (oldListener is CombinedListener<ImageRequest, ImageResult.Success, ImageResult.Error>) {
this.listener = oldListener.fromBuilderListener
this.listeners = oldListener.fromBuilderListeners?.toMutableSet()
this.providerListener = oldListener.fromProviderListener
} else {
this.listener = oldListener
this.listeners = null
this.providerListener = null
}
val oldProgressListener = request.progressListener
if (oldProgressListener is CombinedProgressListener<ImageRequest>) {
this.progressListener = oldProgressListener.fromBuilderProgressListener
this.progressListeners =
oldProgressListener.fromBuilderProgressListeners?.toMutableSet()
this.providerProgressListener = oldProgressListener.fromProviderProgressListener
} else {
this.progressListener = oldProgressListener
this.progressListeners = null
this.providerProgressListener = null
}
this.target = request.target
this.lifecycleResolver = request.lifecycleResolver
this.defaultOptions = request.defaultOptions
this.definedOptionsBuilder = request.definedOptions.newBuilder()
}
/**
* Set the [Listener]
*/
protected fun listener(
listener: Listener<ImageRequest, ImageResult.Success, ImageResult.Error>?
): Builder = apply {
this.listener = listener
}
/**
* Add the [Listener] to set
*/
protected fun addListener(
listener: Listener<ImageRequest, ImageResult.Success, ImageResult.Error>
): Builder = apply {
val listeners = listeners
?: mutableSetOf<Listener<ImageRequest, ImageResult.Success, ImageResult.Error>>().apply {
this@Builder.listeners = this
}
listeners.add(listener)
}
/**
* Remove the [Listener] from set
*/
protected fun removeListener(
listener: Listener<ImageRequest, ImageResult.Success, ImageResult.Error>
): Builder = apply {
listeners?.remove(listener)
}
/**
* Set the [ProgressListener]
*/
protected fun progressListener(
progressListener: ProgressListener<ImageRequest>?
): Builder = apply {
this.progressListener = progressListener
}
/**
* Add the [ProgressListener] to set
*/
protected fun addProgressListener(
progressListener: ProgressListener<ImageRequest>
): Builder = apply {
val progressListeners =
progressListeners ?: mutableSetOf<ProgressListener<ImageRequest>>().apply {
this@Builder.progressListeners = this
}
progressListeners.add(progressListener)
}
/**
* Remove the [ProgressListener] from set
*/
protected fun removeProgressListener(
progressListener: ProgressListener<ImageRequest>
): Builder = apply {
progressListeners?.remove(progressListener)
}
/**
* Set the [Lifecycle] for this request.
*
* Requests are queued while the lifecycle is not at least [Lifecycle.State.STARTED].
* Requests are cancelled when the lifecycle reaches [Lifecycle.State.DESTROYED].
*
* If this is null or is not set the will attempt to find the lifecycle
* for this request through its [context].
*/
open fun lifecycle(lifecycle: Lifecycle?): Builder = apply {
this.lifecycleResolver = if (lifecycle != null) LifecycleResolver(lifecycle) else null
}
/**
* Set the [LifecycleResolver] for this request.
*
* Requests are queued while the lifecycle is not at least [Lifecycle.State.STARTED].
* Requests are cancelled when the lifecycle reaches [Lifecycle.State.DESTROYED].
*
* If this is null or is not set the will attempt to find the lifecycle
* for this request through its [context].
*/
open fun lifecycle(lifecycleResolver: LifecycleResolver?): Builder = apply {
this.lifecycleResolver = lifecycleResolver
}
/**
* Set the [Target].
*/
protected fun target(target: Target?): Builder = apply {
this.target = target
this.viewTargetOptions = target.asOrNull<ViewDisplayTarget<*>>()
?.view.asOrNull<ImageOptionsProvider>()
?.displayImageOptions
}
/**
* Set the requested depth
*/
open fun depth(depth: Depth?, depthFrom: String? = null): Builder = apply {
definedOptionsBuilder.depth(depth, depthFrom)
}
/**
* Bulk set parameters for this request
*/
open fun parameters(parameters: Parameters?): Builder = apply {
definedOptionsBuilder.parameters(parameters)
}
/**
* Set a parameter for this request.
*/
open fun setParameter(
key: String, value: Any?, cacheKey: String? = value?.toString()
): Builder = apply {
definedOptionsBuilder.setParameter(key, value, cacheKey)
}
/**
* Remove a parameter from this request.
*/
open fun removeParameter(key: String): Builder = apply {
definedOptionsBuilder.removeParameter(key)
}
/**
* Bulk set headers for any network request for this request
*/
open fun httpHeaders(httpHeaders: HttpHeaders?): Builder = apply {
definedOptionsBuilder.httpHeaders(httpHeaders)
}
/**
* Add a header for any network operations performed by this request.
*/
open fun addHttpHeader(name: String, value: String): Builder = apply {
definedOptionsBuilder.addHttpHeader(name, value)
}
/**
* Set a header for any network operations performed by this request.
*/
open fun setHttpHeader(name: String, value: String): Builder = apply {
definedOptionsBuilder.setHttpHeader(name, value)
}
/**
* Remove all network headers with the key [name].
*/
open fun removeHttpHeader(name: String): Builder = apply {
definedOptionsBuilder.removeHttpHeader(name)
}
/**
* Set http download cache policy
*/
open fun downloadCachePolicy(cachePolicy: CachePolicy?): Builder = apply {
definedOptionsBuilder.downloadCachePolicy(cachePolicy)
}
/**
* Set [Bitmap.Config] to use when creating the bitmap.
* KITKAT and above [Bitmap.Config.ARGB_4444] will be forced to be replaced with [Bitmap.Config.ARGB_8888].
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun bitmapConfig(bitmapConfig: BitmapConfig?): Builder = apply {
definedOptionsBuilder.bitmapConfig(bitmapConfig)
}
/**
* Set [Bitmap.Config] to use when creating the bitmap.
* KITKAT and above [Bitmap.Config.ARGB_4444] will be forced to be replaced with [Bitmap.Config.ARGB_8888].
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun bitmapConfig(bitmapConfig: Bitmap.Config): Builder = apply {
definedOptionsBuilder.bitmapConfig(bitmapConfig)
}
/**
* Set preferred [Bitmap]'s [ColorSpace]
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
@RequiresApi(VERSION_CODES.O)
open fun colorSpace(colorSpace: ColorSpace?): Builder = apply {
definedOptionsBuilder.colorSpace(colorSpace)
}
/**
* From Android N (API 24), this is ignored. The output will always be high quality.
*
* In [android.os.Build.VERSION_CODES.M] and below, if
* inPreferQualityOverSpeed is set to true, the decoder will try to
* decode the reconstructed image to a higher quality even at the
* expense of the decoding speed. Currently the field only affects JPEG
* decode, in the case of which a more accurate, but slightly slower,
* IDCT method will be used instead.
*
* Applied to [android.graphics.BitmapFactory.Options.inPreferQualityOverSpeed]
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
@Deprecated("From Android N (API 24), this is ignored. The output will always be high quality.")
open fun preferQualityOverSpeed(inPreferQualityOverSpeed: Boolean? = true): Builder =
apply {
@Suppress("DEPRECATION")
definedOptionsBuilder.preferQualityOverSpeed(inPreferQualityOverSpeed)
}
/**
* Set how to resize image
*
* @param size Expected Bitmap size Resolver
* @param precision precision of size, default is [Precision.LESS_PIXELS]
* @param scale Which part of the original image to keep when [precision] is
* [Precision.EXACTLY] or [Precision.SAME_ASPECT_RATIO], default is [Scale.CENTER_CROP]
*/
open fun resize(
size: SizeResolver?,
precision: PrecisionDecider? = null,
scale: ScaleDecider? = null
): Builder = apply {
definedOptionsBuilder.resize(size, precision, scale)
}
/**
* Set how to resize image
*
* @param size Expected Bitmap size
* @param precision precision of size, default is [Precision.LESS_PIXELS]
* @param scale Which part of the original image to keep when [precision] is
* [Precision.EXACTLY] or [Precision.SAME_ASPECT_RATIO], default is [Scale.CENTER_CROP]
*/
open fun resize(
size: Size,
precision: Precision? = null,
scale: Scale? = null
): Builder = apply {
definedOptionsBuilder.resize(size, precision, scale)
}
/**
* Set how to resize image
*
* @param width Expected Bitmap width
* @param height Expected Bitmap height
* @param precision precision of size, default is [Precision.LESS_PIXELS]
* @param scale Which part of the original image to keep when [precision] is
* [Precision.EXACTLY] or [Precision.SAME_ASPECT_RATIO], default is [Scale.CENTER_CROP]
*/
open fun resize(
@Px width: Int,
@Px height: Int,
precision: Precision? = null,
scale: Scale? = null
): Builder = apply {
definedOptionsBuilder.resize(width, height, precision, scale)
}
/**
* Set the [SizeResolver] to lazy resolve the requested size.
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun resizeSize(sizeResolver: SizeResolver?): Builder = apply {
definedOptionsBuilder.resizeSize(sizeResolver)
}
/**
* Set the resize size
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun resizeSize(size: Size): Builder = apply {
definedOptionsBuilder.resizeSize(size)
}
/**
* Set the resize size
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun resizeSize(@Px width: Int, @Px height: Int): Builder = apply {
definedOptionsBuilder.resizeSize(width, height)
}
/**
* Set the resize precision
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun resizePrecision(precisionDecider: PrecisionDecider?): Builder = apply {
definedOptionsBuilder.resizePrecision(precisionDecider)
}
/**
* Set the resize precision
*/
open fun resizePrecision(precision: Precision): Builder = apply {
definedOptionsBuilder.resizePrecision(precision)
}
/**
* Set the resize scale
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun resizeScale(scaleDecider: ScaleDecider?): Builder = apply {
definedOptionsBuilder.resizeScale(scaleDecider)
}
/**
* Set the resize scale
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun resizeScale(scale: Scale): Builder = apply {
definedOptionsBuilder.resizeScale(scale)
}
/**
* Set the list of [Transformation]s to be applied to this request.
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun transformations(transformations: List<Transformation>?): Builder = apply {
definedOptionsBuilder.transformations(transformations)
}
/**
* Set the list of [Transformation]s to be applied to this request.
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun transformations(vararg transformations: Transformation): Builder = apply {
definedOptionsBuilder.transformations(transformations.toList())
}
/**
* Append the list of [Transformation]s to be applied to this request.
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun addTransformations(transformations: List<Transformation>): Builder = apply {
definedOptionsBuilder.addTransformations(transformations)
}
/**
* Append the list of [Transformation]s to be applied to this request.
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun addTransformations(vararg transformations: Transformation): Builder = apply {
definedOptionsBuilder.addTransformations(transformations.toList())
}
/**
* Bulk remove from current [Transformation] list
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun removeTransformations(transformations: List<Transformation>): Builder = apply {
definedOptionsBuilder.removeTransformations(transformations)
}
/**
* Bulk remove from current [Transformation] list
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun removeTransformations(vararg transformations: Transformation): Builder = apply {
definedOptionsBuilder.removeTransformations(transformations.toList())
}
/**
* Set disallow the use of [BitmapFactory.Options.inBitmap] to reuse Bitmap
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun disallowReuseBitmap(disabled: Boolean? = true): Builder = apply {
definedOptionsBuilder.disallowReuseBitmap(disabled)
}
/**
* Set ignore Orientation property in file Exif info
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun ignoreExifOrientation(ignore: Boolean? = true): Builder = apply {
definedOptionsBuilder.ignoreExifOrientation(ignore)
}
/**
* Set disk caching policy for Bitmaps affected by [resizeSize] or [transformations]
*
* Only works on [LoadRequest] and [DisplayRequest]
*/
open fun resultCachePolicy(cachePolicy: CachePolicy?): Builder = apply {
definedOptionsBuilder.resultCachePolicy(cachePolicy)
}
/**
* Set placeholder image when loading
*
* Only works on [DisplayRequest]
*/
open fun placeholder(stateImage: StateImage?): Builder = apply {
definedOptionsBuilder.placeholder(stateImage)
}
/**
* Set Drawable placeholder image when loading
*
* Only works on [DisplayRequest]
*/
open fun placeholder(drawable: Drawable): Builder = apply {
definedOptionsBuilder.placeholder(drawable)
}
/**
* Set Drawable res placeholder image when loading
*
* Only works on [DisplayRequest]
*/
open fun placeholder(@DrawableRes drawableResId: Int): Builder = apply {
definedOptionsBuilder.placeholder(drawableResId)
}
/**
* Set placeholder image when uri is empty
*
* Only works on [DisplayRequest]
*/
open fun uriEmpty(stateImage: StateImage?): Builder = apply {
definedOptionsBuilder.uriEmpty(stateImage)
}
/**
* Set Drawable placeholder image when uri is empty
*
* Only works on [DisplayRequest]
*/
open fun uriEmpty(drawable: Drawable): Builder = apply {
definedOptionsBuilder.uriEmpty(drawable)
}
/**
* Set Drawable res placeholder image when uri is empty
*
* Only works on [DisplayRequest]
*/
open fun uriEmpty(@DrawableRes drawableResId: Int): Builder = apply {
definedOptionsBuilder.uriEmpty(drawableResId)
}
/**
* Set image to display when loading fails.
*
* You can also set image of different error types via the trailing lambda function
*
* Only works on [DisplayRequest]
*/
open fun error(
defaultStateImage: StateImage?,
configBlock: (ErrorStateImage.Builder.() -> Unit)? = null
): Builder = apply {
definedOptionsBuilder.error(defaultStateImage, configBlock)
}
/**
* Set Drawable image to display when loading fails.
*
* You can also set image of different error types via the trailing lambda function
*
* Only works on [DisplayRequest]
*/
open fun error(
defaultDrawable: Drawable, configBlock: (ErrorStateImage.Builder.() -> Unit)? = null
): Builder = apply {
definedOptionsBuilder.error(defaultDrawable, configBlock)
}
/**
* Set Drawable res image to display when loading fails.
*
* You can also set image of different error types via the trailing lambda function
*
* Only works on [DisplayRequest]
*/
open fun error(
defaultDrawableResId: Int, configBlock: (ErrorStateImage.Builder.() -> Unit)? = null
): Builder = apply {
definedOptionsBuilder.error(defaultDrawableResId, configBlock)
}
/**
* Set Drawable res image to display when loading fails.
*
* You can also set image of different error types via the trailing lambda function
*
* Only works on [DisplayRequest]
*/
open fun error(
configBlock: (ErrorStateImage.Builder.() -> Unit)? = null
): Builder = apply {
definedOptionsBuilder.error(configBlock)
}
/**
* Set the transition between the current image and the new image
*
* Only works on [DisplayRequest]
*/
open fun transitionFactory(transitionFactory: Transition.Factory?): Builder = apply {
definedOptionsBuilder.transitionFactory(transitionFactory)
}
/**
* Sets the transition that crossfade
*
* Only works on [DisplayRequest]
*/
open fun crossfade(
durationMillis: Int = CrossfadeDrawable.DEFAULT_DURATION,
fadeStart: Boolean = true,
preferExactIntrinsicSize: Boolean = false,
alwaysUse: Boolean = false,
): Builder = apply {
definedOptionsBuilder.crossfade(
durationMillis,
fadeStart,
preferExactIntrinsicSize,
alwaysUse
)
}
/**
* Set disallow decode animation image, animations such as gif will only decode their first frame and return BitmapDrawable
*
* Only works on [DisplayRequest]
*/
open fun disallowAnimatedImage(disabled: Boolean? = true): Builder = apply {
definedOptionsBuilder.disallowAnimatedImage(disabled)
}
/**
* Set wrap the final [Drawable] use [ResizeDrawable] and resize, the size of [ResizeDrawable] is the same as [resizeSize]
*
* Only works on [DisplayRequest]
*/
open fun resizeApplyToDrawable(resizeApplyToDrawable: Boolean? = true): Builder = apply {
definedOptionsBuilder.resizeApplyToDrawable(resizeApplyToDrawable)
}
/**
* Set bitmap memory caching policy
*
* Only works on [DisplayRequest]
*/
open fun memoryCachePolicy(cachePolicy: CachePolicy?): Builder = apply {
definedOptionsBuilder.memoryCachePolicy(cachePolicy)
}
/**
* Merge the specified [ImageOptions] into the current [Builder]. Currently [Builder] takes precedence
*
* Only works on [DisplayRequest]
*/
open fun merge(options: ImageOptions?): Builder = apply {
definedOptionsBuilder.merge(options)
}
/**
* Set a final [ImageOptions] to complement properties not set
*
* Only works on [DisplayRequest]
*/
open fun default(options: ImageOptions?): Builder = apply {
this.defaultOptions = options
}
/**
* Set the [ComponentRegistry]
*/
open fun components(components: ComponentRegistry?): Builder = apply {
definedOptionsBuilder.components(components)
}
/**
* Build and set the [ComponentRegistry]
*/
open fun components(configBlock: (ComponentRegistry.Builder.() -> Unit)): Builder = apply {
definedOptionsBuilder.components(configBlock)
}
@Suppress("DEPRECATION")
@SuppressLint("NewApi")
open fun build(): ImageRequest {
val listener = combinationListener()
val progressListener = combinationProgressListener()
val lifecycleResolver =
lifecycleResolver ?: DefaultLifecycleResolver(resolveLifecycleResolver())
val definedOptions = definedOptionsBuilder.merge(viewTargetOptions).build()
val finalOptions = definedOptions.merged(defaultOptions)
val depth = finalOptions.depth ?: Depth.NETWORK
val parameters = finalOptions.parameters
val httpHeaders = finalOptions.httpHeaders
val downloadCachePolicy = finalOptions.downloadCachePolicy ?: CachePolicy.ENABLED
val resultCachePolicy = finalOptions.resultCachePolicy ?: CachePolicy.ENABLED
val bitmapConfig = finalOptions.bitmapConfig
val colorSpace = ifOrNull(VERSION.SDK_INT >= VERSION_CODES.O) {
finalOptions.colorSpace
}
val preferQualityOverSpeed = finalOptions.preferQualityOverSpeed ?: false
val resizeSizeResolver = finalOptions.resizeSizeResolver
?: resolveResizeSizeResolver()
val resizePrecisionDecider = finalOptions.resizePrecisionDecider
?: PrecisionDecider(Precision.LESS_PIXELS)
val resizeScaleDecider =
finalOptions.resizeScaleDecider ?: ScaleDecider(resolveResizeScale())
val transformations = finalOptions.transformations
val disallowReuseBitmap = finalOptions.disallowReuseBitmap ?: false
val ignoreExifOrientation = finalOptions.ignoreExifOrientation ?: false
val placeholder = finalOptions.placeholder
val uriEmpty = finalOptions.uriEmpty
val error = finalOptions.error
val transitionFactory = finalOptions.transitionFactory
val disallowAnimatedImage = finalOptions.disallowAnimatedImage ?: false
val resizeApplyToDrawable = finalOptions.resizeApplyToDrawable ?: false
val memoryCachePolicy = finalOptions.memoryCachePolicy ?: CachePolicy.ENABLED
val componentRegistry = finalOptions.componentRegistry
return when (this@Builder) {
is DisplayRequest.Builder -> {
DisplayRequest.DisplayRequestImpl(
context = context,
uriString = uriString,
listener = listener,
progressListener = progressListener,
target = target,
lifecycleResolver = lifecycleResolver,
defaultOptions = defaultOptions,
definedOptions = definedOptions,