Home  >  

User Info Component

Author photo
AddThis Social Bookmark Button
    Welcome back to the series. This time we are goings to build a really exciting component that will be used to simply display information about the user. Well, you might say why to we need such a component, is there are real purpose behind that? Well, in my opinion, yes. There are a lot of facebook applications out there done in Flash where we see information about the friends etc. During the process of facebook application development, there will always be a need to quickly display information about the specific friend. The information that is contained inside the component could be every bit of information that was entered by the user.
In our case, the component will do the following: It will display all the information that was entered by the facebook user, it will contain all the necessary information that is contained in http://wiki.developers.facebook.com/index.php/Users.getInfo. As we can see there are uid, about_me, activities, affiliations, type, college, high school, work, region, year, name, nid, status. So, in the process of development, there will be a need for us to quickly display this information. Some of them we will need to display, some of them will be needed to hide away.
The article will consist of 3 sections. The first section will talk about the back end and how to grad the information from facebook. The 2 section will deal with the functionality of the component and the display of data. The section will deal with all the stuff that is needed to display the actual that that was retrieved. The last section will deal with the look and feel of the displayed component. We will make sure that we can use different fonts, different colors. In short, the last section will handle the look of the front end.
Getting the data we want
Ok, in order to move on we need to set up the standard element we always work with. First we need an empty FLA, then we need the the api and the secret, then we need the facebook API. In the first few lines of code, we will load all the data that is needed and pass it to the component. So, open the FLA we worked on previously and clear all elements from the stage and code:

article13_img1.png
Ok, that's a familiar scenario for us. We don’t need anything from the previous article on the stage and we don’t need the code, we start from scratch.
Let’s get our api key and the secret from the FB Developer page. We need to create the session, here is the familiar code:

import com.facebook.data.users.GetInfoData;
import com.facebook.utils.FacebookSessionUtil;
import com.facebook.data.users.FacebookUser;
import com.facebook.data.users.GetInfoFieldValues;
import com.facebook.commands.users.GetInfo;
import com.facebook.net.FacebookCall;
import com.facebook.events.FacebookEvent;
import com.facebook.Facebook;

var fbook:Facebook;
var session:FacebookSessionUtil;

session = new FacebookSessionUtil("your_api_key","your_secret", loaderInfo);
fbook = session.facebook;
When we compile the swf, upload and run it, we should not see any errors. If there are few, please go back and fix them before we move on, we really don't want them to bother us later.
Displaying the data properly
The next thing we want to create is to create an component architecture and a MovieClip that will serve us as the basis for all upcoming features that will be added to the component. The idea is the same like for the previous samples. So in order to work with components, we need an empty MovieClip. So we go to Insert -> New Symbol…

article13_img2.png
Then in the dialog we type in the following:

article13_img3.png
As we can see from the screen above, the MovieClip needs to be named “UserInfo” and the class that the MovieClip is being linked to is facebookUI.UserInfo. From the previous samples we know that we link the classes from the facebookUI package to Symbols in the FLA. So now that we know where the class needs to be located, we need to create the class. Open your favorite text editor and paste the following code to it:

package facebookUI{
  
  	import fl.core.UIComponent;
  	import flash.text.*;
  	import com.facebook.data.users.GetInfoData;
  	import com.facebook.utils.FacebookSessionUtil;
  	import com.facebook.data.users.FacebookUser;
  	import com.facebook.data.users.GetInfoFieldValues;
  	import com.facebook.data.friends.*;
  	import com.facebook.commands.users.*;
  	import com.facebook.commands.friends.*;
  	import com.facebook.net.FacebookCall;
  	import com.facebook.events.FacebookEvent;
  	import com.facebook.Facebook;
  
  	public class UserInfo extends UIComponent{
    
  		private var _fBook:Facebook;
    
    		function UserInfo() {
      			
      		}
    
    		override protected function configUI():void {
      
        			super.configUI();
      
      		}
    
    		public function set session(f:Facebook):void{
   
      			_fBook = f;
   
      		}
  
  		public function get session():Facebook{
      			
      		
      		}
  
  		     public function set uid(u:Number):void{
      		   		_uid = u;
      		   }
  
  		   public function get uid():Number{
      	                  return _uid;
      		   }
  
   	 
    	}
  
}
Save this as „UserInfo.as“ in the facebookUI folder. So, now we are ready to do some neat stuff! Let's got back to the main timeline where we created our session:

import com.facebook.data.users.GetInfoData;
import com.facebook.utils.FacebookSessionUtil;
import com.facebook.data.users.FacebookUser;
import com.facebook.data.users.GetInfoFieldValues;
import com.facebook.commands.users.GetInfo;
import com.facebook.net.FacebookCall;
import com.facebook.events.FacebookEvent;
import com.facebook.Facebook;

var fbook:Facebook;
var session:FacebookSessionUtil;

session = new FacebookSessionUtil("your_api_key","your_secret", loaderInfo);
fbook = session.facebook;
We need to add the following code to make this work:

var userInfo = new UserInfo();
userInfo.uid = someFacebookUID;
userInfo.session = fbook;
That’s it! We gave the component a valid session and we can almost forget about the code on the main timeline. The rest will be coded inside the component!
Do you know about orthogonality in software development? We all know what orthogonality is but how does this apply to software development? Well, we just applied ortogonality to our application and it is a sign of good software engineering principles. The idea behind that lies that we need to have modules that can be extended but this modification does not have to affect the entire system. Controlling a helicopter is a sample of a non-ortogonal system. Why? Because every control unit is connected to each other and altering one of them control affects the whole helicopter. That is not what we want in software engineering, even not in facebook development. The line of code:

var userInfo = new UserInfo();
userInfo.uid = someFacebookUID;
userInfo.session = fbook;
where we pass the session to the UserInfo component, is a classical sample of an ortogonal system in programming. When we pass the session to the component, the component is a class of it's own and we can place so much code in there as we want. Inside the UserInfo component, we can write 2 lines of code, but we can also write 10 000 lines of code, without affecting the stability of the overall code!
Enough theory, let's get back to the component. Here is the code of the whole class:

package facebookUI{
  
  	import fl.core.UIComponent;
  	import flash.text.*;
  	import com.facebook.data.users.GetInfoData;
  	import com.facebook.utils.FacebookSessionUtil;
  	import com.facebook.data.users.FacebookUser;
  	import com.facebook.data.users.GetInfoFieldValues;
  	import com.facebook.data.friends.*;
  	import com.facebook.commands.users.*;
  	import com.facebook.commands.friends.*;
  	import com.facebook.net.FacebookCall;
  	import com.facebook.events.FacebookEvent;
  	import com.facebook.Facebook;
 
  	public class UserInfo extends UIComponent{
    
  		private var _fBook:Facebook;
  		private var _uid:Number;
    
    		function UserInfo() {
      			
      		}
    
    		override protected function configUI():void {
      
        			super.configUI();
      
      		}
  
    		public function set session(f:Facebook):void{
      			_fBook = f;
      		}
  
  		public function get session():Facebook{
      			
      		
      		}
  
  		   public function set uid(u:Number):void{
      		   		_uid = u;
      		   }
  
  		   public function get uid():Number{
      	                  return _uid;
      		   }
  
    	}
 
}   
As we can see, the session will be received inside the session setter:

public function set session(f:Facebook):void{
 	_fBook = f;
}
We need to modify the setter to start working on facebook. Inside the setter, place the following call:

public function set session(f:Facebook):void{
 	_fBook = f;
         loadData();
}
As we can see from the sample, there will be one method that will load the desired data, very simple. Here is how it looks like:

private function loadData():void{
 
 			var call:FacebookCall = new GetInfo([_uid], [GetInfoFieldValues.ALL_VALUES]);
 		 	call.addEventListener(FacebookEvent.COMPLETE, onDataLoaded);
 			_fBook.post(call);
 
}
The whole data will be received inside this method, because we defined it that way:

private function onDataLoaded(e:FacebookEvent):void{
 	
 	//facebook data loaded, now do some action
 
}
Cool, now we really don’t want to get confused and therefore we really know how the whole class looks like, here is the folder:

package facebookUI{
  
  	import fl.core.UIComponent;
  	import flash.text.*;
  	import com.facebook.data.users.GetInfoData;
  	import com.facebook.utils.FacebookSessionUtil;
  	import com.facebook.data.users.FacebookUser;
  	import com.facebook.data.users.GetInfoFieldValues;
  	import com.facebook.data.friends.*;
  	import com.facebook.commands.users.*;
  	import com.facebook.commands.friends.*;
  	import com.facebook.net.FacebookCall;
  	import com.facebook.events.FacebookEvent;
  	import com.facebook.Facebook;
  
  	public class UserInfo extends UIComponent{
    
  		private var _fBook:Facebook;
  		private var _uid:Number;
    
    		function UserInfo() {
      		}
    
    		override protected function configUI():void {
        			super.configUI();
      		}
  
  		private function loadData():void{
   
   			var call:FacebookCall = new GetInfo([_uid], [GetInfoFieldValues.ALL_VALUES]);
   		 	call.addEventListener(FacebookEvent.COMPLETE, onDataLoaded);
   			_fBook.post(call);
   
   		}
  
  
  		private function onDataLoaded(e:FacebookEvent):void{
   	
   			trace("data is loaded, we can play around...");
   
   		}
  
    
    		public function set session(f:Facebook):void{
      			_fBook = f;
   			loadData();
      		}
  
  		public function get session():Facebook{
      			return _fBook;
      		}
  
  		public function set uid(u:Number):void{
      			_uid = u;
      		}
  
  		public function get uid():Number{
      			return _uid;
      		}
   	 
    	}
 
}
So we got the data, we don't have to crawl the facebook databases for information. The next step is to display the data properly. Depends on what we want to display. So, what will be displayed?
We don’t want the component to be extra large, we want to display data only that we want. So it would be kind of nice to have a system where we simply pass an array of values and they get displayed. Please note that we will not attempt to display any images right now, because this component will be purely text based. Here is the code how it can be done:

public function set displayFields(f:Array):void {
 			_fields = f;
 		}

public function get displayFields():Array {
 	return _fields;
}
This way we store the array of fields we want to have displayed. Because we can’t display the data immediately (before the data is loaded from FB) we have to make sure the fields are store somewhere. Finally, the display method will do the job:

private function onDataLoaded(e:FacebookEvent):void{
 	
 	var userData = ((e.data as GetInfoData).userCollection).getItemAt(0);
 	var i = 0;
 	var len = _fields.length;
 
 	for(i = 0; i < len; i++){
  		var tField:TextField = new TextField();
  		this.addChild(tField);
  		var field = _fields[i];
  		tField.text = userData[field];
  		tField.y = tField.textHeight * i;
  	}
 
}
Back on the main TimeLine, we set the fields we want to be displayed:

userInfo.uid = someID;
userInfo.displayFields = ["first_name", "last_name", "about_me"];
userInfo.session = fbook;
And the result is:

article13_img4.png
Now we know this works. We have an array of fields:
userInfo.displayFields = ["first_name", "last_name", "about_me"];
that we want to display. You can experiment with other fields from the list found in http://wiki.developers.facebook.com/index.php/Users.getInfo. We can add as much fields as we want, all of the will be displayed properly below each other.
Working on the look and feel of the component
We completed the 2 stages and worked hard to load the data and display it, so now we need to work even harder to change the look and feel of the component. We don't want boring text fields that look like they where from the beginning of the internet, but we also don't want to add proprietary graphics that are hard to incorporate into the existing design. The idea behind all this is to make the component flexible so it fits right into all kinds of design. Let's say we have an application that deals with love relationships, we really want the data to appear in the right font and in the right font color. If we have to create a game that deals with robots, certainly we will use a technical font, choose a dark font color so all this fits right in place.
Take a look at those samples:

article13_img5.png

article13_img6.png
For this to happen, we need two component parameters that will be passed: the text size, text color and the text font. Those parameters can be added either at author time, or at run time, we will make both options available. So, let's add the two parameters in the existing class:


	//font size
	public function set fontSize(u:Number):void{
    		_fontFace = u;
    	}

	public function get fontSize():Number{
    		return _fontFace;
    	}

	//font color
	public function set fontColor(u:Number):void{
    		_fontColor = u;
    	}

	public function get fontColor():Number{
    		return _fontColor;
    	}

	//font face
	public function set fontFace(u:Number):void{
    		_fontFace = u;
    	}

	public function get fontFace():Number{
    		return _fontFace;
    	}
Let’s begin with the font face:


//font face
public function set fontFace(u:Number):void{
 	_fontFace = u;
}

public function get fontFace():Number{
   	return _fontFace;
}
Now, we need to modify the font as soon as the font is set, therefore we need the built-in invalidate() function that redraws the component. Remember the information from the article 6, where we discussed the component architecture, we need to utilize the existing structure of the component to fully take advantage of it. In our case, we need to override the draw function provided by UIComponent:


override protected function draw():void {
    
 	// always call super.draw() at the end
 	super.draw();
 
}
It’s best that we place the method right below the contructor, so the complete class now look like this:


package facebookUI{
  
  	import fl.core.UIComponent;
  	import flash.text.*;
  	import com.facebook.data.users.GetInfoData;
  	import com.facebook.utils.FacebookSessionUtil;
  	import com.facebook.data.users.FacebookUser;
  	import com.facebook.data.users.GetInfoFieldValues;
  	import com.facebook.data.friends.*;
  	import com.facebook.commands.users.*;
  	import com.facebook.commands.friends.*;
  	import com.facebook.net.FacebookCall;
  	import com.facebook.events.FacebookEvent;
  	import com.facebook.Facebook;
  
  	public class UserInfo extends UIComponent{
    
  		private var _fBook:Facebook;
  		private var _uid:Number;
  		private var _fields:Array;
  
  		private var _fontFace:String;
  		private var _fontColor:String;
  		private var _fontSize:String;
    
    		function UserInfo() {
      		}
    
    		override protected function configUI():void {
        			super.configUI();
      		}
  
  		private function loadData():void{
   
   			var call:FacebookCall = new GetInfo([_uid], [GetInfoFieldValues.ALL_VALUES]);
   		 	call.addEventListener(FacebookEvent.COMPLETE, onDataLoaded);
   			_fBook.post(call);
   
   		}
  
  		private function onDataLoaded(e:FacebookEvent):void{
   	
   			var userData = ((e.data as GetInfoData).userCollection).getItemAt(0);
   			var i = 0;
   			var len = _fields.length;
   
   			for(i = 0; i < len; i++){
    				var tField:TextField = new TextField();
    				this.addChild(tField);
    				var field = _fields[i];
    				tField.text = userData[field];
    				tField.y = tField.textHeight * i;
    			}
   
   		}
  
  		override protected function draw():void {
      
      		    // always call super.draw() at the end
      		    super.draw();
      
      		}	
  
  		//fields to display
  		public function set displayFields(f:Array):void {
   			_fields = f;
   		}
  
  		public function get displayFields():Array {
   			return _fields;
   		}
    
  		//session
    		public function set session(f:Facebook):void{
      			_fBook = f;
   			loadData();
      		}
  
  		public function get session():Facebook{
      			return _fBook;
      		}
  
  		//uid
  		public function set uid(u:Number):void{
      			_uid = u;
      		}
  
  		public function get uid():Number{
      			return _uid;
      		}
  
  		//font size
  		public function set fontSize(u:Number):void{
      			_fontFace = u;
      		}
  
  		public function get fontSize():Number{
      			return _fontFace;
      		}
  
  		//font color
  		public function set fontColor(u:Number):void{
      			_fontColor = u;
      		}
  
  		public function get fontColor():Number{
      			return _fontColor;
      		}
  
  		//font face
  		public function set fontFace(u:Number):void{
      			_fontFace = u;
      		}
  
  		public function get fontFace():Number{
      			return _fontFace;
      		}
  
    	}
 
} 
Let’s concentrate on the draw() method.

override protected function draw():void {
    
 	// always call super.draw() at the end
    	super.draw();
    
}	
Let's say, we set the font to something else:


//main timeline
var userInfo = new UserInfo();
this.addChild(userInfo);

userInfo.fontFace = "Century Gothic";
userInfo.fontColor = 0xff0000;
userInfo.fontSize = 33;
userInfo.uid = someFacebookUserID;
userInfo.displayFields = ["first_name", "last_name"];
userInfo.session = fbook;
Here is what needs to be added to the draw function:


override protected function draw():void {
    
 	var tf:TextFormat = new TextFormat();
 	tf.font = _fontFace;
 
 	var i = 0; 
 	var len = this.numChildren;
 
 	for(i = 0; i < len; i++){
  		var tField:TextField = this.getChildAt(i);
  		tField.setTextFormat(tf);
  	}
 
    	// always call super.draw() at the end
    	super.draw();
    
}	
And the uploaded result is:

article13_img7.png
Cool, now we have a nice way to access basic information of our friends in our applications and the component is flexible too. Before we finish, we will review the UserInfo class:


package facebookUI{
  
  	import fl.core.UIComponent;
  	import flash.text.*;
  	import com.facebook.data.users.GetInfoData;
  	import com.facebook.utils.FacebookSessionUtil;
  	import com.facebook.data.users.FacebookUser;
  	import com.facebook.data.users.GetInfoFieldValues;
  	import com.facebook.data.friends.*;
  	import com.facebook.commands.users.*;
  	import com.facebook.commands.friends.*;
  	import com.facebook.net.FacebookCall;
  	import com.facebook.events.FacebookEvent;
  	import com.facebook.Facebook;
  
  	public class UserInfo extends UIComponent{
  
  		private var _fBook:Facebook;
  		private var _uid:Number;
  		private var _fields:Array;
  
  		private var _fontFace:String;
  		private var _fontColor:Number;
  		private var _fontSize:Number;
    
    		function UserInfo() {
   			   		}
    
    		override protected function configUI():void {
        			super.configUI();
      		}
   
  		private function loadData():void{
   
   			var call:FacebookCall = new GetInfo([_uid], [GetInfoFieldValues.ALL_VALUES]);
   		 	call.addEventListener(FacebookEvent.COMPLETE, onDataLoaded);
   			_fBook.post(call);
   
   		}
   
  		private function onDataLoaded(e:FacebookEvent):void{
   	
   			var userData = ((e.data as GetInfoData).userCollection).getItemAt(0);
   			var i = 0;
   			var len = _fields.length;
   
   			for(i = 0; i < len; i++){
    				var tField:TextField = new TextField();
    				this.addChild(tField);
    				var field = _fields[i];
    				tField.text = userData[field];
    				tField.y = tField.textHeight * i;
    			}
   
   			invalidate();
   
   		}
  
  		override protected function draw():void {
      
   			var tf:TextFormat = new TextFormat();
   			tf.font = _fontFace;
   			tf.size = _fontSize;
   			tf.color = _fontColor;
   
   			var i = 0; 
   			var len = this.numChildren;
   
   			for(i = 0; i < len; i++){
    				var tField:TextField = this.getChildAt(i);
    				tField.setTextFormat(tf);	
    			}
   
   			for(i = 0; i < len; i++){
    				tField.width = tField.textWidth;
    				tField.height = tField.textHeight;
    				tField.y = tField.textHeight * i;	
    			}
   
      		    // always call super.draw() at the end
      		    super.draw();
      
      		}	
  
  		//fields to display
  		public function set displayFields(f:Array):void {
   			_fields = f;
   		}
  
  		public function get displayFields():Array {
   			return _fields;
   		}
    
  		//session
    		public function set session(f:Facebook):void{
      			_fBook = f;
   			loadData();
      		}
  
  		public function get session():Facebook{
      			return _fBook;
      		}
  
  		//uid
  		public function set uid(u:Number):void{
      			_uid = u;
      		}
  
  		public function get uid():Number{
      			return _uid;
      		}
  
  		//font size
  		public function set fontSize(u:Number):void{
      			_fontSize = u;
   			invalidate();
      		}
  
  		public function get fontSize():Number{
      			return _fontSize;
      		}
  
  		//font color
  		public function set fontColor(u:Number):void{
      			_fontColor = u;
   			invalidate();
      		}
  
  		public function get fontColor():Number{
      			return _fontColor;
      		}
  
  		//font face
  		public function set fontFace(u:String):void{
      			_fontFace = u;
   			invalidate();
      		}
  
  		public function get fontFace():String{
      			return _fontFace;
      		}
  
    	}
 
}

Read more from Mirza Hatipovic. Mirza Hatipovic's Atom feed mirzahat on Twitter

Comments

2 Comments

Dennis said:

Hi Mirza
Great tutorials - thank you very much. I have a small question regarding how to retrieve the location user-info.

In the context of your userinfo component how would i access the hometown_location / city?

I can access the location object but i cant seem to figure out how to obtain the children of that object.

Best regards

Marcos said:

Amazing tutorial!

I had some setbacks in implementing the draw functions, but identified the problem and was corrected, the fault loop!

Thanks,
Marcos from
controle de acesso

Leave a comment


Tag Cloud

Question of the Week: New Year

What are you most excited about for 2010?

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.