Advertisement
  1. Code
  2. Coding Fundamentals
  3. Game Development

Membuat Pencarian YouTube dan Memutar Gadget dengan PureMVC

Scroll to top
Read Time: 28 min

() translation by (you can also view the original English article)

Mengikuti tutorial saya tentang PureMVC dan API YouTube Player, saya pikir itu akan menjadi ide yang baik untuk menunjukkan kepada Anda cara menggunakan API GData YouTube untuk mencari dan memutar video. Jadi saya telah membuat sedikit tutorial yang menggabungkan keahlian PureMVC dan YouTube Player baru Anda ke dalam gadget pencarian dan putar yang bagus dan sederhana.




Sebelum kita mulai...

Ini adalah tutorial untuk Actionscripters menengah hingga mahir dan itu akan berguna jika Anda pertama kali membaca tutorial API PureMVC dan YouTube Player saya.

Langkah 1: Mengapa Menggunakan PureMVC?

Anda mungkin bertanya-tanya mengapa saya memilih menggunakan PureMVC. Yah, saya pikir itu hebat! Dan ini adalah alat hebat yang memungkinkan Anda untuk membuat sesuatu yang kecil dan kemudian mengembangkannya menjadi aplikasi besar - semuanya tentang skalabilitas. Jadi sementara kami membuat aplikasi ini, perlu dicatat bahwa ini dapat digunakan sebagai gadget untuk dimasukkan di beberapa tempat seperti iGoogle, blog, dan bahkan iklan gadget.

Langkah 2: Pengaturan

Jalankan IDE favorit Anda, entah itu Flex Builder, FDT, FlashDevelop, atau TextMate, dan buat proyek Actionscript baru. Kami juga akan membuat SWC jadi sangat berguna jika Anda memiliki salinan Flash (Anda dapat mengunduh jejak dari situs web Adobe).

Selain itu, kita akan menggunakan kelas TweenLite GreenSock dan tidak melupakan basis kode PureMVC.

Catatan: Dalam beberapa langkah pertama kami akan menyiapkan kerangka untuk PureMVC. Penjelasan tentang langkah pertama tersedia di tutorial PureMVC saya.

Langkah 3: Membuat Aplikasi Basis

Sama seperti dengan aplikasi PureMVC, kita perlu mengatur aplikasi dasar kami. Saya akan mulai dengan hanya membuat latar belakang sederhana untuk aplikasi dan kemudian menjalankan perintah start up di fasad, jadi buat file baru bernama 'App.as' dalam 'src /':

1
2
  	package 
3
		{
4
			import com.flashtuts.ApplicationFacade;
5
6
			import flash.display.GradientType;
7
			import flash.display.Sprite;
8
			import flash.geom.Matrix;
9
			import flash.text.Font;
10
11
			[SWF( width='600', height='400', frameRate='30', backgroundColor='#000000' )]
12
13
			public class App extends Sprite
14
			{	
15
				[Embed( systemFont='Arial', fontName='Arial', mimeType='application/x-font' )]
16
				private var arialFont:Class;
17
18
				public function App()
19
				{
20
					init();
21
				}
22
23
				private function init():void
24
				{
25
					var mat:Matrix = new Matrix();
26
					var bg:Sprite = new Sprite();
27
28
					mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );
29
30
					bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
31
					bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
32
					bg.graphics.endFill();
33
34
					addChild( bg );
35
36
					Font.registerFont( arialFont );
37
38
					ApplicationFacade.getInstance().startup( this );
39
				}
40
			}
41
		}

Langkah 4: Membuat Facade

Kami sekarang hanya membuat fasad, tidak ada yang istimewa, seperti fasad yang kami buat di tutorial PureMVC, jadi buat file baru bernama 'ApplicationFacade.as' di dalam 'src / com / flashtuts /':

1
2
		package com.flashtuts
3
		{	
4
			import com.flashtuts.controller.StartupCommand;
5
6
			import org.puremvc.as3.interfaces.IFacade;
7
			import org.puremvc.as3.patterns.facade.Facade;
8
			import org.puremvc.as3.patterns.observer.Notification;
9
10
			public class ApplicationFacade extends Facade implements IFacade
11
			{
12
				public static const NAME:String							= 'ApplicationFacade';
13
14
				public static const STARTUP:String						= NAME + 'StartUp';
15
16
				public static function getInstance():ApplicationFacade
17
				{
18
					return (instance ? instance : new ApplicationFacade()) as ApplicationFacade;
19
				}
20
21
				override protected function initializeController():void
22
				{
23
					super.initializeController();
24
25
					registerCommand( STARTUP, StartupCommand );
26
				}
27
28
				public function startup(stage:Object):void
29
				{
30
					sendNotification( STARTUP, stage );
31
				}
32
33
				override public function sendNotification(notificationName:String, body:Object=null, type:String=null):void
34
				{
35
					trace( 'Sent ' + notificationName );
36
37
					notifyObservers( new Notification( notificationName, body, type ) );
38
				}
39
			}
40
		}

Langkah 5: Membuat Perintah Startup

Sekarang kami akan membuat perintah startup kami dan memastikan bahwa kami mendaftarkan mediator proxy dan aplikasi kami. Buat file bernama 'StartupCommand.as' di 'src / com / flashtuts / controller /':

1
2
		package com.flashtuts.controller
3
		{
4
			import com.flashtuts.model.DataProxy;
5
			import com.flashtuts.view.ApplicationMediator;
6
7
			import org.puremvc.as3.interfaces.ICommand;
8
			import org.puremvc.as3.interfaces.INotification;
9
			import org.puremvc.as3.patterns.command.SimpleCommand;
10
11
			public class StartupCommand extends SimpleCommand implements ICommand
12
			{
13
				override public function execute(notification:INotification):void
14
				{
15
					facade.registerProxy( new DataProxy() );
16
17
					facade.registerMediator( new ApplicationMediator( notification.getBody() as App ) );
18
				}
19
			}
20
		}

Langkah 6: Membuat Proxy

Kami sekarang perlu mengatur proxy kami, jadi mari kita membuat file bernama 'DataProxy.as' di 'src / com / flashtuts / model /':

1
2
		package com.flashtuts.model
3
		{
4
			import com.flashtuts.model.vo.DataVO;
5
6
			import org.puremvc.as3.interfaces.IProxy;
7
			import org.puremvc.as3.patterns.proxy.Proxy;
8
9
			public class DataProxy extends Proxy implements IProxy
10
			{
11
				public static const NAME:String							= 'DataProxy';
12
13
				public function DataProxy()
14
				{
15
					super( NAME, new DataVO() );
16
				} new Proxy
17
18
				public function get vo():DataVO
19
				{
20
					return data as DataVO;
21
				}
22
			}
23
		}

Kami akan kembali ke proxy nanti di tutorial karena kami akan menggunakannya untuk memuat data dari GData dan menyimpannya di VO.

Langkah 7: Menciptakan VO

Kami akan menggunakan VO untuk menyimpan data dari kueri GData kami sehingga jika pengguna mencari kata kunci lebih dari sekali, kami hanya akan memuat data dari VO daripada membuat permintaan lain ke GData API. Buat file bernama 'DataVO.as' di 'src / com / flashtuts / model / vo /':

1
2
		package com.flashtuts.model.vo
3
		{
4
			import flash.utils.Dictionary;
5
6
			public class DataVO
7
			{
8
				public var gdataURL:String 								= 'http://gdata.youtube.com/feeds/api/videos?orderby=published&max-results=15&v=2&q=';			
9
				public var queryResults:Dictionary 						= new Dictionary();
10
			}
11
		}

Memiliki membaca cepat tentang dokumentasi API GData Anda akan melihat bahwa var 'gdataURL' menunjukkan bahwa kita akan mendapatkan 15 hasil dan kami telah membiarkan URL terbuka sehingga kami dapat menempatkan string kueri di bagian belakang URL permintaan.

Langkah 8: Membuat Mediator Aplikasi

Bagian akhir kerangka PureMVC kami adalah mediator aplikasi kami. Kami akan membuatnya dan kemudian mendapatkannya untuk mendaftar pandangan pertama dan mediator kami, 'ProgressView' dan 'ProgressViewMediator', jadi buat file bernama 'ProgressViewMediator.as' dalam 'src / com / flashtuts / view /':

1
2
		package com.flashtuts.view
3
		{
4
			import org.puremvc.as3.interfaces.IMediator;
5
			import org.puremvc.as3.interfaces.INotification;
6
			import org.puremvc.as3.patterns.mediator.Mediator;
7
8
			public class ApplicationMediator extends Mediator implements IMediator
9
			{
10
				public static const NAME:String							= 'ApplicationMediator';
11
12
				public function ApplicationMediator(viewComponent:Object=null)
13
				{
14
					super( NAME, viewComponent );
15
				}
16
17
				override public function onRegister():void
18
				{
19
					
20
				}
21
22
				override public function listNotificationInterests():Array
23
				{
24
					return [
25
					];
26
				}
27
28
				override public function handleNotification(notification:INotification):void
29
				{
30
					var name:String = notification.getName();
31
					var body:Object = notification.getBody();
32
33
					switch ( name )
34
					{
35
						
36
					}
37
				}
38
			}
39
		}

Langkah 9: Membuat Progress View kami

Kami hanya akan memulai dengan tampilan kemajuan yang serupa dengan yang kami buat di tutorial PureMVC, jadi buat file 'ProgressView.as' dalam 'src / com / flashtuts / view / component /':

1
2
		package com.flashtuts.view.component
3
		{
4
			import flash.display.Sprite;
5
6
			import gs.TweenLite;
7
8
			public class ProgressView extends Sprite
9
			{
10
				public static const NAME:String							= 'ProgressView';
11
12
				public static const SHOW:String							= NAME + 'Show';
13
				public static const HIDE:String							= NAME + 'Hide';
14
15
				private var asset:LoaderAsset;
16
17
				public function ProgressView()
18
				{
19
					init();
20
				}
21
22
				private function init():void
23
				{
24
					asset = new LoaderAsset();
25
26
					asset.stop();
27
					asset.x = 275;
28
					asset.y = 175;
29
30
					addChild( asset );
31
				}
32
33
				public function show():void
34
				{	
35
					asset.play();
36
37
					TweenLite.to( this, .5, { autoAlpha: 1 } );
38
				}
39
40
				public function hide():void
41
				{
42
					asset.stop();
43
44
					TweenLite.to( this, .5, { autoAlpha: 0 } );
45
				}
46
			}
47
		}

Anda akan melihat bahwa kami menggunakan kelas baru yang disebut 'LoaderAsset'. Ini, sebenarnya, adalah klip film yang akan kami buat di IDE Flash dan kemudian digunakan dalam tampilan kemajuan kami, bukan hanya menampilkan persentase.

Langkah 10: Membuat SWC

Jalankan Flash IDE (jika Anda tidak memiliki Flash IDE, Anda dapat mengunduh percobaan dari situs web Adobe) dan membuat file AS3 baru:

Sebelum melanjutkan, kita perlu memastikan Flash tahu bahwa kita ingin menargetkan Flash Player 9 dan bahwa kita mengekspor SWC, jadi pilih 'Flash Player 9' dari drop down di bagian atas dan centang kotak di sebelah 'Ekspor SWC 'di bawah judul' Pengaturan SWF ':

Sekarang kita akan membuat loader sederhana. Saya memilih untuk memilih yang berputar, tetapi terserah Anda apa yang Anda lakukan. Buat lingkaran dan buat lubang di dalamnya:

Setelah Anda menempatkan lubang di lingkaran Anda, terapkan gradien radial, pindahkan ke kanan lingkaran. Lalu salin setengah lingkaran, tempelkan di atas lingkaran saat ini dan terapkan isinya. Selesai Sekarang, hal berikutnya adalah membuatnya berputar, jadi mari buat tween:

Saya punya tween berjalan selama 15 frame, Anda dapat memiliki Anda cepat, yang sama atau lebih lambat. Sekarang kita cukup mengaturnya untuk memutar satu kali:

Hal terakhir yang harus dilakukan adalah membungkus ini semua dalam klip film. Setelah Anda selesai melakukannya, buka jendela properti untuk klip video itu dan atur untuk diekspor ke Actionscript:

Seperti yang Anda lihat, saya sudah menyebutnya 'LoaderAsset', nama tautan ini akan menjadi nama kelas yang akan Anda gunakan dalam tampilan Anda, jadi kembali ke 'ProgressView' kami. Pastikan Anda menambahkan aset Anda dengan cara yang sama dengan yang saya miliki di kelas:

1
2
		package com.flashtuts.view.component
3
		{
4
			import flash.display.Sprite;
5
6
			import gs.TweenLite;
7
8
			public class ProgressView extends Sprite
9
			{
10
				public static const NAME:String							= 'ProgressView';
11
12
				public static const SHOW:String							= NAME + 'Show';
13
				public static const HIDE:String							= NAME + 'Hide';
14
15
				private var asset:LoaderAsset;
16
17
				public function ProgressView()
18
				{
19
					init();
20
				}
21
22
				private function init():void
23
				{
24
					asset = new LoaderAsset();
25
26
					asset.stop();
27
					asset.x = 275;
28
					asset.y = 175;
29
30
					addChild( asset );
31
				}
32
33
				public function show():void
34
				{	
35
					asset.play();
36
37
					TweenLite.to( this, .5, { autoAlpha: 1 } );
38
				}
39
40
				public function hide():void
41
				{
42
					asset.stop();
43
44
					TweenLite.to( this, .5, { autoAlpha: 0 } );
45
				}
46
			}
47
		}

Langkah 11: Menyiapkan Mediator Tampilan Kemajuan

Mediator tampilan kemajuan kami akan serupa dengan yang kami buat dalam tutorial PureMVC dengan pengecualian bahwa tidak ada pembaruan karena kami hanya memiliki roda berputar daripada tanda persentase. Buat file 'ProgressViewMediator.as' di 'src / com / flashtuts / view /':

1
2
		package com.flashtuts.view
3
		{
4
			import com.flashtuts.view.component.ProgressView;
5
6
			import org.puremvc.as3.interfaces.IMediator;
7
			import org.puremvc.as3.interfaces.INotification;
8
			import org.puremvc.as3.patterns.mediator.Mediator;
9
10
			public class ProgressViewMediator extends Mediator implements IMediator
11
			{
12
				public static const NAME:String							= 'ProgressViewMediator';
13
14
				private var progressView:ProgressView;
15
16
				public function ProgressViewMediator(viewComponent:Object=null)
17
				{
18
					super( NAME, viewComponent );
19
				}
20
21
				override public function onRegister():void
22
				{
23
					progressView = new ProgressView();
24
25
					progressView.hide();
26
27
					viewComponent.addChild( progressView );
28
				}
29
30
				override public function listNotificationInterests():Array
31
				{
32
					return [
33
						ProgressView.SHOW,
34
						ProgressView.HIDE
35
					];
36
				}
37
38
				override public function handleNotification(notification:INotification):void
39
				{
40
					var name:String = notification.getName();
41
					var body:Object = notification.getBody();
42
43
					switch ( name )
44
					{
45
						case ProgressView.SHOW:
46
						progressView.show();
47
48
						break;
49
50
						case ProgressView.HIDE:
51
						progressView.hide();
52
53
						break;
54
					}
55
				}
56
			}
57
		}

Anda bebas menggunakan loader apa pun yang Anda inginkan, tetapi ada masalah dengan GData YouTube. Anda melihat ketika Flash Player melakukan panggilan, sebagian besar server mengirim panjang konten permintaan ke loader, sehingga memungkinkan Flash Player untuk mengetahui berapa banyak byte yang akan dimuat dan memungkinkan kami untuk mencari persentase. Namun, YouTube GData tampaknya tidak mengirim panjang konten ini dan setiap kali Anda mencoba untuk menentukan persentase, Flash Player menemukan dirinya membagi 'bytesLoaded' dengan nol. Malu.

Langkah 12: Membuat Tampilan Pencarian

Selanjutnya yang perlu kita lakukan adalah membuat tampilan pencarian kita. Ini akan berisi kotak pencarian di mana pengguna akan memasukkan permintaan mereka dan kemudian tombol untuk mereka untuk menekan yang menjalankan query. Selain itu, kami akan menggunakan pendengar acara di kotak pencarian sehingga jika pengguna menekan 'masukkan' permintaan masih akan dijalankan. Buat file bernama 'SearchView.as' dalam 'src / com / flashtuts / view / components /':

1
2
		package com.flashtuts.view.component
3
		{
4
			import flash.display.Sprite;
5
			import flash.events.DataEvent;
6
			import flash.events.FocusEvent;
7
			import flash.events.KeyboardEvent;
8
			import flash.events.MouseEvent;
9
			import flash.text.TextField;
10
			import flash.text.TextFieldAutoSize;
11
			import flash.text.TextFieldType;
12
			import flash.text.TextFormat;
13
			import flash.ui.Keyboard;
14
15
			import mx.utils.StringUtil;
16
17
			public class SearchView extends Sprite
18
			{
19
				public static const NAME:String							= 'SearchView';
20
21
				public static const SHOW:String							= NAME + 'Show';
22
				public static const HIDE:String							= NAME + 'Hide';
23
				public static const SEARCH_RUN:String					= NAME + 'SearchRun';
24
				public static const SEARCH_RESULTS:String				= NAME + 'SearchResults';
25
26
				public static const SEARCH_FIELD_STRING:String			= 'Keywords...';
27
28
				private var searchField:TextField;
29
30
				public function SearchView()
31
				{
32
					init();
33
				}
34
35
				private function init():void
36
				{
37
					var textFormat:TextFormat = new TextFormat();
38
					var boxBg:Sprite = new Sprite();
39
					var boxCopy:TextField = new TextField();
40
					var boxButton:Sprite = new ButtonAsset();
41
42
					textFormat.color = 0x000000;
43
					textFormat.font = 'Arial';
44
					textFormat.size = 10;
45
46
					boxBg.graphics.beginFill( 0xFFFFFF );
47
					boxBg.graphics.drawRoundRectComplex( 0, 0, 300, 35, 0, 0, 5, 5 );
48
					boxBg.graphics.endFill();
49
					boxBg.x = 150;
50
51
					addChild( boxBg );
52
53
					boxCopy.autoSize = TextFieldAutoSize.LEFT;
54
					boxCopy.defaultTextFormat = textFormat;
55
					boxCopy.embedFonts = true;
56
					boxCopy.text = 'Search for:';
57
					boxCopy.x = 10;
58
					boxCopy.y = ( boxBg.height / 2 ) - ( boxCopy.height / 2 );
59
60
					boxBg.addChild( boxCopy );
61
62
					searchField = new TextField();
63
64
					searchField.border = true;
65
					searchField.borderColor = 0x666666;
66
					searchField.defaultTextFormat = textFormat;
67
					searchField.embedFonts = true;
68
					searchField.multiline = false;
69
					searchField.text = SEARCH_FIELD_STRING;
70
					searchField.type = TextFieldType.INPUT;
71
					searchField.width = 185;
72
					searchField.height = 16;
73
					searchField.x = boxCopy.x + boxCopy.width + 10;
74
					searchField.y = ( boxBg.height / 2 ) - ( searchField.height / 2 );
75
76
					searchField.addEventListener( FocusEvent.FOCUS_IN, handleSearchFieldFocusIn );
77
					searchField.addEventListener( FocusEvent.FOCUS_OUT, handleSearchFieldFocusOut );
78
					searchField.addEventListener( KeyboardEvent.KEY_UP, handleSearchFieldKeyUp );
79
80
					boxBg.addChild( searchField );
81
82
					boxButton.buttonMode = true;
83
					boxButton.x = boxCopy.x + boxCopy.width + searchField.width + 20;
84
					boxButton.y = ( boxBg.height / 2 ) - ( boxButton.height / 2 );
85
86
					boxButton.addEventListener( MouseEvent.CLICK, searchRun );
87
88
					boxBg.addChild( boxButton );
89
				}
90
91
				private function handleSearchFieldFocusIn(e:FocusEvent):void
92
				{
93
					if ( searchField.text === SEARCH_FIELD_STRING )
94
					{
95
						searchField.text = '';
96
					}
97
				}
98
99
				private function handleSearchFieldFocusOut(e:FocusEvent):void
100
				{
101
					if ( StringUtil.trim( searchField.text ) == '' )
102
					{
103
						searchField.text = SEARCH_FIELD_STRING;
104
					}
105
				}
106
107
				private function handleSearchFieldKeyUp(e:KeyboardEvent):void
108
				{
109
					if ( e.keyCode === Keyboard.ENTER )
110
					{
111
						searchRun();
112
					}
113
				}
114
115
				private function searchRun(e:*=null):void
116
				{
117
					var query:String = StringUtil.trim( searchField.text );
118
119
					if ( query != '' && query != SEARCH_FIELD_STRING )
120
					{
121
						dispatchEvent( new DataEvent( SEARCH_RUN, true, false, query ) );
122
					}
123
				}
124
			}
125
		}

Kode ini seharusnya bukan hal baru untuk ActionScripter, tetapi ini cepat dijalankan: pertama kita mengatur format teks, kemudian membuat kotak latar belakang (saya menggunakan Sprite.drawRoundRectComplex () untuk menggambar kotak), saya kemudian mengatur label, buat kotak input teks dan kemudian impor aset dari SWC untuk tombol pencarian.

Seperti yang saya sebutkan sebelumnya, saya telah menambahkan pendengar acara ke kotak input teks dan ke tombol kirim. Ini berarti bahwa pengguna dapat menekan enter atau klik pada tombol submit untuk menjalankan query. Fungsi 'handleSearchFieldKeyUp ()' memeriksa untuk memastikan jika tombol enter telah dipukul, jika ada, kemudian menjalankan pencarian. Ini juga merupakan praktik yang baik untuk masalah kegunaan sebagai orang yang sering digunakan untuk memukul masuk daripada harus klik tombol.

Langkah 13: Membuat View Cari Mediator

Cari pemandangan mediator tidak memiliki terlalu banyak tidak seperti itu tidak mendengarkan peristiwa apapun, melainkan itu adalah mengirim mereka ke fasad. Kemudian, mulailah dengan membuat file bernama 'SearchViewMediator.as' dalam ' src/com/flashtuts/pemandangan /':

1
2
		package com.flashtuts.view
3
		{
4
			import com.flashtuts.view.component.SearchView;
5
6
			import flash.events.DataEvent;
7
8
			import org.puremvc.as3.interfaces.IMediator;
9
			import org.puremvc.as3.patterns.mediator.Mediator;
10
11
			public class SearchViewMediator extends Mediator implements IMediator
12
			{
13
				public static const NAME:String							= 'SearchViewMediator';
14
15
				private var searchView:SearchView;
16
17
				public function SearchViewMediator(viewComponent:Object=null)
18
				{
19
					super( NAME, viewComponent );
20
				}
21
22
				override public function onRegister():void
23
				{
24
					searchView = new SearchView();
25
26
					searchView.addEventListener( SearchView.SEARCH_RUN, sendEvent );
27
28
					viewComponent.addChild( searchView );
29
				}
30
31
				private function sendEvent(e:DataEvent):void
32
				{
33
					sendNotification( SearchView.SEARCH_RUN, { query: e.data } );
34
				}
35
			}
36
		}

Jika Anda melihat tampilan, Anda akan melihat bahwa itu akan pengiriman 'DataEvent' sampai dengan mediator. Dalam pengantara kita kita mendengarkan itu dan kemudian mengirim pemberitahuan ke fasad Anda. Pemberitahuan ini akan dijemput oleh perintah yang akan berinteraksi dengan proxy dan kemudian mengirim sebuah acara dengan hasil.

Kami telah mencapai tahap ketika pandangan kami akan mengirimkan permintaan kami untuk fasad, jadi kita sekarang perlu untuk membuat perintah untuk lulus query ini ke proxy kami dan kemudian memperbarui kode kita proxy. Ini kemudian akan menjalankan query, menyimpannya dalam VO, meneruskannya kembali ke mediator dan kemudian pandangan.

Langkah 14: Menciptakan perintah Data

Kita akan mulai dengan memperbarui fasad sehingga akan melewati pemberitahuan 'SearchView.SEARCH_RUN' perintah data kita. Membuka 'ApplicationFacade.as' dan tambahkan lain 'registerCommand' dalam fasad 'initializeController()' fungsi:

1
2
		package com.flashtuts
3
		{	
4
			import com.flashtuts.controller.DataCommand;
5
			import com.flashtuts.controller.StartupCommand;
6
			import com.flashtuts.view.component.SearchView;
7
8
			import org.puremvc.as3.interfaces.IFacade;
9
			import org.puremvc.as3.patterns.facade.Facade;
10
			import org.puremvc.as3.patterns.observer.Notification;
11
12
			public class ApplicationFacade extends Facade implements IFacade
13
			{
14
				public static const NAME:String							= 'ApplicationFacade';
15
16
				public static const STARTUP:String						= NAME + 'StartUp';
17
18
				public static function getInstance():ApplicationFacade
19
				{
20
					return (instance ? instance : new ApplicationFacade()) as ApplicationFacade;
21
				}
22
23
				override protected function initializeController():void
24
				{
25
					super.initializeController();
26
27
					registerCommand( STARTUP, StartupCommand );
28
29
					registerCommand( SearchView.SEARCH_RUN, DataCommand ); // < here!

30
				}
31
32
				public function startup(stage:Object):void
33
				{
34
					sendNotification( STARTUP, stage );
35
				}
36
37
				override public function sendNotification(notificationName:String, body:Object=null, type:String=null):void
38
				{
39
					trace( 'Sent ' + notificationName );
40
41
					notifyObservers( new Notification( notificationName, body, type ) );
42
				}
43
			}
44
		}

Sekarang kita perlu membuat file 'DataCommand.as' dalam ' src/com/flashtuts/controller /':

1
2
		package com.flashtuts.controller
3
		{
4
			import com.flashtuts.model.DataProxy;
5
			import com.flashtuts.view.component.SearchView;
6
7
			import org.puremvc.as3.interfaces.ICommand;
8
			import org.puremvc.as3.interfaces.INotification;
9
			import org.puremvc.as3.patterns.command.SimpleCommand;
10
11
			public class DataCommand extends SimpleCommand implements ICommand
12
			{
13
				override public function execute(notification:INotification):void
14
				{
15
					var name:String = notification.getName();
16
					var body:Object = notification.getBody();
17
18
					switch ( name )
19
					{
20
						case SearchView.SEARCH_RUN:
21
						proxy.searchRun( body.query );
22
23
						break;
24
					}
25
				}
26
27
				private function get proxy():DataProxy
28
				{
29
					return facade.retrieveProxy( DataProxy.NAME ) as DataProxy;
30
				}
31
			}
32
		}

Ini adalah controller yang cukup sederhana, itu adalah mendengarkan di satu pemberitahuan, kemudian hanya lewat ke proxy. Sekali lagi, kita referensi proxy menggunakan fungsi mendapatkan, ini berarti bahwa kita sedang menggunakan contoh fasad daripada kembali menyatakan proxy.

Langkah 15: Menyelesaikan Proxy

Sekarang bahwa gelembung pandangan kami atas acara untuk fasad dan fasad melewati perintah data kita, kita perlu kita proxy untuk melakukan pekerjaan kotor, jadi mari kita memuat beberapa XML.

Kecuali jika Anda bekerja dengan GData sebelum, it's worth dicatat bahwa XML melewati kembali dalam Atom format dan telah mendapat banyak namespaces di dalamnya. Di AS2 menggunakan namespaces adalah sedikit hack, seperti sisa bahasa, tetapi sekarang dalam AS3 ada dua cara:

  1. Cara yang tepat
    Ini adalah cara yang tepat, tetapi itu adalah rasa sakit di gelandangan karena Anda perlu menyatakan setiap namespace dalam AS3 sebelum loading dalam XML, seperti:
    1
    2
    				var rss:Namespace = new Namespace("http://purl.org/rss/1.0/");
    
    3
    				var rdf:Namespace = new Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
    
    4
    				var dc:Namespace  = new Namespace("http://purl.org/dc/elements/1.1/");
    

    Hanya kemudian Anda dapat mengakses variabel XML seperti:

    1
    2
    				var item:String = items[i].dc::date;
    

    Jadi Anda melihat bahwa Anda menaruh namespace yang dinyatakan dan titik dua (ini :) di depan tag tersebut / nama atribut. Hal ini mungkin terlihat menyakitkan - dan itu, tetapi Anda dapat menemukan informasi lebih lanjut di Adobe LiveDocs.

  2. Cara mudah
     Dengan cara ini jauh lebih mudah (dan bersantai kurasa) tapi mendapatkan pekerjaan dilakukan dan tidak berantakan atau hack. Namespace adalah hanya sebuah metode untuk mengasosiasikan Tag (atau atribut) untuk referensi URL, jadi misalnya GData referensi OpenSearch, YouTube dan Google sendiri skema dan banyak lagi. Cara mudah sekitar adalah menyatakan namespaces dan awalan mereka untuk tag / nama atribut, Anda cukup menambahkan asterisk (ini *) seperti:
    1
    2
    				var item:String = items[i].*::date;
    

    Mudah

Jadi sekarang kita mengerti bagaimana menangani XML kami mendapatkan kembali, mari kita pergi tentang menyelesaikan proxy. Peluncuran 'DataProxy.as' di ' src com/flashtuts/model /' dan di sini adalah kode untuk itu:

1
2
		package com.flashtuts.model
3
		{
4
			import com.flashtuts.model.vo.DataVO;
5
			import com.flashtuts.view.component.ProgressView;
6
			import com.flashtuts.view.component.SearchView;
7
8
			import flash.events.Event;
9
			import flash.events.ProgressEvent;
10
			import flash.net.URLLoader;
11
			import flash.net.URLRequest;
12
			import flash.utils.Dictionary;
13
14
			import org.puremvc.as3.interfaces.IProxy;
15
			import org.puremvc.as3.patterns.proxy.Proxy;
16
17
			public class DataProxy extends Proxy implements IProxy
18
			{
19
				public static const NAME:String							= 'DataProxy';
20
21
				private var queryDic:Dictionary = new Dictionary();
22
23
				public function DataProxy()
24
				{
25
					super( NAME, new DataVO() );
26
				}
27
28
				public function searchRun(query:String):void
29
				{
30
					if ( vo.queryResults[ query ] )
31
					{
32
						dataReady( query );
33
					}
34
					else
35
					{
36
						dataLoad( query );
37
					}
38
				}
39
40
				private function dataLoad(query:String):void
41
				{
42
					var request:URLRequest = new URLRequest( vo.gdataURL + query );
43
					var loader:URLLoader = new URLLoader();
44
45
					sendNotification( ProgressView.SHOW );
46
47
					queryDic[ loader ] = query;
48
49
					loader.addEventListener( Event.COMPLETE, handleSearchComplete );
50
51
					loader.load( request );
52
				}
53
54
				private function handleSearchComplete(e:Event):void
55
				{
56
					var data:XML = new XML( e.target.data );
57
58
					vo.queryResults[ queryDic[ e.target ] ] = data..*::entry;
59
60
					dataReady( queryDic[ e.target ] );
61
				}
62
63
				private function dataReady(query:String):void
64
				{
65
					sendNotification( SearchView.SEARCH_RESULTS, { entries: vo.queryResults[ query ] } );
66
67
					sendNotification( ProgressView.HIDE );
68
				}
69
70
				public function get vo():DataVO
71
				{
72
					return data as DataVO;
73
				}
74
			}
75
		}

Kami memulai dengan menciptakan fungsi umum bahwa perintah data kita akan memicu 'searchRun()'. Seperti yang Anda lihat menerima satu parameter, string permintaan:

1
2
		public function searchRun(query:String):void
3
		{
4
			if ( vo.queryResults[ query ] )
5
			{
6
				dataReady( query );
7
			}
8
			else
9
			{
10
				dataLoad( query );
11
			}
12
		}

Sekarang untuk membuat aplikasi berjalan lebih cepat. Saya menggunakan prinsip bahwa setelah query telah dijalankan, data yang disimpan dalam VO dan tidak perlu untuk kueri tersebut untuk menjalankan lagi. Jadi menggunakan kelas AS3's Dictionary, mampu memeriksa untuk melihat apakah hasilnya sudah di VO. Jika mereka tidak, kita perlu untuk mendapatkannya, atau mengirimkannya ke pengantara kita. Kami akan datang ke fungsi 'dataReady()' sedikit lebih bawah:

Jika query belum tetapi telah dijalankan, kita perlu memuat beberapa XML:

1
2
		private function dataLoad(query:String):void
3
		{
4
			var request:URLRequest = new URLRequest( vo.gdataURL + query );
5
			var loader:URLLoader = new URLLoader();
6
7
			sendNotification( ProgressView.SHOW );
8
9
			queryDic[ loader ] = query;
10
11
			loader.addEventListener( Event.COMPLETE, handleSearchComplete );
12
13
			loader.load( request );
14
		}
15
16
		private function handleSearchComplete(e:Event):void
17
		{
18
			var data:XML = new XML( e.target.data );
19
20
			vo.queryResults[ queryDic[ e.target ] ] = data..*::entry;
21
22
			dataReady( queryDic[ e.target ] );
23
		}

Anda akan melihat bahwa kita sedang suffixing query ke 'gdataURL' string disimpan dalam VO kami. Kami kemudian referensi string permintaan menggunakan proxy Kamus sehingga ketika data siap, kita dapat menyimpannya dalam VO di bawah kueri tersebut dan tidak perlu beban itu lagi. Kemudian kita menambahkan acara pendengar dan membuat panggilan. Setelah kami telah mendapat data kembali, kami mendapatkan permintaan dari kamus, menyimpannya dalam VO dan kemudian menjalankan 'dataReady()' fungsi:

1
2
		private function dataReady(query:String):void
3
		{
4
			sendNotification( SearchView.SEARCH_RESULTS, { entries: vo.queryResults[ query ] } );
5
6
			sendNotification( ProgressView.HIDE );
7
		}

Fungsi ini hanya mendapat entri dan mengirim pemberitahuan kembali ke fasad. Sekarang kita dapat menampilkan video kami.

Langkah 16: Membuat tampilan hasil

Setelah kita memiliki entri, hal ini kemudian mudah bagi kita untuk memuat thumbnail untuk entri tersebut dan menampilkan mereka di grid. Mari kita mulai dengan menciptakan sebuah file yang bernama 'ResultsView.as' dalam ' src/com/flashtuts/komponen /':

1
2
		package com.flashtuts.view.component
3
		{
4
			import flash.display.Loader;
5
			import flash.display.Sprite;
6
			import flash.events.DataEvent;
7
			import flash.events.MouseEvent;
8
			import flash.net.URLRequest;
9
			import flash.utils.Dictionary;
10
11
			public class ResultsView extends Sprite
12
			{
13
				public static const NAME:String							= 'ResultsView';
14
15
				public static const SHOW:String							= NAME + 'Show';
16
				public static const HIDE:String							= NAME + 'Hide';
17
				public static const CLICKED:String						= NAME + 'Clicked';
18
19
				private var idsDic:Dictionary							= new Dictionary();
20
				private var thumbnailHeight:Number						= 90;
21
				private var thumbnailSpacing:Number						= 10;
22
				private var thumbnailWidth:Number						= 100;
23
24
				public function buildThumbnails(entries:Object):void
25
				{
26
					var ix:Number = 0;
27
					var iy:Number = 0;
28
					var thumbnails:Sprite = new Sprite();
29
					var thumbnail:Sprite;
30
31
					if ( numChildren > 0 )  
32
		            {  
33
		                for ( var i:Number = 0; i < numChildren; i++ )  
34
		                {  
35
		                    removeChildAt( i );  
36
		                }
37
38
		                buildThumbnails( entries );
39
		            }
40
		            else
41
		            {
42
		            	for each ( var entry:XML in entries )
43
						{
44
							thumbnail = createThumbnail( entry );
45
46
							thumbnail.x = ( thumbnailWidth + thumbnailSpacing ) * ix;
47
							thumbnail.y = ( thumbnailHeight + thumbnailSpacing ) * iy;
48
49
							if ( ix > 3 )
50
							{
51
								ix = 0;
52
								iy++;
53
							}
54
							else
55
							{
56
								ix++;
57
							}
58
59
							thumbnails.addChild( thumbnail );
60
						}
61
62
						thumbnails.x = 25;
63
						thumbnails.y = 70;
64
65
						addChild( thumbnails );
66
		            }
67
				}
68
69
				private function createThumbnail(entry:XML):Sprite
70
				{
71
					var thumbnail:Sprite = new Sprite();
72
					var mask:Sprite = new Sprite();
73
					var request:URLRequest = new URLRequest( entry..*::thumbnail[ 0 ].@url.toString() );
74
					var loader:Loader = new Loader();
75
76
					idsDic[ thumbnail ] = entry..*::videoid.toString();
77
78
					mask.graphics.beginFill( 0x000000 );
79
					mask.graphics.drawRoundRect( 0, 0, thumbnailWidth, thumbnailHeight, 5, 5 );
80
					mask.graphics.endFill();
81
82
					thumbnail.addChild( mask );
83
84
					loader.load( request );
85
86
					thumbnail.addChild( loader );
87
88
					loader.mask = mask;
89
90
					thumbnail.buttonMode = true;
91
					thumbnail.mouseChildren = false;
92
93
					thumbnail.addEventListener( MouseEvent.CLICK, handleThumbnailClicked );
94
95
					return thumbnail;
96
				}
97
98
				private function handleThumbnailClicked(e:MouseEvent):void
99
				{
100
					dispatchEvent( new DataEvent( CLICKED, true, false, idsDic[ e.target ] ) );
101
				}
102
			}
103
		}

Ini adalah hanya sebuah kelas yang hanya membutuhkan id video YouTube dan kemudian beban thumbnail sesuai. Pertama-tama kita mulai dengan menghapus semua anak pandangan dan ketika itu selesai kami menjalankan melalui loop yang kemudian beban thumbnail, masker (sehingga kami memiliki bagus lengkung) dan menambahkan pendengar acara ke sprite. Anda akan melihat bahwa saya menggunakan Kamus lagi di sini disebut 'idsDic'. Ini hanya akan menyimpan referensi sprite yang ditambahkan ke panggung sehingga ketika telah diklik pada, kita tahu id video YouTube terkait untuk memuat.

Akhirnya Anda akan melihat bahwa kelas satu 'DataEvent' yang berisi nomor video kembali untuk mediator yang.

Langkah 17: Menciptakan Mediator Lihat hasil

Mediator ini akan memiliki dua pekerjaan sederhana:

  1. Untuk (re-) membangun thumbnail ketika query telah dijalankan
  2. Untuk lulus nomor video ke pemutar YouTube kami

Jadi mari kita mulai dengan membuat file 'ResultsViewMediator.as' dalam ' src/com/flashtuts/pemandangan /':

1
2
		package com.flashtuts.view
3
		{
4
			import com.flashtuts.view.component.PlayerView;
5
			import com.flashtuts.view.component.ResultsView;
6
			import com.flashtuts.view.component.SearchView;
7
8
			import flash.events.DataEvent;
9
10
			import org.puremvc.as3.interfaces.IMediator;
11
			import org.puremvc.as3.interfaces.INotification;
12
			import org.puremvc.as3.patterns.mediator.Mediator;
13
14
			public class ResultsViewMediator extends Mediator implements IMediator
15
			{
16
				public static const NAME:String							= 'ResultsViewMediator';
17
18
				private var resultsView:ResultsView;
19
20
				public function ResultsViewMediator(viewComponent:Object=null)
21
				{
22
					super( NAME, viewComponent );
23
				}
24
25
				override public function onRegister():void
26
				{
27
					resultsView = new ResultsView();
28
29
					resultsView.addEventListener( ResultsView.CLICKED, sendEvent );
30
31
					viewComponent.addChild( resultsView );
32
				}
33
34
				override public function listNotificationInterests():Array
35
				{
36
					return [
37
						SearchView.SEARCH_RESULTS
38
					];
39
				}
40
41
				override public function handleNotification(notification:INotification):void
42
				{
43
					var name:String = notification.getName();
44
					var body:Object = notification.getBody();
45
46
					switch ( name )
47
					{
48
						case SearchView.SEARCH_RESULTS:
49
						resultsView.buildThumbnails( body.entries );				
50
51
						break;
52
					}
53
				}
54
55
				private function sendEvent(e:DataEvent):void
56
				{
57
					sendNotification( PlayerView.PLAY, { videoId: e.data } );
58
				}
59
			}
60
		}

Seperti saya katakan sebelumnya, mediator ini didengarkan 'SearchView.SEARCH_RESULTS' (Dikirim oleh proxy) dan mengirimkan 'PlayerView.PLAY' setelah thumbnail telah dibuat. Sekarang kita bisa untuk menciptakan tampilan pemain yang akan rumah pemutar YouTube.

Langkah 18: Membuat tampilan pemain

Sebelum Anda memulai dengan ini, Anda harus benar-benar membaca tentang YouTube Player API tutorial saya menulis seperti yang kita akan menggunakan itu di sini. Dalam tutorial yang kami menciptakan satu set kelas dan bungkus pemain. Sekarang salin pembungkus pemain itu dan paste di untuk ' aset/src/swf /'. Untuk kelas kami, aku telah menempatkan mereka dalam sebuah direktori reusable sederhana yang disebut ' src/com/flashtuts/lib /', karena itu aku punya kelas 'YouTubePlayer.as' di ' src/com/flashtuts/lib/tampilan /' dan 'YouTubePlayerEvent.as' dalam ' src/com/flashtuts/lib/peristiwa /'. Ini akan berarti bahwa Anda dapat dengan mudah kembali kelas-kelas ini waktu dan waktu lagi.

Setelah Anda senang dengan lokasi kelas pemutar YouTube Anda, kami akan mulai dengan pandangan pemain, jadi Buat sebuah file baru yang disebut 'PlayerView.as' dalam ' src/com/flashtuts/pemandangan/komponen /':

1
2
		package com.flashtuts.view.component
3
		{
4
			import com.flashtuts.lib.display.YouTubePlayer;
5
6
			import flash.display.Sprite;
7
			import flash.events.MouseEvent;
8
			import flash.filters.GlowFilter;
9
10
			public class PlayerView extends Sprite
11
			{
12
				public static const NAME:String							= 'PlayerView';
13
14
				public static const PLAY:String							= NAME + 'Play';
15
				public static const CLOSE:String						= NAME + 'Close';
16
17
				private var player:YouTubePlayer;
18
19
				public function PlayerView()
20
				{
21
					init();
22
				}
23
24
				private function init():void
25
				{
26
					var bg:Sprite = new Sprite();
27
					var closeButton:CloseButtonAsset = new CloseButtonAsset();
28
29
					bg.graphics.beginFill( 0x000000, .8 );
30
					bg.graphics.drawRect( 0, 0, 600, 400 );
31
					bg.graphics.endFill();
32
33
					addChild( bg ); 
34
35
					player = new YouTubePlayer();
36
37
					player.autoPlay = true;
38
					player.playerWidth = 550;
39
					player.playerHeight = 350;
40
					player.x = 25;
41
					player.y = 25;
42
43
					addChild( player );
44
45
					closeButton.buttonMode = true;
46
					closeButton.filters = [ new GlowFilter( 0x000000, 1, 10, 10 ) ];
47
					closeButton.x = 560;
48
					closeButton.y = 15;
49
50
					closeButton.addEventListener( MouseEvent.CLICK, close );
51
52
					addChild( closeButton );
53
54
					visible = false;
55
				}
56
57
				public function play(videoId:String):void
58
				{			
59
					player.init( videoId );
60
61
					visible = true;
62
				}
63
64
				public function close(e:*=null):void
65
				{
66
					player.stop();
67
68
					visible = false;
69
				}
70
			}
71
		}

Seperti yang Anda lihat, saya mulai dengan menciptakan pemutar YouTube, Semua dalam 'init ()' fungsi dan meninggalkan kelas untuk menjadi tak terlihat. Saya juga telah menggunakan aset SWC lain yang disebut 'CloseButtonAsset'. Kemudian kita memiliki dua fungsi utama kami 'play()' dan 'stop()' dan mereka melakukan persis apa yang tertulis di kaleng.

Sekarang bahwa kami senang dengan pandangan pemain kita, kita bisa mendapatkan dengan mediator.

Langkah 19: Membuat pemain View Mediator

Lagi mediator ini tidak akan sebagai kompleks seperti yang Anda mungkin berpikir. Itu akan lakukan adalah mendengarkan pemberitahuan 'PlayerView.PLAY' dan menunjukkan pemain:

1
2
		package com.flashtuts.view
3
		{
4
			import com.flashtuts.view.component.PlayerView;
5
6
			import org.puremvc.as3.interfaces.IMediator;
7
			import org.puremvc.as3.interfaces.INotification;
8
			import org.puremvc.as3.patterns.mediator.Mediator;
9
10
			public class PlayerViewMediator extends Mediator implements IMediator
11
			{
12
				public static const NAME:String							= 'PlayerViewMediator';
13
14
				private var playerView:PlayerView;
15
16
				public function PlayerViewMediator(viewComponent:Object=null)
17
				{
18
					super( NAME, viewComponent );
19
				}
20
21
				override public function onRegister():void
22
				{
23
					playerView = new PlayerView();
24
25
					viewComponent.addChild( playerView );
26
				}
27
28
				override public function listNotificationInterests():Array
29
				{
30
					return [
31
						PlayerView.PLAY
32
					];
33
				}
34
35
				override public function handleNotification(notification:INotification):void
36
				{
37
					var name:String = notification.getName();
38
					var body:Object = notification.getBody();
39
40
					switch ( name )
41
					{
42
						case PlayerView.PLAY:
43
						playerView.play( body.videoId );
44
45
						break;
46
					}
47
				}
48
			}
49
		}

Langkah 20: Menunda dapat mediator

Kita berada hampir di akhir, tetapi jika Anda telah membayar perhatian Anda akan melihat bahwa kita belum belum ditambahkan hasil Lihat mediator atau mediator Lihat pemain ke kita aplikasi yang belum. Hal ini karena mereka tidak dibutuhkan pada awal aplikasi, misalnya, hasil Lihat mediator hanya diperlukan setelah query sedang dijalankan dan mediator Lihat pemain hanya diperlukan setelah hasil dalam dan siap untuk mengklik. Mediator aplikasi kami akan mengontrol semua ini, peluncuran 'ApplicationMediator.as' - kami akan memperbarui 'listNotificationInterests()' dan 'handleNotification()' fungsi seperti sehingga:

1
2
		package com.flashtuts.view
3
		{
4
			import com.flashtuts.view.component.SearchView;
5
6
			import org.puremvc.as3.interfaces.IMediator;
7
			import org.puremvc.as3.interfaces.INotification;
8
			import org.puremvc.as3.patterns.mediator.Mediator;
9
10
			public class ApplicationMediator extends Mediator implements IMediator
11
			{
12
				public static const NAME:String							= 'ApplicationMediator';
13
14
				public function ApplicationMediator(viewComponent:Object=null)
15
				{
16
					super( NAME, viewComponent );
17
				}
18
19
				override public function onRegister():void
20
				{
21
					facade.registerMediator( new ProgressViewMediator( viewComponent ) );
22
					facade.registerMediator( new SearchViewMediator( viewComponent ) );
23
				}
24
25
				override public function listNotificationInterests():Array
26
				{
27
					return [
28
						SearchView.SEARCH_RUN,
29
						SearchView.SEARCH_RESULTS
30
					];
31
				}
32
33
				override public function handleNotification(notification:INotification):void
34
				{
35
					var name:String = notification.getName();
36
					var body:Object = notification.getBody();
37
38
					switch ( name )
39
					{
40
						case SearchView.SEARCH_RUN:
41
						if ( !facade.hasMediator( ResultsViewMediator.NAME ) )
42
						{
43
							facade.registerMediator( new ResultsViewMediator( viewComponent ) );
44
						}
45
46
						break;
47
48
						case SearchView.SEARCH_RESULTS:
49
						if ( !facade.hasMediator( PlayerViewMediator.NAME ) )
50
						{
51
							facade.registerMediator( new PlayerViewMediator( viewComponent ) );
52
						}
53
54
						break;
55
					}
56
				}
57
			}
58
		}

Anda akan melihat bahwa kita hanya sedang mendaftarkan mediator pada titik tertentu selama interaksi pengguna dengan aplikasi.

Dan kita telah melakukannya! Jalankan aplikasi dan mari kita...

Kesimpulan

Jadi di sana Anda memilikinya. Menggunakan kelincahan PureMVC dan YouTube Player API tutorial Anda sekarang dapat memperluas aplikasi kecil untuk melakukan banyak hal atau mengintegrasikan kode ke situs web atau aplikasi besar. Bantuan terbesar adalah layanan Google GData API, sejak mereka telah mendorongnya ke YouTube, query layanan telah menjadi lebih mudah dan lebih mudah. It's worth memiliki membaca dokumentasi GData karena ada banyak hal yang dapat dilakukan dengan produk Google, meng-upload video ke YouTube, menggunakan Picasa api dan api kalender.

Terima kasih untuk mengikuti sepanjang.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.