Skip to content
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

Remove ShowsUIOnMainThread, refactor UI coordination #609

Merged
merged 42 commits into from
Aug 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
8f1ccba
Rip out ShowsUIOnMainThread property
Deadpikle Aug 11, 2024
0aeea45
Avalonia never supported ShowsUIOnMainThread
Deadpikle Aug 11, 2024
e3eaeff
WPF UI lib UIFactory update; untested/uncompiled atm
Deadpikle Aug 11, 2024
e850e0c
Default to showing WPF UI on main thread
Deadpikle Aug 11, 2024
3127e1d
Only get temp file name on update window response if needed
Deadpikle Aug 11, 2024
ede29fa
Rough update of winforms for no ShowsUIOnMainThread
Deadpikle Aug 11, 2024
cede4fd
Bump a couple samples to net8
Deadpikle Aug 11, 2024
8126044
Remove ShowsUIOnMainThread from some samples
Deadpikle Aug 11, 2024
fb25947
Update README.md
Deadpikle Aug 11, 2024
3f65950
Use FileVersion as backup for AssemblyVersion
Deadpikle Aug 11, 2024
4f3045b
Fix messed up header on win forms
Deadpikle Aug 11, 2024
7a26bad
Make other samples work w/no ShowsUIOnMainThread
Deadpikle Aug 11, 2024
74eadb0
Make event funcs work even without UIFactory
Deadpikle Aug 11, 2024
1722ef6
Move UI threading actions to IUIThreadManager
Deadpikle Aug 12, 2024
4eac532
Only use UI threading if UIFactory is IUIThreadManager
Deadpikle Aug 12, 2024
d9c4194
Add additional logs
Deadpikle Aug 12, 2024
0fd234b
Update README.md
Deadpikle Aug 12, 2024
9548429
Rename CallFuncConsideringUIThreads to PerformUIAction
Deadpikle Aug 12, 2024
9cbbc89
Update NetSparkleUpdater.sln
Deadpikle Aug 12, 2024
26e0cff
Another rename for 100% clarity
Deadpikle Aug 12, 2024
9c7b72a
Actual downloader now triggers download started
Deadpikle Aug 13, 2024
a21b13e
StartLoop now returns Task
Deadpikle Aug 13, 2024
f915efb
Make IUpdateDownloader.StartFileDownload return Task
Deadpikle Aug 13, 2024
3148a88
Rename func
Deadpikle Aug 13, 2024
d8dab0d
Await some Sparkle StartLoop calls
Deadpikle Aug 13, 2024
1a4e988
Add sample for multithreading Windows Forms app
Deadpikle Aug 15, 2024
149a1af
WInForms download progress bars start indeterminate
Deadpikle Aug 15, 2024
fd4757e
Rip out PerformMainThreadAction
Deadpikle Aug 15, 2024
05273fd
Check invoke req'd on net core win forms UpdateAvailableWindow.Show
Deadpikle Aug 15, 2024
ee481d1
Remove now-unnecessary PerformUIAction funcs
Deadpikle Aug 15, 2024
438c687
Re-add sync context for background loop calling to UI thraed
Deadpikle Aug 16, 2024
855baf6
Call UpdateDetected from loop to main thread
Deadpikle Aug 16, 2024
4c5bde7
Pause a few seconds at start of worker loop
Deadpikle Aug 16, 2024
5558735
Add UpdateDetectedAsync
Deadpikle Aug 16, 2024
4c04cdb
Adjust behavior so calling check for updates shows UI
Deadpikle Aug 17, 2024
52563dd
ReleaseNotesGrabber.DownloadReleaseNotes catches more exceptions
Deadpikle Aug 17, 2024
2e3a510
Remove some unneeded params
Deadpikle Aug 17, 2024
900bb77
Update README.md
Deadpikle Aug 17, 2024
9733e6e
Update UPGRADING.md
Deadpikle Aug 17, 2024
a53b796
Add Directory.Build.props for easier Avalonia version management
Deadpikle Aug 17, 2024
ec90908
Better logging for loop breaking on first time run
Deadpikle Aug 17, 2024
3addab2
Update UPGRADING.md
Deadpikle Aug 17, 2024
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
5 changes: 5 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<AvaloniaVersion>11.1.3</AvaloniaVersion>
</PropertyGroup>
</Project>
45 changes: 44 additions & 1 deletion NetSparkleUpdater.sln
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetSparkle.Samples.NetCore.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetSparkle.Samples.NetCore.WinForms", "src\NetSparkle.Samples.NetCore.WinForms\NetSparkle.Samples.NetCore.WinForms.csproj", "{0088BDC7-D50B-4AD4-8EE6-D2B7DA150778}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetSparkle.UI.WinForms.NetFramework", "src\NetSparkle.UI.WinForms.NetFramework\NetSparkle.UI.WinForms.NetFramework.csproj", "{DAB16394-9862-49C3-818B-6B84F22EF5FE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetSparkle.UI.WinForms.NetFramework", "src\NetSparkle.UI.WinForms.NetFramework\NetSparkle.UI.WinForms.NetFramework.csproj", "{DAB16394-9862-49C3-818B-6B84F22EF5FE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetSparkle.UI.Avalonia", "src\NetSparkle.UI.Avalonia\NetSparkle.UI.Avalonia.csproj", "{A50C27FA-CE8E-4253-BC1E-4B60053B0B7E}"
EndProject
Expand All @@ -42,6 +42,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetSparkle.Samples.Avalonia
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F3EF1CB9-F6D1-4D71-87C2-F2E80DD53968}"
ProjectSection(SolutionItems) = preProject
Directory.Build.props = Directory.Build.props
nuget\winformsnetframework\NetSparkleUpdater.UI.WinForms.NetFramework.nuspec = nuget\winformsnetframework\NetSparkleUpdater.UI.WinForms.NetFramework.nuspec
.github\workflows\publish-nuget.yml = .github\workflows\publish-nuget.yml
README.md = README.md
Expand All @@ -51,6 +52,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetSparkle.Samples.Avalonia
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetSparkle.Tests.Trimming", "src\NetSparkle.Tests.Trimming\NetSparkle.Tests.Trimming.csproj", "{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetSparkle.Samples.Forms.Multithread", "src\NetSparkle.Samples.Forms.Multithread\NetSparkle.Samples.Forms.Multithread.csproj", "{7952F006-5B13-45CF-93A8-46A0A470575F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -417,6 +420,46 @@ Global
{314E5B47-24FA-42F5-9975-3E4252853576}.Release|x64.Build.0 = Release|Any CPU
{314E5B47-24FA-42F5-9975-3E4252853576}.Release|x86.ActiveCfg = Release|Any CPU
{314E5B47-24FA-42F5-9975-3E4252853576}.Release|x86.Build.0 = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|ARM.Build.0 = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|x64.ActiveCfg = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|x64.Build.0 = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|x86.ActiveCfg = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Debug|x86.Build.0 = Debug|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|Any CPU.Build.0 = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|ARM.ActiveCfg = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|ARM.Build.0 = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|x64.ActiveCfg = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|x64.Build.0 = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|x86.ActiveCfg = Release|Any CPU
{7AE76C89-60B5-4F0E-A774-6E52F53B59D5}.Release|x86.Build.0 = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|ARM.Build.0 = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|x64.ActiveCfg = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|x64.Build.0 = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|x86.ActiveCfg = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Debug|x86.Build.0 = Debug|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|Any CPU.Build.0 = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|ARM.ActiveCfg = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|ARM.Build.0 = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|x64.ActiveCfg = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|x64.Build.0 = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|x86.ActiveCfg = Release|Any CPU
{7952F006-5B13-45CF-93A8-46A0A470575F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
40 changes: 26 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ We are open to contributions that might make the overall install/update process

### Project file

In your project file, make sure you set up a few things so that the library can read in the pertinent details later.
In your project file, make sure you set up a few things so that the library can read in the pertinent details later. _Note: You can use your own `IAssemblyAccessor` to load version information from somewhere else. However, setting things up in your project file is easy, and NetSparkleUpdater can read that in natively!_

```xml
<PropertyGroup>
Expand All @@ -118,7 +118,7 @@ In your project file, make sure you set up a few things so that the library can
</PropertyGroup>
```

IMPORTANT NOTE: In .NET 8+, a change was made that causes your git/source code commit hash to be included in your app's `<Version>` number. This behavior cannot be avoided by NetSparkleUpdater at this time as we rely on `AssemblyInformationalVersionAttribute`, and this attribute's behavior was changed. Your users may be told that they are currently running `1.0.0+commitHashHere` by NetSparkleUpdater (and your native app itself!). We recommend adding the following lines to your project file (in a new `<PropertyGroup>` or an existing one):
IMPORTANT NOTE: In .NET 8+, a change was made that causes your git/source code commit hash to be included in your app's `<Version>` number. This behavior cannot be avoided by NetSparkleUpdater at this time as we rely on `AssemblyInformationalVersionAttribute`, and this attribute's behavior was changed. Your users may be told that they are currently running `1.0.0+commitHashHere` by NetSparkleUpdater (and your native app itself!). We also recommend adding the following lines to your project file (in a new `<PropertyGroup>` or an existing one):

```xml
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
Expand All @@ -127,17 +127,20 @@ IMPORTANT NOTE: In .NET 8+, a change was made that causes your git/source code c
### Code

```csharp
// NOTE: Under most, if not all, circumstances, SparkleUpdater should be initialized on your app's main UI thread.
// This way, if you're using a built-in UI with no custom adjustments, all calls to UI objects will automatically go to the UI thread for you.
// Basically, SparkleUpdater's background loop will make calls to the thread that the SparkleUpdater was created on via SyncronizationContext.
// So, if you start SparkleUpdater on the UI thread, the background loop events will auto-call to the UI thread for you.
_sparkle = new SparkleUpdater(
"http://example.com/appcast.xml", // link to your app cast file
new Ed25519Checker(SecurityMode.Strict, // security mode -- use .Unsafe to ignore all signature checking (NOT recommended!!)
"base_64_public_key") // your base 64 public key -- generate this with the NetSparkleUpdater.Tools.AppCastGenerator .NET CLI tool on any OS
) {
UIFactory = new NetSparkleUpdater.UI.WPF.UIFactory(icon), // or null or choose some other UI factory or build your own!
UIFactory = new NetSparkleUpdater.UI.WPF.UIFactory(icon), // or null, or choose some other UI factory, or build your own IUIFactory implementation!
RelaunchAfterUpdate = false, // default is false; set to true if you want your app to restart after updating (keep as false if your installer will start your app for you)
CustomInstallerArguments = "", // set if you want your installer to get some command-line args
ShowsUIOnMainThread = true, // required on Avalonia, preferred on WPF/WinForms
};
_sparkle.StartLoop(true); // `true` to run an initial check online -- only call StartLoop once for a given SparkleUpdater instance!
_sparkle.StartLoop(true); // `true` to run an initial check online -- only call StartLoop **once** for a given SparkleUpdater instance!
```

On the first Application.Idle event, your App Cast XML file will be downloaded, read, and compared to the currently running version. If it has a software update inside, the user will be notified with a little toast notification (if supported by the UI and enabled) or with an update dialog containing your release notes. The user can then ignore the update, ask to be reminded later, or download/install it now.
Expand Down Expand Up @@ -403,6 +406,16 @@ Please see [UPGRADING.md](UPGRADING.md) for information on breaking changes betw

Nope. You can just reference the core library and handle everything yourself, including any custom UI. Check out the code samples for an example of doing that!

### Can I run my UI on another thread besides my main UI thread?

This isn't a built-in feature, as NetSparkleUpdater assumes that it can safely make calls/events to the UI on the thread that started the `SparkleUpdater` instance. However, if you'd like to do this, we have a sample on how to do this: `NetSparkle.Samples.Forms.Multithread`. Basically, instead of passing in a `UIFactory` to `SparkleUpdater`, you handle `SparkleUpdater`'s events yourself and show the UI however you want to show it - and yes, you can still use the built-in UI objects for this!

(Note that on Avalonia, the answer is always "No" since they only support one UI thread at this time.)

### On WinForms, can I let the user close the main window and still keep the updater forms around?

Yes. You need to start the `NetSparkleUpdater` forms on a new thread(s). See the `NetSparkle.Samples.Forms.Multithread` sample for how to do this by handling events yourself and still using the built-in WinForms `UIFactory`.

### How do I make my .NET Framework WinForms app high DPI aware?

See #238 [and this documentation](https://docs.microsoft.com/en-us/dotnet/desktop/winforms/high-dpi-support-in-windows-forms?view=netframeworkdesktop-4.8#configuring-your-windows-forms-app-for-high-dpi-support) for the fix for making this work on the sample application. Basically, you need to use an app config file and manifest file to let Windows know that your application is DPI-aware. If that doesn't work for you, try some of the tips at [this SO post](https://stackoverflow.com/questions/4075802/creating-a-dpi-aware-application).
Expand Down Expand Up @@ -490,12 +503,12 @@ Yes! Please help us make this library awesome!

### What's the tagging scheme, here?

* 2.x.y (Core)
* 2.x.y-app-cast-generator
* 2.x.y-dsa-helper
* 2.x.y-UI-Avalonia
* 2.x.y-UI-WinForms
* 2.x.y-UI-WPF
* Major.Minor.Patch (Core)
* Major.Minor.Patch-app-cast-generator
* Major.Minor.Patch-dsa-helper
* Major.Minor.Patch-UI-Avalonia
* Major.Minor.Patch-UI-WinForms
* Major.Minor.Patch-UI-WPF

## Requirements

Expand All @@ -511,9 +524,8 @@ Contributions are ALWAYS welcome! If you see a new feature you'd like to add, pl

### Areas where we could use help/contributions

* Unit tests for all parts of the project
* Extensive testing on macOS/Linux
* More built-in app cast parsers
* Unit tests for all parts of the project, including UI unit tests, full download tests, etc.
* Extensive testing/upgrades on macOS/Linux
* More options in the app cast generator
* See the [issues list](https://github.com/NetSparkleUpdater/NetSparkle/issues) for more

Expand Down
Loading