summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
author Andrey Epin <ayepin@google.com> 2024-06-25 12:48:32 -0700
committer Andrey Yepin <ayepin@google.com> 2024-07-15 13:33:23 -0700
commite48daa217dc397cce855a5357ee11a87b0c7bce4 (patch)
treeaea79b4a9f640e60f4422bb996ca7ec125310a46 /java
parent1936da00dab547490ac4f0a349063fee3591d9d2 (diff)
Update ImageLoader interface to receive preview sizes along with the URI
The UI calculates and provides view sizes but they are not used by the existing ImageLoader implementations thus no functional change is expected. Bug: 348665058 Test: atest IntentResolver-tests-unit Test: atest IntentResolver-tests-activity Test: inject debug logging and verify preview values being requested for app preview types Flag: EXEMPT refactor Change-Id: I0e282f773c424b6fe81587a71e1b8630452ac63c
Diffstat (limited to 'java')
-rw-r--r--java/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoader.kt7
-rw-r--r--java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java5
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ImageLoader.kt14
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt7
-rw-r--r--java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java9
-rw-r--r--java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java17
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt13
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt21
-rw-r--r--java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt42
9 files changed, 100 insertions, 35 deletions
diff --git a/java/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoader.kt
index c9deec1b..f60f550e 100644
--- a/java/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoader.kt
+++ b/java/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoader.kt
@@ -19,6 +19,7 @@ package com.android.intentresolver.contentpreview
import android.graphics.Bitmap
import android.net.Uri
import android.util.Log
+import android.util.Size
import androidx.core.util.lruCache
import com.android.intentresolver.inject.Background
import com.android.intentresolver.inject.ViewModelOwned
@@ -72,11 +73,11 @@ constructor(
}
)
- override fun prePopulate(uris: List<Uri>) {
- uris.take(cache.maxSize()).map { cache[it] }
+ override fun prePopulate(uriSizePairs: List<Pair<Uri, Size>>) {
+ uriSizePairs.take(cache.maxSize()).map { cache[it.first] }
}
- override suspend fun invoke(uri: Uri, caching: Boolean): Bitmap? {
+ override suspend fun invoke(uri: Uri, size: Size, caching: Boolean): Bitmap? {
return if (caching) {
loadCachedImage(uri)
} else {
diff --git a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
index b50f5bc8..30161cfb 100644
--- a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
@@ -23,6 +23,7 @@ import android.content.res.Resources;
import android.net.Uri;
import android.text.util.Linkify;
import android.util.PluralsMessageFormatter;
+import android.util.Size;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -68,6 +69,7 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
private Uri mFirstFilePreviewUri;
private boolean mAllImages;
private boolean mAllVideos;
+ private int mPreviewSize;
// TODO(b/285309527): make this a flag
private static final boolean SHOW_TOGGLE_CHECKMARK = false;
@@ -109,6 +111,7 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
LayoutInflater layoutInflater,
ViewGroup parent,
View headlineViewParent) {
+ mPreviewSize = resources.getDimensionPixelSize(R.dimen.width_text_image_preview_size);
return displayInternal(layoutInflater, parent, headlineViewParent);
}
@@ -164,12 +167,12 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
private void updateUiWithMetadata(ViewGroup contentPreviewView, View headlineView) {
prepareTextPreview(contentPreviewView, headlineView, mActionFactory);
updateHeadline(headlineView, mFileCount, mAllImages, mAllVideos);
-
ImageView imagePreview = mContentPreviewView.requireViewById(R.id.image_view);
if (mIsSingleImage && mFirstFilePreviewUri != null) {
mImageLoader.loadImage(
mScope,
mFirstFilePreviewUri,
+ new Size(mPreviewSize, mPreviewSize),
bitmap -> {
if (bitmap == null) {
imagePreview.setVisibility(View.GONE);
diff --git a/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt
index b4d03ac9..ac34f552 100644
--- a/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt
+++ b/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt
@@ -18,23 +18,25 @@ package com.android.intentresolver.contentpreview
import android.graphics.Bitmap
import android.net.Uri
+import android.util.Size
import java.util.function.Consumer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
/** A content preview image loader. */
-interface ImageLoader : suspend (Uri) -> Bitmap?, suspend (Uri, Boolean) -> Bitmap? {
+interface ImageLoader : suspend (Uri, Size) -> Bitmap?, suspend (Uri, Size, Boolean) -> Bitmap? {
/**
* Load preview image asynchronously; caching is allowed.
*
* @param uri content URI
+ * @param size target bitmap size
* @param callback a callback that will be invoked with the loaded image or null if loading has
* failed.
*/
- fun loadImage(callerScope: CoroutineScope, uri: Uri, callback: Consumer<Bitmap?>) {
+ fun loadImage(callerScope: CoroutineScope, uri: Uri, size: Size, callback: Consumer<Bitmap?>) {
callerScope.launch {
- val bitmap = invoke(uri)
+ val bitmap = invoke(uri, size)
if (isActive) {
callback.accept(bitmap)
}
@@ -42,13 +44,13 @@ interface ImageLoader : suspend (Uri) -> Bitmap?, suspend (Uri, Boolean) -> Bitm
}
/** Prepopulate the image loader cache. */
- fun prePopulate(uris: List<Uri>)
+ fun prePopulate(uriSizePairs: List<Pair<Uri, Size>>)
/** Returns a bitmap for the given URI if it's already cached, otherwise null */
fun getCachedBitmap(uri: Uri): Bitmap? = null
/** Load preview image; caching is allowed. */
- override suspend fun invoke(uri: Uri) = invoke(uri, true)
+ override suspend fun invoke(uri: Uri, size: Size) = invoke(uri, size, true)
/**
* Load preview image.
@@ -56,5 +58,5 @@ interface ImageLoader : suspend (Uri) -> Bitmap?, suspend (Uri, Boolean) -> Bitm
* @param uri content URI
* @param caching indicates if the loaded image could be cached.
*/
- override suspend fun invoke(uri: Uri, caching: Boolean): Bitmap?
+ override suspend fun invoke(uri: Uri, size: Size, caching: Boolean): Bitmap?
}
diff --git a/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt
index 7cf9a8c9..379bdb37 100644
--- a/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt
+++ b/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt
@@ -98,10 +98,11 @@ constructor(
@GuardedBy("lock") private val cache = LruCache<Uri, RequestRecord>(cacheSize)
@GuardedBy("lock") private val runningRequests = HashMap<Uri, RequestRecord>()
- override suspend fun invoke(uri: Uri, caching: Boolean): Bitmap? = loadImageAsync(uri, caching)
+ override suspend fun invoke(uri: Uri, size: Size, caching: Boolean): Bitmap? =
+ loadImageAsync(uri, caching)
- override fun prePopulate(uris: List<Uri>) {
- uris.asSequence().take(cache.maxSize()).forEach { uri ->
+ override fun prePopulate(uriSizePairs: List<Pair<Uri, Size>>) {
+ uriSizePairs.asSequence().take(cache.maxSize()).forEach { (uri, _) ->
scope.launch { loadImageAsync(uri, caching = true) }
}
}
diff --git a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java
index ae7ddcd9..b12eb8cf 100644
--- a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java
@@ -22,6 +22,7 @@ import android.content.res.Resources;
import android.net.Uri;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
+import android.util.Size;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -50,6 +51,7 @@ class TextContentPreviewUi extends ContentPreviewUi {
private final ChooserContentPreviewUi.ActionFactory mActionFactory;
private final HeadlineGenerator mHeadlineGenerator;
private final ContentTypeHint mContentTypeHint;
+ private int mPreviewSize;
TextContentPreviewUi(
CoroutineScope scope,
@@ -83,6 +85,7 @@ class TextContentPreviewUi extends ContentPreviewUi {
LayoutInflater layoutInflater,
ViewGroup parent,
View headlineViewParent) {
+ mPreviewSize = resources.getDimensionPixelSize(R.dimen.width_text_image_preview_size);
return displayInternal(layoutInflater, parent, headlineViewParent);
}
@@ -119,7 +122,7 @@ class TextContentPreviewUi extends ContentPreviewUi {
previewTitleView.setText(mPreviewTitle);
}
- ImageView previewThumbnailView = contentPreviewLayout.findViewById(
+ final ImageView previewThumbnailView = contentPreviewLayout.requireViewById(
com.android.internal.R.id.content_preview_thumbnail);
if (!isOwnedByCurrentUser(mPreviewThumbnail)) {
previewThumbnailView.setVisibility(View.GONE);
@@ -127,9 +130,9 @@ class TextContentPreviewUi extends ContentPreviewUi {
mImageLoader.loadImage(
mScope,
mPreviewThumbnail,
+ new Size(mPreviewSize, mPreviewSize),
(bitmap) -> updateViewWithImage(
- contentPreviewLayout.findViewById(
- com.android.internal.R.id.content_preview_thumbnail),
+ previewThumbnailView,
bitmap));
}
diff --git a/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java
index 88311016..7de988c4 100644
--- a/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java
@@ -20,6 +20,7 @@ import static com.android.intentresolver.contentpreview.ContentPreviewType.CONTE
import android.content.res.Resources;
import android.util.Log;
+import android.util.Size;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -31,6 +32,8 @@ import com.android.intentresolver.widget.ActionRow;
import com.android.intentresolver.widget.ImagePreviewView.TransitionElementStatusCallback;
import com.android.intentresolver.widget.ScrollableImagePreviewView;
+import kotlin.Pair;
+
import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.flow.Flow;
@@ -55,6 +58,7 @@ class UnifiedContentPreviewUi extends ContentPreviewUi {
@Nullable
private ViewGroup mContentPreviewView;
private View mHeadlineView;
+ private int mPreviewSize;
UnifiedContentPreviewUi(
CoroutineScope scope,
@@ -93,14 +97,18 @@ class UnifiedContentPreviewUi extends ContentPreviewUi {
LayoutInflater layoutInflater,
ViewGroup parent,
View headlineViewParent) {
+ mPreviewSize = resources.getDimensionPixelSize(R.dimen.chooser_preview_image_max_dimen);
return displayInternal(layoutInflater, parent, headlineViewParent);
}
private void setFiles(List<FileInfo> files) {
- mImageLoader.prePopulate(files.stream()
- .map(FileInfo::getPreviewUri)
- .filter(Objects::nonNull)
- .toList());
+ Size previewSize = new Size(mPreviewSize, mPreviewSize);
+ mImageLoader.prePopulate(
+ files.stream()
+ .map(FileInfo::getPreviewUri)
+ .filter(Objects::nonNull)
+ .map((uri -> new Pair<>(uri, previewSize)))
+ .toList());
mFiles = files;
if (mContentPreviewView != null) {
updatePreviewWithFiles(mContentPreviewView, mHeadlineView, files);
@@ -121,6 +129,7 @@ class UnifiedContentPreviewUi extends ContentPreviewUi {
ScrollableImagePreviewView imagePreview =
mContentPreviewView.requireViewById(R.id.scrollable_image_preview);
+ imagePreview.setPreviewHeight(mPreviewSize);
imagePreview.setImageLoader(mImageLoader);
imagePreview.setOnNoPreviewCallback(() -> imagePreview.setVisibility(View.GONE));
imagePreview.setTransitionElementStatusCallback(mTransitionElementStatusCallback);
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt
index 3c3381a2..9ac36a87 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt
@@ -111,6 +111,7 @@ private fun PreviewCarousel(
prefetchStrategy = remember { ShareouselLazyListPrefetchStrategy() }
)
var maxAspectRatio by remember { mutableStateOf(0f) }
+ var viewportHeight by remember { mutableStateOf(0) }
val horizontalPadding = 16.dp
Box(
@@ -130,9 +131,8 @@ private fun PreviewCarousel(
MAX_ASPECT_RATIO
)
}
- if (maxAspectRatio != aspectRatio) {
- maxAspectRatio = aspectRatio
- }
+ maxAspectRatio = aspectRatio
+ viewportHeight = placeable.height
layout(placeable.width, placeable.height) { placeable.place(0, 0) }
},
) {
@@ -170,7 +170,12 @@ private fun PreviewCarousel(
}
ShareouselCard(
- viewModel.preview(model, previewIndex, rememberCoroutineScope()),
+ viewModel.preview(
+ model,
+ viewportHeight,
+ previewIndex,
+ rememberCoroutineScope()
+ ),
maxAspectRatio,
)
}
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt
index d0b89860..f1e65f73 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt
@@ -15,6 +15,7 @@
*/
package com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel
+import android.util.Size
import com.android.intentresolver.contentpreview.CachingImagePreviewImageLoader
import com.android.intentresolver.contentpreview.HeadlineGenerator
import com.android.intentresolver.contentpreview.ImageLoader
@@ -57,7 +58,9 @@ data class ShareouselViewModel(
val actions: Flow<List<ActionChipViewModel>>,
/** Creates a [ShareouselPreviewViewModel] for a [PreviewModel] present in [previews]. */
val preview:
- (key: PreviewModel, index: Int?, scope: CoroutineScope) -> ShareouselPreviewViewModel,
+ (
+ key: PreviewModel, previewHeight: Int, index: Int?, scope: CoroutineScope
+ ) -> ShareouselPreviewViewModel,
)
@Module
@@ -114,7 +117,7 @@ interface ShareouselViewModelModule {
}
}
},
- preview = { key, index, previewScope ->
+ preview = { key, previewHeight, index, previewScope ->
keySet.value?.maybeLoad(index)
val previewInteractor = interactor.preview(key)
val contentType =
@@ -130,9 +133,19 @@ interface ShareouselViewModelModule {
ShareouselPreviewViewModel(
bitmapLoadState =
flow {
+ val previewWidth =
+ if (key.aspectRatio > 0) {
+ previewHeight.toFloat() / key.aspectRatio
+ } else {
+ previewHeight
+ }
+ .toInt()
emit(
- key.previewUri?.let { ValueUpdate.Value(imageLoader(it)) }
- ?: ValueUpdate.Absent
+ key.previewUri?.let {
+ ValueUpdate.Value(
+ imageLoader(it, Size(previewWidth, previewHeight))
+ )
+ } ?: ValueUpdate.Absent
)
}
.stateIn(previewScope, SharingStarted.Eagerly, initialBitmapValue),
diff --git a/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt b/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt
index 7fe16091..c706e3ee 100644
--- a/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt
+++ b/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt
@@ -22,6 +22,7 @@ import android.graphics.Rect
import android.net.Uri
import android.util.AttributeSet
import android.util.PluralsMessageFormatter
+import android.util.Size
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
@@ -60,11 +61,13 @@ private const val MIN_ASPECT_RATIO_STRING = "2:5"
private const val MAX_ASPECT_RATIO = 2.5f
private const val MAX_ASPECT_RATIO_STRING = "5:2"
-private typealias CachingImageLoader = suspend (Uri, Boolean) -> Bitmap?
+private typealias CachingImageLoader = suspend (Uri, Size, Boolean) -> Bitmap?
class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
constructor(context: Context) : this(context, null)
+
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
+
constructor(
context: Context,
attrs: AttributeSet?,
@@ -121,12 +124,19 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
* A hint about the maximum width this view can grow to, this helps to optimize preview loading.
*/
var maxWidthHint: Int = -1
+
private var requestedHeight: Int = 0
private var isMeasured = false
private var maxAspectRatio = MAX_ASPECT_RATIO
private var maxAspectRatioString = MAX_ASPECT_RATIO_STRING
private var outerSpacing: Int = 0
+ var previewHeight: Int
+ get() = previewAdapter.previewHeight
+ set(value) {
+ previewAdapter.previewHeight = value
+ }
+
override fun onMeasure(widthSpec: Int, heightSpec: Int) {
super.onMeasure(widthSpec, heightSpec)
if (!isMeasured) {
@@ -198,6 +208,7 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
BatchPreviewLoader(
previewAdapter.imageLoader ?: error("Image loader is not set"),
previews,
+ Size(previewHeight, previewHeight),
totalItemCount,
onUpdate = previewAdapter::addPreviews,
onCompletion = {
@@ -303,11 +314,19 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
private var isLoading = false
private val hasOtherItem
get() = previews.size < totalItemCount
+
val hasPreviews: Boolean
get() = previews.isNotEmpty()
var transitionStatusElementCallback: TransitionElementStatusCallback? = null
+ private var previewSize: Size = Size(0, 0)
+ var previewHeight: Int
+ get() = previewSize.height
+ set(value) {
+ previewSize = Size(value, value)
+ }
+
fun reset(totalItemCount: Int) {
firstImagePos = -1
previews.clear()
@@ -387,6 +406,7 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
vh.bind(
previews[position],
imageLoader ?: error("ImageLoader is missing"),
+ previewSize,
fadeInDurationMs,
isSharedTransitionElement = position == firstImagePos,
previewReadyCallback =
@@ -438,6 +458,7 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
fun bind(
preview: Preview,
imageLoader: CachingImageLoader,
+ previewSize: Size,
fadeInDurationMs: Long,
isSharedTransitionElement: Boolean,
previewReadyCallback: ((String) -> Unit)?
@@ -477,7 +498,7 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
}
}
resetScope().launch {
- loadImage(preview, imageLoader)
+ loadImage(preview, previewSize, imageLoader)
if (preview.type == PreviewType.Image && previewReadyCallback != null) {
image.waitForPreDraw()
previewReadyCallback(TRANSITION_NAME)
@@ -487,12 +508,16 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
}
}
- private suspend fun loadImage(preview: Preview, imageLoader: CachingImageLoader) {
+ private suspend fun loadImage(
+ preview: Preview,
+ previewSize: Size,
+ imageLoader: CachingImageLoader,
+ ) {
val bitmap =
runCatching {
// it's expected for all loading/caching optimizations to be implemented by
// the loader
- imageLoader(preview.uri, true)
+ imageLoader(preview.uri, previewSize, true)
}
.getOrNull()
image.setImageBitmap(bitmap)
@@ -507,6 +532,7 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
setAnimationListener(
object : AnimationListener {
override fun onAnimationStart(animation: Animation?) = Unit
+
override fun onAnimationRepeat(animation: Animation?) = Unit
override fun onAnimationEnd(animation: Animation?) {
@@ -551,6 +577,7 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
private class LoadingItemViewHolder(view: View) : ViewHolder(view) {
fun bind() = Unit
+
override fun unbind() = Unit
}
@@ -638,6 +665,7 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
class BatchPreviewLoader(
private val imageLoader: CachingImageLoader,
private val previews: Flow<Preview>,
+ private val previewSize: Size,
val totalItemCount: Int,
private val onUpdate: (List<Preview>) -> Unit,
private val onCompletion: () -> Unit,
@@ -701,10 +729,10 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
// imagine is one of the first images never loads so we never
// fill the initial viewport and does not show the previews at
// all.
- imageLoader(preview.uri, isFirstBlock)?.let { bitmap ->
+ imageLoader(preview.uri, previewSize, isFirstBlock)?.let {
+ bitmap ->
previewSizeUpdater(preview, bitmap.width, bitmap.height)
- }
- ?: 0
+ } ?: 0
}
.getOrDefault(0)