using JiDangJia.Contracts;
using JiDangJia.Core;
using JiDangJia.Services;
using Microsoft.Maui.Devices.Sensors;
namespace JiDangJia.Views;
internal sealed class PostingLocationField
{
private readonly string account=AuthClient.Current.AccountId;
private readonly CommunityPost? editing;
private readonly Label label=Ui.Text("正在获取发布位置…",13,Ui.Bronze);
private readonly SemaphoreSlim gate=new(1,1);
private PublishLocation? location;
public View View{get;}
public PostingLocationField(CommunityPost? editing)
{
this.editing=editing;
var body=Ui.Stack(Ui.Section("发布位置"),label,Ui.Text("自动获取所在城市与区域,无法手动修改。",11,Ui.Muted));
if(editing?.LocationVerified==true)label.Text=editing.City+" · "+editing.PublishArea+"(原发布位置)";
else body.Add(Ui.Button("重新定位",()=>Load(),false));View=Ui.Card(body);
}
public async Task Start(){try{await Load();}catch(Exception ex){label.Text=ex.Message;}}
private async Task Load()
{
if(editing?.LocationVerified==true)return;
await gate.WaitAsync();try
{
if(location is not null&&location.RecordedAt>DateTimeOffset.UtcNow.AddMinutes(-2))return;
label.Text="正在获取发布位置…";
if(await Permissions.RequestAsync<Permissions.LocationWhenInUse>()!=PermissionStatus.Granted)throw new InvalidOperationException("请允许定位后重新获取发布位置");
using var timeout=new CancellationTokenSource(TimeSpan.FromSeconds(35));
var fix=await Geolocation.Default.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.High,TimeSpan.FromSeconds(20)),timeout.Token)??throw new InvalidOperationException("未取得位置,请到信号良好处重试");
if(fix.IsFromMockProvider)throw new InvalidOperationException("请关闭模拟位置后重新定位");
if(fix.Accuracy is not >0 or >1000||fix.Timestamp<DateTimeOffset.UtcNow.AddMinutes(-5))throw new InvalidOperationException("定位精度不足,请开启精确定位后重试");
var place=(await Geocoding.Default.GetPlacemarksAsync(fix.Latitude,fix.Longitude).WaitAsync(TimeSpan.FromSeconds(12),timeout.Token)).FirstOrDefault()??throw new InvalidOperationException("暂未识别所在城市,请稍后重新定位");
string city=place.Locality??"";
if(city.Length==0&&new[]{"北京","天津","上海","重庆"}.Any(s=>place.AdminArea?.Contains(s)==true))city=place.AdminArea!;
if(city.Length==0)throw new InvalidOperationException("暂未识别所在城市,请稍后重新定位");
if(account!=AuthClient.Current.AccountId)throw new OperationCanceledException("账户已切换");
location=new(fix.Latitude,fix.Longitude,fix.Accuracy.Value,CityCatalog.Normalize(city),place.SubLocality??"",fix.Timestamp);
label.Text=location.City+(location.Area.Length>0?" · "+location.Area:"")+"(自动定位)";
}
catch{location=null;label.Text="定位未完成,请重新定位";throw;}
finally{gate.Release();}
}
public async Task<PublishLocation?> Get()
{
await Load();return location; // Existing publications keep the location held by the server.
}
}
using JiDangJia.Contracts;
using JiDangJia.Core;
using JiDangJia.Services;
using Microsoft.Maui.Devices.Sensors;
namespace JiDangJia.Views;
internal sealed class PostingLocationField
{
private readonly string account=AuthClient.Current.AccountId;
private readonly CommunityPost? editing;
private readonly Label label=Ui.Text("正在获取发布位置…",13,Ui.Bronze);
private readonly SemaphoreSlim gate=new(1,1);
private PublishLocation? location;
public View View{get;}
public PostingLocationField(CommunityPost? editing)
{
this.editing=editing;
var body=Ui.Stack(Ui.Section("发布位置"),label,Ui.Text("自动获取所在城市与区域,无法手动修改。",11,Ui.Muted));
if(editing?.LocationVerified==true)label.Text=editing.City+" · "+editing.PublishArea+"(原发布位置)";
else body.Add(Ui.Button("重新定位",()=>Load(),false));View=Ui.Card(body);
}
public async Task Start(){try{await Load();}catch(Exception ex){label.Text=ex.Message;}}
private async Task Load()
{
if(editing?.LocationVerified==true)return;
await gate.WaitAsync();try
{
if(location is not null&&location.RecordedAt>DateTimeOffset.UtcNow.AddMinutes(-2))return;
label.Text="正在获取发布位置…";
if(await Permissions.RequestAsync<Permissions.LocationWhenInUse>()!=PermissionStatus.Granted)throw new InvalidOperationException("请允许定位后重新获取发布位置");
using var timeout=new CancellationTokenSource(TimeSpan.FromSeconds(35));
var fix=await Geolocation.Default.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.High,TimeSpan.FromSeconds(20)),timeout.Token)??throw new InvalidOperationException("未取得位置,请到信号良好处重试");
if(fix.IsFromMockProvider)throw new InvalidOperationException("请关闭模拟位置后重新定位");
if(fix.Accuracy is not >0 or >1000||fix.Timestamp<DateTimeOffset.UtcNow.AddMinutes(-5))throw new InvalidOperationException("定位精度不足,请开启精确定位后重试");
var place=(await Geocoding.Default.GetPlacemarksAsync(fix.Latitude,fix.Longitude).WaitAsync(TimeSpan.FromSeconds(12),timeout.Token)).FirstOrDefault()??throw new InvalidOperationException("暂未识别所在城市,请稍后重新定位");
string city=place.Locality??"";
if(city.Length==0&&new[]{"北京","天津","上海","重庆"}.Any(s=>place.AdminArea?.Contains(s)==true))city=place.AdminArea!;
if(city.Length==0)throw new InvalidOperationException("暂未识别所在城市,请稍后重新定位");
if(account!=AuthClient.Current.AccountId)throw new OperationCanceledException("账户已切换");
location=new(fix.Latitude,fix.Longitude,fix.Accuracy.Value,CityCatalog.Normalize(city),place.SubLocality??"",fix.Timestamp);
label.Text=location.City+(location.Area.Length>0?" · "+location.Area:"")+"(自动定位)";
}
catch{location=null;label.Text="定位未完成,请重新定位";throw;}
finally{gate.Release();}
}
public async Task<PublishLocation?> Get()
{
await Load();return location; // Existing publications keep the location held by the server.
}
}