diff --git a/feature/sessions/build.gradle.kts b/feature/sessions/build.gradle.kts index d3ebc1b2a..db85d35d1 100644 --- a/feature/sessions/build.gradle.kts +++ b/feature/sessions/build.gradle.kts @@ -8,6 +8,7 @@ dependencies { implementation(projects.core.designsystem) implementation(projects.core.ui) implementation(projects.core.model) + implementation(libs.animation.graphics.android) testImplementation(projects.core.testing) implementation(libs.composeHiltNavigtation) diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/component/TimetableItemDetailBottomAppBar.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/component/TimetableItemDetailBottomAppBar.kt index c7350ffae..e2898052e 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/component/TimetableItemDetailBottomAppBar.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/component/TimetableItemDetailBottomAppBar.kt @@ -1,8 +1,11 @@ package io.github.droidkaigi.confsched2023.sessions.component +import androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi +import androidx.compose.animation.graphics.res.animatedVectorResource +import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter +import androidx.compose.animation.graphics.vector.AnimatedImageVector +import androidx.compose.foundation.clickable import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Bookmark -import androidx.compose.material.icons.filled.BookmarkBorder import androidx.compose.material.icons.filled.Share import androidx.compose.material3.BottomAppBar import androidx.compose.material3.BottomAppBarDefaults @@ -12,6 +15,10 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Surface import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource @@ -53,27 +60,54 @@ fun TimetableItemDetailBottomAppBar( }, floatingActionButton = { FloatingActionButton( - onClick = { onBookmarkClick(timetableItem) }, + onClick = { + // NOOP , + }, modifier = Modifier.testTag(TimetableItemDetailBookmarkIconTestTag), containerColor = BottomAppBarDefaults.bottomAppBarFabColor, elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation(), ) { - if (isBookmarked) { - Icon( - imageVector = Icons.Filled.Bookmark, - contentDescription = SessionsStrings.RemoveFromFavorites.asString(), - ) - } else { - Icon( - imageVector = Icons.Filled.BookmarkBorder, - contentDescription = SessionsStrings.AddToFavorites.asString(), - ) - } + AnimatedBookmarkIcon( + isBookmarked = isBookmarked, + timetableItem = timetableItem, + onClick = onBookmarkClick, + ) } }, ) } +@OptIn(ExperimentalAnimationGraphicsApi::class) +@Composable +fun AnimatedBookmarkIcon( + isBookmarked: Boolean, + timetableItem: TimetableItem, + onClick: (TimetableItem) -> Unit, + modifier: Modifier = Modifier, +) { + var atEnd by remember { mutableStateOf(false) } + val animatedBookmarkIcon = AnimatedImageVector.animatedVectorResource( + id = if (isBookmarked) { + R.drawable.animated_bookmark_icon_reverse + } else { + R.drawable.animated_bookmark_icon + }, + ) + Icon( + painter = rememberAnimatedVectorPainter(animatedBookmarkIcon, atEnd), + contentDescription = if (isBookmarked) { + SessionsStrings.RemoveFromFavorites.asString() + } else { + SessionsStrings.AddToFavorites.asString() + }, + modifier = modifier + .clickable { + atEnd = atEnd.not() + onClick(timetableItem) + }, + ) +} + @MultiThemePreviews @MultiLanguagePreviews @Composable diff --git a/feature/sessions/src/main/res/drawable/animated_bookmark_icon.xml b/feature/sessions/src/main/res/drawable/animated_bookmark_icon.xml new file mode 100644 index 000000000..a552aa923 --- /dev/null +++ b/feature/sessions/src/main/res/drawable/animated_bookmark_icon.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/feature/sessions/src/main/res/drawable/animated_bookmark_icon_reverse.xml b/feature/sessions/src/main/res/drawable/animated_bookmark_icon_reverse.xml new file mode 100644 index 000000000..d0dcc5133 --- /dev/null +++ b/feature/sessions/src/main/res/drawable/animated_bookmark_icon_reverse.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bea7499fb..4945c73a3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -93,6 +93,7 @@ composeCoil = { module = "io.coil-kt:coil-compose", version = "2.4.0" } composeImageLoader = { module = "io.github.qdsfdhvh:image-loader", version = "1.6.4" } composeShimmer = { module = "com.valentinilk.shimmer:compose-shimmer", version = "1.0.5" } lottieCompose = { module = "com.airbnb.android:lottie-compose", version.ref = "lottie" } +animation-graphics-android = { group = "androidx.compose.animation", name = "animation-graphics-android", version = "1.5.1" } androidxFragment = { module = "androidx.fragment:fragment", version.ref = "androidxFragment" } androidxCoreKtx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" }