Commit bf943160 authored by Roman Alifanov's avatar Roman Alifanov

redesign + changing the color of the row when the state is changed

parent 6c288648
......@@ -19,11 +19,11 @@ class CommandRunner:
yes_no_chars = 'yYдДnNнН'
self.dialog = dialog
self.textbuffer = dialog.get_child().get_child().get_child().get_buffer()
self.textbuffer = dialog.logdialog_textview.get_buffer()
def append_log(text):
GLib.idle_add(self.textbuffer.insert_at_cursor, text)
GLib.idle_add(dialog.get_child().get_child().get_child().scroll_to_mark,
GLib.idle_add(dialog.logdialog_textview.scroll_to_mark,
self.textbuffer.get_insert(), 0, False, 0.0, 1.0)
def remove_ansi_escape_sequences(text):
......
......@@ -3,6 +3,7 @@
<gresource prefix="/ru/eepm/PlayGUI">
<file>style.css</file>
<file preprocess="xml-stripblanks">window.ui</file>
<file preprocess="xml-stripblanks">logdialog.ui</file>
<file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
</gresource>
</gresources>
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
<cambalache-project version="0.92.0" target_tk="gtk-4.0">
<ui>
(1,1,"logdialog.ui","logdialog.ui",None,None,None,None,None,None,None)
</ui>
<ui_library>
(1,"adwaita","1.0",None),
(1,"gtk","4.0",None),
(1,"libadwaita","1.5",None)
</ui_library>
<object>
(1,1,"AdwDialog","LogDialog",None,None,None,None,0,None,None),
(1,2,"AdwClamp",None,1,None,None,None,0,None,None),
(1,3,"GtkBox",None,2,None,None,None,0,None,None),
(1,4,"GtkScrolledWindow",None,3,None,None,None,0,None,None),
(1,5,"GtkTextView","logdialog_textview",4,None,None,None,0,"",None)
</object>
<object_property>
(1,1,"AdwDialog","can-close","false",0,None,None,None,None,None,None,None,None),
(1,1,"AdwDialog","follows-content-size","true",0,None,None,None,None,None,None,None,None),
(1,1,"AdwDialog","title","Лог выполнения",0,None,None,None,None,None,None,None,None),
(1,2,"AdwClamp","maximum-size","500",0,None,None,None,None,None,None,None,None),
(1,2,"GtkWidget","margin-bottom","12",0,None,None,None,None,None,None,None,None),
(1,2,"GtkWidget","margin-end","12",0,None,None,None,None,None,None,None,None),
(1,2,"GtkWidget","margin-start","12",0,None,None,None,None,None,None,None,None),
(1,2,"GtkWidget","margin-top","12",0,None,None,None,None,None,None,None,None),
(1,3,"GtkBox","spacing","12",0,None,None,None,None,None,None,None,None),
(1,3,"GtkOrientable","orientation","vertical",0,None,None,None,None,None,None,None,None),
(1,4,"GtkWidget","height-request","259",0,None,None,None,None,None,None,None,None),
(1,4,"GtkWidget","vexpand","true",0,None,None,None,None,None,None,None,None),
(1,4,"GtkWidget","width-request","304",0,None,None,None,None,None,None,None,None),
(1,5,"GtkTextView","cursor-visible","false",0,None,None,None,None,None,None,None,None),
(1,5,"GtkTextView","editable","false",0,None,None,None,None,None,None,None,None),
(1,5,"GtkTextView","monospace","True",0,None,None,None,None,None,None,None,None),
(1,5,"GtkWidget","can-focus","False",None,None,None,None,None,None,None,None,None),
(1,5,"GtkWidget","can-target","False",None,None,None,None,None,None,None,None,None),
(1,5,"GtkWidget","focus-on-click","False",None,None,None,None,None,None,None,None,None)
</object_property>
</cambalache-project>
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.92.0 -->
<interface>
<!-- interface-name logdialog.ui -->
<requires lib="adwaita" version="1.0"/>
<requires lib="gtk" version="4.0"/>
<requires lib="libadwaita" version="1.5"/>
<template class="LogDialog" parent="AdwDialog">
<property name="can-close">false</property>
<property name="follows-content-size">true</property>
<property name="title">Лог выполнения</property>
<child>
<object class="AdwClamp">
<property name="margin-bottom">12</property>
<property name="margin-end">12</property>
<property name="margin-start">12</property>
<property name="margin-top">12</property>
<property name="maximum-size">500</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkScrolledWindow">
<property name="height-request">259</property>
<property name="vexpand">true</property>
<property name="width-request">304</property>
<child>
<object class="GtkTextView" id="logdialog_textview">
<property name="can-focus">False</property>
<property name="can-target">False</property>
<property name="cursor-visible">false</property>
<property name="editable">false</property>
<property name="focus-on-click">False</property>
<property name="monospace">True</property>
<!-- Custom object fragments -->
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>
......@@ -82,7 +82,7 @@
</object_data>
<object_data_arg>
(1,7,"GtkWidget",2,2,"name","linked"),
(1,12,"GtkWidget",2,2,"name","boxed-list"),
(1,12,"GtkWidget",2,2,"name","boxed-list-separate"),
(1,15,"GtkWidget",2,2,"name","boxed-list"),
(1,22,"GtkWidget",2,2,"name","suggested-action")
</object_data_arg>
......
......@@ -26,39 +26,54 @@ _ = gettext.gettext
from .appsmanager import ApplicationManager
from .command_runner import CommandRunner
class ApplicationRow(Adw.ActionRow):
def __init__(self, app, is_installed, on_toggle):
super().__init__(title=app['name'], subtitle=app['dscr'])
self.app = app
self.is_installed = is_installed
self.checkbox = Gtk.CheckButton()
self.checkbox.add_css_class("selection-mode")
self.checkbox.set_active(is_installed)
self.checkbox.connect("toggled", self.on_checkbox_toggled)
self.add_suffix(self.checkbox)
self.on_toggle = on_toggle # Callback for when the checkbox is toggled
def on_checkbox_toggled(self, checkbox):
self.on_toggle(self.app['name'], checkbox.get_active())
self.update_row_css() # Update the row's style when toggled
def is_changed(self):
"""Determine if the checkbox state has changed compared to the installed state."""
return self.checkbox.get_active() != self.is_installed
def update_row_css(self):
"""Update the CSS classes for the row based on the checkbox state."""
for css in ["marked-for-install", "marked-for-removal", "unchanged"]:
self.remove_css_class(css)
# Add the appropriate class based on the current checkbox state
if self.is_changed():
if self.checkbox.get_active():
self.add_css_class("marked-for-install")
print("marked-for-install")
else:
self.add_css_class("marked-for-removal")
print("marked-for-removal")
else:
# self.add_css_class("unchanged")
print("marked-unchanged")
@Gtk.Template(resource_path='/ru/eepm/PlayGUI/logdialog.ui')
class LogDialog(Adw.Dialog):
__gtype_name__ = 'LogDialog'
logdialog_textview = Gtk.Template.Child()
def __init__(self, win, **kwargs):
super().__init__(**kwargs)
self.set_title("Лог выполнения")
self.set_can_close(False)
self.set_follows_content_size(True)
self.win = win
dialog_clamp = Adw.Clamp(
margin_bottom=12,
margin_end=12,
margin_top=12,
margin_start=12,
maximum_size=500
)
textview = Gtk.TextView()
textview.set_editable(False)
textview.set_cursor_visible(False)
textbuffer = textview.get_buffer()
scrolled_window = Gtk.ScrolledWindow(
width_request=304,
height_request=259
)
scrolled_window.set_child(textview)
scrolled_window.set_vexpand(True)
dialog_clamp.set_child(scrolled_window)
self.set_child(dialog_clamp)
def run(self, command, on_done):
self.present(self.win)
# Создание и передача функции обратного вызова для обновления UI
......@@ -67,11 +82,10 @@ class LogDialog(Adw.Dialog):
@Gtk.Template(resource_path='/ru/eepm/PlayGUI/window.ui')
class EepmPlayGuiWindow(Adw.ApplicationWindow, LogDialog):
class EepmPlayGuiWindow(Adw.ApplicationWindow):
__gtype_name__ = 'EepmPlayGuiWindow'
search_entry = Gtk.Template.Child()
search_dropdown = Gtk.Template.Child()
loading_spinner = Gtk.Template.Child()
choice_listbox = Gtk.Template.Child()
apply_button = Gtk.Template.Child()
......@@ -82,10 +96,10 @@ class EepmPlayGuiWindow(Adw.ApplicationWindow, LogDialog):
self.checkboxes = None
self.apply_button.connect("activated", self.on_apply_clicked)
self.search_entry.connect("search-changed", self.on_search_changed)
self.search_dropdown.connect("notify::selected", self.on_filter_changed)
self.choice_listbox.set_filter_func(self.listbox_filter_func)
self.dialog = LogDialog(win=self)
......@@ -132,43 +146,39 @@ class EepmPlayGuiWindow(Adw.ApplicationWindow, LogDialog):
self.choice_listbox.remove_all()
def add_application_row(self, app):
row = Adw.ActionRow(
title=app['name'],
subtitle=app['dscr']
"""Adds an application row to the listbox."""
row = ApplicationRow(
app=app,
is_installed=app['name'] in self.installed_apps,
on_toggle=self.on_checkbox_toggled
)
checkbox = Gtk.CheckButton()
checkbox.add_css_class("selection-mode")
checkbox.set_active(app['name'] in self.installed_apps)
checkbox.connect("toggled", self.on_checkbox_toggled, app['name'])
row.add_suffix(checkbox)
self.choice_listbox.append(row)
self.checkboxes[app['name']] = checkbox
self.checkboxes[app['name']] = row
def on_checkbox_toggled(self, checkbox, app_name):
active = checkbox.get_active()
def on_checkbox_toggled(self, app_name, active):
print(f"{app_name} {'установлен' if active else 'снят'}")
self.update_button_status()
def update_button_status(self):
"""Update the button status based on the current selection."""
to_install, to_remove = self.get_install_remove_lists()
self.apply_button.remove_css_class("suggested-action")
self.apply_button.remove_css_class("destructive-action")
if to_install and to_remove:
self.apply_button.add_css_class("suggested-action")
self.apply_button.set_title(_("Remove and install applications"))
elif to_install:
self.apply_button.add_css_class("suggested-action")
self.apply_button.set_title(_("Install applications"))
elif to_remove:
self.apply_button.add_css_class("destructive-action")
self.apply_button.set_title(_("Remove applications"))
else:
self.apply_button.add_css_class("suggested-action")
self.apply_button.set_title(_("Update applications"))
button_states = {
(True, True): (_("Remove and install applications"), "suggested-action"),
(True, False): (_("Install applications"), "suggested-action"),
(False, True): (_("Remove applications"), "destructive-action"),
(False, False): (_("Update applications"), "suggested-action"),
}
title, css_class = button_states[(bool(to_install), bool(to_remove))]
self.apply_button.set_title(title)
# Remove all previous CSS classes in a loop
for css in ["suggested-action", "destructive-action"]:
self.apply_button.remove_css_class(css)
# Add the new CSS class
self.apply_button.add_css_class(css_class)
def on_search_changed(self, search_entry):
self.choice_listbox.invalidate_filter() # Обновление фильтра при изменении поиска
......@@ -177,7 +187,7 @@ class EepmPlayGuiWindow(Adw.ApplicationWindow, LogDialog):
self.choice_listbox.invalidate_filter() # Обновление фильтра при изменении фильтра
def listbox_filter_func(self, row):
"""Функция фильтрации для GtkListBox, которая проверяет текст и состояние фильтра"""
"""Функция фильтрации для GtkListBox, которая проверяет текст и состояние фильтра."""
search_text = self.search_entry.get_text().lower()
filter_option = self.search_dropdown.get_selected()
......@@ -211,14 +221,14 @@ class EepmPlayGuiWindow(Adw.ApplicationWindow, LogDialog):
else:
self.dialog.run("pkexec epm play --update all", on_done=self.update_ui)
def get_install_remove_lists(self):
if self.checkboxes:
to_install = [app_name for app_name, checkbox in self.checkboxes.items() if checkbox.get_active() and app_name not in self.installed_apps]
to_remove = [app_name for app_name, checkbox in self.checkboxes.items() if not checkbox.get_active() and app_name in self.installed_apps]
to_install = [app_name for app_name, row in self.checkboxes.items() if row.checkbox.get_active() and app_name not in self.installed_apps]
to_remove = [app_name for app_name, row in self.checkboxes.items() if not row.checkbox.get_active() and app_name in self.installed_apps]
return to_install, to_remove
else:
return False, False
def build_commands(self, to_install, to_remove):
commands = []
if to_install:
......@@ -226,4 +236,3 @@ class EepmPlayGuiWindow(Adw.ApplicationWindow, LogDialog):
if to_remove:
commands.append(f"epm play --auto --remove {' '.join(to_remove)}")
return commands
......@@ -74,7 +74,7 @@
<child>
<object class="GtkListBox" id="choice_listbox">
<style>
<class name="boxed-list"/>
<class name="boxed-list-separate"/>
</style>
</object>
</child>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment