Update workflows

This commit is contained in:
MBucari 2023-02-27 16:38:18 -07:00 committed by Mbucari
parent 80ea394934
commit 429aa603f5
27 changed files with 159 additions and 156 deletions

View File

@ -23,10 +23,10 @@ env:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [Linux, MacOS] os: [ubuntu-latest, macos-latest]
arch: [x64, arm64] arch: [x64, arm64]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -45,62 +45,63 @@ jobs:
then then
version="${inputVersion}" version="${inputVersion}"
else else
version="$(grep -oP '(?<=<Version>).*(?=</Version)' ./Source/AppScaffolding/AppScaffolding.csproj)" version="$(grep -Eio -m 1 '<Version>.*</Version>' ./Source/AppScaffolding/AppScaffolding.csproj | sed -r 's/<\/?Version>//g')"
fi fi
echo "version=${version}" >> "${GITHUB_OUTPUT}" echo "version=${version}" >> "${GITHUB_OUTPUT}"
- name: Unit test - name: Unit test
if: ${{ inputs.run_unit_tests }} if: ${{ inputs.run_unit_tests }}
working-directory: ./Source working-directory: ./Source
run: dotnet test run: dotnet test
- name: Publish - name: Publish
id: publish
working-directory: ./Source working-directory: ./Source
run: | run: |
os=${{ matrix.os }} os=${{ matrix.os }}
RUNTIME_IDENTIFIER="$(echo ${os,} | sed 's/macOS/osx/')-${{ matrix.arch }}" target_os="$(echo ${os/-latest/} | sed 's/ubuntu/linux/')"
display_os="$(echo ${target_os/macos/macOS} | sed 's/linux/Linux/')"
echo "display_os=${display_os}" >> $GITHUB_OUTPUT
RUNTIME_IDENTIFIER="$(echo ${target_os/macos/osx})-${{ matrix.arch }}"
echo "$RUNTIME_IDENTIFIER" echo "$RUNTIME_IDENTIFIER"
dotnet publish \ dotnet publish \
LibationAvalonia/LibationAvalonia.csproj \ LibationAvalonia/LibationAvalonia.csproj \
--runtime "$RUNTIME_IDENTIFIER" \ --runtime "$RUNTIME_IDENTIFIER" \
--configuration ${{ env.DOTNET_CONFIGURATION }} \ --configuration ${{ env.DOTNET_CONFIGURATION }} \
--output bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
-p:PublishProfile=LibationAvalonia/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml -p:PublishProfile=LibationAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \ dotnet publish \
LoadByOS/${{ matrix.os }}ConfigApp/${{ matrix.os }}ConfigApp.csproj \ LoadByOS/${display_os}ConfigApp/${display_os}ConfigApp.csproj \
--runtime "$RUNTIME_IDENTIFIER" \ --runtime "$RUNTIME_IDENTIFIER" \
--configuration ${{ env.DOTNET_CONFIGURATION }} \ --configuration ${{ env.DOTNET_CONFIGURATION }} \
--output bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
-p:PublishProfile=LoadByOS/Properties/${{ matrix.os }}ConfigApp/PublishProfiles/${{ matrix.os }}Profile.pubxml -p:PublishProfile=LoadByOS/Properties/${display_os}ConfigApp/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \ dotnet publish \
LibationCli/LibationCli.csproj \ LibationCli/LibationCli.csproj \
--runtime "$RUNTIME_IDENTIFIER" \ --runtime "$RUNTIME_IDENTIFIER" \
--configuration ${{ env.DOTNET_CONFIGURATION }} \ --configuration ${{ env.DOTNET_CONFIGURATION }} \
--output bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
-p:PublishProfile=LibationCli/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml -p:PublishProfile=LibationCli/Properties/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \ dotnet publish \
HangoverAvalonia/HangoverAvalonia.csproj \ HangoverAvalonia/HangoverAvalonia.csproj \
--runtime "$RUNTIME_IDENTIFIER" \ --runtime "$RUNTIME_IDENTIFIER" \
--configuration ${{ env.DOTNET_CONFIGURATION }} \ --configuration ${{ env.DOTNET_CONFIGURATION }} \
--output bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \
-p:PublishProfile=HangoverAvalonia/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml -p:PublishProfile=HangoverAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml
- name: Build bundle - name: Build bundle
id: bundle id: bundle
working-directory: ./Source/bin/Publish/${{ matrix.os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} working-directory: ./Source/bin/Publish/${{ steps.publish.outputs.display_os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }}
run: | run: |
BUNDLE_DIR=$(pwd) BUNDLE_DIR=$(pwd)
echo "Bundle dir: ${BUNDLE_DIR}" echo "Bundle dir: ${BUNDLE_DIR}"
cd .. cd ..
SCRIPT=../../../Scripts/Bundle_${{ matrix.os }}.sh SCRIPT=../../../Scripts/Bundle_${{ steps.publish.outputs.display_os }}.sh
chmod +rx ${SCRIPT} chmod +rx ${SCRIPT}
${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ matrix.arch }}" ${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ matrix.arch }}"
artifact=$(ls ./bundle) artifact=$(ls ./bundle)
echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}" echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"
- name: Publish bundle - name: Publish bundle
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: ${{ steps.bundle.outputs.artifact }} name: ${{ steps.bundle.outputs.artifact }}
path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }} path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }}
if-no-files-found: error if-no-files-found: error

26
.vscode/tasks.json vendored
View File

@ -5,19 +5,37 @@
"tasks": [ "tasks": [
{ {
"label": "build", "label": "build",
"dependsOn": [
"build_libation",
"build_linuxconfigapp"
]
},
{
"label": "build_libation",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
"build", "build",
// Ask msbuild to generate full paths for file names.
"${workspaceFolder}/Source/LibationAvalonia/LibationAvalonia.csproj" "${workspaceFolder}/Source/LibationAvalonia/LibationAvalonia.csproj"
], ],
"group": "build", "group": "build",
"presentation": { "presentation": {
// Reveal the output only if unrecognized errors occur. //"reveal": "silent"
"reveal": "silent" },
"problemMatcher": "$msCompile"
},
{
"label": "build_linuxconfigapp",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"${workspaceFolder}/Source/LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj"
],
"group": "build",
"presentation": {
//"reveal": "silent"
}, },
// Use the standard MS compiler pattern to detect errors, warnings and infos
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
} }
] ]

View File

@ -13,14 +13,10 @@ This walkthrough should get you up and running with Libation on your Mac.
- Move the extracted Libation app bundle to your applications folder. - Move the extracted Libation app bundle to your applications folder.
- Open a terminal (Go > Utilities > Terminal) - Open a terminal (Go > Utilities > Terminal)
- Copy/paste/run the following command (you'll be prompted to enter your password) - Copy/paste/run the following command (you'll be prompted to enter your password)
- macOS x64
```Console ```Console
sudo spctl --master-disable && sudo spctl --add --label "Libation" /Applications/Libation.app && open /Applications/Libation.app && sudo spctl --master-enable sudo spctl --master-disable && sudo spctl --add --label "Libation" /Applications/Libation.app && open /Applications/Libation.app && sudo spctl --master-enable
``` ```
- macOS arm64
```Console
codesign --force --deep -s - /Applications/Libation.app && sudo spctl --master-disable && sudo spctl --add --label "Libation" /Applications/Libation.app && open /Applications/Libation.app && sudo spctl --master-enable
```
- Close the terminal and use Libation! - Close the terminal and use Libation!
## Running Hangover ## Running Hangover

View File

@ -88,38 +88,27 @@ cp $FOLDER_EXEC/Libation.desktop $FOLDER_DESKTOP/Libation.desktop
echo "Creating pre-install file..." echo "Creating pre-install file..."
echo "#!/bin/bash echo "#!/bin/bash
# Pre-install script, removes previous installation program files and sym links # Pre-install script, removes previous installation program files and sym links
echo \"Removing previously created symlinks...\" echo \"Removing previously created symlinks...\"
rm /usr/bin/libation rm /usr/bin/libation
rm /usr/bin/hangover rm /usr/bin/hangover
rm /usr/bin/libationcli rm /usr/bin/libationcli
echo \"Removing previously installed Libation files...\" echo \"Removing previously installed Libation files...\"
rm -r /usr/lib/libation rm -r /usr/lib/libation
# making sure it won't stop installation # making sure it won't stop installation
exit 0 exit 0
" >> $FOLDER_DEBIAN/preinst " >> $FOLDER_DEBIAN/preinst
echo "Creating post-install file..." echo "Creating post-install file..."
echo "#!/bin/bash echo "#!/bin/bash
gtk-update-icon-cache -f /usr/share/icons/hicolor/ gtk-update-icon-cache -f /usr/share/icons/hicolor/
ln -s /usr/lib/libation/Libation /usr/bin/libation ln -s /usr/lib/libation/Libation /usr/bin/libation
ln -s /usr/lib/libation/Hangover /usr/bin/hangover ln -s /usr/lib/libation/Hangover /usr/bin/hangover
ln -s /usr/lib/libation/LibationCli /usr/bin/libationcli ln -s /usr/lib/libation/LibationCli /usr/bin/libationcli
# Increase the maximum number of inotify instances # Increase the maximum number of inotify instances
if ! grep -q 'fs.inotify.max_user_instances=524288' /etc/sysctl.conf; then
if ! grep -q 'fs.inotify.max_user_instances=524288' /etc/sysctl.conf; then
echo fs.inotify.max_user_instances=524288 | tee -a /etc/sysctl.conf && sysctl -p echo fs.inotify.max_user_instances=524288 | tee -a /etc/sysctl.conf && sysctl -p
fi fi
# workaround until this file is moved to the user's home directory # workaround until this file is moved to the user's home directory
touch /usr/lib/libation/appsettings.json touch /usr/lib/libation/appsettings.json
chmod 666 /usr/lib/libation/appsettings.json chmod 666 /usr/lib/libation/appsettings.json
@ -139,6 +128,11 @@ echo "Changing permissions for pre- and post-install files..."
chmod +x "$FOLDER_DEBIAN/preinst" chmod +x "$FOLDER_DEBIAN/preinst"
chmod +x "$FOLDER_DEBIAN/postinst" chmod +x "$FOLDER_DEBIAN/postinst"
if [ "$(uname -s)" == "Darwin" ]; then
echo "macOS detected, installing dpkg"
brew install dpkg
fi
DEB_FILE=Libation.${VERSION}-linux-chardonnay-${ARCH}.deb DEB_FILE=Libation.${VERSION}-linux-chardonnay-${ARCH}.deb
echo "Creating $DEB_FILE" echo "Creating $DEB_FILE"
dpkg-deb -Zxz --build $DEB_DIR ./$DEB_FILE dpkg-deb -Zxz --build $DEB_DIR ./$DEB_FILE
@ -149,4 +143,4 @@ mv $DEB_FILE ./bundle/$DEB_FILE
rm -r "$BIN_DIR" rm -r "$BIN_DIR"
echo "Done!" echo "Done!"

View File

@ -96,6 +96,9 @@ done
APP_FILE=Libation.${VERSION}-macOS-chardonnay-${ARCH}.tgz APP_FILE=Libation.${VERSION}-macOS-chardonnay-${ARCH}.tgz
echo "Signing executables in: $BUNDLE"
codesign --force --deep -s - $BUNDLE
echo "Creating app bundle: $APP_FILE" echo "Creating app bundle: $APP_FILE"
tar -czvf $APP_FILE $BUNDLE tar -czvf $APP_FILE $BUNDLE
@ -105,4 +108,4 @@ mv $APP_FILE ./bundle/$APP_FILE
rm -r $BUNDLE rm -r $BUNDLE
echo "Done!" echo "Done!"

View File

@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Version>9.3.0.1</Version> <Version>9.4.0.1</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Octokit" Version="5.0.0" /> <PackageReference Include="Octokit" Version="5.0.0" />

View File

@ -11,11 +11,13 @@ using System.Threading.Tasks;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using ApplicationServices; using ApplicationServices;
using Avalonia.Controls;
namespace LibationAvalonia namespace LibationAvalonia
{ {
public class App : Application public class App : Application
{ {
public static Window MainWindow { get;private set; }
public static IBrush ProcessQueueBookFailedBrush { get; private set; } public static IBrush ProcessQueueBookFailedBrush { get; private set; }
public static IBrush ProcessQueueBookCompletedBrush { get; private set; } public static IBrush ProcessQueueBookCompletedBrush { get; private set; }
public static IBrush ProcessQueueBookCancelledBrush { get; private set; } public static IBrush ProcessQueueBookCancelledBrush { get; private set; }
@ -213,7 +215,7 @@ namespace LibationAvalonia
private static void ShowMainWindow(IClassicDesktopStyleApplicationLifetime desktop) private static void ShowMainWindow(IClassicDesktopStyleApplicationLifetime desktop)
{ {
var mainWindow = new MainWindow(); var mainWindow = new MainWindow();
desktop.MainWindow = mainWindow; desktop.MainWindow = MainWindow = mainWindow;
mainWindow.RestoreSizeAndLocation(Configuration.Instance); mainWindow.RestoreSizeAndLocation(Configuration.Instance);
mainWindow.OnLoad(); mainWindow.OnLoad();
mainWindow.OnLibraryLoaded(LibraryTask.GetAwaiter().GetResult()); mainWindow.OnLibraryLoaded(LibraryTask.GetAwaiter().GetResult());

View File

@ -1,8 +1,6 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Threading; using LibationAvalonia.Dialogs;
using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace LibationAvalonia namespace LibationAvalonia
@ -18,6 +16,9 @@ namespace LibationAvalonia
return defaultBrush; return defaultBrush;
} }
public static Task<DialogResult> ShowDialogAsync(this DialogWindow dialogWindow, Window owner = null)
=> dialogWindow.ShowDialog<DialogResult>(owner ?? App.MainWindow);
public static Window GetParentWindow(this IControl control) => control.VisualRoot as Window; public static Window GetParentWindow(this IControl control) => control.VisualRoot as Window;
} }
} }

View File

@ -1,22 +0,0 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using System;
using System.Threading.Tasks;
namespace LibationAvalonia.Dialogs.Login
{
public abstract class AvaloniaLoginBase
{
/// <returns>True if ShowDialog's DialogResult == OK</returns>
protected static async Task<bool> ShowDialog(DialogWindow dialog)
{
if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
return false;
var result = await dialog.ShowDialog<DialogResult>(desktop.MainWindow);
Serilog.Log.Logger.Debug("{@DebugInfo}", new { DialogResult = result });
return result == DialogResult.OK;
}
}
}

View File

@ -5,7 +5,7 @@ using AudibleUtilities;
namespace LibationAvalonia.Dialogs.Login namespace LibationAvalonia.Dialogs.Login
{ {
public class AvaloniaLoginCallback : AvaloniaLoginBase, ILoginCallback public class AvaloniaLoginCallback : ILoginCallback
{ {
private Account _account { get; } private Account _account { get; }
@ -19,7 +19,7 @@ namespace LibationAvalonia.Dialogs.Login
public async Task<string> Get2faCodeAsync(string prompt) public async Task<string> Get2faCodeAsync(string prompt)
{ {
var dialog = new _2faCodeDialog(prompt); var dialog = new _2faCodeDialog(prompt);
if (await ShowDialog(dialog)) if (await dialog.ShowDialogAsync() is DialogResult.OK)
return dialog.Code; return dialog.Code;
return null; return null;
@ -28,15 +28,15 @@ namespace LibationAvalonia.Dialogs.Login
public async Task<(string password, string guess)> GetCaptchaAnswerAsync(string password, byte[] captchaImage) public async Task<(string password, string guess)> GetCaptchaAnswerAsync(string password, byte[] captchaImage)
{ {
var dialog = new CaptchaDialog(password, captchaImage); var dialog = new CaptchaDialog(password, captchaImage);
if (await ShowDialog(dialog)) if (await dialog.ShowDialogAsync() is DialogResult.OK)
return (dialog.Password, dialog.Answer); return (dialog.Password, dialog.Answer);
return (null,null); return (null, null);
} }
public async Task<(string name, string value)> GetMfaChoiceAsync(MfaConfig mfaConfig) public async Task<(string name, string value)> GetMfaChoiceAsync(MfaConfig mfaConfig)
{ {
var dialog = new MfaDialog(mfaConfig); var dialog = new MfaDialog(mfaConfig);
if (await ShowDialog(dialog)) if (await dialog.ShowDialogAsync() is DialogResult.OK)
return (dialog.SelectedName, dialog.SelectedValue); return (dialog.SelectedName, dialog.SelectedValue);
return (null, null); return (null, null);
} }
@ -44,7 +44,7 @@ namespace LibationAvalonia.Dialogs.Login
public async Task<(string email, string password)> GetLoginAsync() public async Task<(string email, string password)> GetLoginAsync()
{ {
var dialog = new LoginCallbackDialog(_account); var dialog = new LoginCallbackDialog(_account);
if (await ShowDialog(dialog)) if (await dialog.ShowDialogAsync() is DialogResult.OK)
return (_account.AccountId, dialog.Password); return (_account.AccountId, dialog.Password);
return (null, null); return (null, null);
} }
@ -52,7 +52,7 @@ namespace LibationAvalonia.Dialogs.Login
public async Task ShowApprovalNeededAsync() public async Task ShowApprovalNeededAsync()
{ {
var dialog = new ApprovalNeededDialog(); var dialog = new ApprovalNeededDialog();
await ShowDialog(dialog); await dialog.ShowDialogAsync();
} }
} }
} }

View File

@ -5,14 +5,15 @@ using AudibleUtilities;
namespace LibationAvalonia.Dialogs.Login namespace LibationAvalonia.Dialogs.Login
{ {
public class AvaloniaLoginChoiceEager : AvaloniaLoginBase, ILoginChoiceEager public class AvaloniaLoginChoiceEager : ILoginChoiceEager
{ {
/// <summary>Convenience method. Recommended when wiring up Winforms to <see cref="ApplicationServices.LibraryCommands.ImportAccountAsync"/></summary> /// <summary>Convenience method. Recommended when wiring up Winforms to <see cref="ApplicationServices.LibraryCommands.ImportAccountAsync"/></summary>
public static async Task<ApiExtended> ApiExtendedFunc(Account account) => await ApiExtended.CreateAsync(account, new AvaloniaLoginChoiceEager(account)); public static async Task<ApiExtended> ApiExtendedFunc(Account account)
=> await ApiExtended.CreateAsync(account, new AvaloniaLoginChoiceEager(account));
public ILoginCallback LoginCallback { get; private set; } public ILoginCallback LoginCallback { get; }
private Account _account { get; } private readonly Account _account;
public AvaloniaLoginChoiceEager(Account account) public AvaloniaLoginChoiceEager(Account account)
{ {
@ -24,10 +25,9 @@ namespace LibationAvalonia.Dialogs.Login
{ {
var dialog = new LoginChoiceEagerDialog(_account); var dialog = new LoginChoiceEagerDialog(_account);
if (!await ShowDialog(dialog)) if (await dialog.ShowDialogAsync() is not DialogResult.OK)
return null; return null;
switch (dialog.LoginMethod) switch (dialog.LoginMethod)
{ {
case LoginMethod.Api: case LoginMethod.Api:
@ -35,7 +35,7 @@ namespace LibationAvalonia.Dialogs.Login
case LoginMethod.External: case LoginMethod.External:
{ {
var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl); var externalDialog = new LoginExternalDialog(_account, choiceIn.LoginUrl);
return await ShowDialog(externalDialog) return await externalDialog.ShowDialogAsync() is DialogResult.OK
? ChoiceOut.External(externalDialog.ResponseUrl) ? ChoiceOut.External(externalDialog.ResponseUrl)
: null; : null;
} }

View File

@ -91,7 +91,15 @@ namespace LibationAvalonia.Dialogs.Login
public CaptchaDialogViewModel(string password, Bitmap[] gifFrames, int[] frameDelayMs) public CaptchaDialogViewModel(string password, Bitmap[] gifFrames, int[] frameDelayMs)
{ {
Password = password; Password = password;
FrameSwitch = SwitchFramesAsync(gifFrames, frameDelayMs); if (gifFrames.Length == 1)
{
FrameSwitch = Task.CompletedTask;
CaptchaImage = gifFrames[0];
}
else
{
FrameSwitch = SwitchFramesAsync(gifFrames, frameDelayMs);
}
} }
public async Task StopAsync() public async Task StopAsync()

View File

@ -7,27 +7,28 @@ namespace LibationAvalonia.Views
{ {
public partial class MainWindow public partial class MainWindow
{ {
private void Configure_Update() private void Configure_Upgrade()
{ {
setProgressVisible(false); setProgressVisible(false);
#if !DEBUG #if !DEBUG
async Task upgradeAvailable(UpgradeEventArgs e)
{
var notificationResult = await new UpgradeNotificationDialog(e.UpgradeProperties, e.CapUpgrade).ShowDialogAsync(this);
e.Ignore = notificationResult == DialogResult.Ignore;
e.InstallUpgrade = notificationResult == DialogResult.OK;
}
var upgrader = new Upgrader(); var upgrader = new Upgrader();
upgrader.DownloadProgress += async (_, e) => await Dispatcher.UIThread.InvokeAsync(() => _viewModel.DownloadProgress = e.ProgressPercentage); upgrader.DownloadProgress += async (_, e) => await Dispatcher.UIThread.InvokeAsync(() => _viewModel.DownloadProgress = e.ProgressPercentage);
upgrader.DownloadBegin += async (_, _) => await Dispatcher.UIThread.InvokeAsync(() => setProgressVisible(false)); upgrader.DownloadBegin += async (_, _) => await Dispatcher.UIThread.InvokeAsync(() => setProgressVisible(true));
upgrader.DownloadCompleted += async (_, _) => await Dispatcher.UIThread.InvokeAsync(() => setProgressVisible(true)); upgrader.DownloadCompleted += async (_, _) => await Dispatcher.UIThread.InvokeAsync(() => setProgressVisible(false));
Opened += async (_, _) => await upgrader.CheForUpgradeAsync(UpgradeAvailable); Opened += async (_, _) => await upgrader.CheForUpgradeAsync(upgradeAvailable);
#endif #endif
} }
private void setProgressVisible(bool visible) => _viewModel.DownloadProgress = visible ? 0 : null; private void setProgressVisible(bool visible) => _viewModel.DownloadProgress = visible ? 0 : null;
private async Task UpgradeAvailable(UpgradeEventArgs e)
{
var notificationResult = await new UpgradeNotificationDialog(e.UpgradeProperties, e.CapUpgrade).ShowDialog<DialogResult>(this);
e.Ignore = notificationResult == DialogResult.Ignore;
e.InstallUpdate = notificationResult == DialogResult.OK;
}
} }
} }

View File

@ -40,7 +40,7 @@ namespace LibationAvalonia.Views
Configure_Export(); Configure_Export();
Configure_Settings(); Configure_Settings();
Configure_ProcessQueue(); Configure_ProcessQueue();
Configure_Update(); Configure_Upgrade();
Configure_Filter(); Configure_Filter();
// misc which belongs in winforms app but doesn't have a UI element // misc which belongs in winforms app but doesn't have a UI element
Configure_NonUI(); Configure_NonUI();

View File

@ -8,7 +8,7 @@ namespace LibationFileManager
void SetFolderIcon(string image, string directory); void SetFolderIcon(string image, string directory);
void DeleteFolderIcon(string directory); void DeleteFolderIcon(string directory);
Process RunAsRoot(string exe, string args); Process RunAsRoot(string exe, string args);
void InstallUpdate(string updateBundle); void InstallUpgrade(string upgradeBundle);
bool CanUpdate { get; } bool CanUpgrade { get; }
} }
} }

View File

@ -11,8 +11,8 @@ namespace LibationFileManager
public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException(); public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException();
public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException(); public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException();
public bool CanUpdate => throw new PlatformNotSupportedException(); public bool CanUpgrade => throw new PlatformNotSupportedException();
public Process RunAsRoot(string exe, string args) => throw new PlatformNotSupportedException(); public Process RunAsRoot(string exe, string args) => throw new PlatformNotSupportedException();
public void InstallUpdate(string updateBundle) => throw new PlatformNotSupportedException(); public void InstallUpgrade(string updateBundle) => throw new PlatformNotSupportedException();
} }
} }

View File

@ -13,23 +13,23 @@ namespace LibationUiBase
public UpgradeProperties UpgradeProperties { get; internal init; } public UpgradeProperties UpgradeProperties { get; internal init; }
public bool CapUpgrade { get; internal init; } public bool CapUpgrade { get; internal init; }
private bool _ignore = false; private bool _ignore = false;
private bool _installUpdate = true; private bool _installUpgrade = true;
public bool Ignore public bool Ignore
{ {
get => _ignore; get => _ignore;
set set
{ {
_ignore = value; _ignore = value;
_installUpdate &= !Ignore; _installUpgrade &= !Ignore;
} }
} }
public bool InstallUpdate public bool InstallUpgrade
{ {
get => _installUpdate; get => _installUpgrade;
set set
{ {
_installUpdate = value; _installUpgrade = value;
_ignore &= !InstallUpdate; _ignore &= !InstallUpgrade;
} }
} }
} }
@ -47,35 +47,35 @@ namespace LibationUiBase
var upgradeProperties = await Task.Run(LibationScaffolding.GetLatestRelease); var upgradeProperties = await Task.Run(LibationScaffolding.GetLatestRelease);
if (upgradeProperties is null) return; if (upgradeProperties is null) return;
const string ignoreUpdate = "IgnoreUpdate"; const string ignoreUpgrade = "IgnoreUpgrade";
var config = Configuration.Instance; var config = Configuration.Instance;
if (config.GetString(propertyName: ignoreUpdate) == upgradeProperties.LatestRelease.ToString()) if (config.GetString(propertyName: ignoreUpgrade) == upgradeProperties.LatestRelease.ToString())
return; return;
var interop = InteropFactory.Create(); var interop = InteropFactory.Create();
if (!interop.CanUpdate) if (!interop.CanUpgrade)
Serilog.Log.Logger.Information("Can't perform update automatically"); Serilog.Log.Logger.Information("Can't perform upgrade automatically");
var upgradeEventArgs = new UpgradeEventArgs var upgradeEventArgs = new UpgradeEventArgs
{ {
UpgradeProperties = upgradeProperties, UpgradeProperties = upgradeProperties,
CapUpgrade = interop.CanUpdate CapUpgrade = interop.CanUpgrade
}; };
await upgradeAvailableHandler(upgradeEventArgs); await upgradeAvailableHandler(upgradeEventArgs);
if (upgradeEventArgs.Ignore) if (upgradeEventArgs.Ignore)
config.SetString(upgradeProperties.LatestRelease.ToString(), ignoreUpdate); config.SetString(upgradeProperties.LatestRelease.ToString(), ignoreUpgrade);
if (!upgradeEventArgs.InstallUpdate) return; if (!upgradeEventArgs.InstallUpgrade) return;
//Download the update file in the background, //Download the upgrade file in the background,
DownloadBegin?.Invoke(this, EventArgs.Empty); DownloadBegin?.Invoke(this, EventArgs.Empty);
string updateBundle = await DownloadUpgradeAsync(upgradeProperties); string upgradeBundle = await DownloadUpgradeAsync(upgradeProperties);
if (string.IsNullOrEmpty(updateBundle) || !File.Exists(updateBundle)) if (string.IsNullOrEmpty(upgradeBundle) || !File.Exists(upgradeBundle))
{ {
DownloadCompleted?.Invoke(this, false); DownloadCompleted?.Invoke(this, false);
} }
@ -83,15 +83,15 @@ namespace LibationUiBase
{ {
DownloadCompleted?.Invoke(this, true); DownloadCompleted?.Invoke(this, true);
//Install the update //Install the upgrade
Serilog.Log.Logger.Information($"Begin running auto-updater"); Serilog.Log.Logger.Information($"Begin running auto-upgrader");
interop.InstallUpdate(updateBundle); interop.InstallUpgrade(upgradeBundle);
Serilog.Log.Logger.Information($"Completed running auto-updater"); Serilog.Log.Logger.Information($"Completed running auto-upgrader");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Serilog.Log.Logger.Error(ex, "An error occured while checking for app updates."); Serilog.Log.Logger.Error(ex, "An error occured while checking for app upgrades.");
} }
} }
@ -103,7 +103,7 @@ namespace LibationUiBase
return null; return null;
} }
//Silently download the update in the background, save it to a temp file. //Silently download the upgrade in the background, save it to a temp file.
var zipFile = Path.Combine(Path.GetTempPath(), Path.GetFileName(upgradeProperties.ZipUrl)); var zipFile = Path.Combine(Path.GetTempPath(), Path.GetFileName(upgradeProperties.ZipUrl));
@ -140,7 +140,7 @@ namespace LibationUiBase
} }
catch (Exception ex) catch (Exception ex)
{ {
Serilog.Log.Logger.Error(ex, "Failed to download the update: {pdate}", upgradeProperties.ZipUrl); Serilog.Log.Logger.Error(ex, "Failed to download the upgrade: {bundle}", upgradeProperties.ZipUrl);
return null; return null;
} }
} }

View File

@ -1,4 +1,5 @@
<root> <?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">

View File

@ -6,29 +6,30 @@ namespace LibationWinForms
{ {
public partial class Form1 public partial class Form1
{ {
private void Configure_Update() private void Configure_Upgrade()
{ {
setProgressVisible(false); setProgressVisible(false);
#if !DEBUG #if !DEBUG
Task upgradeAvailable(UpgradeEventArgs e)
{
var notificationResult = new UpgradeNotificationDialog(e.UpgradeProperties).ShowDialog(this);
e.Ignore = notificationResult == System.Windows.Forms.DialogResult.Ignore;
e.InstallUpgrade = notificationResult == System.Windows.Forms.DialogResult.Yes;
return Task.CompletedTask;
}
var upgrader = new Upgrader(); var upgrader = new Upgrader();
upgrader.DownloadProgress += (_, e) => Invoke(() => upgradePb.Value = int.Max(0, int.Min(100, (int)(e.ProgressPercentage ?? 0)))); upgrader.DownloadProgress += (_, e) => Invoke(() => upgradePb.Value = int.Max(0, int.Min(100, (int)(e.ProgressPercentage ?? 0))));
upgrader.DownloadBegin += (_, _) => Invoke(() => setProgressVisible(true)); upgrader.DownloadBegin += (_, _) => Invoke(() => setProgressVisible(true));
upgrader.DownloadCompleted += (_, _) => Invoke(() => setProgressVisible(false)); upgrader.DownloadCompleted += (_, _) => Invoke(() => setProgressVisible(false));
Shown += async (_, _) => await upgrader.CheForUpgradeAsync(UpgradeAvailable); Shown += async (_, _) => await upgrader.CheForUpgradeAsync(upgradeAvailable);
#endif #endif
} }
private void setProgressVisible(bool visible) => upgradeLbl.Visible = upgradePb.Visible = visible; private void setProgressVisible(bool visible) => upgradeLbl.Visible = upgradePb.Visible = visible;
private Task UpgradeAvailable(UpgradeEventArgs e)
{
var notificationResult = new UpgradeNotificationDialog(e.UpgradeProperties).ShowDialog(this);
e.Ignore = notificationResult == System.Windows.Forms.DialogResult.Ignore;
e.InstallUpdate = notificationResult == System.Windows.Forms.DialogResult.Yes;
return Task.CompletedTask;
}
} }
} }

View File

@ -51,7 +51,7 @@ namespace LibationWinForms
Configure_Settings(); Configure_Settings();
Configure_ProcessQueue(); Configure_ProcessQueue();
Configure_Filter(); Configure_Filter();
Configure_Update(); Configure_Upgrade();
// misc which belongs in winforms app but doesn't have a UI element // misc which belongs in winforms app but doesn't have a UI element
Configure_NonUI(); Configure_NonUI();

View File

@ -1,7 +1,6 @@
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using Dinah.Core.WindowsDesktop;
using LibationFileManager; using LibationFileManager;
namespace LibationWinForms namespace LibationWinForms

View File

@ -23,12 +23,12 @@ namespace LinuxConfigApp
public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException(); public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException();
public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException(); public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException();
//only run the auto updater if the current app was installed from the //only run the auto upgrader if the current app was installed from the
//.deb package. Try to detect this by checking if the symlink exists. //.deb package. Try to detect this by checking if the symlink exists.
public bool CanUpdate => Directory.Exists("/usr/lib/libation"); public bool CanUpgrade => Directory.Exists("/usr/lib/libation");
public void InstallUpdate(string updateBundle) public void InstallUpgrade(string upgradeBundle)
{ {
RunAsRoot("apt", $"install '{updateBundle}'"); RunAsRoot("apt", $"install '{upgradeBundle}'");
} }
public Process RunAsRoot(string exe, string args) public Process RunAsRoot(string exe, string args)

View File

@ -13,15 +13,15 @@ namespace MacOSConfigApp
public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException(); public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException();
//I haven't figured out how to find the app bundle's directory from within //I haven't figured out how to find the app bundle's directory from within
//the running process, so don't update unless it's "installed" in /Applications //the running process, so don't upgrade unless it's "installed" in /Applications
public bool CanUpdate => Directory.Exists(AppPath); public bool CanUpgrade => Directory.Exists(AppPath);
public void InstallUpdate(string updateBundle) public void InstallUpgrade(string upgradeBundle)
{ {
Serilog.Log.Information($"Extracting update bundle to {AppPath}"); Serilog.Log.Information($"Extracting upgrade bundle to {AppPath}");
//tar wil overwrite existing without elevated privileges //tar wil overwrite existing without elevated privileges
Process.Start("tar", $"-xf \"{updateBundle}\" -C \"/Applications\"").WaitForExit(); Process.Start("tar", $"-xf \"{upgradeBundle}\" -C \"/Applications\"").WaitForExit();
//For now, it seems like this step is unnecessary. We can overwrite and //For now, it seems like this step is unnecessary. We can overwrite and
//run Libation without needing to re-add the exception. This is insurance. //run Libation without needing to re-add the exception. This is insurance.

View File

@ -97,10 +97,10 @@ namespace WindowsConfigApp
refresh(); refresh();
} }
private static void refresh() => SHChangeNotify(0x08000000, 0x0000, IntPtr.Zero, IntPtr.Zero); //SHCNE_ASSOCCHANGED SHCNF_IDLIST private static void refresh() => SHChangeNotify(0x08000000, 0x0000, 0, 0); //SHCNE_ASSOCCHANGED SHCNF_IDLIST
[DllImport("shell32.dll", SetLastError = true)] [DllImport("shell32.dll", SetLastError = true)]
private static extern void SHChangeNotify(int wEventId, int uFlags, IntPtr dwItem1, IntPtr dwItem2); private static extern void SHChangeNotify(int wEventId, int uFlags, nint dwItem1, nint dwItem2);
} }
} }

View File

@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup> <PropertyGroup>
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>Any CPU</Platform> <Platform>Any CPU</Platform>
<PublishDir>C:\Users\mbuca\OneDrive\Projects\Libation\Source\bin\Publish\Windows-chardonnay</PublishDir> <PublishDir>..\..\bin\Publish\classic</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol> <PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0-windows</TargetFramework> <TargetFramework>net7.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>

View File

@ -33,8 +33,8 @@ namespace WindowsConfigApp
public void DeleteFolderIcon(string directory) public void DeleteFolderIcon(string directory)
=> new DirectoryInfo(directory)?.DeleteIcon(); => new DirectoryInfo(directory)?.DeleteIcon();
public bool CanUpdate => true; public bool CanUpgrade => true;
public void InstallUpdate(string updateBundle) public void InstallUpgrade(string upgradeBundle)
{ {
var thisExe = Environment.ProcessPath; var thisExe = Environment.ProcessPath;
var thisDir = Path.GetDirectoryName(thisExe); var thisDir = Path.GetDirectoryName(thisExe);
@ -42,7 +42,7 @@ namespace WindowsConfigApp
File.Copy("ZipExtractor.exe", zipExtractor, overwrite: true); File.Copy("ZipExtractor.exe", zipExtractor, overwrite: true);
RunAsRoot(zipExtractor, $"--input \"{updateBundle}\" --output \"{thisDir}\" --executable \"{thisExe}\""); RunAsRoot(zipExtractor, $"--input \"{upgradeBundle}\" --output \"{thisDir}\" --executable \"{thisExe}\"");
} }
public Process RunAsRoot(string exe, string args) public Process RunAsRoot(string exe, string args)

View File

@ -14,7 +14,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\..\bin\Avalonia\Debug</OutputPath> <OutputPath>..\..\bin\Debug</OutputPath>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>