diff --git a/App.xaml.cs b/App.xaml.cs index 896a49f..0a1e082 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -1,10 +1,27 @@ -namespace Justice +using Justice.Helpers; +using Justice.Models; + +namespace Justice { public partial class App : Application { public App() { InitializeComponent(); + InitializeDatabaseAsync(); // Call the async method to initialize the database + } + + private async void InitializeDatabaseAsync() + { + try + { + var dbHelper = new DatabaseHelper(); + await dbHelper.InitializeAsync(); // Asynchronously create the EmergencyContact table + } + catch (Exception ex) + { + Console.WriteLine($"Database initialization failed: {ex.Message}"); + } } protected override Window CreateWindow(IActivationState? activationState) @@ -12,4 +29,4 @@ return new Window(new AppShell()); } } -} \ No newline at end of file +} diff --git a/Helpers/DatabaseHelper.cs b/Helpers/DatabaseHelper.cs index 831908e..e2e025b 100644 --- a/Helpers/DatabaseHelper.cs +++ b/Helpers/DatabaseHelper.cs @@ -1,42 +1,38 @@ -using System; +using SQLite; +using System; using System.Collections.Generic; -using System.Linq; +using System.IO; using System.Linq.Expressions; -using System.Text; using System.Threading.Tasks; -using SQLite; namespace Justice.Helpers { public class DatabaseHelper { private readonly SQLiteAsyncConnection _database; - public DatabaseHelper(string databaseName = "Appdatabase.db") + + public DatabaseHelper(string databaseName = "JusticeAppDatabase.db") { var dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), databaseName); _database = new SQLiteAsyncConnection(dbPath); } - public async Task InitializeAsync() where T: new() + + public async Task InitializeAsync() where T : class, new() { await _database.CreateTableAsync(); } - public async Task InsertAsync(T item) where T : new() - { + + public async Task InsertAsync(T item) where T : class, new() + { return await _database.InsertAsync(item); } - public async Task>GetAllAsync()where T : new() + + public async Task> GetAllAsync() where T : class, new() { return await _database.Table().ToListAsync(); } - public async Task> GetAsync(Expression> predicate) where T : new() - { - return await _database.Table().Where(predicate).ToListAsync(); - } - public async Task UpdateAsync(T item) where T : new() - { - return await _database.UpdateAsync(item); - } - public async Task DeleteAsync(T item) where T : new() + + public async Task DeleteAsync(T item) where T : class, new() { return await _database.DeleteAsync(item); } diff --git a/Helpers/GeolocationHelper.cs b/Helpers/GeolocationHelper.cs index 7117e1f..bf7c3e1 100644 --- a/Helpers/GeolocationHelper.cs +++ b/Helpers/GeolocationHelper.cs @@ -3,30 +3,59 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.Maui.ApplicationModel; namespace Justice.Helpers { public class GeolocationHelper { - public static async Task<(double Latitude, double Longitude)> GetCurrentLocationAsync() + /// + /// Retrieves the user's current latitude, longitude, and a readable address. + /// + /// A tuple containing Latitude, Longitude, and Address. + public static async Task<(double Latitude, double Longitude, string Address)> GetCurrentLocationAsync() { - var location = await Geolocation.Default.GetLocationAsync(); - if (location != null) + try { - return (location.Latitude, location.Longitude); - } - throw new Exception("Unable to fetch location"); - } + var location = await Geolocation.Default.GetLocationAsync(new GeolocationRequest + { + DesiredAccuracy = GeolocationAccuracy.High, + Timeout = TimeSpan.FromSeconds(10) + }); - public static async Task GetReadableAddressAsync(double latitude, double longitude) - { - var placemarks = await Geocoding.Default.GetPlacemarksAsync(latitude, longitude); - var placemark = placemarks.FirstOrDefault(); - if ( placemark !=null) + if (location != null) + { + var placemarks = await Geocoding.Default.GetPlacemarksAsync(location); + var placemark = placemarks.FirstOrDefault(); + string address = "Address not found"; + + if (placemark != null) + { + address = $"{placemark.SubLocality}, {placemark.Thoroughfare}, " + + $"{placemark.Locality}, {placemark.AdminArea}, {placemark.CountryName}"; + } + + return (location.Latitude, location.Longitude, address); + } + + // Return a default value if location is null + return (0, 0, "Unable to fetch location."); + } + catch (FeatureNotSupportedException) + { + // Return a default value if location services are not supported + return (0, 0, "Location services are not supported on this device."); + } + catch (PermissionException) + { + // Return a default value if permissions are not granted + return (0, 0, "Location permissions are not granted."); + } + catch (Exception ex) { - return $"{placemark.SubLocality}, {placemark.Thoroughfare}, {placemark.Locality}, {placemark.CountryName}"; + // Return a default value for other errors + return (0, 0, $"An error occurred: {ex.Message}"); } - return "Address Not Found"; } } } diff --git a/Helpers/SmsHelper.cs b/Helpers/SmsHelper.cs new file mode 100644 index 0000000..15baa80 --- /dev/null +++ b/Helpers/SmsHelper.cs @@ -0,0 +1,23 @@ +using Microsoft.Maui.ApplicationModel.Communication; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Justice.Helpers +{ + public static class SmsHelper + { + public static async Task SendSmsAsync(string message, List recipients) + { + try + { + var smsMessage = new SmsMessage(message, recipients); + await Sms.ComposeAsync(smsMessage); + } + catch (Exception ex) + { + throw new Exception($"Unable to send SMS: {ex.Message}"); + } + } + } +} diff --git a/Helpers/SosService.cs b/Helpers/SosService.cs new file mode 100644 index 0000000..b85d9c0 --- /dev/null +++ b/Helpers/SosService.cs @@ -0,0 +1,32 @@ +using Justice.Helpers; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Justice.Services +{ + public class SosService + { + public async Task SendSosAlertAsync(List recipients) + { + try + { + // Fetch location and address + (double latitude, double longitude, string address) = await GeolocationHelper.GetCurrentLocationAsync(); + + + // Prepare the SOS message + string message = $"SOS Alert! I need help. My location:\n" + + $"Latitude: {latitude}, Longitude: {longitude}\n" + + $"Address: {address}\n\n"; + + // Send the SMS + await SmsHelper.SendSmsAsync(message, recipients); + } + catch (Exception ex) + { + throw new Exception($"SOS Alert failed: {ex.Message}"); + } + } + } +} diff --git a/Justice.csproj b/Justice.csproj index 389555e..865d3ae 100644 --- a/Justice.csproj +++ b/Justice.csproj @@ -71,9 +71,18 @@ + + MSBuild:Compile + MSBuild:Compile + + MSBuild:Compile + + + MSBuild:Compile + diff --git a/Justice.csproj.user b/Justice.csproj.user index 23d4721..67620d6 100644 --- a/Justice.csproj.user +++ b/Justice.csproj.user @@ -3,17 +3,26 @@ False net9.0-android - Medium Phone API 35 (Android 15.0 - API 35) - Emulator + Samsung SM-M325F (Android 13.0 - API 33) + PhysicalDevice Medium_Phone_API_35 ProjectDebugger + + Designer + Designer + + Designer + + + Designer + diff --git a/Models/EmergencyContact.cs b/Models/EmergencyContact.cs index 77d3e8c..a521034 100644 --- a/Models/EmergencyContact.cs +++ b/Models/EmergencyContact.cs @@ -4,11 +4,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Justice.Models; +using SQLite; namespace Justice.Models { public class EmergencyContact { + [PrimaryKey,AutoIncrement] public int Id { get; set; } public string Name { get; set; } public string MobileNumber { get; set; } diff --git a/Views/AddContactPage.xaml b/Views/AddContactPage.xaml index b8a2c3b..a4a8f30 100644 --- a/Views/AddContactPage.xaml +++ b/Views/AddContactPage.xaml @@ -1,9 +1,10 @@ + Title="Emergency Contacts"> +