Sunday, August 17, 2014

Javascript variable definition with Swift

Did you know that you can define variables in Swift the same way like in Javascript?

var currentVersion = self.db.version,
    oldVersionString = version! as NSString,
    oldVersion = oldVersionString.doubleValue

The similarity is impressive. Now I'm waiting for a swift to Javascript converter called Swiftscript or Coffeeswift.

Saturday, August 16, 2014

Local push notifications in iOS 8

Back to iOS-Developmenent. I'm currently working on a push notification implemenation.
iOS 8 provides new interaction possibilities to deal with push notifications.
I found this tutorial which explains how to use custom buttons in swift. Very helpful in my opinion.
This guy pointed me to the function which I need to use to catch the notification the user has clicked:

func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void)

Haven't found any explanation in the official push notification guide by apple so I assume its a new function in iOS8. Its available for remote notifications as well.

Friday, August 15, 2014

How to create an image gallery with file upload into different folders (part 2)

This part is about setting the gallery live.
The configuration will be:

There is the fat cloud which contains my small host with a unique IP-Address.
I've been using digital ocean to setup the system at http://gallery.code-lounge.com.
To map the IP-Address to a more readable name I've booked an address at a DNS-Provider. Mine is hosteurope. Eventually the requested page will be delivered to the user.
The application stack on the server contains NodeJS, node-forever and nginx. Nginx is used as a proxy before nodejs. Forever makes sure the script runs forever and won't stop by an error.
I've chosen the distribution Ubuntu 14.04 for my host and my further description will be related to Ubuntu.

Copy the gallery script to the server

I've used the directory /usr/share/nginx/www/gallery for the gallery.
Clone the repository and create the required symlinks explained in part 1.

nginx

First I've added the recommended repository from the nginx wiki to my sources. This will make sure I have a more current version available than the repository that is included into Ubuntu by default.
apt-get install nginx will install nginx.
Now open the /etc/nginx/nginx.conf file and paste the following code into the http part.


upstream gallery.code-lounge.com {
    server 127.0.0.1:3002;
}

server {
    listen 0.0.0.0:80;
    server_name gallery.code-lounge.com;
    access_log /var/log/nginx/gallery.code-lounge.com;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;

        proxy_pass http://gallery.code-lounge.com/;
        proxy_redirect off;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    client_max_body_size 10M;
}

Now replace all occurrences of gallery.code-lounge.com with your own hostname. Save the file and reload nginx with service nginx reload. Testing the host will provide a bad gateway response since nodejs is not setup yet.

NodeJS

Same like for nginx I want to have most current version. Therefor I've executed the curl command recommended in the official node js installation instructions.
apt-get install nodejs will do the installation.

Node-Forever

Now install forever with npm install -g forever.
The server can be started now with using forever start /usr/share/nginx/www/gallery/app.js

forever list will show you the currently running scripts
forever stop index will stop the script.

You should the the folders of your folders.json after typing the url into your browser.

Tuesday, August 12, 2014

How to create an image gallery with file upload into different folders (part 1)

You can checkout the github project here.
There is an example page here: gallery.code-lounge.com

Introduction

I wanted to have an easy to use image gallery with upload functionality.
The effort must be reduced to a minimum (since I have no time).
The article is splitted into two parts. In the first I'll explain how to setup the folder and gallery view including the upload.
The second part will be about setting the system live using nginx and securing the project with htaccess.

I decided to use existing projects of blueimp. 
The Bootstrap image gallery will make sure that the gallery is compatible with most devices. JQuery File Upload (also by blueimp) is responsible for a nice user experience during the upload process. The user must be able to use either drag and drop or select multiple files at once to make the upload process as convenient as possible.

The project in screenshots

I discovered (as always) that the complexity is much higher than previously assumed.
The result will look like this:

Up there you can see the gallery view. Folders are listed there. Blue folders are filled with pictures. Grey ones are empty.


This is the folder view. The images are responsively aligned. Also pictures taken in portrait mode should be handled nicely.


The upload process will look like this. As mentioned multiple files are possible with either using drag and drop or the dialog. After uploading the preview picture and loading animation will fly away (or get removed) with a fancy animation.

Technology

I've used twitter bootstrap, jquery and the two mentioned blueimp libraries for the frontend. Fontawsome provides nice icons.
In the backend I decided to use nodeJS or more specific expressJS.

Please keep in mind: I really needed to get this done as fast as possible. You won't find any new hipster technology like angularJS, unit tests or anything other alike.
The frontend part of the project is based on existing example code copied together.
I spend a little bit more time at the backend nodeJS part, but I think there could be lots of improvements there as well.

Folder Structure


Installing npm packages

Create a new folder, open the terminal and enter:
For initializing the project
npm init

For the file upload
npm install blueimp-file-upload --save

For the image gallery
npm install blueimp-bootstrap-image-gallery --save

For handling the webserver in nodeJS
npm install express --save

For creating smaller preview images in nodeJS
npm install gm --save

For handling file uploads in nodeJS
npm install busboy --save

The next part is system dependend.
An image conversion library is necessary. I decided to use imagemagick
For Ubuntu
sudo apt-get install imagemagick

For MacOSX
sudo port install imagemagick
or
sudo brew install imagemagick

Now I've created a public folder which contains static files delivered by the webserver.

mkdir public

Since I want to expose frontend libraries only I create symlinks to the frontend npm packages:
ln -s /Users/<user>/projects/image_gallery/node_modules/blueimp-bootstrap-image-gallery public
ln -s /Users/<user>/projects/image_gallery/node_modules/blueimp-file-upload public

Folder View

Backend

I kept it very simple: The folders are stored in a JSON file like this:


{
  "folder_1": "Folder 1",
  "folder_2": "Folder 2",
  "folder_3": "Folder 3"
}

The request is done to folder.json but will be catched by expressJS which will look into the photo-folders, check if they are empty and deliver something like this:



{
  "folder_1": {
    "title": "Folder 1",
    "isEmpty": false
  },
  "folder_2": {
    "title": "Folder 2",
    "isEmpty": true
  },
  "folder_3": {
    "title": "Folder 3",
    "isEmpty": true
  }
}


This is needed to show the colors in the frontend.

Frontend

The folder view contains some html and a small js part (which is directly included into html part).
The javascript does an ajax request to request folders.

Gallery View

Frontend

Well I already told you about my copy and paste approach.
So I did:
cp public/blueimp-bootstrap-image-gallery/index.html public/

Edited index.html and replaced lines
<link rel="stylesheet" href="css/bootstrap-image-gallery.css">
<link rel="stylesheet" href="css/demo.css">
<script src="js/bootstrap-image-gallery.js"></script>
<script src="js/demo.js"></script>

with

<link rel="stylesheet" href="blueimp-bootstrap-image-gallery/css/bootstrap-image-gallery.css">
<link rel="stylesheet" href="blueimp-bootstrap-image-gallery/css/demo.css">
<script src="blueimp-bootstrap-image-gallery/js/bootstrap-image-gallery.js"></script>
<script src="blueimp-bootstrap-image-gallery/js/demo.js"></script>

Doubleclicked index.html and check.
For the upload I simply copied lots of basic-plus.html included in the blueimp-file-upload project.
For more information check the github project.

Backend

The backend provides the image names for listing the images and he upload functionionality into different folders.

Setting up a test server

You could just use node app.js but a better approach would be to install nodemon:
(sudo) npm install -g nodemon

Nodemon has the advantage to check if files are modified and restart nodejs atomatically to ensure that the files are always up to date.

nodemon app.js
will start the server.
Open the browser and put http://127.0.0.1:3002 into the address field.

Tuesday, August 5, 2014

Xcode 6 beta 5

Hi,

I'm currently trying Xcode 6 beta 5.
For me one major issue occurred: I'm not able to use IBOutlets from storyboards anymore.
According to the release notes they have introduced strong connection binding but removing "weak" keyword doesn't resolve the issue. The outlets are always nil making the new beta version unusable for me.

Additionally they changed optional parameter checking:

var test: String?

if test {
    NSLog("test is set")
}

This is not possible anymore. I need to refactor my code into:

var test: String?

if test != nil {
    NSLog("test is set")
}

Anyway, I need to stay at beta 4 because of the IBOutlet issue.
Ah almost forgot, the icons are looking more fancy now :)

Update

Don't think about using your app with two beta versions. After refactoring I got an error with beta 4 Type 'Model' does not conform to protocol 'Equatable'.

Update:

The IBOutlet bug is related to view controllers which are using xib-views and are not explicitly instantiated with the nibName.
I just had to do MyController(nibName: "MyController", bundle: nil) instead of MyController().

Found the answer on stackoverflow.

Monday, August 4, 2014

The unfortunate iOS Developer

Hi there,

last week I was struggeling with iOS development. I was so deep into learning and coding that I simply had no nerve to write something in the blog.
It started very well. It was just me, xcode beta and the new programming language swift all together following one target: Developing my app.

What costs me most of the time was layouting.
I was coming from android development where its standard to have the xml files and a visual dummy representation, where I can see what the view will look like. That in mind I thought its a good idea to have a visual representation in the iOS app as well.
First I got in touch with the storyboard which is created by default. It was working quit ok in the beginning. Then I wanted to use a third party library which was shipped with examples based on xib files. While storyboards containing usually more than one view(-controller) a xib file contains only one. So I learned to use xib files too (just for fun, haha).

After doing this excurse I returned to storyboards and wanted to get into serious development: The plan was to position my elements and then be happy. It shouldn't be.
Unfortunately iOS is using absolute positioning in the standard views only which makes it impossible (for me) to dynamically hide and show elements. Maybe this is one reason that iOS is running so smothly compared to Android. All elements do not care about any other than themselfes.

There is a way to use constraints for hiding and showing.
Unfortunately its to big effort to make all the constraints and results in confusing code.

I realized that static table layout could be a solution. I tried to define it in the storyboard.
Unfortunately xcode has a bug that prevented me from using custom cells in the storyboard so that wasn't a solution either.

Then I was trying some third party library call QuickDialog. I got the samples to run.
Unfortunatly I wasn't able to integrate the lib into my project. Also I realized that the lib is a little bit oversized for my project.

So I decided to use the only real way: doing it in code. No visual presentation, but who cares since I'm the only one who needs to do something in the project. Doing it programmatically allows me to render elements depending on certain conditions. I really can recommend to take a look into this autolayout example library.

Wednesday, July 23, 2014

Starting with iOS Development using Swift

Motivation

I'm currently developing an Android-App. I thought it would be nice if this app is also available for iOS. The Android App contains standard components which maybe easy to realise at iOS.

Xcode beta

After installing the Xcode beta I was able to use the new programming language Swift which Apple will officially introduce in Fall this year. Xcode contains a fancy playground for playing with the new Swift language. If you assign variables you can check the values on the right instantly while typing.
Overall I do like Xcode. Its similar to visual studio. It contains an interface builder where I could play with the available UI components.

Approaching development

 Sometime I got bored with senseless clicking in Xcode and I felt ready for first tutorials. I started with a swift tutorial tutorial by Jameson Quave. It was interesting to see how the IB works in action. It is more than just placing components. You can actually do relations between the controller and code. Furthermore it is possible to chain multiple views.

Objective-C together with Swift

There are tons of Objective-C libraries available as open source. It would be a bad move to skip backwards compatibility so apple decided to introduce bridge header for using Objective-C-Code in Swift. It is explained in the apple developer reference.

Using SVWebViewController with Swift

I've chosen the Objective-C library SVWebViewController available on github to use in my test project.

It is a library that mocks a browser window using the internal UIWebView component of iOS. Its creating an own view with the browser window, controls for navigation, page reloading, loading indicator and page title.

Just download a stable release, extract and drag the folder SVWebViewController/SVWebViewController into your project. Xcode may ask something but I left everything at default.
My project was created as an single page Application.
It is named "webview" so I can see a folder "webview" in the project navigator. I dragged the SVWebViewController directly under that folder.

Now I needed to create the bridge header file. Just right click in the Project Navigator -> New File -> iOS -> Source -> header file. I chose the name "bridge-header.h". Then insert the references of the objective-C header files into the the file:

#import "SVWebViewController.h"
#import "SVModalWebViewController.h"

The bridge header file must refer to the projects build settings. In the Project navigator click at the root and click on build settings in the center view. Scroll down to Swift Compiler - Code Generation (or hit command+f to search for it). Click into Objectvie-C Bridging Header and insert the relative path to your bridge header file there. In my case its "webview/bridge-header.h" (<project-name>/<header-filename>.h).

The easiest way to use SVWebViewController is to add code for initialising into the application function of the AppDelegate.swift.


func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    // Override point for customization after application launch.
    self.window = UIWindow(frame:UIScreen.mainScreen().bounds)
    self.window!.backgroundColor = UIColor.whiteColor()
    self.window!.rootViewController = SVModalWebViewController(address: "http://google.de")
    self.window!.makeKeyAndVisible()
    
    return true
}