diff --git a/Helpers/GeolocationHelper.cs b/Helpers/GeolocationHelper.cs index ec8210a..1c294d9 100644 --- a/Helpers/GeolocationHelper.cs +++ b/Helpers/GeolocationHelper.cs @@ -20,7 +20,6 @@ namespace Justice.Helpers DesiredAccuracy = GeolocationAccuracy.High, Timeout = TimeSpan.FromSeconds(10) }); - if (location != null) { // Reverse geocode the location to get the address diff --git a/MauiProgram.cs b/MauiProgram.cs index 5850f3b..504df97 100644 --- a/MauiProgram.cs +++ b/MauiProgram.cs @@ -1,4 +1,6 @@ using Microsoft.Extensions.Logging; +using Microsoft.Maui.Controls.Maps; + namespace Justice { @@ -14,9 +16,10 @@ namespace Justice fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); + #if DEBUG - builder.Logging.AddDebug(); + builder.Logging.AddDebug(); #endif return builder.Build(); diff --git a/Resources/Images/log.svg b/Resources/Images/log.svg new file mode 100644 index 0000000..dc98439 --- /dev/null +++ b/Resources/Images/log.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/Images/logo.png b/Resources/Images/logo.png deleted file mode 100644 index e1ba3c0..0000000 Binary files a/Resources/Images/logo.png and /dev/null differ diff --git a/Resources/Splash/splash.svg b/Resources/Raw/splash.svg similarity index 100% rename from Resources/Splash/splash.svg rename to Resources/Raw/splash.svg diff --git a/Resources/Splash/log.svg b/Resources/Splash/log.svg new file mode 100644 index 0000000..dc98439 --- /dev/null +++ b/Resources/Splash/log.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Services/AuthorityService.cs b/Services/AuthorityService.cs index 205ffa4..7384786 100644 --- a/Services/AuthorityService.cs +++ b/Services/AuthorityService.cs @@ -13,12 +13,12 @@ namespace Justice.Services { private List _authorities = new List { - new Authority { Name = "Police", Email = "amritsyangtan1@gmail.com", Latitude = 47.7008, Longitude = 60.3000, AuthorityType = "Accident" }, - new Authority { Name = "Police", Email = "amreitsyanf@gmail.com", Latitude = 27.7008, Longitude = 85.3000, AuthorityType = "Accident" }, - new Authority { Name = "Fire Department", Email = "amAritsyangtan1@gmail.com", Latitude = 27.7110, Longitude = 85.2915, AuthorityType = "Fire" }, - new Authority { Name = "Crime", Email = "amritsyangtan1@gmail.com", Latitude = 47.7110, Longitude = 90.2915, AuthorityType = "Police" }, - new Authority { Name = "Crime", Email = "amreitsyanf@gmail.com", Latitude = 30.7110, Longitude = 80.2915, AuthorityType = "Police" }, - new Authority { Name = "Ambulance", Email = "ambulance@example.com", Latitude = 27.7052, Longitude = 85.3092, AuthorityType = "Ambulance" } + new Authority { Name = "Police", Email = "", Latitude = 27.7008, Longitude = 27.7008, AuthorityType = "Accident" }, + new Authority { Name = "Police", Email = "policed282@gmail.com", Latitude = 27.7008, Longitude = 85.3000, AuthorityType = "Accident" }, + new Authority { Name = "Fire Department", Email = "", Latitude = 27.7008, Longitude = 27.7008, AuthorityType = "Fire" }, + new Authority { Name = "Crime", Email = "amreitsyanf@gmail.com", Latitude = 27.7008, Longitude = 27.7008, AuthorityType = "Police" }, + new Authority { Name = "Crime", Email = "", Latitude = 27.7008, Longitude = 27.7008, AuthorityType = "Police" }, + new Authority { Name = "Ambulance", Email = "", Latitude = 27.7008, Longitude = 27.7008, AuthorityType = "Ambulance" } }; public List GetNearByAuthorities(double incidentLatitude, double incidentLongitude, double radiusKm = 10) { diff --git a/Services/SmsService.cs b/Services/SmsService.cs new file mode 100644 index 0000000..42a421d --- /dev/null +++ b/Services/SmsService.cs @@ -0,0 +1,35 @@ +using Microsoft.Maui.ApplicationModel.Communication; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Justice.Services +{ + public class SmsService + { + /// + /// Sends a bulk SMS message to a list of phone numbers. + /// + /// List of phone numbers to send the SMS to. + /// The message to send. + public async Task SendBulkSmsAsync(List phoneNumbers, string message) + { + foreach (var number in phoneNumbers) + { + try + { + var sms = new SmsMessage(message, new[] { number }); + await Sms.ComposeAsync(sms); + } + catch (FeatureNotSupportedException) + { + Console.WriteLine($"SMS not supported on this device for number {number}."); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to send SMS to {number}: {ex.Message}"); + } + } + } + } +} diff --git a/Views/AuthorityReportsPage.xaml.cs b/Views/AuthorityReportsPage.xaml.cs index 00aac0c..8c01cf0 100644 --- a/Views/AuthorityReportsPage.xaml.cs +++ b/Views/AuthorityReportsPage.xaml.cs @@ -29,8 +29,11 @@ namespace Justice.Views try { Reports.Clear(); + // Fetch reports from the database and sort them by DateTime in descending order var reportsFromDb = await _dbHelper.GetAllAsync(); - foreach (var report in reportsFromDb) + var sortedReports = reportsFromDb.OrderByDescending(r => r.DateTime).ToList(); + + foreach (var report in sortedReports) { Reports.Add(report); } @@ -41,6 +44,7 @@ namespace Justice.Views } } + private async void OnUpdateStatusClicked(object sender, EventArgs e) { var button = sender as Button; diff --git a/Views/IncidentReportPage.xaml.cs b/Views/IncidentReportPage.xaml.cs index d64f361..90b013a 100644 --- a/Views/IncidentReportPage.xaml.cs +++ b/Views/IncidentReportPage.xaml.cs @@ -1,11 +1,10 @@ using Justice.Services; using Justice.Helpers; using Justice.Models; -using Microsoft.Maui.Storage; using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using MailKit; namespace Justice.Views { @@ -15,6 +14,16 @@ namespace Justice.Views private readonly EmailService _emailService; private string _selectedAttachmentPath; // Store the file path of the selected attachment + // Mapping Incident Types to Authority Emails + private readonly Dictionary _incidentTypeToEmail = new() + { + { "Accident", "amreitsyanf@gmail.com" }, + { "Fire", "policed282@gmail.com" }, + { "Crime", "policed282@gmail.com" }, + { "Medical", "amreitsyanf@gmail.com" }, + { "Other", "general_authority@example.com" } + }; + public IncidentReportPage() { InitializeComponent(); @@ -40,8 +49,6 @@ namespace Justice.Views { var (latitude, longitude, address) = await GeolocationHelper.GetLocationAsync(); LocationEntry.Text = address; - - } catch (Exception ex) { @@ -59,11 +66,11 @@ namespace Justice.Views try { var customFileType = new FilePickerFileType(new Dictionary> - { - { DevicePlatform.Android, new[] { "*/*" } }, // Allow all files on Android - { DevicePlatform.iOS, new[] { "public.data" } }, // iOS equivalent for all files - { DevicePlatform.WinUI, new[] { "*" } } // Allow all files on Windows - }); + { + { DevicePlatform.Android, new[] { "*/*" } }, // Allow all files on Android + { DevicePlatform.iOS, new[] { "public.data" } }, // iOS equivalent for all files + { DevicePlatform.WinUI, new[] { "*" } } // Allow all files on Windows + }); var pickOptions = new PickOptions { @@ -91,7 +98,6 @@ namespace Justice.Views } } - private async void OnSubmitReportClicked(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(ReporterNameEntry.Text) || @@ -101,7 +107,7 @@ namespace Justice.Views await DisplayAlert("Error", "Please fill in all required fields.", "OK"); return; } - await SetLoadingStateAsync(true); //show loader + await SetLoadingStateAsync(true); // Show loader try { var (latitude, longitude, address) = await GeolocationHelper.GetLocationAsync(); @@ -116,86 +122,39 @@ namespace Justice.Views DateTime = DateTime.Now, AttachmentPath = _selectedAttachmentPath }; - //save report to database + + // Save report to database await _databaseHelper.InsertAsync(report); - // get nearby authorities based on incident location - var authorityService = new AuthorityService(); - var nearbyAuthorities = authorityService.GetNearByAuthorities(report.Latitude, report.Longitude); - // Prepare the email content - string emailBody = $"Incident Report:\n\n" + - $"Name: {report.ReporterName}\n" + - $"Type: {report.IncidentType}\n" + - $"Description: {report.Description}\n" + - $"Latitude: {report.Latitude}\n" + - $"Longitude: {report.Longitude}\n" + - $"Location: {report.Address}\n" + - $"Date/Time: {report.DateTime}"; - // Send email to each nearby authority - foreach (var authority in nearbyAuthorities) + // Get the email address for the selected incident type + string incidentType = report.IncidentType; + if (_incidentTypeToEmail.TryGetValue(incidentType, out var recipientEmail)) { - bool emailSent = await _emailService.SendEmailWithAttachmentAsync(authority.Email, "Incident Report", emailBody, _selectedAttachmentPath); + // Prepare the email content + string emailBody = $"Incident Report:\n\n" + + $"Name: {report.ReporterName}\n" + + $"Type: {report.IncidentType}\n" + + $"Description: {report.Description}\n" + + $"Latitude: {report.Latitude}\n" + + $"Longitude: {report.Longitude}\n" + + $"Location: {report.Address}\n" + + $"Date/Time: {report.DateTime}"; + + // Send email + bool emailSent = await _emailService.SendEmailWithAttachmentAsync(recipientEmail, "Incident Report", emailBody, _selectedAttachmentPath); if (emailSent) { - Console.WriteLine($"Email sent to: {authority.Name}"); + Console.WriteLine($"Email sent to: {recipientEmail}"); + await DisplayAlert("Success", "Incident report submitted and email sent.", "OK"); + } + else + { + await DisplayAlert("Error", "Failed to send email.", "OK"); } - } - - await DisplayAlert("Success", "Incident report submitted and email alert sent to nearby authorities.", "OK"); - } - catch (Exception ex) - { - await DisplayAlert("Error", $"Failed to submit report:{ex.Message}", "OK"); - } - finally - { - await SetLoadingStateAsync(false); //hide loader - } - - - // var (latitude, longitude, address) = await GeolocationHelper.GetLocationAsync(); - - /* var report = new IncidentReport - { - ReporterName = ReporterNameEntry.Text.Trim(), - IncidentType = IncidentTypePicker.SelectedItem.ToString(), - Description = DescriptionEditor.Text.Trim(), - Latitude = latitude, - Longitude = longitude, - Address = address, - DateTime = DateTime.Now, - AttachmentPath = _selectedAttachmentPath // Save the attachment path - }; - - try - { - // Save the report to the database - - await _databaseHelper.InsertAsync(report); - - // Get the recipient email based on the incident type - string recipientEmail = _emailService.GetRecipientEmail(report.IncidentType); - - // Prepare the email content - string emailBody = $"Incident Report:\n\n" + - $"Name: {report.ReporterName}\n" + - $"Type: {report.IncidentType}\n" + - $"Description: {report.Description}\n" + - $"Latitude: {report.Latitude}\n" + - $"Longitude: {report.Longitude}\n" + - $"Location: {report.Address}\n" + - $"Date/Time: {report.DateTime}"; - - // Send email - bool emailSent = await _emailService.SendEmailWithAttachmentAsync(recipientEmail, "Incident Report", emailBody, _selectedAttachmentPath); - - if (emailSent) - { - await DisplayAlert("Success", "Incident report submitted and email alert sent.", "OK"); } else { - await DisplayAlert("Error", "Failed to send email alert.", "OK"); + await DisplayAlert("Error", "No authority found for the selected incident type.", "OK"); } } catch (Exception ex) @@ -204,10 +163,8 @@ namespace Justice.Views } finally { - await SetLoadingStateAsync(false); + await SetLoadingStateAsync(false); // Hide loader } - */ } - } } diff --git a/Views/LoginPage.xaml.cs b/Views/LoginPage.xaml.cs index fd1a9e2..1c9d054 100644 --- a/Views/LoginPage.xaml.cs +++ b/Views/LoginPage.xaml.cs @@ -20,10 +20,10 @@ namespace Justice.Views private async void OnLoginButtonClicked(object sender, EventArgs e) { - var endvalidUsername = "enduser"; - var endvalidPassword = "enduser123"; - var authvalidUsername = "authuser"; - var authvalidPassword = "authuser123"; + var endvalidUsername = "euser"; + var endvalidPassword = "euser123"; + var authvalidUsername = "auser"; + var authvalidPassword = "auser123"; var enteredUsername = UsernameEntry?.Text?.Trim(); var enteredPassword = PasswordEntry?.Text?.Trim();