@@ -22,8 +22,6 @@ import android.graphics.drawable.BitmapDrawable
2222import android.graphics.drawable.Drawable
2323import android.net.Uri
2424import android.util.Log
25- import androidx.compose.material3.darkColorScheme
26- import androidx.compose.material3.lightColorScheme
2725import androidx.compose.runtime.Composable
2826import androidx.compose.runtime.LaunchedEffect
2927import androidx.compose.runtime.getValue
@@ -32,6 +30,7 @@ import androidx.compose.runtime.remember
3230import androidx.compose.runtime.rememberCoroutineScope
3331import androidx.compose.runtime.setValue
3432import androidx.compose.ui.graphics.Color
33+ import androidx.compose.ui.unit.Dp
3534import androidx.compose.ui.unit.DpSize
3635import androidx.compose.ui.unit.dp
3736import androidx.compose.ui.unit.sp
@@ -59,7 +58,6 @@ import androidx.glance.layout.Spacer
5958import androidx.glance.layout.fillMaxSize
6059import androidx.glance.layout.padding
6160import androidx.glance.layout.size
62- import androidx.glance.material3.ColorProviders
6361import androidx.glance.text.FontWeight
6462import androidx.glance.text.Text
6563import androidx.glance.text.TextStyle
@@ -70,7 +68,7 @@ import coil.request.ImageRequest
7068import kotlinx.coroutines.Dispatchers
7169import kotlinx.coroutines.launch
7270
73- internal val TAG = " JetcasterAppWidegt "
71+ internal val TAG = " JetcasterAppWidget "
7472
7573/* *
7674 * Implementation of App Widget functionality.
@@ -85,28 +83,32 @@ data class JetcasterAppWidgetViewState(
8583 val podcastTitle : String ,
8684 val isPlaying : Boolean ,
8785 val albumArtUri : String ,
88- val useDynamicColor : Boolean
8986)
9087
9188private object Sizes {
89+ val short = 72 .dp
9290 val minWidth = 140 .dp
9391 val smallBucketCutoffWidth = 250 .dp // anything from minWidth to this will have no title
9492
95- val imageNormal = 80 .dp
96- val imageCondensed = 60 .dp
93+ val normal = 80 .dp
94+ val medium = 56 .dp
95+ val condensed = 48 .dp
9796}
9897
99- private enum class SizeBucket { Invalid , Narrow , Normal }
98+ private enum class SizeBucket { Invalid , Narrow , Normal , NarrowShort , NormalShort }
10099
101100@Composable
102101private fun calculateSizeBucket (): SizeBucket {
103102 val size: DpSize = LocalSize .current
104103 val width = size.width
104+ val height = size.height
105105
106106 return when {
107107 width < Sizes .minWidth -> SizeBucket .Invalid
108- width <= Sizes .smallBucketCutoffWidth -> SizeBucket .Narrow
109- else -> SizeBucket .Normal
108+ width <= Sizes .smallBucketCutoffWidth ->
109+ if (height >= Sizes .short) SizeBucket .Narrow else SizeBucket .NarrowShort
110+ else ->
111+ if (height >= Sizes .short) SizeBucket .Normal else SizeBucket .NormalShort
110112 }
111113}
112114
@@ -122,29 +124,39 @@ class JetcasterAppWidget : GlanceAppWidget() {
122124 podcastTitle = " Now in Android" ,
123125 isPlaying = false ,
124126 albumArtUri = " https://static.libsyn.com/p/assets/9/f/f/3/" +
125- " 9ff3cb5dc6cfb3e2e5bbc093207a2619/NIA000_PodcastThumbnail.png" ,
126- useDynamicColor = false
127+ " 9ff3cb5dc6cfb3e2e5bbc093207a2619/NIA000_PodcastThumbnail.png"
127128 )
128129
129130 provideContent {
130131 val sizeBucket = calculateSizeBucket()
131132 val playPauseIcon = if (testState.isPlaying) PlayPauseIcon .Pause else PlayPauseIcon .Play
132133 val artUri = Uri .parse(testState.albumArtUri)
133134
134- GlanceTheme (
135- colors = ColorProviders (
136- light = lightColorScheme(),
137- dark = darkColorScheme()
138- )
139- ) {
135+ GlanceTheme {
140136 when (sizeBucket) {
141137 SizeBucket .Invalid -> WidgetUiInvalidSize ()
142- SizeBucket .Narrow -> WidgetUiNarrow (
138+ SizeBucket .Narrow -> Widget (
139+ iconSize = Sizes .medium,
143140 imageUri = artUri,
144141 playPauseIcon = playPauseIcon
145142 )
146143
147144 SizeBucket .Normal -> WidgetUiNormal (
145+ iconSize = Sizes .normal,
146+ title = testState.episodeTitle,
147+ subtitle = testState.podcastTitle,
148+ imageUri = artUri,
149+ playPauseIcon = playPauseIcon
150+ )
151+
152+ SizeBucket .NarrowShort -> Widget (
153+ iconSize = Sizes .condensed,
154+ imageUri = artUri,
155+ playPauseIcon = playPauseIcon
156+ )
157+
158+ SizeBucket .NormalShort -> WidgetUiNormal (
159+ iconSize = Sizes .condensed,
148160 title = testState.episodeTitle,
149161 subtitle = testState.podcastTitle,
150162 imageUri = artUri,
@@ -162,20 +174,23 @@ private fun WidgetUiNormal(
162174 subtitle : String ,
163175 imageUri : Uri ,
164176 playPauseIcon : PlayPauseIcon ,
177+ iconSize : Dp ,
165178) {
166- Scaffold (titleBar = {} /* title bar will be optional starting in glance 1.1.0-beta3*/ ) {
179+
180+ Scaffold {
167181 Row (
168182 GlanceModifier .fillMaxSize(), verticalAlignment = Alignment .Vertical .CenterVertically
169183 ) {
170- AlbumArt (imageUri, GlanceModifier .size(Sizes .imageNormal ))
184+ AlbumArt (imageUri, GlanceModifier .size(iconSize ))
171185 PodcastText (title, subtitle, modifier = GlanceModifier .padding(16 .dp).defaultWeight())
172- PlayPauseButton (playPauseIcon, {})
186+ PlayPauseButton (GlanceModifier .size(iconSize), playPauseIcon, {})
173187 }
174188 }
175189}
176190
177191@Composable
178- private fun WidgetUiNarrow (
192+ private fun Widget (
193+ iconSize : Dp ,
179194 imageUri : Uri ,
180195 playPauseIcon : PlayPauseIcon ,
181196) {
@@ -184,9 +199,9 @@ private fun WidgetUiNarrow(
184199 modifier = GlanceModifier .fillMaxSize(),
185200 verticalAlignment = Alignment .Vertical .CenterVertically
186201 ) {
187- AlbumArt (imageUri, GlanceModifier .size(Sizes .imageCondensed ))
202+ AlbumArt (imageUri, GlanceModifier .size(iconSize ))
188203 Spacer (GlanceModifier .defaultWeight())
189- PlayPauseButton (playPauseIcon, {})
204+ PlayPauseButton (GlanceModifier .size(iconSize), playPauseIcon, {})
190205 }
191206 }
192207}
@@ -209,22 +224,44 @@ private fun AlbumArt(
209224@Composable
210225fun PodcastText (title : String , subtitle : String , modifier : GlanceModifier = GlanceModifier ) {
211226 val fgColor = GlanceTheme .colors.onPrimaryContainer
212- Column (modifier) {
213- Text (
214- text = title,
215- style = TextStyle (fontSize = 16 .sp, fontWeight = FontWeight .Medium , color = fgColor),
216- maxLines = 2 ,
217- )
218- Text (
219- text = subtitle,
220- style = TextStyle (fontSize = 14 .sp, color = fgColor),
221- maxLines = 2 ,
222- )
227+ val size = LocalSize .current
228+ when {
229+ size.height >= Sizes .short -> Column (modifier) {
230+ Text (
231+ text = title,
232+ style = TextStyle (
233+ fontSize = 16 .sp,
234+ fontWeight = FontWeight .Medium ,
235+ color = fgColor
236+ ),
237+ maxLines = 2 ,
238+ )
239+ Text (
240+ text = subtitle,
241+ style = TextStyle (fontSize = 14 .sp, color = fgColor),
242+ maxLines = 2 ,
243+ )
244+ }
245+ else -> Column (modifier) {
246+ Text (
247+ text = title,
248+ style = TextStyle (
249+ fontSize = 12 .sp,
250+ fontWeight = FontWeight .Medium ,
251+ color = fgColor
252+ ),
253+ maxLines = 1 ,
254+ )
255+ }
223256 }
224257}
225258
226259@Composable
227- private fun PlayPauseButton (state : PlayPauseIcon , onClick : () -> Unit ) {
260+ private fun PlayPauseButton (
261+ modifier : GlanceModifier = GlanceModifier .size(Sizes .normal),
262+ state : PlayPauseIcon ,
263+ onClick : () -> Unit
264+ ) {
228265 val (iconRes: Int , description: Int ) = when (state) {
229266 PlayPauseIcon .Play -> R .drawable.outline_play_arrow_24 to R .string.content_description_play
230267 PlayPauseIcon .Pause -> R .drawable.outline_pause_24 to R .string.content_description_pause
@@ -234,7 +271,8 @@ private fun PlayPauseButton(state: PlayPauseIcon, onClick: () -> Unit) {
234271 val contentDescription = LocalContext .current.getString(description)
235272
236273 SquareIconButton (
237- provider,
274+ modifier = modifier,
275+ imageProvider = provider,
238276 contentDescription = contentDescription,
239277 onClick = onClick
240278 )
0 commit comments