Skip to content

Commit

Permalink
Add SOS functionality for both online and offline device
Browse files Browse the repository at this point in the history
  • Loading branch information
adityaoberai committed Jan 22, 2023
1 parent 1b6c687 commit c858391
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 12 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore

# Project files

SOS/Constants/AppwriteConstants.cs

# User-specific files
*.rsuser
*.suo
Expand Down
8 changes: 6 additions & 2 deletions SOS/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
using SOS.Data;
using SOS.Business;

namespace SOS;

public partial class App : Application
{
public static SettingsRepository SettingsRepo { get; private set; }

public App(SettingsRepository repo)
public static LocationService LocationService { get; private set; }

public App(SettingsRepository repo, LocationService locationService)
{
InitializeComponent();

MainPage = new AppShell();

SettingsRepo = repo;

LocationService = locationService;
}
}
53 changes: 53 additions & 0 deletions SOS/Business/LocationService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace SOS.Business
{
public class LocationService
{
private CancellationTokenSource _cancelTokenSource;
private bool _isCheckingLocation;

public async Task<Dictionary<string, object>> GetCurrentLocation()
{
try
{
_isCheckingLocation = true;

GeolocationRequest request = new GeolocationRequest(GeolocationAccuracy.Best);

_cancelTokenSource = new CancellationTokenSource();

Location location = await Geolocation.Default.GetLocationAsync(request, _cancelTokenSource.Token);

if (location != null)
{
_isCheckingLocation = false;
return new()
{
{ "found", true },
{ "latitude", location.Latitude.ToString() },
{ "longitude", location.Longitude.ToString() }
};

}
}
catch (Exception ex)
{
return new()
{
{ "found", false },
{ "error", ex.Message }
};
}

return new()
{
{ "found", false }
};
}

public void CancelRequest()
{
if (_isCheckingLocation && _cancelTokenSource != null && _cancelTokenSource.IsCancellationRequested == false)
_cancelTokenSource.Cancel();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using SOS.Models;
using SOS.Constants;
using SOS.Models;
using SQLite;

namespace SOS.Data
namespace SOS.Business
{
public class SettingsRepository
{
Expand All @@ -14,7 +15,7 @@ public async Task Init()
return;
}

conn = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
conn = new SQLiteAsyncConnection(DbConstants.DatabasePath, DbConstants.Flags);
await conn.CreateTableAsync<SettingsData>();
}

Expand Down
4 changes: 2 additions & 2 deletions SOS/Data/Constants.cs → SOS/Constants/DbConstants.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace SOS.Data
namespace SOS.Constants
{
public static class Constants
public static class DbConstants
{
public const string DatabaseFilename = "SOSSettings.db3";

Expand Down
73 changes: 69 additions & 4 deletions SOS/MainPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
namespace SOS;
using Newtonsoft.Json;
using SOS.Helpers;
using SOS.Models;

namespace SOS;

public partial class MainPage : ContentPage
{
public MainPage()
public MainPage()
{
InitializeComponent();

Expand All @@ -27,9 +31,70 @@ private async void SOSButtonClicked(object sender, EventArgs e)
return;
}

var settings = settingsDbResponse.SettingsData;
SettingsData settings = settingsDbResponse.SettingsData;
string phoneNumber = settings.PhoneNumber;

SOSButton.BackgroundColor = Colors.Crimson;
await DisplayAlert("Alert", $"Saved number: {settings.PhoneNumber}", "Ok");

var coordinates = await App.LocationService.GetCurrentLocation();
if (coordinates["found"] is false)
{
await DisplayAlert("Error", "Not able to get location", "Ok");
return;
}

string latitude = coordinates["latitude"].ToString();
string longitude = coordinates["longitude"].ToString();

NetworkAccess accessType = Connectivity.Current.NetworkAccess;

if (accessType != NetworkAccess.Internet)
{
if (Sms.Default.IsComposeSupported)
{
string[] recipients = new[] { phoneNumber };
string text = $"SOS ALERT:\n\nPlease get help at \n\nCoordinates: {latitude},{longitude}";

var message = new SmsMessage(text, recipients);

await Sms.Default.ComposeAsync(message);
}
}
else
{
var endpoint = $"/v1/functions/{AppwriteConstants.FunctionId}/executions";

HttpClient client = new HttpClient();
client.BaseAddress = new Uri(AppwriteConstants.AppwriteUrl);
client.DefaultRequestHeaders.Add("X-Appwrite-Response-Format", "1.0.0");
client.DefaultRequestHeaders.Add("X-Appwrite-Project", AppwriteConstants.ProjectId);
client.DefaultRequestHeaders.Add("X-Appwrite-Key", AppwriteConstants.ApiKey);

Dictionary<string, string> requestData = new Dictionary<string, string>();
requestData.Add("phoneNumber", settings.PhoneNumber);
requestData.Add("latitude", coordinates["latitude"].ToString());
requestData.Add("longitude", coordinates["longitude"].ToString());

var appwriteRequestInput = new Dictionary<string, string>()
{
{ "data", JsonConvert.SerializeObject(requestData) }
};
var jsonContent = new StringContent(JsonConvert.SerializeObject(appwriteRequestInput), System.Text.Encoding.UTF8, "application/json");

var sosResponse = await client.PostAsync(endpoint, jsonContent);
var sosResponseContent = await sosResponse.Content.ReadAsStringAsync();
var sosResponseData = JsonConvert.DeserializeObject<AppwriteApiResponse>(sosResponseContent);

var appwriteFunctionResponse = JsonConvert.DeserializeObject<Dictionary<string, object>>(sosResponseData.Response);
if (Convert.ToBoolean(appwriteFunctionResponse["sos"]))
{
await DisplayAlert("Alert", $"Sent SOS Request to {settings.PhoneNumber}", "Ok");
}
else
{
await DisplayAlert("Alert", "SOS Message Not Sent", "Ok");
}
}
SOSButton.BackgroundColor = Colors.Red;
}
}
3 changes: 2 additions & 1 deletion SOS/MauiProgram.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using SOS.Data;
using SOS.Business;

namespace SOS;

Expand All @@ -16,6 +16,7 @@ public static MauiApp CreateMauiApp()
});

builder.Services.AddSingleton<SettingsRepository>();
builder.Services.AddSingleton<LocationService>();

return builder.Build();
}
Expand Down
44 changes: 44 additions & 0 deletions SOS/Models/AppwriteApiResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;

namespace SOS.Models
{
public class AppwriteApiResponse
{
[JsonProperty("$id")]
public string Id { get; set; }

[JsonProperty("$createdAt")]
public DateTime CreatedAt { get; set; }

[JsonProperty("$updatedAt")]
public DateTime UpdatedAt { get; set; }

[JsonProperty("$permissions")]
public List<object> Permissions { get; set; }

[JsonProperty("functionId")]
public string FunctionId { get; set; }

[JsonProperty("trigger")]
public string Trigger { get; set; }

[JsonProperty("status")]
public string Status { get; set; }

[JsonProperty("statusCode")]
public int StatusCode { get; set; }

[JsonProperty("response")]
public string Response { get; set; }

[JsonProperty("stdout")]
public string Stdout { get; set; }

[JsonProperty("stderr")]
public string Stderr { get; set; }

[JsonProperty("duration")]
public double Duration { get; set; }
}
}
6 changes: 6 additions & 0 deletions SOS/Platforms/Android/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="smsto"/>
</intent>
</queries>
</manifest>
8 changes: 8 additions & 0 deletions SOS/Platforms/Android/MainApplication.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
using Android.App;
using Android.Runtime;

[assembly: UsesPermission(Android.Manifest.Permission.AccessNetworkState)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessFineLocation)]
[assembly: UsesFeature("android.hardware.location", Required = false)]
[assembly: UsesFeature("android.hardware.location.gps", Required = false)]
[assembly: UsesFeature("android.hardware.location.network", Required = false)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessBackgroundLocation)]

namespace SOS;

[Application]
Expand Down
2 changes: 2 additions & 0 deletions SOS/Platforms/MacCatalyst/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Fill in a reason why your app needs access to location.</string>
</dict>
</plist>
2 changes: 2 additions & 0 deletions SOS/Platforms/iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Fill in a reason why your app needs access to location.</string>
</dict>
</plist>
1 change: 1 addition & 0 deletions SOS/SOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
<PackageReference Include="SQLitePCLRaw.core" Version="2.1.0" />
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.0" />
Expand Down

0 comments on commit c858391

Please sign in to comment.