Skip to content

Add StrokeCap to CircularProgressIndicator - #122664

Merged
auto-submit[bot] merged 15 commits into
flutter:masterfrom
bernaferrari:strokecap-progress-indicator
Apr 12, 2023
Merged

auto-submit[bot] merged 15 commits into
flutter:masterfrom
bernaferrari:strokecap-progress-indicator

Conversation

@bernaferrari

@bernaferrari bernaferrari commented Mar 15, 2023 •

Copy link
Copy Markdown
Contributor

Sequel to #109111
Fix #109137

image

I can make LinearProgressIndicator accept BorderRadius (instead of round/square), but I can't (and no one can) make CircularProgressIndicator work with that. You would need someone from Dart/Skia team that is good at math to make drawArc more flexible.

So I used strokeCap everywhere, even though borderRadius (LinearProgressIndicator) + strokeCap (CircularProgressIndicator) would be better IMO. In a future PR I think I could add borderRadius to the "background" of the LinearProgressIndicator, so a borderRadius to the foreground could make a lot of sense. But I think people would be happy already with the round option. What do you think? Option 1 or 2?

Disclaimer: I don't think StrokeCap works that well for what we are doing. It has 3 options, butt, square and round, but 99% of the time you want two of them, and you never know which two you want. CircularProgressIndicator uses square for indeterminate (paints a bit more, so it is always visible, even on 0), butt for determinate (paints exactly). CircularProgressIndicator doesn't use it.

Something like isIndicatorRound would be better, since all we want is true/false. Do you agree?

CircularProgressIndicator(
  strokeCap: StrokeCap.round,
),
// Option 1. This PR.
LinearProgressIndicator(
  strokeCap: StrokeCap.round,
),

or

// Option 2. Different proposal. LinearProgressIndicator only.
LinearProgressIndicator(
  backgroundRadius: BorderRadius.circular(8),
  indicatorRadius: BorderRadius.circular(8),
),

cc @Piinks

@flutter-dashboard flutter-dashboard Bot added p: material_ui material_ui package in flutter/packages framework flutter/packages/flutter repository. See also f: labels. labels Mar 15, 2023
@bernaferrari
bernaferrari force-pushed the strokecap-progress-indicator branch from 001a705 to 1327e51 Compare March 15, 2023 03:51
@bernaferrari bernaferrari changed the title Allow round Progress Indicator Allow ProgressIndicator to be round Mar 15, 2023
@bernaferrari
bernaferrari force-pushed the strokecap-progress-indicator branch 6 times, most recently from 0db3818 to 5f80ae7 Compare March 15, 2023 04:14

@Piinks Piinks left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There are some failing tests, can you take a look?
Also, I'd like @Hari-07 to weigh in here. They originally authored the PR and stated they were already re-staging it.

@bernaferrari

bernaferrari commented Mar 15, 2023 •

Copy link
Copy Markdown
Contributor Author

Yes, I pushed and went to sleep. I only saw his comment after publishing, but he is welcome here. Could you give your feedback on the boolean and Linear indicator ideas?

@Hari-07

Hari-07 commented Mar 15, 2023

Copy link
Copy Markdown
Member

I did rebase my changes but since it'd be identical to this, I think I'll refrain from opening a duplicate PR. As for the discussions about boolean or StrokeCap, I think exposing it as a boolean makes sense, and then setting it to the correct strokecap inside it

The original issue #71085 which got you to reopen #109137, mentions customizing the radius. From what I know the drawArc method at the lowest level interfaces with skia functions, and those read off the StrokeCap on the Paint instance used to do the rendering calculation so in order to allow that radius to be customized I believe a new property would have to be added on Paint , and I think that'd have to be updated in the engine repo

Thanks for taking my input @Piinks

@bernaferrari
bernaferrari force-pushed the strokecap-progress-indicator branch from 844f5f2 to d2224ea Compare March 15, 2023 19:36
@bernaferrari

bernaferrari commented Mar 15, 2023 •

Copy link
Copy Markdown
Contributor Author

I just changed strokeCap to hasRoundStroke boolean property. I think the test fail was the StrokeCap.square <-> StrokeCap.butt difference, circular uses one and refresh uses another (the difference is so small no one ever noticed). Let's see if everything works now.

@whiskeyPeak

whiskeyPeak commented Mar 16, 2023 •

Copy link
Copy Markdown
Contributor

Since the end goal is to potentially add a border radius to both widgets, I think it would make a bit more sense if LinearProgresseIndicator is given the customizable borderRadius property now.

@bernaferrari

Copy link
Copy Markdown
Contributor Author

I don't think adding borderRadius to CircularProgress would ever be possible, but we can decide what to do with the Linear one because it is quite different. I'm just afraid of polluting the theme too much.

Comment thread packages/flutter/test/rendering/mock_canvas.dart Outdated
Comment thread packages/flutter/lib/src/material/progress_indicator.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since StrokeCap.round is only relevant to CircularProgressIndicator (If the Linear one chooses a radius instead), should this only be on the CircularProgressIndicator class?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am also not sure if the name is clear as a user, why not use StrokeCap directly?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

StrokeCap has 3 values and only 2 of them are relevant. Butt and Square collide with each other, because Circular uses Butt when it has value, Square when it doesn't (it is spinning).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

should this only be on the CircularProgressIndicator

Probably. How do you think the theme should be? CircularHasRoundIndicator and LinearIndicatorRadius?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Renamed to preferRoundIndicator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

only 2 of them are relevant

I disagree with this statement, why are there 3 then? :) It's not for us to decide that one is irrelevant, the uses cases have been pointed out in the discussion of this PR.

How do you think the theme should be? CircularHasRoundIndicator and LinearIndicatorRadius?

Are there not individual component themes for circular and linear? I would not put both in the super class ProgressIndicatorTheme.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I disagree with this statement, why are there 3 then? :) It's not for us to decide that one is irrelevant, the uses cases have been pointed out in the discussion of this PR.

If it is square, the value is represented wrong: #109137 (comment).
If it is butt, it is represented correctly.

But if it is butt, on indeterminate, it "disappears", so whoever implemented it made it square so it is always visible.

Exposing this to the user is hard: on square they will have the wrong value, on butt they will have an "unintended" animation (which, if it is to be customizable, we could allow changing other things, such as speed).

Are there not individual component themes for circular and linear?

No, I could make one, I guess..

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No, I could make one, I guess..

Oh, I meant that if they don't exist then we should probably omit theming support for now. :) No worries, no need to create more themes right now for this change.

Comment thread packages/flutter/lib/src/material/progress_indicator.dart Outdated
@bernaferrari

bernaferrari commented Mar 18, 2023 •

Copy link
Copy Markdown
Contributor Author

How do we call the borderRadius? indicatorBorderRadius and borderRadius (1) or backgroundBorderRadius (2)? I'm tempted to go with 1, because it applies to the whole shape, not the background only.

image

The only "unusual" thing I made is that the track has Radius.zero in the start position (when it it is determined). This prevents the left side from being round, which doesn't make sense. Everything is working fine.

@bernaferrari
bernaferrari force-pushed the strokecap-progress-indicator branch 2 times, most recently from 95189e2 to 2822c0b Compare March 18, 2023 04:09
Comment thread packages/flutter/lib/src/material/progress_indicator.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// By default it is null, which produces a rectangular track.
///
/// By default it is null, which produces a rectangular track.

This is a non-nullable parameter. How does it default to null? :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ooops :P

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Actually, I was playing with a few things and forgot to update the documentation. I was checking if I could "auto add a borderRadius" but my idea was bad and it is better to allow the user to break things. IndicatorBorderRadius = 100 + background = 0 result in a weird scenario I was trying to avoid, but I'm letting the user decide.

Comment thread packages/flutter/lib/src/material/progress_indicator.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

square or round

The name/boolean/square-round is kind of confusing here.

I think StrokeCap is still just the straightforward solution.

@bernaferrari bernaferrari Mar 23, 2023 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The issue with strokeCap, as I tried to explain before, is that butt/square are always wrong. If you want butt, indeterminate is wrong. If you want square, value is wrong.

There is no reason for square + value. That must be overridden.
There is no reason for butt + indeterminate. That must be overridden.

Would we have a fourth value (null?) that goes between butt and square? I think that's too much complexity for the user. Even introducing a new enum could be easier to understand.

enum CircularProgressIndicatorShape { square, round }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is StrokeCap not properly documented? Again, these are decisions I do not think are fair for us to make for the developer. I think this should be StrokeCap.

@bernaferrari bernaferrari Mar 23, 2023 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

How do you see the API working? Because either value (square/butt) would be breaking. The strokeCap is documented, but there is a hole from "square paints a bit more" to "it is going to paint the wrong progress value", which is what people won't want. It is hard to even find a default value, because the default depends on the state. Right now it mixes the two.

       | indeterminate | value |
butt   |      ❌       |   ✅   |
square |      ✅       |   ❌   |
round  |      ✅       |   ✅   |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How would it be breaking? Does exposing this value to developers break the default behavior?

@bernaferrari bernaferrari Mar 23, 2023 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oh, I totally agree. The weird thing for me is that there would be 4 values and only 2 would be really "correct". So even though we want to give users options they will shoot themselves with 2 of them (which seem the correct thing, you have circle, you want... square, bang). But considering one day they might add other strokeCap effects, it makes sense.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think where we are disagreeing here is that I do not feel we can be the arbiters of "correct" as you have been asserting. It could very well be the behavior the developer wants.

@bernaferrari bernaferrari Mar 23, 2023 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If the progress value starts on -10 instead of 0, we have a "deterministic" problem. No one would want it to start before, and if they want, we could just expose that number. Same thing, if they want value: 40, they don't want value: 50 (else we would expose like an offset and let they play with it).

For indeterminate, it is less bad because the material animation would change (most of them wouldn't notice), so I believe, if we want the material animation to be customizable, there are other ways of doing this (like allowing to change the speed, curves and delay).

I had a hard time, for example, in the LinearProgressIndicator to see if my borderRadius was working with indeterminate because it is too fast, what if I wanted slower? I can't set this. This could be more useful than say, a value that starts before and ends after.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just my 2cts, I think it is fair to assume that a determinate CircularIndicator is "correct" if it starts right at 90 degrees and that it draws half of a circle when its value is 0.5. Both are not true when using StrokeCap.square (not to say it is not 'circular' because ‘StrokeCap.square’ really means there are two squares drawn at both ends of the arc, which might makes sense if you want to ‘connect’ lines and arcs).

Nonetheless, @Pinks point about the versatility of the public API is valid, especially considering @bernaferrari following argument: “one day they might add other strokeCap effects, it makes sense.” (maybe Impeller will).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I doubt so because CSS is 20 years old and only supports the same 3 strokeCap. But I agree they could. I just don't know what it could be that would add benefit to the framework.

Comment thread packages/flutter/test/material/progress_indicator_test.dart Outdated
@bernaferrari
bernaferrari force-pushed the strokecap-progress-indicator branch 2 times, most recently from e88e684 to e61a241 Compare March 23, 2023 05:05
@bernaferrari
bernaferrari force-pushed the strokecap-progress-indicator branch from 1d1edae to 7f86d40 Compare April 11, 2023 18:50
Comment thread packages/flutter/lib/src/material/progress_indicator.dart Outdated

@Piinks Piinks left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Flutter_LGTM

@Piinks Piinks added the autosubmit Merge PR when tree becomes green via auto submit App label Apr 11, 2023
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Apr 11, 2023
@auto-submit

auto-submit Bot commented Apr 11, 2023

Copy link
Copy Markdown
Contributor

auto label is removed for flutter/flutter, pr: 122664, due to This PR has not met approval requirements for merging. You have project association CONTRIBUTOR and need 1 more review(s) in order to merge this PR.

  • Merge guidelines: You need at least one approved review if you are already a MEMBER or two member reviews if you are not a MEMBER before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

@auto-submit

auto-submit Bot commented Apr 11, 2023

Copy link
Copy Markdown
Contributor

auto label is removed for flutter/flutter, pr: 122664, due to Validations Fail.

@bernaferrari

Copy link
Copy Markdown
Contributor Author

Thanks a lot! 🎉

@Piinks

Piinks commented Apr 11, 2023

Copy link
Copy Markdown
Contributor

Ah! I thought you were a member of flutter hackers! I will sponsor you, then your PRs will not need a second review.

@bernaferrari bernaferrari added the autosubmit Merge PR when tree becomes green via auto submit App label Apr 12, 2023
@bernaferrari

Copy link
Copy Markdown
Contributor Author

Now I have super-powers. It was a fun day. Thanks a lot Piinks!

@auto-submit
auto-submit Bot merged commit 56e4f8e into flutter:master Apr 12, 2023
@bernaferrari
bernaferrari deleted the strokecap-progress-indicator branch April 12, 2023 00:35
@rayliverified

Copy link
Copy Markdown

Amazing, thank you @Piinks and @bernaferrari very much!

Kate, can you shed some light on why this PR was accepted and the previous ones were rejected?

@bernaferrari

bernaferrari commented Apr 12, 2023 •

Copy link
Copy Markdown
Contributor Author

The previous one didn't pass flutter tests. I used it as the base for this.

engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 12, 2023
exaby73 pushed a commit to NevercodeHQ/flutter that referenced this pull request Apr 17, 2023
Add `StrokeCap` to `CircularProgressIndicator`
auto-submit Bot pushed a commit that referenced this pull request Apr 24, 2023
Split from #122664 so it gets easier to review, as this is now unrelated to the `preferRound`. I'm one step from adding a width attribute, lol.

<img width="474" alt="image" src="https://user-images.githubusercontent.com/351125/226083798-71e529e9-4ae9-41de-a500-0412b989a273.png">

cc @Piinks
@jhonatan-3a

Copy link
Copy Markdown

merge, when will be this in stable ?

@bernaferrari

Copy link
Copy Markdown
Contributor Author

Probably in 2 months

@fingerart

Copy link
Copy Markdown

May I ask which version this PR was released in?

@Hari-07

Hari-07 commented Sep 21, 2023

Copy link
Copy Markdown
Member

@fingerart It's out in 3.13

justinmc pushed a commit to flutter/packages that referenced this pull request Apr 17, 2026
Split from flutter/flutter#122664 so it gets easier to review, as this is now unrelated to the `preferRound`. I'm one step from adding a width attribute, lol.

<img width="474" alt="image" src="https://user-images.githubusercontent.com/351125/226083798-71e529e9-4ae9-41de-a500-0412b989a273.png">

cc @Piinks
chunhtai pushed a commit to chunhtai/packages that referenced this pull request Jun 12, 2026
Split from flutter/flutter#122664 so it gets easier to review, as this is now unrelated to the `preferRound`. I'm one step from adding a width attribute, lol.

<img width="474" alt="image" src="https://user-images.githubusercontent.com/351125/226083798-71e529e9-4ae9-41de-a500-0412b989a273.png">

cc @Piinks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App framework flutter/packages/flutter repository. See also f: labels. p: material_ui material_ui package in flutter/packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add StrokeCap parameter on CircularProgressIndicator

8 participants