├── .gitattributes
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── locale-request.md
├── .gitignore
├── .idea
└── .idea.Syn3Updater
│ └── .idea
│ ├── .gitignore
│ ├── encodings.xml
│ ├── indexLayout.xml
│ └── vcs.xml
├── Create Install.bat
├── LICENSE
├── Launcher
├── App.xaml
├── App.xaml.cs
├── BaseViewModel.cs
├── Core.cs
├── Launcher.csproj
├── Properties
│ └── AssemblyInfo.cs
├── Splash.png
├── UpdateCheck.cs
├── UpgradingViewModel.cs
├── UpgradingWindow.xaml
├── UpgradingWindow.xaml.cs
├── app.manifest
└── cyanlabs.ico
├── README.md
├── SharedCode
├── Classes
│ └── LauncherPrefs.cs
├── Methods
│ └── JsonHelpers.cs
├── SharedCode.projitems
└── Updater.Common.shproj
├── Syn3Updater.Tests
├── Helper
│ ├── ApiHelperTests.cs
│ ├── FileHelperTests.cs
│ ├── MathHelperTests.cs
│ ├── SanityCheckHelperTests.cs
│ ├── SystemHelperTests.cs
│ └── USBHelperTests.cs
├── Services
│ ├── DownloadViewModelServiceTests.cs
│ ├── HomeViewModelTests.cs
│ └── TestAutoInstalls
│ │ └── mapautoinstall.lst
└── Syn3Updater.Tests.csproj
├── Syn3Updater.sln
├── Syn3Updater
├── App.xaml
├── App.xaml.cs
├── AppMan.cs
├── Converter
│ ├── BoolToVisibilityConverter.cs
│ ├── ESNConverter.cs
│ ├── HexToASCII.cs
│ ├── HtmltoXaml.cs
│ ├── LocConverter.cs
│ └── StringMatchToVisibilityConverter.cs
├── Helper
│ ├── ActionCommand.cs
│ ├── ApiHelper.cs
│ ├── EventHelper.cs
│ ├── ExceptionExtension.cs
│ ├── FileHelper.cs
│ ├── GraphQLRequests.cs
│ ├── MathHelper.cs
│ ├── SanityCheckHelper.cs
│ ├── SystemHelper.cs
│ ├── UIHelper.cs
│ ├── USBHelper.cs
│ └── effPartition.cs
├── Languages
│ ├── ar.json
│ ├── bg.json
│ ├── ca.json
│ ├── cs.json
│ ├── da.json
│ ├── de.json
│ ├── el.json
│ ├── en-US.json
│ ├── es.json
│ ├── fi.json
│ ├── fr.json
│ ├── hr.json
│ ├── hu.json
│ ├── it.json
│ ├── ku.json
│ ├── nl.json
│ ├── no.json
│ ├── pl.json
│ ├── pt-br.json
│ ├── pt.json
│ ├── ro.json
│ ├── ru.json
│ ├── sk.json
│ ├── sv.json
│ ├── th.json
│ ├── tr.json
│ ├── vi.json
│ ├── zh-CN.json
│ ├── zh-Hans.json
│ └── zh-Hant.json
├── Model
│ ├── APIModel.cs
│ ├── AsBuiltModel.cs
│ ├── BaseViewModel.cs
│ ├── InterrogatorModel.cs
│ ├── JsonSettings.cs
│ ├── LanguageAwareBaseviewModel.cs
│ ├── LanguageModel.cs
│ ├── LogModel.cs
│ └── SModel.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Services
│ ├── DownloadViewModelService.cs
│ └── HomeViewModelService.cs
├── SimpleLogger.cs
├── Syn3Updater.csproj
├── Syn3Updater.csproj.DotSettings
├── UI
│ ├── AttachedProperties.cs
│ ├── CrashWindow.xaml
│ ├── CrashWindow.xaml.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── MainWindowViewModel.cs
│ └── Tabs
│ │ ├── About.xaml
│ │ ├── About.xaml.cs
│ │ ├── AboutViewModel.cs
│ │ ├── Download.xaml
│ │ ├── Download.xaml.cs
│ │ ├── DownloadViewModel.cs
│ │ ├── Home.xaml
│ │ ├── Home.xaml.cs
│ │ ├── HomeViewModel.cs
│ │ ├── Logs.xaml
│ │ ├── Logs.xaml.cs
│ │ ├── LogsViewModel.cs
│ │ ├── News.xaml
│ │ ├── News.xaml.cs
│ │ ├── NewsViewModel.cs
│ │ ├── Profiles.xaml
│ │ ├── Profiles.xaml.cs
│ │ ├── ProfilesViewModel.cs
│ │ ├── Settings.xaml
│ │ ├── Settings.xaml.cs
│ │ ├── SettingsViewModel.cs
│ │ ├── Utility.xaml
│ │ ├── Utility.xaml.cs
│ │ ├── UtilityViewModel.cs
│ │ └── syncversion.png
├── app.manifest
└── cyanlabs.ico
├── THIRD-PARTY-NOTICES
└── cyanlabs_setup.nsi
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 | *.properties text
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: 'Type: Bug'
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | Please explain in as much detail as possible what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - Windows Version: [e.g. 10, 8, 7]
28 | - Syn3 Updater Version [e.g. 2.0.0.0]
29 | - Syn3 Updater Branch [e.g. Stable, Beta or Alpha]
30 |
31 | **Additional context**
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: 'Type: Enhancement'
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/locale-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Locale Request
3 | about: Request a new language be added to POEditor
4 | title: Locale Request
5 | labels: 'Type: Locale, Priority: Low'
6 | assignees: Fma965
7 |
8 | ---
9 |
10 | **Which language do you want added? Please describe.**
11 |
12 | **What is the 4/5 character code for this language, e.g EN-US etc.**
13 |
14 | **Are their similiar "parent" languages, e.g EN already exists and you are wanting EN-GB?**
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # JustCode is a .NET coding add-in
131 | .JustCode
132 |
133 | # TeamCity is a build add-in
134 | _TeamCity*
135 |
136 | # DotCover is a Code Coverage Tool
137 | *.dotCover
138 |
139 | # AxoCover is a Code Coverage Tool
140 | .axoCover/*
141 | !.axoCover/settings.json
142 |
143 | # Visual Studio code coverage results
144 | *.coverage
145 | *.coveragexml
146 |
147 | # NCrunch
148 | _NCrunch_*
149 | .*crunch*.local.xml
150 | nCrunchTemp_*
151 |
152 | # MightyMoose
153 | *.mm.*
154 | AutoTest.Net/
155 |
156 | # Web workbench (sass)
157 | .sass-cache/
158 |
159 | # Installshield output folder
160 | [Ee]xpress/
161 |
162 | # DocProject is a documentation generator add-in
163 | DocProject/buildhelp/
164 | DocProject/Help/*.HxT
165 | DocProject/Help/*.HxC
166 | DocProject/Help/*.hhc
167 | DocProject/Help/*.hhk
168 | DocProject/Help/*.hhp
169 | DocProject/Help/Html2
170 | DocProject/Help/html
171 |
172 | # Click-Once directory
173 | publish/
174 |
175 | # Publish Web Output
176 | *.[Pp]ublish.xml
177 | *.azurePubxml
178 | # Note: Comment the next line if you want to checkin your web deploy settings,
179 | # but database connection strings (with potential passwords) will be unencrypted
180 | *.pubxml
181 | *.publishproj
182 |
183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
184 | # checkin your Azure Web App publish settings, but sensitive information contained
185 | # in these scripts will be unencrypted
186 | PublishScripts/
187 |
188 | # NuGet Packages
189 | *.nupkg
190 | # NuGet Symbol Packages
191 | *.snupkg
192 | # The packages folder can be ignored because of Package Restore
193 | **/[Pp]ackages/*
194 | # except build/, which is used as an MSBuild target.
195 | !**/[Pp]ackages/build/
196 | # Uncomment if necessary however generally it will be regenerated when needed
197 | #!**/[Pp]ackages/repositories.config
198 | # NuGet v3's project.json files produces more ignorable files
199 | *.nuget.props
200 | *.nuget.targets
201 |
202 | # Microsoft Azure Build Output
203 | csx/
204 | *.build.csdef
205 |
206 | # Microsoft Azure Emulator
207 | ecf/
208 | rcf/
209 |
210 | # Windows Store app package directories and files
211 | AppPackages/
212 | BundleArtifacts/
213 | Package.StoreAssociation.xml
214 | _pkginfo.txt
215 | *.appx
216 | *.appxbundle
217 | *.appxupload
218 |
219 | # Visual Studio cache files
220 | # files ending in .cache can be ignored
221 | *.[Cc]ache
222 | # but keep track of directories ending in .cache
223 | !?*.[Cc]ache/
224 |
225 | # Others
226 | ClientBin/
227 | ~$*
228 | *~
229 | *.dbmdl
230 | *.dbproj.schemaview
231 | *.jfm
232 | *.pfx
233 | *.publishsettings
234 | orleans.codegen.cs
235 |
236 | # Including strong name files can present a security risk
237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
238 | #*.snk
239 |
240 | # Since there are multiple workflows, uncomment next line to ignore bower_components
241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
242 | #bower_components/
243 |
244 | # RIA/Silverlight projects
245 | Generated_Code/
246 |
247 | # Backup & report files from converting an old project file
248 | # to a newer Visual Studio version. Backup files are not needed,
249 | # because we have git ;-)
250 | _UpgradeReport_Files/
251 | Backup*/
252 | UpgradeLog*.XML
253 | UpgradeLog*.htm
254 | ServiceFabricBackup/
255 | *.rptproj.bak
256 |
257 | # SQL Server files
258 | *.mdf
259 | *.ldf
260 | *.ndf
261 |
262 | # Business Intelligence projects
263 | *.rdl.data
264 | *.bim.layout
265 | *.bim_*.settings
266 | *.rptproj.rsuser
267 | *- [Bb]ackup.rdl
268 | *- [Bb]ackup ([0-9]).rdl
269 | *- [Bb]ackup ([0-9][0-9]).rdl
270 |
271 | # Microsoft Fakes
272 | FakesAssemblies/
273 |
274 | # GhostDoc plugin setting file
275 | *.GhostDoc.xml
276 |
277 | # Node.js Tools for Visual Studio
278 | .ntvs_analysis.dat
279 | node_modules/
280 |
281 | # Visual Studio 6 build log
282 | *.plg
283 |
284 | # Visual Studio 6 workspace options file
285 | *.opt
286 |
287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
288 | *.vbw
289 |
290 | # Visual Studio LightSwitch build output
291 | **/*.HTMLClient/GeneratedArtifacts
292 | **/*.DesktopClient/GeneratedArtifacts
293 | **/*.DesktopClient/ModelManifest.xml
294 | **/*.Server/GeneratedArtifacts
295 | **/*.Server/ModelManifest.xml
296 | _Pvt_Extensions
297 |
298 | # Paket dependency manager
299 | .paket/paket.exe
300 | paket-files/
301 |
302 | # FAKE - F# Make
303 | .fake/
304 |
305 | # CodeRush personal settings
306 | .cr/personal
307 |
308 | # Python Tools for Visual Studio (PTVS)
309 | __pycache__/
310 | *.pyc
311 |
312 | # Cake - Uncomment if you are using it
313 | # tools/**
314 | # !tools/packages.config
315 |
316 | # Tabs Studio
317 | *.tss
318 |
319 | # Telerik's JustMock configuration file
320 | *.jmconfig
321 |
322 | # BizTalk build output
323 | *.btp.cs
324 | *.btm.cs
325 | *.odx.cs
326 | *.xsd.cs
327 |
328 | # OpenCover UI analysis results
329 | OpenCover/
330 |
331 | # Azure Stream Analytics local run output
332 | ASALocalRun/
333 |
334 | # MSBuild Binary and Structured Log
335 | *.binlog
336 |
337 | # NVidia Nsight GPU debugger configuration file
338 | *.nvuser
339 |
340 | # MFractors (Xamarin productivity tool) working folder
341 | .mfractor/
342 |
343 | # Local History for Visual Studio
344 | .localhistory/
345 |
346 | # BeatPulse healthcheck temp database
347 | healthchecksdb
348 |
349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
350 | MigrationBackup/
351 |
352 | # Ionide (cross platform F# VS Code tools) working folder
353 | .ionide/
354 |
355 | # Private information
356 | Model/APISecretModel.cs
357 | accent.json
358 |
359 | Launcher/Token.cs
360 | Syn3Updater/Model/APISecretModel.cs
361 | references/ModernWpf.dll
362 | references/ModernWpf.Controls.dll
363 | Syn3Updater/PullLanguages.ps1
364 | /Syn3Updater/Properties/launchSettings.json
365 | Syn3Updater/Models/APISecretModel.cs
366 |
367 | refs/
368 | hooks/
369 | HEAD
370 | FETCH_HEAD
371 | config
372 | description
373 | info/exclude
374 | objects/
--------------------------------------------------------------------------------
/.idea/.idea.Syn3Updater/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /projectSettingsUpdater.xml
6 | /modules.xml
7 | /contentModel.xml
8 | /.idea.Syn3Updater.iml
9 |
--------------------------------------------------------------------------------
/.idea/.idea.Syn3Updater/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/.idea.Syn3Updater/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/.idea.Syn3Updater/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Create Install.bat:
--------------------------------------------------------------------------------
1 | "C:\Program Files (x86)\NSIS\makensis.exe" /DProductName="Syn3Updater" cyanlabs_setup.nsi
--------------------------------------------------------------------------------
/Launcher/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Launcher/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Cyanlabs.Launcher
4 | {
5 | ///
6 | /// Interaction logic for App.xaml
7 | ///
8 | public partial class App : Application
9 | {
10 | }
11 | }
--------------------------------------------------------------------------------
/Launcher/BaseViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace Cyanlabs.Launcher
5 | {
6 | ///
7 | ///
8 | /// Represents a basic bindable class which notifies when a property value changes.
9 | ///
10 | public class BaseViewModel : INotifyPropertyChanged
11 | {
12 | #region Events
13 |
14 | ///
15 | /// Occurs when a property value changes.
16 | ///
17 | public event PropertyChangedEventHandler PropertyChanged;
18 |
19 | #endregion
20 |
21 | #region Methods
22 |
23 | ///
24 | /// Checks if the property already matches the desired value and updates it if not.
25 | ///
26 | /// Type of the property.
27 | /// Value to apply.
28 | ///
29 | /// Name of the property used to notify listeners. This value is optional
30 | /// and can be provided automatically when invoked from compilers that support
31 | /// .
32 | ///
33 | /// true if the value was changed, false if the existing value matched the desired value.
34 | internal bool Set(ref T variable, T value, [CallerMemberName] string propertyName = "")
35 | {
36 | if (variable == null && value != null || variable != null && value == null || variable != null && value != null && !variable.Equals(value))
37 | {
38 | variable = value;
39 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
40 | return true;
41 | }
42 |
43 | return false;
44 | }
45 |
46 | #endregion
47 | }
48 | }
--------------------------------------------------------------------------------
/Launcher/Core.cs:
--------------------------------------------------------------------------------
1 | using Cyanlabs.Updater.Common;
2 |
3 | namespace Cyanlabs.Launcher
4 | {
5 | public static class Core
6 | {
7 | public static LauncherPrefs LauncherPrefs;
8 |
9 | static Core()
10 | {
11 | LauncherPrefs = new LauncherPrefs();
12 | }
13 |
14 | public static UpgradingWindow UpgradingWindow { get; set; }
15 | }
16 | }
--------------------------------------------------------------------------------
/Launcher/Launcher.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net472;net6.0-windows10.0.18362
5 | WinExe
6 | Cyanlabs.Launcher
7 | false
8 | false
9 | true
10 | true
11 | cyanlabs.ico
12 | app.manifest
13 |
14 |
15 | ..\bin\Debug\
16 | latest
17 |
18 |
19 | ..\bin\Release\
20 | latest
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Launcher/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("Launcher")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("CyanLabs")]
11 | [assembly: AssemblyProduct("Launcher")]
12 | [assembly: AssemblyCopyright("Copyright © CyanLabs 2023")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | //In order to begin building localizable applications, set
22 | //CultureYouAreCodingWith in your .csproj file
23 | //inside a . For example, if you are using US english
24 | //in your source files, set the to en-US. Then uncomment
25 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
26 | //the line below to match the UICulture setting in the project file.
27 |
28 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
29 |
30 | // Version information for an assembly consists of the following four values:
31 | //
32 | // Major Version
33 | // Minor Version
34 | // Build Number
35 | // Revision
36 | //
37 | // You can specify all the values or you can default the Build and Revision Numbers
38 | // by using the '*' as shown below:
39 | // [assembly: AssemblyVersion("1.0.*")]
40 | [assembly: AssemblyVersion("2.13.3.0")]
41 | [assembly: AssemblyFileVersion("2.13.3.0")]
--------------------------------------------------------------------------------
/Launcher/Splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cyanlabs/Syn3Updater/a1ce25a7775ab91d06e0e5b85ac5e770c1dea1cd/Launcher/Splash.png
--------------------------------------------------------------------------------
/Launcher/UpgradingViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Cyanlabs.Launcher
2 | {
3 | public class UpgradingViewModel : BaseViewModel
4 | {
5 | #region Properties & Fields
6 |
7 | private string _message;
8 | private int _percentage = 100;
9 |
10 | public string Message
11 | {
12 | get => _message;
13 | set => Set(ref _message, value);
14 | }
15 |
16 | public int Percentage
17 | {
18 | get => _percentage;
19 | set => Set(ref _percentage, value);
20 | }
21 |
22 | #endregion
23 | }
24 | }
--------------------------------------------------------------------------------
/Launcher/UpgradingWindow.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Launcher/UpgradingWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Reflection;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Windows;
10 | using Cyanlabs.Updater.Common;
11 | using Newtonsoft.Json;
12 |
13 | namespace Cyanlabs.Launcher
14 | {
15 | ///
16 | /// Interaction logic for UpgradingWindow.xaml
17 | ///
18 | public partial class UpgradingWindow
19 | {
20 | #region Constructors
21 |
22 | public UpgradingWindow()
23 | {
24 | InitializeComponent();
25 | Vm = DataContext as UpgradingViewModel;
26 | Core.UpgradingWindow = this;
27 | }
28 |
29 | #endregion
30 |
31 | #region Properties & Fields
32 |
33 | public static string BaseFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
34 | public UpgradingViewModel Vm;
35 |
36 | #endregion
37 |
38 | #region Methods
39 |
40 | private async void AcrylicWindow_Loaded(object sender, RoutedEventArgs e)
41 | {
42 | Thread.Sleep(100);
43 | await StartCheck();
44 | }
45 |
46 | private async Task StartCheck()
47 | {
48 | // Set 'SecurityProtocolType' to Tls12 to allow Windows 7 and old .NET Framework versions to access TLS1.2 secure sites
49 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
50 |
51 | // Check if Syn3Updater Installer path exists in registry, if so use it's path as the destination path
52 | Process[] processlist = Process.GetProcesses();
53 |
54 | // Forcefully close all Syn3Updater processes, ignore all exceptions
55 | if (processlist.Any(x => x.ProcessName == "Syn3Updater"))
56 | try
57 | {
58 | Process proc = processlist.First(x => x.ProcessName == "Syn3Updater");
59 | proc.Kill();
60 | proc.Dispose();
61 | }
62 | catch
63 | {
64 | // ignored
65 | }
66 |
67 | // Attempt to load existing settings if found, if not use defaults
68 | string commonConfigFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\CyanLabs\\Syn3Updater";
69 | if (File.Exists(commonConfigFolderPath + "\\launcherPrefs.json"))
70 | try
71 | {
72 | Core.LauncherPrefs = JsonConvert.DeserializeObject(File.ReadAllText(commonConfigFolderPath + "\\launcherPrefs.json"));
73 | }
74 | catch (JsonReaderException)
75 | {
76 | File.Delete(commonConfigFolderPath + "\\launcherPrefs.json");
77 | Application.Current.Shutdown();
78 | Process.Start(BaseFolder + "\\Syn3Updater.exe", "/launcher");
79 | }
80 |
81 | // Delete Launcher_OldVersion.exe
82 | if (File.Exists("Launcher_OldVersion.exe"))
83 | File.Delete("Launcher_OldVersion.exe");
84 |
85 | // Start and wait for the UpdateCheck to complete
86 | UpdateCheck check = new();
87 | bool updated = await check.Execute(Core.LauncherPrefs.ReleaseBranch, this, BaseFolder);
88 | // Update complete, either no update needed or new update downloaded and extracted, run Syn3Updater.exe
89 |
90 | string magnet = "";
91 | foreach (string value in Environment.GetCommandLineArgs())
92 | if (value.Contains("syn3updater://"))
93 | magnet = value;
94 |
95 | Process p = new()
96 | {
97 | StartInfo =
98 | {
99 | WindowStyle = ProcessWindowStyle.Hidden,
100 | FileName = BaseFolder + "\\Syn3Updater.exe",
101 | WorkingDirectory = BaseFolder ?? string.Empty,
102 | Arguments = "/launcher" + (updated ? " /updated" : "") + (!string.IsNullOrEmpty(magnet) ? " " + magnet : ""),
103 | UseShellExecute = false
104 | }
105 | };
106 | p.Start();
107 |
108 | await Task.Delay(2000);
109 |
110 | // Exit Launcher
111 | Application.Current.Shutdown();
112 | }
113 |
114 | #endregion
115 | }
116 | }
--------------------------------------------------------------------------------
/Launcher/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
53 |
60 |
61 |
62 |
76 |
77 |
--------------------------------------------------------------------------------
/Launcher/cyanlabs.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cyanlabs/Syn3Updater/a1ce25a7775ab91d06e0e5b85ac5e770c1dea1cd/Launcher/cyanlabs.ico
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Syn3Updater
2 | Syn3 Updater - https://cyanlabs.net/applications/syn3-updater/
3 |
4 | Please note if you fork this repo you will require a APISecret in order to access our API, please contact us if you wish to gain this access!
5 |
--------------------------------------------------------------------------------
/SharedCode/Classes/LauncherPrefs.cs:
--------------------------------------------------------------------------------
1 | namespace Cyanlabs.Updater.Common
2 | {
3 | ///
4 | /// Shared class used for Launcher preferences
5 | ///
6 | public class LauncherPrefs
7 | {
8 | public enum ReleaseType
9 | {
10 | Stable,
11 | Beta,
12 | Alpha
13 | }
14 |
15 | public ReleaseType ReleaseBranch { get; set; }
16 | public string ReleaseInstalled { get; set; } = "0.0.0.0";
17 | public ReleaseType ReleaseTypeInstalled { get; set; }
18 | }
19 | }
--------------------------------------------------------------------------------
/SharedCode/Methods/JsonHelpers.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Newtonsoft.Json;
3 |
4 | namespace Cyanlabs.Updater.Common
5 | {
6 | public static class JsonHelpers
7 | {
8 | public static T Deserialize(Stream s)
9 | {
10 | using StreamReader reader = new(s);
11 | using JsonTextReader jsonReader = new(reader);
12 | JsonSerializer ser = new();
13 | return ser.Deserialize(jsonReader);
14 | }
15 |
16 | public static void Serialize(object value, Stream s)
17 | {
18 | using StreamWriter writer = new(s);
19 | using JsonTextWriter jsonWriter = new(writer);
20 | JsonSerializer ser = new();
21 | ser.Serialize(jsonWriter, value);
22 | jsonWriter.Flush();
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/SharedCode/SharedCode.projitems:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
5 | true
6 | 285a3e6c-652a-4ca2-9b27-3a4dc4e1177b
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/SharedCode/Updater.Common.shproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 285a3e6c-652a-4ca2-9b27-3a4dc4e1177b
5 | 14.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Syn3Updater.Tests/Helper/ApiHelperTests.cs:
--------------------------------------------------------------------------------
1 | using Cyanlabs.Syn3Updater.Helper;
2 | using System;
3 | using NUnit.Framework;
4 | using Cyanlabs.Syn3Updater.Model;
5 | using System.Threading.Tasks;
6 |
7 | namespace Syn3Updater.Tests.Helper
8 | {
9 | [TestFixture]
10 | [Ignore("FIXME")]
11 | public static class ApiHelperTests
12 | {
13 | //TODO:FIXME
14 | [Test]
15 | public static void CanCallGetSpecialIvsu()
16 | {
17 | var url = "TestValue1041730658";
18 | var result = ApiHelper.GetSpecialIvsu(url);
19 | Assert.Fail("Create or modify test");
20 | }
21 |
22 | [TestCase(null)]
23 | [TestCase("")]
24 | [TestCase(" ")]
25 | public static void CannotCallGetSpecialIvsuWithInvalidUrl(string value)
26 | {
27 | Assert.ThrowsAsync(async () => await ApiHelper.GetSpecialIvsu(value));
28 | }
29 |
30 | [Test]
31 | public async static Task GetSpecialIvsuPerformsMapping()
32 | {
33 | var url = "TestValue615803767";
34 | var result = await ApiHelper.GetSpecialIvsu(url);
35 | Assert.That(result.Url, Is.EqualTo(url));
36 | }
37 |
38 | [Test]
39 | public static void CanCallConvertIvsu()
40 | {
41 | var ivsu = new Api.Ivsu { Id = 1987917491, Name = "TestValue507747437", Type = "TestValue391370599", Regions = new[] { "TestValue941055651", "TestValue745553851", "TestValue1110261990" }, Md5 = "TestValue424093519", Url = "TestValue809188826", Notes = "TestValue323075795", Version = "TestValue29422309" };
42 | var result = ApiHelper.ConvertIvsu(ivsu);
43 | Assert.Fail("Create or modify test");
44 | }
45 |
46 | [Test]
47 | public static void CannotCallConvertIvsuWithNullIvsu()
48 | {
49 | Assert.Throws(() => ApiHelper.ConvertIvsu(default));
50 | }
51 |
52 | [Test]
53 | public static void ConvertIvsuPerformsMapping()
54 | {
55 | var ivsu = new Api.Ivsu { Id = 1898385250, Name = "TestValue965838048", Type = "TestValue981252909", Regions = new[] { "TestValue1863182185", "TestValue545353684", "TestValue1411896392" }, Md5 = "TestValue1364557053", Url = "TestValue2131094873", Notes = "TestValue1284512460", Version = "TestValue1676088225" };
56 | var result = ApiHelper.ConvertIvsu(ivsu);
57 | Assert.That(result.Name, Is.EqualTo(ivsu.Name));
58 | Assert.That(result.Type, Is.EqualTo(ivsu.Type));
59 | Assert.That(result.Md5, Is.EqualTo(ivsu.Md5));
60 | Assert.That(result.Url, Is.EqualTo(ivsu.Url));
61 | Assert.That(result.Notes, Is.EqualTo(ivsu.Notes));
62 | Assert.That(result.Version, Is.EqualTo(ivsu.Version));
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/Syn3Updater.Tests/Helper/FileHelperTests.cs:
--------------------------------------------------------------------------------
1 | using Cyanlabs.Syn3Updater.Helper;
2 | using System;
3 | using NUnit.Framework;
4 | using System.Threading;
5 | using Cyanlabs.Syn3Updater.Model;
6 | using System.Threading.Tasks;
7 |
8 | namespace Syn3Updater.Tests.Helper
9 | {
10 | [TestFixture]
11 | [Ignore("FIXME")]
12 | public class FileHelperTests
13 | {
14 | private FileHelper _testClass;
15 | private EventHandler> _externalPercentageChanged;
16 |
17 | [SetUp]
18 | public void SetUp()
19 | {
20 | _externalPercentageChanged = default;
21 | _testClass = new FileHelper(_externalPercentageChanged);
22 | }
23 |
24 | [Test]
25 | public void CanConstruct()
26 | {
27 | var instance = new FileHelper(_externalPercentageChanged);
28 | Assert.That(instance, Is.Not.Null);
29 | }
30 |
31 | [Test]
32 | public void CannotConstructWithNullExternalPercentageChanged()
33 | {
34 | Assert.Throws(() => new FileHelper(default));
35 | }
36 |
37 | [Test]
38 | public async Task CanCallCopyFileAsync()
39 | {
40 | var source = "TestValue1341751390";
41 | var destination = "TestValue442833009";
42 | var ct = CancellationToken.None;
43 | await _testClass.CopyFileAsync(source, destination, ct);
44 | Assert.Fail("Create or modify test");
45 | }
46 |
47 | [TestCase(null)]
48 | [TestCase("")]
49 | [TestCase(" ")]
50 | public void CannotCallCopyFileAsyncWithInvalidSource(string value)
51 | {
52 | Assert.ThrowsAsync(() => _testClass.CopyFileAsync(value, "TestValue988473579", CancellationToken.None));
53 | }
54 |
55 | [TestCase(null)]
56 | [TestCase("")]
57 | [TestCase(" ")]
58 | public void CannotCallCopyFileAsyncWithInvalidDestination(string value)
59 | {
60 | Assert.ThrowsAsync(() => _testClass.CopyFileAsync("TestValue888829737", value, CancellationToken.None));
61 | }
62 |
63 | [Test]
64 | public async Task CanCallDownloadFile()
65 | {
66 | var path = "TestValue806668900";
67 | var filename = "TestValue1123419722";
68 | var ct = CancellationToken.None;
69 | await _testClass.DownloadFile(path, filename, ct);
70 | Assert.Fail("Create or modify test");
71 | }
72 |
73 | [TestCase(null)]
74 | [TestCase("")]
75 | [TestCase(" ")]
76 | public void CannotCallDownloadFileWithInvalidPath(string value)
77 | {
78 | Assert.ThrowsAsync(() => _testClass.DownloadFile(value, "TestValue1826660125", CancellationToken.None));
79 | }
80 |
81 | [TestCase(null)]
82 | [TestCase("")]
83 | [TestCase(" ")]
84 | public void CannotCallDownloadFileWithInvalidFilename(string value)
85 | {
86 | Assert.ThrowsAsync(() => _testClass.DownloadFile("TestValue1989092351", value, CancellationToken.None));
87 | }
88 |
89 | [Test]
90 | public void CanCallValidateFile()
91 | {
92 | var source = "TestValue379678139";
93 | var localfile = "TestValue1507250646";
94 | var md5 = "TestValue1995825226";
95 | var localonly = true;
96 | var ct = CancellationToken.None;
97 | var result = _testClass.ValidateFile(source, localfile, md5, localonly, ct);
98 | Assert.Fail("Create or modify test");
99 | }
100 |
101 | [TestCase(null)]
102 | [TestCase("")]
103 | [TestCase(" ")]
104 | public void CannotCallValidateFileWithInvalidSource(string value)
105 | {
106 | Assert.Throws(() => _testClass.ValidateFile(value, "TestValue1591156435", "TestValue1461748148", true, CancellationToken.None));
107 | }
108 |
109 | [TestCase(null)]
110 | [TestCase("")]
111 | [TestCase(" ")]
112 | public void CannotCallValidateFileWithInvalidLocalfile(string value)
113 | {
114 | Assert.Throws(() => _testClass.ValidateFile("TestValue1248780129", value, "TestValue1745235058", false, CancellationToken.None));
115 | }
116 |
117 | [TestCase(null)]
118 | [TestCase("")]
119 | [TestCase(" ")]
120 | public void CannotCallValidateFileWithInvalidMd5(string value)
121 | {
122 | Assert.Throws(() => _testClass.ValidateFile("TestValue466552766", "TestValue9818853", value, false, CancellationToken.None));
123 | }
124 |
125 | [Test]
126 | public void CanCallGenerateMd5()
127 | {
128 | var filename = "TestValue1138810608";
129 | var ct = CancellationToken.None;
130 | var result = _testClass.GenerateMd5(filename, ct);
131 | Assert.Fail("Create or modify test");
132 | }
133 |
134 | [TestCase(null)]
135 | [TestCase("")]
136 | [TestCase(" ")]
137 | public void CannotCallGenerateMd5WithInvalidFilename(string value)
138 | {
139 | Assert.Throws(() => _testClass.GenerateMd5(value, CancellationToken.None));
140 | }
141 |
142 | [Test]
143 | public void CanCallurl_to_filename()
144 | {
145 | var url = "TestValue1520508193";
146 | var result = FileHelper.url_to_filename(url);
147 | Assert.Fail("Create or modify test");
148 | }
149 |
150 | [TestCase(null)]
151 | [TestCase("")]
152 | [TestCase(" ")]
153 | public void CannotCallurl_to_filenameWithInvalidUrl(string value)
154 | {
155 | Assert.Throws(() => FileHelper.url_to_filename(value));
156 | }
157 |
158 | [Test]
159 | public void CanCallExtractMultiPackage()
160 | {
161 | var item = new SModel.Ivsu { Selected = true, Type = "TestValue818008845", Name = "TestValue126881402", Version = "TestValue1525867736", Notes = "TestValue1513126080", Url = "TestValue918057671", Md5 = "TestValue165400975", FileName = "TestValue1848913370", Source = "TestValue1373573975", FileSize = 1375353975 };
162 | var ct = CancellationToken.None;
163 | var result = _testClass.ExtractMultiPackage(item, ct);
164 | Assert.Fail("Create or modify test");
165 | }
166 |
167 | [Test]
168 | public void CannotCallExtractMultiPackageWithNullItem()
169 | {
170 | Assert.Throws(() => _testClass.ExtractMultiPackage(default, CancellationToken.None));
171 | }
172 | }
173 | }
--------------------------------------------------------------------------------
/Syn3Updater.Tests/Helper/MathHelperTests.cs:
--------------------------------------------------------------------------------
1 | using Cyanlabs.Syn3Updater.Helper;
2 | using System;
3 | using NUnit.Framework;
4 |
5 | namespace Syn3Updater.Tests.Helper
6 | {
7 | [TestFixture]
8 | [Ignore("FIXME")]
9 | public static class MathHelperTests
10 | {
11 | [Test]
12 | public static void CanCallGetDouble()
13 | {
14 | var value = "TestValue6769535";
15 | var defaultValue = 381389917.59;
16 | var result = value.GetDouble(defaultValue);
17 | Assert.Fail("Create or modify test");
18 | }
19 |
20 | [TestCase(null)]
21 | [TestCase("")]
22 | [TestCase(" ")]
23 | public static void CannotCallGetDoubleWithInvalidValue(string value)
24 | {
25 | Assert.Throws(() => value.GetDouble(1896834304.53));
26 | }
27 |
28 | [Test]
29 | public static void CanCallClampWithDoubleAndDoubleAndDouble()
30 | {
31 | var value = 2107456715.43;
32 | var min = 1948516905.06;
33 | var max = 1565912407.95;
34 | var result = MathHelper.Clamp(value, min, max);
35 | Assert.Fail("Create or modify test");
36 | }
37 |
38 | [Test]
39 | public static void CanCallClampWithFloatAndFloatAndFloat()
40 | {
41 | var value = 20907.52F;
42 | var min = 11824.6748F;
43 | var max = 19632.2988F;
44 | var result = MathHelper.Clamp(value, min, max);
45 | Assert.Fail("Create or modify test");
46 | }
47 |
48 | [Test]
49 | public static void CanCallClampWithIntAndIntAndInt()
50 | {
51 | var value = 1139644205;
52 | var min = 1483504046;
53 | var max = 1185586685;
54 | var result = MathHelper.Clamp(value, min, max);
55 | Assert.Fail("Create or modify test");
56 | }
57 |
58 | [Test]
59 | public static void CanCallBytesToString()
60 | {
61 | var byteCount = 1563554813L;
62 | var result = MathHelper.BytesToString(byteCount);
63 | Assert.Fail("Create or modify test");
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/Syn3Updater.Tests/Helper/SanityCheckHelperTests.cs:
--------------------------------------------------------------------------------
1 | using Cyanlabs.Syn3Updater.Helper;
2 | using System;
3 | using NUnit.Framework;
4 |
5 | namespace Syn3Updater.Tests.Helper
6 | {
7 | [TestFixture]
8 | [Ignore("FIXME")]
9 | public static class SanityCheckHelperTests
10 | {
11 | [Test]
12 | public static void CanCallCancelDownloadCheck()
13 | {
14 | var selectedDrive = new USBHelper.Drive { Path = "TestValue866096061", Name = "TestValue539938438" };
15 | var result = SanityCheckHelper.CancelDownloadCheck(selectedDrive);
16 | Assert.Fail("Create or modify test");
17 | }
18 |
19 | [Test]
20 | public static void CannotCallCancelDownloadCheckWithNullSelectedDrive()
21 | {
22 | Assert.Throws(() => SanityCheckHelper.CancelDownloadCheck(default));
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/Syn3Updater.Tests/Helper/SystemHelperTests.cs:
--------------------------------------------------------------------------------
1 | using Cyanlabs.Syn3Updater.Helper;
2 | using NUnit.Framework;
3 |
4 | namespace Syn3Updater.Tests.Helper
5 | {
6 | [TestFixture]
7 | [Ignore("FIXME")]
8 | public static class SystemHelperTests
9 | {
10 | [Test]
11 | public static void CanCallGetPathWithKnownFolder()
12 | {
13 | var knownFolder = SystemHelper.KnownFolder.Downloads;
14 | var result = SystemHelper.GetPath(knownFolder);
15 | Assert.Fail("Create or modify test");
16 | }
17 |
18 | [Test]
19 | public static void CanCallGetPathWithKnownFolderAndDefaultUser()
20 | {
21 | var knownFolder = SystemHelper.KnownFolder.Downloads;
22 | var defaultUser = true;
23 | var result = SystemHelper.GetPath(knownFolder, defaultUser);
24 | Assert.Fail("Create or modify test");
25 | }
26 |
27 | [Test]
28 | public static void CanCallGetOsFriendlyName()
29 | {
30 | var result = SystemHelper.GetOsFriendlyName();
31 | Assert.Fail("Create or modify test");
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/Syn3Updater.Tests/Helper/USBHelperTests.cs:
--------------------------------------------------------------------------------
1 | using Cyanlabs.Syn3Updater.Helper;
2 | using System;
3 | using NUnit.Framework;
4 |
5 | namespace Syn3Updater.Tests.Helper
6 | {
7 | [TestFixture]
8 | [Ignore("FIXME")]
9 | public static class USBHelperTests
10 | {
11 | [Test]
12 | public static void CanCallRefreshDevices()
13 | {
14 | var fakeusb = true;
15 | var result = USBHelper.RefreshDevices(fakeusb);
16 | Assert.Fail("Create or modify test");
17 | }
18 |
19 |
20 | // TODO: make test smarter
21 | [Test]
22 | public static void CanCallGenerateLog()
23 | {
24 | var log = "TestValue202940782";
25 | USBHelper.GenerateLog(log, false);
26 | Assert.Fail("Create or modify test");
27 | }
28 |
29 | [TestCase(null)]
30 | [TestCase("")]
31 | [TestCase(" ")]
32 | public static void CannotCallGenerateLogWithInvalidLog(string value)
33 | {
34 | Assert.Throws(() => USBHelper.GenerateLog(value, false));
35 | }
36 |
37 | //TODO: make test smarter , need moq
38 | [Test]
39 | public static void CanCallUploadLog()
40 | {
41 | var log = "TestValue70820892";
42 | // USBHelper.UploadLog(log);
43 | Assert.Fail("Create or modify test");
44 | }
45 |
46 | [TestCase(null)]
47 | [TestCase("")]
48 | [TestCase(" ")]
49 | public static void CannotCallUploadLogWithInvalidLog(string value)
50 | {
51 | // Assert.Throws(() => USBHelper.UploadLog(value));
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/Syn3Updater.Tests/Services/HomeViewModelTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Cyanlabs.Syn3Updater;
3 | using Cyanlabs.Updater.Common;
4 | using Cyanlabs.Syn3Updater.Model;
5 | using Cyanlabs.Syn3Updater.Helper;
6 | using System.Threading.Tasks;
7 | using Cyanlabs.Syn3Updater.Services;
8 |
9 | namespace Syn3Updater.Tests.Common.Services
10 | {
11 | [TestFixture]
12 | public class HomeViewModelServiceTests
13 | {
14 | private System.Collections.ObjectModel.ObservableCollection IvsuList;
15 | private SModel.Ivsu toTest;
16 | private SModel.SRegion merica;
17 | private USBHelper.Drive nosavedrive;
18 |
19 | [SetUp]
20 | public void SetUp()
21 | {
22 | toTest = new SModel.Ivsu
23 | {
24 | Selected = true,
25 | Type = "APPS",
26 | Name = "5U5T-14G381-AP",
27 | Version = "3.4.19101",
28 | Notes = null,
29 | Url = "https://ivsubinaries.azureedge.net/swparts/5U5T-14G381-AP_1555085337000.TAR.GZ",
30 | Md5 = "98c289f37416a07ba274585350acaa4c",
31 | FileName = "5U5T-14G381-AP_1555085337000.TAR.GZ",
32 | Source = null
33 | };
34 |
35 | IvsuList = new System.Collections.ObjectModel.ObservableCollection() {
36 | new SModel.Ivsu
37 | {
38 | Selected=false,
39 | Type="GRACENOTES",
40 | Name="4U5T-14G423-CA",
41 | Version="1.1.1.1332",
42 | Notes="",
43 | Url="https://ivsubinaries.azureedge.net/swparts/4U5T-14G423-CA_123766.tar.gz",
44 | Md5="95d8331ef437041ec4edd2163c1f2619",
45 | FileName="4U5T-14G423-CA_123766.tar.gz",
46 | Source=null
47 | },
48 | toTest,
49 | new SModel.Ivsu
50 | {
51 | Selected=false,
52 | Type="VOICE",
53 | Name="5U5T-14G391-CL",
54 | Version=null,
55 | Notes=null,
56 | Url="https://ivsubinaries.azureedge.net/swparts/5U5T-14G391-CL_1580862907000.TAR.GZ",
57 | Md5="672fc1d83f6a28fb1ec5ca713d23f050",
58 | FileName="5U5T-14G391-CL_1580862907000.TAR.GZ",
59 | Source=null
60 | },
61 | };
62 | merica = new SModel.SRegion() { Code = "NA", Name = "United States, Canada & Mexico" };
63 | nosavedrive = new USBHelper.Drive() { Name = "Download Only (NO USB)" };
64 | }
65 | //Integration Test
66 | [Test]
67 | public void WhenTheProperParametersArePassedADownloadIsInitiated()
68 | {
69 |
70 | //HomeViewModelService.Download();
71 | //TODO: Capture the Download invoke
72 | }
73 |
74 | //"Unit" test
75 | [Test]
76 | public async Task WhenTheProperParametersArePassedTheStateVariablesAreSetProperly()
77 | {
78 | await HomeViewModelService.SetIvsuList("downgrade", IvsuList, merica, "Sync 3.4.19101", "Non Nav APIM", null);
79 |
80 | Assert.AreEqual(AppMan.App.Ivsus.Count, 4);
81 | Assert.AreEqual(AppMan.App.DriveLetter, null);
82 | Assert.AreEqual(AppMan.App.SelectedRegion, merica.Code);
83 | Assert.AreEqual(AppMan.App.SelectedRelease, "Sync 3.4.19101");
84 | Assert.AreEqual(AppMan.App.SelectedMapVersion, "Non Nav APIM");
85 | //TODO: wire in deep equality checker
86 | Assert.AreEqual(AppMan.App.Ivsus[3].Url, toTest.Url);
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/Syn3Updater.Tests/Services/TestAutoInstalls/mapautoinstall.lst:
--------------------------------------------------------------------------------
1 | [SYNCGen3.0_3.0.1_PRODUCT]
2 | Item1 = MAP_LICENSE - 4U5T-14G424-CD_1616778089000.TAR.GZ
3 | Open1 = SyncMyRide\4U5T-14G424-CD_1616778089000.TAR.GZ
4 | Item2 = VOICE_NAV - 4U5T-14G421-CAD_1615428059000.TAR.GZ
5 | Open2 = SyncMyRide\4U5T-14G421-CAD_1615428059000.TAR.GZ
6 | Item3 = MAP - 4U5T-14G421-CCD_1615428361000.TAR.GZ
7 | Open3 = SyncMyRide\4U5T-14G421-CCD_1615428361000.TAR.GZ
8 | Item4 = MAP - 4U5T-14G421-CHD_1615428793000.TAR.GZ
9 | Open4 = SyncMyRide\4U5T-14G421-CHD_1615428793000.TAR.GZ
10 | Item5 = MAP - 4U5T-14G421-CJD_1615428865000.TAR.GZ
11 | Open5 = SyncMyRide\4U5T-14G421-CJD_1615428865000.TAR.GZ
12 | Options = AutoInstall
13 |
14 | [SYNCGen3.0_3.0.1]
15 | Item1 = MAP - 4U5T-14G421-CDD_1615428467000.TAR.GZ
16 | Open1 = SyncMyRide\4U5T-14G421-CDD_1615428467000.TAR.GZ
17 | Item2 = MAP - 4U5T-14G421-CBD_1615428261000.TAR.GZ
18 | Open2 = SyncMyRide\4U5T-14G421-CBD_1615428261000.TAR.GZ
19 | Item3 = MAP - 4U5T-14G421-CED_1615428554000.TAR.GZ
20 | Open3 = SyncMyRide\4U5T-14G421-CED_1615428554000.TAR.GZ
21 | Item4 = VOICE_NAV - 4U5T-14G422-CCH_1615429127000.TAR.GZ
22 | Open4 = SyncMyRide\4U5T-14G422-CCH_1615429127000.TAR.GZ
23 | Options = AutoInstall, Include, Transaction
24 |
25 | [SYNCGen3.0_ALL]
26 | Item1 = MAP - 4U5T-14G421-CGD_1615428721000.TAR.GZ
27 | Open1 = SyncMyRide\4U5T-14G421-CGD_1615428721000.TAR.GZ
28 | Item2 = MAP - 4U5T-14G421-CAD_1615428059000.TAR.GZ
29 | Open2 = SyncMyRide\4U5T-14G421-CAD_1615428059000.TAR.GZ
30 | Item3 = MAP - 4U5T-14G421-CFD_1615428639000.TAR.GZ
31 | Open3 = SyncMyRide\4U5T-14G421-CFD_1615428639000.TAR.GZ
32 | Item4 = VOICE_NAV - 4U5T-14G422-CBH_1615429039000.TAR.GZ
33 | Open4 = SyncMyRide\4U5T-14G422-CBH_1615429039000.TAR.GZ
34 | Options = Delay, Include, Transaction
35 |
--------------------------------------------------------------------------------
/Syn3Updater.Tests/Syn3Updater.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net472;net5.0-windows10.0.18362.0
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Syn3Updater.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33516.290
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syn3Updater", "Syn3Updater\Syn3Updater.csproj", "{0A3F08DD-2B7B-40A9-A740-7C3BFE4BC2C1}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Launcher", "Launcher\Launcher.csproj", "{400FEC06-C6E7-4A09-80A6-B9A4E750D41A}"
9 | EndProject
10 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Updater.Common", "SharedCode\Updater.Common.shproj", "{285A3E6C-652A-4CA2-9B27-3A4DC4E1177B}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syn3Updater.Tests", "Syn3Updater.Tests\Syn3Updater.Tests.csproj", "{E5D76BA8-D5EF-46F8-8B95-148674590FD8}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {0A3F08DD-2B7B-40A9-A740-7C3BFE4BC2C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {0A3F08DD-2B7B-40A9-A740-7C3BFE4BC2C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {0A3F08DD-2B7B-40A9-A740-7C3BFE4BC2C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {0A3F08DD-2B7B-40A9-A740-7C3BFE4BC2C1}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {400FEC06-C6E7-4A09-80A6-B9A4E750D41A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {400FEC06-C6E7-4A09-80A6-B9A4E750D41A}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {400FEC06-C6E7-4A09-80A6-B9A4E750D41A}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {400FEC06-C6E7-4A09-80A6-B9A4E750D41A}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {E5D76BA8-D5EF-46F8-8B95-148674590FD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {E5D76BA8-D5EF-46F8-8B95-148674590FD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {E5D76BA8-D5EF-46F8-8B95-148674590FD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {E5D76BA8-D5EF-46F8-8B95-148674590FD8}.Release|Any CPU.Build.0 = Release|Any CPU
32 | EndGlobalSection
33 | GlobalSection(SolutionProperties) = preSolution
34 | HideSolutionNode = FALSE
35 | EndGlobalSection
36 | GlobalSection(ExtensibilityGlobals) = postSolution
37 | SolutionGuid = {B67DDE34-44D2-4865-9A54-DAF7D464BDA4}
38 | EndGlobalSection
39 | GlobalSection(SharedMSBuildProjectFiles) = preSolution
40 | SharedCode\SharedCode.projitems*{0a3f08dd-2b7b-40a9-a740-7c3bfe4bc2c1}*SharedItemsImports = 5
41 | SharedCode\SharedCode.projitems*{285a3e6c-652a-4ca2-9b27-3a4dc4e1177b}*SharedItemsImports = 13
42 | SharedCode\SharedCode.projitems*{400fec06-c6e7-4a09-80a6-b9a4e750d41a}*SharedItemsImports = 5
43 | EndGlobalSection
44 | EndGlobal
45 |
--------------------------------------------------------------------------------
/Syn3Updater/App.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
48 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/Syn3Updater/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Runtime.InteropServices;
4 | using System.Windows;
5 | using System.Windows.Threading;
6 |
7 | namespace Cyanlabs.Syn3Updater
8 | {
9 | ///
10 | /// Interaction logic for App.xaml
11 | ///
12 | public partial class App
13 | {
14 | #region Methods
15 |
16 | protected override void OnStartup(StartupEventArgs e)
17 | {
18 | base.OnStartup(e);
19 | {
20 | DispatcherUnhandledException += App_DispatcherUnhandledException;
21 | }
22 | if (SingleInstance.AlreadyRunning())
23 | Current.Shutdown(); // Just shutdown the current application,if any instance found.
24 | AppMan.App.Initialize();
25 | }
26 |
27 | private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
28 | {
29 | AppMan.Logger.CrashWindow(e.Exception);
30 | e.Handled = true;
31 | }
32 |
33 | private void App_OnExit(object sender, ExitEventArgs e)
34 | {
35 | // throw new NotImplementedException();
36 | }
37 |
38 | public sealed class SingleInstance
39 | {
40 | public static bool AlreadyRunning()
41 | {
42 | bool running = false;
43 | try
44 | {
45 | // Getting collection of process
46 | Process currentProcess = Process.GetCurrentProcess();
47 |
48 | // Check with other process already running
49 | foreach (Process p in Process.GetProcesses())
50 | if (p.Id != currentProcess.Id) // Check running process
51 | if (p.ProcessName.Equals(currentProcess.ProcessName))
52 | {
53 | running = true;
54 | IntPtr hFound = p.MainWindowHandle;
55 | User32API.ShowWindow(hFound, 9);
56 | User32API.SetForegroundWindow(hFound); // Activate the window, if process is already running
57 | break;
58 | }
59 | }
60 | catch
61 | {
62 | // ignored
63 | }
64 |
65 | return running;
66 | }
67 | }
68 |
69 | #endregion
70 | }
71 |
72 | public class User32API
73 | {
74 | [DllImport("User32.dll")]
75 | public static extern bool SetForegroundWindow(IntPtr hWnd);
76 |
77 | [DllImport("User32.dll")]
78 | public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
79 | }
80 | }
--------------------------------------------------------------------------------
/Syn3Updater/Converter/BoolToVisibilityConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows;
4 | using System.Windows.Data;
5 |
6 | namespace Cyanlabs.Syn3Updater.Converter
7 | {
8 | [ValueConversion(typeof(bool), typeof(Visibility))]
9 | public class BoolToVisibilityConverter : IValueConverter
10 | {
11 | #region Methods
12 |
13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
14 | {
15 | return value as bool? == true ? Visibility.Visible :
16 | string.Equals(parameter?.ToString(), "true", StringComparison.OrdinalIgnoreCase) ? Visibility.Hidden : Visibility.Collapsed;
17 | }
18 |
19 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
20 | {
21 | return value as Visibility? == Visibility.Visible;
22 | }
23 |
24 | #endregion
25 | }
26 |
27 | public class InvertedBoolToVisibilityConverter : IValueConverter
28 | {
29 | #region Methods
30 |
31 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
32 | {
33 | return value as bool? != true ? Visibility.Visible :
34 | string.Equals(parameter?.ToString(), "false", StringComparison.OrdinalIgnoreCase) ? Visibility.Hidden : Visibility.Collapsed;
35 | }
36 |
37 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
38 | {
39 | return value as Visibility? != Visibility.Visible;
40 | }
41 |
42 | #endregion
43 | }
44 | }
--------------------------------------------------------------------------------
/Syn3Updater/Converter/ESNConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows;
4 | using System.Windows.Data;
5 | using System.Windows.Media;
6 |
7 | namespace Cyanlabs.Syn3Updater.Converter
8 | {
9 | public class ESNConverter : IValueConverter
10 | {
11 | // Convert bool to string
12 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
13 | {
14 | // Handle null values
15 | if (value == null)
16 | {
17 | return ""; // Default value
18 | }
19 |
20 | // Convert bool to string
21 | if (value is bool boolValue)
22 | {
23 |
24 | if (targetType == typeof(string))
25 | {
26 | return boolValue ? "ESN Locked (Pre MY20 Only)" : "Not ESN Locked";
27 | }
28 | else if (targetType == typeof(Brush))
29 | {
30 | return boolValue ? Brushes.Red : Brushes.Green;
31 | }
32 | else if (targetType == typeof(Visibility))
33 | {
34 | return boolValue ? Visibility.Visible : Visibility.Collapsed;
35 | }
36 | else
37 | {
38 | throw new NotSupportedException($"Target type {targetType} is not supported.");
39 | }
40 | }
41 |
42 | // Handle unexpected types
43 | throw new ArgumentException("Value must be a boolean.", nameof(value));
44 | }
45 |
46 | // Convert string back to bool (optional, for two-way binding)
47 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
48 | {
49 | if (value is string stringValue)
50 | {
51 | return stringValue == "ESN Locked (Pre MY20 Only)";
52 | }
53 |
54 | return false; // Default value
55 | }
56 | }
57 |
58 | public class InvertedESNConverter : IValueConverter
59 | {
60 | // Convert bool to string
61 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
62 | {
63 | // Handle null values
64 | if (value == null)
65 | {
66 | return ""; // Default value
67 | }
68 |
69 | // Convert bool to string
70 | if (value is bool boolValue)
71 | {
72 |
73 | if (targetType == typeof(string))
74 | {
75 | return boolValue ? "Not ESN Locked" : "ESN Locked (Pre MY20 Only)";
76 | }
77 | else if (targetType == typeof(Brush))
78 | {
79 | return boolValue ? Brushes.Green : Brushes.Red;
80 | }
81 | else if (targetType == typeof(Visibility))
82 | {
83 | return boolValue ? Visibility.Collapsed : Visibility.Visible;
84 | }
85 | else
86 | {
87 | throw new NotSupportedException($"Target type {targetType} is not supported.");
88 | }
89 | }
90 |
91 | // Handle unexpected types
92 | throw new ArgumentException("Value must be a boolean.", nameof(value));
93 | }
94 |
95 | // Convert string back to bool (optional, for two-way binding)
96 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
97 | {
98 | if (value is string stringValue)
99 | {
100 | return stringValue == "Not ESN Locked";
101 | }
102 |
103 | return false; // Default value
104 | }
105 | }
106 | }
--------------------------------------------------------------------------------
/Syn3Updater/Converter/HexToASCII.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text.RegularExpressions;
5 |
6 | namespace Cyanlabs.Syn3Updater.Converter
7 | {
8 | public static class SyncHexToAscii
9 | {
10 | public static List ConvertPackages( string packageHex)
11 | {
12 | string res = string.Empty;
13 | for (int a = 0; a
7 | /// Helper class for ActionCommands used for MVVM button presses
8 | ///
9 | public class ActionCommand : ICommand
10 | {
11 | #region Constructors
12 |
13 | public ActionCommand(Action command, Func canExecute = null)
14 | {
15 | _command = command;
16 | _canExecute = canExecute;
17 | }
18 |
19 | #endregion
20 |
21 | #region Events
22 |
23 | public event EventHandler CanExecuteChanged;
24 |
25 | #endregion
26 |
27 | #region Properties & Fields
28 |
29 | private readonly Func _canExecute;
30 | private readonly Action _command;
31 |
32 | #endregion
33 |
34 | #region Methods
35 |
36 | public bool CanExecute(object parameter)
37 | {
38 | return _canExecute?.Invoke() ?? true;
39 | }
40 |
41 | public void Execute(object parameter)
42 | {
43 | _command?.Invoke();
44 | }
45 |
46 | public void RaiseCanExecuteChanged()
47 | {
48 | CanExecuteChanged?.Invoke(this, EventArgs.Empty);
49 | }
50 |
51 | #endregion
52 | }
53 | }
--------------------------------------------------------------------------------
/Syn3Updater/Helper/ApiHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using System.Threading.Tasks;
4 | using System.Windows;
5 | using System.Windows.Threading;
6 | using Cyanlabs.Syn3Updater.Model;
7 | using Cyanlabs.Updater.Common;
8 |
9 | namespace Cyanlabs.Syn3Updater.Helper
10 | {
11 | ///
12 | /// Helper class for API functions
13 | ///
14 | public static class ApiHelper
15 | {
16 | #region Methods
17 |
18 | ///
19 | /// Get special IVSU package such as Downgrade or Reformat from our API and passes it to ConvertIvsu
20 | ///
21 | /// SpecialPackage type e.g downgradetool, logtool34 etc.
22 | public static async Task GetSpecialIvsu(string specialPackage)
23 | {
24 | try
25 | {
26 | var graphQlResponse = await AppMan.App.GraphQlClient.SendQueryAsync(GraphQlRequests.GetSpecialPackage(specialPackage));
27 | Api.IvsuRoot ivsu = graphQlResponse.Data;
28 | return ConvertIvsu(ivsu.Ivsus[0]);
29 | }
30 | catch (Exception e)
31 | {
32 | await Application.Current.Dispatcher.BeginInvoke(() => UIHelper.ShowErrorDialog(e.GetFullMessage()));
33 | AppMan.Logger.Info("ERROR: fetching SpecialPackage - " + e.GetFullMessage());
34 | return null;
35 | }
36 | }
37 |
38 | ///
39 | /// Converts a API retrieved Api.Ivsu to SModel.Ivsu
40 | ///
41 | /// SpecialPackage IVSU object from GetSpecialIvsu
42 | /// ivsu as type SModel.Ivsu
43 | public static SModel.Ivsu ConvertIvsu(Api.Ivsu ivsu)
44 | {
45 | return new()
46 | {
47 | Type = ivsu.Type,
48 | Name = ivsu.Name,
49 | Version = ivsu.Version,
50 | Notes = ivsu.Notes,
51 | Url = ivsu.Url,
52 | Md5 = ivsu.Md5,
53 | Selected = true,
54 | FileName = FileHelper.url_to_filename(ivsu.Url).Replace("?dl=1", ""),
55 | FileSize = ivsu.FileSize
56 | };
57 | }
58 |
59 | #endregion
60 | }
61 | }
--------------------------------------------------------------------------------
/Syn3Updater/Helper/EventHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Cyanlabs.Syn3Updater.Helper
4 | {
5 | ///
6 | /// Helper class for EventRaising
7 | ///
8 | public class EventArgs : EventArgs
9 | {
10 | #region Constructors
11 |
12 | public EventArgs(T value, int part)
13 | {
14 | Value = value;
15 | Part = part;
16 | }
17 |
18 | public T Value { get; }
19 | public int Part { get; }
20 |
21 | #endregion
22 | }
23 |
24 | public static class EventRaiser
25 | {
26 | #region Methods
27 |
28 | public static void Raise(this EventHandler> handler, object sender, T value, int part)
29 | {
30 | handler?.Invoke(sender, new EventArgs(value, part));
31 | }
32 |
33 | #endregion
34 | }
35 | }
--------------------------------------------------------------------------------
/Syn3Updater/Helper/ExceptionExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Cyanlabs.Syn3Updater.Helper
4 | {
5 | ///
6 | /// Helper class to extend functionality of Exceptions
7 | ///
8 | public static class ExceptionExtension
9 | {
10 | #region Methods
11 |
12 | ///
13 | /// Recursively get main Exception message and all InnerException messages
14 | ///
15 | /// Exception
16 | ///
17 | /// all innerexception messages as type String
18 | public static string GetFullMessage(this Exception ex, string message = "")
19 | {
20 | if (ex == null) return string.Empty;
21 |
22 | message += ex.Message;
23 |
24 | if (ex.InnerException != null)
25 | message += $"\r\n{GetFullMessage(ex.InnerException)}";
26 |
27 | return message;
28 | }
29 |
30 | #endregion
31 | }
32 |
33 | public class AssemblyModelNotFound : Exception
34 | {
35 | public AssemblyModelNotFound()
36 | {
37 | }
38 |
39 | public AssemblyModelNotFound(string message)
40 | : base(message)
41 | {
42 | }
43 |
44 | public AssemblyModelNotFound(string message, Exception inner)
45 | : base(message, inner)
46 | {
47 | }
48 | }
49 |
50 | public class AssemblyVersionIncompatible : Exception
51 | {
52 | public AssemblyVersionIncompatible()
53 | {
54 | }
55 |
56 | public AssemblyVersionIncompatible(string message)
57 | : base(message)
58 | {
59 | }
60 |
61 | public AssemblyVersionIncompatible(string message, Exception inner)
62 | : base(message, inner)
63 | {
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/Syn3Updater/Helper/GraphQLRequests.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 |
3 | namespace Cyanlabs.Syn3Updater.Helper
4 | {
5 | public class GraphQlRequests
6 | {
7 | public static GraphQLRequest GetAppVersions()
8 | {
9 | return new GraphQLRequest
10 | {
11 | Query = @"
12 | {
13 | ivsu (sort: ""-name"",limit: -1,
14 | filter: {type: { _eq: ""APPS"" }}) {
15 | version
16 | }
17 | }"
18 | };
19 | }
20 |
21 | public static GraphQLRequest IvsuVersionLookup(string ivsuVersion) =>
22 | new()
23 | {
24 | Query = @"
25 | {
26 | ivsu(limit: 1, filter: {name: {_eq: """ + ivsuVersion + @"""}}) {
27 | version
28 | }
29 | }"
30 | };
31 |
32 | public static GraphQLRequest GetReleases(string selectedRegion)
33 | {
34 | return new GraphQLRequest
35 | {
36 | Query = @"
37 | {
38 | releases (
39 | sort: ""-name"",
40 | limit: -1,
41 | filter: {
42 | status: { _in: [""published"", ""private""] },
43 | key: { _in: [""public"", ""v2"", """ + AppMan.App.MainSettings.LicenseKey + @"""]},
44 | regions: {_contains: """ + selectedRegion + @"""},
45 | }
46 | ) {
47 | name, notes, regions, version, feedbackurl
48 | }
49 | }"
50 | };
51 | }
52 |
53 | public static GraphQLRequest GetMapReleases(string selectedRegion, string license, string compat)
54 | {
55 | return new GraphQLRequest
56 | {
57 | Query = @"
58 | {
59 | map_releases(sort: ""-name"", limit: -1,
60 | filter: {_and:
61 | [{ _or: [ {licensekeys: { _null: true}}, {licensekeys: { _empty: true}}," + license + @"],
62 | status: { _in: [""published"", ""private""] }, regions: {_in: """ + selectedRegion + @"""},
63 | " + "" + @"compatibility: {_contains: """ + compat + @"""} }]
64 | }){ name, regions, esn }
65 | }"
66 | };
67 | }
68 |
69 | public static GraphQLRequest GetReleaseIvsus(string selectedRelease, string navtype)
70 | {
71 | return new GraphQLRequest
72 | {
73 | Query = @"
74 | {
75 | releases(limit: -1, filter: {name: {_eq: """ + selectedRelease + @"""}}) {
76 | name
77 | ivsus {
78 | ivsu(filter: {navtype: { _in: [""" + navtype + @""",""all""]}}) {
79 | id, name, type, version, notes, url, md5, filesize, regions}
80 | }
81 | }
82 | }"
83 | };
84 | }
85 |
86 | public static GraphQLRequest GetMapReleaseIvsus(string selectedMapVersion)
87 | {
88 | return new GraphQLRequest
89 | {
90 | Query = @"
91 | {
92 | map_releases(limit: -1, filter: {name: {_eq: """ + selectedMapVersion + @"""}}) {
93 | name
94 | ivsus {
95 | map_ivsu { id, name, type, version, notes, url, md5, filesize, regions, source}
96 | }
97 | }
98 | }"
99 | };
100 | }
101 |
102 | public static GraphQLRequest GetNotices()
103 | {
104 | return new GraphQLRequest
105 | {
106 | Query = @"
107 | {
108 | notices(limit: -1, filter: {enabled: {_eq: true}}) {
109 | id, title, notice, date_created, date_updated, important
110 | }
111 | }"
112 | };
113 | }
114 |
115 | public static GraphQLRequest GetUserAgents()
116 | {
117 | return new GraphQLRequest
118 | {
119 | Query = @"
120 | {
121 | useragents {
122 | useragent,min,max
123 | }
124 | }"
125 | };
126 | }
127 |
128 | public static GraphQLRequest GetMy20Models()
129 | {
130 | return new GraphQLRequest
131 | {
132 | Query = @"
133 | {
134 | my20models {
135 | model
136 | }
137 | }"
138 | };
139 | }
140 |
141 | public static GraphQLRequest GetSpecialPackage(string packageName)
142 | {
143 | return new GraphQLRequest
144 | {
145 | Query = @"
146 | {
147 | ivsu(limit: 1, filter: {specialpackage: {_eq: """+ packageName + @"""}}) {
148 | id, name, type, regions, md5, url, version, filesize, notes, navtype, specialpackage
149 | }
150 | }"
151 | };
152 | }
153 | }
154 | }
--------------------------------------------------------------------------------
/Syn3Updater/Helper/MathHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 |
4 | namespace Cyanlabs.Syn3Updater.Helper
5 | {
6 | ///
7 | /// Helper class for various extra math methods
8 | ///
9 | public static class MathHelper
10 | {
11 | #region Methods
12 |
13 | public static double GetDouble(this string value, double defaultValue = 0)
14 | {
15 | //Try parsing in the current culture
16 | if (!double.TryParse(value, NumberStyles.Any, CultureInfo.CurrentCulture, out double result) &&
17 | //Then try in US english
18 | !double.TryParse(value, NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out result) &&
19 | //Then in neutral language
20 | !double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
21 | result = defaultValue;
22 |
23 | return result;
24 | }
25 |
26 | public static double Clamp(double value, double min, double max)
27 | {
28 | return Math.Max(min, Math.Min(max, value));
29 | }
30 |
31 | public static float Clamp(float value, float min, float max)
32 | {
33 | return (float) Clamp((double) value, min, max);
34 | }
35 |
36 | public static int Clamp(int value, int min, int max)
37 | {
38 | return Math.Max(min, Math.Min(max, value));
39 | }
40 |
41 | public static string BytesToString(long byteCount)
42 | {
43 | string[] suf = {"B", "KB", "MB", "GB", "TB", "PB", "EB"}; //Longs run out around EB
44 | if (byteCount == 0) return $"0{suf[0]}";
45 |
46 | long bytes = Math.Abs(byteCount);
47 | int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
48 | double num = Math.Round(bytes / Math.Pow(1024, place), 1);
49 | return Math.Sign(byteCount) * num + suf[place];
50 | }
51 |
52 | public static bool IsOdd(int value)
53 | {
54 | return value % 2 != 0;
55 | }
56 |
57 | #endregion
58 | }
59 | }
--------------------------------------------------------------------------------
/Syn3Updater/Helper/SanityCheckHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows;
6 | using System.Windows.Threading;
7 | using Cyanlabs.Syn3Updater.Model;
8 | using ModernWpf.Controls;
9 |
10 | namespace Cyanlabs.Syn3Updater.Helper
11 | {
12 | ///
13 | /// Helper class to "Sanity Check" before running the main methods to prevent user error etc
14 | ///
15 | public static class SanityCheckHelper
16 | {
17 | ///
18 | /// A multi-section check to ensure nothing prevents the download from beginning
19 | ///
20 | /// USB Drive
21 | /// true/false as Boolean depending on if Download is cancelled or not
22 | public static async Task CancelDownloadCheck(USBHelper.Drive selectedDrive)
23 | {
24 | // Set local variables to the values of application level variables
25 | string driveLetter = AppMan.App.DriveLetter;
26 | string downloadPath = AppMan.App.DownloadPath;
27 |
28 | // Ensure drive letter is not used as download path
29 | if (!string.IsNullOrEmpty(driveLetter))
30 | if (downloadPath.Contains(driveLetter))
31 | {
32 | await Application.Current.Dispatcher.BeginInvoke(() => UIHelper.ShowErrorDialog(LM.GetValue("MessageBox.CancelDownloadIsDrive")));
33 | return true;
34 | }
35 |
36 | // Optional Format
37 | if (string.IsNullOrWhiteSpace(selectedDrive?.Path) && driveLetter != null)
38 | {
39 | try
40 | {
41 | if (Directory.EnumerateFileSystemEntries(driveLetter, "*", SearchOption.AllDirectories).Any())
42 | {
43 | if (await Application.Current.Dispatcher.Invoke(() => UIHelper.ShowDialog(string.Format(LM.GetValue("MessageBox.OptionalFormat"), driveLetter), LM.GetValue("String.Notice"), LM.GetValue("String.No"),
44 | LM.GetValue("String.Yes"))) == ContentDialogResult.Primary)
45 | {
46 | AppMan.App.SkipFormat = false;
47 | }
48 | else
49 | {
50 | AppMan.Logger.Info("Selected folder will not be cleared before being used");
51 | AppMan.App.SkipFormat = true;
52 | }
53 | }
54 | else
55 | {
56 | AppMan.App.SkipFormat = true;
57 | }
58 | }
59 | catch (DirectoryNotFoundException e)
60 | {
61 | await Application.Current.Dispatcher.BeginInvoke(() => UIHelper.ShowErrorDialog(e.GetFullMessage()));
62 | return true;
63 | }
64 | catch (IOException e)
65 | {
66 | await Application.Current.Dispatcher.BeginInvoke(() => UIHelper.ShowErrorDialog(e.GetFullMessage()));
67 | return true;
68 | }
69 |
70 | }
71 | else
72 | {
73 | if (selectedDrive?.FileSystem == "exFAT" && selectedDrive?.PartitionType == "MBR" && selectedDrive?.VolumeName == "CYANLABS")
74 | {
75 | if (await Application.Current.Dispatcher.Invoke(() => UIHelper.ShowDialog(string.Format(LM.GetValue("MessageBox.OptionalFormatUSB"), selectedDrive.Name, driveLetter), LM.GetValue("String.Notice"),
76 | LM.GetValue("String.No"), LM.GetValue("String.Yes"))) == ContentDialogResult.Primary)
77 | {
78 | AppMan.App.SkipFormat = false;
79 | }
80 | else
81 | {
82 | AppMan.Logger.Info("USB Drive not formatted, using existing filesystem and files");
83 | AppMan.App.SkipFormat = true;
84 | }
85 | }
86 | }
87 |
88 | // Format USB Drive
89 | if (selectedDrive != null && !string.IsNullOrWhiteSpace(selectedDrive.Path) && !AppMan.App.SkipFormat)
90 | if (await Application.Current.Dispatcher.Invoke(() => UIHelper.ShowWarningDialog(string.Format(LM.GetValue("MessageBox.CancelFormatUSB"), selectedDrive.Name, driveLetter), LM.GetValue("String.Warning") + "!",
91 | LM.GetValue("String.No"), LM.GetValue("String.Yes"))) != ContentDialogResult.Primary)
92 | return true;
93 |
94 | if (selectedDrive != null && selectedDrive?.Name == LM.GetValue("Home.NoUSBDir"))
95 | {
96 | AppMan.Logger.Info("Using 'Select a Directory' instead of a USB Drive");
97 | AppMan.App.DownloadToFolder = true;
98 | if (string.IsNullOrEmpty(driveLetter)) return true;
99 |
100 | if (Directory.EnumerateFiles(driveLetter).Any() && !AppMan.App.SkipFormat)
101 | if (await Application.Current.Dispatcher.Invoke(() => UIHelper.ShowWarningDialog(string.Format(LM.GetValue("MessageBox.CancelDeleteFiles"), driveLetter), LM.GetValue("String.Warning") + "!",
102 | LM.GetValue("String.No"), LM.GetValue("String.Yes"))) != ContentDialogResult.Primary)
103 | return true;
104 | }
105 | else
106 | {
107 | AppMan.App.DownloadToFolder = false;
108 | }
109 |
110 | // If nothing above has returned true then download has not been cancelled and method will return false;
111 | return false;
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/Syn3Updater/Helper/SystemHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Management;
4 | using System.Runtime.InteropServices;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Threading;
8 | using Cyanlabs.Syn3Updater.Model;
9 | using Microsoft.Win32;
10 |
11 | namespace Cyanlabs.Syn3Updater.Helper
12 | {
13 | ///
14 | /// Helper class containing methods to retrieve specific file system paths.
15 | /// https://stackoverflow.com/a/21953690
16 | ///
17 | public static class SystemHelper
18 | {
19 | #region Properties & Fields
20 |
21 | [DllImport("Shell32.dll")]
22 | private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr ppszPath);
23 |
24 | [Flags]
25 | private enum KnownFolderFlags : uint
26 | {
27 | DontVerify = 0x00004000
28 | }
29 |
30 | private static readonly string[] KnownFolderGuids =
31 | {
32 | "{374DE290-123F-4565-9164-39C4925E467B}" // Downloads
33 | };
34 |
35 | public enum KnownFolder
36 | {
37 | Downloads
38 | }
39 |
40 | #endregion
41 |
42 | #region Methods
43 |
44 | ///
45 | /// Gets the current path to the specified known folder as currently configured. This does
46 | /// not require the folder to be existent.
47 | ///
48 | /// The known folder which current path will be returned.
49 | /// The default path of the known folder.
50 | ///
51 | /// Thrown if the path
52 | /// could not be retrieved.
53 | ///
54 | public static string GetPath(KnownFolder knownFolder)
55 | {
56 | return GetPath(knownFolder, false);
57 | }
58 |
59 | ///
60 | /// Gets the current path to the specified known folder as currently configured. This does
61 | /// not require the folder to be existent.
62 | ///
63 | /// The known folder which current path will be returned.
64 | ///
65 | /// Specifies if the paths of the default user (user profile
66 | /// template) will be used. This requires administrative rights.
67 | ///
68 | /// The default path of the known folder.
69 | ///
70 | /// Thrown if the path
71 | /// could not be retrieved.
72 | ///
73 | public static string GetPath(KnownFolder knownFolder, bool defaultUser)
74 | {
75 | return GetPath(knownFolder, KnownFolderFlags.DontVerify, defaultUser);
76 | }
77 |
78 | private static string GetPath(KnownFolder knownFolder, KnownFolderFlags flags, bool defaultUser)
79 | {
80 | int result = SHGetKnownFolderPath(new Guid(KnownFolderGuids[(int) knownFolder]), (uint) flags, new IntPtr(defaultUser ? -1 : 0), out IntPtr outPath);
81 | if (result >= 0)
82 | {
83 | string path = Marshal.PtrToStringUni(outPath);
84 | Marshal.FreeCoTaskMem(outPath);
85 | return path;
86 | }
87 |
88 | throw new ExternalException("Unable to retrieve the known folder path. It may not be available on this system.", result);
89 | }
90 |
91 | public static string GetOsFriendlyName()
92 | {
93 | string result = string.Empty;
94 | ManagementObjectSearcher searcher = new("SELECT Caption FROM Win32_OperatingSystem");
95 | foreach (ManagementBaseObject o in searcher.Get())
96 | {
97 | ManagementObject os = (ManagementObject) o;
98 | result = os["Caption"].ToString();
99 | break;
100 | }
101 |
102 | return $"{result} ({Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", "")})";
103 | }
104 |
105 | public static void WriteRegistryHandler()
106 | {
107 | try
108 | {
109 | Registry.CurrentUser.CreateSubKey(@"Software\Classes\syn3updater\Shell\Open\Command");
110 | Registry.CurrentUser.OpenSubKey(@"Software\Classes\syn3updater", true)?.SetValue("", "URL:syn3updater protocol");
111 | Registry.CurrentUser.OpenSubKey(@"Software\Classes\syn3updater", true)?.SetValue("URL Protocol", "");
112 | Registry.CurrentUser.OpenSubKey(@"Software\Classes\syn3updater\Shell\Open\Command", true)
113 | ?.SetValue("", $"\"{AppDomain.CurrentDomain.BaseDirectory}Launcher.exe\" %1");
114 | }
115 | catch
116 | {
117 | // ignored
118 | }
119 | }
120 |
121 | public static void DeleteRegistryHandler()
122 | {
123 | Registry.CurrentUser.DeleteSubKeyTree(@"Software\Classes\syn3updater");
124 | }
125 |
126 | public static async Task OpenWebPage(string url)
127 | {
128 | try
129 | {
130 | Process.Start(url);
131 | }
132 | catch (System.ComponentModel.Win32Exception)
133 | {
134 | Clipboard.SetText(url);
135 | await Application.Current.Dispatcher.BeginInvoke(() => UIHelper.ShowDialog(LM.GetValue("MessageBox.NoBrowser"),LM.GetValue("String.Notice"),LM.GetValue("Download.CancelButton")));
136 | }
137 | }
138 |
139 | #endregion
140 | }
141 | }
--------------------------------------------------------------------------------
/Syn3Updater/Helper/UIHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using System.Windows;
5 | using System.Windows.Media;
6 | using System.Windows.Threading;
7 | using Cyanlabs.Syn3Updater.Model;
8 | using ModernWpf.Controls;
9 |
10 | namespace Cyanlabs.Syn3Updater.Helper
11 | {
12 | ///
13 | /// Helper class containing methods to retrieve specific file system paths.
14 | /// https://stackoverflow.com/a/21953690
15 | ///
16 | public static class UIHelper
17 | {
18 | #region Methods
19 |
20 | ///
21 | ///
22 | ///
23 | ///
24 | ///
25 | ///
26 | ///
27 | ///
28 | ///
29 | public static async Task ShowErrorDialog(string content, string cancel = null)
30 | {
31 | try
32 | {
33 | SequentialDialog contentDialog = new()
34 | {
35 | Title = LM.GetValue("String.Error"),
36 | Content = content,
37 | CloseButtonText = string.IsNullOrEmpty(cancel) ? LM.GetValue("String.OK") : cancel,
38 | Background = Brushes.DarkRed,
39 | Foreground = Brushes.White
40 | };
41 | await DialogManager.OpenDialogAsync(contentDialog, true);
42 | }
43 | catch (InvalidOperationException)
44 | {
45 |
46 | }
47 | }
48 |
49 | public static async Task ShowWarningDialog(string content, string title, string cancel, string primarybutton, string secondarybutton = null)
50 | {
51 | try
52 | {
53 | SequentialDialog contentDialog = new()
54 | {
55 | Title = title,
56 | Content = content,
57 | CloseButtonText = cancel,
58 | Background = Brushes.DarkGoldenrod
59 | };
60 | if (!string.IsNullOrEmpty(primarybutton)) contentDialog.PrimaryButtonText = primarybutton;
61 | if (!string.IsNullOrEmpty(secondarybutton)) contentDialog.SecondaryButtonText = secondarybutton;
62 | return await DialogManager.OpenDialogAsync(contentDialog, true);
63 | }
64 | catch (InvalidOperationException)
65 | {
66 | return ContentDialogResult.None;
67 | }
68 | }
69 |
70 | public static async Task ShowDialog(string content, string title, string cancel, string primarybutton = null, string secondarybutton = null,
71 | ContentDialogButton defaultbutton = ContentDialogButton.None, Brush bg = null)
72 | {
73 | SequentialDialog contentDialog = new()
74 | {
75 | Title = title,
76 | Content = content,
77 | CloseButtonText = cancel,
78 |
79 | };
80 | if (bg != null)
81 | {
82 | contentDialog.Background = bg;
83 | contentDialog.Foreground = Brushes.White;
84 | }
85 | if (!string.IsNullOrEmpty(primarybutton)) contentDialog.PrimaryButtonText = primarybutton;
86 | if (defaultbutton != ContentDialogButton.None) contentDialog.DefaultButton = defaultbutton;
87 | if (!string.IsNullOrEmpty(secondarybutton)) contentDialog.SecondaryButtonText = secondarybutton;
88 | return await DialogManager.OpenDialogAsync(contentDialog, true);
89 | }
90 | }
91 |
92 | #endregion
93 | }
94 |
95 | // https://github.com/microsoft/microsoft-ui-xaml/issues/1679#issuecomment-603214112
96 | public class SequentialDialog : ContentDialog
97 | {
98 | public bool IsAborted;
99 | }
100 |
101 | public static class DialogManager
102 | {
103 | public static SequentialDialog ActiveDialog;
104 | private static TaskCompletionSource _dialogAwaiter = new();
105 |
106 | public static async Task OpenDialogAsync(SequentialDialog dialog, bool awaitPreviousDialog)
107 | {
108 | return await OpenDialog(dialog, awaitPreviousDialog);
109 | }
110 |
111 | static async Task OpenDialog(SequentialDialog dialog, bool awaitPreviousDialog)
112 | {
113 | TaskCompletionSource currentAwaiter = _dialogAwaiter;
114 | TaskCompletionSource nextAwaiter = new();
115 | _dialogAwaiter = nextAwaiter;
116 |
117 | if (ActiveDialog != null)
118 | {
119 | if (awaitPreviousDialog)
120 | {
121 | await currentAwaiter.Task;
122 | }
123 | else
124 | {
125 | ActiveDialog.IsAborted = true;
126 | ActiveDialog.Hide();
127 | }
128 | }
129 |
130 | ActiveDialog = dialog;
131 | ContentDialogResult result = await ActiveDialog.ShowAsync();
132 | nextAwaiter.SetResult(true);
133 | return result;
134 | }
135 | }
--------------------------------------------------------------------------------
/Syn3Updater/Model/APIModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using GraphQL;
3 | using Newtonsoft.Json;
4 |
5 | namespace Cyanlabs.Syn3Updater.Model
6 | {
7 | /*
8 | ///
9 | /// Class to store the API Token, this is a duplicate with palceholder token
10 | /// of the file APISecretModel.cs which is not included in the GitHub Repo
11 | ///
12 | public static class ApiSecret
13 | {
14 | public const string Token = "TOKEN";
15 | }
16 | */
17 |
18 | ///
19 | /// Class for Api related properties and models
20 | /// Json Classes for parsing JSON correctly
21 | ///
22 | public static class Api
23 | {
24 | #region Properties & Fields
25 | public const string Syn3UpdaterGraphQl = "https://syn3updater.cyanlabs.net/graphql";
26 |
27 | public const string APIBase = "https://api.cyanlabs.net/";
28 | private const string AsBuiltBase = "https://cyanlabs.net/fhub/sync3/apim-asbuilt-decoder/";
29 |
30 | public const string CrashLogUrl = "https://cyanlabs.net/syn3-updater-crash-log/?uuid=";
31 | public const string LogUrl = "https://cyanlabs.net/syn3-updater-log/?uuid=";
32 | public const string CrashLogPost = APIBase + "Syn3Updater/crash-logs/post.php";
33 | public const string LogPost = APIBase + "Syn3Updater/logs/post.php";
34 | public const string ChangelogURL = APIBase + "app/syn3updater/githubchangelog/json";
35 |
36 | public const int BlacklistedVersion = 3419274;
37 | public const int ReformatVersion = 3200000;
38 |
39 | public static SModel.Ivsu ReformatTool, DowngradeAppIvsu, DowngradeToolIvsu, InterrogatorTool, GracenotesRemoval, SmallVoicePackage, RWDataCleaner, Upgrade22App;
40 |
41 | public const string AsBuiltPost = APIBase + "Syn3Updater/apim-asbuilt-decode/";
42 | public const string AsBuiltOutput = AsBuiltBase + "?filename=";
43 |
44 | public static class SpecialPackages
45 | {
46 | public const string
47 | DowngradeApp = "downgradeapp",
48 | DowngradeTool = "gracenotesremoval",
49 | LogToolAD = "logtool34-2",
50 | LogToolAC = "logtool34",
51 | LogToolAB = "logtool32",
52 | LogToolAA = "logtool30",
53 | GraceNotesRemoval = "gracenotesremoval",
54 | SmallVoice = "smallvoice",
55 | Reformat = "reformat",
56 | RWDataCleaner = "rwdatacleaner",
57 | Upgrade22App = "upgrade22";
58 | }
59 | #endregion
60 |
61 | #region JSONClasses
62 |
63 | public class ReleasesRoot
64 | {
65 | [JsonProperty("releases")] public IList Releases { get; set; }
66 | [JsonProperty("map_releases")] public IList MapReleases { get; set; }
67 | }
68 |
69 | public class IvsuRoot
70 | {
71 | [JsonProperty("ivsu")] public IList Ivsus { get; set; }
72 | }
73 |
74 | public class NoticesRoot
75 | {
76 | [JsonProperty("notices")] public IList Notices { get; set; }
77 | }
78 |
79 | public class UseragentRoot
80 | {
81 | [JsonProperty("useragents")] public IList UserAgents { get; set; }
82 | }
83 |
84 | public class Release
85 | {
86 | [JsonProperty("id")] public int Id { get; set; }
87 | [JsonProperty("name")] public string Name { get; set; }
88 | [JsonProperty("map_version")] public string MapVersion { get; set; }
89 | [JsonProperty("notes")] public string Notes { get; set; }
90 | [JsonProperty("regions")] public IList Regions { get; set; }
91 | [JsonProperty("version")] public string Version { get; set; }
92 | [JsonProperty("feedbackurl")] public string Feedbackurl { get; set; }
93 | [JsonProperty("status")] public string Status { get; set; }
94 | [JsonProperty("ivsus")] public IList IvsusList { get; set; }
95 | [JsonProperty("esn")] public bool ESN { get; set; }
96 | public bool IsEnabled { get; set; } = true;
97 | }
98 |
99 | public class ReleasesIvsus
100 | {
101 | [JsonProperty("id")] public int Id { get; set; }
102 | [JsonProperty("ivsu")] public Ivsu Ivsu { get; set; }
103 | [JsonProperty("map_ivsu")] public Ivsu MapIvsu { get; set; }
104 | [JsonProperty("release")] public Release Release { get; set; }
105 | }
106 |
107 | public class Ivsu
108 | {
109 | [JsonProperty("id")] public int Id { get; set; }
110 | [JsonProperty("name")] public string Name { get; set; }
111 | [JsonProperty("type")] public string Type { get; set; }
112 | [JsonProperty("regions")] public IList Regions { get; set; }
113 | [JsonProperty("md5")] public string Md5 { get; set; }
114 | [JsonProperty("url")] public string Url { get; set; }
115 | [JsonProperty("notes")] public string Notes { get; set; }
116 | [JsonProperty("version")] public string Version { get; set; }
117 | [JsonProperty("filesize")] public long FileSize { get; set; }
118 | [JsonProperty("source")] public string Source { get; set; }
119 | [JsonProperty("specialpackage")] public string SpecialPackage { get; set; }
120 | }
121 |
122 | public class UserAgent
123 | {
124 | [JsonProperty("useragent")] public string Useragent { get; set; }
125 | [JsonProperty("min")] public int Min { get; set; }
126 | [JsonProperty("max")] public int Max { get; set; }
127 | }
128 |
129 |
130 | public class My20Models
131 | {
132 | [JsonProperty("model")] public string Model { get; set; }
133 | }
134 |
135 | public class My20ModelsRoot
136 | {
137 | [JsonProperty("my20models")] public List My20Models { get; set; }
138 | }
139 |
140 | public class Notice
141 | {
142 | [JsonProperty("id")] public int Id { get; set; }
143 | [JsonProperty("date_created")] public string DateCreated { get; set; }
144 | [JsonProperty("date_updated")] public string DateUpdated { get; set; }
145 | [JsonProperty("notice")] public string NoticeContent { get; set; }
146 | [JsonProperty("title")] public string Title { get; set; }
147 | [JsonProperty("enabled")] public bool Enabled { get; set; }
148 | [JsonProperty("important")] public bool Important { get; set; }
149 | }
150 |
151 | public class Changelogs
152 | {
153 | [JsonProperty("data")] public IList Changelog { get; set; }
154 | }
155 |
156 | public class Changelog
157 | {
158 | [JsonProperty("version")] public string Version { get; set; }
159 | [JsonProperty("date")] public string Date { get; set; }
160 | [JsonProperty("changelog")] public string ReleaseNotes { get; set; }
161 | [JsonProperty("branch")] public string Branch { get; set; }
162 | }
163 | #endregion
164 | }
165 | }
--------------------------------------------------------------------------------
/Syn3Updater/Model/AsBuiltModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | // ReSharper disable InconsistentNaming
5 |
6 | namespace Cyanlabs.Syn3Updater.Model
7 | {
8 | ///
9 | /// Json Class to parse the AsBuilt and post to it to our API
10 | ///
11 | public static class AsBuilt
12 | {
13 | public class DID
14 | {
15 | [JsonProperty("@ID")] public string ID { get; set; }
16 | [JsonProperty("#text")] public string Text { get; set; }
17 | }
18 |
19 | public class VEHICLE
20 | {
21 | [JsonProperty("@MODULE")] public string MODULE { get; set; }
22 | [JsonProperty("@VIN")] public string VIN { get; set; }
23 | [JsonProperty("@VEHICLE_ID")] public string VEHICLEID { get; set; }
24 | [JsonProperty("@VEHICLE_YEAR")] public string VEHICLEYEAR { get; set; }
25 | public List DID { get; set; }
26 | }
27 |
28 | public class DirectConfiguration
29 | {
30 | public VEHICLE VEHICLE { get; set; }
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/Syn3Updater/Model/BaseViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace Cyanlabs.Syn3Updater.Model
5 | {
6 | ///
7 | ///
8 | /// Represents a basic bindable class which notifies when a property value changes.
9 | ///
10 | public abstract class BaseViewModel : IBindable
11 | {
12 | #region Events
13 |
14 | ///
15 | /// Occurs when a property value changes.
16 | ///
17 | public event PropertyChangedEventHandler PropertyChanged;
18 |
19 | #endregion
20 |
21 | #region Methods
22 |
23 | ///
24 | /// Checks if the property already matches the desired value or needs to be updated.
25 | ///
26 | /// Type of the property.
27 | /// Reference to the backing-filed.
28 | /// Value to apply.
29 | ///
30 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
31 | protected virtual bool RequiresUpdate(ref T storage, T value)
32 | {
33 | return !Equals(storage, value);
34 | }
35 |
36 | ///
37 | /// Checks if the property already matches the desired value and updates it if not.
38 | ///
39 | /// Type of the property.
40 | /// Reference to the backing-filed.
41 | /// Value to apply.
42 | ///
43 | /// Name of the property used to notify listeners. This value is optional
44 | /// and can be provided automatically when invoked from compilers that support
45 | /// .
46 | ///
47 | /// true if the value was changed, false if the existing value matched the desired value.
48 | protected virtual bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null)
49 | {
50 | if (!RequiresUpdate(ref storage, value)) return false;
51 |
52 | storage = value;
53 | // ReSharper disable once ExplicitCallerInfoArgument
54 | OnPropertyChanged(propertyName);
55 | return true;
56 | }
57 |
58 | ///
59 | /// Triggers the -event when a a property value has changed.
60 | ///
61 | ///
62 | /// Name of the property used to notify listeners. This value is optional
63 | /// and can be provided automatically when invoked from compilers that support
64 | /// .
65 | ///
66 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
67 | {
68 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
69 | }
70 |
71 | #endregion
72 | }
73 |
74 | ///
75 | /// Represents a basic bindable class which notifies when a property value changes.
76 | ///
77 | public interface IBindable : INotifyPropertyChanged
78 | {
79 | }
80 | }
--------------------------------------------------------------------------------
/Syn3Updater/Model/InterrogatorModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Newtonsoft.Json;
4 | using Newtonsoft.Json.Linq;
5 |
6 | namespace Cyanlabs.Syn3Updater.Model
7 | {
8 | ///
9 | /// Json Class to parse the Interrogator log Direct Configuration XML to JSON
10 | ///
11 | public static class Interrogator
12 | {
13 | public class InterrogatorModel
14 | {
15 | [JsonProperty("?xml")] public Xml Xml { get; set; }
16 | [JsonProperty("p:OTAModuleSnapShot")] public POtaModuleSnapShot POtaModuleSnapShot { get; set; }
17 | }
18 |
19 | public class POtaModuleSnapShot
20 | {
21 | [JsonProperty("@xmlns:d2p1")] public string XmlnsD2P1 { get; set; }
22 | [JsonProperty("@xmlns:xsi")] public Uri XmlnsXsi { get; set; }
23 | [JsonProperty("@xmlns:p")] public string XmlnsP { get; set; }
24 | [JsonProperty("@version")] public DateTimeOffset Version { get; set; }
25 | [JsonProperty("@xsi:schemaLocation")] public string XsiSchemaLocation { get; set; }
26 | [JsonProperty("p:VIN")] public string PVin { get; set; }
27 | [JsonProperty("p:ModuleName")] public string PModuleName { get; set; }
28 | [JsonProperty("p:RequestRole")] public PRequestRole PRequestRole { get; set; }
29 | [JsonProperty("p:BroadcastDTCType")] public object PBroadcastDtcType { get; set; }
30 | [JsonProperty("p:Node")] public PNode PNode { get; set; }
31 | }
32 |
33 | public class PNode
34 | {
35 | [JsonProperty("@isFlashed")] public bool IsFlashed { get; set; }
36 |
37 | [JsonProperty("@specificationCategory")]
38 | public string SpecificationCategory { get; set; }
39 |
40 | [JsonProperty("d2p1:Address")] public string D2P1Address { get; set; }
41 | [JsonProperty("d2p1:ECUAcronym")] public D2P1EcuAcronym D2P1EcuAcronym { get; set; }
42 | [JsonProperty("d2p1:ODLNetwork")] public D2P1OdlNetwork D2P1OdlNetwork { get; set; }
43 |
44 | [JsonProperty("d2p1:AdditionalAttributes")]
45 | public D2P1AdditionalAttributes D2P1AdditionalAttributes { get; set; }
46 | }
47 |
48 | public class D2P1AdditionalAttributes
49 | {
50 | [JsonProperty("@logGeneratedDateTime")]
51 | public DateTimeOffset LogGeneratedDateTime { get; set; }
52 |
53 | [JsonProperty("@RAM")] public long Ram { get; set; }
54 | [JsonProperty("@vmcuVersion")] public string VmcuVersion { get; set; }
55 |
56 | [JsonProperty("d2p1:PartitionHealth")][JsonConverter(typeof(SingleOrArrayConverter))] public List D2P1PartitionHealth { get; set; }
57 | [JsonProperty("d2p1:InstallationLog")] public object D2P1InstallationLog { get; set; }
58 | [JsonProperty("d2p1:SyncData")] public string D2P1SData { get; set; }
59 | }
60 |
61 | public class D2P1PartitionHealth
62 | {
63 | [JsonProperty("@type")] public string Type { get; set; }
64 | [JsonProperty("@total")] public string Total { get; set; }
65 | [JsonProperty("@available")] public string Available { get; set; }
66 | }
67 |
68 | public class D2P1EcuAcronym
69 | {
70 | [JsonProperty("@name")] public string Name { get; set; }
71 | [JsonProperty("d2p1:State")] public D2P1State D2P1State { get; set; }
72 | }
73 |
74 | public class D2P1State
75 | {
76 | [JsonProperty("d2p1:Gateway")] public D2P1Gateway D2P1Gateway { get; set; }
77 | }
78 |
79 | public class D2P1Gateway
80 | {
81 | [JsonProperty("@gatewayType")] public string GatewayType { get; set; }
82 | [JsonProperty("d2p1:DID")] public D2P1Did[] D2P1Did { get; set; }
83 | }
84 |
85 | public class D2P1Did
86 | {
87 | [JsonProperty("@didFormat", NullValueHandling = NullValueHandling.Ignore)]
88 | public string DidFormat { get; set; }
89 |
90 | [JsonProperty("@didType")] public string DidType { get; set; }
91 | [JsonProperty("@didValue")] public string DidValue { get; set; }
92 |
93 | [JsonProperty("@responseLength", NullValueHandling = NullValueHandling.Ignore)]
94 | public long? ResponseLength { get; set; }
95 |
96 | [JsonProperty("d2p1:Response")] public string D2P1Response { get; set; }
97 | [JsonProperty("d2p1:IsConfig")] public bool D2P1IsConfig { get; set; }
98 | }
99 |
100 | public class D2P1OdlNetwork
101 | {
102 | [JsonProperty("@d2p1:NetworkDataRate")]
103 | public long D2P1NetworkDataRate { get; set; }
104 |
105 | [JsonProperty("@d2p1:NetworkName")] public string D2P1NetworkName { get; set; }
106 |
107 | [JsonProperty("@d2p1:NetworkProtocol")]
108 | public string D2P1NetworkProtocol { get; set; }
109 |
110 | [JsonProperty("@d2p1:DLCName")] public string D2P1DlcName { get; set; }
111 | [JsonProperty("@d2p1:Pins")] public string D2P1Pins { get; set; }
112 | }
113 |
114 | public class PRequestRole
115 | {
116 | [JsonProperty("d2p1:Role")] public string D2P1Role { get; set; }
117 | [JsonProperty("d2p1:RoleSource")] public string D2P1RoleSource { get; set; }
118 | [JsonProperty("d2p1:RoleDesc")] public string D2P1RoleDesc { get; set; }
119 | [JsonProperty("d2p1:RoleID")] public string D2P1RoleId { get; set; }
120 | }
121 |
122 | public class Xml
123 | {
124 | [JsonProperty("@version")] public string Version { get; set; }
125 | [JsonProperty("@encoding")] public string Encoding { get; set; }
126 | }
127 | }
128 |
129 | public class SingleOrArrayConverter : JsonConverter
130 | {
131 | public override bool CanConvert(Type objecType)
132 | {
133 | return (objecType == typeof(List));
134 | }
135 |
136 | public override object ReadJson(JsonReader reader, Type objecType, object existingValue,
137 | JsonSerializer serializer)
138 | {
139 | JToken token = JToken.Load(reader);
140 | if (token.Type == JTokenType.Array)
141 | {
142 | return token.ToObject>();
143 | }
144 | return new List { token.ToObject() };
145 | }
146 |
147 | public override bool CanWrite
148 | {
149 | get { return false; }
150 | }
151 |
152 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
153 | {
154 | throw new NotImplementedException();
155 | }
156 | }
157 | }
--------------------------------------------------------------------------------
/Syn3Updater/Model/JsonSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Cyanlabs.Syn3Updater.Model
2 | {
3 | ///
4 | /// Json class for Syn3Updater MainSettings
5 | ///
6 | public class JsonMainSettings
7 | {
8 | public string Lang { get; set; }
9 | public string DownloadPath { get; set; }
10 | public string LicenseKey { get; set; } = "";
11 | public bool DisclaimerAccepted { get; set; } = false;
12 | public string Theme { get; set; }
13 | public string LogPath { get; set; }
14 | public string Profile { get; set; }
15 |
16 | // Old settings for migration purposes
17 | public string CurrentRegion { get; set; }
18 | public int CurrentVersion { get; set; } = 0;
19 | public bool CurrentNav { get; set; } = false;
20 | }
21 |
22 | public class JsonSettings
23 | {
24 | public string CurrentRegion { get; set; }
25 | public int? CurrentVersion { get; set; } = 0;
26 | public bool CurrentNav { get; set; } = false;
27 | public bool? My20v2 { get; set; } = null;
28 | public string InstallMode { get; set; } = "autodetect";
29 | public int DownloadConnections { get; set; } = 1;
30 | }
31 | }
--------------------------------------------------------------------------------
/Syn3Updater/Model/LanguageAwareBaseviewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Cyanlabs.Syn3Updater.Model
2 | {
3 | ///
4 | /// Extension to BaseviewModel to allow it to be LanguageAware
5 | ///
6 | public class LanguageAwareBaseViewModel : BaseViewModel
7 | {
8 | #region Constructors
9 |
10 | public LanguageAwareBaseViewModel()
11 | {
12 | try
13 | {
14 | if (AppMan.App != null)
15 | AppMan.App.LanguageChangedEvent += (sender, args) =>
16 | {
17 | if (AppMan.App.MainSettings.Lang != null) Language = AppMan.App.MainSettings.Lang;
18 | };
19 | }
20 | catch
21 | {
22 | // ignored
23 | }
24 | }
25 |
26 | #endregion
27 |
28 | #region Properties & Fields
29 |
30 | private string _language;
31 |
32 | public string Language
33 | {
34 | get => _language;
35 | set => SetProperty(ref _language, value);
36 | }
37 |
38 | #endregion
39 | }
40 | }
--------------------------------------------------------------------------------
/Syn3Updater/Model/LanguageModel.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Globalization;
6 | using System.IO;
7 | using System.Linq;
8 | using Newtonsoft.Json.Linq;
9 |
10 | // ReSharper disable UnusedAutoPropertyAccessor.Global
11 |
12 | namespace Cyanlabs.Syn3Updater.Model
13 | {
14 | public class LanguageModel
15 | {
16 | #region Constructor
17 |
18 | public LanguageModel(string path)
19 | {
20 | string contents = File.ReadAllText(path);
21 | Code = Path.GetFileName(path).Replace(".json", "");
22 | EnglishName = new CultureInfo(Code, false).DisplayName;
23 | NativeName = new CultureInfo(Code, false).NativeName;
24 | JObject dict = JObject.Parse(contents);
25 | Items = new List();
26 | foreach (KeyValuePair s in dict)
27 | if (s.Value?.ToString() != "")
28 | Items.Add(new LanguageItem
29 | {
30 | Key = s.Key,
31 | Value = s.Value?.ToString()
32 | });
33 | else
34 | Debug.WriteLine(s.Key + ":" + s.Value);
35 | }
36 |
37 | #endregion
38 |
39 | #region Properties & Fields
40 |
41 | public string Code { get; set; }
42 | public string EnglishName { get; set; }
43 | public string NativeName { get; set; }
44 | public string Emoji { get; set; }
45 | public List Items { get; set; }
46 |
47 | public class LanguageItem
48 | {
49 | public string Key { get; set; }
50 | public string Value { get; set; }
51 | }
52 |
53 | #endregion
54 | }
55 |
56 | public static class LM
57 | {
58 | #region Constructors
59 |
60 | static LM()
61 | {
62 | try
63 | {
64 | IEnumerable files = Directory.EnumerateFiles("Languages");
65 |
66 | foreach (string file in files)
67 | try
68 | {
69 | Languages.Add(new LanguageModel(file));
70 | }
71 | catch (Exception e)
72 | {
73 | Debug.WriteLine(e.Message);
74 | }
75 | }
76 | catch
77 | {
78 | // ignored
79 | }
80 | }
81 |
82 | #endregion
83 |
84 | #region Properties & Fields
85 |
86 | public static List Languages { get; set; } = new();
87 |
88 | #endregion
89 |
90 | #region Methods
91 |
92 | public static string GetValue(string key, string lang)
93 | {
94 | try
95 | {
96 | LanguageModel l = Languages.Find(x => x.Code.ToUpper() == lang.ToUpper());
97 | if (l == null)
98 | l = Languages.FirstOrDefault(x => x.Code.ToUpper().StartsWith(lang.ToUpper().Split('-')[0]));
99 |
100 | if (l == null) l = Languages.Find(x => x.Code.ToUpper().StartsWith("EN"));
101 |
102 | if (l == null) return $"[{lang}:{key}]";
103 |
104 | string r = l.Items.Find(x => x.Key.ToLower() == key.ToLower())?.Value.Replace("\\r\\n", Environment.NewLine).Replace("\\n", Environment.NewLine)
105 | .Replace("\\r", Environment.NewLine);
106 | if (string.IsNullOrWhiteSpace(r))
107 | {
108 | r = $"[{lang}:{key}]";
109 | Debug.WriteLine($"couldn't find {r}");
110 | }
111 |
112 | return r;
113 | }
114 | catch
115 | {
116 | // ignored
117 | }
118 |
119 | return $"{lang}:::{key}";
120 | }
121 |
122 | public static string GetValue(string key)
123 | {
124 | if (key == null) return null;
125 |
126 | try
127 | {
128 | string lang = string.Empty; // "EN-US";
129 |
130 | if (AppMan.App.MainSettings.Lang != null) lang = AppMan.App.MainSettings.Lang;
131 |
132 | if (string.IsNullOrWhiteSpace(lang))
133 | {
134 | lang = CultureInfo.CurrentCulture.Name;
135 |
136 | AppMan.App.MainSettings.Lang = lang;
137 | }
138 |
139 | LanguageModel l = Languages.FirstOrDefault(x => x.Code.ToUpper() == lang.ToUpper());
140 | if (l == null)
141 | l = Languages.FirstOrDefault(x => x.Code.ToUpper().StartsWith(lang.ToUpper().Split('-')[0]));
142 |
143 | if (l == null) l = Languages.FirstOrDefault(x => x.Code.ToUpper().StartsWith("EN"));
144 |
145 | if (l == null)
146 | {
147 | //Have to hardcode path for design time :(
148 | string fn = $"C:\\Users\\Scott\\Documents\\GitHub\\Syn3Updater\\Syn3Updater\\Languages\\{lang}.json";
149 |
150 | if (File.Exists(fn))
151 | {
152 | l = new LanguageModel(fn);
153 | Languages.Add(l);
154 | }
155 | }
156 |
157 | if (l == null) return $"[{lang}:{key}]";
158 |
159 | // ReSharper disable once ConstantConditionalAccessQualifier
160 | string r = l.Items.FirstOrDefault(x => x.Key.ToLower() == key.ToLower())?.Value.Replace("\\n", Environment.NewLine).Replace("\\r", Environment.NewLine)
161 | .Replace("\\r\\n", Environment.NewLine);
162 | if (string.IsNullOrWhiteSpace(r))
163 | {
164 | r = $"[{lang}:{key}]";
165 | Debug.WriteLine($"couldn't find {r}");
166 | }
167 |
168 | return r;
169 | }
170 | catch (Exception e)
171 | {
172 | return e.Message;
173 | }
174 | }
175 |
176 | #endregion
177 | }
178 | }
--------------------------------------------------------------------------------
/Syn3Updater/Model/LogModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Cyanlabs.Syn3Updater.Model
4 | {
5 | ///
6 | /// Json class for Log Model
7 | ///
8 | public static class LogModel
9 | {
10 | #region Properties & Fields
11 |
12 | public class Log
13 | {
14 | public bool Selected { get; set; }
15 | public string FileName { get; set; }
16 | public string Profile { get; set; }
17 | public DateTime Date { get; set; }
18 | public string Type { get; set; }
19 | }
20 |
21 | #endregion
22 | }
23 | }
--------------------------------------------------------------------------------
/Syn3Updater/Model/SModel.cs:
--------------------------------------------------------------------------------
1 | namespace Cyanlabs.Syn3Updater.Model
2 | {
3 | ///
4 | /// Json class for additional Models such as Ivsu and SRegion
5 | ///
6 | public static class SModel
7 | {
8 | #region Properties & Fields
9 |
10 | public class SRegion
11 | {
12 | public string Code { get; set; }
13 | public string Name { get; set; }
14 | }
15 |
16 | public class Ivsu
17 | {
18 | public bool Selected { get; set; }
19 | public string Type { get; set; }
20 | public string Name { get; set; }
21 | public string Version { get; set; }
22 | public string Notes { get; set; }
23 | public string Url { get; set; }
24 | public string Md5 { get; set; }
25 | public string FileName { get; set; }
26 | public string Source { get; set; }
27 | public long FileSize { get; set; }
28 | }
29 |
30 | #endregion
31 | }
32 | }
--------------------------------------------------------------------------------
/Syn3Updater/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 | using System.Windows;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Syn3Updater")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("CyanLabs")]
12 | [assembly: AssemblyProduct("Syn3Updater")]
13 | [assembly: AssemblyCopyright("Copyright © CyanLabs 2023")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | //In order to begin building localizable applications, set
23 | //CultureYouAreCodingWith in your .csproj file
24 | //inside a . For example, if you are using US english
25 | //in your source files, set the to en-US. Then uncomment
26 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
27 | //the line below to match the UICulture setting in the project file.
28 |
29 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
30 |
31 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
32 | //(used if a resource is not found in the page,
33 | // or application resource dictionaries)
34 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
35 | //(used if a resource is not found in the page,
36 | // app, or any theme specific resource dictionaries)
37 | )]
38 |
39 | // Version information for an assembly consists of the following four values:
40 | //
41 | // Major Version
42 | // Minor Version
43 | // Build Number
44 | // Revision
45 | //
46 | // You can specify all the values or you can default the Build a nd Revision Numbers
47 | // by using the '*' as shown below:
48 | // [assembly: AssemblyVersion("1.0.*")]
49 | [assembly: AssemblyVersion("2.13.3.0")]
50 | [assembly: AssemblyFileVersion("2.13.3.0")]
--------------------------------------------------------------------------------
/Syn3Updater/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Cyanlabs.Syn3Updater.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Syn3Updater/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Syn3Updater/Services/DownloadViewModelService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 | using Cyanlabs.Syn3Updater.Helper;
7 | using Cyanlabs.Syn3Updater.Model;
8 |
9 | namespace Cyanlabs.Syn3Updater.Services
10 | {
11 | public static class DownloadViewModelService
12 | {
13 | public static StringBuilder CreateAutoInstallFile(string selectedRelease, string selectedRegion)
14 | {
15 | StringBuilder autoinstalllst =
16 | new(
17 | $@"; CyanLabs Syn3Updater {Assembly.GetEntryAssembly()?.GetName().Version} {AppMan.App.LauncherPrefs.ReleaseTypeInstalled} - Autoinstall {(AppMan.App.ModeForced ? "FORCED " : "")}Mode - {selectedRelease} {selectedRegion}{Environment.NewLine}{Environment.NewLine}");
18 | //naviextras not handled here
19 | List ivsuList = AppMan.App.Ivsus.Where(item => item.Source != "naviextras").ToList();
20 |
21 | ivsuList.Remove(Api.RWDataCleaner);
22 |
23 | if (ivsuList.Any(i => i.Type == "MAP"))
24 | {
25 | autoinstalllst.Append($@"[SYNCGen3.0_3.0.1_PRODUCT]{Environment.NewLine}");
26 | autoinstalllst.Append($@"Item1 = RWDataCleaner TOOL - {Api.RWDataCleaner.FileName}\rOpen1 = SyncMyRide\{Api.RWDataCleaner.FileName}\r").Replace(@"\r", Environment.NewLine);
27 |
28 | SModel.Ivsu mapLicense = ivsuList.Find(i => i.Type == "MAP_LICENSE");
29 | if (mapLicense != null)
30 | {
31 | autoinstalllst.Append($@"Item2 = {mapLicense.Type} - {mapLicense.FileName}\rOpen2 = SyncMyRide\{mapLicense.FileName}\r").Replace(@"\r", Environment.NewLine);
32 | ivsuList.Remove(mapLicense);
33 | }
34 |
35 | List vals = ivsuList.ConvertAll(ivsu => (uint) ivsu.FileSize);
36 | //splits the ivsus into 3 evenly distibuted buckets
37 | effPartition buckets = new(vals, 3);
38 | for (ushort i = 0; i < buckets.SubsetCount; i++)
39 | {
40 | for (int j = 0; j < buckets[i].NumbIDs.Count; j++)
41 | {
42 | int subIndex = (int) buckets[i].numbIDs[j];
43 | //indexes for "Items" start at 1
44 | int partIndex = j + 1;
45 | //indexes returned by the partition code start at 1
46 | SModel.Ivsu item = ivsuList[subIndex - 1];
47 |
48 | if (i == 0) //since we added the RWDataCleaner package above
49 | partIndex++;
50 | if (i == 0 && mapLicense != null) //since we added the MAP_LICENCE package above
51 | partIndex++;
52 |
53 | autoinstalllst.Append($@"Item{partIndex} = {item.Type} - {item.FileName}\rOpen{partIndex} = SyncMyRide\{item.FileName}\r")
54 | .Replace(@"\r", Environment.NewLine);
55 | }
56 |
57 | if (i == 0)
58 | autoinstalllst.Append("Options = AutoInstall").Append(Environment.NewLine).Append(Environment.NewLine);
59 | if (i == 0 && ivsuList.Count > 1)
60 | autoinstalllst.Append($@"[SYNCGen3.0_3.0.1]{Environment.NewLine}");
61 | if (i == 1 && ivsuList.Count > 1)
62 | autoinstalllst.Append("Options = AutoInstall, Include, Transaction").Append(Environment.NewLine).Append(Environment.NewLine);
63 | if (i == 1 && ivsuList.Count > 2)
64 | autoinstalllst.Append($@"[SYNCGen3.0_ALL]{Environment.NewLine}");
65 | if (i == 2 && ivsuList.Count > 2)
66 | autoinstalllst.Append("Options = Delay, Include, Transaction").Append(Environment.NewLine);
67 | }
68 | }
69 | else
70 | {
71 | autoinstalllst.Append($@"[SYNCGen3.0_ALL_PRODUCT]{Environment.NewLine}");
72 |
73 | int currentitem = 1;
74 | if (AppMan.App.Action != "logutility" && AppMan.App.Action != "logutilitymy20" && AppMan.App.Action != "gracenotesremoval" && AppMan.App.Action != "voiceshrinker" && AppMan.App.Action != "downgrade" && AppMan.App.Action != "upgrade22")
75 | {
76 | autoinstalllst.Append($@"Item{currentitem} = RWDataCleaner TOOL - {Api.RWDataCleaner.FileName}\rOpen{currentitem}= SyncMyRide\{Api.RWDataCleaner.FileName}\r").Replace(@"\r", Environment.NewLine);
77 | currentitem = 2;
78 | }
79 |
80 | for (int i = 0; i < ivsuList.Count; i++)
81 | {
82 | SModel.Ivsu item = ivsuList[i];
83 | autoinstalllst.Append($@"Item{currentitem} = {item.Type} - {item.FileName}\rOpen{currentitem} = SyncMyRide\{item.FileName}\r").Replace(@"\r", Environment.NewLine);
84 | currentitem = currentitem + 1;
85 | }
86 |
87 | autoinstalllst.Append("Options = AutoInstall").Append(Environment.NewLine);
88 | }
89 |
90 | return autoinstalllst;
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/Syn3Updater/Services/HomeViewModelService.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using System.Windows;
5 | using System.Windows.Media;
6 | using System.Windows.Threading;
7 | using Cyanlabs.Syn3Updater.Helper;
8 | using Cyanlabs.Syn3Updater.Model;
9 | using ModernWpf.Controls;
10 |
11 | namespace Cyanlabs.Syn3Updater.Services
12 | {
13 | public static class HomeViewModelService
14 | {
15 | public static async Task Download(string installMode, ObservableCollection ivsuList,
16 | SModel.SRegion selectedRegion, string selectedRelease, string selectedMapVersion, string driveLetter, USBHelper.Drive selectedDrive)
17 | {
18 | if (await SetIvsuList(installMode, ivsuList, selectedRegion, selectedRelease, selectedMapVersion, driveLetter) == false)
19 | {
20 | await Application.Current.Dispatcher.BeginInvoke(() => UIHelper.ShowErrorDialog(LM.GetValue("MessageBox.NoPackagesSelected")));
21 | return false;
22 | }
23 |
24 | bool canceldownload = false;
25 |
26 | //Install Mode is reformat or downgrade My20 warning
27 | if ((installMode == "reformat" || installMode == "downgrade") && !AppMan.App.DownloadOnly && AppMan.App.Settings.My20v2 == null)
28 | if (await Application.Current.Dispatcher.Invoke(() => UIHelper.ShowDialog(string.Format(LM.GetValue("MessageBox.My20CheckV2")), LM.GetValue("String.Warning") + "!", LM.GetValue("String.No"),
29 | LM.GetValue("String.Yes"), null, ContentDialogButton.None, Brushes.DarkRed)) == ContentDialogResult.Primary)
30 | {
31 | await USBHelper.LogPrepareUSBAction(selectedDrive, driveLetter, "logutilitymy20");
32 | return true;
33 | }
34 |
35 | //Warn is users region is different to new selection
36 | if (selectedRegion.Code != AppMan.App.Settings.CurrentRegion)
37 | if (await Application.Current.Dispatcher.Invoke(() => UIHelper.ShowWarningDialog(string.Format(LM.GetValue("MessageBox.CancelRegionMismatch")), LM.GetValue("String.Warning") + "!", LM.GetValue("String.No"),
38 | LM.GetValue("String.Yes"))) != ContentDialogResult.Primary)
39 | canceldownload = true;
40 |
41 | //Cancel no apps package selected
42 | if (!AppMan.App.AppsSelected && (installMode == "reformat" || installMode == "downgrade"))
43 | {
44 | await Application.Current.Dispatcher.BeginInvoke(() => UIHelper.ShowErrorDialog(LM.GetValue("MessageBox.CancelNoApps")));
45 | canceldownload = true;
46 | }
47 |
48 |
49 | if (!canceldownload && (AppMan.App.DownloadOnly || !await SanityCheckHelper.CancelDownloadCheck(selectedDrive)))
50 | {
51 | if (AppMan.App.DownloadOnly)
52 | {
53 | AppMan.Logger.Info($"Starting download only of ({selectedRelease} - {selectedRegion?.Code} - {selectedMapVersion})");
54 | }
55 | else
56 | {
57 | AppMan.App.DriveNumber = selectedDrive.Path.Replace("Win32_DiskDrive.DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE", "").Replace("\"", "");
58 | AppMan.App.DriveLetter = driveLetter;
59 | AppMan.Logger.Info($"Starting process ({selectedRelease} - {selectedRegion?.Code} - {selectedMapVersion})");
60 | }
61 |
62 | AppMan.App.IsDownloading = true;
63 | AppMan.App.FireDownloadsTabEvent();
64 | return true;
65 | }
66 |
67 | return false;
68 | }
69 |
70 | public static async Task SetIvsuList(string installMode, ObservableCollection ivsuList, SModel.SRegion selectedRegion, string selectedRelease,
71 | string selectedMapVersion, string driveLetter)
72 | {
73 | AppMan.Logger.Info(
74 | $"USB Drive selected - Name: {AppMan.App.DriveName} - FileSystem: {AppMan.App.DriveFileSystem} - PartitionType: {AppMan.App.DrivePartitionType} - Letter: {driveLetter}");
75 | AppMan.App.Ivsus.Clear();
76 |
77 | if (!ivsuList.Any(i => i.Selected)) return false;
78 |
79 | if (installMode == "downgrade")
80 | {
81 | Api.DowngradeAppIvsu = await ApiHelper.GetSpecialIvsu(Api.SpecialPackages.DowngradeApp);
82 | AppMan.App.Ivsus.Add(Api.DowngradeAppIvsu);
83 |
84 | Api.DowngradeToolIvsu = await ApiHelper.GetSpecialIvsu(Api.SpecialPackages.DowngradeTool);
85 | AppMan.App.Ivsus.Add(Api.DowngradeToolIvsu);
86 | }
87 |
88 | if (installMode == "reformat" || installMode == "downgrade")
89 | {
90 | Api.ReformatTool = await ApiHelper.GetSpecialIvsu(Api.SpecialPackages.Reformat);
91 | AppMan.App.Ivsus.Add(Api.ReformatTool);
92 | }
93 |
94 | // Add RWDataCleaner
95 | Api.RWDataCleaner = await ApiHelper.GetSpecialIvsu(Api.SpecialPackages.RWDataCleaner);
96 | AppMan.App.Ivsus.Add(Api.RWDataCleaner);
97 |
98 | AppMan.App.DriveLetter = driveLetter;
99 | foreach (SModel.Ivsu item in ivsuList)
100 | if (item.Selected)
101 | {
102 | if (item.Type == "APPS")
103 | AppMan.App.AppsSelected = true;
104 |
105 | AppMan.App.Ivsus.Add(item);
106 | }
107 |
108 | AppMan.App.SelectedRegion = selectedRegion.Code;
109 | AppMan.App.SelectedRelease = selectedRelease;
110 | AppMan.App.SelectedMapVersion = selectedMapVersion;
111 | return true;
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/Syn3Updater/SimpleLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Drawing.Imaging;
5 | using System.IO;
6 | using System.Runtime.CompilerServices;
7 | using System.Windows.Media.Imaging;
8 | using Cyanlabs.Syn3Updater.Model;
9 | using Cyanlabs.Syn3Updater.UI;
10 | using Newtonsoft.Json;
11 | using QRCoder;
12 |
13 | namespace Cyanlabs.Syn3Updater
14 | {
15 | public class SimpleLogger
16 | {
17 | public List Log = new();
18 |
19 | public void Debug(object log, [CallerMemberName] string cmn = "")
20 | {
21 | Log.Add(new LogEntry(log.ToString(), "Debug", null, cmn));
22 | }
23 |
24 | public void Info(object log, [CallerMemberName] string cmn = "")
25 | {
26 | Log.Add(new LogEntry(log.ToString(), "Info", null, cmn));
27 | }
28 |
29 | public void CrashWindow(Exception ex, [CallerMemberName] string callerMemberName = "")
30 | {
31 | CrashWindow crashWindow = new() {ErrorName = {Text = ex.GetType().ToString()}, Message = {Text = ex.Message}, StackTrace = {Text = ex.StackTrace}};
32 | crashWindow.Show();
33 |
34 | Log.Add(new LogEntry(ex.GetType().ToString(), "Crash", ex));
35 | string guid = crashWindow.SendReport(ex);
36 | var output = JsonConvert.DeserializeAnonymousType(guid, new {uuid = "", status = ""});
37 | string url = Api.CrashLogUrl + output.uuid;
38 | crashWindow.ErrorReportUrl = url;
39 |
40 | QRCodeGenerator qrGenerator = new();
41 | QRCodeData qrCodeData = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
42 | QRCode qrCode = new(qrCodeData);
43 | Bitmap qrCodeImage = qrCode.GetGraphic(20);
44 |
45 | crashWindow.Qrcode.Source = BitmapToImageSource(qrCodeImage);
46 | }
47 |
48 | private BitmapImage BitmapToImageSource(Bitmap bitmap)
49 | {
50 | using MemoryStream memory = new();
51 | bitmap.Save(memory, ImageFormat.Bmp);
52 | memory.Position = 0;
53 | BitmapImage bitmapimage = new();
54 | bitmapimage.BeginInit();
55 | bitmapimage.StreamSource = memory;
56 | bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
57 | bitmapimage.EndInit();
58 |
59 | return bitmapimage;
60 | }
61 |
62 | public class LogEntry
63 | {
64 | public LogEntry(string log, string logType = "Info", Exception exception = null, [CallerMemberName] string callerMemberName = "")
65 | {
66 | Log = log;
67 | Time = DateTime.Now;
68 | Caller = callerMemberName;
69 | LogType = logType;
70 |
71 | if (exception != null) Exception = exception;
72 | }
73 |
74 | public string Log { get; set; }
75 | public DateTime Time { get; set; }
76 | public string Caller { get; set; }
77 | public string LogType { get; set; }
78 | public Exception Exception { get; set; }
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/Syn3Updater/Syn3Updater.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net472;net6.0-windows10.0.18362
5 | WinExe
6 | Cyanlabs.Syn3Updater
7 | false
8 | publish\
9 | true
10 | Disk
11 | false
12 | Foreground
13 | 7
14 | Days
15 | false
16 | false
17 | true
18 | 0
19 | 1.0.0.%2a
20 | false
21 | false
22 | true
23 | false
24 | true
25 | true
26 | Cyanlabs.Syn3Updater.App
27 | cyanlabs.ico
28 | app.manifest
29 |
30 |
31 | ..\bin\Debug\
32 | latest
33 |
34 |
35 | ..\bin\Release\
36 | latest
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | NU1701
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | all
70 |
71 |
72 |
73 |
74 |
75 | False
76 | Microsoft .NET Framework 4.7.2 %28x86 and x64%29
77 | true
78 |
79 |
80 | False
81 | .NET Framework 3.5 SP1
82 | false
83 |
84 |
85 |
86 |
87 |
88 | $(DefaultXamlRuntime)
89 |
90 |
91 |
92 |
93 |
94 |
95 | PreserveNewest
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | True
110 | True
111 | Settings.settings
112 |
113 |
114 |
115 |
116 |
117 | SettingsSingleFileGenerator
118 | Settings.Designer.cs
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/Syn3Updater/Syn3Updater.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | No
--------------------------------------------------------------------------------
/Syn3Updater/UI/AttachedProperties.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | namespace Cyanlabs.Syn3Updater.UI
5 | {
6 | public class TextBoxAttachedProperties
7 | {
8 | #region Methods
9 |
10 | // Using a DependencyProperty as the backing store for AutoScrollToEnd. This enables animation, styling, binding, etc...
11 | public static readonly DependencyProperty AutoScrollToEndProperty = DependencyProperty.RegisterAttached("AutoScrollToEnd", typeof(bool), typeof(TextBoxAttachedProperties),
12 | new PropertyMetadata(false, AutoScrollToEndPropertyChanged));
13 |
14 | public static bool GetAutoScrollToEnd(DependencyObject obj)
15 | {
16 | return (bool) obj.GetValue(AutoScrollToEndProperty);
17 | }
18 |
19 | public static void SetAutoScrollToEnd(DependencyObject obj, bool value)
20 | {
21 | obj.SetValue(AutoScrollToEndProperty, value);
22 | }
23 |
24 | private static void AutoScrollToEndPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
25 | {
26 | if (d is TextBox textbox && e.NewValue is bool mustAutoScroll && mustAutoScroll)
27 | textbox.TextChanged += (s, ee) => AutoScrollToEnd(textbox);
28 | }
29 |
30 | private static void AutoScrollToEnd(TextBox textbox)
31 | {
32 | textbox.ScrollToEnd();
33 | }
34 |
35 | #endregion
36 | }
37 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/CrashWindow.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 | :(
23 |
24 |
26 | Syn3 Updater has crashed.
27 |
28 |
30 | An error occurred and couldn't be handled.
31 |
32 |
34 | If you keep experiencing this issue try using the "Reset Settings" button below
35 |
36 |
37 |
38 |
39 |
40 |
42 | error name
43 |
44 | message
45 |
46 |
47 |
48 |
49 |
51 | stacktrace
52 |
53 |
54 |
55 |
56 |
57 |
61 |
65 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/Syn3Updater/UI/CrashWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Net;
5 | using System.Net.Http;
6 | using System.Reflection;
7 | using System.Windows;
8 | using Cyanlabs.Syn3Updater.Helper;
9 | using Cyanlabs.Syn3Updater.Model;
10 | using Newtonsoft.Json;
11 |
12 | namespace Cyanlabs.Syn3Updater.UI
13 | {
14 | ///
15 | /// Interaction logic for CrashWindow.xaml
16 | ///
17 | public partial class CrashWindow : Window
18 | {
19 | public string ErrorReportUrl;
20 |
21 | public CrashWindow()
22 | {
23 | InitializeComponent();
24 | }
25 |
26 | private void Close_OnClick(object sender, RoutedEventArgs e)
27 | {
28 | AppMan.App.Exit();
29 | }
30 |
31 | public string SendReport(Exception exception)
32 | {
33 | try
34 | {
35 | CrashContainer crashContainer = new();
36 | StackTrace st = new(exception, true);
37 | StackFrame frame = st.GetFrame(st.FrameCount - 1);
38 |
39 | crashContainer.ErrorName = exception.GetType().ToString();
40 | if (frame != null)
41 | crashContainer.ErrorLocation = $"{frame.GetFileName()}/{frame.GetMethod().Name}/{frame.GetFileLineNumber()}";
42 | crashContainer.Logs = AppMan.Logger.Log;
43 |
44 | Dictionary values = new()
45 | {
46 | {"computername", Environment.MachineName},
47 | {"detail", JsonConvert.SerializeObject(crashContainer)},
48 | {"version", Assembly.GetEntryAssembly()?.GetName().Version.ToString()},
49 | {"error", crashContainer.ErrorName},
50 | {"message", exception.Message},
51 | {"operatingsystem", SystemHelper.GetOsFriendlyName()},
52 | {"branch", AppMan.App.LauncherPrefs.ReleaseTypeInstalled.ToString()}
53 | };
54 |
55 | HttpRequestMessage httpRequestMessage = new()
56 | {
57 | Method = HttpMethod.Post,
58 | RequestUri = new Uri(Api.CrashLogPost),
59 | Headers = {
60 | { nameof(HttpRequestHeader.Authorization), $"Bearer {ApiSecret.Token}" },
61 | },
62 | Content = new FormUrlEncodedContent(values)
63 | };
64 |
65 | HttpResponseMessage response = AppMan.Client.SendAsync(httpRequestMessage).GetAwaiter().GetResult();
66 | return response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
67 | }
68 | catch (HttpRequestException)
69 | {
70 | return null;
71 | }
72 | }
73 |
74 | private void ClickQRCode(object sender, RoutedEventArgs e)
75 | {
76 | SystemHelper.OpenWebPage(ErrorReportUrl);
77 | }
78 |
79 | private void ViewReport(object sender, RoutedEventArgs e)
80 | {
81 | SystemHelper.OpenWebPage(ErrorReportUrl);
82 | }
83 |
84 | private void ResetSettings_Click(object sender, RoutedEventArgs e)
85 | {
86 | AppMan.App.ResetSettings();
87 | AppMan.App.RestartApp();
88 | }
89 |
90 | public class CrashContainer
91 | {
92 | public string ErrorName { get; set; }
93 | public string ErrorLocation { get; set; }
94 | public List Logs { get; set; } = new();
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Reflection;
3 | using System.Security.Cryptography;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 | using System.Windows.Input;
7 | using Cyanlabs.Syn3Updater.Model;
8 | using Microsoft.Win32;
9 |
10 | namespace Cyanlabs.Syn3Updater.UI
11 | {
12 | ///
13 | /// Interaction logic for MainWindow.xaml
14 | ///
15 | public partial class MainWindow
16 | {
17 | #region Methods
18 |
19 | public MainWindow()
20 | {
21 | InitializeComponent();
22 | AppMan.Logger.Debug("MainWindow Initialized");
23 | if (CryptoConfig.AllowOnlyFipsAlgorithms)
24 | {
25 | // Do not replace with ContentDialog
26 | MessageBox.Show(
27 | "Syn3 Updater has detected that 'Use FIPS Compliant algorithms for encryption, hashing, and signing.' is enforced via Group Policy, Syn3 Updater will be unable to validate any files using MD5 with this policy enforced and therefore is currently unable to function\n\nThe application will now close!",
28 | LM.GetValue("String.Notice"), MessageBoxButton.OK, MessageBoxImage.Error);
29 | AppMan.App.Exit();
30 | }
31 |
32 | try
33 | {
34 | object v = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Defender\Windows Defender Exploit Guard\Controlled Folder Access",
35 | "EnableControlledFolderAccess", "0");
36 | if (v != null && v.ToString() != "0")
37 | if (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Defender\Windows Defender Exploit Guard\Controlled Folder Access\AllowedApplications",
38 | Assembly.GetExecutingAssembly().Location, null) == null)
39 | MessageBox.Show(
40 | "Syn3 Updater has detected that 'Controlled Folder Access' is enabled on this computer\n\nSyn3 Updater may be unable to read or write to files at certain locations, to prevent potential issues please exclude Syn3 Updater from Controlled Folder Access or ensure you are using a folder that is not protected.",
41 | LM.GetValue("String.Notice"), MessageBoxButton.OK, MessageBoxImage.Warning);
42 | }
43 | catch
44 | {
45 | // ignored
46 | }
47 | }
48 |
49 | private MainWindowViewModel Vm => (MainWindowViewModel) DataContext;
50 |
51 | private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
52 | {
53 | if ((sender as Grid)?.DataContext is MainWindowViewModel.TabItem lvm)
54 | {
55 | if (string.IsNullOrWhiteSpace(lvm.Key))
56 | Vm.HamburgerExtended = !Vm.HamburgerExtended;
57 | else
58 | Vm.CurrentTab = lvm.Key;
59 | }
60 | }
61 |
62 | private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
63 | {
64 | Vm.CurrentTab = "settings";
65 | }
66 |
67 | private void Window_Closing(object sender, CancelEventArgs e)
68 | {
69 | AppMan.App.Exit();
70 | }
71 |
72 | #endregion
73 | }
74 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/About.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Windows;
3 |
4 | namespace Cyanlabs.Syn3Updater.UI.Tabs
5 | {
6 | ///
7 | /// Interaction logic for Install.xaml
8 | ///
9 | public partial class About
10 | {
11 | public About()
12 | {
13 | InitializeComponent();
14 | if (!DesignerProperties.GetIsInDesignMode(this)) (DataContext as AboutViewmodel)?.Init();
15 | }
16 |
17 | private void About_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
18 | {
19 | if ((bool) e.NewValue && !(bool) e.OldValue) (DataContext as AboutViewmodel)?.Reload();
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/AboutViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Windows;
3 | using Cyanlabs.Syn3Updater.Helper;
4 | using Cyanlabs.Syn3Updater.Model;
5 |
6 | namespace Cyanlabs.Syn3Updater.UI.Tabs
7 | {
8 | internal class AboutViewmodel : LanguageAwareBaseViewModel
9 | {
10 | #region Properties & Fields
11 |
12 | private ActionCommand _documentationButton;
13 | private ActionCommand _donateButton;
14 | private ActionCommand _fhubButton;
15 | private ActionCommand _forumButton;
16 | private ActionCommand _websiteButton;
17 | public ActionCommand WebsiteButton => _websiteButton ??= new ActionCommand(WebsiteAction);
18 | public ActionCommand ForumButton => _forumButton ??= new ActionCommand(ForumAction);
19 | public ActionCommand DonateButton => _donateButton ??= new ActionCommand(DonateAction);
20 | public ActionCommand DocButton => _documentationButton ??= new ActionCommand(DocAction);
21 | public ActionCommand FHubButton => _fhubButton ??= new ActionCommand(FHubAction);
22 |
23 | private bool _disclaimerAccepted;
24 |
25 | public bool DisclaimerAccepted
26 | {
27 | get => _disclaimerAccepted;
28 | set
29 | {
30 | SetProperty(ref _disclaimerAccepted, value);
31 | AppMan.App.MainSettings.DisclaimerAccepted = value;
32 | if (value) AppMan.App.FireSettingsTabEvent();
33 | }
34 | }
35 |
36 | private Visibility _englishEndorsement;
37 |
38 | public Visibility EnglishEndorsement
39 | {
40 | get => _englishEndorsement;
41 | set => SetProperty(ref _englishEndorsement, value);
42 | }
43 |
44 | #endregion
45 |
46 | #region Constructors
47 |
48 | public void Init()
49 | {
50 | DisclaimerAccepted = AppMan.App.MainSettings.DisclaimerAccepted;
51 | }
52 |
53 | public void Reload()
54 | {
55 | EnglishEndorsement = AppMan.App.MainSettings.Lang.Contains("en-") ? Visibility.Hidden : Visibility.Visible;
56 | }
57 |
58 | private static void WebsiteAction()
59 | {
60 | SystemHelper.OpenWebPage("https://cyanlabs.net");
61 | }
62 |
63 | private static void ForumAction()
64 | {
65 | SystemHelper.OpenWebPage("https://community.cyanlabs.net");
66 | }
67 |
68 | private static void DonateAction()
69 | {
70 | SystemHelper.OpenWebPage("https://cyanlabs.net/support-us/");
71 | }
72 |
73 | private static void DocAction()
74 | {
75 | SystemHelper.OpenWebPage("https://cyanlabs.net/docs/syn3updater/");
76 | }
77 |
78 | private static void FHubAction()
79 | {
80 | SystemHelper.OpenWebPage("https://cyanlabs.net/fhub");
81 | }
82 |
83 | #endregion
84 | }
85 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/Download.xaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
36 |
38 |
39 |
40 |
42 |
43 |
44 |
45 |
48 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
62 |
64 |
65 |
66 |
69 |
71 |
72 |
73 |
76 |
78 |
79 |
80 |
83 |
85 |
86 |
87 |
88 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
105 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/Download.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Cyanlabs.Syn3Updater.UI.Tabs
4 | {
5 | ///
6 | /// Interaction logic for Install.xaml
7 | ///
8 | public partial class Download
9 | {
10 | public Download()
11 | {
12 | InitializeComponent();
13 | }
14 |
15 | private void Download_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
16 | {
17 | if ((bool) e.NewValue && !(bool) e.OldValue) (DataContext as DownloadViewModel)?.Init();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/Home.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Windows;
3 |
4 | namespace Cyanlabs.Syn3Updater.UI.Tabs
5 | {
6 | ///
7 | /// Interaction logic for Install.xaml
8 | ///
9 | public partial class Home
10 | {
11 | public Home()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | private void Home_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
17 | {
18 | if(AppMan.App.DriveLetter == "invalid") (DataContext as HomeViewModel)?.ReloadUSB();
19 | if ((bool) e.NewValue && !(bool) e.OldValue) (DataContext as HomeViewModel)?.ReloadSettings();
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/Logs.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Cyanlabs.Syn3Updater.UI.Tabs
4 | {
5 | ///
6 | /// Interaction logic for Install.xaml
7 | ///
8 | public partial class Logs
9 | {
10 | public Logs()
11 | {
12 | InitializeComponent();
13 | }
14 |
15 | private void Logs_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
16 | {
17 | if ((bool) e.NewValue && !(bool) e.OldValue) (DataContext as LogsViewModel)?.Reload();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/LogsViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.ObjectModel;
3 | using System.Diagnostics;
4 | using System.Globalization;
5 | using System.IO;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using System.Windows.Threading;
9 | using AsyncAwaitBestPractices.MVVM;
10 | using Cyanlabs.Syn3Updater.Helper;
11 | using Cyanlabs.Syn3Updater.Model;
12 |
13 | namespace Cyanlabs.Syn3Updater.UI.Tabs
14 | {
15 | internal class LogsViewModel : LanguageAwareBaseViewModel
16 | {
17 | #region Constructors
18 |
19 | private AsyncCommand _openLogFile;
20 | public AsyncCommand OpenLogFile => _openLogFile ??= new AsyncCommand(OpenLogFileAction);
21 |
22 | private ActionCommand _deleteLogFiles;
23 | public ActionCommand DeleteLogFiles => _deleteLogFiles ??= new ActionCommand(DeleteLogFilesAction);
24 |
25 | private AsyncCommand _openLogDirectory;
26 | public AsyncCommand OpenLogDirectory => _openLogDirectory ??= new AsyncCommand(OpenLogDirectoryAction);
27 |
28 | #endregion
29 |
30 | #region Properties & Fields
31 |
32 | private string _logLocation;
33 |
34 | public string LogLocation
35 | {
36 | get => _logLocation;
37 | set => SetProperty(ref _logLocation, value);
38 | }
39 |
40 | private ObservableCollection _logFiles;
41 |
42 | public ObservableCollection LogFiles
43 | {
44 | get => _logFiles;
45 | set => SetProperty(ref _logFiles, value);
46 | }
47 |
48 | private LogModel.Log _selectedLogFile;
49 |
50 | public LogModel.Log SelectedLogFile
51 | {
52 | get => _selectedLogFile;
53 | set => SetProperty(ref _selectedLogFile, value);
54 | }
55 |
56 | private string _logTitle;
57 |
58 | public string LogTitle
59 | {
60 | get => _logTitle;
61 | set => SetProperty(ref _logTitle, value);
62 | }
63 |
64 | private string _logDetails;
65 |
66 | public string LogDetails
67 | {
68 | get => _logDetails;
69 | set => SetProperty(ref _logDetails, value);
70 | }
71 |
72 | #endregion
73 |
74 | #region Methods
75 |
76 | public void Reload()
77 | {
78 | LogLocation = AppMan.App.MainSettings.LogPath;
79 | ReloadLogs();
80 | }
81 |
82 | private async Task OpenLogFileAction(string path)
83 | {
84 | try
85 | {
86 | LogTitle = Path.GetFileName(path);
87 | LogDetails = File.ReadAllText(AppMan.App.MainSettings.LogPath + path);
88 | }
89 | catch (Exception e)
90 | {
91 | await UIHelper.ShowErrorDialog(e.GetFullMessage());
92 | }
93 | }
94 |
95 | private void DeleteLogFilesAction()
96 | {
97 | foreach (LogModel.Log log in LogFiles)
98 | {
99 | if (!log.Selected) continue;
100 | try
101 | {
102 | File.Delete(AppMan.App.MainSettings.LogPath + log.FileName);
103 | }
104 | catch
105 | {
106 | // ignored
107 | }
108 | }
109 |
110 | ReloadLogs();
111 | }
112 |
113 | private void ReloadLogs()
114 | {
115 | LogDetails = null;
116 | LogFiles = new ObservableCollection();
117 | if (!string.IsNullOrEmpty(AppMan.App.MainSettings.LogPath))
118 | {
119 | DirectoryInfo dir = new(AppMan.App.MainSettings.LogPath);
120 | foreach (FileInfo file in dir.GetFiles("*.txt"))
121 | LogFiles.Add(new LogModel.Log {Selected = false, FileName = file.Name, Date = file.LastWriteTime, Profile = "Default", Type = "Log" });
122 |
123 | foreach (FileInfo file in dir.GetFiles("*.xml"))
124 | LogFiles.Add(new LogModel.Log { Selected = false, FileName = file.Name, Date = file.LastWriteTime, Profile = "Default", Type = "Interrogator" });
125 | }
126 | }
127 |
128 | private async Task OpenLogDirectoryAction()
129 | {
130 | try
131 | {
132 | Process.Start(AppMan.App.MainSettings.LogPath);
133 | }
134 | catch (Exception e)
135 | {
136 | await UIHelper.ShowErrorDialog(e.GetFullMessage());
137 | }
138 | }
139 |
140 | #endregion
141 | }
142 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/News.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Threading.Tasks;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Input;
6 |
7 | namespace Cyanlabs.Syn3Updater.UI.Tabs
8 | {
9 | ///
10 | /// Interaction logic for Install.xaml
11 | ///
12 | public partial class News
13 | {
14 | public News()
15 | {
16 | InitializeComponent();
17 | if (!DesignerProperties.GetIsInDesignMode(this)) (DataContext as NewsViewModel)?.Init();
18 | }
19 |
20 | private void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
21 | {
22 | if (!(sender is FlowDocumentScrollViewer) || e.Handled) return;
23 | e.Handled = true;
24 | MouseWheelEventArgs eventArg = new(e.MouseDevice, e.Timestamp, e.Delta) {RoutedEvent = MouseWheelEvent, Source = sender};
25 | if (((Control) sender).Parent is UIElement parent) parent.RaiseEvent(eventArg);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/Profiles.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
39 |
40 |
41 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
56 |
60 |
64 |
65 |
70 |
71 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
90 |
93 |
99 |
105 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/Profiles.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Cyanlabs.Syn3Updater.UI.Tabs
4 | {
5 | ///
6 | /// Interaction logic for Install.xaml
7 | ///
8 | public partial class Profiles
9 | {
10 | public Profiles()
11 | {
12 | InitializeComponent();
13 | }
14 |
15 | private void Profiles_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
16 | {
17 | if ((bool) e.NewValue && !(bool) e.OldValue) (DataContext as ProfilesViewModel)?.Reload();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/ProfilesViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.ObjectModel;
3 | using System.IO;
4 | using System.Threading.Tasks;
5 | using System.Windows;
6 | using System.Windows.Threading;
7 | using AsyncAwaitBestPractices.MVVM;
8 | using Cyanlabs.Syn3Updater.Helper;
9 | using Cyanlabs.Syn3Updater.Model;
10 |
11 | namespace Cyanlabs.Syn3Updater.UI.Tabs
12 | {
13 | public static class ProfileModel
14 | {
15 | #region Properties & Fields
16 |
17 | public class Profile
18 | {
19 | public string Name { get; set; }
20 | }
21 |
22 | #endregion
23 | }
24 |
25 | internal class ProfilesViewModel : LanguageAwareBaseViewModel
26 | {
27 | #region Constructors
28 |
29 | private AsyncValueCommand _selectProfile;
30 | public AsyncValueCommand SelectProfile => _selectProfile ??= new AsyncValueCommand(SelectProfileAction);
31 |
32 | private AsyncValueCommand _renameProfile;
33 | public AsyncValueCommand RenameProfile => _renameProfile ??= new AsyncValueCommand(RenameProfileAction);
34 |
35 | private AsyncCommand _deleteProfile;
36 | public AsyncCommand DeleteProfile => _deleteProfile ??= new AsyncCommand(DeleteProfileAction);
37 |
38 | private ActionCommand _createProfile;
39 | public ActionCommand CreateProfile => _createProfile ??= new ActionCommand(CreateProfileAction);
40 |
41 | #endregion
42 |
43 | #region Properties & Fields
44 |
45 | private string _currentProfile;
46 |
47 | public string CurrentProfile
48 | {
49 | get => _currentProfile;
50 | set => SetProperty(ref _currentProfile, value);
51 | }
52 |
53 | private string _profileName;
54 |
55 | public string ProfileName
56 | {
57 | get => _profileName;
58 | set => SetProperty(ref _profileName, value);
59 | }
60 |
61 | private string _renameButtonText;
62 |
63 | public string RenameButtonText
64 | {
65 | get => _renameButtonText;
66 | set => SetProperty(ref _renameButtonText, value);
67 | }
68 |
69 | private ObservableCollection _profileList;
70 |
71 | public ObservableCollection ProfileList
72 | {
73 | get => _profileList;
74 | set => SetProperty(ref _profileList, value);
75 | }
76 |
77 | private ProfileModel.Profile _selectedProfile;
78 |
79 | public ProfileModel.Profile SelectedProfile
80 | {
81 | get => _selectedProfile;
82 | set => SetProperty(ref _selectedProfile, value);
83 | }
84 |
85 | private bool _renameMode;
86 |
87 | public bool RenameMode
88 | {
89 | get => _renameMode;
90 | set => SetProperty(ref _renameMode, value);
91 | }
92 |
93 | #endregion
94 |
95 | #region Methods
96 |
97 | public void Reload()
98 | {
99 | CurrentProfile = AppMan.App.MainSettings.Profile;
100 | ReloadProfiles();
101 | RenameButtonText = LM.GetValue("Profiles.Rename");
102 | RenameMode = false;
103 | ProfileName = null;
104 | }
105 |
106 | private async Task DeleteProfileAction(string name)
107 | {
108 | if (name != AppMan.App.MainSettings.Profile)
109 | {
110 | try
111 | {
112 | File.Delete(AppMan.App.ProfilePath + name + ".json");
113 | }
114 | catch
115 | {
116 | // ignored
117 | }
118 |
119 | ReloadProfiles();
120 | }
121 | else
122 | {
123 | await UIHelper.ShowErrorDialog(LM.GetValue("MessageBox.InvalidProfile"));
124 | }
125 | }
126 |
127 | private void CreateProfileAction()
128 | {
129 | if (!string.IsNullOrEmpty(ProfileName))
130 | {
131 | string filename = FileHelper.MakeValidFileName(ProfileName);
132 | SelectProfileAction(filename);
133 | ReloadProfiles();
134 | }
135 | }
136 |
137 | private ValueTask SelectProfileAction(string name)
138 | {
139 | CurrentProfile = name;
140 | AppMan.App.MainSettings.Profile = name;
141 | AppMan.App.LoadProfile();
142 | AppMan.App.SaveSettings();
143 | AppMan.App.FireSettingsTabEvent();
144 | return new ValueTask();
145 | }
146 |
147 | private void ReloadProfiles()
148 | {
149 | ProfileList = new ObservableCollection();
150 | if (!string.IsNullOrEmpty(AppMan.App.ProfilePath))
151 | {
152 | DirectoryInfo dir = new(AppMan.App.ProfilePath);
153 | foreach (FileInfo file in dir.GetFiles("*.json")) ProfileList.Add(new ProfileModel.Profile {Name = file.Name.Replace(".json", "")});
154 | }
155 | }
156 |
157 | private string _oldname;
158 | private ValueTask RenameProfileAction(string name)
159 | {
160 | if(RenameButtonText == LM.GetValue("Profiles.Rename"))
161 | {
162 | RenameButtonText = LM.GetValue("Profiles.Save");
163 | RenameMode = true;
164 | _oldname = name;
165 | }
166 | else
167 | {
168 | try
169 | {
170 | File.Move(AppMan.App.ProfilePath + _oldname + ".json",AppMan.App.ProfilePath + name + ".json" );
171 | SelectProfileAction(name);
172 | }
173 | catch (Exception e)
174 | {
175 | UIHelper.ShowErrorDialog(e.GetFullMessage());
176 | }
177 | }
178 |
179 |
180 | return new ValueTask();
181 | }
182 | #endregion
183 | }
184 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/Settings.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Http;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using Cyanlabs.Syn3Updater.Helper;
9 | using Cyanlabs.Syn3Updater.Model;
10 | using Cyanlabs.Updater.Common;
11 | using GraphQL;
12 | using ModernWpf.Controls;
13 | using Nito.AsyncEx;
14 |
15 | namespace Cyanlabs.Syn3Updater.UI.Tabs
16 | {
17 | ///
18 | /// Interaction logic for Settings.xaml
19 | ///
20 | public partial class Settings
21 | {
22 | private Api.IvsuRoot _syncVersions;
23 |
24 | public Settings()
25 | {
26 | InitializeComponent();
27 | if (!DesignerProperties.GetIsInDesignMode(this)) (DataContext as SettingsViewModel)?.Init();
28 | }
29 |
30 | private void SyncVersionsAutoSuggestBox_OnGotFocus(object sender, RoutedEventArgs e)
31 | {
32 | if (SyncVersionsAutoSuggestBox.ItemsSource != null) return;
33 | try
34 | {
35 | GraphQLResponse graphQlResponse = Task.Run(async () => await AppMan.App.GraphQlClient.SendQueryAsync(GraphQlRequests.GetAppVersions())).Result;
36 | _syncVersions = graphQlResponse.Data;
37 | }
38 | catch (Exception)
39 | {
40 | //Do nothing
41 | }
42 |
43 | SyncVersionsAutoSuggestBox.ItemsSource = _syncVersions.Ivsus.OrderByDescending(u => u.Version).GroupBy(u => u.Version).Select(u => u.First()).ToList();;
44 | }
45 |
46 | private void Settings_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
47 | {
48 | if ((bool) e.NewValue && !(bool) e.OldValue) (DataContext as SettingsViewModel)?.ReloadSettings();
49 | }
50 |
51 | #region Code to Move to ViewModel at later date
52 |
53 | //TODO - Move to viewModel
54 | private void My20Toggle_OnToggled(object sender, RoutedEventArgs e)
55 | {
56 | (DataContext as SettingsViewModel)?.UpdateMy20Toggle(My20Toggle.IsChecked);
57 | }
58 |
59 | private void AdvancedModeToggle_OnToggled(object sender, RoutedEventArgs e)
60 | {
61 | (DataContext as SettingsViewModel)?.UpdateAdvancedModeToggle(AdvancedToggle.IsOn);
62 | }
63 |
64 | private void AutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
65 | {
66 | if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
67 | SyncVersionsAutoSuggestBox.ItemsSource =
68 | _syncVersions.Ivsus.OrderByDescending(u => u.Version).Where(u => u.Version != null && u.Version.StartsWith(SyncVersionsAutoSuggestBox.Text)).GroupBy(u => u.Version).Select(u => u.First()).ToList();
69 | }
70 |
71 | #endregion
72 | }
73 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/Utility.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Windows;
3 |
4 | namespace Cyanlabs.Syn3Updater.UI.Tabs
5 | {
6 | ///
7 | /// Interaction logic for Install.xaml
8 | ///
9 | public partial class Utility
10 | {
11 | public Utility()
12 | {
13 | InitializeComponent();
14 | if (!DesignerProperties.GetIsInDesignMode(this)) (DataContext as UtilityViewModel)?.Init();
15 | }
16 |
17 | private void Utility_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
18 | {
19 | if (AppMan.App.DriveLetter == "invalid") (DataContext as UtilityViewModel)?.ReloadUSB();
20 | if ((bool) e.NewValue && !(bool) e.OldValue) (DataContext as UtilityViewModel)?.ReloadTab();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Syn3Updater/UI/Tabs/syncversion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cyanlabs/Syn3Updater/a1ce25a7775ab91d06e0e5b85ac5e770c1dea1cd/Syn3Updater/UI/Tabs/syncversion.png
--------------------------------------------------------------------------------
/Syn3Updater/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
53 |
60 |
61 |
62 |
76 |
77 |
--------------------------------------------------------------------------------
/Syn3Updater/cyanlabs.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cyanlabs/Syn3Updater/a1ce25a7775ab91d06e0e5b85ac5e770c1dea1cd/Syn3Updater/cyanlabs.ico
--------------------------------------------------------------------------------
/cyanlabs_setup.nsi:
--------------------------------------------------------------------------------
1 | ;To use this script:
2 | ; 1. Download NSIS (http://nsis.sourceforge.net/Download) and install
3 | ; 2. Add something like the following into your post-build script
4 | ; if $(ConfigurationName) == Release ("C:\Program Files (x86)\NSIS\makensis.exe" /DProductName="$(TargetName)" $(ProjectDir)cyanlabs_setup.nsi)
5 | ; 3. Build your project.
6 | ;
7 |
8 | ; Main constants - define following constants as you want them displayed in your installation wizard
9 | !define PRODUCT_NAME "${ProductName}"
10 | !define PRODUCT_PUBLISHER "CyanLabs"
11 | !define PRODUCT_WEB_SITE "https://cyanlabs.net"
12 |
13 | ; Following constants you should never change
14 | !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
15 | !define PRODUCT_UNINST_ROOT_KEY "HKLM"
16 |
17 | !include "MUI2.nsh"
18 | !define MUI_ABORTWARNING
19 | !define MUI_ICON ".\${PRODUCT_NAME}\cyanlabs.ico"
20 | !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
21 |
22 | Function createicons
23 | SetShellVarContext all
24 | CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\Launcher.exe" ""
25 | CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
26 | CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall Syn3Updater.lnk" "$INSTDIR\uninst.exe" "" "$INSTDIR\uninst.exe" 0
27 | CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\Launcher.exe" "" "$INSTDIR\Launcher.exe" 0
28 | FunctionEnd
29 |
30 | !define MUI_WELCOMEPAGE_TITLE "${PRODUCT_NAME} Setup Wizard"
31 | !define MUI_WELCOMEPAGE_TEXT "Setup will guide you through the installation of ${PRODUCT_NAME}."
32 | !define MUI_DIRECTORYPAGE_TEXT_TOP "Setup will install ${PRODUCT_NAME} in the following folder."
33 | !define MUI_FINISHPAGE_TITLE "${PRODUCT_NAME} Installed"
34 | !define MUI_FINISHPAGE_TEXT "${PRODUCT_NAME} has been installed on your computer."
35 | !define MUI_FINISHPAGE_SHOWREADME ""
36 | !define MUI_FINISHPAGE_SHOWREADME_TEXT "Create StartMenu and Desktop Shortcuts"
37 | !define MUI_FINISHPAGE_SHOWREADME_FUNCTION createicons
38 | !define MUI_FINISHPAGE_RUN "$INSTDIR\Launcher.exe"
39 | #!define MUI_FINISHPAGE_RUN_PARAMETERS "/updated"
40 | !define MUI_FINISHPAGE_RUN_TEXT "Launch ${PRODUCT_NAME}"
41 | !define MUI_FINISHPAGE_LINK "View online documentation"
42 | !define MUI_FINISHPAGE_LINK_LOCATION "https://cyanlabs.net/applications/${PRODUCT_NAME}/"
43 | !define MUI_FINISHPAGE_CANCEL_ENABLED
44 | !define /date MyTIMESTAMP "%d-%m-%Y"
45 |
46 | ; Wizard pages
47 | !insertmacro MUI_PAGE_WELCOME
48 | !insertmacro MUI_PAGE_DIRECTORY
49 | !insertmacro MUI_PAGE_INSTFILES
50 | !insertmacro MUI_PAGE_FINISH
51 | !insertmacro MUI_UNPAGE_INSTFILES
52 | !insertmacro MUI_LANGUAGE "English"
53 |
54 | ; Replace the constants bellow to hit suite your project
55 | Name "${PRODUCT_NAME}"
56 | !system "md bin\Deploy"
57 | OutFile "bin\Deploy\${PRODUCT_NAME}_${MyTIMESTAMP}.exe"
58 | InstallDir "$PROGRAMFILES\${PRODUCT_PUBLISHER}\${PRODUCT_NAME}"
59 |
60 | ShowInstDetails show
61 | ShowUnInstDetails show
62 |
63 | ; Following lists the files you want to include, go through this list carefully!
64 | Section "MainSection" SEC01
65 | SetOutPath "$INSTDIR"
66 | SetOverwrite ifnewer
67 | Delete "$SMPROGRAMS\${PRODUCT_NAME}\*.*"
68 | File "bin\Release\net472\Launcher.exe"
69 | File "bin\Release\net472\Newtonsoft.Json.dll"
70 | File "bin\Release\net472\FluentWPF.dll"
71 | File "bin\Release\net472\Octokit.dll"
72 | SectionEnd
73 |
74 | Section -Post
75 | ;Following lines will make uninstaller work - do not change anything, unless you really want to.
76 | WriteUninstaller "$INSTDIR\uninst.exe"
77 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
78 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
79 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
80 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
81 | WriteRegStr HKCR "syn3updater" "" "Syn3 Updater Link"
82 | WriteRegStr HKCR "syn3updater" "URL Protocol" ""
83 | WriteRegStr HKCR "syn3updater\\shell\\open\\command" "" "$INSTDIR\Launcher.exe %1"
84 | SectionEnd
85 |
86 | ; Removal of application files and reg keys.
87 | Section Uninstall
88 | SetShellVarContext all
89 | RMDir /r "$INSTDIR"
90 | DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
91 | DeleteRegKey HKCR "syn3updater"
92 | Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
93 | RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
94 | RMDir /r "$APPDATA\CyanLabs\${PRODUCT_NAME}"
95 | SetShellVarContext current
96 | RMDir /r "$LOCALAPPDATA\CyanLabs\${PRODUCT_NAME}"
97 | SetAutoClose true
98 | SectionEnd
99 |
100 | Function .onInstSuccess
101 | IfSilent 0 +2
102 | Exec '"$INSTDIR\Launcher.exe"'
103 | FunctionEnd
--------------------------------------------------------------------------------