Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rating view #1706

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
namespace CommunityToolkit.Maui.Core;

/// <summary>
/// Default Values for RatingView
/// </summary>
public static class RatingViewDefaults
{
/// <summary>
/// Default value for <see cref="CurrentRating"/>
/// </summary>
public const int CurrentRating = 0;

/// <summary>
/// Default value for <see cref="MaximumRating"/>
/// </summary>
public const int MaximumRating = 5;

/// <summary>
/// Default value for <see cref="Size"/>
/// </summary>
public const double Size = 20.0;

/// <summary>
/// Default value for <see cref="Spacing"/>
/// </summary>
public const double Spacing = 10.0;

/// <summary>
/// Default value for <see cref="StrokeThickness"/>
/// </summary>
public const double StrokeThickness = 7.0;

/// <summary>
/// Default value for <see cref="IsEnabled"/>
/// </summary>
public const bool IsEnabled = true;

/// <summary>
/// Default value for <see cref="FilledBackgroundColor"/>
/// </summary>
public static Color FilledBackgroundColor { get; } = Colors.Yellow;

/// <summary>
/// Default value for <see cref="EmptyBackgroundColor"/>
/// </summary>
public static Color EmptyBackgroundColor { get; } = Colors.Transparent;

/// <summary>
/// Default value for <see cref="StrokeColor"/>
/// </summary>
public static Color StrokeColor { get; } = Colors.Grey;
}
11 changes: 11 additions & 0 deletions src/CommunityToolkit.Maui.Core/Primitives/Rating.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace CommunityToolkit.Maui.Core.Primitives;

///<summary></summary>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Reminder to add descriptive XML Comments

public class Rating
{
///<summary></summary>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Reminder to add descriptive XML Comments

public double? CurrentRating { get; set; }

///<summary></summary>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Reminder to add descriptive XML Comments

public object? CommandParameter { get; set; }
Eel2000 marked this conversation as resolved.
Show resolved Hide resolved
}
49 changes: 49 additions & 0 deletions src/CommunityToolkit.Maui.Core/Primitives/RatingShape.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
namespace CommunityToolkit.Maui.Core.Primitives;

/// <summary>
/// The type of the shape to display on the rating view
/// </summary>
public readonly struct RatingShape(string pathData)
{
/// <summary>
/// the data path data from the svg
/// </summary>
public string PathData { get; } = pathData;

/// <summary>
/// the default star shape
/// </summary>
public static RatingShape Star { get; } = new(PathShapes.Star);

/// <summary>
/// The default heart shape
/// </summary>
public static RatingShape Heart { get; } = new(PathShapes.Heart);

/// <summary>
/// The circle shape
/// </summary>
public static RatingShape Circle { get; } = new(PathShapes.Circle);

/// <summary>
/// The Like shapes
/// </summary>
public static RatingShape Like { get; } = new(PathShapes.Like);

/// <summary>
/// The Dislike
/// </summary>
public static RatingShape Dislike { get; } = new(PathShapes.Dislike);
}

/// <summary>
///
/// </summary>
static class PathShapes
{
public const string Star = "M9 11.3l3.71 2.7-1.42-4.36L15 7h-4.55L9 2.5 7.55 7H3l3.71 2.64L5.29 14z";
public const string Heart = "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z";
public const string Circle = "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z";
public const string Like = "M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1.91l-.01-.01L23 10z";
public const string Dislike = "M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v1.91l.01.01L1 14c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
using CommunityToolkit.Maui.Core;
using CommunityToolkit.Maui.Core.Primitives;
using CommunityToolkit.Maui.Core.Primitives.Defaults;
using FluentAssertions;
using Microsoft.Maui.Controls.Shapes;
using Xunit;
using Path = Microsoft.Maui.Controls.Shapes.Path;

namespace CommunityToolkit.Maui.UnitTests.Views.RatingView;

public class RatingViewTests : BaseHandlerTest
{
[Fact]
public void DefaultInitialization_ShouldHaveCorrectDefaultValues()
{
// Arrange
var ratingView = new Maui.Views.RatingView.RatingView();

// Assert
Assert.Equal(RatingViewDefaults.CurrentRating, ratingView.CurrentRating);
Assert.Equal(RatingViewDefaults.MaximumRating, ratingView.MaximumRating);
Assert.Equal(RatingViewDefaults.Size, ratingView.Size);
Assert.Equal(RatingViewDefaults.FilledBackgroundColor, ratingView.FilledBackgroundColor);
Assert.Equal(RatingViewDefaults.EmptyBackgroundColor, ratingView.EmptyBackgroundColor);
Assert.Equal(RatingViewDefaults.StrokeThickness, ratingView.StrokeThickness);
Assert.Equal(RatingViewDefaults.Spacing, ratingView.Spacing);
Assert.Equal(RatingViewDefaults.IsEnabled, ratingView.IsEnabled);
}

[Fact]
public void OnControlInitialized_ShouldCreateCorrectNumberOfShapes()
{
// Arrange
var ratingView = new Maui.Views.RatingView.RatingView();
ratingView.MaximumRating = 3;

// Act
ratingView.InitializeShape();

// Assert
ratingView.Control?.ColumnDefinitions.Count.Should().Be(3);
ratingView.Control?.Children.Count.Should().Be(3);
}

[Fact]
public void PropertyChangedEvent_ShouldBeRaised_WhenCurrentRatingChanges()
{
// Arrange
var ratingView = new Maui.Views.RatingView.RatingView();
bool eventRaised = false;
ratingView.PropertyChanged += (_, e) => { eventRaised = true; };

// Act
ratingView.CurrentRating = 3.5;

// Assert
eventRaised.Should().BeTrue();
}

[Fact]
public void Draw_ShouldCreateCorrectNumberOfShapes()
{
// Arrange
var ratingView = new Maui.Views.RatingView.RatingView
{
MaximumRating = 3
};

// Assert
ratingView.Control?.ColumnDefinitions.Count.Should().Be(3);
ratingView.Control?.Children.Count.Should().Be(3);
}

[Fact]
public void ReDraw_ShouldRecreateShapes()
{
// Arrange
var ratingView = new Maui.Views.RatingView.RatingView
{
MaximumRating = 3
};

// Act
ratingView.ReDraw();

// Assert
ratingView.Control?.ColumnDefinitions.Count.Should().Be(3);
ratingView.Control?.Children.Count.Should().Be(3);
}

[Fact]
public void UpdateDraw_ShouldUpdateShapesCorrectly()
{
// Arrange
var ratingView = new Maui.Views.RatingView.RatingView
{
MaximumRating = 3,
CurrentRating = 2.5
};

// Act
ratingView.UpdateDraw();

// Assert
ratingView.Control?.Children.Count.Should().Be(3);
#pragma warning disable CS8602 // Dereference of a possibly null reference.
(ratingView.Control?.Children[0] as Path).Fill.Should()
.BeEquivalentTo(Brush.Yellow);
(ratingView.Control?.Children[0] as Path).Stroke.Should()
.BeEquivalentTo(Brush.Yellow);
#pragma warning restore CS8602 // Dereference of a possibly null reference.
}

[Fact]
public void InitializeShape_ShouldSetShapeAndControlColumnSpacing()
{
// Arrange
var ratingView = new Maui.Views.RatingView.RatingView();

// Act
ratingView.InitializeShape();

// Assert
ratingView.Shape.Should().NotBeNull();
ratingView.Control?.ColumnSpacing.Should().Be(ratingView.Spacing);
}

[Fact]
public void OnShapeTapped_ShouldUpdateCurrentRatingCorrectly()
{
// Arrange
var ratingView = new Maui.Views.RatingView.RatingView
{
MaximumRating = 3,
IsEnabled = true
};

Path tappedShape = new()
{
Data = (Geometry?)new PathGeometryConverter().ConvertFromInvariantString(RatingShape.Star.PathData)
};

// Act
ratingView.OnShapeTapped(tappedShape, null);

// Assert
ratingView.CurrentRating.Should().Be(1);
}

[Fact]
public void ShapeProperty_ShouldSetShapeCorrectly()
{
// Arrange
var ratingView = new Maui.Views.RatingView.RatingView();

// Act
ratingView.Shape = RatingShape.Heart;

// Assert
ratingView.Shape.Should().Be(RatingShape.Heart);
}
}
4 changes: 2 additions & 2 deletions src/CommunityToolkit.Maui/CommunityToolkit.Maui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiPackageVersion)"/>
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiPackageVersion)"/>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiPackageVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiPackageVersion)" />
</ItemGroup>

</Project>
Loading
Loading