qrcode: display qrcode on main page

Relies on libqrencode, cloned and compiled by cmake

Tuleap: #616
Change-Id: I2cb9281289478321751a947fc8828bf0ba5c6f27
diff --git a/src/RingWindowController.mm b/src/RingWindowController.mm
index 3bc5413..01417ed 100644
--- a/src/RingWindowController.mm
+++ b/src/RingWindowController.mm
@@ -18,7 +18,7 @@
  */
 #import "RingWindowController.h"
 #import <QuartzCore/QuartzCore.h>
-
+#include <qrencode.h>
 
 //Qt
 #import <QItemSelectionModel>
@@ -37,15 +37,20 @@
 #import "ConversationVC.h"
 
 #import "PreferencesWC.h"
+#import "views/IconButton.h"
 #import "views/NSColor+RingTheme.h"
 
 @implementation RingWindowController {
 
+    __unsafe_unretained IBOutlet NSLayoutConstraint* centerYQRCodeConstraint;
+    __unsafe_unretained IBOutlet NSLayoutConstraint* centerYWelcomeContainerConstraint;
+    __unsafe_unretained IBOutlet NSView* welcomeContainer;
     __unsafe_unretained IBOutlet NSView* callView;
     __unsafe_unretained IBOutlet NSTextField* ringIDLabel;
     __unsafe_unretained IBOutlet NSButton* shareButton;
+    __unsafe_unretained IBOutlet NSImageView* qrcodeView;
 
-    PreferencesWC *preferencesWC;
+    PreferencesWC* preferencesWC;
     CurrentCallVC* currentCallVC;
     ConversationVC* offlineVC;
 }
@@ -154,11 +159,106 @@
 
 - (IBAction)shareRingID:(id)sender {
     NSSharingServicePicker* sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:[NSArray arrayWithObject:[ringIDLabel stringValue]]];
+    [sharingServicePicker setDelegate:self];
     [sharingServicePicker showRelativeToRect:[sender bounds]
                                       ofView:sender
                                preferredEdge:NSMinYEdge];
 }
 
+- (IBAction)toggleQRCode:(id)sender {
+    // Toggle pressed state of QRCode button
+    [sender setPressed:![sender isPressed]];
+    if (![sender isPressed]) {
+        // Recenter welcome view
+        [self showQRCode:NO];
+        return;
+    }
+
+    auto qrCode = QRcode_encodeString(ringIDLabel.stringValue.UTF8String,
+                                      0,
+                                      QR_ECLEVEL_L, // Lowest level of error correction
+                                      QR_MODE_8, // 8-bit data mode
+                                      1);
+    if (!qrCode) {
+        return;
+    }
+
+    CGFloat size = qrcodeView.frame.size.width;
+
+    // create context
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    CGContextRef ctx = CGBitmapContextCreate(0, size, size, 8, size * 4, colorSpace, kCGImageAlphaPremultipliedLast);
+
+    CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(0, -size);
+    CGAffineTransform scaleTransform = CGAffineTransformMakeScale(1, -1);
+    CGContextConcatCTM(ctx, CGAffineTransformConcat(translateTransform, scaleTransform));
+
+    // draw QR on this context
+    [self drawQRCode:qrCode context:ctx size:size];
+
+    // get image
+    auto qrCGImage = CGBitmapContextCreateImage(ctx);
+    auto qrImage = [[NSImage alloc] initWithCGImage:qrCGImage size:qrcodeView.frame.size];
+
+    // some releases
+    CGContextRelease(ctx);
+    CGImageRelease(qrCGImage);
+    CGColorSpaceRelease(colorSpace);
+    QRcode_free(qrCode);
+
+    [qrcodeView setImage:qrImage];
+    [self showQRCode:YES];
+}
+
+/**
+ * @param code the previously generated QRCode
+ * @param ctx current drawing context
+ * @param size the output size in which to draw
+ */
+- (void)drawQRCode:(QRcode *)code context:(CGContextRef)ctx size:(CGFloat)size {
+    unsigned char *data = 0;
+    int width;
+    data = code->data;
+    width = code->width;
+    int qr_margin = 3;
+    float zoom = ceil((double)size / (code->width + 2.0 * qr_margin));
+    CGRect rectDraw = CGRectMake(0, 0, zoom, zoom);
+
+    int ran;
+    for(int i = 0; i < width; ++i) {
+        for(int j = 0; j < width; ++j) {
+            if(*data & 1) {
+                CGContextSetFillColorWithColor(ctx, [NSColor ringDarkGrey].CGColor);
+                rectDraw.origin = CGPointMake((j + qr_margin) * zoom,(i + qr_margin) * zoom);
+                CGContextAddRect(ctx, rectDraw);
+                CGContextFillPath(ctx);
+            } else {
+                CGContextSetFillColorWithColor(ctx, [NSColor windowBackgroundColor].CGColor);
+                rectDraw.origin = CGPointMake((j + qr_margin) * zoom,(i + qr_margin) * zoom);
+                CGContextAddRect(ctx, rectDraw);
+                CGContextFillPath(ctx);
+            }
+            ++data;
+        }
+    }
+}
+
+/**
+ * Start the in/out animation displaying the QRCode
+ * @param show should the QRCode be animated in or out
+ */
+- (void) showQRCode:(BOOL) show
+{
+    static const NSInteger offset = 110;
+    [NSAnimationContext beginGrouping];
+    NSAnimationContext.currentContext.duration = 0.5;
+    [[NSAnimationContext currentContext] setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
+    qrcodeView.animator.alphaValue = show ? 1.0 : 0.0;
+    [centerYQRCodeConstraint.animator setConstant: show ? offset : 0];
+    [centerYWelcomeContainerConstraint.animator setConstant:show ? -offset : 0];
+    [NSAnimationContext endGrouping];
+}
+
 - (IBAction)openPreferences:(id)sender
 {
     preferencesWC = [[PreferencesWC alloc] initWithWindowNibName:@"PreferencesWindow"];