@@ -8,9 +8,11 @@ import androidx.compose.foundation.focusGroup
8
8
import androidx.compose.foundation.indication
9
9
import androidx.compose.foundation.interaction.MutableInteractionSource
10
10
import androidx.compose.foundation.layout.Arrangement
11
+ import androidx.compose.foundation.layout.BoxWithConstraints
11
12
import androidx.compose.foundation.layout.Column
12
13
import androidx.compose.foundation.layout.PaddingValues
13
14
import androidx.compose.foundation.layout.Spacer
15
+ import androidx.compose.foundation.layout.aspectRatio
14
16
import androidx.compose.foundation.layout.fillMaxWidth
15
17
import androidx.compose.foundation.layout.height
16
18
import androidx.compose.foundation.layout.width
@@ -21,25 +23,42 @@ import androidx.compose.foundation.lazy.rememberLazyListState
21
23
import androidx.compose.foundation.text.selection.SelectionContainer
22
24
import androidx.compose.material.ContentAlpha
23
25
import androidx.compose.material.LocalContentAlpha
26
+ import androidx.compose.material.icons.Icons
27
+ import androidx.compose.material.icons.outlined.ErrorOutline
28
+ import androidx.compose.material.icons.outlined.Terrain
24
29
import androidx.compose.material3.MaterialTheme
25
30
import androidx.compose.material3.Text
26
31
import androidx.compose.runtime.Composable
27
32
import androidx.compose.runtime.CompositionLocalProvider
33
+ import androidx.compose.runtime.getValue
28
34
import androidx.compose.runtime.remember
29
35
import androidx.compose.ui.Alignment
30
36
import androidx.compose.ui.Modifier
37
+ import androidx.compose.ui.draw.clip
38
+ import androidx.compose.ui.graphics.RectangleShape
39
+ import androidx.compose.ui.layout.ContentScale
40
+ import androidx.compose.ui.platform.LocalContext
31
41
import androidx.compose.ui.res.stringResource
32
42
import androidx.compose.ui.semantics.CustomAccessibilityAction
33
43
import androidx.compose.ui.semantics.clearAndSetSemantics
34
44
import androidx.compose.ui.semantics.contentDescription
35
45
import androidx.compose.ui.semantics.customActions
36
46
import androidx.compose.ui.semantics.semantics
37
47
import androidx.compose.ui.unit.dp
48
+ import coil.compose.AsyncImage
49
+ import coil.request.ImageRequest
50
+ import coil.size.Precision
51
+ import coil.size.Scale
38
52
import com.nononsenseapps.feeder.R
39
53
import com.nononsenseapps.feeder.archmodel.Enclosure
54
+ import com.nononsenseapps.feeder.archmodel.isImage
55
+ import com.nononsenseapps.feeder.ui.compose.coil.rememberTintedVectorPainter
40
56
import com.nononsenseapps.feeder.ui.compose.text.WithBidiDeterminedLayoutDirection
57
+ import com.nononsenseapps.feeder.ui.compose.text.WithTooltipIfNotBlank
58
+ import com.nononsenseapps.feeder.ui.compose.text.rememberMaxImageWidth
41
59
import com.nononsenseapps.feeder.ui.compose.theme.LinkTextStyle
42
60
import com.nononsenseapps.feeder.ui.compose.theme.LocalDimens
61
+ import com.nononsenseapps.feeder.ui.compose.theme.hasImageAspectRatioInReader
43
62
import com.nononsenseapps.feeder.ui.compose.utils.ProvideScaledText
44
63
import com.nononsenseapps.feeder.ui.compose.utils.ScreenType
45
64
import com.nononsenseapps.feeder.ui.compose.utils.focusableInNonTouchMode
@@ -158,15 +177,47 @@ fun ReaderView(
158
177
159
178
if (enclosure.present) {
160
179
item {
161
- val openLabel = if (enclosure.name.isBlank()) {
162
- stringResource(R .string.open_enclosed_media)
180
+ if (enclosure.isImage) {
181
+ BoxWithConstraints (
182
+ modifier = Modifier
183
+ .clip(RectangleShape )
184
+ .fillMaxWidth(),
185
+ ) {
186
+ WithTooltipIfNotBlank (tooltip = enclosure.name) { innerModifier ->
187
+ val imageWidth by rememberMaxImageWidth()
188
+ AsyncImage (
189
+ model = ImageRequest .Builder (LocalContext .current)
190
+ .data(enclosure.link)
191
+ .scale(Scale .FIT )
192
+ .size(imageWidth)
193
+ .precision(Precision .INEXACT )
194
+ .build(),
195
+ contentDescription = enclosure.name,
196
+ placeholder = rememberTintedVectorPainter(
197
+ Icons .Outlined .Terrain ,
198
+ ),
199
+ error = rememberTintedVectorPainter(Icons .Outlined .ErrorOutline ),
200
+ contentScale = if (dimens.hasImageAspectRatioInReader) {
201
+ ContentScale .Fit
202
+ } else {
203
+ ContentScale .FillWidth
204
+ },
205
+ modifier = innerModifier
206
+ .fillMaxWidth()
207
+ .run {
208
+ dimens.imageAspectRatioInReader?.let { ratio ->
209
+ aspectRatio(ratio)
210
+ } ? : this
211
+ },
212
+ )
213
+ }
214
+ }
163
215
} else {
164
- stringResource(R .string.open_enclosed_media_file, enclosure.name)
165
- }
166
- Column (
167
- modifier = Modifier
168
- .width(dimens.maxReaderWidth),
169
- ) {
216
+ val openLabel = if (enclosure.name.isBlank()) {
217
+ stringResource(R .string.open_enclosed_media)
218
+ } else {
219
+ stringResource(R .string.open_enclosed_media_file, enclosure.name)
220
+ }
170
221
ProvideScaledText (
171
222
style = MaterialTheme .typography.bodyLarge.merge(
172
223
LinkTextStyle (),
@@ -175,6 +226,7 @@ fun ReaderView(
175
226
Text (
176
227
text = openLabel,
177
228
modifier = Modifier
229
+ .width(dimens.maxReaderWidth)
178
230
.clickable {
179
231
onEnclosureClick()
180
232
}
@@ -189,7 +241,11 @@ fun ReaderView(
189
241
} catch (e: Exception ) {
190
242
// Observed nullpointer exception when setting customActions
191
243
// No clue why it could be null
192
- Log .e(" FeederReaderScreen" , " Exception in semantics" , e)
244
+ Log .e(
245
+ LOG_TAG ,
246
+ " Exception in semantics" ,
247
+ e,
248
+ )
193
249
}
194
250
},
195
251
)
@@ -202,3 +258,5 @@ fun ReaderView(
202
258
}
203
259
}
204
260
}
261
+
262
+ private const val LOG_TAG = " FEEDER_READER"
0 commit comments