From 3aa0b555128ae354756bcfdc21404b41c2efc70f Mon Sep 17 00:00:00 2001 From: Alexa <53471801+Alexa-RR@users.noreply.github.com> Date: Wed, 27 May 2026 11:11:31 +0300 Subject: [PATCH] launcher: QR code + share buttons on host ready panel The single Copy button left it on the user to format a message and get the code into Discord/email. Added a layout that makes sharing obvious: - QR encodes the join code text so a friend with a phone can scan the host's screen and forward the code without typing it - "Copy as message" formats a one-line "Join {server} on DorkNet! Download at github.com/... and paste this code:" pitch - "Email to friend" opens the default mail client with subject + body prefilled, code in the body - QR built via QRCoder -> WriteableBitmap directly (no System.Drawing dependency); palette matches the launcher --- launcher/Backend/QrCodeRenderer.cs | 60 +++++++++++++++++++++++++++ launcher/DorkNet.Launcher.csproj | 7 ++++ launcher/MainWindow.xaml | 65 +++++++++++++++++++++++------- launcher/MainWindow.xaml.cs | 33 +++++++++++++++ 4 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 launcher/Backend/QrCodeRenderer.cs diff --git a/launcher/Backend/QrCodeRenderer.cs b/launcher/Backend/QrCodeRenderer.cs new file mode 100644 index 0000000..9cb7f59 --- /dev/null +++ b/launcher/Backend/QrCodeRenderer.cs @@ -0,0 +1,60 @@ +using System.Windows.Media; +using System.Windows.Media.Imaging; +using QRCoder; + +namespace DorkNet.Launcher.Backend; + +/// Turns a join-code string into a WPF +/// using QRCoder's raw module matrix. We render the matrix directly to a +/// rather than going through PNG bytes so we +/// avoid pulling in System.Drawing.Common (Windows-only, slated for +/// trimming in cross-platform .NET). +/// +/// Colour choice matches the launcher palette: white (Ink) modules +/// on the deep purple-navy (BgDeeper) background so the QR is legible +/// against the dark panel. +public static class QrCodeRenderer +{ + public static BitmapSource Render(string text, int pixelSize = 220) + { + // QRCodeGenerator -> QRCodeData (matrix of bools) -> WriteableBitmap. + using var gen = new QRCodeGenerator(); + using var data = gen.CreateQrCode(text, QRCodeGenerator.ECCLevel.M); + var modules = data.ModuleMatrix; + var moduleCount = modules.Count; + if (moduleCount == 0) + throw new InvalidOperationException("QR generation produced an empty matrix."); + + // Scale up to the requested pixel size — int division so each + // module is an exact pixel count (avoids subpixel blur). Quiet + // zone (4-module margin) is part of QRCodeData already. + var moduleSize = Math.Max(1, pixelSize / moduleCount); + var dim = moduleCount * moduleSize; + + var bmp = new WriteableBitmap(dim, dim, 96, 96, PixelFormats.Bgra32, null); + var stride = dim * 4; + var pixels = new byte[dim * stride]; + + // Light pixel = Ink (#F7F3FF), dark pixel = BgDeeper (#0E0A1F). + // Order is BGRA in the buffer. + var light = new byte[] { 0xFF, 0xF3, 0xF7, 0xFF }; + var dark = new byte[] { 0x1F, 0x0A, 0x0E, 0xFF }; + + for (int y = 0; y < moduleCount; y++) + for (int x = 0; x < moduleCount; x++) + { + var on = modules[y][x]; + var src = on ? dark : light; + for (int py = 0; py < moduleSize; py++) + for (int px = 0; px < moduleSize; px++) + { + var offset = ((y * moduleSize + py) * stride) + ((x * moduleSize + px) * 4); + Buffer.BlockCopy(src, 0, pixels, offset, 4); + } + } + + bmp.WritePixels(new System.Windows.Int32Rect(0, 0, dim, dim), pixels, stride, 0); + bmp.Freeze(); + return bmp; + } +} diff --git a/launcher/DorkNet.Launcher.csproj b/launcher/DorkNet.Launcher.csproj index 54563f7..2eaf223 100644 --- a/launcher/DorkNet.Launcher.csproj +++ b/launcher/DorkNet.Launcher.csproj @@ -20,4 +20,11 @@ The Backend/* classes (release downloader, server process, etc.) are UI-framework-agnostic and stay unchanged from the PhotinoNET draft. --> + + + + + diff --git a/launcher/MainWindow.xaml b/launcher/MainWindow.xaml index e958a6a..cae9de4 100644 --- a/launcher/MainWindow.xaml +++ b/launcher/MainWindow.xaml @@ -235,28 +235,63 @@ - + - -