Develop a simple iOS mobile app (toDoList) using Swift – Part 2

In the first part of the simple iOS mobile app (toDoList) tutorial series, you covered the basics of setting environment and user interface/autolayout.

In this second and final part of the tutorial series, we’ll cover Parse integration.

We’ll start where we left off last tutorial, so open your project from last time, or go through the previous tutorial first. http://blog.revivalx.com/2015/05/13/develop-a-simple-ios-mobile-app-todolist-using-swift-part-1/

Select UITableViewController in Main.Storyboard and edit Attribute Inspector according to this setting:

Style: Basic
Identifier: TaskCell
Accessory: Disclosure Indicator

Attribute Inspector.

Attribute Inspector.

UiTableViewController

UiTableViewController

Go to UIViewController and make sure the user interface is similar like this one. Don’t forget to set constraints for each elements. If you don’t know how to do it, feel free to refer it here, https://developer.apple.com/library/ios/referencelibrary/GettingStarted/RoadMapiOS/DesigningaUserInterface.html.

UIViewController.

UIViewController.

Sign up for your new account here, https://www.parse.com/.

Parse

Parse

Click Create a New App.

Create a New App

Create a New App

Go to Keys and save your Application ID and Client Key. Open AppDelegate.swift file and update the Application ID and Client Key.

import UIKit
import ParseFacebookUtils
 
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
 
  func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // [Optional] Power your app with Local Datastore. For more info, go to
    // https://parse.com/docs/ios_guide#localdatastore/iOS
    Parse.enableLocalDatastore()
 
    // Initialize Parse.
    Parse.setApplicationId("xxxxx",
      clientKey: "xxxxx")
 
    // [Optional] Track statistics around application opens.
    PFAnalytics.trackAppOpenedWithLaunchOptions(launchOptions)
 
    // ...
}
 
// ...

Create two Cocoa Touch Class. One is TableViewController.swift (UITableViewController) and the other one is ViewController.swift (UIViewController).

Xcode 6.4 - New File.

Xcode 6.4 – New File.

Cocoa Touch Class

Cocoa Touch Class

UITableViewController

UITableViewController

UIViewController

UIViewController

Project navigator

Project navigator

Then make sure you attach both files into each controllers in Identity inspector.

Identity inspector - UITableViewController

Identity inspector – UITableViewController

Identity inspector -UIViewController

Identity inspector -UIViewController

Select Table View Cell, go to Identity Inspector and select PFTableViewCell.

PFTableViewCell

PFTableViewCell

Create Task model.

Swift File.

Swift File.

Project navigator

Project navigator

Go to the Task.swift file and replace with this code.

import Foundation
import UIKit

class Task: NSObject {
    var taskId: Int
    var name: String
    
    init(taskId: Int, name: String) {
        self.taskId = taskId
        self.name = name
        super.init()
    }
}

Open TableViewController.swift and update the with this code.

import UIKit
import Parse
import ParseUI

class TableViewController: PFQueryTableViewController {
    
    var id: String!
    var name: String!
    var descriptions: String!
    
    override init(style: UITableViewStyle, className: String?) {
        super.init(style: style, className: className)
    }
    
    @IBAction func addNewTask(sender: AnyObject) {
        self.id = nil
        self.performSegueWithIdentifier("MySegue", sender: self)
    }
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        self.parseClassName = "Task"
        self.textKey = "name"
        self.pullToRefreshEnabled = true
        self.paginationEnabled = false
        
    }
    
    override func queryForTable() -> PFQuery {
        var query = PFQuery(className: "Task")
        query.orderByAscending("name")
        
        
        return query
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableView.estimatedRowHeight = 44
        self.tableView.rowHeight = UITableViewAutomaticDimension
        self.tableView.reloadData()
    }
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
        var cell = tableView.dequeueReusableCellWithIdentifier("TaskCell") as! PFTableViewCell!
        if cell == nil {
            cell = PFTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
        }
        
        cell.textLabel?.text = object!["name"] as? String
        
        return cell
    }

    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {
            let objectToDelete = objects?[indexPath.row] as! PFObject
            objectToDelete.deleteInBackgroundWithBlock {
                (success: Bool, error: NSError?) -> Void in
                if (success) {
                    self.tableView.reloadData()
                }
            }
        }
    }
    
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let object = objects?[indexPath.row] as! PFObject
        var query = PFQuery(className:"Task")
        query.getObjectInBackgroundWithId(object.objectId!) {
            (task: PFObject?, error: NSError?) -> Void in
            if error == nil && task != nil {
                self.id = task!.objectId!
                self.name = task!["name"] as! String
                self.descriptions = task!["description"] as! String
                self.performSegueWithIdentifier("MySegue", sender: self)
            } else {
                print(error)
            }
        }
    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "MySegue" {
            let viewController: ViewController = segue.destinationViewController as! ViewController
            viewController.id = id
            viewController.name = name
            viewController.descriptions = descriptions
        }
    }
}

Open ViewController.swift and replace the with this code.

import UIKit
import Parse

class ViewController: UIViewController {

    @IBOutlet weak var txtName: UITextField!
    @IBOutlet weak var txtDescription: UITextField!
    var id: String!
    var name: String!
    var descriptions: String!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        if id != nil {
            txtName.text = name
            txtDescription.text = descriptions
        }
    }

    @IBAction func btnSubmit(sender: AnyObject) {
        if id != nil {
            var query = PFQuery(className:"Task")
            query.getObjectInBackgroundWithId(id) {
                (task: PFObject?, error: NSError?) -> Void in
                if error != nil {
                    print(error)
                } else if let task = task {
                    task["name"] = self.txtName.text
                    task["description"] = self.txtDescription.text
                    task.saveInBackground()
                    self.navigationController!.popViewControllerAnimated(true)
                }
            }
        } else {
            var task = PFObject(className:"Task")
            task["name"] = txtName.text
            task["description"] = txtDescription.text
            task.saveEventually()
            navigationController!.popViewControllerAnimated(true)
        }
    }
}

Result

ToDoList Screenshot 1

ToDoList Screenshot 1

 

ToDoList Screenshot 2

ToDoList Screenshot 2

Building A Hybrid Mobile App With Parse and PhoneGap

In this tutorial, I will show you how to build a hybrid mobile app with Parse and Phonegap.

What is Parse?

Parse is a cloud app platform that enables users to add a scalable and powerful backend to launch a full-featured app.

Reference: https://www.parse.com/

What is Phonegap?

PhoneGap is a free and open source framework that allows you to create mobile apps using standardized web APIs for the platforms you care about.

Reference: http://en.wikipedia.org/wiki/PhoneGap

Download and install Eclipse Juno SR2 and Xcode 6.3.1 (if you using Mac for mobile development).

Eclipse Juno SR2 – http://www.eclipse.org/downloads/packages/release/juno/sr2
Xcode 6.3.1 – https://developer.apple.com/xcode/downloads/

Setup ADT and Android SDK into your eclipse. You can refer here how to setup, http://blog.revivalx.com/2014/02/21/crud-operation-using-jquery-mobile-on-android-part-1/. Then you need to setup cordova using NPM (node package manager) from that link.

Download Jquery and Ratchet from their official website. You should unzip it to proper location. For this tutorial, we using Jquery 1.11.3 and Ratchet 2.0.2.

Sign up for your new account here, https://www.parse.com/.

Parse

Parse

Click Create a New App.

Create a New App

Create a New App

Go to Keys and save your Application ID and Client Key.

Setting up your development environment

Create a cordova project using command below in your terminal/cmd:

cordova create com.revivalx.todolist.parse
cordova create project

cordova create project

Open config.xml inside com.revivalx.todolist.parse folder and replace with this code.

<?xml version='1.0' encoding='utf-8'?>
<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>ToDo</name>
    <description>
        This source code provides example for todolist app using parse.
    </description>
    <author email="mohammadnrdn@gmail.com" href="http://revivalx.com">
        Mohammad Nurdin bin Norazan
    </author>
    <content src="index.html" />
    <access origin="*" />
</widget>

Add platform for iOS and android.

cordova platform add ios
cordova platform add android
cordova platform add ios

cordova platform add ios

cordova platform add android

cordova platform add android

Create a new project inside your eclipse.

create a new eclipse project

create a new eclipse project

Select General > Project.

new eclipse project

new eclipse project

Enter following details and click Finish.

Project name: com.revivalx.todolist.parse .

Location: your project location.

new eclipse project

new eclipse project

Overview of Cordova directory structures

Here is the Cordova directory structure:

cordova structure

cordova structure

hooks – This directory may contains scripts used to customize cordova commands.

platforms (android and iOS) – Platforms added to your application will have the native application project structures laid out within this directory.

plugins – Any added plugins will be extracted or copied into this directory.

www (css) – The main application CSS directory.

www (img) – The main application image directory.

www (js) – The main application javascript directory.

index.html – The main HTML file.

config.xml – A global configuration file.

Preview your app (android)

Import android project into your eclipse.

import cordova project

import cordova project

Select AndroidExisting Android Code Into Workspace.

import existing android code into workspace

import existing android code into workspace

Browse your project and click Finish.

import android project

import android project

Follow this tutorial how to run android app in android simulator.

http://blog.revivalx.com/2014/02/21/crud-operation-using-jquery-mobile-on-android-part-1/

Preview your app (ios)

Go to your project directory and browse for xcode project, platforms > ios > ToDo.xcodeproj then run xcode project.

Click Play on top left side to preview the app on your simulator.

xcode project

xcode project

Learning client side API and building a multi page application

Right click js folder on your project. Go to New Other.

Javascript Source File

Javascript Source File

Select JavaScript > JavaScript Source File and click Next.

javascript source file

javascript source file

Create 3 javascript files.

  • main.js – initialize function.
  • AddPage.js – to add user details.
  • ListPage.js – to retrieve user list.
  • DetailPage.js – to retrieve user details.

Click Finish.

javascript source file

javascript source file

Right click www folder and go to New > Folder to create a new folder.

add folder

add folder

Name it pages and click Finish.

add folder pages

add folder pages

Then create a few of html pages inside page folder that we already created just now. Right click pages folder and go to New > HTML File.

HTML Files

HTML Files

Select Web > HTML File and click Next.

new html file

new html file

Create 3 html files and click Finish. Repeat.

  • AddPage.html – to add task details.
  • ListPage.html – to retrieve task list.
  • DetailPage.html – to retrieve task details.
new html file

new html file

Copy Jquery javascript files that you already extract from proper location into js folder.

jquery

jquery

Go to extracted Ratchet directory and select/copy all folders inside ratchet-2.0.2 > dist .

ratchet directory

ratchet directory

Then paste it inside www folder.

ratchet

ratchet

Open your index.html and replace with this code.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>

    <!-- Sets initial viewport load and disables zooming  -->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">

    <!-- Makes your prototype chrome-less once bookmarked to your phone's home screen -->
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <!-- Include the compiled Ratchet CSS -->
    <link href="css/ratchet.css" rel="stylesheet">
    <script src="cordova.js" type="text/javascript"></script>
    <script src="js/jquery-1.11.3.min.js"></script>
    <script src="//www.parsecdn.com/js/parse-1.4.2.min.js"></script>
    <script type="text/javascript">
    	Parse.initialize("Application ID", "Client Key");
    </script>
    <script src="js/ratchet.js"></script>
    <script src="js/main.js"></script>
  </head>
  <body onload="init()">

  </body>
</html>

Replace all codes with given codes for each javascript files.

AddPage.js

currentPage = {};
currentPage.init = function() {
	console.log("AddPage :: init");
};
currentPage.back = function() {
	console.log("AddPage :: back");
	$("body").load(path + "pages/ListPage.html", function() {
		$.getScript(path + "js/ListPage.js", function() {
			if (currentPage.init) {
				currentPage.init();
			}
		});
	});
};
currentPage.add = function() {
	console.log("AddPage :: add");
	var name = $("#name").val();
	var description = $("#description").val();
	formData = {
		name: $("#name").val(),
		description: $("#description").val(),
	}
	if (name == "") {
		alert("Please enter name");
	} else if (description == "") {
		alert("Please enter description");
	} else {
		var Task = Parse.Object.extend("Task");
		var task = new Task();
		task.set("name", name);
		task.set("description", description);
		task.save(null, {
			success: function(task) {
				// Execute any logic that should take place after the object is saved.
				alert("Add task success");
				$("body").load(path + "pages/ListPage.html", function() {
					$.getScript(path + "js/ListPage.js", function() {
						if (currentPage.init) {
							currentPage.init();
						}
					});
				});
			},
			error: function(task, error) {
				// Execute any logic that should take place if the save fails.
				// error is a Parse.Error with an error code and message.
				alert('Failed to create new object, with error code: ' + error.message);
			}
		});
	}
};

DetailPage.js

currentPage = {};
currentPage.init = function() {
	console.log("DetailPage :: init");
	detailTask();
};
currentPage.back = function() {
	console.log("DetailPage :: back");
	$("body").load(path + "pages/ListPage.html", function() {
		$.getScript(path + "js/ListPage.js", function() {
			if (currentPage.init) {
				currentPage.init();
			}
		});
	});
};
currentPage.edit = function() {
	console.log("DetailPage :: edit");
	var taskId = sessionStorage.taskId;
	var name = $("#name").val();
	var description = $("#description").val();
	formData = {
		taskId: sessionStorage.taskId,
		name: $("#name").val(),
		description: $("#description").val()
	}
	if (name == "") {
		alert("Please enter name");
	} else if (description == "") {
		alert("Please enter description");
	} else {
		var Task = Parse.Object.extend("Task");
		var query = new Parse.Query(Task);
		query.get(taskId, {
			success: function(task) {
				// The object was retrieved successfully.
				// Create the object.
				task.set("name", name);
				task.set("description", description);
				task.save(null, {
					success: function(task) {
						alert("Edit task success");
						$("body").load(path + "pages/ListPage.html", function() {
							$.getScript(path + "js/ListPage.js", function() {
								if (currentPage.init) {
									currentPage.init();
								}
							});
						});
					}
				});
			},
			error: function(object, error) {
				// The object was not retrieved successfully.
				// error is a Parse.Error with an error code and message.
				alert(error);
			}
		});
	}
};

function detailTask() {
	formData = {
		taskId: sessionStorage.taskId
	}
	var Task = Parse.Object.extend("Task");
	var query = new Parse.Query(Task);
	query.get(taskId, {
		success: function(task) {
			// The object was retrieved successfully.
			$('#name').val(task.get("name"));
			$('#description').val(task.get("description"));
		},
		error: function(object, error) {
			// The object was not retrieved successfully.
			// error is a Parse.Error with an error code and message.
			alert(error);
		}
	});
}
currentPage.remove = function() {
	console.log("DetailPage :: delete");
	deleteTask();
};

function deleteTask() {
	formData = {
		taskId: sessionStorage.taskId
	}
	var Task = Parse.Object.extend("Task");
	var query = new Parse.Query(Task);
	query.get(taskId, {
		success: function(task) {
			// The object was retrieved successfully.
			task.destroy({
				success: function(task) {
					// The object was deleted from the Parse Cloud.
					alert("Delete task success");
					$("body").load(path + "pages/ListPage.html", function() {
						$.getScript(path + "js/ListPage.js", function() {
							if (currentPage.init) {
								currentPage.init();
							}
						});
					});
				},
				error: function(task, error) {
					// The delete failed.
					// error is a Parse.Error with an error code and message.
				}
			});
		},
		error: function(object, error) {
			// The object was not retrieved successfully.
			// error is a Parse.Error with an error code and message.
			alert(error);
		}
	});
}

ListPage.js

currentPage = {};
currentPage.init = function() {
	console.log("ListPage :: init");
	listTasks();
};
currentPage.loadPage = function(pageIndex) {
	console.log("ListPage :: loadPage :: pageIndex: " + pageIndex);
	$("body").load(path + "pages/" + pageIndex + ".html");
	$.getScript(path + "js/" + pageIndex + ".js", function() {
		if (currentPage.init) {
			currentPage.init();
		}
	});
};
currentPage.detailPage = function(userId) {
	sessionStorage.setItem("userId", userId);
	$("body").load(path + "pages/DetailPage.html");
	$.getScript(path + "js/DetailPage.js", function() {
		if (currentPage.init) {
			currentPage.init();
		}
	});
};

function listTasks() {
	var Task = Parse.Object.extend("Task");
	var query = new Parse.Query(Task);
	query.equalTo("typeId", "3");
	query.find({
		success: function(results) {
			var index = 0;
			var Arrlen = results.length;
			for (index = 0; index < Arrlen; ++index) {
				var obj = results[index];
				html += '<li class="table-view-cell">';
				html += '<a class="navigate-right" onclick="currentPage.detailPage(' + obj.id + ');" >';
				html += obj.attributes.name;
				html += '</a></li>';
			}
		},
		error: function(object, error) {
			alert(error);
		}
	});
}

main.js

var pagesHistory = [];
var currentPage = {};
var path = "";

function init(){

    $("body").load(path + "pages/ListPage.html", function(){
        $.getScript(path + "js/ListPage.js", function() {
            if (currentPage.init) {
                currentPage.init();
            }
        });
    });

}

Replace all codes with given codes for each html files.

AddPage.html

<script>
    $.getScript(path + "js/AddPage.js");
</script>
 
<header class="bar bar-nav">
    <a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
    <h1 class="title">AddPage</h1>
</header>

<div class="content">
	<div class="card">
    <ul class="table-view">
        <li class="table-view-cell table-view-divider">Name:</li>

        <li class="table-view-cell"><input id="name" name="name" type="text"></li>

        <li class="table-view-cell table-view-divider">Description:</li>

        <li class="table-view-cell"><input id="description" name="description" type="text"></li>

        <li class="table-view-cell"></li>
    </ul>
   </div>
    <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-positive btn-block" onclick="currentPage.add();">ADD TASK</button>
    </div>
</div>

DetailPage.html

<script>
    $.getScript(path + "js/DetailPage.js");
</script>

<header class="bar bar-nav">
    <a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
    <h1 class="title">DetailPage</h1>
</header>

<div class="content">
	<div class="card">
    <ul class="table-view">
        <li class="table-view-cell table-view-divider">Name:</li>

        <li class="table-view-cell"><input id="name" name="name" type="text"></li>

        <li class="table-view-cell table-view-divider">Description:</li>

        <li class="table-view-cell"><input id="description" name="description" type="text"></li>

    </ul>
   </div>
   <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-positive btn-block" onclick="currentPage.edit();">EDIT TASK</button>
   </div>
   <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-negative btn-block" onclick="currentPage.remove();">REMOVE TASK</button>
   </div>
</div>

ListPage.html

<script>
    $.getScript(path + "js/ListPage.js");
</script>

<header class="bar bar-nav">
	<button id="LoadAddButton" class="btn pull-right" onclick="currentPage.loadPage('AddPage');">Add</button>
  	<h1 class="title">ListPage</h1>
</header>

<div class="content">
	<ul id="taskList" class="table-view"></ul>
</div>

Build and run your project. I’m using Genymotion. If you don’t have, you can download it here,https://www.genymotion.com/.

 

Result.

You can download the source code here, https://github.com/datomnurdin/com.revivalx.todolist.parse.

Develop a simple android mobile app (toDoList) – Part 2

In the first part of the simple android mobile app (toDoList) tutorial series, you covered the basics of setting environment and user interface.

In this second and final part of the tutorial series, we’ll cover Parse integration for each activity classes.

We’ll start where we left off last tutorial, so open your project from last time, or go through the previous tutorial first. http://blog.revivalx.com/2015/06/09/develop-a-simple-android-mobile-app-todolist-part-1/

First, we start from ListActivity where a list of tasks will happen here. Now we need to create a Task class/model. Create a new package to store our model.

Create a new package.

Create a new package.

Enter model for your package name and click OK.

Package name.

Package name.

Then create a java class called Task in model package then replace with this code.

Task.java

public class Task {

    public String taskId;
    public String name;

    public Task(){
        this.taskId = "";
        this.name = "";
    }

    public void setTaskId(String taskId){
        this.taskId = taskId;
    }

    public String getTaskId(){
        return taskId;
    }

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

}

Next, we need to create an XML layout that represents the view template for each item in res/layout/item_task.xml. Right click layout folder > New > Layout resource file.

Layout resource file.

Layout resource file.

Enter item_task in File name. Click OK.

New resource file.

New resource file.

Replace with this code.

item_task.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent" >
   <TextView
      android:id="@+id/txtName"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Name"
      android:padding="5sp"
      android:textSize="25sp" />
</LinearLayout>

Next, we need to define the adapter to describe the process of converting the Java object to a View (in the getView method). Create a new java class in model package, name it as TasksAdapter.

TasksAdapter

public class TasksAdapter extends ArrayAdapter<Task> {
    public TasksAdapter(Context context, ArrayList<Task> tasks) {
        super(context, 0, tasks);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Task task = getItem(position);
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_task, parent, false);
        }
        TextView txtName = (TextView) convertView.findViewById(R.id.txtName);
        txtName.setText(task.name);
        return convertView;
    }
}

Now, we can use that adapter in the ListActivity to display an array of items into the ListView. Once the adapter is attached, items will automatically be populated into the ListView based on the contents of the array. You can add new items to the adapter at any time with:

ListActivity.java

public class ListActivity extends ActionBarActivity {

    private Button btnCreate;
    private TasksAdapter adapter;
    private ArrayList<Task> arrayOfTasks;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list);

        btnCreate = (Button) findViewById(R.id.btnCreate);
        btnCreate.setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {

                Intent createActivity = new Intent(getApplicationContext(), CreateActivity.class);
                startActivity(createActivity);

            }
        });

        arrayOfTasks = new ArrayList<Task>();
        adapter = new TasksAdapter(this, arrayOfTasks);
        ListView listView = (ListView) findViewById(R.id.lv_task);
        listView.setAdapter(adapter);

        ParseQuery<ParseObject> query = ParseQuery.getQuery("Task");

        query.findInBackground(new FindCallback<ParseObject>() {
            public void done(List<ParseObject> taskList, ParseException e) {
                if (e == null) {
                    for (ParseObject tasks : taskList) {

                        Task task = new Task();

                        task.setTaskId(tasks.getObjectId());
                        task.setName(tasks.getString("name"));

                        Log.d("name",task.getName());
                        adapter.add(task);
                    }
                } else {
                    Toast.makeText(getApplicationContext(), "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
                }
            }
        });

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Task task = adapter.getItem(position);

                Intent intent = new Intent(getBaseContext(), UpdateActivity.class);
                intent.putExtra("objectId",  task.getTaskId());
                startActivity(intent);
            }
        });

    }
}

Update activity_list.xml.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.revivalx.androidparsetodolist.ListActivity">

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Create Task"
        android:id="@+id/btnCreate"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />

    <ListView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/lv_task"
        android:layout_below="@+id/btnCreate"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

Replace with this code for CreateActivity.java.

CreateActivity.java

public class CreateActivity extends ActionBarActivity {

    private TextView txtName;
    private TextView txtDescription;
    private String name;
    private String description;
    private Button btnCreate;
    private Button btnBack;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_create);

        txtName = (TextView) findViewById(R.id.txtName);
        txtDescription = (TextView) findViewById(R.id.txtDescription);

        btnCreate = (Button) findViewById(R.id.btnCreate);
        btnCreate.setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {

                name = txtName.getText().toString();
                description = txtDescription.getText().toString();

                if (name.equals("") && description.equals("")) {
                    Toast.makeText(getApplicationContext(),
                            "Please enter name and description",
                            Toast.LENGTH_LONG).show();

                } else {
                    ParseObject task = new ParseObject("Task");
                    task.put("name", name);
                    task.put("description", description);
                    task.saveInBackground();

                    Intent listActivity = new Intent(getApplicationContext(), ListActivity.class);
                    startActivity(listActivity);
                }

            }
        });

        btnBack = (Button) findViewById(R.id.btnBack);
        btnBack.setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {

                Intent listActivity = new Intent(getApplicationContext(), ListActivity.class);
                startActivity(listActivity);

            }
        });
    }

}

Replace with this code for UpdateActivity.java.

public class UpdateActivity extends ActionBarActivity {

    private TextView txtName;
    private TextView txtDescription;
    private Intent intent;
    private Task task;
    private String name;
    private String description;
    private Button btnUpdate;
    private Button btnDelete;
    private Button btnBack;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_update);

        intent = getIntent();

        task = new Task();
        task.setTaskId(intent.getStringExtra("objectId"));

        txtName = (TextView) findViewById(R.id.txtName);
        txtDescription = (TextView) findViewById(R.id.txtDescription);

        ParseQuery<ParseObject> query = ParseQuery.getQuery("Task");
        query.getInBackground(task.getTaskId(), new GetCallback<ParseObject>() {
            public void done(ParseObject task, ParseException e) {
                if (e == null) {
                    name = task.getString("name");
                    description = task.getString("description");

                    txtName.setText(name);
                    txtDescription.setText(description);

                } else {
                    Toast.makeText(getApplicationContext(),
                            "Something went wrong",
                            Toast.LENGTH_LONG).show();
                }
            }
        });

        btnUpdate = (Button) findViewById(R.id.btnUpdate);
        btnUpdate.setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {

                name = txtName.getText().toString();
                description = txtDescription.getText().toString();

                if (name.equals("") && description.equals("")) {
                    Toast.makeText(getApplicationContext(),
                            "Please enter name and description",
                            Toast.LENGTH_LONG).show();

                } else {
                    ParseQuery<ParseObject> query = ParseQuery.getQuery("GameScore");

                    query.getInBackground(task.getTaskId(), new GetCallback<ParseObject>() {
                        public void done(ParseObject task, ParseException e) {
                            if (e == null) {
                                task.put("name", name);
                                task.put("description", description);
                                task.saveInBackground();

                                Intent listActivity = new Intent(getApplicationContext(), ListActivity.class);
                                startActivity(listActivity);
                            } else {
                                Toast.makeText(getApplicationContext(),
                                        "Something went wrong",
                                        Toast.LENGTH_LONG).show();
                            }
                        }
                    });


                }

            }
        });

        btnDelete = (Button) findViewById(R.id.btnDelete);
        btnDelete.setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {

                ParseQuery<ParseObject> query = ParseQuery.getQuery("task");
                query.getInBackground(task.getTaskId(), new GetCallback<ParseObject>() {
                    public void done(ParseObject task, ParseException e) {
                        if (e == null) {

                            task.deleteInBackground();

                            Intent listActivity = new Intent(getApplicationContext(), ListActivity.class);
                            startActivity(listActivity);

                        } else {
                            Toast.makeText(getApplicationContext(),
                                    "Something went wrong",
                                    Toast.LENGTH_LONG).show();
                        }
                    }
                });

            }
        });

        btnBack = (Button) findViewById(R.id.btnBack);
        btnBack.setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {

                Intent listActivity = new Intent(getApplicationContext(), ListActivity.class);
                startActivity(listActivity);

            }
        });

    }

}

Update your activity_update.xml.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.revivalx.androidparsetodolist.UpdateActivity">

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/txtName"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:hint="Name"/>

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/txtDescription"
        android:layout_below="@+id/txtName"
        android:layout_centerHorizontal="true"
        android:hint="Description"/>

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Update Task"
        android:id="@+id/btnUpdate"
        android:layout_below="@+id/txtDescription"
        android:layout_centerHorizontal="true" />

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Delete"
        android:id="@+id/btnDelete"
        android:layout_below="@+id/btnUpdate"
        android:layout_centerHorizontal="true" />

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Back"
        android:id="@+id/btnBack"
        android:layout_below="@+id/btnDelete"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

Run your project. I’m using Genymotion. If you don’t have, you can download it here, https://www.genymotion.com/.

Result.

ListActivity.

ListActivity.

CreateActivity.

CreateActivity.

UpdateActivity.

UpdateActivity.

You can download the source code here, https://github.com/datomnurdin/AndroidParseToDoList

Develop a simple iOS mobile app (toDoList) using Swift – Part 1

Swift is an innovative new programming language for Cocoa and Cocoa Touch. Writing code is interactive and fun, the syntax is concise yet expressive, and apps run lightning-fast. Swift is ready for your next iOS and OS X project — or for addition into your current app — because Swift code works side-by-side with Objective-C.

swift programming language

swift programming language

Here are some of features:

  1. Modern
  2. Designed for Safety
  3. Fast and Powerful
  4. Interactive Playgrounds
  5. Ready Today
  6. Read-Eval-Print-Loop (REPL)

Reference: https://developer.apple.com/swift/

Getting Started.

Before we start this tutorial, make sure you already setup your machine (mac) with these tools:

  1. Xcode 6.3.2 GM seed – https://developer.apple.com/xcode/downloads/ (More stable than Xcode 6.3.1).

Open Xcode and create a new Single View Application. For product name, use RevivalxSwiftToDoList and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and make sure only iPhone is selected in Devices.

Single View Application

Single View Application

RevivalxSwiftToDoList

RevivalxSwiftToDoList

Install CocoaPods using terminal. What is CocoaPods?

CocoaPods manages library dependencies for your Xcode projects.

The dependencies for your projects are specified in a single text file called a Podfile. CocoaPods will resolve dependencies between libraries, fetch the resulting source code, then link it together in an Xcode workspace to build your project.

Ultimately the goal is to improve discoverability of, and engagement in, third party open-source libraries by creating a more centralised ecosystem.

Reference: https://guides.cocoapods.org/using/getting-started.html

Open your terminal and type this command.

sudo gem install cocoapods
sudo gem install cocoapods

sudo gem install cocoapods

Go to your directory and initialize your pod using this command.

cd /Users/MNurdin/Documents/iOS/RevivalxSwiftToDoList
pod init
pod init

pod init

Open your finder and edit pod file (Podfile) with these one.

# Uncomment this line to define a global platform for your project
#platform :ios, '8.0'
use_frameworks!

pod 'HanekeSwift'
pod 'Parse'
pod 'ParseFacebookUtils'
pod 'ParseUI'

target 'RevivalxSwiftToDoList' do

end

target 'RevivalxSwiftToDoListTests' do

end

The reasons why we need these libraries because

Go back to your terminal and run pod install to install all the dependencies. It takes a few of minutes to download.

pod install
Pod install.

Pod install.

After finish downloading, open RevivalxSwiftToDoList.xcworkspace file, not RevivalxSwiftToDoList.xcodeproj because we want to use the pod.

Storyboards and interface builder

Set to Compact Width | Any Height.

Compact Width | Any Height

Compact Width | Any Height

Delete ViewController.swift and ViewController on the Main.Storyboard. Drag a Table View Controller and View Controller to Main.Storyboard.

Main.Storyboard

Main.Storyboard

Select Table View Controller and navigate to Attributes inspector. Tick Is Initial View Controller.

Attributes inspector

Attributes inspector

Select the Table View Controller again and in the menu go to Editor > Embed In > Navigation Controller. This adds a Navigation Controller to the storyboard with an initial scene.

Editor > Embed In > Navigation Controller

Editor > Embed In > Navigation Controller

Select the Navigation Item under the Table View Controller, and in the Attributes Inspector type To Do List as the Title.

Navigation Item

Navigation Item

From the Object Library, drag a Bar Button Item to the right of the navigation bar on the Table View Controller. Select the Bar Button Item (which has a default value of “Item”) and in the Attributes Inspector, in the Identifier option, choose Add. This will change the button to the add symbol (+).

Bar Button Item

Bar Button Item

Select the Table View Controller, press control button and drag to View Controller like image below. We added a segue.

Segue

Segue

Name it MySegue in Show the Attributes Inspector > Identifier.

Storyboard Segue

Storyboard Segue

Result

Main.Storyboard

Main.Storyboard

Continue on next post, http://blog.revivalx.com/2015/08/12/develop-a-simple-ios-mobile-app-todolist-using-swift-part-2/.