Daniel Brötzmann pushed to branch mainwindow at gajim / gajim
Commits: dd1451d5 by wurstsalat at 2021-05-17T21:33:03+02:00 Add AppSideBar and AppPage
- - - - -
8 changed files:
- + gajim/data/gui/app_page.ui - gajim/data/gui/main.ui - gajim/data/style/gajim.css - + gajim/gtk/app_page.py - + gajim/gtk/app_side_bar.py - gajim/gtk/main.py - gajim/gtk/main_stack.py - gajim/gui_interface.py
Changes:
===================================== gajim/data/gui/app_page.ui ===================================== @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 --> +<interface> + <requires lib="gtk+" version="3.24"/> + <object class="GtkBox" id="gajim_update"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkButton"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="tooltip-text" translatable="yes">Dismiss</property> + <property name="valign">center</property> + <signal name="clicked" handler="_on_dismiss_update_clicked" swapped="no"/> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">window-close-symbolic</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton"> + <property name="label" translatable="yes">Website</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="valign">center</property> + <signal name="clicked" handler="_on_visit_website_clicked" swapped="no"/> + <style> + <class name="suggested-action"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="valign">center</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes">Gajim Update</property> + <property name="ellipsize">end</property> + <property name="max-width-chars">30</property> + <property name="xalign">0</property> + <style> + <class name="bold"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="update_message"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">start</property> + <property name="ellipsize">end</property> + <property name="max-width-chars">30</property> + <property name="xalign">0</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <style> + <class name="padding-6"/> + </style> + </object> + <object class="GtkBox" id="gajim_update_check"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkButton"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="tooltip-text" translatable="yes">Dismiss</property> + <property name="valign">center</property> + <signal name="clicked" handler="_on_dismiss_check_clicked" swapped="no"/> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">window-close-symbolic</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton"> + <property name="label" translatable="yes">Yes</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="valign">center</property> + <signal name="clicked" handler="_on_check_clicked" swapped="no"/> + <style> + <class name="suggested-action"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="valign">center</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes">Update Check</property> + <property name="ellipsize">end</property> + <property name="max-width-chars">30</property> + <property name="xalign">0</property> + <style> + <class name="bold"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes">Search for Gajim updates periodically?</property> + <property name="ellipsize">end</property> + <property name="max-width-chars">30</property> + <property name="xalign">0</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <style> + <class name="padding-6"/> + </style> + </object> +</interface>
===================================== gajim/data/gui/main.ui ===================================== @@ -67,21 +67,13 @@ </packing> </child> <child> - <object class="GtkBox"> + <object class="GtkBox" id="app_box"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="orientation">vertical</property> <property name="spacing">12</property> <child> - <object class="GtkImage" id="app_image"> - <property name="visible">True</property> - <property name="can-focus">False</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> + <placeholder/> </child> <child> <object class="GtkSeparator"> @@ -91,11 +83,12 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> + <property name="pack-type">end</property> <property name="position">1</property> </packing> </child> <style> - <class name="app-image-box"/> + <class name="app-page-box"/> </style> </object> <packing>
===================================== gajim/data/style/gajim.css ===================================== @@ -144,9 +144,19 @@ background: @theme_bg_color; }
-.app-image-box { margin: 12px 12px 0px 12px; } -.app-image-box > separator { +.app-page-box { + margin-top: 6px; +} +.app-page-box > separator { background-color: darker(@theme_bg_color); + margin-left: 12px; + margin-right: 12px; +} +.app-page { + padding: 18px; +} +.app-message-listbox row { + border: 1px solid @borders; }
/* Workspace sidebar */
===================================== gajim/gtk/app_page.py ===================================== @@ -0,0 +1,117 @@ +# This file is part of Gajim. +# +# Gajim is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; version 3 only. +# +# Gajim is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Gajim. If not, see http://www.gnu.org/licenses/. + +from gi.repository import GObject +from gi.repository import Gtk + +from gajim.common import app +from gajim.common.helpers import open_uri +from gajim.common.i18n import _ + +from .util import get_builder + + +class AppPage(Gtk.Box): + + __gsignals__ = { + 'unread-count-changed': (GObject.SignalFlags.RUN_LAST, + None, + (int, )), + } + + def __init__(self): + Gtk.Box.__init__(self, + orientation=Gtk.Orientation.VERTICAL, + spacing=12) + self.get_style_context().add_class('app-page') + + self._unread_count = 0 + + update_label = Gtk.Label(label=_('Updates')) + update_label.get_style_context().add_class('large-header') + self.add(update_label) + + self._app_message_listbox = AppMessageListBox() + self.add(self._app_message_listbox) + + self.show_all() + + def add_app_message(self, category, message): + self._app_message_listbox.add_app_message(category, message) + + self._unread_count += 1 + self.emit('unread-count-changed', self._unread_count) + + def remove_app_message(self): + self._unread_count -= 1 + self.emit('unread-count-changed', self._unread_count) + + def process_event(self, event): + pass + + +class AppMessageListBox(Gtk.ListBox): + def __init__(self): + Gtk.ListBox.__init__(self) + self.set_selection_mode(Gtk.SelectionMode.NONE) + self.set_halign(Gtk.Align.CENTER) + self.set_size_request(400, -1) + self.get_style_context().add_class('app-message-listbox') + + placeholder = Gtk.Label(label=_('No updates available')) + placeholder.get_style_context().add_class('dim-label') + placeholder.show() + self.set_placeholder(placeholder) + + self.show_all() + + def add_app_message(self, category, message): + row = AppMessageRow(category, message) + self.add(row) + + def remove_app_message(self, row): + self.remove(row) + self.get_parent().remove_app_message() + + +class AppMessageRow(Gtk.ListBoxRow): + def __init__(self, category, message=None): + Gtk.ListBoxRow.__init__(self) + self._ui = get_builder('app_page.ui') + + if category == 'gajim-update-check': + self.add(self._ui.gajim_update_check) + + if category == 'gajim-update': + self.add(self._ui.gajim_update) + text = _('Version %s is available') % message + self._ui.update_message.set_text(text) + + self._ui.connect_signals(self) + self.show_all() + + def _on_check_clicked(self, _button): + app.interface.get_latest_release() + self.get_parent().remove_app_message(self) + + def _on_dismiss_check_clicked(self, _button): + app.settings.set('check_for_update', False) + self.get_parent().remove_app_message(self) + + def _on_visit_website_clicked(self, _button): + open_uri('https://gajim.org/download') + self.get_parent().remove_app_message(self) + + def _on_dismiss_update_clicked(self, _button): + self.get_parent().remove_app_message(self)
===================================== gajim/gtk/app_side_bar.py ===================================== @@ -0,0 +1,81 @@ +# This file is part of Gajim. +# +# Gajim is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; version 3 only. +# +# Gajim is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Gajim. If not, see http://www.gnu.org/licenses/. + +from gi.repository import Gtk + +from gajim.common import app + +from gajim.gui.util import load_icon + + +class AppSideBar(Gtk.ListBox): + def __init__(self, app_page): + Gtk.ListBox.__init__(self) + self.set_selection_mode(Gtk.SelectionMode.NONE) + self.set_valign(Gtk.Align.START) + self.get_style_context().add_class('workspace-sidebar') + + self.connect('row-activated', self._on_app_row_activated) + + app_page.connect('unread-count-changed', self._on_unread_count_changed) + + self._app_row = AppRow() + self.add(self._app_row) + + self.show_all() + + @staticmethod + def _on_app_row_activated(_listbox, _row): + app.window.show_app_page() + + def _on_unread_count_changed(self, _app_page, count): + self._app_row.set_unread_count(count) + + +class AppRow(Gtk.ListBoxRow): + def __init__(self): + Gtk.ListBoxRow.__init__(self) + self.get_style_context().add_class('workspace-sidebar-item') + + self._unread_label = Gtk.Label() + self._unread_label.get_style_context().add_class( + 'unread-counter') + self._unread_label.set_no_show_all(True) + self._unread_label.set_halign(Gtk.Align.END) + self._unread_label.set_valign(Gtk.Align.START) + + surface = load_icon('org.gajim.Gajim', self, 40) + image = Gtk.Image.new_from_surface(surface) + + selection_bar = Gtk.Box() + selection_bar.set_size_request(6, -1) + selection_bar.get_style_context().add_class('selection-bar') + + item_box = Gtk.Box() + item_box.add(selection_bar) + item_box.add(image) + + overlay = Gtk.Overlay() + overlay.add(item_box) + overlay.add_overlay(self._unread_label) + + self.add(overlay) + self.show_all() + + def set_unread_count(self, count): + if count < 1000: + self._unread_label.set_text(str(count)) + else: + self._unread_label.set_text('999+') + self._unread_label.set_visible(bool(count))
===================================== gajim/gtk/main.py ===================================== @@ -13,12 +13,12 @@
from gajim.gui.adhoc import AdHocCommand from gajim.gui.account_side_bar import AccountSideBar +from gajim.gui.app_side_bar import AppSideBar from gajim.gui.workspace_side_bar import WorkspaceSideBar from gajim.gui.main_stack import MainStack from gajim.gui.dialogs import DialogButton from gajim.gui.dialogs import ConfirmationDialog from gajim.gui.util import get_builder -from gajim.gui.util import load_icon
from .util import open_window
@@ -42,14 +42,15 @@ def __init__(self):
self.add(self._ui.main_grid)
- surface = load_icon('org.gajim.Gajim', self, 40) - self._ui.app_image.set_from_surface(surface) - self._main_stack = MainStack() self._ui.main_grid.add(self._main_stack)
self._chat_page = self._main_stack.get_chat_page()
+ self._app_page = self._main_stack.get_app_page() + self._app_side_bar = AppSideBar(self._app_page) + self._ui.app_box.add(self._app_side_bar) + self._workspace_side_bar = WorkspaceSideBar(self._chat_page) self._ui.workspace_scrolled.add(self._workspace_side_bar)
@@ -334,6 +335,12 @@ def _add_to_roster(_action, param): _workspace, account, jid = param.unpack() open_window('AddContact', account=account, jid=jid)
+ def show_app_page(self): + self._main_stack.show_app_page() + + def add_app_message(self, category, message=None): + self._app_page.add_app_message(category, message) + def get_control(self, *args, **kwargs): return self._chat_page.get_control(*args, **kwargs)
===================================== gajim/gtk/main_stack.py ===================================== @@ -16,6 +16,7 @@
from gajim.common import app
+from .app_page import AppPage from .chat_page import ChatPage from .account_page import AccountPage
@@ -26,6 +27,9 @@ def __init__(self):
self.add_named(Gtk.Box(), 'empty')
+ self._app_page = AppPage() + self.add_named(self._app_page, 'app') + self._chat_page = ChatPage() self._chat_page.connect('chat-selected', self._on_chat_selected) self.add_named(self._chat_page, 'chats') @@ -44,6 +48,12 @@ def remove_account_page(self, account): def remove_chats_for_account(self, account): self._chat_page.remove_chats_for_account(account)
+ def show_app_page(self): + self.set_visible_child_name('app') + + def get_app_page(self): + return self.get_child_by_name('app') + def show_chats(self, workspace_id): self._chat_page.show_workspace_chats(workspace_id) self.set_visible_child_name('chats')
===================================== gajim/gui_interface.py ===================================== @@ -91,7 +91,6 @@ from gajim.gui.dialogs import WarningDialog from gajim.gui.dialogs import InformationDialog from gajim.gui.dialogs import ConfirmationDialog -from gajim.gui.dialogs import ConfirmationCheckDialog from gajim.gui.dialogs import InputDialog from gajim.gui.dialogs import PassphraseDialog from gajim.gui.filechoosers import FileChooserDialog @@ -1710,35 +1709,21 @@ def check_for_updates(self): now = datetime.now() last_check = app.settings.get('last_update_check') if not last_check: - def _on_cancel(): - app.settings.set('check_for_update', False) - - def _on_check(): - self._get_latest_release() - - ConfirmationDialog( - _('Update Check'), - _('Gajim Update Check'), - _('Search for Gajim updates periodically?'), - [DialogButton.make('Cancel', - text=_('_No'), - callback=_on_cancel), - DialogButton.make('Accept', - text=_('_Search Periodically'), - callback=_on_check)]).show() + app.window.add_app_message('gajim-update-check') return
last_check_time = datetime.strptime(last_check, '%Y-%m-%d %H:%M') if (now - last_check_time).days < 7: return
- self._get_latest_release() + self.get_latest_release()
- def _get_latest_release(self): + def get_latest_release(self): log.info('Checking for Gajim updates') session = Soup.Session() session.props.user_agent = 'Gajim %s' % app.version - message = Soup.Message.new('GET', 'https://gajim.org/current-version.json') + message = Soup.Message.new( + 'GET', 'https://gajim.org/current-version.json') session.queue_message(message, self._on_update_checked)
def _on_update_checked(self, _session, message): @@ -1754,27 +1739,7 @@ def _on_update_checked(self, _session, message): latest_version = data['current_version']
if V(latest_version) > V(app.version): - def _on_cancel(is_checked): - if is_checked: - app.settings.set('check_for_update', False) - - def _on_update(is_checked): - if is_checked: - app.settings.set('check_for_update', False) - helpers.open_uri('https://gajim.org/download') - - ConfirmationCheckDialog( - _('Update Available'), - _('Gajim Update Available'), - _('There is an update available for Gajim ' - '(latest version: %s)') % str(latest_version), - _('_Do not show again'), - [DialogButton.make('Cancel', - text=_('_Later'), - callback=_on_cancel), - DialogButton.make('Accept', - text=_('_Update Now'), - callback=_on_update)]).show() + app.window.add_app_message('gajim-update', latest_version) else: log.info('Gajim is up to date')
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/dd1451d50b394e4a94abd1c9afaa94353...