[rigo] App Rating integration, NotificationBox Context support, a lot of other improvements
This commit is contained in:
@@ -1,66 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="150"
|
||||
height="40"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="comment-separator.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4"
|
||||
inkscape:cx="-72.515822"
|
||||
inkscape:cy="26.150743"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="744"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Livello 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1012.3622)">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#aaaaaa;fill-opacity:1;stroke:none"
|
||||
id="path2985"
|
||||
sodipodi:cx="64.285713"
|
||||
sodipodi:cy="45"
|
||||
sodipodi:rx="20"
|
||||
sodipodi:ry="20"
|
||||
d="m 84.285713,45 a 20,20 0 1 1 -40,0 20,20 0 1 1 40,0 z"
|
||||
transform="matrix(0.76580796,0,0,0.76580796,25.769489,997.90084)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -106,6 +106,7 @@ GtkInfoBar #message-area-error GtkLabel {
|
||||
}
|
||||
|
||||
/* Application View Comment Box */
|
||||
|
||||
#comment-box-title {
|
||||
color: #613056; /* purple */
|
||||
}
|
||||
@@ -114,4 +115,4 @@ GtkInfoBar #message-area-error GtkLabel {
|
||||
}
|
||||
#comment-box-author {
|
||||
color: brown;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<signal name="delete-event" handler="onDeleteWindow" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkVBox" id="appVbox">
|
||||
<property name="width_request">600</property>
|
||||
<property name="width_request">650</property>
|
||||
<property name="height_request">400</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
@@ -264,11 +264,21 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkVBox" id="appViewCommentsVbox">
|
||||
<object class="GtkAlignment" id="appViewCommentsAlign">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="top_padding">5</property>
|
||||
<property name="left_padding">25</property>
|
||||
<property name="right_padding">25</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
<object class="GtkVBox" id="appViewCommentsVbox">
|
||||
<property name="width_request">300</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -278,11 +288,21 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkVBox" id="appViewMyCommentsVbox">
|
||||
<object class="GtkAlignment" id="appViewMyCommentsAlign">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="bottom_padding">5</property>
|
||||
<property name="left_padding">25</property>
|
||||
<property name="right_padding">25</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
<object class="GtkVBox" id="appViewMyCommentsVbox">
|
||||
<property name="width_request">300</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -295,20 +315,6 @@
|
||||
<object class="GtkVBox" id="appViewCommentsWriteVbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="appViewCommentWriteLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes"><small><i>Comment this <b>Application</b></i></small></property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="appViewCommentTextAlign">
|
||||
<property name="visible">True</property>
|
||||
@@ -332,7 +338,7 @@
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
@@ -341,13 +347,20 @@
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="appViewCommentSendButton">
|
||||
<property name="label" translatable="yes">_Send</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="image">appViewCommentSendImage1</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="appViewCommentSendButtonLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_Write a <b>comment</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
@@ -360,7 +373,19 @@
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">4</property>
|
||||
<property name="position">3</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="appViewCommentMoreLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label">Want to see more?</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -36,12 +36,13 @@ from entropy.client.services.interfaces import ClientWebService
|
||||
import entropy.tools
|
||||
|
||||
from rigo.enums import Icons
|
||||
from rigo.utils import build_application_store_url
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
class ReviewStats(object):
|
||||
|
||||
NO_RATING = 1
|
||||
NO_RATING = 0
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
@@ -816,12 +817,17 @@ class Application(object):
|
||||
else:
|
||||
use_txt += _("No use flags")
|
||||
|
||||
text = "<small>%s\n%s\n%s\n%s\n%s</small>" % (
|
||||
more_txt = "<a href=\"%s\"><b>%s</b></a>" % (
|
||||
build_application_store_url(self, ""),
|
||||
_("Click here for more details"),)
|
||||
|
||||
text = "<small>%s\n%s\n%s\n%s\n%s\n\n%s</small>" % (
|
||||
down_size_txt,
|
||||
required_space_txt,
|
||||
licenses_txt,
|
||||
digest_txt,
|
||||
use_txt,
|
||||
more_txt,
|
||||
)
|
||||
return text
|
||||
|
||||
|
||||
@@ -32,6 +32,27 @@ class CommentBox(Gtk.VBox):
|
||||
self._is_last = is_last
|
||||
|
||||
def render(self):
|
||||
|
||||
vbox = Gtk.VBox()
|
||||
|
||||
ts_id = Document.DOCUMENT_TIMESTAMP_ID
|
||||
user_id = DocumentFactory.DOCUMENT_USERNAME_ID
|
||||
label = Gtk.Label()
|
||||
time_str = entropy.tools.convert_unix_time_to_human_time(
|
||||
self._comment[ts_id])
|
||||
time_str = GObject.markup_escape_text(time_str)
|
||||
label.set_markup(
|
||||
"<small><b>%s</b>" % (self._comment[user_id],) \
|
||||
+ ", <i>" + time_str + "</i>" \
|
||||
+ "</small>")
|
||||
label.set_line_wrap(True)
|
||||
label.set_line_wrap_mode(Pango.WrapMode.WORD)
|
||||
label.set_alignment(0.0, 1.0)
|
||||
label.set_selectable(True)
|
||||
label.set_name("comment-box-author")
|
||||
label.show()
|
||||
vbox.pack_start(label, False, False, 0)
|
||||
|
||||
# title, keywords, ddata, document_id
|
||||
title = self._comment['title'].strip()
|
||||
|
||||
@@ -45,7 +66,7 @@ class CommentBox(Gtk.VBox):
|
||||
label.set_alignment(0.0, 0.0)
|
||||
label.set_selectable(True)
|
||||
label.show()
|
||||
self.pack_start(label, False, False, 0)
|
||||
vbox.pack_start(label, False, False, 0)
|
||||
|
||||
data_id = Document.DOCUMENT_DATA_ID
|
||||
label = Gtk.Label()
|
||||
@@ -56,29 +77,13 @@ class CommentBox(Gtk.VBox):
|
||||
label.set_alignment(0.0, 0.0)
|
||||
label.set_selectable(True)
|
||||
label.show()
|
||||
self.pack_start(label, False, False, 0)
|
||||
vbox.pack_start(label, False, False, 0)
|
||||
|
||||
ts_id = Document.DOCUMENT_TIMESTAMP_ID
|
||||
user_id = DocumentFactory.DOCUMENT_USERNAME_ID
|
||||
label = Gtk.Label()
|
||||
time_str = entropy.tools.convert_unix_time_to_human_time(
|
||||
self._comment[ts_id])
|
||||
time_str = GObject.markup_escape_text(time_str)
|
||||
label.set_markup(
|
||||
"<small><i>" + time_str \
|
||||
+ "</i>, <b>%s</b>" % (self._comment[user_id],) \
|
||||
+ "</small>")
|
||||
label.set_line_wrap(True)
|
||||
label.set_line_wrap_mode(Pango.WrapMode.WORD)
|
||||
label.set_alignment(0.98, 0.0)
|
||||
label.set_selectable(True)
|
||||
label.set_name("comment-box-author")
|
||||
label.show()
|
||||
self.pack_start(label, False, False, 0)
|
||||
|
||||
if not self._is_last:
|
||||
image = Gtk.Image.new_from_icon_name("comment-separator",
|
||||
Gtk.IconSize.BUTTON)
|
||||
image.set_pixel_size(50)
|
||||
self.pack_start(image, False, False, 0)
|
||||
image.show()
|
||||
if self._is_last:
|
||||
self.pack_start(vbox, False, False, 0)
|
||||
else:
|
||||
align = Gtk.Alignment()
|
||||
align.set_padding(0, 10, 0, 0)
|
||||
align.add(vbox)
|
||||
self.pack_start(align, False, False, 0)
|
||||
align.show_all()
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
|
||||
import subprocess
|
||||
|
||||
from gi.repository import Gtk, GLib, GObject
|
||||
|
||||
from rigo.utils import build_register_url, open_url
|
||||
|
||||
from entropy.i18n import _
|
||||
from entropy.services.client import WebService
|
||||
from entropy.misc import ParallelTask
|
||||
|
||||
|
||||
|
||||
class NotificationBox(Gtk.HBox):
|
||||
|
||||
"""
|
||||
@@ -14,7 +19,8 @@ class NotificationBox(Gtk.HBox):
|
||||
"""
|
||||
|
||||
def __init__(self, message, message_widget=None,
|
||||
message_type=None, tooltip=None):
|
||||
message_type=None, tooltip=None,
|
||||
context_id=None):
|
||||
Gtk.HBox.__init__(self)
|
||||
self._message = message
|
||||
# if not None, it will replace Gtk.Label(self._message)
|
||||
@@ -24,6 +30,7 @@ class NotificationBox(Gtk.HBox):
|
||||
if self._type is None:
|
||||
self._type = Gtk.MessageType.INFO
|
||||
self._tooltip = tooltip
|
||||
self._context_id = context_id
|
||||
|
||||
def add_button(self, text, clicked_callback):
|
||||
"""
|
||||
@@ -82,6 +89,15 @@ class NotificationBox(Gtk.HBox):
|
||||
bar.get_action_area().hide()
|
||||
self.pack_start(bar, True, True, 0)
|
||||
|
||||
def get_context_id(self):
|
||||
"""
|
||||
Multiple NotificationBox instances can
|
||||
share the same context_id. This information
|
||||
is useful when showing multiple notifications
|
||||
sharing the same context is unwanted.
|
||||
"""
|
||||
return self._context_id
|
||||
|
||||
|
||||
class UpdatesNotificationBox(NotificationBox):
|
||||
|
||||
@@ -118,7 +134,8 @@ class UpdatesNotificationBox(NotificationBox):
|
||||
|
||||
NotificationBox.__init__(self, msg,
|
||||
tooltip=_("Updates available, how about installing them?"),
|
||||
message_type=Gtk.MessageType.WARNING)
|
||||
message_type=Gtk.MessageType.WARNING,
|
||||
context_id="UpdatesNotificationBox")
|
||||
self.add_button(_("_Update System"), self._update)
|
||||
self.add_button(_("_Show"), self._show)
|
||||
self.add_destroy_button(_("_Ignore"))
|
||||
@@ -154,7 +171,8 @@ class RepositoriesUpdateNotificationBox(NotificationBox):
|
||||
|
||||
NotificationBox.__init__(self, msg,
|
||||
tooltip=_("I dunno dude, I'd say Yes"),
|
||||
message_type=Gtk.MessageType.ERROR)
|
||||
message_type=Gtk.MessageType.ERROR,
|
||||
context_id="RepositoriesUpdateNotificationBox")
|
||||
self.add_button(_("_Yes, why not?"), self._update)
|
||||
self.add_destroy_button(_("_No, thanks"))
|
||||
|
||||
@@ -185,17 +203,21 @@ class LoginNotificationBox(NotificationBox):
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, entropy_ws, app):
|
||||
def __init__(self, entropy_ws, app, context_id=None):
|
||||
self._entropy_ws = entropy_ws
|
||||
self._app = app
|
||||
self._repository_id = app.get_details().channelname
|
||||
if context_id is None:
|
||||
context_id = "LoginNotificationBox"
|
||||
|
||||
NotificationBox.__init__(self, None,
|
||||
message_widget=self._make_login_box(),
|
||||
tooltip=_("You need to login to Entropy Web Services"),
|
||||
message_type=Gtk.MessageType.WARNING)
|
||||
message_type=Gtk.MessageType.WARNING,
|
||||
context_id=context_id)
|
||||
|
||||
self.add_button(_("_Login"), self._login)
|
||||
self.add_button(_("Register"), self._register)
|
||||
|
||||
def _destroy(*args):
|
||||
self.emit("login-failed", self._app)
|
||||
@@ -277,3 +299,8 @@ class LoginNotificationBox(NotificationBox):
|
||||
task.daemon = True
|
||||
task.start()
|
||||
|
||||
def _register(self, button):
|
||||
"""
|
||||
Register button click event.
|
||||
"""
|
||||
open_url(build_register_url())
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from entropy.const import etpConst
|
||||
from entropy.core.settings.base import SystemSettings
|
||||
from entropy.misc import ParallelTask
|
||||
|
||||
def build_application_store_url(app, sub_page):
|
||||
"""
|
||||
@@ -33,3 +35,15 @@ def build_register_url():
|
||||
Build User Account Registration Form URL.
|
||||
"""
|
||||
return os.path.join(etpConst['distro_website_url'], "register")
|
||||
|
||||
def open_url(url):
|
||||
"""
|
||||
Open the given URL using xdg-open
|
||||
"""
|
||||
def _open_url(url):
|
||||
subprocess.call(["xdg-open", url])
|
||||
|
||||
task = ParallelTask(_open_url, url)
|
||||
task.name = "UrlOpen"
|
||||
task.daemon = True
|
||||
task.start()
|
||||
|
||||
272
rigo/rigo_app.py
272
rigo/rigo_app.py
@@ -169,6 +169,7 @@ class NotificationViewController(GObject.Object):
|
||||
self._box = notification_box
|
||||
self._updates = None
|
||||
self._security_updates = None
|
||||
self._context_id_map = {}
|
||||
|
||||
def setup(self):
|
||||
GLib.timeout_add(3000, self._calculate_updates)
|
||||
@@ -238,10 +239,18 @@ class NotificationViewController(GObject.Object):
|
||||
"""
|
||||
self._avc.set_many_safe(self._updates)
|
||||
|
||||
def append(self, box, timeout=None):
|
||||
def append(self, box, timeout=None, context_id=None):
|
||||
"""
|
||||
Append a notification to the Notification area.
|
||||
context_id is used to automatically drop any other
|
||||
notification exposing the same context identifier.
|
||||
"""
|
||||
context_id = box.get_context_id()
|
||||
if context_id is not None:
|
||||
old_box = self._context_id_map.get(context_id)
|
||||
if old_box is not None:
|
||||
old_box.destroy()
|
||||
self._context_id_map[context_id] = box
|
||||
box.render()
|
||||
self._box.pack_start(box, False, False, 0)
|
||||
box.show()
|
||||
@@ -263,7 +272,7 @@ class NotificationViewController(GObject.Object):
|
||||
area, if there.
|
||||
"""
|
||||
if box in self._box.get_children():
|
||||
self._box.remove(box)
|
||||
self._context_id_map.pop(box.get_context_id(), None)
|
||||
box.destroy()
|
||||
|
||||
def remove_safe(self, box):
|
||||
@@ -277,8 +286,8 @@ class NotificationViewController(GObject.Object):
|
||||
Clear all the notifications.
|
||||
"""
|
||||
for child in self._box.get_children():
|
||||
self._box.remove(child)
|
||||
child.destroy()
|
||||
self._context_id_map.clear()
|
||||
|
||||
def clear_safe(self):
|
||||
"""
|
||||
@@ -294,6 +303,19 @@ class ApplicationViewController(GObject.Object):
|
||||
TreeView.
|
||||
"""
|
||||
|
||||
class WindowedReactiveStar(ReactiveStar):
|
||||
|
||||
def __init__(self, window):
|
||||
self._window = window
|
||||
self._hand = Gdk.Cursor.new(Gdk.CursorType.HAND2)
|
||||
ReactiveStar.__init__(self)
|
||||
|
||||
def on_enter_notify(self, widget, event):
|
||||
self._window.get_window().set_cursor(self._hand)
|
||||
|
||||
def on_leave_notify(self, widget, event):
|
||||
self._window.get_window().set_cursor(None)
|
||||
|
||||
__gsignals__ = {
|
||||
# Double click on application widget
|
||||
"application-activated" : (GObject.SignalFlags.RUN_LAST,
|
||||
@@ -325,6 +347,9 @@ class ApplicationViewController(GObject.Object):
|
||||
),
|
||||
}
|
||||
|
||||
VOTE_NOTIFICATION_CONTEXT_ID = "VoteNotificationContext"
|
||||
COMMENT_NOTIFICATION_CONTEXT_ID = "CommentNotificationContext"
|
||||
|
||||
def __init__(self, entropy_client, entropy_ws, builder):
|
||||
GObject.Object.__init__(self)
|
||||
self._builder = builder
|
||||
@@ -334,14 +359,21 @@ class ApplicationViewController(GObject.Object):
|
||||
self._last_app = None
|
||||
self._nc = None
|
||||
|
||||
self._window = self._builder.get_object("rigoWindow")
|
||||
self._image = self._builder.get_object("appViewImage")
|
||||
self._app_name_lbl = self._builder.get_object("appViewNameLabel")
|
||||
self._app_info_lbl = self._builder.get_object("appViewInfoLabel")
|
||||
self._app_downloaded_lbl = self._builder.get_object(
|
||||
"appViewDownloadedLabel")
|
||||
self._app_comments_box = self._builder.get_object("appViewCommentsVbox")
|
||||
self._app_comments_box.set_name("comments-box")
|
||||
self._app_comments_align = self._builder.get_object(
|
||||
"appViewCommentsAlign")
|
||||
self._app_my_comments_box = self._builder.get_object(
|
||||
"appViewMyCommentsVbox")
|
||||
self._app_my_comments_align = self._builder.get_object(
|
||||
"appViewMyCommentsAlign")
|
||||
self._app_my_comments_box.set_name("comments-box")
|
||||
self._app_comment_send_button = self._builder.get_object(
|
||||
"appViewCommentSendButton")
|
||||
self._app_comment_text_view = self._builder.get_object(
|
||||
@@ -349,9 +381,12 @@ class ApplicationViewController(GObject.Object):
|
||||
self._app_comment_text_view.set_name("rigo-text-view")
|
||||
self._app_comment_text_buffer = self._builder.get_object(
|
||||
"appViewCommentTextBuffer")
|
||||
self._app_comment_more_label = self._builder.get_object(
|
||||
"appViewCommentMoreLabel")
|
||||
self._stars_container = self._builder.get_object("appViewStarsSelVbox")
|
||||
|
||||
self._stars = ReactiveStar()
|
||||
self._stars = ApplicationViewController.WindowedReactiveStar(
|
||||
self._window)
|
||||
self._stars_alignment = Gtk.Alignment.new(0.0, 0.5, 1.0, 1.0)
|
||||
self._stars_alignment.set_padding(0, 5, 0, 0)
|
||||
self._stars_alignment.add(self._stars)
|
||||
@@ -378,6 +413,7 @@ class ApplicationViewController(GObject.Object):
|
||||
self._app_comment_send_button.set_sensitive(False)
|
||||
self._app_comment_text_buffer.connect(
|
||||
"changed", self._on_comment_buffer_changed)
|
||||
self._stars.connect("changed", self._on_stars_clicked)
|
||||
|
||||
def _on_comment_buffer_changed(self, widget):
|
||||
"""
|
||||
@@ -411,6 +447,149 @@ class ApplicationViewController(GObject.Object):
|
||||
icon = self._app_store.get_icon(pkg_match)
|
||||
self._setup_application_stats(stats, icon)
|
||||
|
||||
def _on_stars_clicked(self, widget, app=None):
|
||||
"""
|
||||
Stars clicked, user wants to vote.
|
||||
"""
|
||||
if app is None:
|
||||
app = self._last_app
|
||||
if app is None:
|
||||
# wtf
|
||||
return
|
||||
|
||||
def _sender(app, vote):
|
||||
if not app.is_webservice_available():
|
||||
GLib.idle_add(self._notify_webservice_na, app,
|
||||
self.VOTE_NOTIFICATION_CONTEXT_ID)
|
||||
return
|
||||
ws_user = app.get_webservice_username()
|
||||
if ws_user is not None:
|
||||
GLib.idle_add(self._notify_vote_submit, app, ws_user, vote)
|
||||
else:
|
||||
GLib.idle_add(self._notify_login_request, app, vote,
|
||||
self._on_stars_login_success,
|
||||
self._on_stars_login_failed,
|
||||
self.VOTE_NOTIFICATION_CONTEXT_ID)
|
||||
|
||||
vote = int(self._stars.get_rating()) # is float
|
||||
task = ParallelTask(_sender, app, vote)
|
||||
task.name = "AppViewSendVote"
|
||||
task.start()
|
||||
|
||||
def _on_stars_login_success(self, widget, username, app):
|
||||
"""
|
||||
Notify user that we successfully logged in!
|
||||
"""
|
||||
box = NotificationBox(
|
||||
_("Logged in as <b>%s</b>! How about your <b>vote</b>?") \
|
||||
% (GObject.markup_escape_text(username),),
|
||||
message_type=Gtk.MessageType.INFO,
|
||||
context_id=self.VOTE_NOTIFICATION_CONTEXT_ID)
|
||||
|
||||
def _send_vote(widget):
|
||||
# widget.destroy()
|
||||
self._on_stars_clicked(self._stars, app=app)
|
||||
box.add_button(_("_Vote now"), _send_vote)
|
||||
|
||||
box.add_destroy_button(_("_Abort"))
|
||||
self._nc.append(box)
|
||||
|
||||
def _on_stars_login_failed(self, widget, app):
|
||||
"""
|
||||
Entropy Web Services Login failed message.
|
||||
"""
|
||||
box = NotificationBox(
|
||||
_("Login failed. Your <b>vote</b> hasn't been added"),
|
||||
message_type=Gtk.MessageType.ERROR,
|
||||
context_id=self.VOTE_NOTIFICATION_CONTEXT_ID)
|
||||
box.add_destroy_button(_("_Ok, thanks"))
|
||||
self._nc.append(box)
|
||||
|
||||
def _notify_vote_submit(self, app, username, vote):
|
||||
"""
|
||||
Notify User about Comment submission with current credentials.
|
||||
"""
|
||||
box = NotificationBox(
|
||||
_("Rate <b>%s</b> as <b>%s</b>, with <b>%d</b> stars?") \
|
||||
% (app.name, GObject.markup_escape_text(username),
|
||||
vote,),
|
||||
message_type=Gtk.MessageType.INFO,
|
||||
context_id=self.VOTE_NOTIFICATION_CONTEXT_ID)
|
||||
|
||||
def _vote_submit(widget):
|
||||
#box.destroy()
|
||||
self._vote_submit(app, username, vote)
|
||||
box.add_button(_("_Ok, cool!"), _vote_submit)
|
||||
|
||||
def _send_vote():
|
||||
self._on_stars_clicked(self._stars, app=app)
|
||||
def _logout_webservice(widget):
|
||||
#box.destroy()
|
||||
self._logout_webservice(app, _send_vote)
|
||||
box.add_button(_("_No, logout!"), _logout_webservice)
|
||||
|
||||
box.add_destroy_button(_("_Abort"))
|
||||
self._nc.append(box)
|
||||
|
||||
def _vote_submit(self, app, username, vote):
|
||||
"""
|
||||
Do the actual vote submit.
|
||||
"""
|
||||
task = ParallelTask(
|
||||
self._vote_submit_thread_body,
|
||||
app, username, vote)
|
||||
task.name = "VoteSubmitThreadBody"
|
||||
task.daemon = True
|
||||
task.start()
|
||||
|
||||
def _vote_submit_thread_body(self, app, username, vote):
|
||||
"""
|
||||
Called by _vote_submit(), does the actualy submit.
|
||||
"""
|
||||
repository_id = app.get_details().channelname
|
||||
webserv = self._entropy_ws.get(repository_id)
|
||||
if webserv is None:
|
||||
# impossible!
|
||||
return
|
||||
|
||||
key = app.get_details().pkgkey
|
||||
|
||||
err_msg = None
|
||||
try:
|
||||
voted = webserv.add_vote(
|
||||
key, vote)
|
||||
except WebService.WebServiceException as err:
|
||||
voted = False
|
||||
err_msg = str(err)
|
||||
|
||||
def _submit_success():
|
||||
nbox = NotificationBox(
|
||||
_("Your vote has been added!"),
|
||||
message_type=Gtk.MessageType.INFO,
|
||||
context_id=self.VOTE_NOTIFICATION_CONTEXT_ID)
|
||||
nbox.add_destroy_button(_("Ok, great!"))
|
||||
self._nc.append(nbox, timeout=10)
|
||||
self._on_redraw_request(None, app.get_details().pkg)
|
||||
|
||||
def _submit_fail(err_msg):
|
||||
if err_msg is None:
|
||||
box = NotificationBox(
|
||||
_("You already voted this <b>Application</b>"),
|
||||
message_type=Gtk.MessageType.ERROR,
|
||||
context_id=self.VOTE_NOTIFICATION_CONTEXT_ID)
|
||||
else:
|
||||
box = NotificationBox(
|
||||
_("Vote error: <i>%s</i>") % (err_msg,),
|
||||
message_type=Gtk.MessageType.ERROR,
|
||||
context_id=self.VOTE_NOTIFICATION_CONTEXT_ID)
|
||||
box.add_destroy_button(_("Ok, thanks"))
|
||||
self._nc.append(box)
|
||||
|
||||
if voted:
|
||||
GLib.idle_add(_submit_success)
|
||||
else:
|
||||
GLib.idle_add(_submit_fail, err_msg)
|
||||
|
||||
def __application_activate(self, app):
|
||||
"""
|
||||
Collect data from app, then call the UI setup in the main loop.
|
||||
@@ -456,19 +635,23 @@ class ApplicationViewController(GObject.Object):
|
||||
|
||||
def _sender(app, text):
|
||||
if not app.is_webservice_available():
|
||||
GLib.idle_add(self._notify_webservice_na, app)
|
||||
GLib.idle_add(self._notify_webservice_na, app,
|
||||
self.COMMENT_NOTIFICATION_CONTEXT_ID)
|
||||
return
|
||||
ws_user = app.get_webservice_username()
|
||||
if ws_user is not None:
|
||||
GLib.idle_add(self._notify_comment_submit, app, ws_user, text)
|
||||
else:
|
||||
GLib.idle_add(self._notify_login_request, app, text)
|
||||
GLib.idle_add(self._notify_login_request, app, text,
|
||||
self._on_comment_login_success,
|
||||
self._on_comment_login_failed,
|
||||
self.COMMENT_NOTIFICATION_CONTEXT_ID)
|
||||
|
||||
task = ParallelTask(_sender, app, text)
|
||||
task.name = "AppViewSendComment"
|
||||
task.start()
|
||||
|
||||
def _notify_webservice_na(self, app):
|
||||
def _notify_webservice_na(self, app, context_id):
|
||||
"""
|
||||
Notify Web Service unavailability for given Application object.
|
||||
"""
|
||||
@@ -476,7 +659,8 @@ class ApplicationViewController(GObject.Object):
|
||||
"%s: <b>%s</b>" % (
|
||||
_("Entropy Web Services not available for repository"),
|
||||
app.get_details().channelname),
|
||||
message_type=Gtk.MessageType.ERROR)
|
||||
message_type=Gtk.MessageType.ERROR,
|
||||
context_id=context_id)
|
||||
box.add_destroy_button(_("Ok, thanks"))
|
||||
self._nc.append(box)
|
||||
|
||||
@@ -487,15 +671,16 @@ class ApplicationViewController(GObject.Object):
|
||||
box = NotificationBox(
|
||||
_("You are about to add a <b>comment</b> as <b>%s</b>.") \
|
||||
% (GObject.markup_escape_text(username),),
|
||||
message_type=Gtk.MessageType.INFO)
|
||||
message_type=Gtk.MessageType.INFO,
|
||||
context_id=self.COMMENT_NOTIFICATION_CONTEXT_ID)
|
||||
|
||||
def _comment_submit(widget):
|
||||
box.destroy()
|
||||
#box.destroy()
|
||||
self._comment_submit(app, username, text)
|
||||
box.add_button(_("_Ok, cool!"), _comment_submit)
|
||||
|
||||
def _logout_webservice(widget):
|
||||
box.destroy()
|
||||
#box.destroy()
|
||||
self._logout_webservice(app)
|
||||
box.add_button(_("_No, logout!"), _logout_webservice)
|
||||
|
||||
@@ -544,7 +729,8 @@ class ApplicationViewController(GObject.Object):
|
||||
|
||||
nbox = NotificationBox(
|
||||
_("Your comment has been submitted!"),
|
||||
message_type=Gtk.MessageType.INFO)
|
||||
message_type=Gtk.MessageType.INFO,
|
||||
context_id=self.COMMENT_NOTIFICATION_CONTEXT_ID)
|
||||
nbox.add_destroy_button(_("Ok, great!"))
|
||||
self._app_comment_text_buffer.set_text("")
|
||||
self._nc.append(nbox, timeout=10)
|
||||
@@ -552,7 +738,8 @@ class ApplicationViewController(GObject.Object):
|
||||
def _submit_fail():
|
||||
box = NotificationBox(
|
||||
_("Comment submit error: <i>%s</i>") % (err_msg,),
|
||||
message_type=Gtk.MessageType.ERROR)
|
||||
message_type=Gtk.MessageType.ERROR,
|
||||
context_id=self.COMMENT_NOTIFICATION_CONTEXT_ID)
|
||||
box.add_destroy_button(_("Ok, thanks"))
|
||||
self._nc.append(box)
|
||||
|
||||
@@ -561,7 +748,7 @@ class ApplicationViewController(GObject.Object):
|
||||
else:
|
||||
GLib.idle_add(_submit_fail)
|
||||
|
||||
def _logout_webservice(self, app):
|
||||
def _logout_webservice(self, app, reinit_callback):
|
||||
"""
|
||||
Execute logout of current credentials from Web Service.
|
||||
Actually, this means removing the local cookie.
|
||||
@@ -571,17 +758,16 @@ class ApplicationViewController(GObject.Object):
|
||||
if webserv is not None:
|
||||
webserv.remove_credentials()
|
||||
|
||||
def _send_comment():
|
||||
self._on_send_comment(None, app=app)
|
||||
GLib.idle_add(_send_comment)
|
||||
GLib.idle_add(reinit_callback)
|
||||
|
||||
def _notify_login_request(self, app, text):
|
||||
def _notify_login_request(self, app, text, on_success, on_fail,
|
||||
context_id):
|
||||
"""
|
||||
Notify User that login is required
|
||||
"""
|
||||
box = LoginNotificationBox(self._entropy_ws, app)
|
||||
box.connect("login-success", self._on_comment_login_success)
|
||||
box.connect("login-failed", self._on_comment_login_failed)
|
||||
box.connect("login-success", on_success)
|
||||
box.connect("login-failed", on_fail)
|
||||
self._nc.append(box)
|
||||
|
||||
def _on_comment_login_success(self, widget, username, app):
|
||||
@@ -591,9 +777,10 @@ class ApplicationViewController(GObject.Object):
|
||||
box = NotificationBox(
|
||||
_("Logged in as <b>%s</b>! How about your <b>comment</b>?") \
|
||||
% (GObject.markup_escape_text(username),),
|
||||
message_type=Gtk.MessageType.INFO)
|
||||
message_type=Gtk.MessageType.INFO,
|
||||
context_id=self.COMMENT_NOTIFICATION_CONTEXT_ID)
|
||||
def _send_comment(widget):
|
||||
box.destroy()
|
||||
#box.destroy()
|
||||
self._on_send_comment(widget, app=app)
|
||||
box.add_button(_("_Send now"), _send_comment)
|
||||
box.add_destroy_button(_("_Abort"))
|
||||
@@ -605,7 +792,8 @@ class ApplicationViewController(GObject.Object):
|
||||
"""
|
||||
box = NotificationBox(
|
||||
_("Login failed. Your <b>comment</b> hasn't been added"),
|
||||
message_type=Gtk.MessageType.ERROR)
|
||||
message_type=Gtk.MessageType.ERROR,
|
||||
context_id=self.COMMENT_NOTIFICATION_CONTEXT_ID)
|
||||
box.add_destroy_button(_("_Ok, thanks"))
|
||||
self._nc.append(box)
|
||||
|
||||
@@ -624,33 +812,25 @@ class ApplicationViewController(GObject.Object):
|
||||
label.set_markup(
|
||||
_("<i>No <b>comments</b> for this Application, yet!</i>"))
|
||||
self._app_comments_box.pack_start(label, False, False, 1)
|
||||
|
||||
label = Gtk.Label()
|
||||
url = build_register_url()
|
||||
url = GObject.markup_escape_text(url)
|
||||
reg_msg = _("You need to <a href=\"%s\">register here</a>") % (
|
||||
url,)
|
||||
label.set_markup("<small>" + reg_msg + "</small>")
|
||||
label.show()
|
||||
self._app_comments_box.pack_start(label, False, False, 1)
|
||||
return
|
||||
|
||||
if has_more:
|
||||
button_box = Gtk.HButtonBox()
|
||||
button = Gtk.Button()
|
||||
button.set_label(_("Older comments"))
|
||||
button.set_alignment(0.5, 0.5)
|
||||
def _enqueue_download(widget):
|
||||
widget.hide()
|
||||
widget.get_parent().destroy()
|
||||
spinner = Gtk.Spinner()
|
||||
spinner.set_size_request(-1, 24)
|
||||
spinner.set_size_request(24, 24)
|
||||
spinner.set_tooltip_text(_("Loading older comments..."))
|
||||
spinner.set_name("comment-box-spinner")
|
||||
self._app_comments_box.pack_start(spinner, False, False, 3)
|
||||
self._app_comments_box.pack_end(spinner, False, False, 3)
|
||||
spinner.show()
|
||||
downloader.enqueue_download()
|
||||
button.connect("clicked", _enqueue_download)
|
||||
|
||||
button_box = Gtk.HButtonBox()
|
||||
button_box.pack_start(button, False, False, 0)
|
||||
self._app_comments_box.pack_start(button_box, False, False, 1)
|
||||
button_box.show_all()
|
||||
@@ -687,7 +867,7 @@ class ApplicationViewController(GObject.Object):
|
||||
self._app_downloaded_lbl.set_markup(down_msg)
|
||||
if icon:
|
||||
self._image.set_from_pixbuf(icon)
|
||||
self._stars.set_rating(stats.ratings_average - 1)
|
||||
self._stars.set_rating(stats.ratings_average)
|
||||
self._stars_alignment.show_all()
|
||||
|
||||
def _setup_application_info(self, app, metadata):
|
||||
@@ -699,7 +879,15 @@ class ApplicationViewController(GObject.Object):
|
||||
|
||||
# FIXME, lxnay complete
|
||||
# install/remove/update buttons
|
||||
# for the rest, point to the remote www service
|
||||
|
||||
|
||||
# only comments supported, point to the remote
|
||||
# www service for the rest
|
||||
self._app_comment_more_label.set_markup(
|
||||
"<b>%s</b>: <a href=\"%s\">%s</a>" % (
|
||||
_("Want to add images, etc?"),
|
||||
build_application_store_url(app, "ugc"),
|
||||
_("click here!"),))
|
||||
|
||||
stats = metadata['stats']
|
||||
icon = metadata['icon']
|
||||
@@ -733,16 +921,7 @@ class ApplicationViewController(GObject.Object):
|
||||
self._avc = avc
|
||||
self._offset = 0
|
||||
self._callback = callback
|
||||
self._avc.connect("application-hide", self.stop)
|
||||
self._task = ParallelTask(self._download)
|
||||
self._started = False
|
||||
|
||||
def stop(self, *args):
|
||||
"""
|
||||
Stop downloading comments, if we're still doing it.
|
||||
"""
|
||||
self._started = False
|
||||
print("Application-hide called, this is", self)
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
@@ -750,7 +929,6 @@ class ApplicationViewController(GObject.Object):
|
||||
Loop over until we have more of them to download.
|
||||
"""
|
||||
self._offset = 0
|
||||
self._started = True
|
||||
self._task.start()
|
||||
|
||||
def _download_callback(self, document_list):
|
||||
|
||||
Reference in New Issue
Block a user