├── .gitattributes
├── .gitignore
├── Horizon.slnx
├── LICENSE
├── README.md
├── external
├── KeyboardShortcutsJS
│ └── main.js
└── QRCoder
│ ├── AbstractQRCode.cs
│ ├── BitmapByteQRCode.cs
│ ├── Exceptions
│ └── DataTooLongException.cs
│ ├── Extensions
│ └── BitArrayExtensions.cs
│ ├── PayloadGenerator
│ ├── Payload.cs
│ └── Url.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── QRCodeData.cs
│ ├── QRCodeGenerator.cs
│ ├── QRCodeGenerator
│ ├── AlignmentPattern.cs
│ ├── CodewordBlock.cs
│ ├── ECCInfo.cs
│ ├── ECCLevel.cs
│ ├── EciMode.cs
│ ├── EncodingMode.cs
│ ├── ModulePlacer.BlockedModules.cs
│ ├── ModulePlacer.MaskPattern.cs
│ ├── ModulePlacer.cs
│ ├── Point.cs
│ ├── Polynom.cs
│ ├── PolynomItem.cs
│ ├── Rectangle.cs
│ ├── VersionInfo.cs
│ └── VersionInfoDetails.cs
│ └── QRCoder.csproj
├── images
├── ghreleasesbadge.png
└── msstorebadge.png
├── package
└── Horizon.Package
│ ├── Assets
│ ├── AppIcons
│ │ ├── LargeTile.scale-100.png
│ │ ├── LargeTile.scale-125.png
│ │ ├── LargeTile.scale-150.png
│ │ ├── LargeTile.scale-200.png
│ │ ├── LargeTile.scale-400.png
│ │ ├── SmallTile.scale-100.png
│ │ ├── SmallTile.scale-125.png
│ │ ├── SmallTile.scale-150.png
│ │ ├── SmallTile.scale-200.png
│ │ ├── SmallTile.scale-400.png
│ │ ├── SplashScreen.scale-100.png
│ │ ├── SplashScreen.scale-125.png
│ │ ├── SplashScreen.scale-150.png
│ │ ├── SplashScreen.scale-200.png
│ │ ├── SplashScreen.scale-400.png
│ │ ├── Square150x150Logo.scale-100.png
│ │ ├── Square150x150Logo.scale-125.png
│ │ ├── Square150x150Logo.scale-150.png
│ │ ├── Square150x150Logo.scale-200.png
│ │ ├── Square150x150Logo.scale-400.png
│ │ ├── Square44x44Logo.altform-lightunplated_targetsize-16.png
│ │ ├── Square44x44Logo.altform-lightunplated_targetsize-24.png
│ │ ├── Square44x44Logo.altform-lightunplated_targetsize-256.png
│ │ ├── Square44x44Logo.altform-lightunplated_targetsize-32.png
│ │ ├── Square44x44Logo.altform-lightunplated_targetsize-48.png
│ │ ├── Square44x44Logo.altform-unplated_targetsize-16.png
│ │ ├── Square44x44Logo.altform-unplated_targetsize-256.png
│ │ ├── Square44x44Logo.altform-unplated_targetsize-32.png
│ │ ├── Square44x44Logo.altform-unplated_targetsize-48.png
│ │ ├── Square44x44Logo.scale-100.png
│ │ ├── Square44x44Logo.scale-125.png
│ │ ├── Square44x44Logo.scale-150.png
│ │ ├── Square44x44Logo.scale-200.png
│ │ ├── Square44x44Logo.scale-400.png
│ │ ├── Square44x44Logo.targetsize-16.png
│ │ ├── Square44x44Logo.targetsize-24.png
│ │ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ │ ├── Square44x44Logo.targetsize-256.png
│ │ ├── Square44x44Logo.targetsize-32.png
│ │ ├── Square44x44Logo.targetsize-48.png
│ │ ├── StoreLogo.scale-100.png
│ │ ├── StoreLogo.scale-125.png
│ │ ├── StoreLogo.scale-150.png
│ │ ├── StoreLogo.scale-200.png
│ │ ├── StoreLogo.scale-400.png
│ │ ├── Wide310x150Logo.scale-100.png
│ │ ├── Wide310x150Logo.scale-125.png
│ │ ├── Wide310x150Logo.scale-150.png
│ │ ├── Wide310x150Logo.scale-200.png
│ │ └── Wide310x150Logo.scale-400.png
│ ├── FileIcons
│ │ ├── document.png
│ │ └── link.png
│ ├── Icons
│ │ ├── DevSanx.png
│ │ └── paypal.png
│ └── JS
│ │ └── readability.js
│ ├── Horizon.Package.wapproj
│ └── Package.appxmanifest
└── src
├── App.xaml
├── App.xaml.cs
├── Controls
└── Tabs
│ ├── Tab.cs
│ └── WebTabCreationParams.cs
├── Core
├── AppVersionHelper.cs
├── Backdrops.cs
├── ClipboardHelper.cs
├── FileHelper.cs
├── FolderHelper.cs
├── IconHelper.cs
├── ModernAboutBlank.cs
├── SearchEngine.cs
├── SearchEngineHelper.cs
├── SettingsHelper.cs
├── UrlHelper.cs
├── WebView2ProfileHelper.cs
├── Win32Helper.cs
├── WindowHelper.cs
└── WindowsHelloHelper.cs
├── GlobalUsings.cs
├── Horizon.csproj
├── Horizon.ico
├── Modules
├── Favorites
│ ├── FavoriteItem.cs
│ └── FavoritesHelper.cs
├── QRCodeGen
│ └── QRCodeHelper.cs
└── Readability
│ └── ReadabilityHelper.cs
├── NativeMethods.txt
├── Pages
├── ExtensionsPage.xaml
├── ExtensionsPage.xaml.cs
├── SettingsPage.xaml
├── SettingsPage.xaml.cs
├── SplitTabPage.xaml
├── SplitTabPage.xaml.cs
├── WebViewPage.xaml
└── WebViewPage.xaml.cs
├── Properties
└── PublishProfiles
│ ├── win-arm64.pubxml
│ └── win-x64.pubxml
├── Styles
└── Merged.xaml
├── ViewModels
└── SettingsViewModel.cs
├── WindowChrome.xaml
├── WindowChrome.xaml.cs
└── app.manifest
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.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/main/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 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual Studio profiler
105 | *.psess
106 | *.vsp
107 | *.vspx
108 | *.sap
109 |
110 | # Visual Studio Trace Files
111 | *.e2e
112 |
113 | # TFS 2012 Local Workspace
114 | $tf/
115 |
116 | # Guidance Automation Toolkit
117 | *.gpState
118 |
119 | # ReSharper is a .NET coding add-in
120 | _ReSharper*/
121 | *.[Rr]e[Ss]harper
122 | *.DotSettings.user
123 |
124 | # TeamCity is a build add-in
125 | _TeamCity*
126 |
127 | # DotCover is a Code Coverage Tool
128 | *.dotCover
129 |
130 | # AxoCover is a Code Coverage Tool
131 | .axoCover/*
132 | !.axoCover/settings.json
133 |
134 | # Coverlet is a free, cross platform Code Coverage Tool
135 | coverage*.json
136 | coverage*.xml
137 | coverage*.info
138 |
139 | # Visual Studio code coverage results
140 | *.coverage
141 | *.coveragexml
142 |
143 | # NCrunch
144 | _NCrunch_*
145 | .*crunch*.local.xml
146 | nCrunchTemp_*
147 |
148 | # MightyMoose
149 | *.mm.*
150 | AutoTest.Net/
151 |
152 | # Web workbench (sass)
153 | .sass-cache/
154 |
155 | # Installshield output folder
156 | [Ee]xpress/
157 |
158 | # DocProject is a documentation generator add-in
159 | DocProject/buildhelp/
160 | DocProject/Help/*.HxT
161 | DocProject/Help/*.HxC
162 | DocProject/Help/*.hhc
163 | DocProject/Help/*.hhk
164 | DocProject/Help/*.hhp
165 | DocProject/Help/Html2
166 | DocProject/Help/html
167 |
168 | # Click-Once directory
169 | publish/
170 |
171 | # Publish Web Output
172 | *.[Pp]ublish.xml
173 | *.azurePubxml
174 | # Note: Comment the next line if you want to checkin your web deploy settings,
175 | # but database connection strings (with potential passwords) will be unencrypted
176 | # *.pubxml
177 | *.publishproj
178 |
179 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
180 | # checkin your Azure Web App publish settings, but sensitive information contained
181 | # in these scripts will be unencrypted
182 | PublishScripts/
183 |
184 | # NuGet Packages
185 | *.nupkg
186 | # NuGet Symbol Packages
187 | *.snupkg
188 | # The packages folder can be ignored because of Package Restore
189 | **/[Pp]ackages/*
190 | # except build/, which is used as an MSBuild target.
191 | !**/[Pp]ackages/build/
192 | # Uncomment if necessary however generally it will be regenerated when needed
193 | #!**/[Pp]ackages/repositories.config
194 | # NuGet v3's project.json files produces more ignorable files
195 | *.nuget.props
196 | *.nuget.targets
197 |
198 | # Microsoft Azure Build Output
199 | csx/
200 | *.build.csdef
201 |
202 | # Microsoft Azure Emulator
203 | ecf/
204 | rcf/
205 |
206 | # Windows Store app package directories and files
207 | AppPackages/
208 | BundleArtifacts/
209 | Package.StoreAssociation.xml
210 | _pkginfo.txt
211 | *.appx
212 | *.appxbundle
213 | *.appxupload
214 |
215 | # Visual Studio cache files
216 | # files ending in .cache can be ignored
217 | *.[Cc]ache
218 | # but keep track of directories ending in .cache
219 | !?*.[Cc]ache/
220 |
221 | # Others
222 | ClientBin/
223 | ~$*
224 | *~
225 | *.dbmdl
226 | *.dbproj.schemaview
227 | *.jfm
228 | *.pfx
229 | *.publishsettings
230 | orleans.codegen.cs
231 |
232 | # Including strong name files can present a security risk
233 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
234 | #*.snk
235 |
236 | # Since there are multiple workflows, uncomment next line to ignore bower_components
237 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
238 | #bower_components/
239 |
240 | # RIA/Silverlight projects
241 | Generated_Code/
242 |
243 | # Backup & report files from converting an old project file
244 | # to a newer Visual Studio version. Backup files are not needed,
245 | # because we have git ;-)
246 | _UpgradeReport_Files/
247 | Backup*/
248 | UpgradeLog*.XML
249 | UpgradeLog*.htm
250 | ServiceFabricBackup/
251 | *.rptproj.bak
252 |
253 | # SQL Server files
254 | *.mdf
255 | *.ldf
256 | *.ndf
257 |
258 | # Business Intelligence projects
259 | *.rdl.data
260 | *.bim.layout
261 | *.bim_*.settings
262 | *.rptproj.rsuser
263 | *- [Bb]ackup.rdl
264 | *- [Bb]ackup ([0-9]).rdl
265 | *- [Bb]ackup ([0-9][0-9]).rdl
266 |
267 | # Microsoft Fakes
268 | FakesAssemblies/
269 |
270 | # GhostDoc plugin setting file
271 | *.GhostDoc.xml
272 |
273 | # Node.js Tools for Visual Studio
274 | .ntvs_analysis.dat
275 | node_modules/
276 |
277 | # Visual Studio 6 build log
278 | *.plg
279 |
280 | # Visual Studio 6 workspace options file
281 | *.opt
282 |
283 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
284 | *.vbw
285 |
286 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
287 | *.vbp
288 |
289 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
290 | *.dsw
291 | *.dsp
292 |
293 | # Visual Studio 6 technical files
294 | *.ncb
295 | *.aps
296 |
297 | # Visual Studio LightSwitch build output
298 | **/*.HTMLClient/GeneratedArtifacts
299 | **/*.DesktopClient/GeneratedArtifacts
300 | **/*.DesktopClient/ModelManifest.xml
301 | **/*.Server/GeneratedArtifacts
302 | **/*.Server/ModelManifest.xml
303 | _Pvt_Extensions
304 |
305 | # Paket dependency manager
306 | .paket/paket.exe
307 | paket-files/
308 |
309 | # FAKE - F# Make
310 | .fake/
311 |
312 | # CodeRush personal settings
313 | .cr/personal
314 |
315 | # Python Tools for Visual Studio (PTVS)
316 | __pycache__/
317 | *.pyc
318 |
319 | # Cake - Uncomment if you are using it
320 | # tools/**
321 | # !tools/packages.config
322 |
323 | # Tabs Studio
324 | *.tss
325 |
326 | # Telerik's JustMock configuration file
327 | *.jmconfig
328 |
329 | # BizTalk build output
330 | *.btp.cs
331 | *.btm.cs
332 | *.odx.cs
333 | *.xsd.cs
334 |
335 | # OpenCover UI analysis results
336 | OpenCover/
337 |
338 | # Azure Stream Analytics local run output
339 | ASALocalRun/
340 |
341 | # MSBuild Binary and Structured Log
342 | *.binlog
343 |
344 | # NVidia Nsight GPU debugger configuration file
345 | *.nvuser
346 |
347 | # MFractors (Xamarin productivity tool) working folder
348 | .mfractor/
349 |
350 | # Local History for Visual Studio
351 | .localhistory/
352 |
353 | # Visual Studio History (VSHistory) files
354 | .vshistory/
355 |
356 | # BeatPulse healthcheck temp database
357 | healthchecksdb
358 |
359 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
360 | MigrationBackup/
361 |
362 | # Ionide (cross platform F# VS Code tools) working folder
363 | .ionide/
364 |
365 | # Fody - auto-generated XML schema
366 | FodyWeavers.xsd
367 |
368 | # VS Code files for those working on multiple tools
369 | .vscode/*
370 | !.vscode/settings.json
371 | !.vscode/tasks.json
372 | !.vscode/launch.json
373 | !.vscode/extensions.json
374 | *.code-workspace
375 |
376 | # Local History for Visual Studio Code
377 | .history/
378 |
379 | # Windows Installer files from build outputs
380 | *.cab
381 | *.msi
382 | *.msix
383 | *.msm
384 | *.msp
385 |
386 | # JetBrains Rider
387 | *.sln.iml
388 |
--------------------------------------------------------------------------------
/Horizon.slnx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Horizon is a modern webbrowser which enhances your browsing experience. It has been in active development for over two years, and is being constantly updated with bug fixes, performance improvements and new features.
13 |
14 | ## Headline features:
15 | - Responsive UI and quick startup time
16 | - Integrates nicely with other native Windows apps
17 | - Split tabs
18 | - Reading mode
19 | - Translate websites
20 | - Password lock
21 | - Generate QRCode for website
22 | - Export page to pdf (version 5.1 and newer)
23 | - Export page text content as txt (version 7.5 and newer)
24 | - New tab background images
25 | - Focus mode
26 |
27 | Check the app out to see them in action!
28 |
29 | ## Installing
30 |
31 | You can get Horizon from the main sources:
32 |
33 | ### Microsoft Store (recommended)
34 |
35 | This is the recommended source for most users, you can get Horizon easily [here](https://apps.microsoft.com/detail/9pfs0vxcd5sr)
36 |
37 | ### Winget
38 |
39 | If you prefer installing your apps from the command line, you can do so via winget
40 |
41 | ```batch
42 | winget install HorizonBrowser
43 | ```
44 |
45 | ### GitHub releases (advanced)
46 |
47 | > [!WARNING]
48 | > You might not recive updates if you install Horizon this way, thus this method is only recommended for advanced users
49 |
50 | If you like to get the msix for yourself and install without winget or Microsoft Store, you can get the package [here](https://github.com/horizon-developers/browser/releases)
51 |
52 | You have to get the dependencies for your architecture (either X86, X64 or ARM64) as well as the main package. Then you can install them via PowerShell or App installer
53 |
54 | ```powershell
55 | Add-AppxPackage ".\Microsoft.WindowsAppRuntime.1.7_7000.456.1632.0_arm64__8wekyb3d8bbwe.msix"
56 | Add-AppxPackage ".\Microsoft.VCLibs.140.00_14.0.33519.0_arm64__8wekyb3d8bbwe.appx"
57 | Add-AppxPackage ".\Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_arm64__8wekyb3d8bbwe.appx"
58 | Add-AppxPackage ".\HorizonBrowser_10.0.5.0.msixbundle"
59 | ```
60 | Be sure to replace them with the names of your packages according to your system and the latest versions
61 | ## Contributing
62 |
63 | ### Contributing source code
64 | You would like to contribute to this project?
65 |
66 | Awesome! Please first create an issue, so we can talk about the changes you like to implement
67 |
68 | ### Support the project by donating
69 | You would like to support this project because you love it, but do not have the time or expertise to contribute source code?
70 |
71 | A donation would be highly appreciated, and it helps me out a lot. Thanks :)
72 |
73 | [PayPal](https://www.paypal.com/paypalme/julianhasreiter)
74 |
75 | ## Building from source
76 |
77 | ### 1. Prerequisites
78 | - Visual Studio 2022, version 17.13 or newer
79 | - Windows 11 SDK (10.0.26100.0)
80 | - .NET 9 SDK
81 | - Windows Application Workload
82 |
83 | ### 2. Clone the repository
84 | ```batch
85 | git clone https://github.com/horizon-developers/browser.git
86 | ```
87 |
88 | ### 3. Build the app
89 | In the newly cloned folder, navigate into the src folder and open Horizon.sln (or Horizon.slnx if you prefer that)
90 | On the top, select your configuration and platform and click on the play icon.
91 | Now VS should start building the app and will start it shortly.
92 |
93 | ## License
94 | GPL v3.0
95 |
--------------------------------------------------------------------------------
/external/KeyboardShortcutsJS/main.js:
--------------------------------------------------------------------------------
1 | document.addEventListener("keydown", function (event) {
2 | if (event.ctrlKey && event.key === "l") {
3 | event.preventDefault();
4 | window.chrome.webview.postMessage("ControlL");
5 | }
6 | if (event.ctrlKey && event.key === "t") {
7 | event.preventDefault();
8 | window.chrome.webview.postMessage("ControlT");
9 | }
10 | });
--------------------------------------------------------------------------------
/external/QRCoder/AbstractQRCode.cs:
--------------------------------------------------------------------------------
1 | namespace QRCoder;
2 |
3 | ///
4 | /// Abstract base class for generating QR codes.
5 | /// Derived classes typically render a QR code into a specific format (png, System.Drawing.Bitmap, PDF, etc).
6 | ///
7 | public abstract class AbstractQRCode
8 | {
9 | ///
10 | /// Gets or sets the QRCodeData used to generate the QR code.
11 | ///
12 | protected QRCodeData QrCodeData { get; set; }
13 |
14 | ///
15 | /// Initializes a new instance of the AbstractQRCode class.
16 | ///
17 | protected AbstractQRCode()
18 | {
19 | QrCodeData = null!;
20 | }
21 |
22 | ///
23 | /// Initializes a new instance of the AbstractQRCode class with the specified QRCodeData.
24 | ///
25 | /// The QRCodeData object generated by QRCodeGenerator.CreateQrCode().
26 | protected AbstractQRCode(QRCodeData data)
27 | {
28 | QrCodeData = data;
29 | }
30 |
31 | ///
32 | /// Sets the QRCodeData object that will be used to generate the QR code.
33 | /// This method is useful for COM objects connections.
34 | ///
35 | /// The QRCodeData object generated by QRCodeGenerator.CreateQrCode().
36 | public virtual void SetQRCodeData(QRCodeData data)
37 | => QrCodeData = data;
38 |
39 | ///
40 | /// Disposes the QRCodeData object.
41 | ///
42 | public void Dispose()
43 | {
44 | QrCodeData?.Dispose();
45 | QrCodeData = null!;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/external/QRCoder/BitmapByteQRCode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using static QRCoder.QRCodeGenerator;
3 |
4 | namespace QRCoder;
5 |
6 |
7 | ///
8 | /// Represents a QR code generator that outputs QR codes as bitmap byte arrays.
9 | ///
10 | // ReSharper disable once InconsistentNaming
11 | public class BitmapByteQRCode : AbstractQRCode, IDisposable
12 | {
13 | private static readonly byte[] _bitmapHeaderPart1 = new byte[] { 0x42, 0x4D };
14 | private static readonly byte[] _bitmapHeaderPart2 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 };
15 | private static readonly byte[] _bitmapHeaderPartEnd = new byte[] { 0x01, 0x00, 0x18, 0x00 };
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | /// Constructor without parameters to be used in COM objects connections.
20 | ///
21 | public BitmapByteQRCode() { }
22 |
23 | ///
24 | /// Initializes a new instance of the class with the specified .
25 | ///
26 | /// generated by the QRCodeGenerator.
27 | public BitmapByteQRCode(QRCodeData data) : base(data) { }
28 |
29 | ///
30 | /// Returns the QR code graphic as a bitmap byte array.
31 | ///
32 | /// The number of pixels each dark/light module of the QR code will occupy in the final QR code image.
33 | /// Returns the QR code graphic as a bitmap byte array.
34 | public byte[] GetGraphic(int pixelsPerModule)
35 | => GetGraphic(pixelsPerModule, new byte[] { 0x00, 0x00, 0x00 }, new byte[] { 0xFF, 0xFF, 0xFF });
36 |
37 | ///
38 | /// Returns the QR code graphic as a bitmap byte array.
39 | ///
40 | /// The number of pixels each dark/light module of the QR code will occupy in the final QR code image.
41 | /// The color of the dark modules in HTML hex format.
42 | /// The color of the light modules in HTML hex format.
43 | /// Returns the QR code graphic as a bitmap byte array.
44 | public byte[] GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex)
45 | => GetGraphic(pixelsPerModule, HexColorToByteArray(darkColorHtmlHex), HexColorToByteArray(lightColorHtmlHex));
46 |
47 | ///
48 | /// Returns the QR code graphic as a bitmap byte array.
49 | ///
50 | /// The number of pixels each dark/light module of the QR code will occupy in the final QR code image.
51 | /// The color of the dark modules as an RGB byte array.
52 | /// The color of the light modules as an RGB byte array.
53 | /// Returns the QR code graphic as a bitmap byte array.
54 | public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightColorRgb)
55 | {
56 | var sideLength = QrCodeData.ModuleMatrix.Count * pixelsPerModule;
57 |
58 | // Pre-calculate color/module bytes
59 | byte[] moduleDark = new byte[pixelsPerModule * 3];
60 | byte[] moduleLight = new byte[pixelsPerModule * 3];
61 | for (int i = 0; i < pixelsPerModule * 3; i += 3)
62 | {
63 | moduleDark[i] = darkColorRgb[2];
64 | moduleDark[i + 1] = darkColorRgb[1];
65 | moduleDark[i + 2] = darkColorRgb[0];
66 | moduleLight[i] = lightColorRgb[2];
67 | moduleLight[i + 1] = lightColorRgb[1];
68 | moduleLight[i + 2] = lightColorRgb[0];
69 | }
70 |
71 | // Pre-calculate padding bytes
72 | var paddingLen = sideLength % 4;
73 |
74 | // Calculate filesize (header + pixel data + padding)
75 | var fileSize = 54 + (3 * (sideLength * sideLength)) + (sideLength * paddingLen);
76 |
77 | // Bitmap container
78 | byte[] bmp = new byte[fileSize];
79 | int ix = 0;
80 |
81 | // Header part 1
82 | Array.Copy(_bitmapHeaderPart1, 0, bmp, ix, _bitmapHeaderPart1.Length);
83 | ix += _bitmapHeaderPart1.Length;
84 |
85 | // Filesize
86 | CopyIntAs4ByteToArray(fileSize, ix, bmp);
87 | ix += 4;
88 |
89 | // Header part 2
90 | Array.Copy(_bitmapHeaderPart2, 0, bmp, ix, _bitmapHeaderPart2.Length);
91 | ix += _bitmapHeaderPart2.Length;
92 |
93 | // Width
94 | CopyIntAs4ByteToArray(sideLength, ix, bmp);
95 | ix += 4;
96 | // Height
97 | CopyIntAs4ByteToArray(sideLength, ix, bmp);
98 | ix += 4;
99 |
100 | // Header end
101 | Array.Copy(_bitmapHeaderPartEnd, 0, bmp, ix, _bitmapHeaderPartEnd.Length);
102 | ix += _bitmapHeaderPartEnd.Length;
103 |
104 | // Add header null-bytes
105 | ix += 24;
106 |
107 |
108 | // Draw qr code
109 | for (var x = sideLength - 1; x >= 0; x -= pixelsPerModule)
110 | {
111 | var modMatrixX = (x + pixelsPerModule) / pixelsPerModule - 1;
112 |
113 | // Write data for first pixel of pixelsPerModule
114 | int posStartFirstPx = ix;
115 | for (var y = 0; y < sideLength; y += pixelsPerModule)
116 | {
117 | var module = QrCodeData.ModuleMatrix[modMatrixX][(y + pixelsPerModule) / pixelsPerModule - 1];
118 | Array.Copy(module ? moduleDark : moduleLight, 0, bmp, ix, moduleDark.Length);
119 | ix += moduleDark.Length;
120 | }
121 | // Add padding (to make line length a multiple of 4)
122 | ix += paddingLen;
123 | int lenFirstPx = ix - posStartFirstPx;
124 |
125 | // Re-write (copy) first pixel (pixelsPerModule - 1) times
126 | for (int pm = 0; pm < (pixelsPerModule - 1); pm++)
127 | {
128 | // Draw pixels
129 | Array.Copy(bmp, posStartFirstPx, bmp, ix, lenFirstPx);
130 | ix += lenFirstPx;
131 | }
132 | }
133 |
134 | return bmp;
135 | }
136 |
137 |
138 | ///
139 | /// Converts a hex color string to a byte array.
140 | ///
141 | /// The hex color string to convert.
142 | /// Returns the color as a byte array.
143 | private byte[] HexColorToByteArray(string colorString)
144 | {
145 | if (colorString.StartsWith("#"))
146 | colorString = colorString.Substring(1);
147 | byte[] byteColor = new byte[colorString.Length / 2];
148 | for (int i = 0; i < byteColor.Length; i++)
149 | byteColor[i] = byte.Parse(colorString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture);
150 | return byteColor;
151 | }
152 |
153 |
154 | ///
155 | /// Converts an integer to a 4 bytes and writes them to a byte array at given position
156 | ///
157 | /// The integer to convert.
158 | /// Index of destinationArray where the converted bytes are written to
159 | /// Destination byte array that receives the bytes
160 | private void CopyIntAs4ByteToArray(int inp, int destinationIndex, byte[] destinationArray)
161 | {
162 | unchecked
163 | {
164 | destinationArray[destinationIndex + 3] = (byte)(inp >> 24);
165 | destinationArray[destinationIndex + 2] = (byte)(inp >> 16);
166 | destinationArray[destinationIndex + 1] = (byte)(inp >> 8);
167 | destinationArray[destinationIndex + 0] = (byte)(inp);
168 | }
169 | }
170 | }
171 |
172 |
173 | ///
174 | /// Provides helper functions for creating bitmap byte array QR codes.
175 | ///
176 | public static class BitmapByteQRCodeHelper
177 | {
178 | ///
179 | /// Creates a bitmap byte array QR code with a single function call.
180 | ///
181 | /// The text or payload to be encoded inside the QR code.
182 | /// The number of pixels each dark/light module of the QR code will occupy in the final QR code image.
183 | /// The color of the dark modules in HTML hex format.
184 | /// The color of the light modules in HTML hex format.
185 | /// The level of error correction data.
186 | /// Specifies whether the generator should be forced to work in UTF-8 mode.
187 | /// Specifies whether the byte-order-mark should be used.
188 | /// Specifies which ECI mode should be used.
189 | /// Sets the fixed QR code target version.
190 | /// Returns the QR code graphic as a bitmap byte array.
191 | public static byte[] GetQRCode(string plainText, int pixelsPerModule, string darkColorHtmlHex,
192 | string lightColorHtmlHex, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false,
193 | EciMode eciMode = EciMode.Default, int requestedVersion = -1)
194 | {
195 | using var qrGenerator = new QRCodeGenerator();
196 | using var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode,
197 | requestedVersion);
198 | using var qrCode = new BitmapByteQRCode(qrCodeData);
199 | return qrCode.GetGraphic(pixelsPerModule, darkColorHtmlHex, lightColorHtmlHex);
200 | }
201 |
202 | ///
203 | /// Creates a bitmap byte array QR code with a single function call.
204 | ///
205 | /// The text or payload to be encoded inside the QR code.
206 | /// The level of error correction data.
207 | /// The number of pixels each dark/light module of the QR code will occupy in the final QR code image.
208 | /// Returns the QR code graphic as a bitmap byte array.
209 | public static byte[] GetQRCode(string txt, QRCodeGenerator.ECCLevel eccLevel, int size)
210 | {
211 | using var qrGen = new QRCodeGenerator();
212 | using var qrCode = qrGen.CreateQrCode(txt, eccLevel);
213 | using var qrBmp = new BitmapByteQRCode(qrCode);
214 | return qrBmp.GetGraphic(size);
215 |
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/external/QRCoder/Exceptions/DataTooLongException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace QRCoder.Exceptions;
4 |
5 | ///
6 | /// Exception thrown when the given payload exceeds the maximum size of the QR code standard.
7 | ///
8 | public class DataTooLongException : Exception
9 | {
10 | ///
11 | /// Initializes a new instance of the class with a specified error message.
12 | ///
13 | /// The error correction level of the QR code.
14 | /// The encoding mode of the QR code.
15 | /// The maximum size allowed for the given parameters in bytes.
16 | public DataTooLongException(string eccLevel, string encodingMode, int maxSizeByte) : base(
17 | $"The given payload exceeds the maximum size of the QR code standard. The maximum size allowed for the chosen parameters (ECC level={eccLevel}, EncodingMode={encodingMode}) is {maxSizeByte} bytes."
18 | )
19 | { }
20 |
21 | ///
22 | /// Initializes a new instance of the class with a specified error message.
23 | ///
24 | /// The error correction level of the QR code.
25 | /// The encoding mode of the QR code.
26 | /// The fixed version of the QR code.
27 | /// The maximum size allowed for the given parameters in bytes.
28 | public DataTooLongException(string eccLevel, string encodingMode, int version, int maxSizeByte) : base(
29 | $"The given payload exceeds the maximum size of the QR code standard. The maximum size allowed for the chosen parameters (ECC level={eccLevel}, EncodingMode={encodingMode}, FixedVersion={version}) is {maxSizeByte} bytes."
30 | )
31 | { }
32 | }
33 |
--------------------------------------------------------------------------------
/external/QRCoder/Extensions/BitArrayExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 |
3 | namespace QRCoder;
4 |
5 | ///
6 | /// Helper methods for .
7 | ///
8 | internal static class BitArrayExtensions
9 | {
10 | ///
11 | /// Copies a specified number of elements from one to another starting at the specified offsets.
12 | ///
13 | /// The source from which elements will be copied.
14 | /// The zero-based index in the source at which copying begins.
15 | /// The destination to which elements will be copied.
16 | /// The zero-based index in the destination at which storing begins.
17 | /// The number of elements to copy.
18 | /// The index in the destination immediately following the last copied element.
19 | public static int CopyTo(this BitArray source, BitArray destination, int sourceOffset, int destinationOffset, int count)
20 | {
21 | for (int i = 0; i < count; i++)
22 | {
23 | destination[destinationOffset + i] = source[sourceOffset + i];
24 | }
25 | return destinationOffset + count;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/external/QRCoder/PayloadGenerator/Payload.cs:
--------------------------------------------------------------------------------
1 | namespace QRCoder;
2 |
3 | ///
4 | /// Contains classes and methods for generating payloads for QR codes.
5 | ///
6 | public static partial class PayloadGenerator
7 | {
8 | ///
9 | /// Represents the base class for all QR code payloads.
10 | ///
11 | public abstract class Payload
12 | {
13 | ///
14 | /// Gets the version of the QR code payload.
15 | ///
16 | public virtual int Version => -1;
17 |
18 | ///
19 | /// Gets the error correction level of the QR code payload.
20 | ///
21 | public virtual QRCodeGenerator.ECCLevel EccLevel => QRCodeGenerator.ECCLevel.Default;
22 |
23 | ///
24 | /// Gets the ECI mode of the QR code payload.
25 | ///
26 | public virtual QRCodeGenerator.EciMode EciMode => QRCodeGenerator.EciMode.Default;
27 |
28 | ///
29 | /// Returns a string representation of the QR code payload.
30 | ///
31 | /// A string representation of the QR code payload.
32 | public abstract override string ToString();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/external/QRCoder/PayloadGenerator/Url.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace QRCoder;
4 |
5 | public static partial class PayloadGenerator
6 | {
7 | ///
8 | /// Generates a URL payload for QR codes.
9 | ///
10 | public class Url : Payload
11 | {
12 | private readonly string _url;
13 |
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | /// The target URL. If the protocol is not specified, the http protocol will be added.
18 | public Url(string url)
19 | {
20 | _url = url;
21 | }
22 |
23 | ///
24 | /// Returns the URL payload as a string.
25 | ///
26 | /// The URL payload as a string, ensuring it starts with "http://" if no protocol is specified.
27 | public override string ToString()
28 | => !_url.StartsWith("http", StringComparison.OrdinalIgnoreCase) ? "http://" + _url : _url;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/external/QRCoder/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // Allgemeine Informationen über eine Assembly werden über die folgenden
5 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
6 | // die mit einer Assembly verknüpft sind.
7 | [assembly: AssemblyTitle("QRCoder")]
8 | [assembly: AssemblyDescription("QRCoder is a simple library, written in C#.NET, which enables you to create QR Codes. It's licensed under the MIT-license.")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("www.code-bude.net")]
11 | [assembly: AssemblyProduct("QRCoder")]
12 | [assembly: AssemblyCopyright("Copyright © www.code-bude.net / Raffael Herrmann. All rights reserved.")]
13 | [assembly: AssemblyTrademark("written by Raffael Herrmann")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
17 | // für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
18 | // COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
19 | [assembly: ComVisible(true)]
20 |
21 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
22 | [assembly: Guid("e668b98b-83bb-4e60-b33c-4fd5ed9c0156")]
23 |
24 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
25 | //
26 | // Hauptversion
27 | // Nebenversion
28 | // Buildnummer
29 | // Revision
30 | //
31 | // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
32 | // übernehmen, indem Sie "*" eingeben:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.6.1.0")]
35 | [assembly: AssemblyFileVersion("1.6.1.0")]
36 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.IO.Compression;
6 |
7 | namespace QRCoder;
8 |
9 | ///
10 | /// Represents the data structure of a QR code.
11 | ///
12 | public class QRCodeData : IDisposable
13 | {
14 | ///
15 | /// Gets or sets the module matrix of the QR code.
16 | ///
17 | public List ModuleMatrix { get; set; }
18 |
19 | ///
20 | /// Initializes a new instance of the class with the specified version.
21 | ///
22 | /// The version of the QR code.
23 | public QRCodeData(int version)
24 | {
25 | Version = version;
26 | var size = ModulesPerSideFromVersion(version);
27 | ModuleMatrix = new List(size);
28 | for (var i = 0; i < size; i++)
29 | ModuleMatrix.Add(new BitArray(size));
30 | }
31 |
32 | ///
33 | /// Initializes a new instance of the class with the specified version and padding option.
34 | ///
35 | /// The version of the QR code.
36 | /// Indicates whether padding should be added to the QR code.
37 | public QRCodeData(int version, bool addPadding)
38 | {
39 | Version = version;
40 | var size = ModulesPerSideFromVersion(version) + (addPadding ? 8 : 0);
41 | ModuleMatrix = new List(size);
42 | for (var i = 0; i < size; i++)
43 | ModuleMatrix.Add(new BitArray(size));
44 | }
45 |
46 | ///
47 | /// Initializes a new instance of the class with raw data from a specified path and compression mode.
48 | ///
49 | /// The path to the raw data file.
50 | /// The compression mode used for the raw data.
51 | public QRCodeData(string pathToRawData, Compression compressMode) : this(File.ReadAllBytes(pathToRawData), compressMode)
52 | {
53 | }
54 |
55 | ///
56 | /// Initializes a new instance of the class with raw data and compression mode.
57 | ///
58 | /// The raw data of the QR code.
59 | /// The compression mode used for the raw data.
60 | public QRCodeData(byte[] rawData, Compression compressMode)
61 | {
62 | var bytes = new List(rawData);
63 |
64 | //Decompress
65 | if (compressMode == Compression.Deflate)
66 | {
67 | using var input = new MemoryStream(bytes.ToArray());
68 | using var output = new MemoryStream();
69 | using (var dstream = new DeflateStream(input, CompressionMode.Decompress))
70 | {
71 | dstream.CopyTo(output);
72 | }
73 | bytes = new List(output.ToArray());
74 | }
75 | else if (compressMode == Compression.GZip)
76 | {
77 | using var input = new MemoryStream(bytes.ToArray());
78 | using var output = new MemoryStream();
79 | using (var dstream = new GZipStream(input, CompressionMode.Decompress))
80 | {
81 | dstream.CopyTo(output);
82 | }
83 | bytes = new List(output.ToArray());
84 | }
85 |
86 | if (bytes[0] != 0x51 || bytes[1] != 0x52 || bytes[2] != 0x52)
87 | throw new Exception("Invalid raw data file. Filetype doesn't match \"QRR\".");
88 |
89 | //Set QR code version
90 | var sideLen = (int)bytes[4];
91 | bytes.RemoveRange(0, 5);
92 | Version = (sideLen - 21 - 8) / 4 + 1;
93 |
94 | //Unpack
95 | var modules = new Queue(8 * bytes.Count);
96 | foreach (var b in bytes)
97 | {
98 | var bArr = new BitArray(new byte[] { b });
99 | for (int i = 7; i >= 0; i--)
100 | {
101 | modules.Enqueue((b & (1 << i)) != 0);
102 | }
103 | }
104 |
105 | //Build module matrix
106 | ModuleMatrix = new List(sideLen);
107 | for (int y = 0; y < sideLen; y++)
108 | {
109 | ModuleMatrix.Add(new BitArray(sideLen));
110 | for (int x = 0; x < sideLen; x++)
111 | {
112 | ModuleMatrix[y][x] = modules.Dequeue();
113 | }
114 | }
115 |
116 | }
117 |
118 | ///
119 | /// Gets the raw data of the QR code with the specified compression mode.
120 | ///
121 | /// The compression mode used for the raw data.
122 | /// Returns the raw data of the QR code as a byte array.
123 | public byte[] GetRawData(Compression compressMode)
124 | {
125 | var bytes = new List();
126 |
127 | //Add header - signature ("QRR")
128 | bytes.AddRange(new byte[] { 0x51, 0x52, 0x52, 0x00 });
129 |
130 | //Add header - rowsize
131 | bytes.Add((byte)ModuleMatrix.Count);
132 |
133 | //Build data queue
134 | var dataQueue = new Queue();
135 | foreach (var row in ModuleMatrix)
136 | {
137 | foreach (var module in row)
138 | {
139 | dataQueue.Enqueue((bool)module ? 1 : 0);
140 | }
141 | }
142 | for (int i = 0; i < 8 - (ModuleMatrix.Count * ModuleMatrix.Count) % 8; i++)
143 | {
144 | dataQueue.Enqueue(0);
145 | }
146 |
147 | //Process queue
148 | while (dataQueue.Count > 0)
149 | {
150 | byte b = 0;
151 | for (int i = 7; i >= 0; i--)
152 | {
153 | b += (byte)(dataQueue.Dequeue() << i);
154 | }
155 | bytes.Add(b);
156 | }
157 | var rawData = bytes.ToArray();
158 |
159 | //Compress stream (optional)
160 | if (compressMode == Compression.Deflate)
161 | {
162 | using var output = new MemoryStream();
163 | using (var dstream = new DeflateStream(output, CompressionMode.Compress))
164 | {
165 | dstream.Write(rawData, 0, rawData.Length);
166 | }
167 | rawData = output.ToArray();
168 | }
169 | else if (compressMode == Compression.GZip)
170 | {
171 | using var output = new MemoryStream();
172 | using (var gzipStream = new GZipStream(output, CompressionMode.Compress, true))
173 | {
174 | gzipStream.Write(rawData, 0, rawData.Length);
175 | }
176 | rawData = output.ToArray();
177 | }
178 | return rawData;
179 | }
180 |
181 | ///
182 | /// Saves the raw data of the QR code to a specified file with the specified compression mode.
183 | ///
184 | /// The path to the file where the raw data will be saved.
185 | /// The compression mode used for the raw data.
186 | public void SaveRawData(string filePath, Compression compressMode)
187 | => File.WriteAllBytes(filePath, GetRawData(compressMode));
188 |
189 | ///
190 | /// Gets the version of the QR code.
191 | ///
192 | public int Version { get; private set; }
193 |
194 | ///
195 | /// Gets the number of modules per side from the specified version.
196 | ///
197 | /// The version of the QR code.
198 | /// Returns the number of modules per side.
199 | private static int ModulesPerSideFromVersion(int version)
200 | => 21 + (version - 1) * 4;
201 |
202 | ///
203 | /// Releases all resources used by the .
204 | ///
205 | public void Dispose()
206 | {
207 | ModuleMatrix = null!;
208 | Version = 0;
209 |
210 | }
211 |
212 | ///
213 | /// Specifies the compression mode used for the raw data.
214 | ///
215 | public enum Compression
216 | {
217 | ///
218 | /// No compression.
219 | ///
220 | Uncompressed,
221 | ///
222 | /// Deflate compression.
223 | ///
224 | Deflate,
225 | ///
226 | /// GZip compression.
227 | ///
228 | GZip
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/AlignmentPattern.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace QRCoder;
4 |
5 | public partial class QRCodeGenerator
6 | {
7 | ///
8 | /// Represents the alignment pattern used in QR codes, which helps ensure the code remains readable even if it is somewhat distorted.
9 | /// Each QR code version has its own specific alignment pattern locations which this struct encapsulates.
10 | ///
11 | private struct AlignmentPattern
12 | {
13 | ///
14 | /// The version of the QR code. Higher versions have more complex and numerous alignment patterns.
15 | ///
16 | public int Version;
17 |
18 | ///
19 | /// A list of points where alignment patterns are located within the QR code matrix.
20 | /// Each point represents the center of an alignment pattern.
21 | ///
22 | public List PatternPositions;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/CodewordBlock.cs:
--------------------------------------------------------------------------------
1 | namespace QRCoder;
2 |
3 | public partial class QRCodeGenerator
4 | {
5 | ///
6 | /// Represents a block of codewords in a QR code. QR codes are divided into several blocks for error correction purposes.
7 | /// Each block contains a series of data codewords followed by error correction codewords.
8 | ///
9 | private struct CodewordBlock
10 | {
11 | ///
12 | /// Initializes a new instance of the CodewordBlock struct with specified arrays of code words and error correction (ECC) words.
13 | ///
14 | /// The offset of the data codewords within the main BitArray. Data codewords carry the actual information.
15 | /// The length in bits of the data codewords within the main BitArray.
16 | /// The array of error correction codewords for this block. These codewords help recover the data if the QR code is damaged.
17 | public CodewordBlock(int codeWordsOffset, int codeWordsLength, byte[] eccWords)
18 | {
19 | CodeWordsOffset = codeWordsOffset;
20 | CodeWordsLength = codeWordsLength;
21 | ECCWords = eccWords;
22 | }
23 |
24 | ///
25 | /// Gets the offset of the data codewords in the BitArray.
26 | ///
27 | public int CodeWordsOffset { get; }
28 |
29 | ///
30 | /// Gets the length of the data codewords in the BitArray.
31 | ///
32 | public int CodeWordsLength { get; }
33 |
34 | ///
35 | /// Gets the error correction codewords associated with this block.
36 | ///
37 | public byte[] ECCWords { get; }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/ECCInfo.cs:
--------------------------------------------------------------------------------
1 | namespace QRCoder;
2 |
3 | public partial class QRCodeGenerator
4 | {
5 | ///
6 | /// Represents the error correction coding (ECC) information for a specific version and error correction level of a QR code.
7 | ///
8 | private struct ECCInfo
9 | {
10 | ///
11 | /// Initializes a new instance of the ECCInfo struct with specified properties.
12 | ///
13 | /// The version number of the QR code.
14 | /// The error correction level used in the QR code.
15 | /// The total number of data codewords for this version and error correction level.
16 | /// The number of error correction codewords per block.
17 | /// The number of blocks in group 1.
18 | /// The number of codewords in each block of group 1.
19 | /// The number of blocks in group 2, if any.
20 | /// The number of codewords in each block of group 2, if any.
21 | public ECCInfo(int version, ECCLevel errorCorrectionLevel, int totalDataCodewords, int eccPerBlock, int blocksInGroup1,
22 | int codewordsInGroup1, int blocksInGroup2, int codewordsInGroup2)
23 | {
24 | Version = version;
25 | ErrorCorrectionLevel = errorCorrectionLevel;
26 | TotalDataCodewords = totalDataCodewords;
27 | ECCPerBlock = eccPerBlock;
28 | BlocksInGroup1 = blocksInGroup1;
29 | CodewordsInGroup1 = codewordsInGroup1;
30 | BlocksInGroup2 = blocksInGroup2;
31 | CodewordsInGroup2 = codewordsInGroup2;
32 | }
33 |
34 | ///
35 | /// Gets the version number of the QR code.
36 | ///
37 | public int Version { get; }
38 |
39 | ///
40 | /// Gets the error correction level of the QR code.
41 | ///
42 | public ECCLevel ErrorCorrectionLevel { get; }
43 |
44 | ///
45 | /// Gets the total number of data codewords for this version and error correction level.
46 | ///
47 | public int TotalDataCodewords { get; }
48 |
49 | ///
50 | /// Gets the number of error correction codewords per block.
51 | ///
52 | public int ECCPerBlock { get; }
53 |
54 | ///
55 | /// Gets the number of blocks in group 1.
56 | ///
57 | public int BlocksInGroup1 { get; }
58 |
59 | ///
60 | /// Gets the number of codewords in each block of group 1.
61 | ///
62 | public int CodewordsInGroup1 { get; }
63 |
64 | ///
65 | /// Gets the number of blocks in group 2, if any.
66 | ///
67 | public int BlocksInGroup2 { get; }
68 |
69 | ///
70 | /// Gets the number of codewords in each block of group 2, if any.
71 | ///
72 | public int CodewordsInGroup2 { get; }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/ECCLevel.cs:
--------------------------------------------------------------------------------
1 | namespace QRCoder;
2 |
3 | public partial class QRCodeGenerator
4 | {
5 | ///
6 | /// Defines the levels of error correction available in QR codes.
7 | /// Each level specifies the proportion of data that can be recovered if the QR code is partially obscured or damaged.
8 | ///
9 | public enum ECCLevel
10 | {
11 | ///
12 | /// Default error correction level, which will select Level M (Medium) unless otherwise specified by the payload.
13 | /// Level M allows approximately 15% of data to be recovered, offering a balance between data capacity and error recovery.
14 | ///
15 | Default = -1,
16 |
17 | ///
18 | /// Level L: Low error correction (approximately 7% of data can be recovered).
19 | /// This level allows the highest data density.
20 | ///
21 | L = 0,
22 |
23 | ///
24 | /// Level M: Medium error correction (approximately 15% of data can be recovered).
25 | /// Offers a balance between data capacity and error recovery.
26 | ///
27 | M = 1,
28 |
29 | ///
30 | /// Level Q: Quartile error correction (approximately 25% of data can be recovered).
31 | /// More robust error correction at the cost of reduced data capacity.
32 | ///
33 | Q = 2,
34 |
35 | ///
36 | /// Level H: High error correction (approximately 30% of data can be recovered).
37 | /// Provides the highest level of error recovery, ideal for environments with high risk of data loss.
38 | ///
39 | H = 3
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/EciMode.cs:
--------------------------------------------------------------------------------
1 | namespace QRCoder;
2 |
3 | public partial class QRCodeGenerator
4 | {
5 | ///
6 | /// Enumerates the Extended Channel Interpretation (ECI) modes used in QR codes to handle different character encoding standards.
7 | /// ECI mode allows QR codes to efficiently encode data using character sets other than the default ISO-8859-1.
8 | ///
9 | public enum EciMode
10 | {
11 | ///
12 | /// Default encoding mode (typically ISO-8859-1). Used when no ECI mode is explicitly specified.
13 | /// This mode is assumed in basic QR codes where no extended character sets are needed.
14 | ///
15 | Default = 0,
16 |
17 | ///
18 | /// Specifies the use of the ISO-8859-1 character set, covering most Western European languages.
19 | /// This mode explicitly sets the encoding to ISO-8859-1, which includes characters used in languages such as English, French, German, and Spanish.
20 | ///
21 | Iso8859_1 = 3,
22 |
23 | ///
24 | /// Specifies the use of the ISO-8859-2 character set, which is primarily used for Central and Eastern European languages.
25 | /// This includes characters used in languages such as Polish, Czech, Slovak, Hungarian, and Romanian.
26 | ///
27 | Iso8859_2 = 4,
28 |
29 | ///
30 | /// Specifies the use of UTF-8 encoding.
31 | /// UTF-8 can encode any Unicode character and is useful for QR codes that need to support multi-language content.
32 | ///
33 | Utf8 = 26
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/EncodingMode.cs:
--------------------------------------------------------------------------------
1 | namespace QRCoder;
2 |
3 | public partial class QRCodeGenerator
4 | {
5 | ///
6 | /// Specifies the encoding modes for the characters in a QR code.
7 | ///
8 | private enum EncodingMode
9 | {
10 | ///
11 | /// Numeric encoding mode, which is used to encode numeric data (digits 0-9).
12 | /// Three characters are encoded into 10 bits.
13 | ///
14 | Numeric = 1,
15 |
16 | ///
17 | /// Alphanumeric encoding mode, which is used to encode alphanumeric characters (0-9, A-Z, space, and some punctuation).
18 | /// Two characters are encoded into 11 bits.
19 | ///
20 | Alphanumeric = 2,
21 |
22 | ///
23 | /// Byte encoding mode, primarily using the ISO-8859-1 character set. Each character is encoded into 8 bits.
24 | /// When combined with ECI, it can be adapted to use other character sets.
25 | ///
26 | Byte = 4,
27 |
28 | ///
29 | /// Kanji encoding mode, which is used to encode characters from the Shift JIS character set, primarily for Japanese Kanji and Kana characters.
30 | /// One character is encoded into 13 bits. This mode is not currently supported by QRCoder.
31 | ///
32 | Kanji = 8,
33 |
34 | ///
35 | /// Extended Channel Interpretation (ECI) mode, which specifies a character set via an 8-bit number followed by one of the other encoding modes.
36 | /// This allows adapting the byte encoding to accommodate various global text encodings.
37 | ///
38 | ECI = 7
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/ModulePlacer.BlockedModules.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Threading;
4 |
5 | namespace QRCoder;
6 |
7 | public partial class QRCodeGenerator
8 | {
9 | private static partial class ModulePlacer
10 | {
11 | ///
12 | /// Struct that represents blocked modules using rectangles.
13 | ///
14 | public struct BlockedModules : IDisposable
15 | {
16 | private readonly BitArray[] _blockedModules;
17 |
18 | private static BitArray[]? _staticBlockedModules;
19 |
20 | ///
21 | /// Initializes a new instance of the struct with a specified capacity.
22 | ///
23 | /// The initial capacity of the blocked modules list.
24 | public BlockedModules(int size)
25 | {
26 | _blockedModules = Interlocked.Exchange(ref _staticBlockedModules, null)!;
27 | if (_blockedModules != null && _blockedModules.Length >= size)
28 | {
29 | for (int i = 0; i < size; i++)
30 | _blockedModules[i].SetAll(false);
31 | }
32 | else
33 | {
34 | _blockedModules = new BitArray[size];
35 | for (int i = 0; i < size; i++)
36 | _blockedModules[i] = new BitArray(size);
37 | }
38 | }
39 |
40 | ///
41 | /// Adds a blocked module at the specified coordinates.
42 | ///
43 | /// The x-coordinate of the module.
44 | /// The y-coordinate of the module.
45 | public void Add(int x, int y)
46 | => _blockedModules[y][x] = true;
47 |
48 | ///
49 | /// Adds a blocked module defined by the specified rectangle.
50 | ///
51 | /// The rectangle that defines the blocked module.
52 | public void Add(Rectangle rect)
53 | {
54 | for (int y = rect.Y; y < rect.Y + rect.Height; y++)
55 | {
56 | for (int x = rect.X; x < rect.X + rect.Width; x++)
57 | {
58 | _blockedModules[y][x] = true;
59 | }
60 | }
61 | }
62 |
63 | ///
64 | /// Checks if the specified coordinates are blocked.
65 | ///
66 | /// The x-coordinate to check.
67 | /// The y-coordinate to check.
68 | /// true if the coordinates are blocked; otherwise, false.
69 | public bool IsBlocked(int x, int y)
70 | => _blockedModules[y][x];
71 |
72 | ///
73 | /// Checks if the specified rectangle is blocked.
74 | ///
75 | /// The rectangle to check.
76 | /// true if the rectangle is blocked; otherwise, false.
77 | public bool IsBlocked(Rectangle r1)
78 | {
79 | for (int y = r1.Y; y < r1.Y + r1.Height; y++)
80 | {
81 | for (int x = r1.X; x < r1.X + r1.Width; x++)
82 | {
83 | if (_blockedModules[y][x])
84 | return true;
85 | }
86 | }
87 | return false;
88 | }
89 |
90 | public void Dispose()
91 | => Interlocked.CompareExchange(ref _staticBlockedModules, _blockedModules, null);
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/ModulePlacer.MaskPattern.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace QRCoder;
5 |
6 | public partial class QRCodeGenerator
7 | {
8 | private static partial class ModulePlacer
9 | {
10 | ///
11 | /// Provides static methods and properties to handle mask patterns used in QR code generation.
12 | /// Mask patterns are applied to QR codes to break up patterns in the data matrix that might confuse scanners.
13 | ///
14 | private static class MaskPattern
15 | {
16 | ///
17 | /// A dictionary mapping each mask pattern index to its corresponding function that calculates whether a given pixel should be masked.
18 | ///
19 | public static readonly List> Patterns =
20 | new List>(8) {
21 | MaskPattern.Pattern1, MaskPattern.Pattern2, MaskPattern.Pattern3, MaskPattern.Pattern4,
22 | MaskPattern.Pattern5, MaskPattern.Pattern6, MaskPattern.Pattern7, MaskPattern.Pattern8
23 | };
24 |
25 | ///
26 | /// Mask pattern 1: (x + y) % 2 == 0
27 | /// Applies a checkerboard mask on the QR code.
28 | ///
29 | public static bool Pattern1(int x, int y)
30 | => (x + y) % 2 == 0;
31 |
32 | ///
33 | /// Mask pattern 2: y % 2 == 0
34 | /// Applies a horizontal striping mask on the QR code.
35 | ///
36 | public static bool Pattern2(int x, int y)
37 | => y % 2 == 0;
38 |
39 | ///
40 | /// Mask pattern 3: x % 3 == 0
41 | /// Applies a vertical striping mask on the QR code.
42 | ///
43 | public static bool Pattern3(int x, int y)
44 | => x % 3 == 0;
45 |
46 | ///
47 | /// Mask pattern 4: (x + y) % 3 == 0
48 | /// Applies a diagonal striping mask on the QR code.
49 | ///
50 | public static bool Pattern4(int x, int y)
51 | => (x + y) % 3 == 0;
52 |
53 | ///
54 | /// Mask pattern 5: ((y / 2) + (x / 3)) % 2 == 0
55 | /// Applies a complex pattern mask on the QR code, mixing horizontal and vertical rules.
56 | ///
57 | public static bool Pattern5(int x, int y)
58 | => ((int)(Math.Floor(y / 2d) + Math.Floor(x / 3d)) % 2) == 0;
59 |
60 | ///
61 | /// Mask pattern 6: ((x * y) % 2 + (x * y) % 3) == 0
62 | /// Applies a mask based on the product of x and y coordinates modulo 2 and 3.
63 | ///
64 | public static bool Pattern6(int x, int y)
65 | => ((x * y) % 2) + ((x * y) % 3) == 0;
66 |
67 | ///
68 | /// Mask pattern 7: (((x * y) % 2 + (x * y) % 3) % 2) == 0
69 | /// Applies a mask based on a more complex function involving the product of x and y coordinates.
70 | ///
71 | public static bool Pattern7(int x, int y)
72 | => (((x * y) % 2) + ((x * y) % 3)) % 2 == 0;
73 |
74 | ///
75 | /// Mask pattern 8: (((x + y) % 2) + ((x * y) % 3) % 2) == 0
76 | /// Combines rules of checkers and complex multiplicative masks.
77 | ///
78 | public static bool Pattern8(int x, int y)
79 | => (((x + y) % 2) + ((x * y) % 3)) % 2 == 0;
80 |
81 | ///
82 | /// Calculates a penalty score for a QR code to evaluate the effectiveness of a mask pattern.
83 | /// A lower score indicates a QR code that is easier for decoders to read accurately.
84 | /// The score is the sum of four penalty rules applied to the QR code.
85 | ///
86 | /// The QR code data structure to be evaluated.
87 | /// The total penalty score of the QR code.
88 | public static int Score(QRCodeData qrCode)
89 | {
90 | int score1 = 0, // Penalty for groups of five or more same-color modules in a row (or column)
91 | score2 = 0, // Penalty for blocks of modules in the same color
92 | score3 = 0, // Penalty for specific patterns found within the QR code
93 | score4 = 0; // Penalty for having more than 50% black modules or more than 50% white modules
94 | var size = qrCode.ModuleMatrix.Count;
95 |
96 | //Penalty 1: Checking for consecutive modules of the same color in rows and columns
97 | for (var y = 0; y < size; y++)
98 | {
99 | var modInRow = 0;
100 | var modInColumn = 0;
101 | var lastValRow = qrCode.ModuleMatrix[y][0];
102 | var lastValColumn = qrCode.ModuleMatrix[0][y];
103 | for (var x = 0; x < size; x++)
104 | {
105 | // Check rows for consecutive modules
106 | if (qrCode.ModuleMatrix[y][x] == lastValRow)
107 | modInRow++;
108 | else
109 | modInRow = 1;
110 | if (modInRow == 5)
111 | score1 += 3;
112 | else if (modInRow > 5)
113 | score1++;
114 | lastValRow = qrCode.ModuleMatrix[y][x];
115 |
116 | // Check columns for consecutive modules
117 | if (qrCode.ModuleMatrix[x][y] == lastValColumn)
118 | modInColumn++;
119 | else
120 | modInColumn = 1;
121 | if (modInColumn == 5)
122 | score1 += 3;
123 | else if (modInColumn > 5)
124 | score1++;
125 | lastValColumn = qrCode.ModuleMatrix[x][y];
126 | }
127 | }
128 |
129 | //Penalty 2: Checking for blocks of modules in the same color
130 | for (var y = 0; y < size - 1; y++)
131 | {
132 | for (var x = 0; x < size - 1; x++)
133 | {
134 | if (qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y][x + 1] &&
135 | qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y + 1][x] &&
136 | qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y + 1][x + 1])
137 | score2 += 3;
138 | }
139 | }
140 |
141 | //Penalty 3: Checking for specific patterns within the QR code (patterns that should be avoided)
142 | for (var y = 0; y < size; y++)
143 | {
144 | for (var x = 0; x < size - 10; x++)
145 | {
146 | // Horizontal pattern matching
147 | if ((qrCode.ModuleMatrix[y][x] &&
148 | !qrCode.ModuleMatrix[y][x + 1] &&
149 | qrCode.ModuleMatrix[y][x + 2] &&
150 | qrCode.ModuleMatrix[y][x + 3] &&
151 | qrCode.ModuleMatrix[y][x + 4] &&
152 | !qrCode.ModuleMatrix[y][x + 5] &&
153 | qrCode.ModuleMatrix[y][x + 6] &&
154 | !qrCode.ModuleMatrix[y][x + 7] &&
155 | !qrCode.ModuleMatrix[y][x + 8] &&
156 | !qrCode.ModuleMatrix[y][x + 9] &&
157 | !qrCode.ModuleMatrix[y][x + 10]) ||
158 | (!qrCode.ModuleMatrix[y][x] &&
159 | !qrCode.ModuleMatrix[y][x + 1] &&
160 | !qrCode.ModuleMatrix[y][x + 2] &&
161 | !qrCode.ModuleMatrix[y][x + 3] &&
162 | qrCode.ModuleMatrix[y][x + 4] &&
163 | !qrCode.ModuleMatrix[y][x + 5] &&
164 | qrCode.ModuleMatrix[y][x + 6] &&
165 | qrCode.ModuleMatrix[y][x + 7] &&
166 | qrCode.ModuleMatrix[y][x + 8] &&
167 | !qrCode.ModuleMatrix[y][x + 9] &&
168 | qrCode.ModuleMatrix[y][x + 10]))
169 | {
170 | score3 += 40;
171 | }
172 |
173 | // Vertical pattern matching
174 | if ((qrCode.ModuleMatrix[x][y] &&
175 | !qrCode.ModuleMatrix[x + 1][y] &&
176 | qrCode.ModuleMatrix[x + 2][y] &&
177 | qrCode.ModuleMatrix[x + 3][y] &&
178 | qrCode.ModuleMatrix[x + 4][y] &&
179 | !qrCode.ModuleMatrix[x + 5][y] &&
180 | qrCode.ModuleMatrix[x + 6][y] &&
181 | !qrCode.ModuleMatrix[x + 7][y] &&
182 | !qrCode.ModuleMatrix[x + 8][y] &&
183 | !qrCode.ModuleMatrix[x + 9][y] &&
184 | !qrCode.ModuleMatrix[x + 10][y]) ||
185 | (!qrCode.ModuleMatrix[x][y] &&
186 | !qrCode.ModuleMatrix[x + 1][y] &&
187 | !qrCode.ModuleMatrix[x + 2][y] &&
188 | !qrCode.ModuleMatrix[x + 3][y] &&
189 | qrCode.ModuleMatrix[x + 4][y] &&
190 | !qrCode.ModuleMatrix[x + 5][y] &&
191 | qrCode.ModuleMatrix[x + 6][y] &&
192 | qrCode.ModuleMatrix[x + 7][y] &&
193 | qrCode.ModuleMatrix[x + 8][y] &&
194 | !qrCode.ModuleMatrix[x + 9][y] &&
195 | qrCode.ModuleMatrix[x + 10][y]))
196 | {
197 | score3 += 40;
198 | }
199 | }
200 | }
201 |
202 | //Penalty 4: Proportions of dark and light modules
203 | int blackModules = 0;
204 | foreach (var bitArray in qrCode.ModuleMatrix)
205 | for (var x = 0; x < size; x++)
206 | if (bitArray[x])
207 | blackModules++;
208 |
209 | var percentDiv5 = blackModules * 20 / (qrCode.ModuleMatrix.Count * qrCode.ModuleMatrix.Count);
210 | var prevMultipleOf5 = Math.Abs(percentDiv5 - 10);
211 | var nextMultipleOf5 = Math.Abs(percentDiv5 - 9);
212 | score4 = Math.Min(prevMultipleOf5, nextMultipleOf5) * 10;
213 |
214 | // Return the sum of all four penalties
215 | return (score1 + score2) + (score3 + score4);
216 | }
217 | }
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/Point.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 |
5 | namespace QRCoder;
6 |
7 | public partial class QRCodeGenerator
8 | {
9 | ///
10 | /// Represents a 2D point with integer coordinates.
11 | ///
12 | private readonly struct Point : IEquatable
13 | {
14 | ///
15 | /// Gets the X-coordinate of the point.
16 | ///
17 | public int X { get; }
18 |
19 | ///
20 | /// Gets the Y-coordinate of the point.
21 | ///
22 | public int Y { get; }
23 |
24 | ///
25 | /// Initializes a new instance of the struct with specified X and Y coordinates.
26 | ///
27 | /// The X-coordinate of the point.
28 | /// The Y-coordinate of the point.
29 | public Point(int x, int y)
30 | {
31 | X = x;
32 | Y = y;
33 | }
34 |
35 | ///
36 | /// Determines whether the specified is equal to the current .
37 | ///
38 | /// The to compare with the current .
39 | /// True if the specified has the same X and Y coordinates as the current ; otherwise, false.
40 | ///
41 | /// If this method which implements is not implemented, comparisons used by methods such as
42 | /// fall back to reflection, which causes heap allocations internally during the calls to .
43 | ///
44 | public bool Equals(Point other)
45 | => X == other.X && Y == other.Y;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/Polynom.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Text;
5 |
6 | namespace QRCoder;
7 |
8 | public partial class QRCodeGenerator
9 | {
10 | ///
11 | /// Represents a polynomial, which is a sum of polynomial terms.
12 | ///
13 | private struct Polynom : IDisposable
14 | {
15 | private PolynomItem[] _polyItems;
16 |
17 | ///
18 | /// Initializes a new instance of the struct with a specified number of initial capacity for polynomial terms.
19 | ///
20 | /// The initial capacity of the polynomial items list.
21 | public Polynom(int count)
22 | {
23 | Count = 0;
24 | _polyItems = RentArray(count);
25 | }
26 |
27 | ///
28 | /// Adds a polynomial term to the polynomial.
29 | ///
30 | public void Add(PolynomItem item)
31 | {
32 | AssertCapacity(Count + 1);
33 | _polyItems[Count++] = item;
34 | }
35 |
36 | ///
37 | /// Removes the polynomial term at the specified index.
38 | ///
39 | public void RemoveAt(int index)
40 | {
41 | if ((uint)index >= (uint)Count)
42 | throw new IndexOutOfRangeException();
43 |
44 | if (index < Count - 1)
45 | Array.Copy(_polyItems, index + 1, _polyItems, index, Count - index - 1);
46 |
47 | Count--;
48 | }
49 |
50 | ///
51 | /// Gets or sets a polynomial term at the specified index.
52 | ///
53 | public PolynomItem this[int index]
54 | {
55 | get
56 | {
57 | if ((uint)index >= Count)
58 | ThrowIndexOutOfRangeException();
59 | return _polyItems[index];
60 | }
61 | set
62 | {
63 | if ((uint)index >= Count)
64 | ThrowIndexOutOfRangeException();
65 | _polyItems[index] = value;
66 | }
67 | }
68 |
69 | #if NET6_0_OR_GREATER
70 | [StackTraceHidden]
71 | #endif
72 | private static void ThrowIndexOutOfRangeException() => throw new IndexOutOfRangeException();
73 |
74 |
75 | ///
76 | /// Gets the number of polynomial terms in the polynomial.
77 | ///
78 | public int Count { get; private set; }
79 |
80 | ///
81 | /// Removes all polynomial terms from the polynomial.
82 | ///
83 | public void Clear() => Count = 0;
84 |
85 | ///
86 | /// Clones the polynomial, creating a new instance with the same polynomial terms.
87 | ///
88 | public Polynom Clone()
89 | {
90 | var newPolynom = new Polynom(Count);
91 | Array.Copy(_polyItems, newPolynom._polyItems, Count);
92 | newPolynom.Count = Count;
93 | return newPolynom;
94 | }
95 |
96 | ///
97 | /// Sorts the collection of using a custom comparer function.
98 | ///
99 | ///
100 | /// A function that compares two objects and returns an integer indicating their relative order:
101 | /// less than zero if the first is less than the second, zero if they are equal, or greater than zero if the first is greater than the second.
102 | ///
103 | public void Sort(Func comparer)
104 | {
105 | if (comparer == null)
106 | throw new ArgumentNullException(nameof(comparer));
107 |
108 | var items = _polyItems ?? throw new ObjectDisposedException(nameof(Polynom));
109 |
110 | if (Count <= 1)
111 | {
112 | return; // Nothing to sort if the list is empty or contains only one element
113 | }
114 |
115 | void QuickSort(int left, int right)
116 | {
117 | int i = left;
118 | int j = right;
119 | var pivot = items[(left + right) / 2];
120 |
121 | while (i <= j)
122 | {
123 | while (comparer(items[i], pivot) < 0)
124 | i++;
125 | while (comparer(items[j], pivot) > 0)
126 | j--;
127 |
128 | if (i <= j)
129 | {
130 | // Swap items[i] and items[j]
131 | var temp = items[i];
132 | items[i] = items[j];
133 | items[j] = temp;
134 | i++;
135 | j--;
136 | }
137 | }
138 |
139 | // Recursively sort the sub-arrays
140 | if (left < j)
141 | QuickSort(left, j);
142 | if (i < right)
143 | QuickSort(i, right);
144 | }
145 |
146 | QuickSort(0, Count - 1);
147 | }
148 |
149 | ///
150 | /// Returns a string that represents the polynomial in standard algebraic notation.
151 | /// Example output: "a^2*x^3 + a^5*x^1 + a^3*x^0", which represents the polynomial 2x³ + 5x + 3.
152 | ///
153 | public override string ToString()
154 | {
155 | var sb = new StringBuilder();
156 |
157 | foreach (var polyItem in _polyItems)
158 | {
159 | sb.Append("a^" + polyItem.Coefficient + "*x^" + polyItem.Exponent + " + ");
160 | }
161 |
162 | // Remove the trailing " + " if the string builder has added terms
163 | if (sb.Length > 0)
164 | sb.Length -= 3;
165 |
166 | return sb.ToString();
167 | }
168 |
169 | ///
170 | public void Dispose()
171 | {
172 | ReturnArray(_polyItems);
173 | _polyItems = null!;
174 | }
175 |
176 | ///
177 | /// Ensures that the polynomial has enough capacity to store the specified number of polynomial terms.
178 | ///
179 | private void AssertCapacity(int min)
180 | {
181 | if (_polyItems.Length < min)
182 | {
183 | // All math by QRCoder should be done with fixed polynomials, so we don't need to grow the capacity.
184 | ThrowNotSupportedException();
185 |
186 | // Sample code for growing the capacity:
187 | //var newArray = RentArray(Math.Max(min - 1, 8) * 2); // Grow by 2x, but at least by 8
188 | //Array.Copy(_polyItems, newArray, _length);
189 | //ReturnArray(_polyItems);
190 | //_polyItems = newArray;
191 | }
192 |
193 | #if NET6_0_OR_GREATER
194 | [StackTraceHidden]
195 | #endif
196 | void ThrowNotSupportedException() => throw new NotSupportedException("The polynomial capacity is fixed and cannot be increased.");
197 | }
198 |
199 | #if NETCOREAPP
200 | ///
201 | /// Rents memory for the polynomial terms from the shared memory pool.
202 | ///
203 | private static PolynomItem[] RentArray(int count)
204 | => System.Buffers.ArrayPool.Shared.Rent(count);
205 |
206 | ///
207 | /// Returns memory allocated for the polynomial terms back to the shared memory pool.
208 | ///
209 | private static void ReturnArray(PolynomItem[] array)
210 | => System.Buffers.ArrayPool.Shared.Return(array);
211 | #else
212 | // Implement a poor-man's array pool for .NET Framework
213 | [ThreadStatic]
214 | private static List? _arrayPool;
215 |
216 | ///
217 | /// Rents memory for the polynomial terms from a shared memory pool.
218 | ///
219 | private static PolynomItem[] RentArray(int count)
220 | {
221 | if (count <= 0)
222 | ThrowArgumentOutOfRangeException();
223 |
224 | // Search for a suitable array in the thread-local pool, if it has been initialized
225 | if (_arrayPool != null)
226 | {
227 | for (int i = 0; i < _arrayPool.Count; i++)
228 | {
229 | var array = _arrayPool[i];
230 | if (array.Length >= count)
231 | {
232 | _arrayPool.RemoveAt(i);
233 | return array;
234 | }
235 | }
236 | }
237 |
238 | // No suitable buffer found; create a new one
239 | return new PolynomItem[count];
240 |
241 | void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException(nameof(count), "The count must be a positive number.");
242 | }
243 |
244 | ///
245 | /// Returns memory allocated for the polynomial terms back to a shared memory pool.
246 | ///
247 | private static void ReturnArray(PolynomItem[] array)
248 | {
249 | if (array == null)
250 | return;
251 |
252 | // Initialize the thread-local pool if it's not already done
253 | _arrayPool ??= new List(8);
254 |
255 | // Add the buffer back to the pool
256 | _arrayPool.Add(array);
257 | }
258 | #endif
259 |
260 | ///
261 | /// Returns an enumerator that iterates through the polynomial terms.
262 | ///
263 | public PolynumEnumerator GetEnumerator() => new PolynumEnumerator(this);
264 |
265 | ///
266 | /// Value type enumerator for the struct.
267 | ///
268 | public struct PolynumEnumerator
269 | {
270 | private Polynom _polynom;
271 | private int _index;
272 |
273 | public PolynumEnumerator(Polynom polynom)
274 | {
275 | _polynom = polynom;
276 | _index = -1;
277 | }
278 |
279 | public PolynomItem Current => _polynom[_index];
280 |
281 | public bool MoveNext() => ++_index < _polynom.Count;
282 | }
283 | }
284 | }
285 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/PolynomItem.cs:
--------------------------------------------------------------------------------
1 | namespace QRCoder;
2 |
3 | public partial class QRCodeGenerator
4 | {
5 | ///
6 | /// Represents an individual term of a polynomial, consisting of a coefficient and an exponent.
7 | /// For example, the term 3x² would be represented as a with a coefficient of 3 and an exponent of 2.
8 | ///
9 | private struct PolynomItem
10 | {
11 | ///
12 | /// Initializes a new instance of the struct with the specified coefficient and exponent.
13 | ///
14 | /// The coefficient of the polynomial term. For example, in the term 3x², the coefficient is 3.
15 | /// The exponent of the polynomial term. For example, in the term 3x², the exponent is 2.
16 | public PolynomItem(int coefficient, int exponent)
17 | {
18 | Coefficient = coefficient;
19 | Exponent = exponent;
20 | }
21 |
22 | ///
23 | /// Gets the coefficient of the polynomial term.
24 | ///
25 | public int Coefficient { get; }
26 |
27 | ///
28 | /// Gets the exponent of the polynomial term.
29 | ///
30 | public int Exponent { get; }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/Rectangle.cs:
--------------------------------------------------------------------------------
1 | namespace QRCoder;
2 |
3 | public partial class QRCodeGenerator
4 | {
5 | ///
6 | /// Represents a rectangle defined by its top-left corner's coordinates, width, and height.
7 | ///
8 | private readonly struct Rectangle
9 | {
10 | ///
11 | /// Gets the X-coordinate of the top-left corner of the rectangle.
12 | ///
13 | public int X { get; }
14 |
15 | ///
16 | /// Gets the Y-coordinate of the top-left corner of the rectangle.
17 | ///
18 | public int Y { get; }
19 |
20 | ///
21 | /// Gets the width of the rectangle.
22 | ///
23 | public int Width { get; }
24 |
25 | ///
26 | /// Gets the height of the rectangle.
27 | ///
28 | public int Height { get; }
29 |
30 | ///
31 | /// Initializes a new instance of the struct with the specified top-left corner coordinates, width, and height.
32 | ///
33 | /// The X-coordinate of the top-left corner of the rectangle.
34 | /// The Y-coordinate of the top-left corner of the rectangle.
35 | /// The width of the rectangle.
36 | /// The height of the rectangle.
37 | public Rectangle(int x, int y, int w, int h)
38 | {
39 | X = x;
40 | Y = y;
41 | Width = w;
42 | Height = h;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/VersionInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace QRCoder;
4 |
5 | public partial class QRCodeGenerator
6 | {
7 | ///
8 | /// Represents version-specific information of a QR code.
9 | ///
10 | private struct VersionInfo
11 | {
12 | ///
13 | /// Initializes a new instance of the struct with a specific version number and its details.
14 | ///
15 | /// The version number of the QR code. Each version has a different module configuration.
16 | /// A list of detailed information related to error correction levels and capacity for each encoding mode.
17 | public VersionInfo(int version, List versionInfoDetails)
18 | {
19 | Version = version;
20 | Details = versionInfoDetails;
21 | }
22 |
23 | ///
24 | /// Gets the version number of the QR code. Each version number specifies a different size of the QR matrix.
25 | ///
26 | public int Version { get; }
27 |
28 | ///
29 | /// Gets a list of details about the QR code version, including the error correction levels and encoding capacities.
30 | ///
31 | public List Details { get; }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCodeGenerator/VersionInfoDetails.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace QRCoder;
4 |
5 | public partial class QRCodeGenerator
6 | {
7 | ///
8 | /// Represents the detailed information about each error correction level and its corresponding capacities in different encoding modes for a specific version of a QR code.
9 | ///
10 | private struct VersionInfoDetails
11 | {
12 | ///
13 | /// Initializes a new instance of the struct, detailing the error correction level and the capacity for each encoding mode.
14 | ///
15 | /// The error correction level, which determines how much of the code can be restored if the QR code gets damaged.
16 | /// A dictionary mapping each encoding mode to its capacity for the specific error correction level.
17 | public VersionInfoDetails(ECCLevel errorCorrectionLevel, Dictionary capacityDict)
18 | {
19 | ErrorCorrectionLevel = errorCorrectionLevel;
20 | CapacityDict = capacityDict;
21 | }
22 |
23 | ///
24 | /// Gets the error correction level of the QR code, influencing how robust the QR code is against errors and damage.
25 | ///
26 | public ECCLevel ErrorCorrectionLevel { get; }
27 |
28 | ///
29 | /// Gets a dictionary that contains the capacities of different encoding modes under the specified error correction level.
30 | /// These capacities dictate how many characters can be encoded under each mode.
31 | ///
32 | public Dictionary CapacityDict { get; }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/external/QRCoder/QRCoder.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 | true
7 | true
8 | $(WarningsAsErrors);CS1591
9 | enable
10 |
11 |
12 |
13 |
14 | false
15 | QRCoder
16 | 1.6.0
17 | Raffael Herrmann
18 | Raffael Herrmann
19 | QRCoder
20 | MIT
21 | c# csharp qr qrcoder qrcode qr-generator qr-code-generator
22 | git
23 | QRCoder is a simple library, written in C#.NET, which enables you to create QR codes. This version has reduced functionality and has been adapted for use in Horizon
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/images/ghreleasesbadge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/images/ghreleasesbadge.png
--------------------------------------------------------------------------------
/images/msstorebadge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/images/msstorebadge.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-100.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-125.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-150.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-200.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/LargeTile.scale-400.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-100.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-125.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-150.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-200.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SmallTile.scale-400.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-100.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-125.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-150.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/SplashScreen.scale-400.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-100.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-125.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-150.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square150x150Logo.scale-400.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-16.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-24.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-256.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-32.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-48.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-unplated_targetsize-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-unplated_targetsize-16.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-unplated_targetsize-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-unplated_targetsize-256.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-unplated_targetsize-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-unplated_targetsize-32.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-unplated_targetsize-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.altform-unplated_targetsize-48.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-100.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-125.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-150.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.scale-400.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-16.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-24.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-256.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-32.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Square44x44Logo.targetsize-48.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-100.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-125.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-150.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-200.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/StoreLogo.scale-400.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-100.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-125.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-150.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/AppIcons/Wide310x150Logo.scale-400.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/FileIcons/document.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/FileIcons/document.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/FileIcons/link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/FileIcons/link.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/Icons/DevSanx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/Icons/DevSanx.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Assets/Icons/paypal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/package/Horizon.Package/Assets/Icons/paypal.png
--------------------------------------------------------------------------------
/package/Horizon.Package/Horizon.Package.wapproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 15.0
5 |
6 |
7 |
8 | Debug
9 | x64
10 |
11 |
12 | Release
13 | x64
14 |
15 |
16 | Debug
17 | ARM64
18 |
19 |
20 | Release
21 | ARM64
22 |
23 |
24 |
25 | $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\
26 |
27 |
28 |
29 | b6778c81-1666-4c6a-90d2-2dffe9002500
30 | 10.0.26100.0
31 | 10.0.17763.0
32 | en-US
33 | false
34 | $(NoWarn);NU1702
35 | ..\..\src\Horizon.csproj
36 | True
37 | False
38 | SHA256
39 | False
40 | False
41 | x64|arm64
42 | 0
43 |
44 |
45 | Always
46 |
47 |
48 | Always
49 |
50 |
51 | Always
52 |
53 |
54 | Always
55 |
56 |
57 |
58 | Designer
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | PreserveNewest
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/package/Horizon.Package/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
14 |
15 |
16 |
17 |
18 | HorizonBrowser
19 | Pinguin2001
20 | Assets\AppIcons\StoreLogo.png
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Horizon
54 | Assets/FileIcons/link.png
55 |
56 |
57 |
58 |
59 | Horizon
60 | Assets/FileIcons/link.png
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/src/App.xaml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/App.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon;
2 |
3 | ///
4 | /// Provides application-specific behavior to supplement the default Application class.
5 | ///
6 | public partial class App : Application
7 | {
8 | ///
9 | /// Initializes the singleton application object. This is the first line of authored code
10 | /// executed, and as such is the logical equivalent of main() or WinMain().
11 | ///
12 | public App()
13 | {
14 | this.InitializeComponent();
15 | SettingsHelper.LoadSettingsOnStartup();
16 | UnhandledException += App_UnhandledException;
17 | }
18 |
19 | private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
20 | {
21 | string AppVersion = AppVersionHelper.GetAppVersion();
22 | string WV2RuntimeVersion;
23 | try
24 | {
25 | WV2RuntimeVersion = CoreWebView2Environment.GetAvailableBrowserVersionString();
26 | }
27 | catch
28 | {
29 | WV2RuntimeVersion = "NOT INSTALLED";
30 | }
31 | string dotnetver = Environment.Version.ToString();
32 | string apparch = RuntimeInformation.ProcessArchitecture.ToString();
33 | string BRI =
34 | $"Horizon version: {AppVersion}\n" +
35 | $"WebView2Runtime version: {WV2RuntimeVersion}\n" +
36 | $"DotNetRuntime version: {dotnetver}\n" +
37 | $"Host architecture: {apparch}\n" +
38 | "\n\n" +
39 | e.Exception.Message +
40 | e.Exception.StackTrace;
41 | Win32Helper.ShowMessageBox("Horizon crash handler", $"An unhandled exception occured!\nWe prevented the app from crashing, however you should report this bug!\nBug report information (press Ctrl + C to copy):\n" + BRI);
42 | e.Handled = true;
43 | }
44 |
45 | ///
46 | /// Invoked when the application is launched.
47 | ///
48 | /// Details about the launch request and process.
49 | protected override async void OnLaunched(LaunchActivatedEventArgs args)
50 | {
51 | var appArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
52 | var mainInstance = AppInstance.FindOrRegisterForKey("HorizonSingleInstance");
53 |
54 | // If the main instance isn't this current instance
55 | if (!mainInstance.IsCurrent)
56 | {
57 | // Redirect activation to that instance
58 | await mainInstance.RedirectActivationToAsync(appArgs);
59 |
60 | // And exit our instance and stop
61 | System.Diagnostics.Process.GetCurrentProcess().Kill();
62 | return;
63 | }
64 |
65 | // Otherwise, register for activation redirection
66 | AppInstance.GetCurrent().Activated += App_Activated;
67 |
68 | if (SettingsHelper.GetSetting("IsAppLockEnabled") == "true")
69 | {
70 | if (await WindowsHelloHelper.CheckSec())
71 | {
72 | WindowHelper.CreateMainWindow();
73 | WindowHelper.ActivateMainWindow();
74 | }
75 | else
76 | {
77 | System.Diagnostics.Process.GetCurrentProcess().Kill();
78 | return;
79 | }
80 | }
81 | else
82 | {
83 | WindowHelper.CreateMainWindow();
84 | WindowHelper.ActivateMainWindow();
85 | }
86 |
87 | HandleUriActivation(appArgs);
88 |
89 | if (Environment.IsPrivilegedProcess)
90 | {
91 | Win32Helper.ShowMessageBox("Horizon - Warning", "Warning!\nThis instance of Horizon is running elevated, which isn't recommened due to possible security issues.");
92 | }
93 | }
94 |
95 | private void App_Activated(object sender, AppActivationArguments e)
96 | {
97 | HandleUriActivation(e);
98 | WindowHelper.RestoreMainWindow();
99 | }
100 |
101 | private static void HandleUriActivation(AppActivationArguments args)
102 | {
103 | string uri = string.Empty;
104 | if (args.Data != null && args.Kind is ExtendedActivationKind.Protocol)
105 | {
106 | WAMA.IProtocolActivatedEventArgs ProtocolArgs = args.Data.As();
107 | uri = ProtocolArgs.Uri.ToString();
108 | }
109 | WindowHelper.CreateNewTabInMainWindow("New tab", uri);
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Controls/Tabs/Tab.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Controls.Tabs;
2 |
3 | public partial class Tab : ObservableObject
4 | {
5 | private string _title;
6 | public string Title
7 | {
8 | get => _title;
9 | set => SetProperty(ref _title, value);
10 | }
11 |
12 | /*private Uri _icon;
13 | public Uri Icon
14 | {
15 | get => _icon;
16 | set => SetProperty(ref _icon, value);
17 | }*/
18 |
19 | private UIElement _content;
20 | public UIElement Content
21 | {
22 | get => _content;
23 | set => SetProperty(ref _content, value);
24 | }
25 | }
--------------------------------------------------------------------------------
/src/Controls/Tabs/WebTabCreationParams.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Controls.Tabs;
2 |
3 | public class WebTabCreationParams
4 | {
5 | public WebTabCreationParams() { }
6 | public string LaunchURL { get; set; }
7 | public Tab myTab { get; set; }
8 | public bool IsSplitTab { get; set; } = false;
9 | }
10 |
--------------------------------------------------------------------------------
/src/Core/AppVersionHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public static class AppVersionHelper
4 | {
5 | public static string GetAppVersion()
6 | {
7 | WAM.Package package = WAM.Package.Current;
8 | WAM.PackageId packageId = package.Id;
9 | WAM.PackageVersion version = packageId.Version;
10 |
11 | return string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Core/Backdrops.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public static class Backdrops
4 | {
5 | public static readonly string[] BackdropsList = new string[] {
6 | "Acrylic",
7 | "Mica",
8 | "Mica Alt",
9 | };
10 | }
--------------------------------------------------------------------------------
/src/Core/ClipboardHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public static class ClipboardHelper
4 | {
5 | public static void CopyTextToClipboard(string text)
6 | {
7 | DataPackage package = new();
8 | package.SetText(text);
9 | Clipboard.SetContent(package);
10 | }
11 |
12 | public static async Task PasteUriAsStringFromClipboardAsync()
13 | {
14 | var package = Clipboard.GetContent();
15 | if (package.Contains(StandardDataFormats.Text))
16 | {
17 | var text = await package.GetTextAsync();
18 | return text.ToString();
19 | }
20 | return string.Empty;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Core/FileHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public class FileHelper
4 | {
5 | public static async Task SaveBytesAsFileAsync(string fileName, byte[] buffer, string filetypefriendlyname, string filetype) => await SaveFileAsync(fileName, filetypefriendlyname, filetype, buffer, null);
6 |
7 | public static async Task SaveStringAsFileAsync(string fileName, string fileContent, string filetypefriendlyname, string filetype) => await SaveFileAsync(fileName, filetypefriendlyname, filetype, null, fileContent);
8 |
9 | private static async Task SaveFileAsync(string fileName, string filetypefriendlyname, string filetype, byte[] BytesFileContent = null, string TextFileContent = null)
10 | {
11 | // Create a file picker
12 | FileSavePicker savePicker = new()
13 | {
14 | // Set options for your file picker
15 | SuggestedStartLocation = PickerLocationId.DocumentsLibrary
16 | };
17 |
18 | // See the sample code below for how to make the window accessible from the App class.
19 | var window = WindowHelper.MainWindow;
20 |
21 | // Retrieve the window handle (HWND) of the current WinUI 3 window.
22 | var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
23 |
24 | // Initialize the file picker with the window handle (HWND).
25 | WinRT.Interop.InitializeWithWindow.Initialize(savePicker, hWnd);
26 |
27 |
28 | // Dropdown of file types the user can save the file as
29 | savePicker.FileTypeChoices.Add(filetypefriendlyname, new List() { filetype });
30 | // Default file name if the user does not type one in or select a file to replace
31 | savePicker.SuggestedFileName = fileName;
32 |
33 | // Open the picker for the user to pick a file
34 | StorageFile file = await savePicker.PickSaveFileAsync();
35 | if (file != null)
36 | {
37 | // Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync.
38 | CachedFileManager.DeferUpdates(file);
39 |
40 | // write to file
41 | // depending on which type we either write bytes or text
42 | if (BytesFileContent != null)
43 | {
44 | await FileIO.WriteBytesAsync(file, BytesFileContent);
45 | }
46 | if (TextFileContent != null)
47 | {
48 | await FileIO.WriteTextAsync(file, TextFileContent);
49 | }
50 |
51 | // Let Windows know that we're finished changing the file so the other app can update the remote version of the file.
52 | // Completing updates may require Windows to ask for user input.
53 | FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
54 | if (status == FileUpdateStatus.Complete)
55 | {
56 | //NotificationHelper.NotifyUser("Success", "File " + file.Name + " was saved to\n" + file.Path);
57 | }
58 | else
59 | {
60 | //await UI.ShowDialog("Error", "File " + file.Name + " couldn't be saved.");
61 | }
62 | }
63 | }
64 |
65 | public static async Task DeleteLocalFile(string fileName)
66 | {
67 | var file = await ApplicationData.Current.LocalFolder.TryGetItemAsync(fileName);
68 | if (file != null)
69 | await file.DeleteAsync();
70 | }
71 | }
--------------------------------------------------------------------------------
/src/Core/FolderHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core
2 | {
3 | internal static class FolderHelper
4 | {
5 | public static StorageFolder localFolder = ApplicationData.Current.LocalFolder;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/Core/IconHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public static class IconHelper
4 | {
5 | public static IconSource ConvFavURLToIconSource(string url)
6 | {
7 | try
8 | {
9 | System.Uri faviconUrl = new(url);
10 | BitmapIconSource iconsource = new() { UriSource = faviconUrl, ShowAsMonochrome = false };
11 | return iconsource;
12 | }
13 | catch
14 | {
15 | IconSource iconsource = new SymbolIconSource() { Symbol = Symbol.Document };
16 | return iconsource;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Core/ModernAboutBlank.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | internal static class ModernAboutBlank
4 | {
5 | public static string MinifiedModernBlackPageHTML = "";
6 | }
--------------------------------------------------------------------------------
/src/Core/SearchEngine.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public class SearchEngine(string EngineFriendlyName, string SearchUrl)
4 | {
5 | public string EngineFriendlyName { get; set; } = EngineFriendlyName;
6 | public string SearchUrl { get; set; } = SearchUrl;
7 | }
--------------------------------------------------------------------------------
/src/Core/SearchEngineHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public class SearchEngineHelper
4 | {
5 | public static void SetSearchEngine(SearchEngine engine)
6 | {
7 | SettingsHelper.SetSetting("EngineFriendlyName", engine.EngineFriendlyName);
8 | SettingsHelper.SetSetting("SearchUrl", engine.SearchUrl);
9 | SettingsHelper.CurrentSearchUrl = engine.SearchUrl;
10 | return;
11 | }
12 |
13 | public static IReadOnlyList SearchEngines = new SearchEngine[]
14 | {
15 | new("Ask", "https://www.ask.com/web?q="),
16 | new("Baidu", "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd="),
17 | new("Bing", "https://www.bing.com?q="),
18 | new("Brave Search", "https://search.brave.com/search?q="),
19 | new("DuckDuckGo", "https://www.duckduckgo.com?q="),
20 | new("Ecosia", "https://www.ecosia.org/search?q="),
21 | new("Google", "https://www.google.com/search?q="),
22 | new("Kagi", "https://kagi.com/search?q="),
23 | new("Qwant", "https://www.qwant.com/?q="),
24 | new("Startpage", "https://www.startpage.com/search?q="),
25 | new("Unduck", "https://unduck.link?q="),
26 | new("Yahoo!", "https://search.yahoo.com/search?p="),
27 | new("Yandex", "https://yandex.com/search/?text=")
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/src/Core/SettingsHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public static class SettingsHelper
4 | {
5 | private static readonly ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
6 |
7 | public static string GetSetting(string Setting)
8 | {
9 | string SettingValue = localSettings.Values[Setting] as string;
10 | return SettingValue;
11 | }
12 |
13 | public static void SetSetting(string Setting, string SettingValue)
14 | {
15 | localSettings.Values[Setting] = SettingValue;
16 | }
17 |
18 | public static void LoadSettingsOnStartup()
19 | {
20 | CurrentSearchUrl = GetSetting("SearchUrl") ?? DefaultSearchUrl;
21 | CurrentBackdrop = GetSetting("OverrideBackdropType") ?? DefaultBackdrop;
22 | }
23 |
24 | // Settings
25 | public static readonly string DefaultSearchUrl = "https://www.duckduckgo.com?q=";
26 | public static readonly string DefaultBackdrop = "Mica";
27 |
28 | public static string CurrentSearchUrl { get; set; }
29 | public static string CurrentBackdrop { get; set; }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Core/UrlHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public static partial class UrlHelper
4 | {
5 | private static readonly Regex UrlMatch = UrlRegex();
6 | private static readonly Regex IPMatch = IPRegex();
7 | public static string GetInputType(string input)
8 | {
9 | string type;
10 |
11 | if (input.StartsWith("http://") || input.StartsWith("https://") || input.StartsWith("edge://"))
12 | {
13 | type = "url";
14 | }
15 | else if (UrlMatch.IsMatch(input) || IPMatch.IsMatch(input))
16 | {
17 | type = "urlNOProtocol";
18 | }
19 | else
20 | {
21 | type = "searchquery";
22 | }
23 | return type;
24 | }
25 |
26 | [GeneratedRegex("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?::([0-9]{1,5}))?$", RegexOptions.Singleline)]
27 | private static partial Regex IPRegex();
28 | [GeneratedRegex(@"^(http(s)?:\/\/)?(www.)?([a-zA-Z0-9])+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,63}(:[0-9]{1,5})?(\/[^\s]*)?$", RegexOptions.Singleline)]
29 | private static partial Regex UrlRegex();
30 | }
--------------------------------------------------------------------------------
/src/Core/WebView2ProfileHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | public static class WebView2ProfileHelper
4 | {
5 | public static async Task ClearAllProfileDataAsync(WebView2 wv2)
6 | {
7 | CoreWebView2Profile profile = wv2.CoreWebView2.Profile;
8 | await profile.ClearBrowsingDataAsync();
9 | await FileHelper.DeleteLocalFile("Favorites.json");
10 | SettingsViewModel.SettingsVM.FavoritesList.Clear();
11 | }
12 | }
--------------------------------------------------------------------------------
/src/Core/Win32Helper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | ///
4 | /// A helper class for Win32 api calls which have not yet been migrated to CsWin32
5 | ///
6 | internal class Win32Helper
7 | {
8 | [DllImport("user32.dll", CharSet = CharSet.Unicode)]
9 | static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
10 |
11 | public static void ShowMessageBox(string title, string message, IntPtr hwnd = 0)
12 | {
13 | MessageBox(hwnd, message, title, 0);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Core/WindowHelper.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | // This is fine here, there is no scenario where these should lead to a crash
3 | // at least that's what I hope lmao
4 | #pragma warning disable CS8618
5 |
6 | namespace Horizon.Core;
7 |
8 | ///
9 | /// A common helper for Window operations
10 | /// It allows for easy creation of new windows, modifing, accessing and closing them
11 | ///
12 | public static class WindowHelper
13 | {
14 | public static void SetFullScreen(bool fs)
15 | {
16 | switch (fs)
17 | {
18 | case true:
19 | MainAppWindow.SetPresenter(AppWindowPresenterKind.FullScreen);
20 | _ = MainWindow.DispatcherQueue.TryEnqueue(() =>
21 | {
22 | MainWindow.TabContentPresenter.Margin = new Thickness(-42, -34, -192, -7);
23 | MainWindow.Sidebar.Visibility = Visibility.Collapsed;
24 | });
25 | break;
26 | case false:
27 | MainAppWindow.SetPresenter(AppWindowPresenterKind.Default);
28 | _ = MainWindow.DispatcherQueue.TryEnqueue(() =>
29 | {
30 | MainWindow.TabContentPresenter.Margin = new Thickness(0);
31 | MainWindow.Sidebar.Visibility = Visibility.Visible;
32 | });
33 | break;
34 | }
35 | }
36 |
37 | public static bool IsWindowInFullScreen()
38 | {
39 | if (MainAppWindow.Presenter.Kind == AppWindowPresenterKind.FullScreen)
40 | return true;
41 | else
42 | return false;
43 | }
44 |
45 | static public void CreateMainWindow()
46 | {
47 | MainWindow = new();
48 | MainAppWindow = MainWindow.AppWindow;
49 | MainWindow.Title = "Horizon";
50 | MainWindow.ExtendsContentIntoTitleBar = true;
51 | SetMinWindowSize();
52 | string Backdrop = SettingsHelper.GetSetting("OverrideBackdropType");
53 | switch (Backdrop)
54 | {
55 | case "Acrylic":
56 | MainWindow.SystemBackdrop = new DesktopAcrylicBackdrop();
57 | break;
58 | case "Mica Alt":
59 | MainWindow.SystemBackdrop = new MicaBackdrop
60 | {
61 | Kind = Microsoft.UI.Composition.SystemBackdrops.MicaKind.BaseAlt
62 | };
63 | break;
64 | default:
65 | MainWindow.SystemBackdrop = new MicaBackdrop();
66 | break;
67 | }
68 | MainWindow.SetTitleBar(MainWindow.TitleBarControl);
69 | if (SettingsHelper.GetSetting("IsScreencaptureBlocked") == "true")
70 | {
71 | BlockScreencaptureForMainWindow(true);
72 | }
73 | if (SettingsHelper.GetSetting("IsAlwaysOnTopEnabled") == "true")
74 | {
75 | SetMainWindowAlwaysOnTop(true);
76 | }
77 | }
78 |
79 | static public void ActivateMainWindow()
80 | {
81 | MainWindow.Activate();
82 | }
83 |
84 | static public void RestoreMainWindow()
85 | {
86 | if (MainAppWindow.Presenter is OverlappedPresenter presenter)
87 | {
88 | presenter.Restore();
89 | }
90 | }
91 |
92 | static public void CloseMainWindow()
93 | {
94 | MainWindow.Close();
95 | }
96 |
97 | static public void CreateNewTabInMainWindow(string title, string uri)
98 | {
99 | _ = MainWindow.DispatcherQueue.TryEnqueue(() =>
100 | {
101 | MainWindow.CreateWebTab(title, uri);
102 | });
103 | }
104 |
105 | static public void CreateNativeTabInMainWindow(string title, Type page)
106 | {
107 | _ = MainWindow.DispatcherQueue.TryEnqueue(() =>
108 | {
109 | MainWindow.CreateTab(title, page);
110 | });
111 | }
112 |
113 | static public void SetMinWindowSize()
114 | {
115 | if (MainAppWindow.Presenter is OverlappedPresenter presenter)
116 | {
117 | presenter.PreferredMinimumWidth = 800;
118 | presenter.PreferredMinimumHeight = 500;
119 | }
120 | }
121 |
122 | static public void BlockScreencaptureForMainWindow(bool b)
123 | {
124 | var hwnd = (Windows.Win32.Foundation.HWND)WinRT.Interop.WindowNative.GetWindowHandle(MainWindow);
125 | switch (b)
126 | {
127 | case true:
128 | Windows.Win32.PInvoke.SetWindowDisplayAffinity(hwnd, WINDOW_DISPLAY_AFFINITY.WDA_MONITOR);
129 | break;
130 | case false:
131 | Windows.Win32.PInvoke.SetWindowDisplayAffinity(hwnd, WINDOW_DISPLAY_AFFINITY.WDA_NONE);
132 | break;
133 | }
134 | }
135 |
136 | static public void SetMainWindowAlwaysOnTop(bool t)
137 | {
138 | if (MainAppWindow.Presenter is OverlappedPresenter presenter)
139 | {
140 | presenter.IsAlwaysOnTop = t;
141 | }
142 | }
143 |
144 | public static WindowChrome MainWindow { get; set; }
145 | public static AppWindow MainAppWindow { get; private set; }
146 | }
147 |
--------------------------------------------------------------------------------
/src/Core/WindowsHelloHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Core;
2 |
3 | ///
4 | /// A helper class for common Windows Hello functionality
5 | ///
6 | public class WindowsHelloHelper
7 | {
8 | ///
9 | /// Performs an authentication using Windows Hello
10 | ///
11 | /// If the authentication has been successful
12 | public static async Task CheckSec()
13 | {
14 | if (await CheckAvailability() == UserConsentVerifierAvailability.Available)
15 | {
16 | UserConsentVerificationResult consent = await UserConsentVerifier.RequestVerificationAsync(string.Empty);
17 | if (consent == UserConsentVerificationResult.Verified)
18 | {
19 | return true;
20 | }
21 | return false;
22 | }
23 | return true;
24 | }
25 |
26 | ///
27 | /// Checks if Windows Hello is currently available
28 | ///
29 | /// A UserConsentVerifierAvailability value that describes the result of the availability check operation.
30 | public static async Task CheckAvailability()
31 | {
32 | UserConsentVerifierAvailability availability = await UserConsentVerifier.CheckAvailabilityAsync();
33 | return availability;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using CommunityToolkit.Mvvm.ComponentModel;
2 | global using CommunityToolkit.WinUI.Controls;
3 | global using Horizon.Controls.Tabs;
4 | global using Horizon.Core;
5 | global using Horizon.Modules.Favorites;
6 | global using Horizon.Pages;
7 | global using Horizon.ViewModels;
8 | global using Microsoft.UI.Windowing;
9 | global using Microsoft.UI.Xaml;
10 | global using Microsoft.UI.Xaml.Controls;
11 | global using Microsoft.UI.Xaml.Controls.Primitives;
12 | global using Microsoft.UI.Xaml.Input;
13 | global using Microsoft.UI.Xaml.Media;
14 | global using Microsoft.UI.Xaml.Media.Animation;
15 | global using Microsoft.UI.Xaml.Media.Imaging;
16 | global using Microsoft.UI.Xaml.Navigation;
17 | global using Microsoft.Web.WebView2.Core;
18 | global using Microsoft.Windows.AppLifecycle;
19 | global using QRCoder;
20 | global using System;
21 | global using System.Collections.Generic;
22 | global using System.Collections.ObjectModel;
23 | global using System.Runtime.InteropServices;
24 | global using System.Text.Json;
25 | global using System.Text.Json.Serialization;
26 | global using System.Text.RegularExpressions;
27 | global using System.Threading.Tasks;
28 | global using WAM = Windows.ApplicationModel;
29 | global using WAMA = Windows.ApplicationModel.Activation;
30 | global using Windows.ApplicationModel.DataTransfer;
31 | global using Windows.Security.Credentials.UI;
32 | global using Windows.Storage;
33 | global using Windows.Storage.Pickers;
34 | global using Windows.Storage.Provider;
35 | global using Windows.Storage.Streams;
36 | global using WS = Windows.System;
37 | global using Windows.Win32.UI.WindowsAndMessaging;
38 | global using WinRT;
--------------------------------------------------------------------------------
/src/Horizon.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinExe
4 | net9.0-windows10.0.26100.0
5 | 10.0.17763.0
6 | Horizon
7 | app.manifest
8 | x64;ARM64
9 | win-x86;win-x64;win-arm64
10 | win-$(Platform).pubxml
11 | true
12 | Horizon.ico
13 | true
14 | true
15 | true
16 | Speed
17 | true
18 | true
19 | preview
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | all
30 | runtime; build; native; contentfiles; analyzers; buildtransitive
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | MSBuild:Compile
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/Horizon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/horizon-developers/browser/7ee7950aa726389f85c2fb4c14a3753aad341a44/src/Horizon.ico
--------------------------------------------------------------------------------
/src/Modules/Favorites/FavoriteItem.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Modules.Favorites;
2 |
3 | [JsonSerializable(typeof(ObservableCollection))]
4 | public partial class FavoriteItemSerializerContext : JsonSerializerContext
5 | {
6 | }
7 |
8 | public class FavoriteItem
9 | {
10 | public string Title { get; set; }
11 | public string Url { get; set; }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Modules/Favorites/FavoritesHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Modules.Favorites;
2 |
3 | public class FavoritesHelper
4 | {
5 | public static StorageFolder localFolder = ApplicationData.Current.LocalFolder;
6 |
7 | public static async void LoadFavoritesOnStartup()
8 | {
9 | SettingsViewModel.SettingsVM.FavoritesList = await GetFavoritesListAsync();
10 | }
11 |
12 | public static async void CreateFirstFavorite(string title, string url)
13 | {
14 | // Generate json
15 | string json = "[{\"Title\":\"" + title + "\"," + "\"Url\":\"" + url + "\"}]";
16 | // create json file
17 | var file = await localFolder.CreateFileAsync("Favorites.json", CreationCollisionOption.ReplaceExisting);
18 | // write json to json file
19 | await FileIO.WriteTextAsync(file, json);
20 | // new historyitem
21 | FavoriteItem newFavoriteItem = new()
22 | {
23 | Title = title,
24 | Url = url
25 | };
26 | // add item to favorites list
27 | SettingsViewModel.SettingsVM.FavoritesList.Insert(0, newFavoriteItem);
28 | }
29 |
30 | public static async void AddFavorite(string title, string url)
31 | {
32 | var fileData = await localFolder.TryGetItemAsync("Favorites.json");
33 | if (fileData == null) CreateFirstFavorite(title, url);
34 | else
35 | {
36 | // new historyitem
37 | FavoriteItem newFavoriteItem = new()
38 | {
39 | Title = title,
40 | Url = url
41 | };
42 | // add item to favorites list
43 | SettingsViewModel.SettingsVM.FavoritesList.Insert(0, newFavoriteItem);
44 | SaveListChangesToDisk();
45 | }
46 | }
47 |
48 | public static void RemoveFavorite(FavoriteItem item)
49 | {
50 | SettingsViewModel.SettingsVM.FavoritesList.Remove(item);
51 | SaveListChangesToDisk();
52 | }
53 |
54 | public static async Task> GetFavoritesListAsync()
55 | {
56 | var fileData = await localFolder.TryGetItemAsync("Favorites.json");
57 | if (fileData == null)
58 | {
59 | ObservableCollection placeholderItems = [];
60 | return placeholderItems;
61 | }
62 | else
63 | {
64 | System.Diagnostics.Debug.WriteLine("LOADED FAVORITES");
65 | string filecontent = await FileIO.ReadTextAsync((IStorageFile)fileData);
66 | ObservableCollection Items = JsonSerializer.Deserialize(filecontent, FavoriteItemSerializerContext.Default.ObservableCollectionFavoriteItem);
67 | foreach (FavoriteItem item in Items)
68 | {
69 | System.Diagnostics.Debug.WriteLine(item.Url);
70 | }
71 | return Items;
72 | }
73 | }
74 |
75 | private static async void SaveListChangesToDisk()
76 | {
77 | var fileData = await localFolder.GetFileAsync("Favorites.json");
78 | if (SettingsViewModel.SettingsVM.FavoritesList.Count < 1)
79 | {
80 | await fileData.DeleteAsync();
81 | }
82 | else
83 | {
84 | // Convert list to json
85 | string newJson = JsonSerializer.Serialize(SettingsViewModel.SettingsVM.FavoritesList, FavoriteItemSerializerContext.Default.ObservableCollectionFavoriteItem);
86 | // Write json to json file
87 | await FileIO.WriteTextAsync(fileData, newJson);
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/Modules/QRCodeGen/QRCodeHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Modules.QRCodeGen;
2 |
3 | public static class QRCodeHelper
4 | {
5 | public static readonly QRCodeGenerator SingletonQrGenerator = new();
6 | public static Task GenerateQRCodeFromUrlAsync(string url)
7 | {
8 | try
9 | {
10 | //Create raw qr code data
11 |
12 | QRCodeData qrCodeData = SingletonQrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.M);
13 |
14 | //Create byte/raw bitmap qr code
15 | BitmapByteQRCode qrCodeBmp = new(qrCodeData);
16 |
17 | return Task.FromResult(qrCodeBmp.GetGraphic(20));
18 | }
19 | catch
20 | {
21 | return null;
22 | }
23 | }
24 |
25 | public static async Task ConvertBitmapBytesToImage(byte[] bytes)
26 | {
27 | var image = new BitmapImage();
28 | using (InMemoryRandomAccessStream stream = new())
29 | {
30 | using (DataWriter writer = new(stream.GetOutputStreamAt(0)))
31 | {
32 | writer.WriteBytes(bytes);
33 | await writer.StoreAsync();
34 | }
35 | await image.SetSourceAsync(stream);
36 | }
37 | return image;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Modules/Readability/ReadabilityHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Modules.Readability;
2 |
3 | public class ReadabilityHelper
4 | {
5 | public static string JScript { private set; get; }
6 |
7 | public static async Task GetReadabilityScriptAsync()
8 | {
9 | if (JScript == null)
10 | {
11 | StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/JS/readability.js"));
12 | JScript = await FileIO.ReadTextAsync(file);
13 | }
14 | return JScript;
15 | }
16 | }
--------------------------------------------------------------------------------
/src/NativeMethods.txt:
--------------------------------------------------------------------------------
1 | SetWindowDisplayAffinity
--------------------------------------------------------------------------------
/src/Pages/ExtensionsPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
22 |
23 |
28 |
34 |
35 |
36 |
40 |
41 |
42 |
43 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
61 |
62 |
63 |
64 |
65 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/src/Pages/ExtensionsPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Pages;
2 |
3 | public sealed partial class ExtensionsPage : Page
4 | {
5 | private WebView2 HeadlessWebViewInstance = new();
6 | public ExtensionsPage()
7 | {
8 | this.InitializeComponent();
9 | InitHeadless();
10 |
11 | }
12 |
13 | private async void InitHeadless()
14 | {
15 | CoreWebView2EnvironmentOptions options = new()
16 | {
17 | AreBrowserExtensionsEnabled = true,
18 | ScrollBarStyle = CoreWebView2ScrollbarStyle.FluentOverlay
19 | };
20 | CoreWebView2Environment environment = await CoreWebView2Environment.CreateWithOptionsAsync(null, null, options);
21 | await HeadlessWebViewInstance.EnsureCoreWebView2Async(environment);
22 | /*HeadlessWebViewInstance.CoreWebView2.NewWindowRequested += (sender, args) =>
23 | {
24 | MainPage page = WindowHelper.GetMainPageContentForWindow(App.WindowHelper.MainWindow);
25 | page.CreateWebTab("Tab", args.Uri);
26 | args.Handled = true;
27 | };*/
28 | }
29 |
30 | public void DisposeHeadless()
31 | {
32 | HeadlessWebViewInstance.Close();
33 | }
34 |
35 | private async Task> GetExtensionListAsync()
36 | {
37 | IReadOnlyList extensions = await HeadlessWebViewInstance.CoreWebView2.Profile.GetBrowserExtensionsAsync();
38 | #if DEBUG
39 | foreach (CoreWebView2BrowserExtension extension in extensions)
40 | {
41 | System.Diagnostics.Debug.WriteLine(extension.Name + ": " + extension.Id);
42 | }
43 | #endif
44 | return extensions;
45 | }
46 |
47 | private async void InstallExButton_Click(object sender, RoutedEventArgs e)
48 | {
49 | // Create a folder picker
50 | FolderPicker openPicker = new();
51 |
52 | // See the sample code below for how to make the window accessible from the App class.
53 | var window = WindowHelper.MainWindow;
54 |
55 | // Retrieve the window handle (HWND) of the current WinUI 3 window.
56 | var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
57 |
58 | // Initialize the folder picker with the window handle (HWND).
59 | WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd);
60 |
61 | // Set options for your folder picker
62 | openPicker.SuggestedStartLocation = PickerLocationId.Desktop;
63 | openPicker.FileTypeFilter.Add("*");
64 |
65 | // Open the picker for the user to pick a folder
66 | StorageFolder folder = await openPicker.PickSingleFolderAsync();
67 | if (folder != null)
68 | {
69 | //StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder);
70 | //PickFolderOutputTextBlock.Text = "Picked folder: " + folder.Name;
71 | try
72 | {
73 | await HeadlessWebViewInstance.CoreWebView2.Profile.AddBrowserExtensionAsync(folder.Path);
74 | }
75 | catch (Exception ex)
76 | {
77 | Win32Helper.ShowMessageBox("Horizon", "Installation failed because:\n" + ex.Message);
78 | }
79 | RefreshExtensionsList();
80 | }
81 | else
82 | {
83 | //PickFolderOutputTextBlock.Text = "Operation cancelled.";
84 | }
85 |
86 |
87 | }
88 |
89 | private void ListExtension_Click(object sender, RoutedEventArgs e)
90 | {
91 | RefreshExtensionsList();
92 | }
93 |
94 | private async void RefreshExtensionsList()
95 | {
96 | ExtensionsListView.SelectedItem = null;
97 | ExtensionsListView.Items.Clear();
98 | IReadOnlyList list = await GetExtensionListAsync();
99 | foreach (CoreWebView2BrowserExtension extension in list)
100 | {
101 | ExtensionsListView.Items.Add(extension);
102 | }
103 | }
104 |
105 | CoreWebView2BrowserExtension selectedItem;
106 | private void ExtensionsListView_RightTapped(object sender, RightTappedRoutedEventArgs e)
107 | {
108 | selectedItem = ((FrameworkElement)e.OriginalSource).DataContext as CoreWebView2BrowserExtension;
109 | }
110 |
111 | private async void MenuFlyoutItem_Click(object sender, RoutedEventArgs e)
112 | {
113 | switch ((sender as MenuFlyoutItem).Tag)
114 | {
115 | case "CopyID":
116 | ClipboardHelper.CopyTextToClipboard(selectedItem.Id);
117 | break;
118 | case "Delete":
119 | ContentDialog dialog = new()
120 | {
121 | Title = "Remove?",
122 | PrimaryButtonText = "Remove",
123 | CloseButtonText = "Cancel",
124 | XamlRoot = XamlRoot,
125 | Content = "Do you really want to remove " + selectedItem.Name + "?"
126 | };
127 |
128 | var dialogResult = await dialog.ShowAsync();
129 | if (dialogResult == ContentDialogResult.Primary)
130 | {
131 | IReadOnlyList list = await GetExtensionListAsync();
132 | foreach (CoreWebView2BrowserExtension extension in list)
133 | {
134 | if (extension.Id == selectedItem.Id)
135 | {
136 | await extension.RemoveAsync();
137 | }
138 | }
139 | RefreshExtensionsList();
140 | }
141 | break;
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/Pages/SettingsPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
19 |
20 |
24 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
53 |
54 |
55 |
56 |
57 |
58 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
168 |
169 |
175 |
176 |
177 |
178 |
179 |
185 |
186 |
187 |
188 |
189 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
--------------------------------------------------------------------------------
/src/Pages/SettingsPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Pages;
2 |
3 | public sealed partial class SettingsPage : Page
4 | {
5 | private WebView2 HeadlessWebViewInstance = new();
6 |
7 | public SettingsPage()
8 | {
9 | this.InitializeComponent();
10 | InitHeadless();
11 | }
12 |
13 | protected override void OnNavigatedTo(NavigationEventArgs e)
14 | {
15 | base.OnNavigatedFrom(e);
16 | // Get settings and display them in the UI
17 | SearchEngineSelector.ItemsSource = SearchEngineHelper.SearchEngines;
18 | string SearchEngine = SettingsHelper.GetSetting("EngineFriendlyName");
19 |
20 | foreach (SearchEngine engine in SearchEngineHelper.SearchEngines)
21 | {
22 | if (engine.SearchUrl == SettingsHelper.CurrentSearchUrl)
23 | {
24 | SearchEngineSelector.SelectedItem = engine;
25 | }
26 | }
27 |
28 | BackdropTypeSelector.ItemsSource = Backdrops.BackdropsList;
29 | string Backdrop = SettingsHelper.GetSetting("OverrideBackdropType");
30 | foreach (string Backdp in Backdrops.BackdropsList)
31 | {
32 | if (Backdp == SettingsHelper.CurrentBackdrop)
33 | {
34 | BackdropTypeSelector.SelectedItem = Backdp;
35 | }
36 | }
37 |
38 | if (SettingsHelper.GetSetting("AdvancedCTX") == "true")
39 | {
40 | AdvancedCTXToggle.IsOn = true;
41 | }
42 |
43 | if (SettingsHelper.GetSetting("IsScreencaptureBlocked") == "true")
44 | {
45 | BlockCaptureToggle.IsOn = true;
46 | }
47 |
48 | if (SettingsHelper.GetSetting("IsAppLockEnabled") == "true")
49 | {
50 | WindowsHelloToggle.IsOn = true;
51 | }
52 |
53 | if (SettingsHelper.GetSetting("IsAlwaysOnTopEnabled") == "true")
54 | {
55 | AlwaysOnTopToggle.IsOn = true;
56 | }
57 |
58 | // Set event handlers
59 | SearchEngineSelector.SelectionChanged += SearchEngineSelector_SelectionChanged;
60 | BackdropTypeSelector.SelectionChanged += BackdropTypeSelector_SelectionChanged;
61 | AdvancedCTXToggle.Toggled += AdvancedCTXToggle_Toggled;
62 | BlockCaptureToggle.Toggled += BlockCaptureToggle_Toggled;
63 | WindowsHelloToggle.Toggled += WindowsHelloLockToggle_Toggled;
64 | AlwaysOnTopToggle.Toggled += AlwaysOnTopToggle_Toggled;
65 | }
66 |
67 | private async void InitHeadless()
68 | {
69 | CoreWebView2EnvironmentOptions options = new()
70 | {
71 | AreBrowserExtensionsEnabled = true,
72 | ScrollBarStyle = CoreWebView2ScrollbarStyle.FluentOverlay
73 | };
74 | CoreWebView2Environment environment = await CoreWebView2Environment.CreateWithOptionsAsync(null, null, options);
75 | await HeadlessWebViewInstance.EnsureCoreWebView2Async(environment);
76 | UpdateSetDownloadFolderSettingsCardDescription();
77 | }
78 |
79 | public void DisposeHeadless()
80 | {
81 | HeadlessWebViewInstance.Close();
82 | }
83 |
84 | private void SetAsDefaultButton_Click(object sender, RoutedEventArgs e)
85 | {
86 |
87 | }
88 |
89 | private void SearchEngineSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
90 | {
91 | SearchEngine engine = e.AddedItems[0] as SearchEngine;
92 | SearchEngineHelper.SetSearchEngine(engine);
93 | }
94 |
95 | private async void OpenProfileFolder_Click(object sender, RoutedEventArgs e)
96 | {
97 | await WS.Launcher.LaunchFolderAsync(ApplicationData.Current.LocalFolder);
98 | }
99 |
100 | private void UpdateSetDownloadFolderSettingsCardDescription()
101 | {
102 | CoreWebView2Profile profile = HeadlessWebViewInstance.CoreWebView2.Profile;
103 | SetDownloadFolderSettingsCard.Description = profile.DefaultDownloadFolderPath;
104 | }
105 |
106 | private async void SetDownloadFolderButton_Click(object sender, RoutedEventArgs e)
107 | {
108 | //disable the button to avoid double-clicking
109 | var senderButton = sender as Button;
110 | senderButton.IsEnabled = false;
111 |
112 | // Create a folder picker
113 | FolderPicker openPicker = new FolderPicker();
114 |
115 | // Retrieve the window handle (HWND) of the current WinUI 3 window.
116 | var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(WindowHelper.MainWindow);
117 |
118 | // Initialize the folder picker with the window handle (HWND).
119 | WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd);
120 |
121 | // Set options for your folder picker
122 | openPicker.SuggestedStartLocation = PickerLocationId.Desktop;
123 | openPicker.FileTypeFilter.Add("*");
124 |
125 | // Open the picker for the user to pick a folder
126 | StorageFolder folder = await openPicker.PickSingleFolderAsync();
127 | if (folder != null)
128 | {
129 | CoreWebView2Profile profile = HeadlessWebViewInstance.CoreWebView2.Profile;
130 | profile.DefaultDownloadFolderPath = folder.Path;
131 | }
132 |
133 | //re-enable the button
134 | senderButton.IsEnabled = true;
135 |
136 | UpdateSetDownloadFolderSettingsCardDescription();
137 |
138 | }
139 |
140 | private void BackdropTypeSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
141 | {
142 | string Selection = e.AddedItems[0].ToString();
143 | SettingsHelper.SetSetting("OverrideBackdropType", e.AddedItems[0].ToString());
144 | switch (Selection)
145 | {
146 | case "Acrylic":
147 | WindowHelper.MainWindow.SystemBackdrop = new DesktopAcrylicBackdrop();
148 | break;
149 | case "Mica":
150 | WindowHelper.MainWindow.SystemBackdrop = new MicaBackdrop();
151 | break;
152 | case "Mica Alt":
153 | WindowHelper.MainWindow.SystemBackdrop = new MicaBackdrop
154 | {
155 | Kind = Microsoft.UI.Composition.SystemBackdrops.MicaKind.BaseAlt
156 | };
157 | break;
158 | }
159 | }
160 |
161 | private void AdvancedCTXToggle_Toggled(object sender, RoutedEventArgs e)
162 | {
163 | switch ((sender as ToggleSwitch).IsOn)
164 | {
165 | case true:
166 | SettingsHelper.SetSetting("AdvancedCTX", "true");
167 | break;
168 | case false:
169 | SettingsHelper.SetSetting("AdvancedCTX", "false");
170 | break;
171 | }
172 | }
173 |
174 | private void BlockCaptureToggle_Toggled(object sender, RoutedEventArgs e)
175 | {
176 | switch ((sender as ToggleSwitch).IsOn)
177 | {
178 | case true:
179 | SettingsHelper.SetSetting("IsScreencaptureBlocked", "true");
180 | WindowHelper.BlockScreencaptureForMainWindow(true);
181 | break;
182 | case false:
183 | SettingsHelper.SetSetting("IsScreencaptureBlocked", "false");
184 | WindowHelper.BlockScreencaptureForMainWindow(false);
185 | break;
186 | }
187 | }
188 |
189 | private async void WindowsHelloLockToggle_Toggled(object sender, RoutedEventArgs e)
190 | {
191 | switch ((sender as ToggleSwitch).IsOn)
192 | {
193 | case true:
194 | UserConsentVerifierAvailability IsWinHelloAvailable = await WindowsHelloHelper.CheckAvailability();
195 | if (IsWinHelloAvailable == UserConsentVerifierAvailability.Available)
196 | {
197 | SettingsHelper.SetSetting("IsAppLockEnabled", "true");
198 | return;
199 | }
200 | if (IsWinHelloAvailable == UserConsentVerifierAvailability.NotConfiguredForUser)
201 | {
202 | Win32Helper.ShowMessageBox("Horizon", "An error occured while trying to setup App Lock using Windows Hello.\n\nPlease setup it in Windows Settings");
203 | (sender as ToggleSwitch).IsOn = false;
204 | break;
205 | }
206 | break;
207 | case false:
208 | SettingsHelper.SetSetting("IsAppLockEnabled", "false");
209 | break;
210 | }
211 | }
212 |
213 | private void AlwaysOnTopToggle_Toggled(object sender, RoutedEventArgs e)
214 | {
215 | switch ((sender as ToggleSwitch).IsOn)
216 | {
217 | case true:
218 | WindowHelper.SetMainWindowAlwaysOnTop(true);
219 | SettingsHelper.SetSetting("IsAlwaysOnTopEnabled", "false");
220 | break;
221 | case false:
222 | WindowHelper.SetMainWindowAlwaysOnTop(false);
223 | SettingsHelper.SetSetting("IsAlwaysOnTopEnabled", "false");
224 | break;
225 | }
226 | }
227 |
228 | /*private async void ClearUserDataButton_Click(object sender, RoutedEventArgs e)
229 | {
230 | // ShowDialogWithAction is no longer available, as PenguinApps.Core has never been updated to support WinAppSdk / WinUI
231 | var result = await UI.ShowDialogWithAction($"Question", "Do you really want to clear all user data?", "Yes", "No");
232 | if (result == ContentDialogResult.Primary)
233 | {
234 | ClearUserDataProgressRing.IsActive = true;
235 | ClearUserDataBtn.IsEnabled = false;
236 | await WebView2ProfileDataHelper.ClearAllProfileDataAsync(HeadlessWebViewInstance);
237 | ClearUserDataProgressRing.IsActive = false;
238 | ClearUserDataBtn.IsEnabled = true;
239 | ContentDialog dialog = new()
240 | {
241 | Title = "Info",
242 | Content = "User data was cleared",
243 | PrimaryButtonText = "Ok & restart app"
244 | };
245 |
246 | ContentDialogResult contentDialogResult = await dialog.ShowAsync();
247 | // This doesn't work for WinAppSdk apps, we have to find another way
248 | if (contentDialogResult == ContentDialogResult.Primary)
249 | {
250 | var appRestart = await CoreApplication.RequestRestartAsync(string.Empty);
251 | if (appRestart == AppRestartFailureReason.NotInForeground || appRestart == AppRestartFailureReason.RestartPending || appRestart == AppRestartFailureReason.Other)
252 | {
253 | NotificationHelper.NotifyUser("Error", "Please restart Horizon manually");
254 | }
255 | }
256 | }
257 | }*/
258 |
259 | private void VersionTextBlock_Loaded(object sender, RoutedEventArgs e)
260 | {
261 | string appversion = AppVersionHelper.GetAppVersion();
262 | string apparch = RuntimeInformation.ProcessArchitecture.ToString();
263 | (sender as TextBlock).Text = $"Version {appversion} ({apparch})";
264 | }
265 |
266 | private async void SettingsCardClickHandler(object sender, RoutedEventArgs e)
267 | {
268 | switch ((sender as SettingsCard).Tag)
269 | {
270 | case "Extensions":
271 | WindowHelper.CreateNativeTabInMainWindow("Extensions", typeof(ExtensionsPage));
272 | break;
273 | case "GNU":
274 | await WS.Launcher.LaunchUriAsync(new Uri("https://raw.githubusercontent.com/horizon-developers/browser/refs/heads/main/LICENSE"));
275 | break;
276 | case "GitHub":
277 | await WS.Launcher.LaunchUriAsync(new Uri("https://github.com/Horizon-developers/browser"));
278 | break;
279 | case "DevSanx":
280 | await WS.Launcher.LaunchUriAsync(new Uri("https://discord.com/invite/windows-apps-hub-714581497222398064"));
281 | break;
282 | case "Donate":
283 | await WS.Launcher.LaunchUriAsync(new Uri("https://paypal.me/julianhasreiter"));
284 | break;
285 | case "BuildInfo":
286 | string dotnetver = Environment.Version.ToString();
287 | string appver = AppVersionHelper.GetAppVersion();
288 | string apparch = RuntimeInformation.ProcessArchitecture.ToString();
289 | string sysarch = RuntimeInformation.OSArchitecture.ToString();
290 | string sysversion = Environment.OSVersion.VersionString;
291 |
292 | string wv2version = CoreWebView2Environment.GetAvailableBrowserVersionString();
293 |
294 | string appsdkversion = $"{Microsoft.WindowsAppSDK.Release.Major}.{Microsoft.WindowsAppSDK.Release.Minor}.{Microsoft.WindowsAppSDK.Release.Patch}";
295 | string appsdkchannel = Microsoft.WindowsAppSDK.Release.Channel;
296 |
297 | string debugCombinedString = $"Horizon Version {appver}\n.NET Version: {dotnetver}\nAppArch: {apparch}\nSys: {sysversion}\nSysArch: {sysarch}\nWebView2Runtime version: {wv2version}\nWindowsAppSdk: {appsdkversion} ({appsdkchannel})\n";
298 |
299 |
300 | Win32Helper.ShowMessageBox("Horizon", $"Build information (press Ctrl + C to copy):\n" + debugCombinedString);
301 | break;
302 | }
303 | }
304 | }
305 |
--------------------------------------------------------------------------------
/src/Pages/SplitTabPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
21 |
25 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/Pages/SplitTabPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.Pages;
2 |
3 | public sealed partial class SplitTabPage : Page
4 | {
5 | public SplitTabPage()
6 | {
7 | this.InitializeComponent();
8 | WebTabCreationParams parameters = new()
9 | {
10 | LaunchURL = string.Empty,
11 | IsSplitTab = true
12 | };
13 | LeftFrame.Navigate(typeof(WebViewPage), parameters);
14 | RightFrame.Navigate(typeof(WebViewPage), parameters);
15 | }
16 |
17 | public void CloseWebViews()
18 | {
19 | (LeftFrame.Content as WebViewPage).WebViewControl.Close();
20 | (RightFrame.Content as WebViewPage).WebViewControl.Close();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Properties/PublishProfiles/win-arm64.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | FileSystem
8 | ARM64
9 | win-arm64
10 | bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
11 |
12 |
--------------------------------------------------------------------------------
/src/Properties/PublishProfiles/win-x64.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | FileSystem
8 | x64
9 | win-x64
10 | bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
11 |
12 |
--------------------------------------------------------------------------------
/src/Styles/Merged.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
83 |
84 |
165 |
166 |
173 |
174 |
175 |
176 |
177 | 4
178 |
179 |
187 |
188 |
--------------------------------------------------------------------------------
/src/ViewModels/SettingsViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon.ViewModels;
2 |
3 | partial class SettingsViewModel : ObservableObject
4 | {
5 | public static SettingsViewModel SettingsVM = new();
6 |
7 | [ObservableProperty]
8 | public partial ObservableCollection FavoritesList { get; set; } = [];
9 |
10 | [ObservableProperty]
11 | public partial ObservableCollection Tabs { get; set; } = [];
12 |
13 | public SettingsViewModel()
14 | {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/WindowChrome.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace Horizon;
2 |
3 | ///
4 | /// The main WindowChrome of the app. It displays the titlebar, the tab bar and the sidebar, as well as the the WebContent
5 | ///
6 | public sealed partial class WindowChrome : Window
7 | {
8 | public WindowChrome()
9 | {
10 | InitializeComponent();
11 | GetFavorites();
12 | }
13 |
14 | public static async void GetFavorites()
15 | {
16 | SettingsViewModel.SettingsVM.FavoritesList = await FavoritesHelper.GetFavoritesListAsync();
17 | #if DEBUG
18 | foreach (FavoriteItem item in SettingsViewModel.SettingsVM.FavoritesList)
19 | {
20 | System.Diagnostics.Debug.WriteLine(item.Url);
21 | }
22 | System.Diagnostics.Debug.WriteLine("Favorites:" + SettingsViewModel.SettingsVM.FavoritesList.Count);
23 | #endif
24 | }
25 |
26 | public void CreateTab(string title, Type page, string launchurl = null)
27 | {
28 | Frame frame = new();
29 |
30 | Tab tab = new()
31 | {
32 | Title = title,
33 | Content = frame
34 | };
35 |
36 | if (launchurl != null)
37 | {
38 | WebTabCreationParams parameters = new()
39 | {
40 | LaunchURL = launchurl,
41 | myTab = tab
42 | };
43 |
44 | frame.Navigate(page, parameters, new DrillInNavigationTransitionInfo());
45 | }
46 | else
47 | {
48 | frame.Navigate(page, tab, new DrillInNavigationTransitionInfo());
49 | }
50 | SettingsViewModel.SettingsVM.Tabs.Add(tab);
51 | TabListView.SelectedItem = tab;
52 | }
53 |
54 | public void CreateWebTab(string title, string launchurl)
55 | {
56 | CreateTab(title, typeof(WebViewPage), launchurl);
57 | }
58 |
59 | private void TabListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
60 | {
61 | ListView listView = sender as ListView;
62 | Tab item = (Tab)listView.SelectedItem;
63 | UIElement tabContent = item?.Content;
64 | TabContentPresenter.Content = tabContent;
65 | }
66 |
67 | private void CloseTabButton_Click(object sender, RoutedEventArgs e)
68 | {
69 | if (SettingsViewModel.SettingsVM.Tabs.Count > 1)
70 | {
71 | var button = (Button)sender;
72 | var tab = (Tab)button.DataContext;
73 | int index = SettingsViewModel.SettingsVM.Tabs.IndexOf(tab);
74 | if ((tab.Content as Frame).Content is WebViewPage)
75 | {
76 | ((tab.Content as Frame).Content as WebViewPage).WebViewControl.Close();
77 | }
78 | if ((tab.Content as Frame).Content is SplitTabPage)
79 | {
80 | ((tab.Content as Frame).Content as SplitTabPage).CloseWebViews();
81 | }
82 | if ((tab.Content as Frame).Content is ExtensionsPage)
83 | {
84 | ((tab.Content as Frame).Content as ExtensionsPage).DisposeHeadless();
85 | }
86 | if ((tab.Content as Frame).Content is SettingsPage)
87 | {
88 | ((tab.Content as Frame).Content as SettingsPage).DisposeHeadless();
89 | }
90 | tab.Content = null;
91 | if (index == 0)
92 | TabListView.SelectedIndex = 1;
93 | else
94 | TabListView.SelectedIndex = SettingsViewModel.SettingsVM.Tabs.Count - 2;
95 | SettingsViewModel.SettingsVM.Tabs.Remove(tab);
96 | }
97 | else
98 | {
99 | WindowHelper.CloseMainWindow();
100 | }
101 | }
102 |
103 | public Tab SelectedTab
104 | {
105 | get
106 | {
107 | Tab item = (Tab)TabListView.SelectedItem;
108 | return item;
109 | }
110 | set
111 | {
112 | TabListView.SelectedItem = value;
113 | }
114 | }
115 |
116 | private void ToolbarButton_Click(object sender, RoutedEventArgs e)
117 | {
118 | switch ((sender as Button).Tag)
119 | {
120 | case "NewTab":
121 | CreateWebTab("New tab", string.Empty);
122 | break;
123 | case "NewSplitTab":
124 | CreateTab("New split tab", typeof(SplitTabPage));
125 | break;
126 | case "Downloads":
127 | CreateWebTab("Downloads", "edge://downloads");
128 | break;
129 | case "History":
130 | CreateWebTab("History", "edge://history");
131 | break;
132 | }
133 | }
134 |
135 | private void ToolbarFlyoutItem_Click(object sender, RoutedEventArgs e)
136 | {
137 | switch ((sender as MenuFlyoutItem).Tag)
138 | {
139 | case "Extensions":
140 | CreateTab("Extensions", typeof(ExtensionsPage));
141 | break;
142 | case "Settings":
143 | CreateTab("Settings", typeof(SettingsPage));
144 | break;
145 | }
146 | }
147 |
148 | private void Grid_PointerPressed(object sender, PointerRoutedEventArgs e)
149 | {
150 | //System.Diagnostics.Debug.WriteLine(sender.GetType().Name);
151 | var pointer = e.GetCurrentPoint(sender as Grid);
152 | if (pointer.Properties.IsMiddleButtonPressed)
153 | {
154 | if (SettingsViewModel.SettingsVM.Tabs.Count > 1)
155 | {
156 | var button = (Grid)sender;
157 | var tab = (Tab)button.DataContext;
158 | int index = SettingsViewModel.SettingsVM.Tabs.IndexOf(tab);
159 | if ((tab.Content as Frame).Content is WebViewPage)
160 | {
161 | ((tab.Content as Frame).Content as WebViewPage).WebViewControl.Close();
162 | }
163 | tab.Content = null;
164 | if (index == 0)
165 | TabListView.SelectedIndex = 1;
166 | else
167 | TabListView.SelectedIndex = SettingsViewModel.SettingsVM.Tabs.Count - 2;
168 | SettingsViewModel.SettingsVM.Tabs.Remove(tab);
169 | }
170 | else
171 | {
172 | WindowHelper.CloseMainWindow();
173 | }
174 | }
175 |
176 |
177 | }
178 |
179 | #region Favorites flyout
180 | private void FavoritesFlyoutButton_Click(object sender, RoutedEventArgs e)
181 | {
182 | FavoritesFlyout.ShowAt(FavoritesBtn);
183 | FavoritesListView.SelectedItem = null;
184 | }
185 |
186 | private void FavoritesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
187 | {
188 | ListView listView = sender as ListView;
189 | if (listView.SelectedItem != null)
190 | {
191 | FavoriteItem item = (FavoriteItem)listView.SelectedItem;
192 | CreateWebTab(item.Title, item.Url);
193 | FavoritesFlyout.Hide();
194 | }
195 | }
196 |
197 | FavoriteItem selectedItem;
198 | private void FavoritesListView_RightTapped(object sender, RightTappedRoutedEventArgs e)
199 | {
200 | selectedItem = ((FrameworkElement)e.OriginalSource).DataContext as FavoriteItem;
201 | }
202 |
203 | private void FavContextItem_Click(object sender, RoutedEventArgs e)
204 | {
205 | switch ((sender as AppBarButton).Tag)
206 | {
207 | case "Copy":
208 | ClipboardHelper.CopyTextToClipboard(selectedItem.Url);
209 | break;
210 | case "Delete":
211 | FavoritesListView.SelectedItem = null;
212 | FavoritesHelper.RemoveFavorite(selectedItem);
213 | break;
214 | case "CopyText":
215 | ClipboardHelper.CopyTextToClipboard(selectedItem.Title);
216 | break;
217 | }
218 | FavoritesContextMenu.Hide();
219 | }
220 | #endregion
221 | }
222 |
--------------------------------------------------------------------------------
/src/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | PerMonitorV2
17 |
18 |
19 |
--------------------------------------------------------------------------------