Index: SlimBrowserApplet.lua =================================================================== --- SlimBrowserApplet.lua (revision 1554) +++ SlimBrowserApplet.lua (working copy) @@ -25,7 +25,7 @@ local math = require("math") local table = require("jive.utils.table") local string = require("string") - + local Applet = require("jive.Applet") local AppletManager = require("jive.AppletManager") local Player = require("jive.slim.Player") @@ -47,14 +47,14 @@ local Checkbox = require("jive.ui.Checkbox") local SimpleMenu = require("jive.ui.SimpleMenu") local DateTime = require("jive.utils.datetime") - + local DB = require("applets.SlimBrowser.DB") local debug = require("jive.utils.debug") local log = require("jive.utils.log").logger("player.browse") local logd = require("jive.utils.log").logger("player.browse.data") - + local EVENT_KEY_ALL = jive.ui.EVENT_KEY_ALL local EVENT_KEY_DOWN = jive.ui.EVENT_KEY_DOWN local EVENT_KEY_UP = jive.ui.EVENT_KEY_UP @@ -129,7 +129,7 @@ --============================================================================== --- Forward declarations +-- Forward declarations local _newDestination local _actionHandler @@ -165,7 +165,7 @@ for i=1, select('#', ...) do local v = select(i, ...) -- log:debug(v) - if v then + if v then local res = v[key] if res then return res end end @@ -200,7 +200,7 @@ -- use gd file format to get the output direct from libgd without compression local artworkUri local resizeFrag = '_' .. size .. 'x' .. size .. '_p' -- 'p' is for padded - if thisIsAnId then + if thisIsAnId then -- we want a 56 pixel thumbnail if it wasn't specified artworkUri = '/music/' .. iconId .. '/cover' .. resizeFrag .. '.' .. imgFormat elseif string.match(iconId, '.png') then @@ -250,10 +250,10 @@ local new = volume + delta * volumeStep if new > 100 then new = 100 elseif new < 0 then new = 0 end - + volume = _player:volume(new) or volume slider:setValue(volume) - + popup:showBriefly() end @@ -272,12 +272,16 @@ local evtCode = event:getKeycode() -- we're only interested in volume keys + if evtCode & (KEY_VOLUME_UP | KEY_VOLUME_DOWN) == 0 then + return EVENT_UNUSED + end if evtCode == KEY_VOLUME_UP then vol = 1 elseif evtCode == KEY_VOLUME_DOWN then vol = -1 else - return EVENT_UNUSED + -- TODO: both pressed? should toggle mute? + vol = 0 end -- if timer is gone, don't do anything => the window is closing @@ -346,7 +350,7 @@ step.cancelled = true end) end - + step.loaded = function() if _curStep.menu then _curStep.menu:unlock() @@ -362,14 +366,14 @@ local function _newWindowSpec(db, item, titleStyle) if not titleStyle then titleStyle = '' end log:debug("_newWindowSpec()") - + local bWindow local iWindow = _safeDeref(item, 'window') if db then bWindow = _safeDeref(db:chunk(), 'base', 'window') end - + local help = _safeDeref(item, 'window', 'help', 'text') -- determine style @@ -383,7 +387,7 @@ ["text"] = _priorityAssign('text', item["text"], iWindow, bWindow), ["icon-id"] = _priorityAssign('icon-id', item["icon-id"], iWindow, bWindow), ["icon"] = _priorityAssign('icon', item["icon"], iWindow, bWindow), - } + } end -- _staticArtworkThumbUri @@ -418,7 +422,7 @@ -- Don't load artwork while accelerated _server:cancelArtwork(icon) else - + local remoteContent = string.find(item['icon'], 'http://') if remoteContent then -- Fetch a remote image URL, sized to 56x56 (artwork from a streamed source) @@ -454,10 +458,10 @@ log:debug("checkbox updated: ", checkboxFlag) if (checkboxFlag) then log:debug("ON: ", checkboxFlag) - _actionHandler(nil, nil, db, nil, nil, 'on', item) + _actionHandler(nil, nil, db, nil, nil, 'on', item) else log:debug("OFF: ", checkboxFlag) - _actionHandler(nil, nil, db, nil, nil, 'off', item) + _actionHandler(nil, nil, db, nil, nil, 'off', item) end end, checkboxFlag == 1 @@ -475,9 +479,9 @@ item["_jive_button"] = RadioButton( "radio", db:getRadioGroup(), - function() - log:warn('Callback has been called') - _actionHandler(nil, nil, db, nil, nil, 'do', item) + function() + log:warn('Callback has been called') + _actionHandler(nil, nil, db, nil, nil, 'do', item) end, radioFlag == 1 ) @@ -541,21 +545,21 @@ -- performs the JSON action... local function _performJSONAction(jsonAction, from, qty, sink) log:debug("_performJSONAction(from:", from, ", qty:", qty, "):") - + local cmdArray = jsonAction["cmd"] - + -- sanity check if not cmdArray or type(cmdArray) != 'table' then log:error("JSON action for ", actionName, " has no cmd or not of type table") return end - + -- replace player if needed local playerid = jsonAction["player"] if not playerid or tostring(playerid) == "0" then playerid = _player.id end - + -- look for __INPUT__ as a param value local params = jsonAction["params"] local newparams @@ -569,7 +573,7 @@ local _secondsFromMidnight = DateTime:secondsFromMidnight(_lastInput) log:debug("SECONDS FROM MIDNIGHT", _secondsFromMidnight) table.insert( newparams, k .. ":" .. _secondsFromMidnight ) - else + else table.insert( newparams, k .. ":" .. _lastInput ) end else @@ -577,22 +581,22 @@ end end end - + local request = {} - + for i, v in ipairs(cmdArray) do table.insert(request, v) end - + table.insert(request, from) table.insert(request, qty) - + if newparams then for i, v in ipairs(newparams) do table.insert(request, v) end end - + -- send the command _server:request(sink, playerid, request) end @@ -636,7 +640,7 @@ end ) - + popup:show() _connectingPopup = popup @@ -698,7 +702,7 @@ return end - -- function to perform when the data is loaded? + -- function to perform when the data is loaded? if step.loaded then step.loaded() step.loaded = nil @@ -706,14 +710,14 @@ if chunk then local data - + -- move result key up to top-level if chunk.result then data = chunk.result else data = chunk.data end - + if logd:isDebug() then debug.dump(chunk, 8) end @@ -727,12 +731,12 @@ -- what's missing? local from, qty = step.db:missing(step.menu:isAccelerated()) - + if from then _performJSONAction(step.data, from, qty, step.sink) end end - + else log:error(err) end @@ -811,7 +815,7 @@ end, selectedIndex ) - + item.icon = choice --add the item to the menu @@ -852,15 +856,15 @@ jsonAction ) from, qty = step.db:missing(step.menu and step.menu:isAccelerated()) - + jiveMain:lockItem(item, function() step.cancelled = true end) - + step.loaded = function() jiveMain:unlockItem(item) - + _curStep = step step.window:show() end @@ -902,7 +906,7 @@ -- sink that sets the data for our status window(s) local function _statusSink(step, chunk, err) log:debug("_statusSink()") - + -- currently we're not going anywhere with Now Playing... _assert(step == _statusStep) @@ -915,16 +919,16 @@ if logd:isDebug() then debug.dump(data, 8) end - + -- handle the case where the player disappears -- return silently if data.error then log:info("_statusSink() chunk has error: returning") return end - + -- FIXME: this can go away once we dispense of the upgrade messages - -- if we have a data.item_loop[1].text == 'READ ME', + -- if we have a data.item_loop[1].text == 'READ ME', -- we've hit the SC upgrade message and shouldn't be dropping it into NOW PLAYING if data.item_loop and data.item_loop[1].text == 'READ ME' then log:debug('This is not a message suitable for the Now Playing list') @@ -944,14 +948,14 @@ local _globalActions = { ["home"] = function() local windowStack = Framework.windowStack - + -- are we in home? if #windowStack > 1 then goHome() else _goNowPlaying() end - + return EVENT_CONSUME end, @@ -1013,9 +1017,9 @@ -- provides a function for each actionName for which Jive provides a default behaviour -- the function prototype is the same than _actionHandler (i.e. the whole shebang to cover all cases) local _defaultActions = { - + -- default commands in Now Playing - + ["play-status"] = function(_1, _2, _3, dbIndex) if _player:isPaused() and _player:isCurrent(dbIndex) then _player:togglePause() @@ -1049,17 +1053,17 @@ -- some actions work (f.e. pause) even with no item around if item then - + local chunk = db:chunk() local bAction local iAction local onAction local offAction - + -- special cases for go action: if actionName == 'go' then - - -- check first for a hierarchical menu or a input to perform + + -- check first for a hierarchical menu or a input to perform if item['count'] or (item['input'] and not item['_inputDone']) then log:debug("_actionHandler(", actionName, "): hierachical or input") @@ -1067,7 +1071,7 @@ -- make a new window local step, sink = _newDestination(_curStep, item, _newWindowSpec(db, item), _browseSink) - + _pushToNewWindow(step) -- the item is the data, wrapped into a result hash @@ -1078,7 +1082,7 @@ _browseSink(step, res) return EVENT_CONSUME end - + -- check for a 'do' action (overrides a straight 'go') -- actionName is corrected below!! bAction = _safeDeref(chunk, 'base', 'actions', 'do') @@ -1086,8 +1090,8 @@ onAction = _safeDeref(item, 'actions', 'on') offAction = _safeDeref(item, 'actions', 'off') end - - + + -- now check for a run-of-the mill action if not (iAction or bAction or onAction or offAction) then bAction = _safeDeref(chunk, 'base', 'actions', actionName) @@ -1097,39 +1101,39 @@ -- okay to call on or off this, as they are just special cases of 'do' actionName = 'do' end - + -- XXX: Fred: After an input box is used, chunk is nil, so base can't be used - + if iAction or bAction then - + -- the resulting action, if any local jsonAction - + -- process an item action first if iAction then log:debug("_actionHandler(", actionName, "): item action") - + -- found a json command if type(iAction) == 'table' then jsonAction = iAction end - + -- not item action, look for a base one elseif bAction then log:debug("_actionHandler(", actionName, "): base action") - + -- found a json command if type(bAction) == 'table' then - + jsonAction = bAction - + -- this guy may want to be completed by something in the item -- base gives the name of item key in key itemParams -- we're looking for item[base.itemParams] local paramName = jsonAction["itemsParams"] log:debug("..paramName:", paramName) if paramName then - + -- sanity check if type(paramName) != 'string' then log:error("Base action for ", actionName, " has itemParams field but not of type string!") @@ -1138,13 +1142,13 @@ local iParams = item[paramName] if iParams then - + -- sanity check, can't hurt if type(iParams) != 'table' then log:error("Base action for ", actionName, " has itemParams: ", paramName, " found in item but not of type table!") return EVENT_UNUSED end - + -- found 'em! -- add them to the command -- make sure the base has a params item! @@ -1163,7 +1167,7 @@ end end end -- elseif bAction - + -- now we may have found a command if jsonAction then log:debug("_actionHandler(", actionName, "): json action") @@ -1171,7 +1175,7 @@ if menuItem then menuItem:playSound("WINDOWSHOW") end - + -- set good or dummy sink as needed -- prepare the window if needed local step @@ -1192,18 +1196,18 @@ end _pushToNewWindow(step) - + -- send the command _performJSONAction(jsonAction, from, qty, sink) - + return EVENT_CONSUME end end end - + -- fallback to built-in -- these may work without an item - + -- Note the assumption here: event handling happens for front window only if _curStep.actionModifier then local builtInAction = actionName .. _curStep.actionModifier @@ -1214,13 +1218,13 @@ return func(menu, menuItem, db, dbIndex, event, builtInAction, item) end end - + local func = _defaultActions[actionName] if func then log:debug("_actionHandler(", actionName, "): built-in") return func(menu, menuItem, db, dbIndex, event, actionName, item) end - + -- no success here for this event return EVENT_UNUSED end @@ -1246,10 +1250,10 @@ -- map from a key to an actionName local _keycodeActionName = { - [KEY_VOLUME_UP] = 'volup', - [KEY_VOLUME_DOWN] = 'voldown', - [KEY_HOME] = 'home', - [KEY_PAUSE] = 'pause', + [KEY_VOLUME_UP] = 'volup', + [KEY_VOLUME_DOWN] = 'voldown', + [KEY_HOME] = 'home', + [KEY_PAUSE] = 'pause', [KEY_PLAY] = 'play', [KEY_FWD] = 'fwd', [KEY_REW] = 'rew', @@ -1259,7 +1263,7 @@ -- 'inputDone' -- _browseMenuListener --- called +-- called local function _browseMenuListener(menu, db, menuItem, dbIndex, event) -- ok so joe did press a key while in our menu... @@ -1276,7 +1280,7 @@ end log:debug("_browseMenuListener(", event:tostring(), ", " , index, ")") - + -- we don't care about events not on the current window -- assumption for event handling code: _curStep corresponds to current window! if _curStep.menu != menu then @@ -1285,7 +1289,7 @@ log:debug("Ignoring, not visible") return EVENT_UNUSED end - + -- we don't want to do anything if this menu item involves an active decoration -- like a radio, checkbox, or set of choices -- further, we want the event to propagate to the active widget, so return EVENT_UNUSED @@ -1294,11 +1298,11 @@ return EVENT_UNUSED end - + -- actions on button down if evtType == EVENT_ACTION then log:debug("_browseMenuListener: EVENT_ACTION") - + if item then -- check for a local action local func = item._go @@ -1307,23 +1311,23 @@ menuItem:playSound("WINDOWSHOW") return func() end - + -- otherwise, check for a handler return _actionHandler(menu, menuItem, db, dbIndex, event, 'go', item) end elseif evtType == EVENT_KEY_PRESS then log:debug("_browseMenuListener: EVENT_KEY_PRESS") - + local actionName = _keycodeActionName[event:getKeycode()] if actionName then return _actionHandler(menu, menuItem, db, dbIndex, event, actionName, item) end - + elseif evtType == EVENT_KEY_HOLD then log:debug("_browseMenuListener: EVENT_KEY_HOLD") - + local actionName = _keycodeActionName[event:getKeycode()] if actionName then @@ -1344,7 +1348,7 @@ -- this last list can contain null, so we iterate from 1 to toRenderSize local labelItemStyle = db:labelItemStyle() - + local menuAccel, dir = menu:isAccelerated() if menuAccel then _server:cancelAllArtwork() @@ -1352,15 +1356,15 @@ for widgetIndex = 1, toRenderSize do local dbIndex = toRenderIndexes[widgetIndex] - + if dbIndex then - + -- the widget in widgets[widgetIndex] shall correspond to data[dataIndex] -- log:debug( --- "_browseMenuRenderer: rendering widgetIndex:", +-- "_browseMenuRenderer: rendering widgetIndex:", -- widgetIndex, ", dataIndex:", dbIndex, ")" -- ) - + local widget = widgets[widgetIndex] local item, current = db:item(dbIndex) @@ -1376,7 +1380,7 @@ local bActionGo = _safeDeref(chunk, 'base', 'actions', 'go') local iActionGo = _safeDeref(item, 'actions', 'go') end - + if current then style = "albumcurrent" elseif item and item["style"] then @@ -1433,22 +1437,22 @@ _newDestination = function(origin, item, windowSpec, sink, data) log:debug("_newDestination():") log:debug(windowSpec) - - - -- a DB (empty...) + + + -- a DB (empty...) local db = DB(windowSpec) - + -- create a window in all cases local window = Window(windowSpec.windowStyle) window:setTitleWidget(_decoratedLabel(nil, windowSpec.labelTitleStyle, windowSpec, db, false)) - + local menu -- if the item has an input field, we must ask for it if item and item['input'] and not item['_inputDone'] then local inputSpec - + -- legacy SS compatibility -- FIXME: remove SS compatibility with legacy JiveMLON generation if type(item['input']) != "table" then @@ -1461,11 +1465,11 @@ else inputSpec = item["input"] end - + -- make sure it's a number for the comparison below -- Lua insists on checking type while Perl couldn't care less :( inputSpec.len = tonumber(inputSpec.len) - + -- default allowedChars if not inputSpec.allowedChars then inputSpec.allowedChars = _string("ALLOWEDCHARS_CAPS") @@ -1479,7 +1483,7 @@ local _v = DateTime:timeFromSFM(v) v = Textinput.timeValue(_v) end - else + else if inputStyle == 'time' then v = Textinput.timeValue("00:00") end @@ -1487,7 +1491,7 @@ -- create a text input local input = Textinput( - "textinput", + "textinput", v, function(_, value) -- check for min number of chars @@ -1495,11 +1499,11 @@ return false end - + log:debug("Input: " , value) _lastInput = value item['_inputDone'] = value - + -- now we should perform the action ! _actionHandler(nil, nil, db, nil, nil, 'go', item) -- close the text input if this is a "do" @@ -1525,7 +1529,7 @@ end end end - + local softButtons = { inputSpec.softbutton1, inputSpec.softbutton2 } local helpStyle = 'help' @@ -1544,7 +1548,7 @@ if softButtons[2] then window:addWidget(Label("softButton2", softButtons[2])) end - + window:addWidget(input) -- special case for sending over textArea @@ -1552,13 +1556,13 @@ local textArea = Textarea("textarea", item['textArea']) window:addWidget(textArea) else - + -- create a cozy place for our items... -- a db above - + -- a menu. We manage closing ourselves to guide our path menu = Menu(windowSpec.menuStyle, _browseMenuRenderer, _browseMenuListener, _browseMenuAvailable) - + -- alltogether now menu:setItems(db:menuItems()) window:addWidget(menu) @@ -1574,8 +1578,8 @@ end end - - + + -- a step for our enlightenment path local step = { origin = origin, -- origin step @@ -1587,9 +1591,9 @@ data = data, -- data (generic) actionModifier = false, -- modifier } - + log:debug("new step: " , step) - + -- make sure closing our windows do keep the path alive! window:addListener( EVENT_WINDOW_POP, @@ -1607,11 +1611,11 @@ end end ) - + -- manage sink local stepSink = _getStepSink(step, sink) step.sink = stepSink - + return step, stepSink end @@ -1687,12 +1691,12 @@ _statusStep.origin = _curStep _curStep = _statusStep - -- current playlist should select currently playing item + -- current playlist should select currently playing item -- if there is only one item in the playlist, bring the selected item to top local playlistSize = _safeDeref(_player, 'playerStatus', 'playlist_tracks') if playlistSize == 1 then _statusStep.menu["_lastSelectedIndex"] = 1 - _statusStep.menu["_lastSelectedOffset"] = 1 + _statusStep.menu["_lastSelectedOffset"] = 1 _statusStep.menu.selected = 1 _statusStep.menu:_updateWidgets() -- otherwise bring the currently playing item to the screen with offset of 2 @@ -1702,7 +1706,7 @@ _statusStep.menu["_lastSelectedIndex"] = _statusStep.menu.selected _statusStep.menu["_lastSelectedOffset"] = 2 end - -- since we've hacked the _lastSelectedIndex, it's necessary to + -- since we've hacked the _lastSelectedIndex, it's necessary to -- _updateWidgets to display correctly selected item _statusStep.menu:_updateWidgets() end @@ -1712,7 +1716,7 @@ local evtCode = event:getKeycode() if evtCode == KEY_BACK then local windowStack = Framework.windowStack - -- if this window is #2 on the stack there is no NowPlaying window + -- if this window is #2 on the stack there is no NowPlaying window -- (e.g., when playlist is empty) if #windowStack == 2 then goHome() @@ -1889,18 +1893,18 @@ nil, nil, _newWindowSpec( - nil, + nil, { text = _string("SLIMBROWSER_NOW_PLAYING"), - window = { - ["menuStyle"] = "album", + window = { + ["menuStyle"] = "album", } } ), _statusSink ) _statusStep = step - + -- make sure it has our modifier (so that we use different default action in Now Playing) _statusStep.actionModifier = "-status" @@ -2038,19 +2042,19 @@ -- walk down our path and close... local step = _curStep - + while step do step.window:hide() step = step.origin end - + local step = _statusStep - + while step do step.window:hide() step = step.origin end - + return true end