Skip to content

Jetcaster Material Expressive update #1565

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
May 16, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
26 changes: 26 additions & 0 deletions Jetcaster/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# When authoring changes in .editorconfig, run ./gradlew spotlessApply --no-daemon
# Reference: https://github.com/diffplug/spotless/issues/1924
[*.{kt,kts}]
ktlint_code_style = android_studio
ij_kotlin_allow_trailing_comma = true
ij_kotlin_allow_trailing_comma_on_call_site = true
max_line_length = 140 # ktlint official
ktlint_function_naming_ignore_when_annotated_with = Composable, Test
ktlint_standard_filename = disabled
ktlint_standard_package-name = disabled
ktlint_standard_property-naming = disabled
ktlint_standard_backing-property-naming = disabled
ktlint_standard_argument-list-wrapping = disabled
ktlint_standard_parameter-list-wrapping = disabled
ktlint_standard_double-colon-spacing = disabled
ktlint_standard_enum-entry-name-case = disabled
ktlint_standard_multiline-if-else = disabled
ktlint_standard_no-empty-first-line-in-method-block = disabled
ktlint_standard_package-name = disabled
ktlint_standard_trailing-comma = disabled
ktlint_standard_spacing-around-angle-brackets = disabled
ktlint_standard_spacing-between-declarations-with-annotations = disabled
ktlint_standard_spacing-between-declarations-with-comments = disabled
ktlint_standard_unary-op-spacing = disabled
ktlint_standard_function-expression-body = disabled
ktlint_standard_value-parameter-comment = disabled
37 changes: 5 additions & 32 deletions Jetcaster/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,45 +32,18 @@ apply("${project.rootDir}/buildscripts/toml-updater-config.gradle")
subprojects {
apply(plugin = "com.diffplug.spotless")
configure<com.diffplug.gradle.spotless.SpotlessExtension> {
ratchetFrom = "origin/main"
kotlin {
target("**/*.kt")
targetExclude("**/build/**/*.kt")
ktlint().editorConfigOverride(
mapOf(
"ktlint_code_style" to "android_studio",
"ij_kotlin_allow_trailing_comma" to true,
"ktlint_function_naming_ignore_when_annotated_with" to "Composable",
// These rules were introduced in ktlint 0.46.0 and should not be
// enabled without further discussion. They are disabled for now.
// See: https://github.com/pinterest/ktlint/releases/tag/0.46.0
"disabled_rules" to
"filename," +
"annotation,annotation-spacing," +
"argument-list-wrapping," +
"double-colon-spacing," +
"enum-entry-name-case," +
"multiline-if-else," +
"no-empty-first-line-in-method-block," +
"package-name," +
"trailing-comma," +
"spacing-around-angle-brackets," +
"spacing-between-declarations-with-annotations," +
"spacing-between-declarations-with-comments," +
"unary-op-spacing"
)
)
targetExclude("${layout.buildDirectory}/**/*.kt")
ktlint()
licenseHeaderFile(rootProject.file("spotless/copyright.kt"))
}
format("kts") {
target("**/*.kts")
targetExclude("**/build/**/*.kts")
// Look for the first line that doesn't have a block comment (assumed to be the license)
licenseHeaderFile(rootProject.file("spotless/copyright.kt"), "(^(?![\\/ ]\\*).*$)")
}
kotlinGradle {
target("*.gradle.kts")
targetExclude("${layout.buildDirectory}/**/*.kt")
ktlint()
// Look for the first line that doesn't have a block comment (assumed to be the license)
licenseHeaderFile(rootProject.file("spotless/copyright.kt"), "(^(?![\\/ ]\\*).*$)")
}
}
}
29 changes: 26 additions & 3 deletions Jetcaster/core/data-testing/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}

android {
namespace = "com.example.jetcaster.core.data.testing"
compileSdk = libs.versions.compileSdk.get().toInt()
compileSdk =
libs.versions.compileSdk
.get()
.toInt()

defaultConfig {
minSdk = libs.versions.minSdk.get().toInt()
minSdk =
libs.versions.minSdk
.get()
.toInt()

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
Expand All @@ -19,7 +42,7 @@ android {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
"proguard-rules.pro",
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,14 @@ class TestCategoryStore : CategoryStore {
private val episodesFromPodcasts =
MutableStateFlow<Map<Long, List<EpisodeToPodcast>>>(emptyMap())

override fun categoriesSortedByPodcastCount(limit: Int): Flow<List<Category>> =
categoryFlow
override fun categoriesSortedByPodcastCount(limit: Int): Flow<List<Category>> = categoryFlow

override fun podcastsInCategorySortedByPodcastCount(
categoryId: Long,
limit: Int
): Flow<List<PodcastWithExtraInfo>> = podcastsInCategoryFlow.map {
it[categoryId]?.take(limit) ?: emptyList()
}
override fun podcastsInCategorySortedByPodcastCount(categoryId: Long, limit: Int): Flow<List<PodcastWithExtraInfo>> =
podcastsInCategoryFlow.map {
it[categoryId]?.take(limit) ?: emptyList()
}

override fun episodesFromPodcastsInCategory(
categoryId: Long,
limit: Int
): Flow<List<EpisodeToPodcast>> = episodesFromPodcasts.map {
override fun episodesFromPodcastsInCategory(categoryId: Long, limit: Int): Flow<List<EpisodeToPodcast>> = episodesFromPodcasts.map {
it[categoryId]?.take(limit) ?: emptyList()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,52 +29,47 @@ import kotlinx.coroutines.flow.update
class TestEpisodeStore : EpisodeStore {

private val episodesFlow = MutableStateFlow<List<Episode>>(listOf())
override fun episodeWithUri(episodeUri: String): Flow<Episode> =
episodesFlow.map { episodes ->
episodes.first { it.uri == episodeUri }
override fun episodeWithUri(episodeUri: String): Flow<Episode> = episodesFlow.map { episodes ->
episodes.first { it.uri == episodeUri }
}

override fun episodeAndPodcastWithUri(episodeUri: String): Flow<EpisodeToPodcast> = episodesFlow.map { episodes ->
val e = episodes.first {
it.uri == episodeUri
}
EpisodeToPodcast().apply {
episode = e
_podcasts = emptyList()
}
}

override fun episodeAndPodcastWithUri(episodeUri: String): Flow<EpisodeToPodcast> =
episodesFlow.map { episodes ->
val e = episodes.first {
it.uri == episodeUri
}
override fun episodesInPodcast(podcastUri: String, limit: Int): Flow<List<EpisodeToPodcast>> = episodesFlow.map { episodes ->
episodes.filter {
it.podcastUri == podcastUri
}.map { e ->
EpisodeToPodcast().apply {
episode = e
_podcasts = emptyList()
}
}
}

override fun episodesInPodcast(podcastUri: String, limit: Int): Flow<List<EpisodeToPodcast>> =
episodesFlow.map { episodes ->
episodes.filter {
it.podcastUri == podcastUri
}.map { e ->
EpisodeToPodcast().apply {
episode = e
}
override fun episodesInPodcasts(podcastUris: List<String>, limit: Int): Flow<List<EpisodeToPodcast>> = episodesFlow.map { episodes ->
episodes.filter {
podcastUris.contains(it.podcastUri)
}.map { ep ->
EpisodeToPodcast().apply {
episode = ep
}
}
}

override fun episodesInPodcasts(
podcastUris: List<String>,
limit: Int
): Flow<List<EpisodeToPodcast>> =
episodesFlow.map { episodes ->
episodes.filter {
podcastUris.contains(it.podcastUri)
}.map { ep ->
EpisodeToPodcast().apply {
episode = ep
}
}
}
override suspend fun addEpisodes(episodes: Collection<Episode>) = episodesFlow.update {
it + episodes
}

override suspend fun addEpisodes(episodes: Collection<Episode>) =
episodesFlow.update {
it + episodes
}
override suspend fun deleteEpisode(episode: Episode) = episodesFlow.update {
it - episode
}

override suspend fun isEmpty(): Boolean =
episodesFlow.first().isEmpty()
override suspend fun isEmpty(): Boolean = episodesFlow.first().isEmpty()
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,71 +31,62 @@ class TestPodcastStore : PodcastStore {

private val podcastFlow = MutableStateFlow<List<Podcast>>(listOf())
private val followedPodcasts = mutableSetOf<String>()
override fun podcastWithUri(uri: String): Flow<Podcast> =
podcastFlow.map { podcasts ->
podcasts.first { it.uri == uri }
}
override fun podcastWithUri(uri: String): Flow<Podcast> = podcastFlow.map { podcasts ->
podcasts.first { it.uri == uri }
}

override fun podcastWithExtraInfo(podcastUri: String): Flow<PodcastWithExtraInfo> =
podcastFlow.map { podcasts ->
val podcast = podcasts.first { it.uri == podcastUri }
PodcastWithExtraInfo().apply {
this.podcast = podcast
}
override fun podcastWithExtraInfo(podcastUri: String): Flow<PodcastWithExtraInfo> = podcastFlow.map { podcasts ->
val podcast = podcasts.first { it.uri == podcastUri }
PodcastWithExtraInfo().apply {
this.podcast = podcast
}
}

override fun podcastsSortedByLastEpisode(limit: Int): Flow<List<PodcastWithExtraInfo>> =
podcastFlow.map { podcasts ->
podcasts.map { p ->
PodcastWithExtraInfo().apply {
podcast = p
isFollowed = followedPodcasts.contains(p.uri)
}
override fun podcastsSortedByLastEpisode(limit: Int): Flow<List<PodcastWithExtraInfo>> = podcastFlow.map { podcasts ->
podcasts.map { p ->
PodcastWithExtraInfo().apply {
podcast = p
isFollowed = followedPodcasts.contains(p.uri)
}
}
}

override fun followedPodcastsSortedByLastEpisode(limit: Int): Flow<List<PodcastWithExtraInfo>> =
podcastFlow.map { podcasts ->
podcasts.filter {
followedPodcasts.contains(it.uri)
}.map { p ->
PodcastWithExtraInfo().apply {
podcast = p
isFollowed = true
}
override fun followedPodcastsSortedByLastEpisode(limit: Int): Flow<List<PodcastWithExtraInfo>> = podcastFlow.map { podcasts ->
podcasts.filter {
followedPodcasts.contains(it.uri)
}.map { p ->
PodcastWithExtraInfo().apply {
podcast = p
isFollowed = true
}
}
}

override fun searchPodcastByTitle(
keyword: String,
limit: Int
): Flow<List<PodcastWithExtraInfo>> =
podcastFlow.map { podcastList ->
podcastList.filter {
it.title.contains(keyword)
}.map { p ->
PodcastWithExtraInfo().apply {
podcast = p
isFollowed = true
}
override fun searchPodcastByTitle(keyword: String, limit: Int): Flow<List<PodcastWithExtraInfo>> = podcastFlow.map { podcastList ->
podcastList.filter {
it.title.contains(keyword)
}.map { p ->
PodcastWithExtraInfo().apply {
podcast = p
isFollowed = true
}
}
}

override fun searchPodcastByTitleAndCategories(
keyword: String,
categories: List<Category>,
limit: Int
): Flow<List<PodcastWithExtraInfo>> =
podcastFlow.map { podcastList ->
podcastList.filter {
it.title.contains(keyword)
}.map { p ->
PodcastWithExtraInfo().apply {
podcast = p
isFollowed = true
}
limit: Int,
): Flow<List<PodcastWithExtraInfo>> = podcastFlow.map { podcastList ->
podcastList.filter {
it.title.contains(keyword)
}.map { p ->
PodcastWithExtraInfo().apply {
podcast = p
isFollowed = true
}
}
}

override suspend fun togglePodcastFollowed(podcastUri: String) {
if (podcastUri in followedPodcasts) {
Expand All @@ -113,9 +104,7 @@ class TestPodcastStore : PodcastStore {
followedPodcasts.remove(podcastUri)
}

override suspend fun addPodcast(podcast: Podcast) =
podcastFlow.update { it + podcast }
override suspend fun addPodcast(podcast: Podcast) = podcastFlow.update { it + podcast }

override suspend fun isEmpty(): Boolean =
podcastFlow.first().isEmpty()
override suspend fun isEmpty(): Boolean = podcastFlow.first().isEmpty()
}
Loading