HP – What the hell happened there?

For us webOS developers, it’s been a roller-coaster over the last month or so. You’d have thought that HP would have committed to it’s devices having paid $1.6bn for webOS, but who knows anything in today’s world. Suffice to say, it has been the source of much merriment to my iOS friends. Ah whatever, webOS is still around and is still a fantastic place to start learning mobile dev. I’ve learned a lot, and am continuing to do so. My original Pre is still going strong (just a new battery) and it’s still a great bit of kit.

With the ditching of the new Pre3 (1 month from upgrade time), I decided to jump on the band wagon of desperados looking for the cut price Touchpads. Currys, Comet, Amazon, PC World, Currys again, Comet again, Argos. All no such luck. Time for Plan B – ebay. I managed to pick uo a 16gb model for £185. Do I consider myself lucky? To be honest, yes. I wanted one for dev purposes, not to sell on ebay and double my money. Looking at the long term, it was still half the price of the original retail price and a fantastic piece of kit (in fact, this document has been created using OpenOffice on the Touchpad).

One sideline of this, is the blog name is a bit crap now. Yes, I’m still continuing Palm Pre dev, but I’ll also be moving into the Touchpad dev. It’s the same problem that PreCentral have, so if they’re ok with it, then I’ll be fine.

So, what’s next?

Where to start is a good place? So far, I’ve 3 apps on the App Catalog (4 if you count a lite version as well), and the simplest thing will be to convert one of these.

QuickMessage is a pointless exercise being an SMS App. The first thing I released on the Pre, but it’ll serve no purpose on the Touchpad.

TaskMaster will be ideal. It’s a dynamic task app on the Pre, but being nearly a year in development and also being extremely complicated and inextricably bound to Mojo, it’ll be a nightmare for a first project, Let’s not forget that Mojo is sooooo last year and enyo is the future so this will have to wait. Not only that, there’s quite a few changes to the interface seeing as it will benefit from a bigger display. This will be done, just not yet.

So, that leaves Infection. This is the most recent app I’ve done. Having converted an old game from the Amiga to the Pre and being turn based, this would be an excellent place to start. Everyone loves games, right?

Visit Infection for more about the game.

 

Advertisements
Posted in enyo, HP TouchPad, Palm Pre Dev, WebOS | Leave a comment

Deleting Just Type entries from the HP Touchpad

If you’re one of those lucky ones who managed to grab a HP Touchpad before they dried up, you’ll be still trying to get to grips with it. The JustType facility is one such area, where it seems to be a fantastic idea, but with every website with a search engine popping up on the notification bar telling you to add this to your engines, it fills up a little too quick for my liking. Not only that, I don’t need every search site listed, and neither do I need it to go off looking though all of these.

Agreed, you can mark the site as inactive in the JustType settings but that doesn’t stop the list for growing ever large by the day.

For me, there are 2 areas which need clarifying.

  1. When you get alerted in the notification bar that a new search engine is available, you seem to have to accept it.
  2. When we have accepted it, how can we get rid of them?

Let’s start with the simple one first. Ignoring the alert in the first place. Those that have been with webOS from day one will know that swiping left or right is usually how you delete anything.

As I’m right handed, I tend to swipe left to remove anything, but this does not work. Swiping right DOES work though, and will immediately drop the notification.

Secondly, once you’ve added a search engine to Just Type, there is no swipe to delete functionality at all in the Just Type settings page. There is a hidden way of removing MOST of them though.

  • Open the web browser.
  • Open your preferences via the top left menu.
  • Delete your cache
  • Delete your history
  • Delete your cookies
  • Tap Done. That’s it.

Now, it doesn’t get rid of any of that are marked as active, and it doesn’t get rid of all the unselected ones. Right now, I’m unsure of the logic, but it’s a start.

I would like to take credit for this discovery, but I actually found this in a youtube video, so a massive über thanks to those guys.

http://www.youtube.com/watch?v=b8kBpS3nMpA

Posted in HP TouchPad, Swipe, WebOS | 1 Comment

webOS & a javaScript collection

Wow! It’s been a long time since I posted anything webOS related. In that time I’ve managed to get a couple of apps published – you can check them out here.

Quick Message (http://www.rahisi.co.uk/Product/QuickMessage)
TaskMaster (http://www.rahisi.co.uk/Product/TaskMaster)

Anyway, anything of interest? Yep, collections.

Whilst working on TaskMaster, I needed a collection class to wrap all the requirements up into one easy to manage class.
For example, one of the data sets includes a collection of people, and creating this via a javascript function gives a wrapper for managing them.

function person(name, title, age)
{
	this.name = name;
	this.title = title;
	this.age = age;
}

Putting these into a collection is easy enough using an array, but there’s a lot more functionality I could do with to manage these things easily enough.

What’s the basic functionality a collection needs?

  • Add ability
  • Delete
  • Count functionality

… and anything else that’ll make my life easier.

  • Sorting
  • Searching within the collection
  • A quick way to get data in and out of the depot.

OK, I’m going to dive straight in and not explain everything in intricate detail about how the thing works, so let’s start with the constructor. This is a standard javaScript function which contains a few properties including the underlying array (this.item).

function Collection(depot, dataName) {
	this.item = [];
	this.depot = depot;
	this.dataName = dataName;
};

Then add the basics for any collection. The Add function adds the new item to your collection and returns the new length.

Collection.prototype.Add = function(item){
	return this.item.push(item);
};

Count and length are the same functionality, but it makes it nice to be able to vary how the length is referenced. Coming from a .NET backgound, I prefer Count(), but either are allowed.

Collection.prototype.Count = function(){
	return this.item.length;
};

Collection.prototype.length = function(){
	return this.item.length;
};

Next I’ve added a range of delete functions. The first ,RemoveByIndex, will strip out an item at position [x] …

Collection.prototype.RemoveByIndex = function(index){
	if ((index>-1) && (index+1 <= this.item.length)){
		this.item.splice(index,1);
	}
};

… and RemoveByKey will remove an entry based on a property of the object. For example, delete the first entry where the age is 20. – collection.RemoveByKey(“age”,20);

Collection.prototype.RemoveByKey = function(keyname, keyvalue){
	var index =-1;
	for (var counter = 0; counter < this.item.length; counter++){
		if (this.item[counter][keyname] == keyvalue){
			index = counter;
			break;
		}
	}
	if (index > -1){
		this.RemoveByIndex(index);
	}
};

Clear immediately empties the contents of the collection…

Collection.prototype.Clear = function(){
	this.item = [];
}

… whereas Truncate will remove the last [x] number of items from the collection.

Collection.prototype.Truncate = function(limit){
	if((limit<0) || ( this.Count() <= limit)){
		return;
	}
	else{
		this.item.splice(limit);
	}
};

GetAll returns the underlying collection.

Collection.prototype.GetAll = function(){
	return this.item;
};

There are a number of functions to allow you to search the collection.
GetByKey() will return the first item that matches the key/value supplied [ e.g. item = collection.GetByKey(“age”,20) ]

Collection.prototype.GetByKey = function(keyname, keyvalue){
	var index =-1;
	for (var counter = 0; counter < this.item.length; counter++){
		if (this.item[counter][keyname] == keyvalue){
			index = counter;
			break;
		}
	}
	if (index > -1){
		return this.GetByIndex(index);
	}
	return null;
};

GetIndexByKey() will return the index of the first item that matches the key/value supplied [ e.g. itemIndex = collection.GetIndexByKey(“age”,20) ]

Collection.prototype.GetIndexByKey = function(keyname, keyvalue){
	var index =-1;
	for (var counter = 0; counter < this.item.length; counter++){
		if (this.item[counter][keyname] == keyvalue){
			index = counter;
			break;
		}
	}
	return index;
};

Finally, GetByIndex() will return an item at a specific index location. If you are outside of the range of the length of the collection, then null is returned.

Collection.prototype.GetByIndex = function(index){
	if ((index>-1) & (index+1 <= this.item.length)){
		return this.item[index];
	}
	return null;
};

Refresh provides a deep copy of the array from another source. It also allows the collection to be refreshed by passing itself in. The reason I added this was due to the fact I had issues updating a collection which has come from a data source in webOS. Any update to a collection populated straight from a DBSuccess call back didn’t update. Couldn’t figure this one out, but adding a refresh function to rebuild a list worked.

Collection.prototype.Refresh = function(source){
	this.Clear();
	if (source.length == 0){
		return;
	}
	var objectType = source[0].objectType;
	var objectClass = null;
	var objectInstance = null;
	var typeFound = false;
	if(objectType != "undefined"){
		objectClass = eval(objectType);
		typeFound = true;
	}
	for (var count = 0; count < source.length; count++)
	{
		if (typeFound){
			objectInstance = new objectClass(source[count]);
			this.Add( objectInstance);
		}
		else {
			this.Add( source[count] );
		}
	}
};

Sort will reorder the collection based on the key supplied (e.g. “age”), in either descending or ascending order. It is also possible to move all null values to the bottom of the collection. This uses the Swap function which is explained later.

Collection.prototype.Sort = function(keyname, order, nullsToBottom){
	if (this.Count() <2)
	{
		return;
	}
	if (typeof(keyname) == "string" )
	{
		keyname = new Array(keyname);
	}
	if (typeof(order) != "string" )
	{
		order = "asc";
	}
	if ((order != "asc") && (order != "desc"))
	{
		order = "asc";
	}
	var swapNeeded;
	for (var outerLoop = 0; outerLoop < this.Count(); outerLoop++)
	{
		for (var innerLoop = 0; innerLoop < outerLoop; innerLoop++)
		{
			if (innerLoop != outerLoop){

				swapNeeded = false;
				for (var keyCount = 0; keyCount< keyname.length; keyCount++)
				{
					if(( nullsToBottom ) &&
					   ((this.item[innerLoop][keyname[keyCount]] == null )&&
					   (this.item[outerLoop][keyname[keyCount]] !=null ))){
						swapNeeded = true;
						break;
					}
					if (order=="asc"){
						if (this.item[innerLoop][keyname[keyCount]] >
						    this.item[outerLoop][keyname[keyCount]]){
							swapNeeded = true;
							break;
						}
						else if (this.item[innerLoop][keyname[keyCount]]<
							 this.item[outerLoop][keyname[keyCount]]){
							break;
						}
					} else {
						if (this.item[innerLoop][keyname[keyCount]] <
						    this.item[outerLoop][keyname[keyCount]]){
							swapNeeded = true;
							break;
						}
						else if (this.item[innerLoop][keyname[keyCount]]>
							 this.item[outerLoop][keyname[keyCount]]){
							break;
						}
					}
				}
				if (swapNeeded){
					this.Swap(innerLoop, outerLoop);
				}
			}
		}
	}
	return;
};

Now for the additional stuff. Not necessary but the nice to haves. Update provides a quick way of updating a specific items property without actually accessing the item directly.
For example. collection.Update( collection.GetIndexByKey(“age”, 20″), “age”, 30); will update the first entry with an age of 20 to 30.

Collection.prototype.Update = function(index, field, value){
	this.item[index][field]=value;
};

Swap does exactly what it says.

Collection.prototype.Swap = function(index1, index2) {
	if ((index1 <= this.Count()) &&
	    (index2 <= this.Count())){

		var tempHold = this.item[index1];
		this.item[index1] = this.item[index2];
		this.item[index2] = tempHold;
	}
};

Finally, Save and Load provide quick access to the Depot.

Collection.prototype.Save = function(dbSuccess, dbFailure) {
	if ((this.depot) && (this.dataName))
	{
		this.depot.simpleAdd( this.dataName, this, dbSuccess, dbFailure);
	}
};

Collection.prototype.Load = function(dbSuccess, dbFailure) {
	if ((this.depot) && (this.dataName))
	{
		this.depot.get( this.dataName, dbSuccess, dbFailure);
	}
};

Although much of this functionality is already available in an array, I like to bring it all togther under an umbrella. If you feel this will be of use then feel free to use this and adapt it as necessary. It’s also worth noting there’s probaly a whole range of functionality that can still be added.

Posted in javascript, Palm Pre Dev, WebOS | Leave a comment

Palm Pre – Managing complex objects in the depot

Although the Pre comes with SQLite under the hood, if you just want to save small data items, it seems a bit of a long convoluted drawn out bore to start using the database. To make your life easier, Mojo has a ‘Depot’ object which will allow basic saving and retrieval of data. However, this comes at a price…
The bottom line – you can only store and retrieve simple objects.

This is not strictly true. Consider the following…

function Message(message){
this.key = message.key;
this.text = message.text;
this.name = "Message"+message.key;
this.objectType = "Message";
this.lastUsed = null;
};

This is a JavaScript message object I needed for ‘Quick Message’. Instantiation is done by passing in an anonymous type like so …

var newMessage = new Message( { key: “key1”, text: “message text”});

Technically, this is not a simple type, yet the depot will save and retrieve this quite happily. The problem will start when you either use a ‘Date’ object or start attaching functionality to the object using ‘prototype’.
Let’s start with the Date object. Without actual confirmation, I can’t say, but these aren’t stored in with the depot. Saving and retrieval of this won’t fail, you’ll just get null returned.

What about saving it as a string and converting it when needed?
As I need them quite a lot around the application, I need a more OO way of doing this. The Message object needs to be as ‘standalone’ as possible, so I can create one anywhere. I don’t want to have to create one or retrieve one, then keep calculating a date based on the string.

So, l left the original field in there and created a corresponding ‘DateString’ property as well.

function Message(message){
this.key = message.key;
this.text = message.text;
this.name = "Message"+message.key;
this.objectType = "Message";
this.lastUsed = null;
this.lastUsedDateString = "Not previously used";
};

Doing this will allow me to retrieve a date string in ‘lastUsedDateString’, then convert it how I want to when needed.

The final piece of functionality, is to determine if the anonymous type passed in contains a property called ‘lastUsedDateString’ and if so, assign it to our new object.

function Message(message){
this.key = message.key;
this.text = message.text;
this.name = "Message"+message.key;
this.objectType = "Message";
this.lastUsed = null;
this.lastUsedDateString = "Not previously used";
if (message.lastUsedDateString != undefined){
this.lastUsedDateString = message.lastUsedDateString;
}
};

This is still of no use when retrieving ‘Date’ type objects. So, I’ve extended the Message object using prototype to provide a method to populate the ‘lastUsed’ property using the ‘lastUsedDateString’ immediately.

Message.prototype.ReCalcDate = function(){
if ((this.lastUsed == null) && (this.lastUsedDateString != "Not previously used" )){
this.lastUsed = new Date(this.lastUsedDateString);
}
};

You think you had problems before with complex objects, you have now. Functions are most definitely not persisted using the depot.

This means that when you retrieve your Message for the Depot, the ‘lastUsedDataString’ is populated ok, but if you then tried …

testMessage.ReCalcDate();

…it would fail, because the depot will not support the function. At this point, it simply doesn’t exist.

There is, however a neat little way of getting around this. Remember the anonymous type I used to populate the message when created. Rather than using the response from the depot as the data, passing the data into a new message will provide enough information for the new Message objects to be created, populated with the data from the Depot, and any prototype methods will be available.

testMessage = new Message(testMessage);
testMessage.ReCalcDate();

As an added bonus, if we move the ReCalcDate() call into the object creation itself, it’ll always be done for us.

function Message(message){
this.key = message.key;
this.text = message.text;
this.name = "Message"+message.key;
this.objectType = "Message";
this.lastUsed = null;
this.lastUsedDateString = "Not previously used";
if (message.lastUsedDateString != undefined){
this.lastUsedDateString = message.lastUsedDateString;
}
this.ReCalcDate();
};

Of course, if you change either of lastUsed, or lastUsedDateString you’ll need to keep them in sync, but you don’t need me for that.

Posted in Depot, javascript, Palm Pre Dev, WebOS | 1 Comment

Palm Pre – Changing the swipe delete style

What’s wrong with this list?

Personally, I think it looks ok. Using the list is easy enough – tap the bottom to add a new entry, tap an entry to edit it, and swipe to delete. The first 2 are easy enough, and so is the delete option. All that is required is…

this.listModel = {
items: smsDataMessages.item
};
this.controller.setupWidget("lstMessages",
{
itemTemplate: "maintenance/msglistitems",
listTemplate: "maintenance/msglist",
addItemLabel: "Add New Message",
swipeToDelete: true,
renderLimit: 40,
reorderable: true
}, this.listModel );


Mojo.Event.listen(this.controller.get('lstMessages'),Mojo.Event.listAdd, this.btnAddClick.bind(this));
Mojo.Event.listen(this.controller.get('lstMessages'),Mojo.Event.listTap, this.lstMessagesClick.bind(this) );
Mojo.Event.listen(this.controller.get('lstMessages'),Mojo.Event.listDelete, this.lstDelete.bind(this) );

… which will set up the list on the scene complete with swipe functionality. When the swipe is invoked, the Mojo.Event.listDelete event is raised and the method “this.lstDelete” will fire. This method removes the entry from the list and quickly saves the new list in the depot.

Unfortunately, the built in markup and css is not suited to a list contained in a panel. This is what you get …

Removing the panel ensures it sits perfectly and the swipe section contains both delete options…

… but I don’t want that. I want my list to reside inside the panel. It looks neater and more professional.

So, we need to either render our list differently, or get inside the HTML & CSS and override it.

After a little digging around, I’ve found the underlying class names for the swipe to delete css.

  • palm-swipe-delete – controls the css definitions of the whole swipe-delete look and feel. You know, the grey area.
  • palm-swipe-delete-button – the main delete button.
  • palm-swipe-undo-button – the cancel button.

So, the next step is to implement out new styles into the css our app uses…


.palm-swipe-delete {
  width: 100%
}
.palm-swipe-delete-button,
.palm-swipe-undo-button
{
  width: 108px;
}
.palm-swipe-undo-button
{
  font-weight:bold;
}

The main swipe area is to be 100% of the parent container. This will force it to fit, which it did anyway.

Both buttons are to be 108 pixels wide, which means they will fit nicely. Finally, I’ve made the cancel button a bold text to highlight the seriousness of the operation. OK, so it’s just a list and not really serious, but you get the idea.

So, what are we looking like now?

And that, my fellow Palm Pre devvers is exactly what we require.

Note – The eagle eyed amongst you may have noticed the list has changed in the screen images. I decided to expand on what was displayed, which will be explained in another blog. This will also included formatters, which are not the most documented features of a list.

Posted in Lists, Palm Pre Dev, Swipe, WebOS | Leave a comment