QRCoder icon indicating copy to clipboard operation
QRCoder copied to clipboard

[WIP/QRCoder2] Fluent API experimentation PR

Open Shane32 opened this issue 1 year ago • 3 comments

Summary

Experimentation with fluent API syntax

Samples

var code = QRCodeBuilder.CreateEmail("[email protected]")
    .WithSubject("Testing")
    .WithBody("Hello World!")
    .WithErrorCorrection(QRCodeGenerator.ECCLevel.H)
    .RenderWith<AsciiRenderer>()
    .WithQuietZone(false)
    .ToString();

var image = QRCodeBuilder.CreatePhoneNumber("1234567890")
    .WithErrorCorrection(QRCodeGenerator.ECCLevel.H)
    .RenderWith<SystemDrawingRenderer>(20)
    .WithQuietZone(false)
    .ToBitmap();

var base64 = QRCodeBuilder.CreateMMS("1234567890", "Hello")
    .RenderWith<PngRenderer>()
    .ToBase64String();

Intellisense samples

image

image

Preliminary Findings

  1. Could start with new QRCodeBuilder.Email("[email protected]") rather than QRCodeBuilder.CreateEmail("[email protected]") - which is pretty similar to the existing new PayloadGenerator.Wifi() syntax actually, with the difference being the fluent syntax for configuration. One benefit of using new is that additional payloads can be added by simply adding a new class into the correct namespace. Whereas methods cannot be added to QRCodeBuilder outside of QRCoder.
  2. Using RenderWith<T> breaks the intellisense pattern because T does not give a list of the specific renderers available. Probably better to create an extension method for each renderer, like RenderAsAscii() and RenderAsPng(20) instead
  3. RenderWith<T> does not allow for render-specific constructor parameters. I've compensated with support for only two patterns: (1) no arguments (2) pixels per module argument. Having RenderAs...() dedicated methods would allow each renderer to require specific arguments.
  4. The builder syntax could likely be added to v1.x as a new layer, as shown in this PR, with any implementation changes we wish to make within the builder methods. Then v2 just removes (or makes internal) all the old methods.
  5. The new builders, when layered on the old code, are quite easy to write. Once the old code is removed, additional optimizations can be added to enhance trimming support. This trimming capability may consolidate the QRCode and ArtQRCode classes.
  6. All of the supporting code can be nested as deep within namespaces as desired, since intellisense always provides the correct context-sensitive methods. Except for RenderWith<T>, as noted in item 2 above. Another reason to use RenderAsAscii() or similar.
  7. The extension methods on the renderers (ToArray, ToStream, ToFile, etc) are really cool -- each renderer need only implement ToStream and all the other methods are available via extension methods. Similar functionality for text renderers; even with only implementing ToString they can also provide ToFile, ToStream, ToBase64, and so on via extension methods.

Shane32 avatar Jun 01 '24 05:06 Shane32

The builder syntax could likely be added to v1.x as a new layer, as shown in this PR

QRCoder2.FluentExtensions maybe? šŸ˜‰

csturm83 avatar Jun 02 '24 03:06 csturm83

Hi Shane, thanks for the PR. That looks pretty interesting. However, I don't want to merge this into v1.x, but would like to include it in v2 first, as I don't want to make/document/communicate any more major API changes to v1. I hope that's okay with you.

codebude avatar Jun 02 '24 10:06 codebude

Certainly. I wrote this more of a discussion/preview/review of a potential approach.

Shane32 avatar Jun 02 '24 12:06 Shane32

Hi @Shane32 ,

since QRCoder will reach its end of life and the repository will be archived on November 1st, 2025, I’d like to clarify how to proceed with this PR.

Would you prefer me to merge it before the archival, or should I close it instead?
Please let me know what you think – I want to handle your contribution in the way that feels most appropriate to you.

Thanks again for your effort and contribution!

codebude avatar Sep 27 '25 21:09 codebude

Closed in consultation with @Shane32

codebude avatar Sep 30 '25 12:09 codebude