Skip to content

Commit 6a4e86d

Browse files
committed
Added Locate IP page (#673)
1 parent 8ac9136 commit 6a4e86d

File tree

3 files changed

+428
-2
lines changed

3 files changed

+428
-2
lines changed

InternetTest/InternetTest/Models/Ip.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2424
using System.Net.Http;
2525
using System.Text.Json;
2626
using System.Text.Json.Serialization;
27+
using System.Text.RegularExpressions;
2728

2829
namespace InternetTest.Models;
2930
public class Ip
@@ -40,6 +41,9 @@ public class Ip
4041
[JsonPropertyName("countryCode")]
4142
public string? CountryCode { get; set; }
4243

44+
[JsonPropertyName("district")]
45+
public string? District { get; set; }
46+
4347
[JsonPropertyName("region")]
4448
public string? Region { get; set; }
4549

@@ -70,6 +74,15 @@ public class Ip
7074
[JsonPropertyName("as")]
7175
public string? As { get; set; }
7276

77+
[JsonPropertyName("mobile")]
78+
public bool? Mobile { get; set; }
79+
80+
[JsonPropertyName("proxy")]
81+
public bool? Proxy { get; set; }
82+
83+
[JsonPropertyName("hosting")]
84+
public bool? Hosting { get; set; }
85+
7386
public override string ToString() => $"{Properties.Resources.Country}: {Country}\n" +
7487
$"{Properties.Resources.Region}: {RegionName}\n" +
7588
$"{Properties.Resources.City}: {City}\n" +
@@ -92,4 +105,27 @@ public static async Task<Ip> GetIp(string ip)
92105
return new();
93106
}
94107
}
108+
109+
public static bool IsValid(string ip)
110+
{
111+
if (ip == "") return true; // This is valid, it will return the user's current IP
112+
113+
if (IsUrlValid(ip)) return true; // This is valid, it is possible to get IP info from a URL
114+
115+
// Initialize a regex that checks if an IP is valid
116+
Regex ipRegex = new(@"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
117+
118+
// Check if the IP is valid
119+
return ipRegex.IsMatch(ip);
120+
}
121+
122+
private static bool IsUrlValid(string url)
123+
{
124+
if (!url.StartsWith("http://") || !url.StartsWith("https://"))
125+
{
126+
url = "https://" + url;
127+
}
128+
return Uri.TryCreate(url, UriKind.Absolute, out Uri? uriResult)
129+
&& (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
130+
}
95131
}

InternetTest/InternetTest/ViewModels/LocateIpPageViewModel.cs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,127 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2121
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
SOFTWARE.
2323
*/
24+
using InternetTest.Commands;
25+
using InternetTest.Enums;
2426
using InternetTest.Models;
27+
using InternetTest.ViewModels.Components;
28+
using Microsoft.Win32;
29+
using System.Collections.ObjectModel;
30+
using System.Diagnostics;
31+
using System.IO;
32+
using System.Windows;
33+
using System.Windows.Input;
2534

2635
namespace InternetTest.ViewModels;
2736
public class LocateIpPageViewModel : ViewModelBase
2837
{
2938
private readonly Settings _settings;
3039

40+
private ObservableCollection<GridItemViewModel> _details = [];
41+
public ObservableCollection<GridItemViewModel> Details { get => _details; set { _details = value; OnPropertyChanged(nameof(Details)); } }
42+
43+
private ObservableCollection<GridItemViewModel> _ispInfo = [];
44+
public ObservableCollection<GridItemViewModel> IspInfo { get => _ispInfo; set { _ispInfo = value; OnPropertyChanged(nameof(IspInfo)); } }
45+
46+
private string? _ipAddress;
47+
public string? IpAddress { get => _ipAddress; set { _ipAddress = value; OnPropertyChanged(nameof(IpAddress)); } }
48+
49+
private bool _empty = true;
50+
public bool Empty { get => _empty; set { _empty = value; OnPropertyChanged(nameof(Empty)); } }
51+
52+
private Ip? _ip;
53+
54+
public ICommand LocateIpCommand => new RelayCommand(async o => await GetIp());
55+
public ICommand MyIpCommand => new RelayCommand(async o => { IpAddress = ""; await GetIp(); });
56+
public ICommand ShowMapCommand => new RelayCommand(o =>
57+
{
58+
if (_ip is null) return;
59+
double lat = _ip.Lat;
60+
double lon = _ip.Lon;
61+
62+
Process.Start("explorer.exe", _settings.MapProvider switch
63+
{
64+
MapProvider.OpenStreetMap => $"\"https://www.openstreetmap.org/directions?engine=graphhopper_foot&route={lat}%2C{lon}%3B{lat}%2C{lon}#map={_settings.MapZoomLevel}/{lat}/{lon}\"",
65+
MapProvider.Google => $"\"https://www.google.com/maps/place/{GetGoogleMapsPoint(lat, lon)}\"",
66+
MapProvider.Microsoft => $"\"https://www.bing.com/maps?q={lat} {lon}&lvl={_settings.MapZoomLevel}&cp={lat}~{lon}\"",
67+
MapProvider.Here => $"\"https://wego.here.com/directions/mix/{lat},{lon}/?map={lat},{lon},{_settings.MapZoomLevel}\"",
68+
MapProvider.Yandex => $"\"https://yandex.com/maps/?ll={lon}%2C{lat}&z={_settings.MapZoomLevel}\"",
69+
_ => $"\"https://www.openstreetmap.org/directions?engine=graphhopper_foot&route={lat}%2C{lon}%3B{lat}%2C{lon}#map={_settings.MapZoomLevel}/{lat}/{lon}\""
70+
});
71+
});
72+
public ICommand ResetCommand => new RelayCommand(o => { IpAddress = ""; Empty = true; });
73+
public ICommand SaveCommand => new RelayCommand(o =>
74+
{
75+
if (_ip is null) return;
76+
SaveFileDialog dialog = new()
77+
{
78+
Title = Properties.Resources.Save,
79+
Filter = Properties.Resources.TxtFiles + " (*.txt)|*.txt",
80+
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
81+
FileName = _ip.Query + ".txt",
82+
DefaultExt = ".txt"
83+
};
84+
85+
if (dialog.ShowDialog() ?? false)
86+
{
87+
File.WriteAllText(dialog.FileName, _ip?.ToString());
88+
}
89+
});
90+
3191
public LocateIpPageViewModel(Settings settings)
3292
{
3393
_settings = settings;
3494
}
95+
96+
private async Task GetIp()
97+
{
98+
if (!Ip.IsValid(IpAddress ?? ""))
99+
{
100+
MessageBox.Show(Properties.Resources.InvalidURLMsg);
101+
return;
102+
}
103+
104+
_ip = await Ip.GetIp(IpAddress ?? "");
105+
106+
IpAddress = _ip.Query ?? Properties.Resources.Unknown;
107+
108+
Details = [
109+
new(Properties.Resources.Country, _ip.Country ?? Properties.Resources.Unknown, 0, 0),
110+
new(Properties.Resources.Region, _ip.RegionName ?? Properties.Resources.Unknown, 1, 0),
111+
new(Properties.Resources.ZIPCode, _ip.Zip ?? Properties.Resources.Unknown, 2, 0),
112+
new(Properties.Resources.Latitude, _ip.Lat.ToString(), 3, 0),
113+
new(Properties.Resources.City, _ip.City ?? Properties.Resources.Unknown, 0, 1),
114+
new(Properties.Resources.District, _ip.District ?? Properties.Resources.Unknown, 1, 1),
115+
new(Properties.Resources.Status, _ip.Status == "success" ? Properties.Resources.Successful : Properties.Resources.Failed, 2, 1),
116+
new(Properties.Resources.Longitude, _ip.Lon.ToString(), 3, 1),
117+
];
118+
119+
IspInfo = [
120+
new (Properties.Resources.ISP, _ip.Isp ?? Properties.Resources.Unknown, 0, 0),
121+
new (Properties.Resources.AsNumber, _ip.As ?? Properties.Resources.Unknown, 1, 0),
122+
new (Properties.Resources.Mobile, (_ip.Mobile ?? false ) ? Properties.Resources.Yes : Properties.Resources.No, 2, 0),
123+
new (Properties.Resources.Organization, _ip.Org ?? Properties.Resources.Unknown, 0, 1),
124+
new (Properties.Resources.Timezone, _ip.Timezone ?? Properties.Resources.Unknown, 1, 1),
125+
new (Properties.Resources.Proxy, (_ip.Proxy ?? false) ? Properties.Resources.Yes : Properties.Resources.No, 2, 1),
126+
];
127+
128+
Empty = false;
129+
}
130+
131+
private static string GetGoogleMapsPoint(double lat, double lon)
132+
{
133+
int deg = (int)lat; // Get integer
134+
int deg2 = (int)lon; // Get integer
135+
136+
double d = (lat - deg) * 60d;
137+
double d2 = (lon - deg2) * 60d;
138+
139+
string fDir = lat >= 0 ? "N" : "S"; // Get if the location is in the North or South
140+
string sDir = lon >= 0 ? "E" : "W"; // Get if the location is in the East or West
141+
142+
string sD = d.ToString().Replace(",", "."); // Ensure to use . instead of ,
143+
string sD2 = d2.ToString().Replace(",", "."); // Ensure to use . instead of ,
144+
145+
return $"{deg}° {sD}' {fDir}, {deg2}° {sD2}' {sDir}".Replace("-", "");
146+
}
35147
}

0 commit comments

Comments
 (0)