@ -0,0 +1,42 @@ |
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" |
||||
x:Class="Justice.Views.MapTimer" |
||||
Title="Track Journey"> |
||||
<VerticalStackLayout Padding="20" Spacing="15"> |
||||
<!-- Page Title --> |
||||
<Label Text="Track Your Journey" FontSize="Large" HorizontalOptions="Center" FontAttributes="Bold" /> |
||||
|
||||
<!-- Current Location --> |
||||
<Label Text="Current Location (Latitude, Longitude):" FontSize="Medium" /> |
||||
<Entry x:Name="SourceLatitudeEntry" IsReadOnly="True" Placeholder="Latitude" /> |
||||
<Entry x:Name="SourceLongitudeEntry" IsReadOnly="True" Placeholder="Longitude" /> |
||||
<Entry x:Name="SourceAddressEntry" IsReadOnly="True" Placeholder="Address" /> |
||||
|
||||
<!-- Destination Location --> |
||||
<Label Text="Destination Location (Latitude, Longitude):" FontSize="Medium" /> |
||||
<Entry x:Name="DestinationLatitudeEntry" Placeholder="Enter Destination Latitude" /> |
||||
<Entry x:Name="DestinationLongitudeEntry" Placeholder="Enter Destination Longitude" /> |
||||
|
||||
<!-- Timer --> |
||||
<Label Text="Set Timer (minutes):" FontSize="Medium" /> |
||||
<Entry x:Name="TimerEntry" Keyboard="Numeric" Placeholder="Enter timer in minutes" /> |
||||
|
||||
<!-- Countdown Display --> |
||||
<Label x:Name="TimerLabel" |
||||
Text="Set your timer and start tracking." |
||||
FontSize="Medium" |
||||
HorizontalOptions="Center" |
||||
VerticalOptions="CenterAndExpand" |
||||
TextColor="DarkGray" /> |
||||
|
||||
<!-- Start Button --> |
||||
<Button Text="Start Tracking" Clicked="StartTrackingClicked" /> |
||||
|
||||
<!-- Activity Indicator --> |
||||
<ActivityIndicator x:Name="LoadingIndicator" |
||||
IsRunning="False" |
||||
IsVisible="False" |
||||
HorizontalOptions="Center" |
||||
VerticalOptions="Center" /> |
||||
</VerticalStackLayout> |
||||
</ContentPage> |
@ -0,0 +1,142 @@ |
||||
using Justice.Helpers; |
||||
using Microsoft.Maui.ApplicationModel.Communication; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Justice.Views |
||||
{ |
||||
public partial class MapTimer : ContentPage |
||||
{ |
||||
private bool isTrackingActive; |
||||
|
||||
public MapTimer() |
||||
{ |
||||
InitializeComponent(); |
||||
FetchLocation(); |
||||
} |
||||
|
||||
private async void StartTrackingClicked(object sender, EventArgs e) |
||||
{ |
||||
if (string.IsNullOrWhiteSpace(DestinationLatitudeEntry.Text) || |
||||
string.IsNullOrWhiteSpace(DestinationLongitudeEntry.Text)) |
||||
{ |
||||
await DisplayAlert("Error", "Please enter destination coordinates.", "OK"); |
||||
return; |
||||
} |
||||
|
||||
if (!double.TryParse(DestinationLatitudeEntry.Text, out double destinationLatitude) || |
||||
!double.TryParse(DestinationLongitudeEntry.Text, out double destinationLongitude)) |
||||
{ |
||||
await DisplayAlert("Error", "Invalid destination coordinates.", "OK"); |
||||
return; |
||||
} |
||||
|
||||
if (!int.TryParse(TimerEntry.Text, out int timerMinutes)) |
||||
{ |
||||
await DisplayAlert("Error", "Invalid timer value. Please enter a numeric value.", "OK"); |
||||
return; |
||||
} |
||||
|
||||
isTrackingActive = true; |
||||
|
||||
// Set timer duration |
||||
var timerDuration = TimeSpan.FromMinutes(timerMinutes); |
||||
var timerEnd = DateTime.Now.Add(timerDuration); |
||||
string phoneNumber = "9860104625"; |
||||
|
||||
// Start countdown display |
||||
_ = UpdateCountdownDisplay(timerEnd); |
||||
|
||||
while (isTrackingActive && DateTime.Now < timerEnd) |
||||
{ |
||||
await Task.Delay(5000); // Check location every 5 seconds |
||||
|
||||
// Fetch current location |
||||
var (currentLatitude, currentLongitude, _) = await GeolocationHelper.GetLocationAsync(); |
||||
|
||||
// Define tolerance for proximity |
||||
const double Tolerance = 0.0001; |
||||
|
||||
// Check if user has reached the destination |
||||
if (Math.Abs(destinationLatitude - currentLatitude) < Tolerance && |
||||
Math.Abs(destinationLongitude - currentLongitude) < Tolerance) |
||||
{ |
||||
isTrackingActive = false; |
||||
|
||||
// Notify user and send SMS |
||||
string reachedMessage = "User has safely reached the destination."; |
||||
await DisplayAlert("Success", "Safely reached the destination!", "OK"); |
||||
await SendSmsNotification(phoneNumber, reachedMessage); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
// 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); |
||||
} |
||||
|
||||
// Clear the timer label after countdown ends |
||||
TimerLabel.Text = isTrackingActive ? "Time's Up!" : "You reached the destination!"; |
||||
} |
||||
|
||||
private async void FetchLocation() |
||||
{ |
||||
try |
||||
{ |
||||
var (latitude, longitude, address) = await GeolocationHelper.GetLocationAsync(); |
||||
SourceLatitudeEntry.Text = latitude.ToString(); |
||||
SourceLongitudeEntry.Text = longitude.ToString(); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
Console.WriteLine($"Error fetching location: {ex.Message}"); |
||||
await DisplayAlert("Error", $"Failed to get location: {ex.Message}", "OK"); |
||||
} |
||||
} |
||||
|
||||
private async Task SendSmsNotification(string phoneNumber, string message) |
||||
{ |
||||
try |
||||
{ |
||||
if (Sms.Default.IsComposeSupported) |
||||
{ |
||||
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) |
||||
{ |
||||
Console.WriteLine($"Error sending SMS: {ex.Message}"); |
||||
await DisplayAlert("Error", "Failed to send SMS.", "OK"); |
||||
} |
||||
} |
||||
} |
||||
} |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 114 KiB |
Before Width: | Height: | Size: 301 KiB After Width: | Height: | Size: 477 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 186 KiB |
After Width: | Height: | Size: 427 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 21 KiB |