-
Notifications
You must be signed in to change notification settings - Fork 5
feat: add auto updater #117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
TrayIcon.OpenCommand = Tray_OpenCommand; | ||
TrayIcon.CheckForUpdatesCommand = Tray_CheckForUpdatesCommand; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we wouldn't include this if it's administratively disabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clicking it will show a popup explaining that it's disabled by an administrator, which I think is good enough for now. I'll file a ticket to revisit this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
bool IUIFactory.HideReleaseNotes { get; set; } | ||
bool IUIFactory.HideSkipButton { get; set; } | ||
bool IUIFactory.HideRemindMeLaterButton { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are these bools IUIFactor
instead of just normal public bool
?
Is there some reason we only want them accessed via the interface?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just like the pattern, discovered it while looking at some of the NetSparkle code
# -outputAppCastSignaturePath <path> | ||
param ( | ||
[Parameter(Mandatory = $true)] | ||
[ValidatePattern("^v\d+\.\d+\.\d+$")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we are going to enforce that the tag follows this format, then why not just compute it from the version? Seems like a gnarly bug if they didn't match versions.
return; | ||
} | ||
|
||
var dispatcherQueue = ((App)Application.Current).TrayWindow?.DispatcherQueue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want it to be the UserNotifier's business to figure out which thread the activation needs to run on. The Sparkle stuff needs to be on the UI, but other actions might not need to be.
Getting onto the correct thread should be the job of the callback itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that most (if not all) callbacks will want to run on the UI thread so they can e.g. spawn a window, update fields on the view model.
Either way we have to do the workaround to use the TrayWindow's DispatcherQueue in this case, so I think this avoids us having to have this workaround in multiple places in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think it shouldn't be in UserNotifier
but if you're going to insist, then the DispatcherQueue
needs to be passed in at startup in some reasonably portable way. Doing it like this will make this impossible to unit test.
.AddText(message) | ||
.AddArgument(CoderNotificationId, id) | ||
.BuildNotification(); | ||
ActionHandlers[id] = action; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this end up leaking handlers for every notification we send that doesn't get clicked?
I think we need to define some notification types, and allow a single handler per type. It could be dynamically registered at runtime, or just hard-coded handlers per type in App.xaml.cs
(and then UserNotifier doesn't even need to worry about activations, just sending notifications).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair, but I'd prefer this to be handled at the UserNotifier
level then in App.xaml.cs
. Ideally the IUserNotifier
interface has a method called HandleActivation
that takes a custom data type for ease of testing.
And I guess each handler would either be in a dictionary or registered once at startup.
$newAppCastSignaturePath = $newAppCastPath + ".signature" | ||
& ./scripts/Update-AppCast.ps1 ` | ||
-tag "${{ github.ref_name }}" ` | ||
-version "${{ steps.version.outputs.VERSION }}" ` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
considering the update will fail if we don't "bump" the version number (ie. previous is lower than new) - do we want to check this here within the script?
// | ||
// HACK: This isn't super robust, but the security risk is | ||
// minor anyway. Malicious apps running as the user could | ||
// likely override this setting by altering the memory of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One way to remove this risk is by always treating registry as a source of truth instead of relying on the in-memory value to block this.
@@ -32,7 +32,7 @@ | |||
<XamlUICommand | |||
Label="Show Window" | |||
Description="Show Window" | |||
Command="{x:Bind OpenCommand}"> | |||
Command="{x:Bind OpenCommand, Mode=OneWay}"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The command shouldn't need a direction on the bind IIRC
<XamlUICommand | ||
Label="Check for Updates" | ||
Description="Check for Updates" | ||
Command="{x:Bind CheckForUpdatesCommand, Mode=OneWay}"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Command="{x:Bind CheckForUpdatesCommand, Mode=OneWay}"> | |
Command="{x:Bind CheckForUpdatesCommand}"> |
<MenuFlyoutItem> | ||
<MenuFlyoutItem.Command> | ||
<XamlUICommand | ||
Label="Exit" | ||
Description="Exit" | ||
Command="{x:Bind ExitCommand}"> | ||
Command="{x:Bind ExitCommand, Mode=OneWay}"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Command="{x:Bind ExitCommand, Mode=OneWay}"> | |
Command="{x:Bind ExitCommand}"> |
|
||
InitializeComponent(); | ||
TitleBarIcon.SetTitlebarIcon(this); | ||
SystemBackdrop = new DesktopAcrylicBackdrop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SystemBackdrop = new DesktopAcrylicBackdrop(); |
|
||
public UpdaterDownloadProgressViewModel ViewModel; | ||
|
||
private bool _didCallDownloadProcessCompletedHandler; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private bool _didCallDownloadProcessCompletedHandler; | |
private bool _downloadProcessCompletedInvoked; |
just a nitpick
having an auxilary verb in the property name sounds weird imho
MinWidth="600" MinHeight="500"> | ||
|
||
<Window.SystemBackdrop> | ||
<DesktopAcrylicBackdrop /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<DesktopAcrylicBackdrop /> | |
<MicaBackdrop /> |
|
||
InitializeComponent(); | ||
TitleBarIcon.SetTitlebarIcon(this); | ||
SystemBackdrop = new DesktopAcrylicBackdrop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SystemBackdrop = new DesktopAcrylicBackdrop(); |
|
||
void IUpdateAvailable.Close() | ||
{ | ||
UserRespondedToUpdateCheck(UpdateAvailableResult.None); // the Avalonia UI does this "just in case" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we reference the Avalonia UI in the comment?
Closes: #122
Adds an auto updater utility using NetSparkle.
Most of the UI matches the way it's done in NetSparkle for the built-in UIs (I referenced the Avalonia and WPF ones mostly), including most of the copy and implementation (incl. quirks). I did this in case we ever want to contribute this upstream. The only major difference is how I handle the release notes stuff.
For release notes, I use the
<description>
tag to generate HTML for the web view. There's a hardcoded """template""" in the source code and a copy of sindresorhus/github-markdown-css in the repo that gets included as an asset in the binary. This matches what we do on macOS but diverges from the way NetSparkle does release notes rendering using<sparkle:releaseNotesUrl>
(or something like that).TODO:
Follow up: