Skip to content

Commit 526d10d

Browse files
authored
Merge branch 'master' into intro-skipper
2 parents a93d790 + 70b8a12 commit 526d10d

19 files changed

+461
-421
lines changed

.github/workflows/app-build.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
- name: Create publish bundle
2929
run: mkdir -p build/gh-app-publish/; find app/build/ -iname "*.apk" -exec mv "{}" build/gh-app-publish/ \;
3030
- name: Upload artifacts
31-
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
31+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
3232
with:
3333
name: build-artifacts
3434
retention-days: 14

.github/workflows/app-lint.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
- name: Run detekt and lint tasks
2929
run: ./gradlew detekt lint
3030
- name: Upload SARIF files
31-
uses: github/codeql-action/upload-sarif@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
31+
uses: github/codeql-action/upload-sarif@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
3232
if: ${{ always() }}
3333
with:
3434
sarif_file: .

app/src/main/java/org/jellyfin/androidtv/ui/NowPlayingView.kt

+58-61
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import androidx.compose.animation.fadeOut
99
import androidx.compose.foundation.layout.Arrangement
1010
import androidx.compose.foundation.layout.Box
1111
import androidx.compose.foundation.layout.Column
12-
import androidx.compose.foundation.layout.PaddingValues
1312
import androidx.compose.foundation.layout.Row
1413
import androidx.compose.foundation.layout.fillMaxWidth
1514
import androidx.compose.foundation.layout.height
@@ -34,6 +33,7 @@ import androidx.compose.ui.unit.dp
3433
import androidx.compose.ui.unit.sp
3534
import androidx.core.content.ContextCompat
3635
import org.jellyfin.androidtv.R
36+
import org.jellyfin.androidtv.ui.base.JellyfinTheme
3737
import org.jellyfin.androidtv.ui.base.ProvideTextStyle
3838
import org.jellyfin.androidtv.ui.base.Text
3939
import org.jellyfin.androidtv.ui.base.button.ButtonBase
@@ -70,74 +70,71 @@ fun NowPlayingComposable(
7070
) {
7171
ButtonBase(
7272
onClick = { navigationRepository.navigate(Destinations.nowPlaying) },
73-
shape = RoundedCornerShape(4.dp),
74-
contentPadding = PaddingValues(0.dp),
73+
shape = JellyfinTheme.shapes.extraSmall,
7574
modifier = Modifier
7675
.widthIn(0.dp, 250.dp)
7776
) {
78-
Box {
79-
Box(
80-
modifier = Modifier
81-
.align(Alignment.BottomStart)
82-
.fillMaxWidth()
83-
.height(1.dp)
84-
.drawWithContent {
85-
// Background
86-
drawRect(Color.White, alpha = 0.4f)
87-
// Foreground
88-
drawRect(Color.White, size = size.copy(width = progress * size.width))
89-
}
90-
)
77+
Box(
78+
modifier = Modifier
79+
.align(Alignment.BottomStart)
80+
.fillMaxWidth()
81+
.height(1.dp)
82+
.drawWithContent {
83+
// Background
84+
drawRect(Color.White, alpha = 0.4f)
85+
// Foreground
86+
drawRect(Color.White, size = size.copy(width = progress * size.width))
87+
}
88+
)
9189

92-
ProvideTextStyle(
93-
value = TextStyle.Default.copy(
94-
fontSize = 12.sp,
95-
)
90+
ProvideTextStyle(
91+
value = TextStyle.Default.copy(
92+
fontSize = 12.sp,
93+
)
94+
) {
95+
Row(
96+
horizontalArrangement = Arrangement.spacedBy(10.dp),
97+
verticalAlignment = Alignment.CenterVertically,
98+
modifier = Modifier
99+
.padding(5.dp)
96100
) {
97-
Row(
98-
horizontalArrangement = Arrangement.spacedBy(10.dp),
99-
verticalAlignment = Alignment.CenterVertically,
100-
modifier = Modifier
101-
.padding(5.dp)
102-
) {
103-
val primaryImageTag = item?.imageTags?.get(ImageType.PRIMARY)
104-
val (imageItemId, imageTag) = when {
105-
primaryImageTag != null -> item.id to primaryImageTag
106-
(item?.albumId != null && item.albumPrimaryImageTag != null) -> item.albumId to item.albumPrimaryImageTag
107-
else -> null to null
108-
}
109-
val imageUrl = when {
110-
imageItemId != null && imageTag != null -> imageHelper.getImageUrl(
111-
itemId = imageItemId,
112-
imageType = ImageType.PRIMARY,
113-
imageTag = imageTag
114-
)
101+
val primaryImageTag = item?.imageTags?.get(ImageType.PRIMARY)
102+
val (imageItemId, imageTag) = when {
103+
primaryImageTag != null -> item.id to primaryImageTag
104+
(item?.albumId != null && item.albumPrimaryImageTag != null) -> item.albumId to item.albumPrimaryImageTag
105+
else -> null to null
106+
}
107+
val imageUrl = when {
108+
imageItemId != null && imageTag != null -> imageHelper.getImageUrl(
109+
itemId = imageItemId,
110+
imageType = ImageType.PRIMARY,
111+
imageTag = imageTag
112+
)
115113

116-
else -> null
117-
}
118-
val imageBlurHash = imageTag?.let { tag ->
119-
item?.imageBlurHashes?.get(ImageType.PRIMARY)?.get(tag)
120-
}
114+
else -> null
115+
}
116+
val imageBlurHash = imageTag?.let { tag ->
117+
item?.imageBlurHashes?.get(ImageType.PRIMARY)?.get(tag)
118+
}
121119

122-
AsyncImage(
123-
url = imageUrl,
124-
blurHash = imageBlurHash,
125-
placeholder = ContextCompat.getDrawable(LocalContext.current, R.drawable.ic_album),
126-
aspectRatio = item?.primaryImageAspectRatio ?: 1.0,
127-
modifier = Modifier
128-
.size(35.dp)
129-
.clip(RoundedCornerShape(4.dp)),
130-
scaleType = ImageView.ScaleType.CENTER_CROP,
131-
)
120+
AsyncImage(
121+
url = imageUrl,
122+
blurHash = imageBlurHash,
123+
placeholder = ContextCompat.getDrawable(LocalContext.current, R.drawable.ic_album),
124+
aspectRatio = item?.primaryImageAspectRatio ?: 1.0,
125+
modifier = Modifier
126+
.size(35.dp)
127+
.clip(RoundedCornerShape(4.dp)),
128+
scaleType = ImageView.ScaleType.CENTER_CROP,
129+
)
132130

133-
Column(
134-
verticalArrangement = Arrangement.SpaceAround,
135-
) {
136-
// Name
137-
Text(text = item?.name.orEmpty(), maxLines = 1, overflow = TextOverflow.Ellipsis)
138-
val artists = item?.artists ?: item?.albumArtists ?: item?.albumArtist?.let(::listOf)
139-
Text(text = artists?.joinToString(", ").orEmpty(), maxLines = 1, overflow = TextOverflow.Ellipsis)
140-
}
131+
Column(
132+
verticalArrangement = Arrangement.SpaceAround,
133+
) {
134+
// Name
135+
Text(text = item?.name.orEmpty(), maxLines = 1, overflow = TextOverflow.Ellipsis)
136+
val artists = item?.artists ?: item?.albumArtists ?: item?.albumArtist?.let(::listOf)
137+
Text(text = artists?.joinToString(", ").orEmpty(), maxLines = 1, overflow = TextOverflow.Ellipsis)
141138
}
142139
}
143140
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package org.jellyfin.androidtv.ui.base.button
2+
3+
import androidx.compose.foundation.interaction.MutableInteractionSource
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.PaddingValues
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.RowScope
8+
import androidx.compose.foundation.layout.defaultMinSize
9+
import androidx.compose.foundation.layout.padding
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.ui.Alignment
12+
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.graphics.Shape
14+
import androidx.compose.ui.unit.dp
15+
16+
@Composable
17+
private fun ButtonRow(
18+
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
19+
content: @Composable RowScope.() -> Unit,
20+
) = Row(
21+
modifier = Modifier
22+
.defaultMinSize(
23+
minWidth = 58.dp,
24+
minHeight = 40.dp
25+
)
26+
.padding(contentPadding),
27+
horizontalArrangement = Arrangement.Center,
28+
verticalAlignment = Alignment.CenterVertically,
29+
content = content
30+
)
31+
32+
@Composable
33+
fun Button(
34+
onClick: () -> Unit,
35+
modifier: Modifier = Modifier,
36+
onLongClick: (() -> Unit)? = null,
37+
enabled: Boolean = true,
38+
shape: Shape = ButtonDefaults.Shape,
39+
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
40+
interactionSource: MutableInteractionSource? = null,
41+
content: @Composable RowScope.() -> Unit
42+
) {
43+
ButtonBase(
44+
onClick = onClick,
45+
modifier = modifier,
46+
onLongClick = onLongClick,
47+
enabled = enabled,
48+
shape = shape,
49+
interactionSource = interactionSource,
50+
) {
51+
ButtonRow(
52+
contentPadding = contentPadding,
53+
content = content,
54+
)
55+
}
56+
}
57+
58+
@Composable
59+
fun ProgressButton(
60+
progress: Float,
61+
onClick: () -> Unit,
62+
modifier: Modifier = Modifier,
63+
onLongClick: (() -> Unit)? = null,
64+
enabled: Boolean = true,
65+
shape: Shape = ButtonDefaults.Shape,
66+
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
67+
interactionSource: MutableInteractionSource? = null,
68+
content: @Composable RowScope.() -> Unit
69+
) {
70+
ProgressButtonBase(
71+
progress = progress,
72+
onClick = onClick,
73+
modifier = modifier,
74+
onLongClick = onLongClick,
75+
enabled = enabled,
76+
shape = shape,
77+
interactionSource = interactionSource,
78+
) {
79+
ButtonRow(
80+
contentPadding = contentPadding,
81+
content = content,
82+
)
83+
}
84+
}
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,21 @@
11
package org.jellyfin.androidtv.ui.base.button
22

33
import androidx.compose.foundation.ExperimentalFoundationApi
4-
import androidx.compose.foundation.LocalIndication
54
import androidx.compose.foundation.background
65
import androidx.compose.foundation.combinedClickable
76
import androidx.compose.foundation.interaction.MutableInteractionSource
87
import androidx.compose.foundation.interaction.collectIsFocusedAsState
98
import androidx.compose.foundation.interaction.collectIsPressedAsState
10-
import androidx.compose.foundation.layout.Arrangement
119
import androidx.compose.foundation.layout.Box
12-
import androidx.compose.foundation.layout.PaddingValues
13-
import androidx.compose.foundation.layout.Row
14-
import androidx.compose.foundation.layout.RowScope
15-
import androidx.compose.foundation.layout.defaultMinSize
16-
import androidx.compose.foundation.layout.padding
17-
import androidx.compose.foundation.shape.CircleShape
10+
import androidx.compose.foundation.layout.BoxScope
1811
import androidx.compose.runtime.Composable
1912
import androidx.compose.runtime.getValue
2013
import androidx.compose.runtime.remember
21-
import androidx.compose.ui.Alignment
2214
import androidx.compose.ui.Modifier
15+
import androidx.compose.ui.draw.clip
2316
import androidx.compose.ui.graphics.Shape
24-
import androidx.compose.ui.graphics.graphicsLayer
2517
import androidx.compose.ui.res.colorResource
2618
import androidx.compose.ui.semantics.Role
27-
import androidx.compose.ui.unit.dp
2819
import androidx.compose.ui.unit.sp
2920
import org.jellyfin.androidtv.R
3021
import org.jellyfin.androidtv.ui.base.JellyfinTheme
@@ -37,10 +28,9 @@ fun ButtonBase(
3728
modifier: Modifier = Modifier,
3829
onLongClick: (() -> Unit)? = null,
3930
enabled: Boolean = true,
40-
shape: Shape = CircleShape,
41-
contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 10.dp),
31+
shape: Shape = ButtonDefaults.Shape,
4232
interactionSource: MutableInteractionSource? = null,
43-
content: @Composable RowScope.() -> Unit
33+
content: @Composable BoxScope.() -> Unit
4434
) {
4535
@Suppress("NAME_SHADOWING")
4636
val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
@@ -61,34 +51,20 @@ fun ButtonBase(
6151
else -> containerColor to contentColor
6252
}
6353

64-
Box(
65-
modifier = modifier
66-
.combinedClickable(
67-
interactionSource = interactionSource,
68-
indication = LocalIndication.current,
69-
enabled = enabled,
70-
role = Role.Button,
71-
onClick = onClick,
72-
onLongClick = onLongClick,
73-
)
74-
.background(colors.first, shape)
75-
.graphicsLayer {
76-
this.shape = shape
77-
this.clip = true
78-
}
79-
) {
80-
ProvideTextStyle(value = JellyfinTheme.typography.default.copy(fontSize = 14.sp, color = colors.second)) {
81-
Row(
82-
modifier = Modifier
83-
.defaultMinSize(
84-
minWidth = 58.dp,
85-
minHeight = 40.dp
86-
)
87-
.padding(contentPadding),
88-
horizontalArrangement = Arrangement.Center,
89-
verticalAlignment = Alignment.CenterVertically,
90-
content = content
91-
)
92-
}
54+
ProvideTextStyle(value = JellyfinTheme.typography.default.copy(fontSize = 14.sp, color = colors.second)) {
55+
Box(
56+
modifier = modifier
57+
.combinedClickable(
58+
interactionSource = interactionSource,
59+
indication = null,
60+
enabled = enabled,
61+
role = Role.Button,
62+
onClick = onClick,
63+
onLongClick = onLongClick,
64+
)
65+
.background(colors.first, shape)
66+
.clip(shape),
67+
content = content,
68+
)
9369
}
9470
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.jellyfin.androidtv.ui.base.button
2+
3+
import androidx.compose.foundation.layout.PaddingValues
4+
import androidx.compose.foundation.shape.CircleShape
5+
import androidx.compose.ui.graphics.Shape
6+
import androidx.compose.ui.unit.dp
7+
8+
object ButtonDefaults {
9+
val Shape: Shape = CircleShape
10+
val ContentPadding: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 10.dp)
11+
}

0 commit comments

Comments
 (0)