EcasaGui.py: bump to 15 pictures on wall, implement previous/next page
[enigma2-plugins.git] / ecasa / src / EcasaGui.py
1 from __future__ import print_function
2
3 #pragma mark - GUI
4
5 #pragma mark Screens
6 from Screens.Screen import Screen
7 from Screens.HelpMenu import HelpableScreen
8
9 #pragma mark Components
10 from Components.ActionMap import HelpableActionMap
11 from Components.AVSwitch import AVSwitch
12 from Components.Pixmap import Pixmap, MovingPixmap
13 from Components.Sources.StaticText import StaticText
14 from Components.Sources.List import List
15
16 #pragma mark Configuration
17 from Components.config import config
18
19 #pragma mark Picasa
20 from .PicasaApi import PicasaApi
21
22 from enigma import ePicLoad
23 from collections import deque
24
25 try:
26         xrange = xrange
27 except NameError:
28         xrange = range
29
30 our_print = lambda *args, **kwargs: print("[EcasaGui]", *args, **kwargs)
31
32 class EcasaPictureWall(Screen, HelpableScreen):
33         PICS_PER_PAGE = 15
34         skin = """<screen position="center,center" size="600,380">
35                 <ePixmap position="0,0" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on"/>
36                 <ePixmap position="140,0" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on"/>
37                 <ePixmap position="280,0" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on"/>
38                 <ePixmap position="420,0" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on"/>
39                 <ePixmap position="565,10" size="35,25" pixmap="skin_default/buttons/key_menu.png" alphatest="on"/>
40                 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1"/>
41                 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1"/>
42                 <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1"/>
43                 <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1"/>
44                 <widget name="image0"  position="30,50"   size="90,90"/>
45                 <widget name="image1"  position="140,50"  size="90,90"/>
46                 <widget name="image2"  position="250,50"  size="90,90"/>
47                 <widget name="image3"  position="360,50"  size="90,90"/>
48                 <widget name="image4"  position="470,50"  size="90,90"/>
49                 <widget name="image5"  position="30,160"  size="90,90"/>
50                 <widget name="image6"  position="140,160" size="90,90"/>
51                 <widget name="image7"  position="250,160" size="90,90"/>
52                 <widget name="image8"  position="360,160" size="90,90"/>
53                 <widget name="image9"  position="470,160" size="90,90"/>
54                 <widget name="image10" position="30,270"  size="90,90"/>
55                 <widget name="image11" position="140,270" size="90,90"/>
56                 <widget name="image12" position="250,270" size="90,90"/>
57                 <widget name="image13" position="360,270" size="90,90"/>
58                 <widget name="image14" position="470,270" size="90,90"/>
59                 <!-- TODO: find/create :P -->
60                 <widget name="highlight" position="20,45" size="100,100"/>
61                 </screen>"""
62         def __init__(self, session, api=None):
63                 Screen.__init__(self, session)
64                 HelpableScreen.__init__(self)
65
66                 if api is None:
67                         self.api = PicasaApi(
68                                         config.plugins.ecasa.google_username.value,
69                                         config.plugins.ecasa.google_password.value,
70                                         config.plugins.ecasa.cache.value)
71
72                 self["key_red"] = StaticText(_("Close"))
73                 self["key_green"] = StaticText()
74                 self["key_yellow"] = StaticText()
75                 self["key_blue"] = StaticText()
76                 for i in xrange(self.PICS_PER_PAGE):
77                         self['image%d' % i] = Pixmap()
78                         self['title%d' % i] = StaticText()
79                 self["highlight"] = MovingPixmap()
80
81                 self["overviewActions"] = HelpableActionMap(self, "EcasaOverviewActions", {
82                         "up": self.up,
83                         "down": self.down,
84                         "left": self.left,
85                         "right": self.right,
86                         "nextPage": (self.nextPage, _("show next page")),
87                         "prevPage": (self.prevPage, _("show previous page")),
88                         "select": self.select,
89                         "exit":self.close,
90                         }, -1)
91
92                 self.offset = 0
93                 self.highlighted = 0
94
95                 # thumbnail loader
96                 self.picload = ePicLoad()
97                 self.picload.PictureData.get().append(self.gotPicture)
98                 sc = AVSwitch().getFramebufferScale()
99                 self.picload.setPara((90, 90, sc[0], sc[1], False, 1, '#ff000000')) # TODO: hardcoded size is evil!
100                 self.currentphoto = None
101                 self.queue = deque()
102
103         def gotPicture(self, picInfo=None):
104                 our_print("picture decoded")
105                 ptr = self.picload.getData()
106                 if ptr is not None:
107                         idx = self.pictures.index(self.currentphoto)
108                         realIdx = idx - self.offset
109                         self['image%d' % realIdx].instance.setPixmap(ptr.__deref__())
110                 self.currentphoto = None
111                 self.maybeDecode()
112
113         def maybeDecode(self):
114                 our_print("maybeDecode")
115                 if self.currentphoto is not None: return
116                 our_print("no current photo, checking for queued ones")
117                 try:
118                         filename, self.currentphoto = self.queue.pop()
119                 except IndexError:
120                         our_print("no queued photos")
121                         # no more pictures
122                         pass
123                 else:
124                         self.picload.startDecode(filename)
125
126         def pictureDownloaded(self, tup):
127                 filename, photo = tup
128                 our_print("pictureDownloaded", filename, photo)
129                 self.queue.append((filename, photo))
130                 self.maybeDecode()
131
132         def pictureDownloadFailed(self, tup):
133                 error, photo = tup
134                 our_print("pictureDownloadFailed", error, photo)
135                 # TODO: indicate in gui
136
137         def setup(self):
138                 our_print("setup")
139                 self.queue.clear()
140                 pictures = self.pictures
141                 for i in xrange(self.PICS_PER_PAGE):
142                         try:
143                                 our_print("trying to initiate download of idx", i+self.offset)
144                                 self.api.downloadThumbnail(pictures[i+self.offset]).addCallbacks(self.pictureDownloaded, self.pictureDownloadFailed)
145                         except IndexError:
146                                 # no more pictures
147                                 # TODO: set invalid pic for remaining items
148                                 our_print("no more pictures in setup")
149                                 break
150
151         def up(self):
152                 our_print("UP")
153         def down(self):
154                 our_print("DOWN")
155         def left(self):
156                 our_print("LEFT")
157         def right(self):
158                 our_print("RIGHT")
159         def nextPage(self):
160                 our_print("nextPage")
161                 offset = self.offset + self.PICS_PER_PAGE
162                 if offset > len(self.pictures):
163                         self.offset = 0
164                 else:
165                         self.offset = offset
166                 self.setup()
167         def prevPage(self):
168                 our_print("prevPage")
169                 offset = self.offset - self.PICS_PER_PAGE
170                 if offset < 0:
171                         Len = len(self.pictures)
172                         self.offset = Len - (Len % self.PICS_PER_PAGE)
173                 else:
174                         self.offset = offset
175                 self.setup()
176         def select(self):
177                 our_print("SELECT")
178
179 class EcasaOverview(EcasaPictureWall):
180         def __init__(self, session):
181                 EcasaPictureWall.__init__(self, session)
182                 self.skinName = ["EcasaOverview", "EcasaPictureWall"]
183                 self.onLayoutFinish.append(self.go)
184
185         def go(self):
186                 self.onLayoutFinish.remove(self.go)
187                 # NOTE: possibility of a socket.timeout
188                 self.pictures = self.api.getFeatured()
189                 self.setup()
190