Skip to content

Commit

Permalink
Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
naweed committed Aug 21, 2022
1 parent 691cad7 commit 80c853f
Show file tree
Hide file tree
Showing 37 changed files with 1,302 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
71 changes: 71 additions & 0 deletions src/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiBMICalculator"
x:Class="MauiBMICalculator.App">
<Application.Resources>

<!-- Colors -->
<Color x:Key="PageBackgroundColor">#FFFFFF</Color>
<Color x:Key="LightBackgroundColor">#D3D3D3</Color>
<Color x:Key="DarkTextColor">#00133D</Color>

<!-- Content Page Style -->
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
<Setter Property="NavigationPage.HasNavigationBar" Value="False" />
<Setter Property="BackgroundColor" Value="{StaticResource PageBackgroundColor}" />
</Style>

<!-- Button Styles -->
<Style TargetType="ImageButton" x:Key="NextButtonStyle">
<Setter Property="HeightRequest" Value="60" />
<Setter Property="WidthRequest" Value="60" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="Aspect" Value="AspectFit" />
<Setter Property="Source" Value="nextbutton.png" />
</Style>

<!-- Grid Styles -->
<Style TargetType="Grid">
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="RowSpacing" Value="0" />
<Setter Property="ColumnSpacing" Value="0" />
<Setter Property="BackgroundColor" Value="Transparent" />
</Style>

<!-- Label Styles -->
<Style TargetType="Label" x:Key="SectionHeaderStyle">
<Setter Property="FontSize" Value="24" />
<Setter Property="TextColor" Value="{StaticResource DarkTextColor}" />
<Setter Property="FontFamily" Value="MediumFont" />
</Style>

<Style TargetType="Label" x:Key="ScaleHeaderStyle">
<Setter Property="FontSize" Value="10" />
<Setter Property="TextColor" Value="{StaticResource DarkTextColor}" />
<Setter Property="FontFamily" Value="MediumFont" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>

<Style TargetType="Label" x:Key="ScaleDisplayStyle">
<Setter Property="FontSize" Value="10" />
<Setter Property="TextColor" Value="{StaticResource DarkTextColor}" />
<Setter Property="FontFamily" Value="RegularFont" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>

<Style TargetType="Label" x:Key="BMIResultStyle">
<Setter Property="FontSize" Value="96" />
<Setter Property="TextColor" Value="{StaticResource DarkTextColor}" />
<Setter Property="FontFamily" Value="MediumFont" />
</Style>

</Application.Resources>
</Application>

12 changes: 12 additions & 0 deletions src/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace MauiBMICalculator;

public partial class App : Application
{
public App()
{
InitializeComponent();

MainPage = new NavigationPage(new StartPage());
}
}

15 changes: 15 additions & 0 deletions src/Controls/VerticalGuage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentView
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp.Views.Maui.Controls;assembly=SkiaSharp.Views.Maui.Controls"
x:Class="MauiBMICalculator.Controls.VerticalGuage">

<skia:SKCanvasView
x:Name="guageCanvas"
PaintSurface="OnPaintSurface"
EnableTouchEvents="True"
Touch="guageCanvas_Touch" />

</ContentView>

273 changes: 273 additions & 0 deletions src/Controls/VerticalGuage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
using SkiaSharp.Views.Maui;

namespace MauiBMICalculator.Controls;

public partial class VerticalGuage : ContentView
{
private float density;
private float regularStrokeWidth = 3;
private float majorStrokeWidth = 4;
private float minorStrokeWidth = 2;
private float indicatorStrokeWidth = 6;
private float guageWidth = 60;

private SKPaint regularStrokePaint, minorStrokePaint, majorStrokePaint, indicatorStrokePaint, fillPaint;
private SKColor strokeColor = new SKColor(117, 117, 117, 230);
private SKColor fillColor = new SKColor(117, 117, 117, 50);

public static BindableProperty MaximumProperty = BindableProperty.Create("Maximum", typeof(float), typeof(VerticalGuage), 100f, BindingMode.OneWay, null, InvalidateGauge);

public static BindableProperty MinimumProperty = BindableProperty.Create("Minimum", typeof(float), typeof(VerticalGuage), 0f, BindingMode.OneWay, null, InvalidateGauge);

public static BindableProperty StepProperty = BindableProperty.Create("Step", typeof(float), typeof(VerticalGuage), 20f, BindingMode.OneWay, null, InvalidateGauge);

public static BindableProperty MinorTicksProperty = BindableProperty.Create("MinorTicks", typeof(float), typeof(VerticalGuage), 20f, BindingMode.OneWay, null, InvalidateGauge);

public static BindableProperty IndicatorValueProperty = BindableProperty.Create("IndicatorValue", typeof(float), typeof(VerticalGuage), 20f, BindingMode.OneWay, null, InvalidateGauge);

public static BindableProperty IndicatorValueUnitProperty = BindableProperty.Create("IndicatorValueUnit", typeof(string), typeof(VerticalGuage), "", BindingMode.OneWay, null, InvalidateGauge);

public static BindableProperty IndicatorDirectionProperty = BindableProperty.Create("IndicatorDirection", typeof(string), typeof(VerticalGuage), "Right", BindingMode.OneWay, null, InvalidateGauge);

public float Maximum
{
get => (float)this.GetValue(MaximumProperty);
set => this.SetValue(MaximumProperty, value);
}

public float Minimum
{
get => (float)this.GetValue(MinimumProperty);
set => this.SetValue(MinimumProperty, value);
}

public float Step
{
get => (float)this.GetValue(StepProperty);
set => this.SetValue(StepProperty, value);
}

public float MinorTicks
{
get => (float)this.GetValue(MinorTicksProperty);
set => this.SetValue(MinorTicksProperty, value);
}

public float IndicatorValue
{
get => (float)this.GetValue(IndicatorValueProperty);
set => this.SetValue(IndicatorValueProperty, value);
}

public string IndicatorValueUnit
{
get => (string)this.GetValue(IndicatorValueUnitProperty);
set => this.SetValue(IndicatorValueUnitProperty, value);
}

public string IndicatorDirection
{
get => (string)this.GetValue(IndicatorDirectionProperty);
set => this.SetValue(IndicatorDirectionProperty, value);
}

private static void InvalidateGauge(BindableObject bindable, object oldValue, object newValue) =>
(bindable as VerticalGuage).guageCanvas.InvalidateSurface();


public VerticalGuage()
{
InitializeComponent();

regularStrokePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
StrokeWidth = regularStrokeWidth,
Color = strokeColor,
IsAntialias = true
};

minorStrokePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
StrokeWidth = minorStrokeWidth,
Color = strokeColor,
IsAntialias = true
};

majorStrokePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
StrokeWidth = majorStrokeWidth,
Color = strokeColor,
IsAntialias = true
};

indicatorStrokePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
StrokeWidth = indicatorStrokeWidth,
Color = strokeColor,
IsAntialias = true
};

fillPaint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = fillColor,
IsAntialias = true
};
}

void OnPaintSurface(System.Object sender, SkiaSharp.Views.Maui.SKPaintSurfaceEventArgs e)
{
SKSurface surface = e.Surface;
SKCanvas canvas = surface.Canvas;
SKImageInfo info = e.Info;

//Compute the Screen Density
var width = info.Width;
var height = info.Height;
density = width / (float)this.Width;

// clear the surface
canvas.Clear(SKColors.Transparent);

//Draw the guage container
DrawGuageOutLine(canvas, width, height);

//Draw Axis
DrawGuageAxis(canvas, width, height);

//Draw Value Indicator
DrawValueIndicator(canvas, width, height);
}

private void DrawGuageOutLine(SKCanvas canvas, int width, int height)
{
float verticalMargin = guageWidth / 2 + regularStrokeWidth / 2;

using (SKPath containerPath = new SKPath())
{
switch (IndicatorDirection)
{
case "Right":
containerPath.MoveTo(regularStrokeWidth / 2, verticalMargin);
containerPath.ArcTo(guageWidth / 2, guageWidth / 2, 0, SKPathArcSize.Large, SKPathDirection.Clockwise, guageWidth + regularStrokeWidth / 2, verticalMargin);
containerPath.LineTo(guageWidth + regularStrokeWidth / 2, height - verticalMargin);
containerPath.ArcTo(guageWidth / 2, guageWidth / 2, 0, SKPathArcSize.Large, SKPathDirection.Clockwise, regularStrokeWidth / 2, height - verticalMargin);
containerPath.Close();
break;
case "Left":
containerPath.MoveTo(width - guageWidth - regularStrokeWidth / 2, verticalMargin);
containerPath.ArcTo(guageWidth / 2, guageWidth / 2, 0, SKPathArcSize.Large, SKPathDirection.Clockwise, width - regularStrokeWidth / 2, verticalMargin);
containerPath.LineTo(width - regularStrokeWidth / 2, height - verticalMargin);
containerPath.ArcTo(guageWidth / 2, guageWidth / 2, 0, SKPathArcSize.Large, SKPathDirection.Clockwise, width - guageWidth - regularStrokeWidth / 2, height - verticalMargin);
containerPath.Close();
break;
}

canvas.DrawPath(containerPath, regularStrokePaint);
}
}

private void DrawGuageAxis(SKCanvas canvas, int width, int height)
{
var numMajorTicks = (Maximum - Minimum) / Step;
var majorDistance = (height - guageWidth * 2) / numMajorTicks;

var numMinorTicks = MinorTicks * numMajorTicks;
var minorDistance = (height - guageWidth * 2) / numMinorTicks;

for (int i = 0; i <= numMajorTicks; i++)
{
var start = new SKPoint(IndicatorDirection == "Right" ? guageWidth : width - guageWidth, i * majorDistance + guageWidth);
var end = new SKPoint(IndicatorDirection == "Right" ? guageWidth / 2.5f : width - guageWidth / 2.5f, i * majorDistance + guageWidth);

canvas.DrawLine(start, end, majorStrokePaint);
}

for (int i = 0; i <= numMinorTicks; i++)
{
var start = new SKPoint(IndicatorDirection == "Right" ? guageWidth : width - guageWidth, i * minorDistance + guageWidth);
var end = new SKPoint(IndicatorDirection == "Right" ? guageWidth - guageWidth / 4 : width - guageWidth + guageWidth / 4, i * minorDistance + guageWidth);

canvas.DrawLine(start, end, minorStrokePaint);
}
}

private void DrawValueIndicator(SKCanvas canvas, int width, int height)
{
if (IndicatorValue < Minimum || IndicatorValue > Maximum)
return;

float indicatorPosition = (height - guageWidth * 2) * (1f - (IndicatorValue - Minimum) / (Maximum - Minimum)) + guageWidth;
float verticalMargin = guageWidth / 2 + regularStrokeWidth / 2;

//Draw Indicator Line
var start = new SKPoint(IndicatorDirection == "Right" ? guageWidth + 10 : width - guageWidth - 10, indicatorPosition);
var end = new SKPoint(IndicatorDirection == "Right" ? guageWidth + 40 : width - guageWidth - 40, indicatorPosition);

canvas.DrawLine(start, end, indicatorStrokePaint);

//Draw Value Label
using (var textPaint = new SKPaint())
{
textPaint.TextSize = (DeviceInfo.Platform == DevicePlatform.Android) ? 40 : 32;
textPaint.IsAntialias = true;
textPaint.Color = strokeColor;
textPaint.IsStroke = false;

var indicatorText = IndicatorValue.ToString("0.0") + (!String.IsNullOrEmpty(IndicatorValueUnit) ? " " + IndicatorValueUnit : "");

if (IndicatorDirection == "Right")
canvas.DrawText(indicatorText, guageWidth + 40 + 10, indicatorPosition + 10, textPaint);
else
{
float textWidth = textPaint.MeasureText(indicatorText);

canvas.DrawText(indicatorText, width - guageWidth - 40 - 10 - textWidth, indicatorPosition + 10, textPaint);
}
}

//Fill the guage
using (SKPath containerPath = new SKPath())
{
switch (IndicatorDirection)
{
case "Right":
containerPath.MoveTo(regularStrokeWidth / 2, indicatorPosition);
containerPath.LineTo(guageWidth + regularStrokeWidth / 2, indicatorPosition);
containerPath.LineTo(guageWidth + regularStrokeWidth / 2, height - verticalMargin);
containerPath.ArcTo(guageWidth / 2, guageWidth / 2, 0, SKPathArcSize.Large, SKPathDirection.Clockwise, regularStrokeWidth / 2, height - verticalMargin);
containerPath.Close();
break;
case "Left":
containerPath.MoveTo(width - guageWidth - regularStrokeWidth / 2, indicatorPosition);
containerPath.LineTo(width - regularStrokeWidth / 2, indicatorPosition);
containerPath.LineTo(width - regularStrokeWidth / 2, height - verticalMargin);
containerPath.ArcTo(guageWidth / 2, guageWidth / 2, 0, SKPathArcSize.Large, SKPathDirection.Clockwise, width - guageWidth - regularStrokeWidth / 2, height - verticalMargin);
containerPath.Close();
break;
}

canvas.DrawPath(containerPath, fillPaint);
}
}

void guageCanvas_Touch(System.Object sender, SkiaSharp.Views.Maui.SKTouchEventArgs e)
{
if (e.ActionType == SKTouchAction.Pressed || e.ActionType == SKTouchAction.Released || e.ActionType == SKTouchAction.Moved)
{
var actualHeight = Height * density;
var y = e.Location.Y;

if (y < guageWidth || y > actualHeight - guageWidth)
return;

IndicatorValue = Convert.ToSingle(Minimum + (actualHeight - y - guageWidth) * (Maximum - Minimum) / (actualHeight - 2 * guageWidth));
}

e.Handled = true;
}
}
21 changes: 21 additions & 0 deletions src/Converters/BMIOpacityConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace MauiBMICalculator.Converters;

public class BMIOpacityConverter : IValueConverter
{
public float FromValue { get; set; }
public float ToValue { get; set; }

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var _value = System.Convert.ToSingle(value, new NumberFormatInfo() { NumberDecimalDigits = 1 });

if (_value >= FromValue && _value <= ToValue)
return 1.0f;

return 0.4f;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotImplementedException();
}

Loading

0 comments on commit 80c853f

Please sign in to comment.