Skip to content
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
6681eee
Add to Jetcaster: shared elements, swipetodismiss, lazy list animatio…
simona-anomis Oct 9, 2024
87b8385
Spotless formatting
simona-anomis Oct 9, 2024
15a032e
Remove comments and add mapping logic
simona-anomis Oct 15, 2024
3158d1d
Merge branch 'main' into anomis/jetcaster-ui-update
simona-anomis Oct 15, 2024
260cb85
Merge branch 'main' into anomis/jetcaster-ui-update
simona-anomis Oct 16, 2024
a27c1ca
Add shared elements, swipe to dismiss and removal logic to Jetcaster
simona-anomis Nov 6, 2024
3aebb7a
Add fade in and fade out for the player thumbnail placeholder
simona-anomis Nov 6, 2024
b90e21a
spotless formatting
simona-anomis Nov 6, 2024
91aa707
test spotless
simona-anomis Nov 6, 2024
b8e47f3
Merge main and resolve conflicts by adding removeEpisode to HomeActions
simona-anomis Jan 20, 2025
c7d597d
Adding dependencies and updating Theme file
MagicalMeghan Jan 22, 2025
ad737d4
Updating theme colors
MagicalMeghan Feb 5, 2025
dc3be91
Rounding the filter buttons
MagicalMeghan Feb 6, 2025
7513f23
Remove hero carousel from Discover
MagicalMeghan Feb 6, 2025
47e188d
Merge "Rounding the filter buttons" into main
MagicalMeghan Feb 7, 2025
faa0737
Merge "Updating theme colors" into main
riggaroo Feb 11, 2025
bdfaf28
Adding horizontal carousel
MagicalMeghan Feb 14, 2025
d32ecce
Adding pill toolbar
MagicalMeghan Feb 13, 2025
f247113
Merged main
MagicalMeghan Feb 21, 2025
c97e7de
adding uncontained carousel to discover tab
MagicalMeghan Feb 21, 2025
d80640e
Adding Media Player for podcast using "media3 ui compose"
satishshendeg Apr 8, 2025
4bf631f
updating typography for player screen
MagicalMeghan Apr 22, 2025
385ccd0
Merge "updating typography for player screen" into main
MagicalMeghan May 6, 2025
4f2e5cd
Update Podcast Detail Screen Layout
MagicalMeghan Feb 27, 2025
d49f3e3
update player buttons on player screen
MagicalMeghan May 5, 2025
7ea3c88
Updating discover carousel buttons
MagicalMeghan May 7, 2025
df55641
Merge "Update Podcast Detail Screen Layout" into main
MagicalMeghan May 9, 2025
02db77d
Merge "update player buttons on player screen" into main
MagicalMeghan May 9, 2025
6ff9397
Resolve merge conflicts
MagicalMeghan May 15, 2025
a1fd2b0
update media 3
MagicalMeghan May 15, 2025
96a29e2
Spotless fixes
MagicalMeghan May 15, 2025
d0581e2
Fix spotless for Jetcaster
mlykotom May 16, 2025
bb567f5
Apply spotless for Jetcaster
mlykotom May 16, 2025
c11adad
Fixes spotless checks for Jetcaster (#1566)
mlykotom May 16, 2025
3ab21f6
Fix unstable api lint
mlykotom May 16, 2025
56422b5
Update Episode params
MagicalMeghan May 16, 2025
8f39bce
spotless
MagicalMeghan May 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ class TestEpisodeStore : EpisodeStore {
it + episodes
}

override suspend fun deleteEpisode(episode: Episode) =
episodesFlow.update {
it - episode
}

override suspend fun isEmpty(): Boolean =
episodesFlow.first().isEmpty()
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import java.time.Duration
import java.time.OffsetDateTime

Expand All @@ -41,7 +43,7 @@ import java.time.OffsetDateTime
)
]
)
@Immutable
@TypeConverters(ListOfStringConverter::class)
data class Episode(
@PrimaryKey @ColumnInfo(name = "uri") val uri: String,
@ColumnInfo(name = "podcast_uri") val podcastUri: String,
Expand All @@ -50,5 +52,18 @@ data class Episode(
@ColumnInfo(name = "summary") val summary: String? = null,
@ColumnInfo(name = "author") val author: String? = null,
@ColumnInfo(name = "published") val published: OffsetDateTime,
@ColumnInfo(name = "duration") val duration: Duration? = null
@ColumnInfo(name = "duration") val duration: Duration? = null,
@ColumnInfo(name = "media_urls") val mediaUrls: List<String>
)

class ListOfStringConverter {
@TypeConverter
fun fromString(value: String): List<String> {
return value.split(",")
}

@TypeConverter
fun fromList(list: List<String>): String {
return list.joinToString(",")
}
Comment on lines +60 to +67
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ListOfStringConverter uses a simple comma (,) as a delimiter for storing a list of media URLs as a single string. While this works for many cases, could there be a scenario where a URL itself might contain a comma? If so, this would lead to incorrect parsing.

Consider if a more robust serialization method, like storing the list as a JSON array string (e.g., using kotlinx.serialization), might be safer for future-proofing, or if it's confirmed that media URLs will never contain commas.

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.example.jetcaster.core.data.database.model.Episode
import com.example.jetcaster.core.data.database.model.Podcast
import com.rometools.modules.itunes.EntryInformation
import com.rometools.modules.itunes.FeedInformation
import com.rometools.rome.feed.synd.SyndEnclosure
import com.rometools.rome.feed.synd.SyndEntry
import com.rometools.rome.feed.synd.SyndFeed
import com.rometools.rome.io.SyndFeedInput
Expand Down Expand Up @@ -124,7 +125,7 @@ sealed class PodcastRssResponse {
*/
private fun SyndFeed.toPodcastResponse(feedUrl: String): PodcastRssResponse {
val podcastUri = uri ?: feedUrl
val episodes = entries.map { it.toEpisode(podcastUri) }
val episodes = entries.map { it.toEpisode(podcastUri, it.enclosures) }

val feedInfo = getModule(PodcastModuleDtd) as? FeedInformation
val podcast = Podcast(
Expand All @@ -146,7 +147,10 @@ private fun SyndFeed.toPodcastResponse(feedUrl: String): PodcastRssResponse {
/**
* Map a Rome [SyndEntry] instance to our own [Episode] data class.
*/
private fun SyndEntry.toEpisode(podcastUri: String): Episode {
private fun SyndEntry.toEpisode(
podcastUri: String,
enclosures: List<SyndEnclosure>
): Episode {
val entryInformation = getModule(PodcastModuleDtd) as? EntryInformation
return Episode(
uri = uri,
Expand All @@ -156,7 +160,8 @@ private fun SyndEntry.toEpisode(podcastUri: String): Episode {
summary = entryInformation?.summary ?: description?.value,
subtitle = entryInformation?.subtitle,
published = Instant.ofEpochMilli(publishedDate.time).atOffset(ZoneOffset.UTC),
duration = entryInformation?.duration?.milliseconds?.let { Duration.ofMillis(it) }
duration = entryInformation?.duration?.milliseconds?.let { Duration.ofMillis(it) },
mediaUrls = enclosures.map { it.url }
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ interface EpisodeStore {
*/
suspend fun addEpisodes(episodes: Collection<Episode>)

/**
* Deletes an [Episode] from this store.
*/
suspend fun deleteEpisode(episode: Episode)

suspend fun isEmpty(): Boolean
}

Expand Down Expand Up @@ -86,6 +91,7 @@ class LocalEpisodeStore(
): Flow<List<EpisodeToPodcast>> {
return episodesDao.episodesForPodcastUri(podcastUri, limit)
}

/**
* Returns a list of episodes for the given podcast URIs ordering by most recently published
* to least recently published.
Expand All @@ -104,5 +110,12 @@ class LocalEpisodeStore(
override suspend fun addEpisodes(episodes: Collection<Episode>) =
episodesDao.insertAll(episodes)

/**
* Deletes an [Episode] from this store.
*/
override suspend fun deleteEpisode(episode: Episode) {
episodesDao.delete(episode)
}

override suspend fun isEmpty(): Boolean = episodesDao.count() == 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ fun PodcastImage(
podcastImageUrl: String,
contentDescription: String?,
modifier: Modifier = Modifier,
// TODO: Remove the nested component modifier when shared elements are applied to entire app
imageModifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.Crop,
placeholderBrush: Brush = thumbnailPlaceholderDefaultBrush(),
) {
Expand Down Expand Up @@ -80,7 +82,7 @@ fun PodcastImage(
}
else -> {
Box(
modifier = Modifier
modifier = modifier
.background(placeholderBrush)
.fillMaxSize()

Expand All @@ -92,7 +94,7 @@ fun PodcastImage(
painter = imageLoader,
contentDescription = contentDescription,
contentScale = contentScale,
modifier = modifier,
modifier = modifier.then(imageModifier)
)
}
}
Loading
Loading