QRCoder icon indicating copy to clipboard operation
QRCoder copied to clipboard

[WIP/QRCoder2] Fluent API experimentation PR

Open Shane32 opened this issue 1 month 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