Skip to content

Commit

Permalink
Merge pull request #9 from AathifMahir/AutoStop
Browse files Browse the repository at this point in the history
New Auto Stop Property Implementation and Overall Enhancements
  • Loading branch information
AathifMahir authored May 19, 2023
2 parents 577e586 + 780002f commit 28ec416
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 68 deletions.
8 changes: 8 additions & 0 deletions sample/MauiShakeDetectorSample/MainPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@
Clicked="BtnStartListening_Clicked"
HorizontalOptions="Center" />

<Button
Margin="0,12,0,0"
x:Name="BtnStopListening"
Text="Stop Listening"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="BtnStopListening_Clicked"
HorizontalOptions="Center" />

<Label x:Name="TxtShakeStatus" HorizontalOptions="Center" VerticalOptions="Center" BackgroundColor="{StaticResource Primary}" TextColor="White" Padding="12,12,12,12" Text="Not Yet Listening" />

</VerticalStackLayout>
Expand Down
33 changes: 16 additions & 17 deletions sample/MauiShakeDetectorSample/MainPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using MauiShakeDetector;
using System.Diagnostics;

namespace MauiShakeDetectorSample;

Expand All @@ -9,8 +10,6 @@ public MainPage()
{
InitializeComponent();
}

bool isListening = false;
private void BtnStartListening_Clicked(object sender, EventArgs e)
{
if (!ShakeDetector.Default.IsSupported)
Expand All @@ -23,27 +22,27 @@ private void BtnStartListening_Clicked(object sender, EventArgs e)
TxtShakeStatus.Text = "Shake Detector is ALready Running";
return;
}
if (!isListening)
{
BtnStartListening.Text = "Stop Listening";
isListening = true;

ShakeDetector.Default.StartListening();
ShakeDetector.Default.ShakeDetected += Detector_ShakeDetected;
return;
}

BtnStartListening.Text = "Start Listening";
isListening = false;
ShakeDetector.Default.StopListening();
ShakeDetector.Default.ShakeDetected -= Detector_ShakeDetected;
TxtShakeStatus.Text = "Shake Detector is Stop Listening";
TxtShakeStatus.Text = "Started Listening";
//ShakeDetector.Default.AutoStopAfterNoShakes = 5;
ShakeDetector.Default.StartListening();
ShakeDetector.Default.ShakeDetected += Detector_ShakeDetected;
}

private void Detector_ShakeDetected(object sender, ShakeDetectedEventArgs e)
{
TxtShakeStatus.Text += $" and No of Shakes {e.NoOfShakes}";
TxtShakeStatus.Text = $"No of Shakes {e.NoOfShakes}";
}

private void BtnStopListening_Clicked(object sender, EventArgs e)
{

if(ShakeDetector.Default.IsMonitoring)
{
ShakeDetector.Default.StopListening();
ShakeDetector.Default.ShakeDetected -= Detector_ShakeDetected;
TxtShakeStatus.Text = "Shake Detector is Stop Listening";
}
}
}

30 changes: 30 additions & 0 deletions src/MauiShakeDetector.UnitTest/MauiShakeDetector.UnitTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\MauiShakeDetector\MauiShakeDetector.csproj" />
</ItemGroup>

</Project>
5 changes: 5 additions & 0 deletions src/MauiShakeDetector.UnitTest/ShakeDetectorDefaultTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace MauiShakeDetector.UnitTest;
public class ShakeDetectorDefaultTest
{

}
14 changes: 14 additions & 0 deletions src/MauiShakeDetector.UnitTest/ShakeEventArgsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using FluentAssertions;

namespace MauiShakeDetector.UnitTest;
public class ShakeEventArgsTest
{
[Theory]
[InlineData(1)]
[InlineData(2)]
public void NoOfShakesShouldBeEqualInShakeDetectedEventArgs(int noOfShakes)
{
var eventArgs = new ShakeDetectedEventArgs(noOfShakes);
eventArgs.NoOfShakes.Should().Be(noOfShakes);
}
}
1 change: 1 addition & 0 deletions src/MauiShakeDetector.UnitTest/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Xunit;
6 changes: 6 additions & 0 deletions src/MauiShakeDetector.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiShakeDetector", "MauiSh
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiShakeDetectorSample", "..\sample\MauiShakeDetectorSample\MauiShakeDetectorSample.csproj", "{A7020180-920D-42F8-93FB-BA36927F8B37}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MauiShakeDetector.UnitTest", "MauiShakeDetector.UnitTest\MauiShakeDetector.UnitTest.csproj", "{9BB800E4-ACE7-49DB-BDA9-6626AA36F0DF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -23,6 +25,10 @@ Global
{A7020180-920D-42F8-93FB-BA36927F8B37}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7020180-920D-42F8-93FB-BA36927F8B37}.Release|Any CPU.Build.0 = Release|Any CPU
{A7020180-920D-42F8-93FB-BA36927F8B37}.Release|Any CPU.Deploy.0 = Release|Any CPU
{9BB800E4-ACE7-49DB-BDA9-6626AA36F0DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9BB800E4-ACE7-49DB-BDA9-6626AA36F0DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9BB800E4-ACE7-49DB-BDA9-6626AA36F0DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9BB800E4-ACE7-49DB-BDA9-6626AA36F0DF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
64 changes: 40 additions & 24 deletions src/MauiShakeDetector/IShakeDetector.cs
Original file line number Diff line number Diff line change
@@ -1,69 +1,85 @@
namespace MauiShakeDetector;
public interface IShakeDetector
{

/// <summary>
/// Gets a Value Indicating Whether ShakeDetector is Supported on this Device
/// Gets a value indicating whether ShakeDetector is supported on this device
/// </summary>
bool IsSupported { get; }
/// <summary>
/// Gets a Value Indicating Whether ShakeDetector is Already Monitoring
/// Gets a value indicating whether ShakeDetector is already monitoring
/// </summary>
bool IsMonitoring { get; }

/// <summary>
/// Get or Set the Value of Shake Detection Threshold
/// In Summary The Gforce Value for Shake To Be Detected
/// Gets or sets the value of shake detection threshold
/// In summary, the Gforce value for shake to be detected
/// </summary>
double ShakeThresholdGravity { get; set; }
double ShakeThresholdGravity { get; set; }

/// <summary>
/// Get or Set the value of Minimum Delay betweem Shakes
/// Gets or sets the value of minimum delay between shakes
/// </summary>
TimeSpan ShakeIntervalInMilliseconds { get; set; }
TimeSpan ShakeIntervalInMilliseconds { get; set; }

/// <summary>
/// Get or Set the Value of Shake Reset Interval in Milliseconds
/// Gets or sets the value of shake reset interval in milliseconds
/// </summary>
TimeSpan ShakeResetIntervalInMilliseconds { get; set; }
TimeSpan ShakeResetIntervalInMilliseconds { get; set; }

/// <summary>
/// Get or Set the Value for Number of Shakes Required Before Shake is Triggered
/// Gets or sets the value for number of shakes required before shake is triggered
/// </summary>
int MinimumShakeCount { get; set; }
int MinimumShakeCount { get; set; }
/// <summary>
/// Gets a Value Indicating Whether Haptics is Enabled or not
/// Gets a value indicating whether haptics is enabled or not
/// </summary>
/// <remarks>
/// Default is true, you can disable it if you want by setting it to false
/// </remarks>
/// <remarks>
/// Will throw Microsoft.Maui.ApplicationModel.FeatureNotSupportedException If MauiShakeDetector.IShakeDetector.IsHapticsSupported is false,
/// Therefore Please Check Whether MauiShakeDetector.IShakeDetector.IsHapticsSupported is true before enabling haptics on the device
/// </remarks>
bool IsHapticsEnabled { get; set; }
/// <summary>
/// Gets a Value Indicating Whether Haptics Supported in this Device
/// Gets a value indicating whether haptics is supported on this device
/// </summary>
bool IsHapticsSupported { get;}
/// <remarks>
/// Will throw Microsoft.Maui.ApplicationModel.FeatureNotSupportedException If MauiShakeDetector.IShakeDetector.IsHapticsSupported is false
/// </remarks>
bool IsHapticsSupported { get; }
/// <summary>
/// Gets or sets the value of haptics duration
/// </summary>
TimeSpan HapticsDurationInMilliseconds { get; set; }
/// <summary>
/// Get or Set the Value Of Haptics Duration
/// Gets or sets the value of auto stop listening to shake event after number of shakes triggered
/// </summary>
TimeSpan HapticsDurationInMilliseconds { get; set; }
/// <remarks>
/// Default is 0 and it means feature is disabled by default. You can set the count to some other value to enable this feature
/// </remarks>
int AutoStopAfterNoShakes { get; set; }
/// <summary>
/// Shake Detected Event for Detecting Whether User Shaked the Device
/// Shake detected event for detecting whether user shook the device
/// </summary>
#nullable enable
event EventHandler<ShakeDetectedEventArgs>? ShakeDetected;
#nullable disable

/// <summary>
/// Start listening for Shake Event
/// Start listening for shake event
/// </summary>
/// <param name="sensorSpeed">
/// Speed to monitor the Shake Events.
/// Speed to monitor the shake events.
/// </param>
/// <remarks>
/// Will throw Microsoft.Maui.ApplicationModel.FeatureNotSupportedException if MauiShakeDetector.IShakeDetector.IsSupported
/// is false. Will throw System.InvalidOperationException if MauiShakeDetector.IShakeDetector.IsMonitoring
/// is true.
/// Will throw Microsoft.Maui.ApplicationModel.FeatureNotSupportedException if MauiShakeDetector.IShakeDetector.IsSupported is false.
/// Will throw System.InvalidOperationException if MauiShakeDetector.IShakeDetector.IsMonitoring is true.
/// </remarks>
void StartListening(SensorSpeed sensorSpeed = SensorSpeed.Default);
/// <summary>
/// Stop Already Monitoring Shake Event
/// Stop already monitoring shake event
/// </summary>
void StopListening();
}
6 changes: 3 additions & 3 deletions src/MauiShakeDetector/MauiShakeDetector.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
<Description>Maui Shake Detector Shake Event Detector Library with Lots of Customization like GForce Tuning, Shake Intervals and Haptics for Shake Events</Description>
<PackageIcon>icon.png</PackageIcon>
<Product>$(AssemblyName) ($(TargetFramework))</Product>
<AssemblyVersion>0.1.0.0</AssemblyVersion>
<AssemblyFileVersion>0.1.0.0</AssemblyFileVersion>
<Version>0.1.0</Version>
<AssemblyVersion>0.2.0.0</AssemblyVersion>
<AssemblyFileVersion>0.2.0.0</AssemblyFileVersion>
<Version>0.2.0</Version>
<PackageVersion>$(Version)$(VersionSuffix)</PackageVersion>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageTags>Maui,Shake,ShakeDetector,MauiShake,</PackageTags>
Expand Down
6 changes: 5 additions & 1 deletion src/MauiShakeDetector/ReleaseNotes.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
v0.1.0
v0.2.0
• Added New Property to Auto Stop Listening to Shake Event "AutoStopAfterNoShakes"
• Enhancements for Comments

v0.1.0
• First Stable Build
• Enhancements for Comments

Expand Down
1 change: 1 addition & 0 deletions src/MauiShakeDetector/ShakeDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public static class ShakeDetector
public static bool IsHapticsSupported => Default.IsHapticsSupported;
public static bool IsHapticsEnabled => Default.IsHapticsEnabled;
public static TimeSpan HapticsDurationInMilliseconds => Default.HapticsDurationInMilliseconds;
public static int AutoStopAfterNoShakes => Default.AutoStopAfterNoShakes;

public static event EventHandler<ShakeDetectedEventArgs> ShakeDetected
{
Expand Down
61 changes: 38 additions & 23 deletions src/MauiShakeDetector/ShakeDetectorDefault.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@
internal sealed class ShakeDetectorDefault : IShakeDetector
{
// Properties
public bool IsSupported { get; set; } = Accelerometer.Default.IsSupported;
public bool IsMonitoring { get; set; } = Accelerometer.Default.IsMonitoring;
public bool IsSupported => Accelerometer.Default.IsSupported;
public bool IsMonitoring => Accelerometer.Default.IsMonitoring;
public double ShakeThresholdGravity { get; set; } = 1.9;
public TimeSpan ShakeIntervalInMilliseconds { get; set; } = TimeSpan.FromMilliseconds(500);
public TimeSpan ShakeResetIntervalInMilliseconds { get; set; } = TimeSpan.FromMilliseconds(3000);
public int MinimumShakeCount { get; set; } = 1;
public bool IsHapticsEnabled { get; set; } = true;
public bool IsHapticsSupported { get; set; } = Vibration.Default.IsSupported;
public bool IsHapticsSupported => Vibration.Default.IsSupported;
public TimeSpan HapticsDurationInMilliseconds { get; set; } = TimeSpan.FromMilliseconds(1700);

public int AutoStopAfterNoShakes { get; set; } = 0;

// Private Fields

TimeSpan currentShakeTimeInMilliseconds = new(DateTime.Now.Ticks);

int currentShakeCount = 0;
int currentTriggeredShakesCount = 0;

static bool useSyncContext;

Expand All @@ -44,31 +45,44 @@ private void Accelerometer_ReadingChanged(object sender, AccelerometerChangedEve

double gForce = Math.Sqrt(x * x + y * y + z * z);

if (gForce > ShakeThresholdGravity)
{
TimeSpan now = new(DateTime.Now.Ticks);
if (gForce < ShakeThresholdGravity) return;

TimeSpan now = new(DateTime.Now.Ticks);

if (currentShakeTimeInMilliseconds + ShakeIntervalInMilliseconds > now) return;
if (currentShakeTimeInMilliseconds + ShakeIntervalInMilliseconds > now) return;

if (currentShakeTimeInMilliseconds + ShakeResetIntervalInMilliseconds < now) currentShakeCount = 0;
if (currentShakeTimeInMilliseconds + ShakeResetIntervalInMilliseconds < now) currentShakeCount = 0;

currentShakeTimeInMilliseconds = now;
currentShakeCount++;
currentShakeTimeInMilliseconds = now;
currentShakeCount++;

if (currentShakeCount < MinimumShakeCount) return;

if (IsHapticsEnabled)
{
if (!IsHapticsSupported) throw new FeatureNotSupportedException("Haptics is Not Supported in Your Device");
Vibration.Default.Vibrate(HapticsDurationInMilliseconds);
}

if (currentShakeCount < MinimumShakeCount) return;
if (useSyncContext)
{
currentTriggeredShakesCount++;
MainThread.BeginInvokeOnMainThread(() => ShakeDetected?.Invoke(this, new ShakeDetectedEventArgs(currentShakeCount)));
AutoStopAfterNoShakeEvents();
return;
}

if (IsHapticsEnabled)
{
if (!IsHapticsSupported) throw new FeatureNotSupportedException("Haptics is Not Supported in Your Device");
Vibration.Default.Vibrate(HapticsDurationInMilliseconds);
}
currentTriggeredShakesCount++;
ShakeDetected?.Invoke(this, new ShakeDetectedEventArgs(currentShakeCount));
AutoStopAfterNoShakeEvents();
}

if (useSyncContext)
{
MainThread.BeginInvokeOnMainThread(() => ShakeDetected?.Invoke(this, new ShakeDetectedEventArgs(currentShakeCount)));
return;
}
ShakeDetected?.Invoke(this, new ShakeDetectedEventArgs(currentShakeCount));
private void AutoStopAfterNoShakeEvents()
{
if(AutoStopAfterNoShakes != 0 && currentTriggeredShakesCount >= AutoStopAfterNoShakes)
{
currentTriggeredShakesCount = 0;
StopListening();
}
}

Expand All @@ -77,6 +91,7 @@ public void StopListening()
if (Accelerometer.Default.IsMonitoring)
{
Accelerometer.Default.ReadingChanged -= Accelerometer_ReadingChanged;
currentTriggeredShakesCount = 0;
Accelerometer.Default.Stop();
}
}
Expand Down
1 change: 1 addition & 0 deletions src/MauiShakeDetector/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ using MauiShakeDetector;
| **ShakeIntervalInMilliseconds** | `TimeSpan` | Get or Set the value of Minimum Delay betweem Shakes |
| **ShakeResetIntervalInMilliseconds** | `TimeSpan` | Get or Set the Value of Shake Reset Interval in Milliseconds |
| **MinimumShakeCount** | `int` | Get or Set the Value for Number of Shakes Required Before Shake is Triggered |
| **AutoStopAfterNoShakes** | `int` | Gets or sets the value of Auto Stop listening to shake event after number of shakes triggered |
| **HapticsDurationInMilliseconds** | `TimeSpan` | Get or Set the Value Of Haptics Duration |
| **ShakeDetected** | `event` | Shake Detected Event for Detecting Whether User Shaked the Device |
| **StartListening()** | `method` | Start listening for Shake Event |
Expand Down

0 comments on commit 28ec416

Please sign in to comment.