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" }