Skip to content

Conversation

@XDdevv
Copy link
Contributor

@XDdevv XDdevv commented Aug 18, 2025

Overview

This PR adds a small rotation animation to the "Follow" icon in the Jetcaster app to improve visual feedback when toggling follow/unfollow. This implements the TODO found in FollowButton.kt: // TODO: think about animating these icons

What Changed

  • Added an animateFloatAsState to animate icon rotation from 0f to 360f when isFollowed changes
  • Applied Modifier.rotate() to the Icon based on the animated value

Why

This small UX enhancement helps to make the follow action feel more responsive and polished visually for users.

How it looks like (example screen recording)

Screen_recording_20250818_202230

Let me know if any adjustments are needed. 🙂

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @XDdevv, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the user experience in the Jetcaster app by adding a visual animation to the 'Follow' icon. When a user toggles the follow/unfollow state, the icon now performs a subtle rotation, providing clear and immediate feedback. This small but impactful change improves the responsiveness and polish of the application's user interface, making interactions feel more fluid and engaging.

Highlights

  • Animated Follow Icon: This PR introduces a subtle rotation animation to the 'Follow' icon within the Jetcaster application. The animation triggers when the follow/unfollow state changes, providing immediate visual feedback to the user.
  • Compose Animation API Usage: The animation is implemented using Jetpack Compose's animateFloatAsState function, which smoothly interpolates the rotation value from 0 to 360 degrees. A spring animation spec is used for a natural, bouncy feel.
  • Direct Modifier Application: The Modifier.rotate() is applied directly to the Icon composable, utilizing the animated float value to control the visual rotation, ensuring the animation is directly tied to the icon's rendering.
  • Addressing Technical Debt: This change directly addresses a previously existing TODO comment in the FollowButton.kt file, indicating a planned enhancement for icon animations.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a rotation animation to the follow/unfollow button, which is a nice UX improvement. The implementation uses animateFloatAsState to drive the rotation. My review focuses on a subtle issue with this approach where the animation can trigger on initial display, not just on user interaction. I've suggested using updateTransition to create a more robust animation that only runs when the follow state is toggled, avoiding any unintended initial animations.

Comment on lines 59 to 65
val iconRotation by animateFloatAsState(
targetValue = if(isFollowed) 0f else 360f,
animationSpec = spring(
dampingRatio = .6f,
stiffness = 200f
)
)
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Using animateFloatAsState here can cause an unintended animation when the button is first displayed (if isFollowed is initially false). This is because the animation's target value will be 360f while its initial value is 0f.

A more robust approach is to use updateTransition, which allows you to specify a different transitionSpec for the initial state, effectively disabling the animation on first composition. This ensures the rotation only happens when the user actually toggles the follow state.

To implement this, you'll need to adjust your imports to use updateTransition and tween instead of animateFloatAsState.

        val transition = updateTransition(targetState = isFollowed, label = "FollowToggle")
        val iconRotation by transition.animateFloat(
            label = "IconRotation",
            transitionSpec = {
                if (initialState == targetState) {
                    androidx.compose.animation.core.tween(durationMillis = 0)
                } else {
                    spring(
                        dampingRatio = .6f,
                        stiffness = 200f
                    )
                }
            }
        ) { followed ->
            if (followed) 360f else 0f
        }

label = "IconRotation",
transitionSpec = {
if (initialState == targetState) {
tween(durationMillis = 0)
Copy link
Collaborator

Choose a reason for hiding this comment

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

this can be replaced with snap spec instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion! Updated to use snap() instead of tween(0) 👍

@riggaroo
Copy link
Collaborator

Thanks, lovely bit of delight!

@riggaroo
Copy link
Collaborator

You need to run spotless on the code please :)

@XDdevv
Copy link
Contributor Author

XDdevv commented Aug 19, 2025

@riggaroo Thank you so much for the review! Really appreciate it 😊

@XDdevv
Copy link
Contributor Author

XDdevv commented Aug 19, 2025

@riggaroo running spotless right now 👍

@riggaroo riggaroo merged commit cdc1d41 into android:main Aug 19, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants