Skip to content

Conversation

a-man-called-q
Copy link
Contributor

Describe the changes

  • Initial Implementation for Rating Page

Checklist

  • I have read the CONTRIBUTING.md.
  • I have included the relevant unit/golden tests.
  • I have included the relevant samples.
  • I have updated the documentation accordingly.
  • I have added the required flutters_hook for widget controllers.
  • I have updated the CHANGELOG.md if necessary.

… sample and change EmptyPage to InitialPage showing all the routes available.
@Copilot Copilot AI review requested due to automatic review settings April 28, 2025 16:54
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 4 out of 11 changed files in this pull request and generated no comments.

Files not reviewed (7)
  • forui/lib/forui.dart: Language not supported
  • forui/lib/src/widgets/rating/rating.dart: Language not supported
  • forui/lib/src/widgets/rating/rating_content.dart: Language not supported
  • forui/lib/widgets/rating.dart: Language not supported
  • forui/test/src/widgets/rating/rating_golden_test.dart: Language not supported
  • samples/lib/main.dart: Language not supported
  • samples/lib/widgets/rating.dart: Language not supported

@auto-maid auto-maid bot temporarily deployed to docs-development April 28, 2025 16:56 Inactive
@a-man-called-q
Copy link
Contributor Author

This should complete #328 with additional caveats :

  • the implementation is quite complex since there's a hover handler for displaying the rating and supports half value ( need a decent refactor )
  • I don't know if the implementation fits the way of Forui should be.

@auto-maid
Copy link
Contributor

auto-maid bot commented Apr 28, 2025

Documentation Preview

Latest Commit SHA 3aac7c1
Preview URL https://b9aec55e.forui-docs-dev.pages.dev/docs

You're seeing this because the docs/samples were updated.

@Pante Pante requested a review from kawaijoe April 29, 2025 01:44
Copy link
Member

@Pante Pante left a comment

Choose a reason for hiding this comment

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

Thanks for the PR!

Just a heads up, we probably won't be able to fully review this until next week as we're got quite a packed week ahead of us.

}

@override
Widget build(BuildContext context) {
Copy link
Member

Choose a reason for hiding this comment

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

I think you can use FTappable to manage the tapping/hovering logic.

final int count;

/// Called when the rating value changes.
final ValueChanged<double>? onStateChanged;
Copy link
Member

Choose a reason for hiding this comment

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

This should be onChange, onStateChange is meant for WidgetState changes.

final FocusNode? focusNode;

/// {@macro forui.foundation.doc_templates.onFocusChange}
final ValueChanged<bool>? onFocusChange;
Copy link
Member

Choose a reason for hiding this comment

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

We should probably add a onHoverChange, I think you can use FButton as a reference.

Comment on lines +52 to +53
/// The spacing between rating icons.
final double spacing;
Copy link
Member

Choose a reason for hiding this comment

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

This should be in the style.

Comment on lines +63 to +64
this.filledIcon = const Icon(FIcons.star, color: Color(0xFFFFD700)), // Gold
this.emptyIcon = const Icon(FIcons.starOff, color: Color(0xFFBDBDBD)), // Gray
Copy link
Member

Choose a reason for hiding this comment

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

We should move the color to inside the style. Generally for icons, we wrap them in a IconTheme inside the build method, e.g. IconTheme(style.iconThemeData, child: filledIcon).

..add(IntProperty('count', count))
..add(FlagProperty('enabled', value: enabled, ifTrue: 'enabled'))
..add(DiagnosticsProperty('style', style))
..add(ObjectFlagProperty<ValueChanged<double>?>.has('onStateChanged', onStateChanged))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
..add(ObjectFlagProperty<ValueChanged<double>?>.has('onStateChanged', onStateChanged))
..add(ObjectFlagProperty.has('onStateChanged', onStateChanged))

Generally we don't specify the generic type for diagnostic properties.

..add(DiagnosticsProperty('style', style))
..add(ObjectFlagProperty<ValueChanged<double>?>.has('onStateChanged', onStateChanged))
..add(StringProperty('semanticsLabel', semanticsLabel))
..add(DiagnosticsProperty<bool>('autofocus', autofocus))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
..add(DiagnosticsProperty<bool>('autofocus', autofocus))
..add(FlagProperty('autofocus', value: autofocus, ifTrue: 'autofocus'))

Comment on lines +97 to +132
double _calculateRating(double dx, double totalWidth) {
if (totalWidth <= 0) {
return 0;
}

final itemWidth = totalWidth / widget.count;
final x = dx.clamp(0.0, totalWidth);
final index = x ~/ itemWidth;
final localPosition = x - (index * itemWidth);

double rating = index + 1.0;
if (widget.halfFilledIcon != null && localPosition < itemWidth / 2) {
rating -= 0.5;
}

return rating.clamp(0.0, widget.count.toDouble());
}

void _handleHover(PointerHoverEvent event) {
final box = context.findRenderObject() as RenderBox?;
if (box == null) {
return;
}

final localPosition = box.globalToLocal(event.position);
setState(() => _hoverValue = _calculateRating(localPosition.dx, box.size.width));
}

void _handleTap(TapUpDetails details) {
final box = context.findRenderObject()! as RenderBox;
final localPosition = box.globalToLocal(details.globalPosition);
final rating = _calculateRating(localPosition.dx, box.size.width);

widget.onStateChanged?.call(rating);
setState(() => _isHovering = false);
}
Copy link
Member

Choose a reason for hiding this comment

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

Generally, I think we should try to avoid using retrieving the renderbox like this. Perhaps, you can use the PointerEnterEvent passed into MouseRegion.onEnter to calculate the size?

I think there's something similar for tap gestures too.

Comment on lines +3 to +5
/// A line calendar displays dates in a single horizontal, scrollable line.
///
/// See https://forui.dev/docs/data/line-calendar for working examples.
Copy link
Member

Choose a reason for hiding this comment

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

docs need to be updated.

Comment on lines +172 to +183
final class FRatingStyle with Diagnosticable, _$FRatingStyleFunctions {
/// The color of the rating icons.
@override
final Color? color;

/// The size of the rating icons.
@override
final double? size;

/// Creates a [FRatingStyle].
const FRatingStyle({this.color, this.size});
}
Copy link
Member

Choose a reason for hiding this comment

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

I think these properties can be merged into a IconThemeData. IconThemeData can then be wrapped inside a FWidgetStateMap to account for the various states, i.e. selected & unselected.

I think you can reference FTileContentStyle.

@a-man-called-q
Copy link
Contributor Author

It's ok. I'll be busy till weekend anyways.

@a-man-called-q
Copy link
Contributor Author

Btw.. I suggest that this should be delayed until 0.12. Seeing how @Pante refactored the nested header. It seems like I need to be guided more.

Not a good programmer here lol, plus I need the header update soon for my future app.

@Pante
Copy link
Member

Pante commented Apr 29, 2025

No worries! On another note, we're planning to release 0.11.0 on 1st May.

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