Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions OneGateApp/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ internal bool ProcessAppLinkUri(Uri uri)
{
try
{
if (!string.Equals(uri.Host, SharedOptions.OneGateDomain, StringComparison.OrdinalIgnoreCase))
return null;
return uri.Segments[1] switch
{
"app/" => new LaunchDAppAction(uri),
Expand Down
25 changes: 20 additions & 5 deletions OneGateApp/Controls/Handlers/DAppSearchHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ namespace NeoOrder.OneGate.Controls.Handlers;
partial class DAppSearchHandler : SearchHandler
{
public readonly static BindableProperty DAppsProperty = BindableProperty.Create(nameof(DApps), typeof(IList<DApp>), typeof(DAppSearchHandler));
Uri? launchUri;
int? launchAppId;

public IList<DApp>? DApps
{
Expand All @@ -16,21 +18,27 @@ public IList<DApp>? DApps

protected override void OnQueryChanged(string oldValue, string newValue)
{
ItemsSource = Search(newValue, DApps)?.ToArray();
ItemsSource = Search(newValue, DApps, out launchUri, out launchAppId)?.ToArray();
#if IOS
if (string.IsNullOrEmpty(newValue)) HideSoftInputAsync();
#endif
}

static IEnumerable<DApp>? Search(string? keyword, IEnumerable<DApp>? dapps)
static IEnumerable<DApp>? Search(string? keyword, IEnumerable<DApp>? dapps, out Uri? launchUri, out int? launchAppId)
{
launchUri = null;
launchAppId = null;
if (string.IsNullOrWhiteSpace(keyword)) return null;
if (dapps is null) return null;
if (Uri.TryCreate(keyword, UriKind.Absolute, out var uri))
{
if (uri.Scheme != "https") return null;
if (uri.Authority == SharedOptions.OneGateDomain && uri.Segments.Length == 3 && uri.Segments[1] == "app/" && int.TryParse(uri.Segments[2], out int id))
if (DAppLaunchUri.TryGetAppId(uri, out int id))
{
launchUri = uri;
launchAppId = id;
return dapps.Where(p => p.Id == id);
}
else
return dapps.Where(p => p.Url == keyword);
}
Expand All @@ -42,13 +50,20 @@ protected override void OnQueryChanged(string oldValue, string newValue)

protected override void OnItemSelected(object item)
{
Commands.LaunchDApp.Execute(item);
Commands.LaunchDApp.Execute(GetLaunchParameter(item));
}

protected override void OnQueryConfirmed()
{
DApp[]? results = ItemsSource?.Cast<DApp>().ToArray();
if (results?.Length == 1)
Commands.LaunchDApp.Execute(results[0]);
Commands.LaunchDApp.Execute(GetLaunchParameter(results[0]));
}

object GetLaunchParameter(object item)
{
if (item is DApp dapp && launchUri is not null && launchAppId == dapp.Id)
return launchUri;
return item;
}
}
14 changes: 12 additions & 2 deletions OneGateApp/Models/AppLinks/LaunchDAppAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@

namespace NeoOrder.OneGate.Models.AppLinks;

class LaunchDAppAction(Uri uri) : AppLinkAction
class LaunchDAppAction : AppLinkAction
{
readonly Uri uri;

public LaunchDAppAction(Uri uri)
{
if (!DAppLaunchUri.TryGetAppId(uri, out int appId))
throw new ArgumentException("Invalid dApp URI.", nameof(uri));
this.uri = uri;
AppId = appId;
}

protected override string Route => "//dapps/launch";
public int AppId { get; } = int.Parse(uri.Segments[2]);
public int AppId { get; }

protected override Page CreatePage(IServiceProvider serviceProvider)
{
Expand Down
2 changes: 1 addition & 1 deletion OneGateApp/Pages/Commands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ await Microsoft.Maui.ApplicationModel.DataTransfer.Share.RequestAsync(new ShareT
intent.SetAction(Android.Content.Intent.ActionView);
intent.SetData(Android.Net.Uri.Parse(canonicalUri));
intent.AddFlags(Android.Content.ActivityFlags.NewDocument);
if (!string.IsNullOrEmpty(uri.Query))
if (DAppLaunchUri.HasLaunchParameters(uri))
intent.PutExtra("org.neoorder.onegate.ORIGINAL_URI", uri.AbsoluteUri);
activity.StartActivity(intent);
#else
Expand Down
5 changes: 1 addition & 4 deletions OneGateApp/Pages/LaunchDAppPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,7 @@ public async void ApplyQueryAttributes(IDictionary<string, object> query)
return;
}
DApp = (await response.Content.ReadFromJsonAsync<DApp>())!;
if (string.IsNullOrEmpty(uri.Query))
Url = DApp.Url;
else
Url = DApp.Url + uri.Query;
Url = DAppLaunchUri.ApplyLaunchParameters(DApp.Url, uri);
}
List<int>? favorites = await dbContext.Settings.GetAsync<List<int>>("dapps/favorite");
IsFavorite = favorites?.Contains(DApp.Id) ?? false;
Expand Down
5 changes: 1 addition & 4 deletions OneGateApp/Pages/ScanPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,7 @@ async Task<bool> ProcessHttpsSchemeAsync(Uri uri)

async Task<bool> ProcessDappUriAsync(Uri uri)
{
if (uri.Segments.Length != 3) return false;
if (uri.Segments[1] != "app/") return false;
if (!int.TryParse(uri.Segments[2], out int appId)) return false;
if (appId <= 0) return false;
if (!DAppLaunchUri.TryGetAppId(uri, out _)) return false;
if (action is null)
{
await Shell.Current.GoToAsync("..");
Expand Down
38 changes: 38 additions & 0 deletions OneGateApp/Services/DAppLaunchUri.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace NeoOrder.OneGate.Services;

static class DAppLaunchUri
{
public static bool TryGetAppId(Uri uri, out int appId)
{
appId = 0;
if (!uri.IsAbsoluteUri) return false;
if (!string.Equals(uri.Scheme, "https", StringComparison.OrdinalIgnoreCase)) return false;
if (!string.Equals(uri.Host, SharedOptions.OneGateDomain, StringComparison.OrdinalIgnoreCase)) return false;
if (uri.Segments.Length != 3) return false;
if (!string.Equals(uri.Segments[1], "app/", StringComparison.Ordinal)) return false;
return int.TryParse(uri.Segments[2], out appId) && appId > 0;
}

public static bool HasLaunchParameters(Uri uri)
{
return !string.IsNullOrEmpty(uri.Query) || !string.IsNullOrEmpty(uri.Fragment);
}

public static string ApplyLaunchParameters(string dappUrl, Uri launchUri)
{
if (!HasLaunchParameters(launchUri)) return dappUrl;

UriBuilder builder = new(dappUrl);
if (!string.IsNullOrEmpty(launchUri.Query))
{
string baseQuery = builder.Query.TrimStart('?');
string launchQuery = launchUri.Query.TrimStart('?');
builder.Query = string.IsNullOrEmpty(baseQuery)
? launchQuery
: $"{baseQuery}&{launchQuery}";
}
if (!string.IsNullOrEmpty(launchUri.Fragment))
builder.Fragment = launchUri.Fragment.TrimStart('#');
return builder.Uri.AbsoluteUri;
}
}