Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
ionite34 committed Jul 25, 2023
2 parents 85bee4f + fa8ac43 commit 538e5bf
Show file tree
Hide file tree
Showing 18 changed files with 292 additions and 68 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:
with:
environment: production
ignore_missing: true
version: StabilityMatrix@${{ env.GIT_TAG_NAME }}
version: StabilityMatrix.Avalonia@${{ env.GIT_TAG_NAME }}

- name: Create Sentry release
if: ${{ github.event_name == 'workflow_dispatch' }}
Expand All @@ -97,7 +97,7 @@ jobs:
with:
environment: production
ignore_missing: true
version: StabilityMatrix@${{ github.event.inputs.version }}
version: StabilityMatrix.Avalonia@${{ github.event.inputs.version }}


release-windows:
Expand Down Expand Up @@ -143,7 +143,6 @@ jobs:
-o out -c Release -r ${{ env.platform-id }}
-p:Version=$env:RELEASE_VERSION
-p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
-p:PublishTrimmed=true
-p:SentryOrg=${{ secrets.SENTRY_ORG }} -p:SentryProject=${{ secrets.SENTRY_PROJECT }}
-p:SentryUploadSymbols=true -p:SentryUploadSources=true
Expand Down
2 changes: 1 addition & 1 deletion StabilityMatrix.Avalonia.pupnet.conf
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ DotnetProjectPath = StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
# '-p:DebugType=None -p:DebugSymbols=false -p:PublishSingleFile=true -p:PublishReadyToRun=true
# -p:PublishTrimmed=true -p:TrimMode=link'. Note. This value may use macro variables. Use 'pupnet --help macro'
# for reference. See: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish
DotnetPublishArgs = -p:Version=${APP_VERSION} --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None -p:DebugSymbols=false -p:PublishTrimmed=true
DotnetPublishArgs = -p:Version=${APP_VERSION} -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None -p:DebugSymbols=false --self-contained

# Post-publish (or standalone build) command on Linux (ignored on Windows). It is called after dotnet
# publish, but before the final output is built. This could, for example, be a script which copies
Expand Down
45 changes: 27 additions & 18 deletions StabilityMatrix.Avalonia/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
using Avalonia.Styling;
using FluentAvalonia.UI.Controls;
Expand Down Expand Up @@ -62,6 +63,7 @@ public sealed class App : Application
[NotNull] public static IServiceProvider? Services { get; private set; }
[NotNull] public static Visual? VisualRoot { get; private set; }
[NotNull] public static IStorageProvider? StorageProvider { get; private set; }
// ReSharper disable once MemberCanBePrivate.Global
[NotNull] public static IConfiguration? Config { get; private set; }

// ReSharper disable once MemberCanBePrivate.Global
Expand Down Expand Up @@ -107,6 +109,9 @@ public override void OnFrameworkInitializationCompleted()
setupWindow.ShowAsDialog = true;
setupWindow.ShowActivated = true;
setupWindow.ShowAsyncCts = new CancellationTokenSource();

setupWindow.ExtendClientAreaChromeHints = Program.Args.NoWindowChromeEffects ?
ExtendClientAreaChromeHints.NoChrome : ExtendClientAreaChromeHints.PreferSystemChrome;

DesktopLifetime.MainWindow = setupWindow;

Expand Down Expand Up @@ -141,6 +146,9 @@ private void ShowMainWindow()
var mainWindow = Services.GetRequiredService<MainWindow>();
mainWindow.DataContext = mainViewModel;
mainWindow.NotificationService = notificationService;

mainWindow.ExtendClientAreaChromeHints = Program.Args.NoWindowChromeEffects ?
ExtendClientAreaChromeHints.NoChrome : ExtendClientAreaChromeHints.PreferSystemChrome;

var settingsManager = Services.GetRequiredService<ISettingsManager>();
var windowSettings = settingsManager.Settings.WindowSettings;
Expand Down Expand Up @@ -475,31 +483,35 @@ private static void OnExit(object? sender, ControlledApplicationLifetimeExitEven

private static LoggingConfiguration ConfigureLogging()
{
var logConfig = new LoggingConfiguration();

// File target
logConfig.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal,
new FileTarget("logfile")
LogManager.Setup().LoadConfiguration(builder => {
var debugTarget = builder.ForTarget("console").WriteTo(new DebuggerTarget
{
Layout = "${message}"
}).WithAsync();
var fileTarget = builder.ForTarget("logfile").WriteTo(new FileTarget
{
Layout = "${longdate}|${level:uppercase=true}|${logger}|${message:withexception=true}",
ArchiveOldFileOnStartup = true,
FileName = "${specialfolder:folder=ApplicationData}/StabilityMatrix/app.log",
ArchiveFileName = "${specialfolder:folder=ApplicationData}/StabilityMatrix/app.{#}.log",
ArchiveNumbering = ArchiveNumberingMode.Rolling,
MaxArchiveFiles = 2
});

// Debugger Target
logConfig.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal,
new DebuggerTarget("debugger")
{
Layout = "${message}"
});
}).WithAsync();
// Filter some sources to be warn levels or above only
builder.ForLogger("System.*").WriteToNil(NLog.LogLevel.Warn);
builder.ForLogger("Microsoft.*").WriteToNil(NLog.LogLevel.Warn);
builder.ForLogger("Microsoft.Extensions.Http.*").WriteToNil(NLog.LogLevel.Warn);
builder.ForLogger().FilterMinLevel(NLog.LogLevel.Trace).WriteTo(debugTarget);
builder.ForLogger().FilterMinLevel(NLog.LogLevel.Debug).WriteTo(fileTarget);
});

// Sentry
if (SentrySdk.IsEnabled)
{
logConfig.AddSentry(o =>
LogManager.Configuration.AddSentry(o =>
{
o.InitializeSdk = false;
o.Layout = "${message}";
Expand All @@ -513,9 +525,6 @@ private static LoggingConfiguration ConfigureLogging()
});
}

LogManager.Configuration = logConfig;


return logConfig;
return LogManager.Configuration;
}
}
9 changes: 8 additions & 1 deletion StabilityMatrix.Avalonia/DesignData/DesignData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ public static void Initialize()
{
FilePath = "~/Models/Lora/electricity-light.safetensors",
Title = "Auroral Background",
PreviewImagePath = "https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/" +
"78fd2a0a-42b6-42b0-9815-81cb11bb3d05/00009-2423234823.jpeg",
ConnectedModel = new ConnectedModelInfo
{
VersionName = "Lightning Auroral",
Expand All @@ -170,7 +172,7 @@ public static void Initialize()
FilePath = "~/Models/Lora/model.safetensors",
Title = "Some model"
},
}
},
},
new(settingsManager, downloadService, modelFinder)
{
Expand All @@ -187,6 +189,11 @@ public static void Initialize()
}
};

foreach (var folder in CheckpointsPageViewModel.CheckpointFolders)
{
folder.DisplayedCheckpointFiles = folder.CheckpointFiles;
}

CheckpointBrowserViewModel.ModelCards = new
ObservableCollection<CheckpointBrowserCardViewModel>
{
Expand Down
16 changes: 14 additions & 2 deletions StabilityMatrix.Avalonia/DesignData/MockNotificationService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls.Notifications;
using StabilityMatrix.Avalonia.Services;
Expand Down Expand Up @@ -29,7 +30,18 @@ public Task<TaskResult<bool>> TryAsync(Task task, string title = "Error", string
return Task.FromResult(new TaskResult<bool>(true));
}

public void Show(string title, string message, NotificationType appearance = NotificationType.Information)
public void Show(
string title,
string message,
NotificationType appearance = NotificationType.Information,
TimeSpan? expiration = null)
{
}

public void ShowPersistent(
string title,
string message,
NotificationType appearance = NotificationType.Information)
{
}
}
70 changes: 70 additions & 0 deletions StabilityMatrix.Avalonia/FallbackRamCachedWebImageLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using AsyncImageLoader.Loaders;
using Avalonia.Media.Imaging;

namespace StabilityMatrix.Avalonia;

public readonly record struct ImageLoadFailedEventArgs(string Url, Exception Exception);

[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class FallbackRamCachedWebImageLoader : RamCachedWebImageLoader
{
private readonly WeakEventManager<ImageLoadFailedEventArgs> loadFailedEventManager = new();

public event EventHandler<ImageLoadFailedEventArgs> LoadFailed
{
add => loadFailedEventManager.AddEventHandler(value);
remove => loadFailedEventManager.RemoveEventHandler(value);
}

protected void OnLoadFailed(string url, Exception exception) => loadFailedEventManager.RaiseEvent(
this, new ImageLoadFailedEventArgs(url, exception), nameof(LoadFailed));

/// <summary>
/// Attempts to load bitmap
/// </summary>
/// <param name="url">Target url</param>
/// <returns>Bitmap</returns>
protected override async Task<Bitmap?> LoadAsync(string url)
{
// Try to load from local file first
if (File.Exists(url))
{
try
{
return new Bitmap(url);
}
catch (Exception e)
{
OnLoadFailed(url, e);
return null;
}
}

var internalOrCachedBitmap =
await LoadFromInternalAsync(url).ConfigureAwait(false)
?? await LoadFromGlobalCache(url).ConfigureAwait(false);

if (internalOrCachedBitmap != null) return internalOrCachedBitmap;

try
{
var externalBytes = await LoadDataFromExternalAsync(url).ConfigureAwait(false);
if (externalBytes == null) return null;

using var memoryStream = new MemoryStream(externalBytes);
var bitmap = new Bitmap(memoryStream);
await SaveToGlobalCache(url, externalBytes).ConfigureAwait(false);
return bitmap;
}
catch (Exception)
{
return null;
}
}

}
28 changes: 28 additions & 0 deletions StabilityMatrix.Avalonia/Models/AppArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace StabilityMatrix.Avalonia.Models;

/// <summary>
/// Command line arguments passed to the application.
/// </summary>
public class AppArgs
{
/// <summary>
/// Whether to use the exception dialog while debugger is attached.
/// When no debugger is attached, the exception dialog is always used.
/// </summary>
public bool DebugExceptionDialog { get; set; }

/// <summary>
/// Whether to use Sentry when a debugger is attached.
/// </summary>
public bool DebugSentry { get; set; }

/// <summary>
/// Whether to disable Sentry.
/// </summary>
public bool NoSentry { get; set; }

/// <summary>
/// Whether to disable window chrome effects
/// </summary>
public bool NoWindowChromeEffects { get; set; }
}
24 changes: 20 additions & 4 deletions StabilityMatrix.Avalonia/Program.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using AsyncImageLoader;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
Expand All @@ -16,6 +18,7 @@
using Projektanker.Icons.Avalonia.FontAwesome;
using Semver;
using Sentry;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Helper;
Expand All @@ -27,29 +30,33 @@ namespace StabilityMatrix.Avalonia;
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class Program
{
private static bool isExceptionDialogEnabled;
public static AppArgs Args { get; } = new();

// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args)
{
Args.DebugExceptionDialog = args.Contains("--debug-exception-dialog");
Args.DebugSentry = args.Contains("--debug-sentry");
Args.NoSentry = args.Contains("--no-sentry");
Args.NoWindowChromeEffects = args.Contains("--no-window-chrome-effects");

HandleUpdateReplacement();

var infoVersion = Assembly.GetExecutingAssembly()
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
Compat.AppVersion = SemVersion.Parse(infoVersion ?? "0.0.0", SemVersionStyles.Strict);

// Configure exception dialog for unhandled exceptions
if (!Debugger.IsAttached || args.Contains("--debug-exception-dialog"))
if (!Debugger.IsAttached || Args.DebugExceptionDialog)
{
isExceptionDialogEnabled = true;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}

// Configure Sentry
if ((Debugger.IsAttached && args.Contains("--debug-sentry")) || !args.Contains("--no-sentry"))
if (!Args.NoSentry && (!Debugger.IsAttached || Args.DebugSentry))
{
ConfigureSentry();
}
Expand All @@ -61,6 +68,9 @@ public static void Main(string[] args)
public static AppBuilder BuildAvaloniaApp()
{
IconProvider.Current.Register<FontAwesomeIconProvider>();
// Use our custom image loader for custom local load error handling
ImageLoader.AsyncImageLoader.Dispose();
ImageLoader.AsyncImageLoader = new FallbackRamCachedWebImageLoader();

return AppBuilder.Configure<App>()
.UsePlatformDetect()
Expand Down Expand Up @@ -89,6 +99,12 @@ private static void HandleUpdateReplacement()
{
currentExe.CopyTo(targetExe, true);

// Ensure permissions are set for unix
if (Compat.IsUnix)
{
File.SetUnixFileMode(targetExe, (UnixFileMode) 0x755);
}

// Start the new app
Process.Start(targetExe);

Expand Down
Loading

0 comments on commit 538e5bf

Please sign in to comment.