| 1 | /** |
|---|
| 2 | * Process all input from the views and modifies the model. |
|---|
| 3 | **/ |
|---|
| 4 | package com.jeroenwijering.player { |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | import flash.display.MovieClip; |
|---|
| 8 | import flash.events.*; |
|---|
| 9 | import flash.net.*; |
|---|
| 10 | import com.jeroenwijering.events.*; |
|---|
| 11 | import com.jeroenwijering.player.*; |
|---|
| 12 | import com.jeroenwijering.utils.*; |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | public class Controller extends EventDispatcher { |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | /** Configuration object **/ |
|---|
| 19 | private var config:Object; |
|---|
| 20 | /** Reference to the skin; for stage event subscription. **/ |
|---|
| 21 | private var skin:MovieClip; |
|---|
| 22 | /** Object that manages the playlist. **/ |
|---|
| 23 | private var playlister:Playlister; |
|---|
| 24 | /** Reference to the player's model. **/ |
|---|
| 25 | private var model:Model; |
|---|
| 26 | /** Reference to the player's view. **/ |
|---|
| 27 | private var view:View; |
|---|
| 28 | /** object that povides randomization. **/ |
|---|
| 29 | private var randomizer:Randomizer; |
|---|
| 30 | /** save the state of the model. **/ |
|---|
| 31 | private var state:String; |
|---|
| 32 | |
|---|
| 33 | |
|---|
| 34 | /** Constructor, set up stage and playlist listeners. **/ |
|---|
| 35 | public function Controller(cfg:Object,skn:MovieClip) { |
|---|
| 36 | config = cfg; |
|---|
| 37 | skin = skn; |
|---|
| 38 | skin.stage.scaleMode = "noScale"; |
|---|
| 39 | skin.stage.align = "TL"; |
|---|
| 40 | skin.stage.addEventListener(Event.RESIZE,resizeHandler); |
|---|
| 41 | skin.stage.addEventListener(Event.FULLSCREEN,resizeHandler); |
|---|
| 42 | playlister = new Playlister(); |
|---|
| 43 | playlister.addEventListener(Event.COMPLETE,playlistHandler); |
|---|
| 44 | playlister.addEventListener(ErrorEvent.ERROR,errorHandler); |
|---|
| 45 | }; |
|---|
| 46 | |
|---|
| 47 | |
|---|
| 48 | /** Register view and model with controller, start loading playlist. **/ |
|---|
| 49 | public function start(mdl:Model,vie:View) { |
|---|
| 50 | model= mdl; |
|---|
| 51 | model.addEventListener(ModelEvent.STATE,stateHandler); |
|---|
| 52 | model.addEventListener(ModelEvent.META,metaHandler); |
|---|
| 53 | model.addEventListener(ModelEvent.TIME,metaHandler); |
|---|
| 54 | view = vie; |
|---|
| 55 | view.addEventListener(ViewEvent.CAPTION,captionHandler); |
|---|
| 56 | view.addEventListener(ViewEvent.FULLSCREEN,fullscreenHandler); |
|---|
| 57 | view.addEventListener(ViewEvent.ITEM,itemHandler); |
|---|
| 58 | view.addEventListener(ViewEvent.LINK,linkHandler); |
|---|
| 59 | view.addEventListener(ViewEvent.LOAD,loadHandler); |
|---|
| 60 | view.addEventListener(ViewEvent.MUTE,muteHandler); |
|---|
| 61 | view.addEventListener(ViewEvent.NEXT,nextHandler); |
|---|
| 62 | view.addEventListener(ViewEvent.PLAY,playHandler); |
|---|
| 63 | view.addEventListener(ViewEvent.PREV,prevHandler); |
|---|
| 64 | view.addEventListener(ViewEvent.QUALITY,qualityHandler); |
|---|
| 65 | view.addEventListener(ViewEvent.SEEK,seekHandler); |
|---|
| 66 | view.addEventListener(ViewEvent.STOP,stopHandler); |
|---|
| 67 | view.addEventListener(ViewEvent.VOLUME,volumeHandler); |
|---|
| 68 | resizeHandler(new Event(Event.RESIZE)); |
|---|
| 69 | playlister.load(config); |
|---|
| 70 | }; |
|---|
| 71 | |
|---|
| 72 | |
|---|
| 73 | /** Save new state of the dub/caption switches. **/ |
|---|
| 74 | private function captionHandler(evt:ViewEvent) { |
|---|
| 75 | if(evt.data.state && evt.data.state != config['caption']) { |
|---|
| 76 | config['caption'] = evt.data.state; |
|---|
| 77 | } else { |
|---|
| 78 | config['caption'] = !config['caption']; |
|---|
| 79 | } |
|---|
| 80 | Configger.saveCookie('caption',config['caption']); |
|---|
| 81 | dispatchEvent(new ControllerEvent(ControllerEvent.CAPTION,{state:config['caption']})); |
|---|
| 82 | }; |
|---|
| 83 | |
|---|
| 84 | |
|---|
| 85 | /** Catch errors dispatched by the playlister. **/ |
|---|
| 86 | private function errorHandler(evt:ErrorEvent) { |
|---|
| 87 | dispatchEvent(new ControllerEvent(ControllerEvent.ERROR,{message:evt.text})); |
|---|
| 88 | }; |
|---|
| 89 | |
|---|
| 90 | |
|---|
| 91 | /** Switch fullscreen state. **/ |
|---|
| 92 | private function fullscreenHandler(evt:ViewEvent) { |
|---|
| 93 | if(skin.stage.displayState == 'fullScreen') { |
|---|
| 94 | skin.stage.displayState = 'normal'; |
|---|
| 95 | } else { |
|---|
| 96 | skin.stage.displayState = 'fullScreen'; |
|---|
| 97 | } |
|---|
| 98 | }; |
|---|
| 99 | |
|---|
| 100 | |
|---|
| 101 | /** Jump to a userdefined item in the playlist. **/ |
|---|
| 102 | private function itemHandler(evt:ViewEvent) { |
|---|
| 103 | var itm = evt.data.index; |
|---|
| 104 | if (itm < 0) { |
|---|
| 105 | playItem(0); |
|---|
| 106 | } else if (itm > playlist.length-1) { |
|---|
| 107 | playItem(playlist.length-1); |
|---|
| 108 | } else if (!isNaN(itm)) { |
|---|
| 109 | playItem(itm); |
|---|
| 110 | } |
|---|
| 111 | }; |
|---|
| 112 | |
|---|
| 113 | |
|---|
| 114 | /** Jump to the link of a playlistitem. **/ |
|---|
| 115 | private function linkHandler(evt:ViewEvent) { |
|---|
| 116 | var itm = evt.data.index; |
|---|
| 117 | if (itm == undefined) { |
|---|
| 118 | itm = config['item']; |
|---|
| 119 | } |
|---|
| 120 | var lnk = playlist[itm]['link']; |
|---|
| 121 | if(lnk != undefined) { |
|---|
| 122 | navigateToURL(new URLRequest(lnk),config['linktarget']); |
|---|
| 123 | } |
|---|
| 124 | }; |
|---|
| 125 | |
|---|
| 126 | |
|---|
| 127 | /** Load a new playlist. **/ |
|---|
| 128 | private function loadHandler(evt:ViewEvent) { |
|---|
| 129 | try { |
|---|
| 130 | playlister.load(evt.data.object); |
|---|
| 131 | } catch (err:Error) { |
|---|
| 132 | dispatchEvent(new ControllerEvent(ControllerEvent.ERROR,{message:err.message})); |
|---|
| 133 | } |
|---|
| 134 | }; |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | |
|---|
| 138 | /** Update playlist item duration. **/ |
|---|
| 139 | private function metaHandler(evt:ModelEvent) { |
|---|
| 140 | if(evt.data.duration) { |
|---|
| 141 | var dur = Math.round(evt.data.duration*10)/10 |
|---|
| 142 | playlister.update(config['item'],'duration',dur); |
|---|
| 143 | } |
|---|
| 144 | }; |
|---|
| 145 | |
|---|
| 146 | |
|---|
| 147 | /** Save new state of the mute switch and send volume. **/ |
|---|
| 148 | private function muteHandler(evt:ViewEvent) { |
|---|
| 149 | if(evt.data.state) { |
|---|
| 150 | if(evt.data.state == config['mute']) { |
|---|
| 151 | return; |
|---|
| 152 | } else { |
|---|
| 153 | config['mute'] = evt.data.state; |
|---|
| 154 | } |
|---|
| 155 | } else { |
|---|
| 156 | config['mute'] = !config['mute']; |
|---|
| 157 | } |
|---|
| 158 | Configger.saveCookie('mute',config['mute']); |
|---|
| 159 | dispatchEvent(new ControllerEvent(ControllerEvent.MUTE,{state:config['mute']})); |
|---|
| 160 | }; |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | /** Jump to the next item in the playlist. **/ |
|---|
| 164 | private function nextHandler(evt:ViewEvent) { |
|---|
| 165 | if(config['shuffle'] == true) { |
|---|
| 166 | playItem(randomizer.pick()); |
|---|
| 167 | } else if (config['item'] == playlist.length - 1) { |
|---|
| 168 | playItem(0); |
|---|
| 169 | } else { |
|---|
| 170 | playItem(config['item']+1); |
|---|
| 171 | } |
|---|
| 172 | }; |
|---|
| 173 | |
|---|
| 174 | |
|---|
| 175 | /** change the playback state. **/ |
|---|
| 176 | private function playHandler(evt:ViewEvent) { |
|---|
| 177 | if(evt.data.state) { |
|---|
| 178 | dispatchEvent(new ControllerEvent(ControllerEvent.PLAY,{state:evt.data.state})); |
|---|
| 179 | } else if(state == ModelStates.PLAYING || state == ModelStates.BUFFERING) { |
|---|
| 180 | dispatchEvent(new ControllerEvent(ControllerEvent.PLAY,{state:false})); |
|---|
| 181 | } else { |
|---|
| 182 | dispatchEvent(new ControllerEvent(ControllerEvent.PLAY,{state:true})); |
|---|
| 183 | } |
|---|
| 184 | }; |
|---|
| 185 | |
|---|
| 186 | |
|---|
| 187 | /** Direct the model to play a new item. **/ |
|---|
| 188 | private function playItem(nbr:Number) { |
|---|
| 189 | if(config['item'] != nbr) { |
|---|
| 190 | config['item'] = nbr; |
|---|
| 191 | dispatchEvent(new ControllerEvent(ControllerEvent.ITEM,{index:config['item']})); |
|---|
| 192 | } |
|---|
| 193 | dispatchEvent(new ControllerEvent(ControllerEvent.PLAY,{state:true})); |
|---|
| 194 | }; |
|---|
| 195 | |
|---|
| 196 | |
|---|
| 197 | /** Manage playback state changes **/ |
|---|
| 198 | private function playlistHandler(evt:Event) { |
|---|
| 199 | dispatchEvent(new ControllerEvent(ControllerEvent.PLAYLIST,{playlist:playlist})); |
|---|
| 200 | if(config['shuffle'] == true) { |
|---|
| 201 | randomizer = new Randomizer(playlist.length); |
|---|
| 202 | config['item'] = randomizer.pick(); |
|---|
| 203 | } |
|---|
| 204 | dispatchEvent(new ControllerEvent(ControllerEvent.ITEM,{index:config['item']})); |
|---|
| 205 | if(config['autostart'] == true) { |
|---|
| 206 | dispatchEvent(new ControllerEvent(ControllerEvent.PLAY,{state:true})); |
|---|
| 207 | } |
|---|
| 208 | }; |
|---|
| 209 | |
|---|
| 210 | |
|---|
| 211 | /** Jump to the previous item in the playlist. **/ |
|---|
| 212 | private function prevHandler(evt:ViewEvent) { |
|---|
| 213 | if(config['shuffle'] == true) { |
|---|
| 214 | playItem(randomizer.back()); |
|---|
| 215 | } else if (config['item'] == 0) { |
|---|
| 216 | playItem(playlist.length-1); |
|---|
| 217 | } else { |
|---|
| 218 | playItem(config['item']-1); |
|---|
| 219 | } |
|---|
| 220 | }; |
|---|
| 221 | |
|---|
| 222 | |
|---|
| 223 | /** Switch playback quality. **/ |
|---|
| 224 | private function qualityHandler(evt:ViewEvent) { |
|---|
| 225 | if(evt.data.state && evt.data.state != config['quality']) { |
|---|
| 226 | config['quality'] = evt.data.state; |
|---|
| 227 | } else { |
|---|
| 228 | config['quality'] = !config['quality']; |
|---|
| 229 | } |
|---|
| 230 | Configger.saveCookie('quality',config['quality']); |
|---|
| 231 | dispatchEvent(new ControllerEvent(ControllerEvent.QUALITY,{state:config['quality']})); |
|---|
| 232 | }; |
|---|
| 233 | |
|---|
| 234 | |
|---|
| 235 | /** Forward a resizing of the stage. **/ |
|---|
| 236 | private function resizeHandler(evt:Event) { |
|---|
| 237 | var dat = { |
|---|
| 238 | height:skin.stage.stageHeight, |
|---|
| 239 | width:skin.stage.stageWidth, |
|---|
| 240 | fullscreen:false |
|---|
| 241 | }; |
|---|
| 242 | if(config['controlbar'] == 'bottom') { |
|---|
| 243 | dat.height -= config['controlbarsize']; |
|---|
| 244 | } |
|---|
| 245 | if(config['playlist'] == 'right') { |
|---|
| 246 | dat.width -= config['playlistsize']; |
|---|
| 247 | } else if(config['playlist'] == 'bottom') { |
|---|
| 248 | dat.height -= config['playlistsize']; |
|---|
| 249 | } |
|---|
| 250 | if(skin.stage.displayState == 'fullScreen') { |
|---|
| 251 | dat.fullscreen = true; |
|---|
| 252 | dat.height = skin.stage.stageHeight; |
|---|
| 253 | dat.width = skin.stage.stageWidth; |
|---|
| 254 | } |
|---|
| 255 | config['height'] = dat.height; |
|---|
| 256 | config['width'] = dat.width; |
|---|
| 257 | dispatchEvent(new ControllerEvent(ControllerEvent.RESIZE,dat)); |
|---|
| 258 | }; |
|---|
| 259 | |
|---|
| 260 | |
|---|
| 261 | /** Seek to a specific part in a mediafile. **/ |
|---|
| 262 | private function seekHandler(evt:ViewEvent) { |
|---|
| 263 | var pos = evt.data.position; |
|---|
| 264 | if(pos < 2) { pos = 0; } |
|---|
| 265 | if(playlist[config['item']]['duration'] > 0) { |
|---|
| 266 | dispatchEvent(new ControllerEvent(ControllerEvent.SEEK,{position:pos})); |
|---|
| 267 | } |
|---|
| 268 | }; |
|---|
| 269 | |
|---|
| 270 | |
|---|
| 271 | /** Stop all playback and bufering. **/ |
|---|
| 272 | private function stopHandler(evt:ViewEvent) { |
|---|
| 273 | dispatchEvent(new ControllerEvent(ControllerEvent.STOP)); |
|---|
| 274 | }; |
|---|
| 275 | |
|---|
| 276 | |
|---|
| 277 | /** Manage playback state changes **/ |
|---|
| 278 | private function stateHandler(evt:ModelEvent) { |
|---|
| 279 | state = evt.data.newstate; |
|---|
| 280 | if(evt.data.newstate == ModelStates.COMPLETED && (config['repeat'] == true || |
|---|
| 281 | (config['shuffle'] == true && randomizer.length > 0) || |
|---|
| 282 | (config['shuffle'] == false && config['item'] < playlist.length-1))) { |
|---|
| 283 | if(config['shuffle'] == true) { |
|---|
| 284 | playItem(randomizer.pick()); |
|---|
| 285 | } else if(config['item'] == playlist.length-1) { |
|---|
| 286 | playItem(0); |
|---|
| 287 | } else { |
|---|
| 288 | playItem(config['item']+1); |
|---|
| 289 | } |
|---|
| 290 | } |
|---|
| 291 | }; |
|---|
| 292 | |
|---|
| 293 | |
|---|
| 294 | /** Save new state of the mute switch and send volume. **/ |
|---|
| 295 | private function volumeHandler(evt:ViewEvent) { |
|---|
| 296 | var vol = evt.data.percentage; |
|---|
| 297 | if (vol < 1) { |
|---|
| 298 | muteHandler(new ViewEvent(ViewEvent.MUTE,{state:true})); |
|---|
| 299 | } else if (!isNaN(vol) && vol < 101) { |
|---|
| 300 | if(config['mute'] == true) { |
|---|
| 301 | muteHandler(new ViewEvent(ViewEvent.MUTE,{state:false})); |
|---|
| 302 | } |
|---|
| 303 | config['volume'] = vol; |
|---|
| 304 | Configger.saveCookie('volume',vol); |
|---|
| 305 | dispatchEvent(new ControllerEvent(ControllerEvent.VOLUME,{percentage:vol})); |
|---|
| 306 | } |
|---|
| 307 | }; |
|---|
| 308 | |
|---|
| 309 | |
|---|
| 310 | /** Getter for the playlist. **/ |
|---|
| 311 | public function get playlist():Array { |
|---|
| 312 | return playlister.playlist; |
|---|
| 313 | }; |
|---|
| 314 | |
|---|
| 315 | |
|---|
| 316 | } |
|---|
| 317 | |
|---|
| 318 | |
|---|
| 319 | } |
|---|