diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100755 index 0000000..fb2c99b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "HOMEROKU", + "type": "brightscript", + "request": "launch", + "host": "192.168.0.109", + "password": "1143", + "rootDir": "${workspaceFolder}", + "injectRdbOnDeviceComponent": true + } + ] +} diff --git a/EX.json b/EX.json new file mode 100755 index 0000000..2f58be3 --- /dev/null +++ b/EX.json @@ -0,0 +1,13 @@ +{ + "month": "7", + "num": 614, + "link": "", + "year": "2009", + "news": "", + "safe_title": "Woodpecker", + "transcript": "[[A man with a beret and a woman are standing on a boardwalk, leaning on a handrail.]]\nMan: A woodpecker!\n<>\nWoman: Yup.\n\n[[The woodpecker is banging its head against a tree.]]\nWoman: He hatched about this time last year.\n<>\n\n[[The woman walks away. The man is still standing at the handrail.]]\n\nMan: ... woodpecker?\nMan: It's your birthday!\n\nMan: Did you know?\n\nMan: Did... did nobody tell you?\n\n[[The man stands, looking.]]\n\n[[The man walks away.]]\n\n[[There is a tree.]]\n\n[[The man approaches the tree with a present in a box, tied up with ribbon.]]\n\n[[The man sets the present down at the base of the tree and looks up.]]\n\n[[The man walks away.]]\n\n[[The present is sitting at the bottom of the tree.]]\n\n[[The woodpecker looks down at the present.]]\n\n[[The woodpecker sits on the present.]]\n\n[[The woodpecker pulls on the ribbon tying the present closed.]]\n\n((full width panel))\n[[The woodpecker is flying, with an electric drill dangling from its feet, held by the cord.]]\n\n{{Title text: If you don't have an extension cord I can get that too. Because we're friends! Right?}}", + "alt": "If you don't have an extension cord I can get that too. Because we're friends! Right?", + "img": "https://imgs.xkcd.com/comics/woodpecker.png", + "title": "Woodpecker", + "day": "24" +} \ No newline at end of file diff --git a/README.md b/README.md index 58e3777..47cde68 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # XKCDViewer -Unofficial XKCD Reader for Roku® source code. \ No newline at end of file +Unofficial XKCD Reader for Roku® source code. diff --git a/components/BigScene.xml b/components/BigScene.xml new file mode 100755 index 0000000..97292ed --- /dev/null +++ b/components/BigScene.xml @@ -0,0 +1,328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/GetXKCDComic.xml b/components/GetXKCDComic.xml new file mode 100755 index 0000000..ac05689 --- /dev/null +++ b/components/GetXKCDComic.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/components/GetXKCDImage.xml b/components/GetXKCDImage.xml new file mode 100755 index 0000000..141c6e7 --- /dev/null +++ b/components/GetXKCDImage.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/components/TypePad.xml b/components/TypePad.xml new file mode 100755 index 0000000..6bfed64 --- /dev/null +++ b/components/TypePad.xml @@ -0,0 +1,26 @@ + + + + + + + + + \ No newline at end of file diff --git a/images/buttons/back.png b/images/buttons/back.png new file mode 100755 index 0000000..17e8dca Binary files /dev/null and b/images/buttons/back.png differ diff --git a/images/buttons/down.png b/images/buttons/down.png new file mode 100755 index 0000000..d4ee269 Binary files /dev/null and b/images/buttons/down.png differ diff --git a/images/buttons/fastforward.png b/images/buttons/fastforward.png new file mode 100755 index 0000000..daa4a09 Binary files /dev/null and b/images/buttons/fastforward.png differ diff --git a/images/buttons/left.png b/images/buttons/left.png new file mode 100755 index 0000000..a11326e Binary files /dev/null and b/images/buttons/left.png differ diff --git a/images/buttons/ok.png b/images/buttons/ok.png new file mode 100755 index 0000000..b3ed0cb Binary files /dev/null and b/images/buttons/ok.png differ diff --git a/images/buttons/replay.png b/images/buttons/replay.png new file mode 100755 index 0000000..c238d29 Binary files /dev/null and b/images/buttons/replay.png differ diff --git a/images/buttons/rewind.png b/images/buttons/rewind.png new file mode 100755 index 0000000..1cadb2f Binary files /dev/null and b/images/buttons/rewind.png differ diff --git a/images/buttons/right.png b/images/buttons/right.png new file mode 100755 index 0000000..aeaad5c Binary files /dev/null and b/images/buttons/right.png differ diff --git a/images/buttons/star.png b/images/buttons/star.png new file mode 100755 index 0000000..2e27a79 Binary files /dev/null and b/images/buttons/star.png differ diff --git a/images/buttons/up.png b/images/buttons/up.png new file mode 100755 index 0000000..1b6422d Binary files /dev/null and b/images/buttons/up.png differ diff --git a/images/channel-poster_fhd.png b/images/channel-poster_fhd.png new file mode 100755 index 0000000..6c4ed3a Binary files /dev/null and b/images/channel-poster_fhd.png differ diff --git a/images/channel-poster_hd.png b/images/channel-poster_hd.png new file mode 100755 index 0000000..9c92e96 Binary files /dev/null and b/images/channel-poster_hd.png differ diff --git a/images/channel-poster_sd.png b/images/channel-poster_sd.png new file mode 100755 index 0000000..6a46199 Binary files /dev/null and b/images/channel-poster_sd.png differ diff --git a/images/coolKeyboardLayoutKDF.json b/images/coolKeyboardLayoutKDF.json new file mode 100755 index 0000000..0b1f7c8 --- /dev/null +++ b/images/coolKeyboardLayoutKDF.json @@ -0,0 +1,53 @@ +{ + "keyboardWidthFHD": 300, + "keyboardHeightFHD": 242, + "keyboardWidthHD": 300, + "keyboardHeightHD": 242, + "sections": [ + { + "grids": [ + { + "rows": [ + { + "keys": [ + { "label": "1" }, + { "label": "2" }, + { "label": "3" } + ] + }, + { + "keys": [ + { "label": "4" }, + { "label": "5" }, + { "label": "6" } + ] + }, + { + "keys": [ + { "label": "7" }, + { "label": "8" }, + { "label": "9" } + ] + }, + { + "keys": [ + { + "icon": "theme:DKB_ClearKeyBitmap", + "focusIcon": "theme:DKB_ClearKeyFocusBitmap", + "strOut": "clear" + }, + { "label": "0" }, + { + "icon": "theme:DKB_DeleteKeyBitmap", + "focusIcon": "theme:DKB_DeleteKeyFocusBitmap", + "autoRepeat": 1, + "strOut": "backspace" + } + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/images/reactions/loading.png b/images/reactions/loading.png new file mode 100755 index 0000000..138f2bc Binary files /dev/null and b/images/reactions/loading.png differ diff --git a/images/reactions/loadingBig.png b/images/reactions/loadingBig.png new file mode 100755 index 0000000..4b06d13 Binary files /dev/null and b/images/reactions/loadingBig.png differ diff --git a/images/reactions/logo.png b/images/reactions/logo.png new file mode 100755 index 0000000..e7f52a2 Binary files /dev/null and b/images/reactions/logo.png differ diff --git a/images/reactions/text_entry.png b/images/reactions/text_entry.png new file mode 100755 index 0000000..77b6ecf Binary files /dev/null and b/images/reactions/text_entry.png differ diff --git a/images/splash-screen_fhd.jpg b/images/splash-screen_fhd.jpg new file mode 100755 index 0000000..8a840a3 Binary files /dev/null and b/images/splash-screen_fhd.jpg differ diff --git a/images/splash-screen_hd.jpg b/images/splash-screen_hd.jpg new file mode 100755 index 0000000..679cb04 Binary files /dev/null and b/images/splash-screen_hd.jpg differ diff --git a/images/splash-screen_sd.jpg b/images/splash-screen_sd.jpg new file mode 100755 index 0000000..91370fa Binary files /dev/null and b/images/splash-screen_sd.jpg differ diff --git a/images/xkcd.ttf b/images/xkcd.ttf new file mode 100755 index 0000000..1ed2100 Binary files /dev/null and b/images/xkcd.ttf differ diff --git a/manifest b/manifest new file mode 100755 index 0000000..b4f684c --- /dev/null +++ b/manifest @@ -0,0 +1,29 @@ +# +# Copyright (c) 2015 Roku, Inc. All rights reserved. +# Roku Channel Manifest File +# Full spec at bit.ly/roku-manifest-file +# + +## Channel Details +title=Unofficial XKCD Reader for Roku® +major_version=1 +minor_version=0 +build_version=00001 + +## Channel Assets +### Main Menu Icons / Channel Poster Artwork +#### Image sizes are FHD: 540x405px | HD: 290x218px | SD: 214x144px +mm_icon_focus_fhd=pkg:/images/channel-poster_fhd.png +mm_icon_focus_hd=pkg:/images/channel-poster_hd.png +mm_icon_focus_sd=pkg:/images/channel-poster_sd.png + +### Splash Screen + Loading Screen Artwork +#### Image sizes are FHD: 1920x1080px | HD: 1280x720px | SD: 720x480px +splash_screen_fhd=pkg:/images/splash-screen_fhd.jpg +splash_screen_hd=pkg:/images/splash-screen_hd.jpg +splash_screen_sd=pkg:/images/splash-screen_sd.jpg + +splash_color=#FFFFFF +splash_min_time=3 + +confirm_partner_button=1 \ No newline at end of file diff --git a/out/roku-deploy.zip b/out/roku-deploy.zip new file mode 100755 index 0000000..c02571c Binary files /dev/null and b/out/roku-deploy.zip differ diff --git a/source/Main.brs b/source/Main.brs new file mode 100755 index 0000000..ebbe858 --- /dev/null +++ b/source/Main.brs @@ -0,0 +1,19 @@ +sub Main() + print "in showChannelSGScreen" + 'Indicate this is a Roku SceneGraph application' + screen = CreateObject("roSGScreen") + m.port = CreateObject("roMessagePort") + screen.setMessagePort(m.port) + + scene = screen.CreateScene("BigScene") + screen.show() + + while(true) + msg = wait(0, m.port) + msgType = type(msg) + if msgType = "roSGScreenEvent" + if msg.isScreenClosed() then return + end if + end while +end sub + diff --git a/source/literally_everything.brs b/source/literally_everything.brs new file mode 100644 index 0000000..882f2b4 --- /dev/null +++ b/source/literally_everything.brs @@ -0,0 +1,286 @@ +function init() + m.Keebpalette = createObject("roSGNode", "RSGPalette") + m.Keebpalette.colors = { DialogBackgroundColor: "0xFFFFFFFF", + DialogItemColor: "0x000000FF", + DialogTextColor: "0x000000FF", + DialogFocusColor: "0xFFFFFFFF", + DialogFocusItemColor: "0x000000FF", + DialogSecondaryItemColor: "0x000000FF", + DialogKeyboardColor: "0xFFFFFFFF", + DialogInputFieldColor: "0xFFFFFFFF", + DialogFootprintColor: "0xFFFFFFFF" } + m.isBig = false + m.canExitSearch = true + m.inKeyboard = false + m.inBigAlt = false + m.skipGet = false + m.months = ["January", "Febuary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] + m.top.backgroundColor = "0xFFFFFFFF" + m.top.backgroundURI = "" + m.XKCDfontcolor = "0x000000FF" + m.XKCDseccolor = "0x606060FF" + + m.title = m.top.findNode("title") + m.num = m.top.findNode("num") + m.date = m.top.findNode("date") + m.comic = m.top.findNode("comic") + m.scrim = m.top.findNode("scrim") + m.comic_sel_label = m.top.findNode("comic_sel_label") + m.alt = m.top.findNode("alt") + m.alttextbig = m.top.findNode("alttextbig") + m.title.font.uri = "pkg:/images/xkcd.ttf" + m.title.font.size = 40 + m.title.color = m.XKCDfontcolor + m.comic_sel_label.font.uri = "pkg:/images/xkcd.ttf" + m.comic_sel_label.font.size = 40 + m.comic_sel_label.color = m.XKCDfontcolor + m.num.font.uri = "pkg:/images/xkcd.ttf" + m.num.font.size = 20 + m.num.color = m.XKCDfontcolor + m.date.font.uri = "pkg:/images/xkcd.ttf" + m.date.font.size = 20 + m.date.color = m.XKCDfontcolor + m.alt.font.uri = "pkg:/images/xkcd.ttf" + m.alt.font.size = 20 + m.alt.color = m.XKCDseccolor + m.alttextbig.font.uri = "pkg:/images/xkcd.ttf" + m.alttextbig.font.size = 20 + m.alttextbig.color = m.XKCDfontcolor + m.MainScene = m.top.findNode("MainScene") + m.SearchScene = m.top.findNode("SearchScene") + m.comic_id = m.top.findNode("comic_id") + m.doneButton = m.top.findNode("doneButton") + m.backButton = m.top.findNode("backButton") + m.comic_id.observeField("text", "searchkeyboardUpdate") + m.doneButton.observeField("buttonSelected", "searchbuttonClick") + m.backButton.observeField("buttonSelected", "backbuttonClick") + +' m.TextKeeb = m.top.findNode("TextKeeb") +' m.TextKeeb.palette = m.Keebpalette +' m.TextKeeb.buttons = [ +' "BACK", +' "DONE" +' ] + + getNewestComicLol() + + m.top.setFocus(true) +end function + +function OpenSearchDialog() + m.SearchScene.visible = true + m.top.findNode("SearchScrim").visible = true + m.inKeyboard = true + m.comic_id.setFocus(true) + if m.comic_id.text.toInt() > m.num_latestComic OR m.comic_id.text.toInt() <= 0 then + m.canExitSearch = false + else + m.canExitSearch = true + end if +end function + +function searchkeyboardUpdate() + ?m.comic_id.text + if Len(m.comic_id.text) > 5 then + m.comic_id.text = Left(m.comic_id.text, 5) + end if + if m.comic_id.text.toInt() > m.num_latestComic OR m.comic_id.text.toInt() <= 0 then + m.canExitSearch = false + else + m.canExitSearch = true + end if + m.comic_sel_label.text = "GET COMIC #" + m.comic_id.text +end function + +function searchbuttonClick() + if not m.canExitSearch or not m.inKeyboard then return 0 + m.SearchScene.visible = false + m.top.findNode("SearchScrim").visible = false + m.inKeyboard = false + specificcomicget(m.comic_id.text.toInt()) + m.comic_id.text = "" + m.comic_sel_label.text = "GET COMIC #..." + m.comic_id.setFocus(false) + m.doneButton.setFocus(false) + m.backButton.setFocus(false) + m.top.setFocus(true) +end function + +function backbuttonClick() + m.SearchScene.visible = false + m.top.findNode("SearchScrim").visible = false + m.inKeyboard = false + m.comic_id.text = "" + m.comic_sel_label.text = "GET COMIC #..." + m.comic_id.setFocus(false) + m.doneButton.setFocus(false) + m.backButton.setFocus(false) + m.top.setFocus(true) +end function + +function getNewestComicLol() + m.getLatestComicTask = createObject("roSGNode", "GetXKCDComic") + m.ct = m.getLatestComicTask + m.getLatestComicTask.comicid = "" + m.getLatestComicTask.observeField("comic", "startComicInitial") + m.getLatestComicTask.control = "RUN" +end function + +function startComicInitial() + m.num_earliestComic = 1 + m.num_latestComic = m.getLatestComicTask.comic.num + m.num_currentComic = m.getLatestComicTask.comic.num + sec = CreateObject("roRegistrySection", "Settings") + if sec.Exists("CurrentComic") and not m.skipGet then + specificcomicget(sec.Read("CurrentComic").toInt()) + else + getcomic() + endif + m.skipGet = true +end function + +function getcomic() + ?m.ct.comic + if m.ct.comic = invalid then + m.title.text = "For some reason, that failed." + return true + end if + m.title.text = m.ct.comic.title + m.num.text = "Comic #" + m.ct.comic.num.ToStr() + m.alt.text = m.ct.comic.alt + m.alttextbig.text = m.ct.comic.alt + m.date.text = m.months[m.ct.comic.month.toInt() - 1] + " " + m.ct.comic.day + ", " + m.ct.comic.year + m.comic.SetCertificatesFile("common:/certs/ca-bundle.crt") + m.comic.InitClientCertificates() + m.comic.uri = m.ct.comic.img + if m.ct.comic.num >= m.num_latestComic then + m.top.findNode("changeIfFinal").text = "NEW?" + else + m.top.findNode("changeIfFinal").text = "NEXT" + end if + if m.ct.comic.num <= m.num_earliestComic then + m.top.findNode("changeIfFirst").text = "" + else + m.top.findNode("changeIfFirst").text = "PREV" + end if + sec = CreateObject("roRegistrySection", "Settings") + sec.Write("CurrentComic", m.ct.comic.num.toStr()) + sec.Flush() +end function + +function newcomicget(number as Integer) + m.num_currentComic = m.num_currentComic + number + if m.num_currentComic > m.num_latestComic then + m.num_currentComic = m.num_latestComic + getNewestComicLol() + return 0 + else if m.num_currentComic < m.num_earliestComic then + m.num_currentComic = m.num_earliestComic + return 0 + end if + m.getComicTask = createObject("roSGNode", "GetXKCDComic") + m.ct = m.getComicTask + m.getComicTask.comicid = "/" + m.num_currentComic.ToStr() + m.getComicTask.observeField("comic", "getcomic") + m.getComicTask.control = "RUN" +end function + +function specificcomicget(number as Integer) + m.num_currentComic = number + m.getComicTask = createObject("roSGNode", "GetXKCDComic") + m.ct = m.getComicTask + m.getComicTask.comicid = "/" + m.num_currentComic.ToStr() + ?m.getComicTask.comicid + m.getComicTask.observeField("comic", "getcomic") + m.getComicTask.control = "RUN" +end function + +function toggleBig() + m.isBig = not m.isBig + if m.isBig then + m.comic.translation = [100, 50] + m.comic.width = 1080 + m.comic.height = 620 + m.comic.loadingBitmapUri="pkg:/images/reactions/loadingBig.png" + m.scrim.visible = true + else + m.comic.translation = [100, 0] + m.comic.width = 1080 + m.comic.height = 400 + m.comic.loadingBitmapUri="pkg:/images/reactions/loading.png" + m.scrim.visible = false + end if +end function + +function toggleAlt() + m.inBigAlt = not m.inBigAlt + if m.inBigAlt then + m.top.findNode("AltScrim").visible = true + m.top.findNode("AltScene").visible = true + else + m.top.findNode("AltScrim").visible = false + m.top.findNode("AltScene").visible = false + end if +end function + +function onKeyEvent(key as String, press as Boolean) as Boolean + handled = false + if press then + if not m.inKeyboard then + if (key = "back") then + handled = false + if m.inBigAlt then + toggleAlt() + handled = true + end if + if m.isBig then + toggleBig() + handled = true + end if + else + if (key = "left") then + newcomicget(-1) + else if (key = "right") then + newcomicget(1) + else if (key = "down") then + if not m.isBig and not m.inBigAlt then OpenSearchDialog() + else if (key = "up") then + if not m.isBig then + toggleAlt() + else + toggleBig() + end if + else if (key = "replay" OR key = "fastforward") then + getNewestComicLol() + else if (key = "rewind") then + specificcomicget(1) + else if (key = "OK") then + if not m.inBigAlt then + toggleBig() + else + toggleAlt() + end if + end if + handled = true + end if + else + if (key = "back") then + backbuttonClick() + else if key = "down" and not m.backButton.hasFocus() and not m.doneButton.hasFocus() + m.backButton.setFocus(true) + else if key = "up" and not m.comic_id.hasFocus() + m.comic_id.setFocus(true) + else if key = "left" and not m.doneButton.hasFocus() and not m.comic_id.hasFocus() + m.doneButton.setFocus(true) + else if key = "left" and not m.backButton.hasFocus() and not m.comic_id.hasFocus() + m.backButton.setFocus(true) + else if key = "right" and not m.doneButton.hasFocus() and not m.comic_id.hasFocus() + m.doneButton.setFocus(true) + else if key = "right" and not m.backButton.hasFocus() and not m.comic_id.hasFocus() + m.backButton.setFocus(true) + end if + handled = true + end if + end if + return handled +end function \ No newline at end of file