source: lliurex-store/trunk/fuentes/lliurex-store-gui/usr/share/lliurex-store/lliurex-store-gui/DetailsBox.py @ 8187

Last change on this file since 8187 was 8187, checked in by hectorgh, 15 months ago

search related by threads

File size: 18.3 KB
Line 
1import gi
2gi.require_version('Gtk', '3.0')
3
4from gi.repository import Gtk, Pango, GdkPixbuf, Gdk, Gio,GLib
5import Screenshot
6import ImageManager
7
8import Core
9
10import signal
11signal.signal(signal.SIGINT, signal.SIG_DFL)
12
13import time
14import threading
15from subprocess import Popen
16import os
17import html2text
18import random
19import copy
20
21import gettext
22gettext.textdomain('lliurex-store')
23_ = gettext.gettext
24
25
26
27class DetailsBox(Gtk.VBox):
28
29        def __init__(self):
30               
31                Gtk.VBox.__init__(self)
32               
33                self.core=Core.Core.get_core()
34               
35                self.banner_full_size=250
36                self.screenshot_small=100
37                self.banner_small=135
38                self.icon_size=64
39               
40                self.details_max_width=25
41                self.app_max_width=8
42                self.short_description_max_width=10
43               
44                self.full_info_box=Gtk.HBox()
45                self.pack_start(self.full_info_box,True,True,5)
46               
47                self.related_aborted=False
48                self.current_id=None
49               
50                # ####### LEFT SIDE ######
51               
52                self.app_details=Gtk.VBox()
53                self.app_details.set_margin_left(10)
54                self.app_details.set_margin_bottom(10)
55                self.app_details.set_margin_top(5)
56                self.full_info_box.pack_start(self.app_details,False,False,0)
57
58                self.app_banner=Screenshot.ScreenshotNeo()
59                self.app_banner.set_size_request(self.banner_full_size,self.banner_full_size)
60
61                self.app_details.pack_start(self.app_banner,False,False,0)
62                self.install_button=Gtk.Button()
63                self.install_button_label=Gtk.Label(_("Install"))
64                self.install_button.add(self.install_button_label)
65                self.install_button.connect("clicked",self.install_clicked)
66               
67                vbox=Gtk.VBox()
68                self.install_label=Gtk.Label(_("Installing..."))
69                vbox.pack_start(self.install_label,False,False,0)
70                vbox.set_valign(Gtk.Align.FILL)
71                vbox.set_halign(Gtk.Align.FILL)
72               
73                self.install_label.set_halign(Gtk.Align.START)
74                self.install_pbar=Gtk.ProgressBar()
75                self.install_pbar.set_valign(Gtk.Align.FILL)
76                self.install_pbar.set_halign(Gtk.Align.FILL)
77                vbox.pack_start(self.install_pbar,True,True,0)
78
79                hbox=Gtk.HBox()
80                self.uninstall_button=Gtk.Button(_("Uninstall"))
81                self.uninstall_button.connect("clicked",self.uninstall_clicked)
82                self.open_button=Gtk.Button(_("Open"))
83                self.open_button.connect("clicked",self.open_clicked)
84                self.open_button.set_margin_right(10)
85                hbox.pack_start(self.open_button,True,True,0)
86                hbox.pack_start(self.uninstall_button,True,True,0)
87               
88                self.install_stack=Gtk.Stack()
89                self.install_stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
90                self.install_stack.set_transition_duration(500)
91                self.install_stack.add_titled(self.install_button,"install","Install")
92                self.install_stack.add_titled(vbox,"progress","Progress")
93                self.install_stack.add_titled(hbox,"installed","Open/Uninstall")
94               
95                self.app_details.pack_start(self.install_stack,False,False,10)
96               
97                self.details_label=Gtk.Label("Details")
98                self.details_label.set_alignment(0,0.5)
99                self.details_label.set_margin_left(0)
100                self.app_details.pack_start(self.details_label,False,False,0)
101               
102                self.details_divider=Gtk.HBox()
103                self.details_divider.set_size_request(0,1)
104                self.app_details.pack_start(self.details_divider,False,False,5)
105               
106                self.version_label=Gtk.Label(_("Version"))
107                self.version_label.set_alignment(0,0.5)
108                self.category_label=Gtk.Label(_("Category"))
109                self.category_label.set_alignment(0,0.5)
110                self.license_label=Gtk.Label(_("License"))
111                self.license_label.set_alignment(0,0.5)
112                self.size_label=Gtk.Label(_("Size"))
113                self.size_label.set_alignment(0,0.5)
114                self.website_label=Gtk.Label(_("Website"))
115                self.website_label.set_alignment(0,0.5)
116
117                self.version_value_label=Gtk.Label()
118                self.version_value_label.set_alignment(1,0.5)
119                self.version_value_label.set_max_width_chars(self.details_max_width)
120                self.version_value_label.set_ellipsize(Pango.EllipsizeMode.END)
121                self.category_value_label=Gtk.Label()
122                self.category_value_label.set_alignment(1,0.5)
123                self.category_value_label.set_max_width_chars(self.details_max_width)
124                self.category_value_label.set_ellipsize(Pango.EllipsizeMode.END)
125                self.license_value_label=Gtk.Label()
126                self.license_value_label.set_alignment(1,0.5)
127                self.license_value_label.set_max_width_chars(self.details_max_width)
128                self.license_value_label.set_ellipsize(Pango.EllipsizeMode.END)
129                self.size_value_label=Gtk.Label()
130                self.size_value_label.set_alignment(1,0.5)
131                self.size_value_label.set_max_width_chars(self.details_max_width)
132                self.size_value_label.set_ellipsize(Pango.EllipsizeMode.END)
133                self.website_value_label=Gtk.Label()
134                self.website_value_label.set_alignment(1,0.5)
135                self.website_value_label.set_max_width_chars(self.details_max_width)
136                self.website_value_label.set_ellipsize(Pango.EllipsizeMode.END)
137               
138                hbox=Gtk.HBox()
139                hbox.pack_start(self.version_label,False,False,0)
140                hbox.pack_end(self.version_value_label,False,False,0)
141                self.app_details.pack_start(hbox,False,False,0)
142                hbox=Gtk.HBox()
143                hbox.pack_start(self.category_label,False,False,0)
144                hbox.pack_end(self.category_value_label,False,False,0)
145                self.app_details.pack_start(hbox,False,False,0)
146                hbox=Gtk.HBox()
147                hbox.pack_start(self.license_label,False,False,0)
148                hbox.pack_end(self.license_value_label,False,False,0)
149                self.app_details.pack_start(hbox,False,False,0)
150                hbox=Gtk.HBox()
151                hbox.pack_start(self.size_label,False,False,0)
152                hbox.pack_end(self.size_value_label,False,False,0)
153                self.app_details.pack_start(hbox,False,False,0)
154                hbox=Gtk.HBox()
155                hbox.pack_start(self.website_label,False,False,0)
156                hbox.pack_end(self.website_value_label,False,False,0)
157                self.app_details.pack_start(hbox,False,False,0)
158               
159               
160                # ############# #
161               
162                # ####### RIGHT SIDE ######
163               
164                self.app_details_r=Gtk.VBox()
165                self.app_details_r.set_margin_top(5)
166                self.full_info_box.pack_start(self.app_details_r,True,True,20)
167               
168                hbox=Gtk.HBox()
169                self.app_icon=Screenshot.ScreenshotNeo()
170                self.app_icon.set_size_request(64,64)
171               
172                hbox.pack_start(self.app_icon,False,False,0)
173               
174                self.app_name_label=Gtk.Label("")
175                self.app_name_label.set_max_width_chars(self.app_max_width)
176                self.app_name_label.set_ellipsize(Pango.EllipsizeMode.END)
177                self.app_name_label.set_alignment(0,1)
178                self.short_description_label=Gtk.Label("")
179                self.short_description_label.set_alignment(0,0)
180                self.short_description_label.set_max_width_chars(self.short_description_max_width)
181                self.short_description_label.set_ellipsize(Pango.EllipsizeMode.END)
182               
183                vbox=Gtk.VBox()
184                vbox.pack_start(self.app_name_label,True,True,0)
185                vbox.pack_start(self.short_description_label,True,True,0)
186                hbox.pack_start(vbox,True,True,5)
187               
188                self.app_details_r.pack_start(hbox,False,False,0)
189               
190                self.full_description_label=Gtk.Label()
191                self.full_description_label.set_margin_right(10)
192                self.full_description_label.set_alignment(0,1)
193                self.full_description_label.set_justify(Gtk.Justification.FILL)
194                self.full_description_label.set_line_wrap(True)
195                self.full_description_label.set_valign(Gtk.Align.START)
196                self.full_description_label.set_halign(Gtk.Align.FILL)
197               
198                sw=Gtk.ScrolledWindow()
199                sw.set_shadow_type(Gtk.ShadowType.NONE)
200                sw.set_overlay_scrolling(True)
201                sw.set_kinetic_scrolling(True)
202                vp=Gtk.Viewport()
203                sw.add(vp)
204                sw.set_size_request(0,100)
205                vp.add(self.full_description_label)
206               
207                self.app_details_r.pack_start(sw,True,True,10)
208               
209                self.description_divider=Gtk.HBox()
210                self.description_divider.set_size_request(0,1)
211                self.description_divider.set_valign(Gtk.Align.START)
212                self.app_details_r.pack_start(self.description_divider,False,False,5)
213               
214                ss_sw=Gtk.ScrolledWindow()
215                ss_sw.set_shadow_type(Gtk.ShadowType.NONE)
216                ss_vp=Gtk.Viewport()
217               
218                ss_sw.add(ss_vp)
219               
220                self.screenshots_box=Gtk.HBox()
221               
222                ss_sw.set_size_request(0,130)
223                vbox=Gtk.VBox()
224                vbox.pack_start(self.screenshots_box,True,False,0)
225                ss_vp.add(vbox)
226                self.app_details_r.set_valign(Gtk.Align.FILL)
227                self.app_details_r.pack_start(ss_sw,False,False,5)
228               
229               
230                # ####################### #
231               
232                # ## RELATED #######
233               
234                related_vbox=Gtk.VBox()
235                related_vbox.set_margin_left(10)
236               
237                self.related_label=Gtk.Label(_("Related"))
238                self.related_label.set_alignment(0,1)
239               
240                related_vbox.pack_start(self.related_label,False,False,0)
241                               
242                self.related_divider=Gtk.HBox()
243                self.related_divider.set_size_request(0,1)
244                self.related_divider.set_margin_right(20)
245                related_vbox.pack_start(self.related_divider,False,False,5)
246               
247                self.related_sw=Gtk.ScrolledWindow()
248                self.related_sw.set_shadow_type(Gtk.ShadowType.NONE)
249                self.related_sw.set_size_request(0,self.banner_small+40)
250                self.related_sw.set_margin_right(20)
251                related_vp=Gtk.Viewport()
252                self.related_sw.add(related_vp)
253               
254                self.related_box=Gtk.HBox()
255                self.related_box.set_margin_bottom(10)
256               
257                related_vp.add(self.related_box)
258               
259                related_vbox.pack_start(self.related_sw,False,False,5)
260                self.pack_start(related_vbox,True,True,0)
261               
262                # #################
263
264                self.set_css_info()
265               
266        #def  init
267       
268        def set_package_info(self,pkg):
269               
270                self.current_id=random.random()
271               
272                info={}
273               
274                info["image_url"]=pkg["banner_small"]
275                info["image_id"]=pkg["package"]+"_banner_small"
276                info["x"]=self.banner_full_size
277                info["y"]=self.banner_full_size
278                info["aspect_ratio"]=False
279                info["name"]=pkg["package"].capitalize()
280                info["installed"]=True if pkg["state"]=="installed" else False
281               
282                if pkg["banner_small"] !=None:
283                        self.app_banner.download_image(info)
284                else:
285                        info["name"]=None
286                        if os.path.exists(self.core.tmp_store_dir+info["image_id"]):
287                               
288                                info["image_path"]=self.core.tmp_store_dir+info["image_id"]
289                                self.app_banner.set_from_file(info)
290                        else:
291                                info["image_path"]=self.core.resources.get_icon(pkg)
292                       
293                                self.app_banner.create_banner_from_file(info)
294               
295                self.version_value_label.set_text(pkg["version"])
296                self.category_value_label.set_text(pkg["category"])
297                self.license_value_label.set_text(pkg["license"])
298                try:
299                        size= "{:.2f} MB".format(float(pkg["size"])/1000000) 
300                        self.size_value_label.set_text(size)
301                except:
302                        pass
303                self.website_value_label.set_markup("<a href=\"%s\">%s</a>"%(pkg["homepage"],pkg["homepage"]))
304                self.app_name_label.set_text(pkg["name"])
305                self.short_description_label.set_text(pkg["summary"])
306                h=html2text.HTML2Text()
307                h.body_width=500
308                txt=h.handle(pkg["description"])
309                txt=txt.replace("&lt;", "<")
310                txt=txt.replace("&gt;", ">")
311                txt=txt.replace("&amp;", "&")
312                self.full_description_label.set_text(txt)
313               
314                if info["installed"]:
315                        self.install_stack.set_visible_child_name("installed")
316                else:
317                        self.install_stack.set_visible_child_name("install")
318                       
319               
320                info["image_path"]=self.core.resources.get_icon(pkg)
321                info["image_id"]=pkg["icon"]+"_icon"
322                info["x"]=self.icon_size
323                info["y"]=self.icon_size
324               
325                self.app_icon.set_from_file(info)
326               
327                for s in self.screenshots_box.get_children():
328                        self.screenshots_box.remove(s)
329               
330                count=0
331                for v in pkg["videos"]:
332                       
333                        image=Screenshot.ScreenshotNeo()
334                        info["video_url"]=v["url"].replace("http://metadata.tanglu.org/appstream/media/xenial/","").replace("https://www.youtube.com/watch?v=","https://www.youtube.com/embed/")
335                        info["image_url"]=v["preview"]
336                        info["image_id"]=pkg["package"]+"_video_"+str(count)
337                        info["x"]=self.screenshot_small
338                        info["y"]=self.screenshot_small
339                       
340                        image.set_video_info(info)
341                       
342                        b=Gtk.Button()
343                        b.set_name("RELATED_BUTTON")
344                        b.add(image)
345                        self.screenshots_box.pack_start(b,False,False,5)
346                       
347                        count+=1
348                       
349                count=0
350                for s in pkg["screenshots"]:
351                       
352                        image=Screenshot.ScreenshotNeo()
353                        i={}
354                       
355                        i["image_url"]=s
356                        i["image_id"]=pkg["package"]+"_screenshot_"+str(count)
357                        i["x"]=self.screenshot_small
358                        i["y"]=self.screenshot_small
359                        i["aspect_ratio"]=False
360                                               
361                        image.download_image(i)
362                        b=Gtk.Button()
363                        b.set_name("RELATED_BUTTON")
364                        b.add(image)
365                        self.screenshots_box.pack_start(b,False,False,5)
366                        count+=1
367               
368                self.screenshots_box.show_all()
369
370                for p in self.related_box.get_children():
371                        self.related_box.remove(p)
372               
373                categories=copy.deepcopy(pkg["categories"])
374               
375                self.related=None
376               
377                self.related_thread=threading.Thread(target=self.search_related_packages_from_categories_thread,args=(pkg["package"],categories,self.current_id))
378                self.related_thread.daemon=True
379                self.related_thread.start()
380                GLib.timeout_add(500,self.related_pkg_listener,self.current_id)
381               
382                '''
383                for p in pkg["related_packages"]:
384                       
385                        image=Screenshot.ScreenshotNeo()
386
387                        i={}
388                        i["image_id"]=p["package"]+"_banner_small"
389                        i["x"]=self.banner_small
390                        i["y"]=self.banner_small
391                        i["name"]=p["package"].capitalize()
392                        i["package"]=p["package"]
393                        i["icon"]=p["icon"]
394                        i["component"]=p["component"]
395
396                        if p["banner"]!=None:
397                                i["image_url"]=p["banner"]
398                                i["custom_frame"]=False
399                        else:
400                                i["image_path"]=self.core.resources.get_icon(p)
401                                i["custom_frame"]=True
402                               
403                        if not i["custom_frame"]:
404                                image.download_image(i)
405                        else:
406                                i["force_text"]=True
407                                image.create_banner_from_file(i)
408                       
409                        b=Gtk.Button()
410                        b.add(image)
411                        b.set_size_request(self.banner_small,self.banner_small)
412                        b.set_margin_top(10)
413                        b.connect("clicked",self.related_app_clicked,p)
414                        b.set_name("RELATED_BUTTON")
415                        b.set_valign(Gtk.Align.CENTER)
416                        b.set_tooltip_text(p["name"])
417                        self.related_box.pack_start(b,False,False,3)
418               
419                self.related_sw.get_hadjustment().set_value(0)
420                self.related_box.show_all()
421                '''
422               
423                for x in self.screenshots_box.get_children():
424                        x.connect("clicked",self.core.main_window.screenshot_clicked)
425               
426               
427        #def set_values
428       
429       
430        def search_related_packages_from_categories_thread(self,pkg,categories,id):
431
432                self.related=self.core.store.get_random_packages_from_categories(pkg,categories)
433               
434        #def search_related_packages_from_categories_thread
435       
436        def related_pkg_listener(self,id):
437               
438                if id!=self.current_id:
439                        return False
440                       
441                if self.related_thread.is_alive():
442                        return True
443                       
444                if self.related!=None:
445                       
446                       
447                        for p in self.related["related_packages"]:
448                               
449                                image=Screenshot.ScreenshotNeo()
450
451                                i={}
452                                i["image_id"]=p["package"]+"_banner_small"
453                                i["x"]=self.banner_small
454                                i["y"]=self.banner_small
455                                i["name"]=p["package"].capitalize()
456                                i["package"]=p["package"]
457                                i["icon"]=p["icon"]
458                                i["component"]=p["component"]
459
460                                if p["banner"]!=None:
461                                        i["image_url"]=p["banner"]
462                                        i["custom_frame"]=False
463                                else:
464                                        i["image_path"]=self.core.resources.get_icon(p)
465                                        i["custom_frame"]=True
466                                       
467                                if not i["custom_frame"]:
468                                        image.download_image(i)
469                                else:
470                                        i["force_text"]=True
471                                        image.create_banner_from_file(i)
472                               
473                                b=Gtk.Button()
474                                b.add(image)
475                                b.set_size_request(self.banner_small,self.banner_small)
476                                b.set_margin_top(10)
477                                b.connect("clicked",self.related_app_clicked,p)
478                                b.set_name("RELATED_BUTTON")
479                                b.set_valign(Gtk.Align.CENTER)
480                                b.set_tooltip_text(p["name"])
481                                self.related_box.pack_start(b,False,False,3)
482                       
483                        self.related_sw.get_hadjustment().set_value(0)
484                        self.related_box.show_all()                     
485                       
486                       
487                return False
488                       
489        #def related_pkg_listener
490       
491       
492        def set_css_info(self):
493               
494                self.style_provider=Gtk.CssProvider()
495                f=Gio.File.new_for_path(self.core.rsrc_dir+"lliurex-store.css")
496                self.style_provider.load_from_file(f)
497                Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),self.style_provider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
498               
499                self.set_name("DETAILS_BOX")
500               
501                self.details_divider.set_name("DIVIDER")
502                self.description_divider.set_name("DIVIDER")
503                self.related_divider.set_name("DIVIDER")
504               
505                self.details_label.set_name("DETAILS_LABEL")
506                self.version_label.set_name("DETAILS_OPTIONS")
507                self.category_label.set_name("DETAILS_OPTIONS")
508                self.license_label.set_name("DETAILS_OPTIONS")
509                self.size_label.set_name("DETAILS_OPTIONS")
510                self.website_label.set_name("DETAILS_OPTIONS")
511               
512                self.version_value_label.set_name("DETAILS_VALUES")
513                self.category_value_label.set_name("DETAILS_VALUES")
514                self.license_value_label.set_name("DETAILS_VALUES")
515                self.size_value_label.set_name("DETAILS_VALUES")
516                self.website_value_label.set_name("DETAILS_VALUES")
517               
518                self.app_name_label.set_name("TITLE")
519                self.short_description_label.set_name("SHORT_DESCRIPTION")
520                self.full_description_label.set_name("FULL_DESCRIPTION")
521               
522                self.related_label.set_name("RELATED_LABEL")
523               
524                self.install_button.set_name("INSTALL_BUTTON")
525                self.install_label.set_name("DETAILS_LABEL")
526                self.uninstall_button.set_name("UNINSTALL_BUTTON")
527                self.open_button.set_name("INSTALL_BUTTON")
528               
529        #def set-css_info
530       
531       
532        def related_app_clicked(self,widget,app):
533               
534                self.core.main_window.load_pkg_data(app["package"])
535               
536        #def related_app_clicked
537       
538       
539        def install_clicked(self,widget):
540               
541                self.install_label.set_text("Installing...")
542                self.install_stack.set_visible_child_name("progress")
543               
544                t=threading.Thread(target=self.install_pkg)
545                t.daemon=True
546                t.start()
547                GLib.timeout_add(100,self.pulse_pbar,t,"installed","install")
548               
549        #def install_clicked
550       
551       
552        def uninstall_clicked(self,widget):
553               
554                self.install_label.set_text("Uninstalling...")
555                self.install_stack.set_visible_child_name("progress")
556               
557                t=threading.Thread(target=self.uninstall_pkg)
558                t.daemon=True
559                t.start()
560                GLib.timeout_add(100,self.pulse_pbar,t,"install","installed")
561               
562        #def install_clicked
563       
564               
565        def pulse_pbar(self,t,target,fallback):
566               
567                if t.is_alive():
568                        self.install_pbar.pulse()
569                        return True
570               
571               
572                if self.thread_ret:
573                        self.install_stack.set_visible_child_name(target)
574                else:
575                        self.install_stack.set_visible_child_name(fallback)
576               
577                return False
578               
579        #def pulse_pbar
580       
581       
582        def install_pkg(self):
583               
584                pkg=self.core.main_window.current_pkg["package"]
585                self.thread_ret=self.core.store.install_package(pkg)
586               
587        #def install_pkg
588       
589       
590        def uninstall_pkg(self):
591               
592                pkg=self.core.main_window.current_pkg["package"]
593                self.thread_ret=self.core.store.uninstall_package(pkg)
594               
595        #def uninstall_pkg
596       
597       
598        def open_clicked(self,widget):
599                if self.core.main_window.current_pkg["name"].endswith('.snap'):
600                        snap=self.core.main_window.current_pkg["name"].replace('.snap','')
601                        if os.path.exists("/snap/bin/%s"%snap):
602                                Popen(["/snap/bin/%s"%snap])
603                elif self.core.main_window.current_pkg["package"].endswith('.appimage'):
604                        appimg=self.core.main_window.current_pkg["package"].lower()
605                        if os.path.exists(os.getenv("HOME")+"/.local/bin/%s"%appimg):
606                                Popen([os.getenv("HOME")+"/.local/bin/%s"%appimg])
607#                               os.system(os.getenv("HOME")+"/.local/bin/%s"%appimg)
608                elif 'Zomando' in self.core.main_window.current_pkg["categories"]:
609                        zmd=self.core.main_window.current_pkg["id"]+".zmd"
610                        if os.path.exists("/usr/share/zero-center/zmds/%s"%zmd):
611                                Popen(["pe", "/usr/share/zero-center/zmds/%s"%zmd])
612                else:
613                        desktop=self.core.main_window.current_pkg["id"]
614                        if os.path.exists("/usr/share/applications/%s"%desktop):
615                                os.system("gtk-launch %s"%desktop)
616               
617        #def open_clicked
618       
Note: See TracBrowser for help on using the repository browser.