mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 13:28:33 +00:00
Workshop - Added button to copy share link to profile detail page
This commit is contained in:
parent
1b0796c68b
commit
279761abd3
150
src/Artemis.Core/Utilities/StringUtilities.cs
Normal file
150
src/Artemis.Core/Utilities/StringUtilities.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Artemis.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Provides some random string utilities.
|
||||
/// </summary>
|
||||
public static class StringUtilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Produces optional, URL-friendly version of a title, "like-this-one".
|
||||
/// hand-tuned for speed, reflects performance refactoring contributed
|
||||
/// by John Gietzen (user otac0n)
|
||||
/// </summary>
|
||||
/// <remarks>Source: https://stackoverflow.com/a/25486</remarks>
|
||||
public static string UrlFriendly(string? title)
|
||||
{
|
||||
if (title == null) return "";
|
||||
|
||||
const int maxlen = 80;
|
||||
int len = title.Length;
|
||||
bool prevdash = false;
|
||||
StringBuilder sb = new(len);
|
||||
char c;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
c = title[i];
|
||||
if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
|
||||
{
|
||||
sb.Append(c);
|
||||
prevdash = false;
|
||||
}
|
||||
else if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
// tricky way to convert to lowercase
|
||||
sb.Append((char) (c | 32));
|
||||
prevdash = false;
|
||||
}
|
||||
else if (c == ' ' || c == ',' || c == '.' || c == '/' ||
|
||||
c == '\\' || c == '-' || c == '_' || c == '=')
|
||||
{
|
||||
if (!prevdash && sb.Length > 0)
|
||||
{
|
||||
sb.Append('-');
|
||||
prevdash = true;
|
||||
}
|
||||
}
|
||||
else if (c >= 128)
|
||||
{
|
||||
int prevlen = sb.Length;
|
||||
sb.Append(RemapInternationalCharToAscii(c));
|
||||
if (prevlen != sb.Length) prevdash = false;
|
||||
}
|
||||
|
||||
if (i == maxlen) break;
|
||||
}
|
||||
|
||||
if (prevdash)
|
||||
return sb.ToString().Substring(0, sb.Length - 1);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remaps internation characters to their ASCII equivalent.
|
||||
/// <remarks>Source: https://meta.stackexchange.com/a/7696</remarks>
|
||||
/// </summary>
|
||||
/// <param name="c">The character to remap</param>
|
||||
/// <returns>The ASCII equivalent.</returns>
|
||||
public static string RemapInternationalCharToAscii(char c)
|
||||
{
|
||||
string s = c.ToString().ToLowerInvariant();
|
||||
if ("àåáâäãåą".Contains(s))
|
||||
{
|
||||
return "a";
|
||||
}
|
||||
else if ("èéêëę".Contains(s))
|
||||
{
|
||||
return "e";
|
||||
}
|
||||
else if ("ìíîïı".Contains(s))
|
||||
{
|
||||
return "i";
|
||||
}
|
||||
else if ("òóôõöøőð".Contains(s))
|
||||
{
|
||||
return "o";
|
||||
}
|
||||
else if ("ùúûüŭů".Contains(s))
|
||||
{
|
||||
return "u";
|
||||
}
|
||||
else if ("çćčĉ".Contains(s))
|
||||
{
|
||||
return "c";
|
||||
}
|
||||
else if ("żźž".Contains(s))
|
||||
{
|
||||
return "z";
|
||||
}
|
||||
else if ("śşšŝ".Contains(s))
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
else if ("ñń".Contains(s))
|
||||
{
|
||||
return "n";
|
||||
}
|
||||
else if ("ýÿ".Contains(s))
|
||||
{
|
||||
return "y";
|
||||
}
|
||||
else if ("ğĝ".Contains(s))
|
||||
{
|
||||
return "g";
|
||||
}
|
||||
else if (c == 'ř')
|
||||
{
|
||||
return "r";
|
||||
}
|
||||
else if (c == 'ł')
|
||||
{
|
||||
return "l";
|
||||
}
|
||||
else if (c == 'đ')
|
||||
{
|
||||
return "d";
|
||||
}
|
||||
else if (c == 'ß')
|
||||
{
|
||||
return "ss";
|
||||
}
|
||||
else if (c == 'Þ')
|
||||
{
|
||||
return "th";
|
||||
}
|
||||
else if (c == 'ĥ')
|
||||
{
|
||||
return "h";
|
||||
}
|
||||
else if (c == 'ĵ')
|
||||
{
|
||||
return "j";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,14 +22,24 @@
|
||||
<StackPanel Grid.Row="1" Grid.Column="0" Margin="0 0 10 0" Spacing="10">
|
||||
<Border Classes="card" VerticalAlignment="Top">
|
||||
<StackPanel>
|
||||
<Border CornerRadius="6"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0 0 10 0"
|
||||
Width="80"
|
||||
Height="80"
|
||||
ClipToBounds="True">
|
||||
<Image Stretch="UniformToFill" il:ImageLoader.Source="{CompiledBinding Entry.Id, Converter={StaticResource EntryIconUriConverter}, Mode=OneWay}" />
|
||||
</Border>
|
||||
<Panel>
|
||||
<Border CornerRadius="6"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0 0 10 0"
|
||||
Width="80"
|
||||
Height="80"
|
||||
ClipToBounds="True">
|
||||
<Image Stretch="UniformToFill" il:ImageLoader.Source="{CompiledBinding Entry.Id, Converter={StaticResource EntryIconUriConverter}, Mode=OneWay}" />
|
||||
</Border>
|
||||
<Button Classes="icon-button"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{CompiledBinding CopyShareLink}"
|
||||
ToolTip.Tip="Copy share link">
|
||||
<avalonia:MaterialIcon Kind="ShareVariant"/>
|
||||
</Button>
|
||||
</Panel>
|
||||
|
||||
|
||||
<TextBlock Theme="{StaticResource TitleTextBlockStyle}"
|
||||
MaxLines="3"
|
||||
|
||||
@ -3,6 +3,7 @@ using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Screens.Workshop.Parameters;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
using Artemis.UI.Shared.Services;
|
||||
@ -21,8 +22,8 @@ public class ProfileDetailsViewModel : RoutableScreen<WorkshopDetailParameters>
|
||||
private readonly IWorkshopClient _client;
|
||||
private readonly ProfileEntryInstallationHandler _installationHandler;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly IWindowService _windowService;
|
||||
private readonly ObservableAsPropertyHelper<DateTimeOffset?> _updatedAt;
|
||||
private readonly IWindowService _windowService;
|
||||
private IGetEntryById_Entry? _entry;
|
||||
|
||||
public ProfileDetailsViewModel(IWorkshopClient client, ProfileEntryInstallationHandler installationHandler, INotificationService notificationService, IWindowService windowService)
|
||||
@ -34,8 +35,11 @@ public class ProfileDetailsViewModel : RoutableScreen<WorkshopDetailParameters>
|
||||
_updatedAt = this.WhenAnyValue(vm => vm.Entry).Select(e => e?.LatestRelease?.CreatedAt ?? e?.CreatedAt).ToProperty(this, vm => vm.UpdatedAt);
|
||||
|
||||
DownloadLatestRelease = ReactiveCommand.CreateFromTask(ExecuteDownloadLatestRelease);
|
||||
CopyShareLink = ReactiveCommand.CreateFromTask(ExecuteCopyShareLink);
|
||||
}
|
||||
|
||||
public ReactiveCommand<Unit, Unit> CopyShareLink { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DownloadLatestRelease { get; }
|
||||
|
||||
public DateTimeOffset? UpdatedAt => _updatedAt.Value;
|
||||
@ -75,4 +79,13 @@ public class ProfileDetailsViewModel : RoutableScreen<WorkshopDetailParameters>
|
||||
else
|
||||
_notificationService.CreateNotification().WithTitle("Failed to install profile").WithMessage(result.Message).WithSeverity(NotificationSeverity.Error).Show();
|
||||
}
|
||||
|
||||
private async Task ExecuteCopyShareLink(CancellationToken arg)
|
||||
{
|
||||
if (Entry == null)
|
||||
return;
|
||||
|
||||
await Shared.UI.Clipboard.SetTextAsync($"{WorkshopConstants.WORKSHOP_URL}/entries/{Entry.Id}/{StringUtilities.UrlFriendly(Entry.Name)}");
|
||||
_notificationService.CreateNotification().WithTitle("Copied share link to clipboard.").Show();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user