|
|
@ -1,14 +1,16 @@ |
|
|
|
using Justice.Helpers; |
|
|
|
using Justice.Helpers; |
|
|
|
using Microsoft.Maui.ApplicationModel.Communication; |
|
|
|
|
|
|
|
using System; |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Collections.Generic; |
|
|
|
|
|
|
|
using System.Threading; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using System.Threading.Tasks; |
|
|
|
|
|
|
|
using Microsoft.Maui.ApplicationModel.Communication; |
|
|
|
|
|
|
|
|
|
|
|
namespace Justice.Views |
|
|
|
namespace Justice.Views |
|
|
|
{ |
|
|
|
{ |
|
|
|
public partial class MapTimer : ContentPage |
|
|
|
public partial class MapTimer : ContentPage |
|
|
|
{ |
|
|
|
{ |
|
|
|
private bool isTrackingActive; |
|
|
|
private CancellationTokenSource _cancellationTokenSource; |
|
|
|
|
|
|
|
private readonly double _tolerance = 0.0001; |
|
|
|
|
|
|
|
|
|
|
|
public MapTimer() |
|
|
|
public MapTimer() |
|
|
|
{ |
|
|
|
{ |
|
|
@ -16,126 +18,126 @@ namespace Justice.Views |
|
|
|
FetchLocation(); |
|
|
|
FetchLocation(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async void StartTrackingClicked(object sender, EventArgs e) |
|
|
|
private async void FetchLocation() |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (string.IsNullOrWhiteSpace(DestinationLatitudeEntry.Text) || |
|
|
|
try |
|
|
|
string.IsNullOrWhiteSpace(DestinationLongitudeEntry.Text)) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
await DisplayAlert("Error", "Please enter destination coordinates.", "OK"); |
|
|
|
var (latitude, longitude, address) = await GeolocationHelper.GetLocationAsync(); |
|
|
|
return; |
|
|
|
SourceLatitudeEntry.Text = latitude.ToString(); |
|
|
|
|
|
|
|
SourceLongitudeEntry.Text = longitude.ToString(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
catch (Exception ex) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
await DisplayAlert("Error", $"Failed to fetch location: {ex.Message}", "OK"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private async void StartTrackingClicked(object sender, EventArgs e) |
|
|
|
|
|
|
|
{ |
|
|
|
if (!double.TryParse(DestinationLatitudeEntry.Text, out double destinationLatitude) || |
|
|
|
if (!double.TryParse(DestinationLatitudeEntry.Text, out double destinationLatitude) || |
|
|
|
!double.TryParse(DestinationLongitudeEntry.Text, out double destinationLongitude)) |
|
|
|
!double.TryParse(DestinationLongitudeEntry.Text, out double destinationLongitude)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
await DisplayAlert("Error", "Invalid destination coordinates.", "OK"); |
|
|
|
await DisplayAlert("Error", "Please enter valid destination coordinates.", "OK"); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!int.TryParse(TimerEntry.Text, out int timerMinutes)) |
|
|
|
if (!int.TryParse(TimerEntry.Text, out int timerSeconds) || timerSeconds <= 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
await DisplayAlert("Error", "Invalid timer value. Please enter a numeric value.", "OK"); |
|
|
|
await DisplayAlert("Error", "Please enter a valid timer value in seconds.", "OK"); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
isTrackingActive = true; |
|
|
|
await StartTimerAsync(destinationLatitude, destinationLongitude, timerSeconds); |
|
|
|
|
|
|
|
} |
|
|
|
// Set timer duration |
|
|
|
|
|
|
|
var timerDuration = TimeSpan.FromMinutes(timerMinutes); |
|
|
|
|
|
|
|
var timerEnd = DateTime.Now.Add(timerDuration); |
|
|
|
|
|
|
|
string phoneNumber = "9860104625"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Start countdown display |
|
|
|
private async Task StartTimerAsync(double destinationLatitude, double destinationLongitude, int timerSeconds) |
|
|
|
_ = UpdateCountdownDisplay(timerEnd); |
|
|
|
{ |
|
|
|
|
|
|
|
var startTime = DateTime.Now; |
|
|
|
|
|
|
|
var endTime = startTime.AddSeconds(timerSeconds); |
|
|
|
|
|
|
|
_cancellationTokenSource = new CancellationTokenSource(); |
|
|
|
|
|
|
|
|
|
|
|
while (isTrackingActive && DateTime.Now < timerEnd) |
|
|
|
while (DateTime.Now <= endTime) |
|
|
|
{ |
|
|
|
{ |
|
|
|
await Task.Delay(5000); // Check location every 5 seconds |
|
|
|
if (_cancellationTokenSource.Token.IsCancellationRequested) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
// Fetch current location |
|
|
|
// Fetch the current location |
|
|
|
var (currentLatitude, currentLongitude, _) = await GeolocationHelper.GetLocationAsync(); |
|
|
|
var (currentLatitude, currentLongitude, _) = await GeolocationHelper.GetLocationAsync(); |
|
|
|
|
|
|
|
|
|
|
|
// Define tolerance for proximity |
|
|
|
// Update TimerLabel |
|
|
|
const double Tolerance = 0.0001; |
|
|
|
var remainingTime = endTime - DateTime.Now; |
|
|
|
|
|
|
|
TimerLabel.Text = $"Remaining Time: {remainingTime.Seconds}s"; |
|
|
|
|
|
|
|
|
|
|
|
// Check if user has reached the destination |
|
|
|
// Check if the user has reached the destination |
|
|
|
if (Math.Abs(destinationLatitude - currentLatitude) < Tolerance && |
|
|
|
if (Math.Abs(destinationLatitude - currentLatitude) < _tolerance && |
|
|
|
Math.Abs(destinationLongitude - currentLongitude) < Tolerance) |
|
|
|
Math.Abs(destinationLongitude - currentLongitude) < _tolerance) |
|
|
|
{ |
|
|
|
{ |
|
|
|
isTrackingActive = false; |
|
|
|
var successMessage = "Safely reached the destination!"; |
|
|
|
|
|
|
|
await SendSmsNotification("9767581384", successMessage); |
|
|
|
// Notify user and send SMS |
|
|
|
//await SendEmailNotification("amreitsyanf@gmail.com", "Journey Update", successMessage); |
|
|
|
string reachedMessage = "User has safely reached the destination."; |
|
|
|
TimerLabel.Text = "Journey Complete."; |
|
|
|
await DisplayAlert("Success", "Safely reached the destination!", "OK"); |
|
|
|
|
|
|
|
await SendSmsNotification(phoneNumber, reachedMessage); |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// Wait for 1 second before re-checking |
|
|
|
|
|
|
|
|
|
|
|
// If timer expires and destination is not reached |
|
|
|
|
|
|
|
if (isTrackingActive) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
string notReachedMessage = "User did not reach the destination within the set time."; |
|
|
|
|
|
|
|
await DisplayAlert("Time's Up", "You did not reach the destination within the set timer.", "OK"); |
|
|
|
|
|
|
|
await SendSmsNotification(phoneNumber, notReachedMessage); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private async Task UpdateCountdownDisplay(DateTime timerEnd) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
while (isTrackingActive && DateTime.Now < timerEnd) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
TimeSpan remainingTime = timerEnd - DateTime.Now; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Update the UI with remaining time |
|
|
|
|
|
|
|
TimerLabel.Text = $"Time Remaining: {remainingTime.Minutes:D2}:{remainingTime.Seconds:D2}"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wait for 1 second before updating again |
|
|
|
|
|
|
|
await Task.Delay(1000); |
|
|
|
await Task.Delay(1000); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Clear the timer label after countdown ends |
|
|
|
// Timer expired, user didn't reach the destination |
|
|
|
TimerLabel.Text = isTrackingActive ? "Time's Up!" : "You reached the destination!"; |
|
|
|
var failureMessage = "Did not reach the destination on time."; |
|
|
|
|
|
|
|
await SendSmsNotification("9767581384", failureMessage); |
|
|
|
|
|
|
|
//await SendEmailNotification("amreitsyanf@gmail.com", "Journey Update", failureMessage); |
|
|
|
|
|
|
|
//await DisplayAlert("Alert", failureMessage, "OK"); |
|
|
|
|
|
|
|
TimerLabel.Text = "Time Expired."; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async void FetchLocation() |
|
|
|
private async Task SendSmsNotification(string phoneNumber, string message) |
|
|
|
{ |
|
|
|
{ |
|
|
|
try |
|
|
|
try |
|
|
|
{ |
|
|
|
{ |
|
|
|
var (latitude, longitude, address) = await GeolocationHelper.GetLocationAsync(); |
|
|
|
if (Sms.Default.IsComposeSupported) |
|
|
|
SourceLatitudeEntry.Text = latitude.ToString(); |
|
|
|
{ |
|
|
|
SourceLongitudeEntry.Text = longitude.ToString(); |
|
|
|
var smsMessage = new SmsMessage |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Body = message, |
|
|
|
|
|
|
|
Recipients = new List<string> { phoneNumber } |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await Sms.Default.ComposeAsync(smsMessage); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
await DisplayAlert("Error", "SMS is not supported on this device.", "OK"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Console.WriteLine($"Error fetching location: {ex.Message}"); |
|
|
|
await DisplayAlert("Error", $"Failed to send SMS: {ex.Message}", "OK"); |
|
|
|
await DisplayAlert("Error", $"Failed to get location: {ex.Message}", "OK"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async Task SendSmsNotification(string phoneNumber, string message) |
|
|
|
private async Task SendEmailNotification(string emailAddress, string subject, string body) |
|
|
|
{ |
|
|
|
{ |
|
|
|
try |
|
|
|
try |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (Sms.Default.IsComposeSupported) |
|
|
|
if (Email.Default.IsComposeSupported) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var smsMessage = new SmsMessage |
|
|
|
var emailMessage = new EmailMessage |
|
|
|
{ |
|
|
|
{ |
|
|
|
Body = message, |
|
|
|
Subject = subject, |
|
|
|
Recipients = new List<string> { phoneNumber } |
|
|
|
Body = body, |
|
|
|
|
|
|
|
To = new List<string> { emailAddress } |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
await Sms.Default.ComposeAsync(smsMessage); |
|
|
|
await Email.Default.ComposeAsync(emailMessage); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
|
await DisplayAlert("Error", "SMS is not supported on this device.", "OK"); |
|
|
|
await DisplayAlert("Error", "Email is not supported on this device.", "OK"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Console.WriteLine($"Error sending SMS: {ex.Message}"); |
|
|
|
await DisplayAlert("Error", $"Failed to send email: {ex.Message}", "OK"); |
|
|
|
await DisplayAlert("Error", "Failed to send SMS.", "OK"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|