From da41c34d3b9baa160b8030cbd8b059a3086a724a Mon Sep 17 00:00:00 2001 From: gmmcosta15 Date: Wed, 19 Nov 2025 16:49:55 +0000 Subject: [PATCH 1/8] refactor: change network list to listview --- BlocksScreen/lib/panels/networkWindow.py | 493 ++++++++++++----------- 1 file changed, 253 insertions(+), 240 deletions(-) diff --git a/BlocksScreen/lib/panels/networkWindow.py b/BlocksScreen/lib/panels/networkWindow.py index 5df4b81d..f97fd6a5 100644 --- a/BlocksScreen/lib/panels/networkWindow.py +++ b/BlocksScreen/lib/panels/networkWindow.py @@ -1,5 +1,6 @@ import logging import typing +import copy import subprocess from functools import partial @@ -8,7 +9,14 @@ from lib.ui.wifiConnectivityWindow_ui import Ui_wifi_stacked_page from lib.utils.list_button import ListCustomButton from lib.panels.widgets.keyboardPage import CustomQwertyKeyboard +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.blocks_frame import BlocksCustomFrame +from lib.panels.widgets.loadPage import LoadScreen +from lib.utils.icon_button import IconButton +from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem from PyQt6 import QtCore, QtGui, QtWidgets +from PyQt6.QtCore import QVariant +from PyQt6.QtWidgets import QScroller, QScrollerProperties logger = logging.getLogger("logs/BlocksScreen.log") @@ -137,23 +145,41 @@ class NetworkControlWindow(QtWidgets.QStackedWidget): delete_network_signal = QtCore.pyqtSignal(str, name="delete-network") def __init__(self, parent: typing.Optional[QtWidgets.QWidget], /) -> None: - super(NetworkControlWindow, self).__init__(parent) - self.background: typing.Optional[QtGui.QPixmap] = None + if parent: + super().__init__(parent) + else: + super().__init__() + self.panel = Ui_wifi_stacked_page() self.panel.setupUi(self) + + self._setupUI() + #self.background: typing.Optional[QtGui.QPixmap] = None + self.ongoing_update: bool = False + self.popup = Popup(self) self.sdbus_network = SdbusNetworkManagerAsync() self.start: bool = True - self.saved_network = dict + self.saved_network = {} + + self.load_popup: LoadScreen = LoadScreen(self) + self.repeated_request_status = QtCore.QTimer() + self.repeated_request_status.setInterval(2000) # every 2 seconds self._load_timer = QtCore.QTimer() self._load_timer.setSingleShot(True) self._load_timer.timeout.connect(self._handle_load_timeout) + + #View Models and Controllers + self.model = EntryListModel() + self.model.setParent(self.network_list_widget) + self.entry_delegate = EntryDelegate() + self.network_list_widget.setModel(self.model) + self.network_list_widget.setItemDelegate(self.entry_delegate) + self.entry_delegate.item_selected.connect(self.ssid_item_clicked) + self.panel.network_backButton.clicked.connect(self.reset_view_model) # Network Scan - self.network_list_widget = QtWidgets.QListWidget( - parent=self.panel.network_list_page - ) self.build_network_list() self.network_list_worker = BuildNetworkList() @@ -166,10 +192,7 @@ def __init__(self, parent: typing.Optional[QtWidgets.QWidget], /) -> None: self.sdbus_network.nm_state_change.connect(self.evaluate_network_state) self.panel.wifi_button.clicked.connect( - partial( - self.setCurrentIndex, - self.indexOf(self.panel.network_list_page), - ) + partial(self.setCurrentIndex, self.indexOf(self.panel.network_list_page)) ) self.panel.hotspot_button.clicked.connect( partial(self.setCurrentIndex, self.indexOf(self.panel.hotspot_page)) @@ -326,6 +349,7 @@ def __init__(self, parent: typing.Optional[QtWidgets.QWidget], /) -> None: self.network_list_worker.build() self.request_network_scan.emit() self.hide() + self.info_box_load() self.qwerty = CustomQwertyKeyboard(self) @@ -355,6 +379,54 @@ def __init__(self, parent: typing.Optional[QtWidgets.QWidget], /) -> None: ) ) + def handle_update_end(self) -> None: + """Handles update end signal + (closes loading page, returns to normal operation) + """ + if self.load_popup.isVisible(): + self.load_popup.close() + self.repeated_request_status.stop() + self.request_network_scan.emit() + self.build_model_list() + + def handle_ongoing_update(self) -> None: + """Handled ongoing update signal, + calls loading page (blocks user interaction) + """ + self.load_popup.set_status_message("Updating...") + self.load_popup.show() + self.repeated_request_status.start(2000) + + # View Model Methods + def reset_view_model(self) -> None: + """Clears items from ListView + (Resets `QAbstractListModel` by clearing entries) + """ + self.model.clear() + self.entry_delegate.clear() + + def deleteLater(self) -> None: + """Schedule the object for deletion, resets the list model first""" + self.reset_view_model() + return super().deleteLater() + + def showEvent(self, event: QtGui.QShowEvent | None) -> None: + """Re-add clients to update list""" + self.build_model_list() + return super().showEvent(event) + + def build_model_list(self) -> None: + """Builds the model list (`self.model`) containing updatable clients""" + self.network_list_widget.blockSignals(True) + self.model.clear() + #logger.debug(f"len saved: {len(self.saved_network.items())}") + test:dict = copy.copy(self.saved_network) + if test.items(): + for ssid,(signal,is_saved) in test.items(): + self.add_network_entry(ssid=ssid, signal=signal, is_saved=is_saved) + + self.network_list_widget.blockSignals(False) + def saved_wifi_option_selected(self): _sender = self.sender() self.panel.wifi_button.toggle_button.state = self.panel.wifi_button.toggle_button.State.ON @@ -369,7 +441,6 @@ def saved_wifi_option_selected(self): self.sdbus_network.connect_network(self.panel.saved_connection_network_name.text()) self.info_box_load(True) - def on_show_keyboard(self, panel: QtWidgets.QWidget, field: QtWidgets.QLineEdit): self.previousPanel = panel self.currentField = field @@ -399,7 +470,6 @@ def info_box_load(self, toggle: bool = False) -> None: self._load_timer.stop() self._load_timer.start(30000) - def _handle_load_timeout(self): """ Logic to execute if the loading screen is still visible after 30 seconds.< @@ -732,32 +802,32 @@ def add_network(self) -> None: self.panel.add_network_validation_button.repaint() self.popup.new_message(message_type=Popup.MessageType.ERROR, message=message) - - @QtCore.pyqtSlot(QtWidgets.QListWidgetItem, name="ssid_item_clicked") - def ssid_item_clicked(self, item: QtWidgets.QListWidgetItem) -> None: + @QtCore.pyqtSlot(ListItem, name="ssid_item_clicked") + def ssid_item_clicked(self, item: ListItem) -> None: """Handles when a network is clicked on the QListWidget. Args: item (QListWidgetItem): The list entry that was clicked """ - _current_item: QtWidgets.QWidget = ( - self.panel.network_list_widget.itemWidget(item) # type: ignore - ) - if _current_item: - _current_ssid_name = _current_item.findChild(QtWidgets.QLabel).text() - - if ( - _current_ssid_name in self.sdbus_network.get_saved_ssid_names() - ): # Network already saved go to the information page - self.setCurrentIndex(self.indexOf(self.panel.saved_connection_page)) - self.panel.saved_connection_network_name.setText( - str(_current_ssid_name) - ) - else: # Network not saved go to the add network page - self.setCurrentIndex(self.indexOf(self.panel.add_network_page)) - self.panel.add_network_network_label.setText( - str(_current_ssid_name) - ) # Add the network name to the title + if not item: + return + + _current_ssid_name = item.text + #_current_ssid_name = self.saved_network.get(item.text, {}) + self.selected_item = copy.copy(item) + if ( + _current_ssid_name in self.sdbus_network.get_saved_ssid_names() + ): # Network already saved go to the information page + self.setCurrentIndex(self.indexOf(self.panel.saved_connection_page)) + self.panel.saved_connection_network_name.setText( + str(_current_ssid_name) + ) + else: # Network not saved go to the add network page + self.setCurrentIndex(self.indexOf(self.panel.add_network_page)) + self.panel.add_network_network_label.setText( + str(_current_ssid_name) + ) # Add the network name to the title + def update_network( self, @@ -777,28 +847,19 @@ def update_network( self.setCurrentIndex(self.indexOf(self.panel.network_list_page)) @QtCore.pyqtSlot(list, name="finished-network-list-build") - def handle_network_list(self, data: typing.List[typing.Tuple]) -> None: - scroll_bar_position = self.network_list_widget.verticalScrollBar().value() + def handle_network_list(self, data: typing.Dict) -> None: self.network_list_widget.blockSignals(True) - self.network_list_widget.clear() - self.network_list_widget.setSpacing(35) for entry in data: - if entry == "separator": - self.separator_item() + if entry[0] == self.sdbus_network.hotspot_ssid: continue - elif entry == "blank": - self.blank_space_item() + if entry == "blank": continue - if entry[0] == self.sdbus_network.hotspot_ssid: + if entry == "separator": continue - self.network_button_item(*entry) - - max_v = self.network_list_widget.verticalScrollBar().maximum() - if scroll_bar_position > max_v: - self.network_list_widget.verticalScrollBar().setValue(max_v) - else: - self.network_list_widget.verticalScrollBar().setValue(scroll_bar_position) - self.network_list_widget.verticalScrollBar().update() + self.saved_network[entry[0]] = (entry[1], entry[2] == "Saved" or entry[2] == "Active") + self.build_model_list() + self.network_list_widget.blockSignals(False) + self.evaluate_network_state() QtCore.QTimer().singleShot(10000, lambda: self.network_list_worker.build()) @@ -818,21 +879,6 @@ def handle_button_click(self, ssid: str): self.setCurrentIndex(self.indexOf(self.panel.add_network_page)) self.panel.add_network_network_label.setText(str(ssid)) - def event(self, event: QtCore.QEvent) -> bool: - """Receives PyQt eEvents, this method is reimplemented from the QEvent class - - Args: - event (QtCore.QEvent) - - Returns: - bool: Event has been handled or not 1 - """ - if event.type() == QtCore.QEvent.Type.ApplicationActivated: - # Request a networks scan right at the start of the application - self.request_network_scan.emit() - return False - return super().event(event) - def setCurrentIndex(self, index: int): """Re-implementation of the QStackedWidget setCurrentIndex method in order to clear and display text as needed for each panel on the StackedWidget @@ -902,198 +948,165 @@ def show_network_panel( self.updateGeometry() self.update() self.show() + + def add_network_entry(self, ssid: str, signal: int, is_saved:str) -> None: + """Adds a new item to the list model""" + + wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/no_wifi.svg") + if 70 <= signal <= 100: + wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/3bar_wifi.svg") + elif signal >= 40: + wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/2bar_wifi.svg") + elif 1 < signal < 40: + wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/1bar_wifi.svg") + + item = ListItem( + text=ssid, + left_icon=wifi_pixmap, + right_text=f"Signal - {signal} % | {'Active' if is_saved else 'Protect'} ", + selected=False, + allow_check=False, + _lfontsize=17, + _rfontsize=13, + height=60, + ) + self.model.add_item(item) + + def _setupUI(self) -> None: + + """Sets up the UI components and layout for the network window.""" + + font_id = QtGui.QFontDatabase.addApplicationFont( + ":/font/media/fonts for text/Momcake-Bold.ttf" + ) + font_family = QtGui.QFontDatabase.applicationFontFamilies(font_id)[0] + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + #sizePolicy.setVerticalStretch(1) + self.setSizePolicy(sizePolicy) + self.setMinimumSize(QtCore.QSize(800, 500)) + #self.setMaximumSize(QtCore.QSize(800, 500)) + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.main_content_layout = QtWidgets.QHBoxLayout() + self.main_content_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) + + font = QtGui.QFont() + font.setFamily(font_family) + font.setPointSize(24) + + self.header_title = QtWidgets.QLabel(self) + self.header_title.setMinimumSize(QtCore.QSize(100, 60)) + self.header_title.setMaximumSize(QtCore.QSize(16777215, 60)) + self.header_title.setFont(font) + + # Timer for loading screen timeout + self._load_timer = QtCore.QTimer(self) + + #Buttons frame for update buttons + self.network_buttons_frame = BlocksCustomFrame() + #self.network_buttons_frame.setMinimumSize(QtCore.QSize(100, 100)) + #self.network_buttons_frame.setMaximumSize(QtCore.QSize(800, 450)) + + #List widget for update buttons + self.network_list_widget = QtWidgets.QListView(self.network_buttons_frame) + + self.network_buttons_layout = QtWidgets.QVBoxLayout() + self.network_buttons_layout.setContentsMargins(15, 20, 20, 5) + self.network_buttons_layout.addWidget(self.network_list_widget, 0, QtCore.Qt.AlignmentFlag.AlignBottom) + self.network_buttons_frame.setLayout(self.network_buttons_layout) + self.main_content_layout.addWidget(self.network_buttons_frame, 0) + self.setLayout(self.main_content_layout) + def build_network_list(self) -> None: - """Build available/saved network list""" + """Build available/saved network list with optimized palette setup.""" + def set_brush_for_all_groups(palette, role, color, style=QtCore.Qt.BrushStyle.SolidPattern): + """Helper to set a brush for Active, Inactive, and Disabled states.""" + brush = QtGui.QBrush(QtGui.QColor(*color)) + brush.setStyle(style) + for group in [ + QtGui.QPalette.ColorGroup.Active, + QtGui.QPalette.ColorGroup.Inactive, + QtGui.QPalette.ColorGroup.Disabled, + ]: + palette.setBrush(group, role, brush) + palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Button, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Base, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Window, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 120, 215, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Highlight, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Link, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Button, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Base, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Window, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 120, 215, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Highlight, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Link, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Button, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Base, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Window, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 120, 215, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Highlight, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Link, - brush, - ) + + # Transparent backgrounds + set_brush_for_all_groups(palette, QtGui.QPalette.ColorRole.Button, (0, 0, 0, 0)) + set_brush_for_all_groups(palette, QtGui.QPalette.ColorRole.Window, (0, 0, 0, 0)) + + # Base (black, no brush) + set_brush_for_all_groups(palette, QtGui.QPalette.ColorRole.Base, (0, 0, 0), QtCore.Qt.BrushStyle.NoBrush) + + # Highlight & link + set_brush_for_all_groups(palette, QtGui.QPalette.ColorRole.Highlight, (0, 120, 215, 0)) + set_brush_for_all_groups(palette, QtGui.QPalette.ColorRole.Link, (0, 0, 255, 0)) + + # Apply palette self.network_list_widget.setPalette(palette) + + # General QListView setup self.network_list_widget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) self.network_list_widget.setStyleSheet("background-color:transparent") self.network_list_widget.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) self.network_list_widget.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.network_list_widget.setVerticalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.network_list_widget.setHorizontalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.network_list_widget.setSizeAdjustPolicy( - QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents - ) + self.network_list_widget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAsNeeded) + self.network_list_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.network_list_widget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored) self.network_list_widget.setAutoScroll(False) self.network_list_widget.setProperty("showDropIndicator", False) self.network_list_widget.setDefaultDropAction(QtCore.Qt.DropAction.IgnoreAction) self.network_list_widget.setAlternatingRowColors(False) - self.network_list_widget.setSelectionMode( - QtWidgets.QAbstractItemView.SelectionMode.NoSelection - ) - self.network_list_widget.setSelectionBehavior( - QtWidgets.QAbstractItemView.SelectionBehavior.SelectItems + self.network_list_widget.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.NoSelection) + self.network_list_widget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectItems) + self.network_list_widget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) + self.network_list_widget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) + self.network_list_widget.setUniformItemSizes(True) + + #self.network_list_widget.setStyleSheet("QListView { padding-bottom: 8px; }") + + # inside build_network_list + + # ... (your palette / list-view setup) + + # Grab gesture on the viewport + viewport = self.network_list_widget.viewport() + QScroller.grabGesture(viewport, QScroller.ScrollerGestureType.TouchGesture) + QScroller.grabGesture(viewport, QScroller.ScrollerGestureType.LeftMouseButtonGesture) + + scroller = QScroller.scroller(viewport) + props = scroller.scrollerProperties() + + props.setScrollMetric( + QScrollerProperties.ScrollMetric.VerticalOvershootPolicy, + QVariant(QScrollerProperties.OvershootPolicy.OvershootAlwaysOff) ) - self.network_list_widget.setVerticalScrollMode( - QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel + props.setScrollMetric( + QScrollerProperties.ScrollMetric.OvershootDragResistanceFactor, + QVariant(1.0) ) - self.network_list_widget.setHorizontalScrollMode( - QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel + props.setScrollMetric( + QScrollerProperties.ScrollMetric.OvershootDragDistanceFactor, + QVariant(0.0) ) - QtWidgets.QScroller.grabGesture( - self.network_list_widget, - QtWidgets.QScroller.ScrollerGestureType.TouchGesture, + props.setScrollMetric( + QScrollerProperties.ScrollMetric.OvershootScrollDistanceFactor, + QVariant(0.0) ) - QtWidgets.QScroller.grabGesture( - self.network_list_widget, - QtWidgets.QScroller.ScrollerGestureType.LeftMouseButtonGesture, + props.setScrollMetric( + QScrollerProperties.ScrollMetric.OvershootScrollTime, + QVariant(0.0) ) - self.network_list_widget.setObjectName("network_list_widget") - self.panel.nl_content_layout.addWidget(self.network_list_widget) + scroller.setScrollerProperties(props) - def separator_item(self) -> None: - """Add separator item to network list""" - separator_item = QtWidgets.QListWidgetItem() - separator_widget = QtWidgets.QLabel() - separator_widget.setStyleSheet( - "background-color: gray; margin: 1px 1px; min-height: 1px; max-height: 1px;" - ) - separator_item.setSizeHint(QtCore.QSize(0, 2)) # Total vertical space: 2px - self.network_list_widget.addItem(separator_item) - self.network_list_widget.setItemWidget(separator_item, separator_widget) - - def blank_space_item(self) -> None: - """Add blank space item to network list""" - spacer_item = QtWidgets.QListWidgetItem() - spacer_widget = QtWidgets.QWidget() - spacer_widget.setFixedHeight(10) # Adjust height as needed - spacer_item.setSizeHint(spacer_widget.sizeHint()) - self.network_list_widget.addItem(spacer_item) - self.network_list_widget.setItemWidget(spacer_item, spacer_widget) - - def network_button_item(self, ssid, signal, right_text, /) -> None: - """Add a network entry to network list""" - wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/no_wifi.svg") - if 70 <= signal <= 100: - wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/3bar_wifi.svg") - elif signal >= 40: - wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/2bar_wifi.svg") - elif 1 < signal < 40: - wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/1bar_wifi.svg") + # ... add widget to layout, etc. - button = ListCustomButton(parent=self.network_list_widget) - button.setText(ssid) - button.setRightText(right_text) - button.setPixmap(QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg")) - button.setSecondPixmap(wifi_pixmap) - button.setFixedHeight(80) - button.setLeftFontSize(17) - button.setRightFontSize(12) - - button.clicked.connect(lambda checked, s=ssid: self.handle_button_click(s)) - item = QtWidgets.QListWidgetItem() - item.setSizeHint(button.sizeHint()) - self.network_list_widget.addItem(item) - self.network_list_widget.setItemWidget(item, button) + + self.network_list_widget.setObjectName("network_list_widget") + self.panel.nl_content_layout.addWidget(self.network_list_widget) From 9285fb7d8f307b266fef29f98d60fd949506d491 Mon Sep 17 00:00:00 2001 From: gmmcosta15 Date: Thu, 20 Nov 2025 16:19:05 +0000 Subject: [PATCH 2/8] Refactor: Refac to MVC view with Controller being runnables on a threadpoll --- BlocksScreen/lib/panels/networkWindow.py | 333 ++++++++++-------- .../lib/ui/resources/icon_resources.qrc | 13 +- .../resources/media/btn_icons/0bar_wifi.svg | 1 + .../media/btn_icons/0bar_wifi_protected.svg | 1 + .../resources/media/btn_icons/1bar_wifi.svg | 2 +- .../media/btn_icons/1bar_wifi_protected.svg | 1 + .../resources/media/btn_icons/2bar_wifi.svg | 2 +- .../media/btn_icons/2bar_wifi_protected.svg | 1 + .../resources/media/btn_icons/3bar_wifi.svg | 2 +- .../media/btn_icons/3bar_wifi_protected.svg | 1 + .../resources/media/btn_icons/4bar_wifi.svg | 1 + .../media/btn_icons/4bar_wifi_protected.svg | 1 + 12 files changed, 211 insertions(+), 148 deletions(-) create mode 100644 BlocksScreen/lib/ui/resources/media/btn_icons/0bar_wifi.svg create mode 100644 BlocksScreen/lib/ui/resources/media/btn_icons/0bar_wifi_protected.svg create mode 100644 BlocksScreen/lib/ui/resources/media/btn_icons/1bar_wifi_protected.svg create mode 100644 BlocksScreen/lib/ui/resources/media/btn_icons/2bar_wifi_protected.svg create mode 100644 BlocksScreen/lib/ui/resources/media/btn_icons/3bar_wifi_protected.svg create mode 100644 BlocksScreen/lib/ui/resources/media/btn_icons/4bar_wifi.svg create mode 100644 BlocksScreen/lib/ui/resources/media/btn_icons/4bar_wifi_protected.svg diff --git a/BlocksScreen/lib/panels/networkWindow.py b/BlocksScreen/lib/panels/networkWindow.py index f97fd6a5..e63f5f81 100644 --- a/BlocksScreen/lib/panels/networkWindow.py +++ b/BlocksScreen/lib/panels/networkWindow.py @@ -4,138 +4,202 @@ import subprocess from functools import partial +from PyQt6 import QtCore, QtGui, QtWidgets +from PyQt6.QtCore import QRunnable, QThreadPool, QObject, pyqtSignal, QVariant +from PyQt6.QtWidgets import QScroller, QScrollerProperties + from lib.network import SdbusNetworkManagerAsync from lib.panels.widgets.popupDialogWidget import Popup from lib.ui.wifiConnectivityWindow_ui import Ui_wifi_stacked_page -from lib.utils.list_button import ListCustomButton from lib.panels.widgets.keyboardPage import CustomQwertyKeyboard -from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame from lib.panels.widgets.loadPage import LoadScreen -from lib.utils.icon_button import IconButton from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem -from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt6.QtCore import QVariant -from PyQt6.QtWidgets import QScroller, QScrollerProperties + logger = logging.getLogger("logs/BlocksScreen.log") -class BuildNetworkList(QtCore.QThread): - """Retrieves information from sdbus interface about scanned networks""" +class NetworkScanRunnable(QRunnable): + """QRunnable task that performs network scanning using SdbusNetworkManagerAsync + + This runnable: + - Triggers a network rescan via SdbusNetworkManagerAsync + - collects SSIDs, signal strenght and saved status + - emits signal with raw scan data and a processed lisgs + + Signals: + - scan_results (dict): Emitted with raw scan results mapping SSID to properties + - finished_network_list_build (list): Emitted with processed list of networks + - error (str): Emitted if an error occurs during scanning + + """ + + class Signals(QObject): + scan_results = pyqtSignal(dict, name="scan-results") + finished_network_list_build = pyqtSignal(list, name="finished-network-list-build") + error = pyqtSignal(str) + + def __init__(self): + super().__init__() + self.nm = SdbusNetworkManagerAsync() + self.signals = NetworkScanRunnable.Signals() + + def run(self): + try: + logger.debug("NetworkScanRunnable: scanning networks") + self.nm.rescan_networks() + saved = self.nm.get_saved_ssid_names() + available = self.nm.get_available_networks() if self.nm.check_wifi_interface() else {} + + data_dict: dict[str, dict] = {} + for ssid, props in available.items(): + signal = int(props.get("signal_level", 0)) + data_dict[ssid] = { + "signal_level": signal, + "is_saved": ssid in saved, + } + + # Emit scan_result (same name) + self.signals.scan_results.emit(data_dict) - scan_result: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - dict, name="scan-results" - ) - finished_network_list_build: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - list, name="finished-network-list-build" - ) + # Transform into your “list of tuples + blank / separator” format + items: list[typing.Union[tuple[str,int,str], str]] = [] + saved_nets = [ (ssid, info["signal_level"]) for ssid, info in data_dict.items() if info["is_saved"] ] + unsaved_nets = [ (ssid, info["signal_level"]) for ssid, info in data_dict.items() if not info["is_saved"] ] + saved_nets.sort(key=lambda x: -x[1]) + unsaved_nets.sort(key=lambda x: -x[1]) - def __init__(self) -> None: + # Build your list with statuses + for ssid, sig in saved_nets: + status = "Active" if ssid == self.nm.get_current_ssid() else "Saved" + items.append((ssid, sig, status)) + + for ssid, sig in unsaved_nets: + items.append((ssid, sig, "Protected")) + + self.signals.finished_network_list_build.emit(items) + + except Exception as e: + logger.error("Error scanning networks", exc_info=True) + self.signals.error.emit(str(e)) + +class BuildNetworkList(QtCore.QObject): + """ + Controller class that schedules and manages repeted network scans + + Uses a QThreadPool to un NetworkScanRunnable tasks periodically. with a QTimer to trigger scans. + Prevents overlapping scans by tracking whether a scan is already in progress. + + Args: + poll_interval_ms: (int) Milliseconds between scans (default: 10000) + _timer (QtCore.QTimer): Timer that schedules next scan + _is_scanning (bool): Flag indicating if a scan is currently in progress + + Signals: + scan_results (dict): Emitted with raw scan results mapping SSID to properties + finished_network_list_build (list): Emitted with processed list of networks + error (str): Emitted if an error occurs during scanning + """ + scan_results = pyqtSignal(dict, name="scan-results") + finished_network_list_build = pyqtSignal(list, name="finished-network-list-build") + error = pyqtSignal(str) + + def __init__(self, poll_interval_ms: int = 10000): super().__init__() - self.mutex = QtCore.QMutex() - self.condition = QtCore.QWaitCondition() - self.restart = False - self.mutex.unlock() - self.network_items_list = [] - self.nm = SdbusNetworkManagerAsync() - if not self.nm: - logger.error( - "Cannot scan for networks, parent does not have \ - sdbus_network ('SdbusNetworkManagerAsync' instance class)" - ) + self.threadpool = QThreadPool.globalInstance() + self.poll_interval_ms = poll_interval_ms + self._is_scanning = False + + self._timer = QtCore.QTimer(self) + self._timer.setSingleShot(True) + self._timer.timeout.connect(self._do_scan) + + def start_polling(self): + self._schedule_next_scan() + + def stop_polling(self): + self._timer.stop() + + def build(self): + self._do_scan() + + def _schedule_next_scan(self): + self._timer.start(self.poll_interval_ms) + + def _on_task_finished(self, items): + self._is_scanning = False + self.finished_network_list_build.emit(items) + self._schedule_next_scan() + + def _on_task_scan_results(self, data_dict): + self.scan_results.emit(data_dict) + + def _on_task_error(self, err): + self._is_scanning = False + self.error.emit(err) + self._schedule_next_scan() + + def _do_scan(self): + if self._is_scanning: + logger.debug("Already scanning, skip scheduling.") + self._schedule_next_scan() return - logger.info("Network Scanner Thread Initiated") - def build(self) -> None: - """Starts QThread""" - with QtCore.QMutexLocker(self.mutex): - if not self.isRunning(): - self.start(QtCore.QThread.Priority.LowPriority) - else: - self.restart = True - self.condition.wakeOne() - - def stop(self): - """Stops QThread execution""" - self.mutex.lock() - self.condition.wakeOne() - self.mutex.unlock() - self.deleteLater() - - def run(self) -> None: - """BuildNetworkList main thread logic""" - logger.debug("Scanning and building network list") - while True: - self.mutex.lock() - self.network_items_list.clear() - self.nm.rescan_networks() - saved_ssids = self.nm.get_saved_ssid_names() - saved_networks = self.nm.get_saved_networks() - unsaved_networks = [] - networks = [] - if self.nm.check_wifi_interface(): - available_networks = self.nm.get_available_networks() - if not available_networks: # Skip everything if no networks exist - logger.debug("No available networks after scan") - self.finished_network_list_build.emit(self.network_items_list) - return - for ssid_key in available_networks: - properties = available_networks.get(ssid_key, {}) - signal = int(properties.get("signal_level", 0)) - networks.append( - { - "ssid": ssid_key if ssid_key else "UNKNOWN", - "signal": signal, - "is_saved": bool(ssid_key in saved_ssids), - } - ) - if networks: - saved_networks = sorted( - [n for n in networks if n["is_saved"]], - key=lambda x: -x["signal"], - ) - unsaved_networks = sorted( - [n for n in networks if not n["is_saved"]], - key=lambda x: -x["signal"], - ) - elif saved_networks: - saved_networks = sorted([n for n in saved_networks], key=lambda x: -1) - if saved_networks: - for net in saved_networks: - if "ap" in net.get("mode", ""): - return - ssid = net.get("ssid", "UNKNOWN") - signal = ( - self.nm.get_connection_signal_by_ssid(ssid) - if ssid != "UNKNOWN" - else 0 - ) - if ssid == self.nm.get_current_ssid(): - self.network_items_list.append((ssid, signal, "Active")) - else: - self.network_items_list.append((ssid, signal, "Saved")) - if saved_networks and unsaved_networks: # Separator - self.network_items_list.append("separator") - if unsaved_networks: - for net in unsaved_networks: - ssid = net.get("ssid", "UNKNOWN") - signal = ( - self.nm.get_connection_signal_by_ssid(ssid) - if ssid != "UNKNOWN" - else 0 - ) - self.network_items_list.append((ssid, signal, "Protected")) - # Add a dummy blank space at the end if there are any unsaved networks - if unsaved_networks: - self.network_items_list.append("blank") - - self.finished_network_list_build.emit(self.network_items_list) - if not self.restart: - self.condition.wait(self.mutex) - self.restart = False - self.mutex.unlock() + self._is_scanning = True + task = NetworkScanRunnable() + task.signals.finished_network_list_build.connect(self._on_task_finished) + task.signals.scan_results.connect(self._on_task_scan_results) + task.signals.error.connect(self._on_task_error) + + self.threadpool.start(task) + logger.debug("Submitted scan task to thread pool") + +class WifiIconProvider: + """Simple provider: loads QPixmap for WiFi bars + protection without caching.""" + + def __init__(self): + # Map from (bars, is_protected) to resource path + self.paths = { + ("no", False): ":/network/media/btn_icons/0bar_wifi.svg", + (4, False): ":/network/media/btn_icons/4bar_wifi.svg", + (3, False): ":/network/media/btn_icons/3bar_wifi.svg", + (2, False): ":/network/media/btn_icons/2bar_wifi.svg", + (1, False): ":/network/media/btn_icons/1bar_wifi.svg", + + ("no", True): ":/network/media/btn_icons/0bar_wifi_protected.svg", + (4, True): ":/network/media/btn_icons/4bar_wifi_protected.svg", + (3, True): ":/network/media/btn_icons/3bar_wifi_protected.svg", + (2, True): ":/network/media/btn_icons/2bar_wifi_protected.svg", + (1, True): ":/network/media/btn_icons/1bar_wifi_protected.svg", + } + + + def get_pixmap(self, signal: int, state: str) -> QtGui.QPixmap: + """Return a QPixmap for the given signal (0-100) and state ("Protected" or not).""" + # Normalize signal + if signal <= 0: + bars = "no" + elif signal >= 75: + bars = 4 + elif signal >= 50: + bars = 3 + elif signal >= 25: + bars = 2 + else: + bars = 1 + + is_protected = (state == "Protected") + key = (bars, is_protected) + path = self.paths.get(key) + if path is None: + logger.warning(f"No icon path for key {key}, falling back to no-signal unprotected") + path = self.paths[("no", False)] + pm = QtGui.QPixmap(path) + if pm.isNull(): + logger.error(f"Failed to load pixmap from '{path}' for key {key}") + return pm class NetworkControlWindow(QtWidgets.QStackedWidget): """Network Control panel Widget""" @@ -154,7 +218,8 @@ def __init__(self, parent: typing.Optional[QtWidgets.QWidget], /) -> None: self.panel.setupUi(self) self._setupUI() - #self.background: typing.Optional[QtGui.QPixmap] = None + + self._provider = WifiIconProvider() self.ongoing_update: bool = False self.popup = Popup(self) @@ -170,7 +235,7 @@ def __init__(self, parent: typing.Optional[QtWidgets.QWidget], /) -> None: self._load_timer.setSingleShot(True) self._load_timer.timeout.connect(self._handle_load_timeout) - #View Models and Controllers + #View Models and Delegates self.model = EntryListModel() self.model.setParent(self.network_list_widget) self.entry_delegate = EntryDelegate() @@ -186,9 +251,8 @@ def __init__(self, parent: typing.Optional[QtWidgets.QWidget], /) -> None: self.network_list_worker.finished_network_list_build.connect( self.handle_network_list ) - self.panel.rescan_button.clicked.connect( - lambda: QtCore.QTimer.singleShot(100, self.network_list_worker.build) - ) + self.network_list_worker.start_polling() + self.panel.rescan_button.clicked.connect(self.network_list_worker.build) self.sdbus_network.nm_state_change.connect(self.evaluate_network_state) self.panel.wifi_button.clicked.connect( @@ -419,7 +483,7 @@ def build_model_list(self) -> None: """Builds the model list (`self.model`) containing updatable clients""" self.network_list_widget.blockSignals(True) self.model.clear() - #logger.debug(f"len saved: {len(self.saved_network.items())}") + test:dict = copy.copy(self.saved_network) if test.items(): for ssid,(signal,is_saved) in test.items(): @@ -856,7 +920,7 @@ def handle_network_list(self, data: typing.Dict) -> None: continue if entry == "separator": continue - self.saved_network[entry[0]] = (entry[1], entry[2] == "Saved" or entry[2] == "Active") + self.saved_network[entry[0]] = (entry[1], entry[2]) self.build_model_list() self.network_list_widget.blockSignals(False) @@ -952,23 +1016,17 @@ def show_network_panel( def add_network_entry(self, ssid: str, signal: int, is_saved:str) -> None: """Adds a new item to the list model""" - wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/no_wifi.svg") - if 70 <= signal <= 100: - wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/3bar_wifi.svg") - elif signal >= 40: - wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/2bar_wifi.svg") - elif 1 < signal < 40: - wifi_pixmap = QtGui.QPixmap(":/network/media/btn_icons/1bar_wifi.svg") + wifi_pixmap = self._provider.get_pixmap(signal=signal, state=is_saved) item = ListItem( text=ssid, left_icon=wifi_pixmap, - right_text=f"Signal - {signal} % | {'Active' if is_saved else 'Protect'} ", + right_text=is_saved, selected=False, allow_check=False, _lfontsize=17, _rfontsize=13, - height=60, + height=70, ) self.model.add_item(item) @@ -1067,14 +1125,8 @@ def set_brush_for_all_groups(palette, role, color, style=QtCore.Qt.BrushStyle.So self.network_list_widget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) self.network_list_widget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) self.network_list_widget.setUniformItemSizes(True) - - #self.network_list_widget.setStyleSheet("QListView { padding-bottom: 8px; }") - - # inside build_network_list - - # ... (your palette / list-view setup) - - # Grab gesture on the viewport + self.network_list_widget.setSpacing(3) + viewport = self.network_list_widget.viewport() QScroller.grabGesture(viewport, QScroller.ScrollerGestureType.TouchGesture) QScroller.grabGesture(viewport, QScroller.ScrollerGestureType.LeftMouseButtonGesture) @@ -1105,8 +1157,5 @@ def set_brush_for_all_groups(palette, role, color, style=QtCore.Qt.BrushStyle.So scroller.setScrollerProperties(props) - # ... add widget to layout, etc. - - self.network_list_widget.setObjectName("network_list_widget") self.panel.nl_content_layout.addWidget(self.network_list_widget) diff --git a/BlocksScreen/lib/ui/resources/icon_resources.qrc b/BlocksScreen/lib/ui/resources/icon_resources.qrc index 3022fd4d..7c9abcdd 100644 --- a/BlocksScreen/lib/ui/resources/icon_resources.qrc +++ b/BlocksScreen/lib/ui/resources/icon_resources.qrc @@ -1,11 +1,18 @@ - media/btn_icons/wifi_config.svg - media/btn_icons/wifi_locked.svg - media/btn_icons/wifi_unlocked.svg + media/btn_icons/0bar_wifi.svg + media/btn_icons/0bar_wifi_protected.svg media/btn_icons/1bar_wifi.svg + media/btn_icons/1bar_wifi_protected.svg media/btn_icons/2bar_wifi.svg + media/btn_icons/2bar_wifi_protected.svg media/btn_icons/3bar_wifi.svg + media/btn_icons/3bar_wifi_protected.svg + media/btn_icons/4bar_wifi.svg + media/btn_icons/4bar_wifi_protected.svg + media/btn_icons/wifi_config.svg + media/btn_icons/wifi_locked.svg + media/btn_icons/wifi_unlocked.svg media/btn_icons/hotspot.svg media/btn_icons/no_wifi.svg media/btn_icons/retry_wifi.svg diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/0bar_wifi.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/0bar_wifi.svg new file mode 100644 index 00000000..ceaff53d --- /dev/null +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/0bar_wifi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/0bar_wifi_protected.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/0bar_wifi_protected.svg new file mode 100644 index 00000000..a10ea388 --- /dev/null +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/0bar_wifi_protected.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/1bar_wifi.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/1bar_wifi.svg index debc48b2..3258893d 100644 --- a/BlocksScreen/lib/ui/resources/media/btn_icons/1bar_wifi.svg +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/1bar_wifi.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/1bar_wifi_protected.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/1bar_wifi_protected.svg new file mode 100644 index 00000000..8793447e --- /dev/null +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/1bar_wifi_protected.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/2bar_wifi.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/2bar_wifi.svg index d9ba78c1..203b70bb 100644 --- a/BlocksScreen/lib/ui/resources/media/btn_icons/2bar_wifi.svg +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/2bar_wifi.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/2bar_wifi_protected.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/2bar_wifi_protected.svg new file mode 100644 index 00000000..a9f3233b --- /dev/null +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/2bar_wifi_protected.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/3bar_wifi.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/3bar_wifi.svg index 7c694b76..8d98855c 100644 --- a/BlocksScreen/lib/ui/resources/media/btn_icons/3bar_wifi.svg +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/3bar_wifi.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/3bar_wifi_protected.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/3bar_wifi_protected.svg new file mode 100644 index 00000000..458c1ac5 --- /dev/null +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/3bar_wifi_protected.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/4bar_wifi.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/4bar_wifi.svg new file mode 100644 index 00000000..9aadd8e7 --- /dev/null +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/4bar_wifi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/BlocksScreen/lib/ui/resources/media/btn_icons/4bar_wifi_protected.svg b/BlocksScreen/lib/ui/resources/media/btn_icons/4bar_wifi_protected.svg new file mode 100644 index 00000000..639762e7 --- /dev/null +++ b/BlocksScreen/lib/ui/resources/media/btn_icons/4bar_wifi_protected.svg @@ -0,0 +1 @@ + \ No newline at end of file From a3dc9aca1d970e90424bafc2535647908003ee51 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Wed, 26 Nov 2025 03:47:11 +0000 Subject: [PATCH 3/8] FilesPage: Refactor almost complete missing passing the directory by itemclick helper_methods: updated the get_file_loc method to return always the filename instead of the full path Signed-off-by: Guilherme Costa --- BlocksScreen/helper_methods.py | 16 +- BlocksScreen/lib/panels/widgets/filesPage.py | 202 ++++++++++--------- 2 files changed, 124 insertions(+), 94 deletions(-) diff --git a/BlocksScreen/helper_methods.py b/BlocksScreen/helper_methods.py index b086c751..9a336efb 100644 --- a/BlocksScreen/helper_methods.py +++ b/BlocksScreen/helper_methods.py @@ -303,8 +303,20 @@ def check_file_on_path( return os.path.exists(_filepath) -def get_file_loc(filename) -> pathlib.Path: - ... +def get_file_loc(filename: typing.Optional[str]) -> str: + # If filename is None or empty, return empty string instead of None + if not filename: + return "" + # Remove trailing slashes or backslashes + filename = filename.rstrip("/\\") + + # Normalize Windows backslashes to forward slashes + filename = filename.replace("\\", "/") + + parts = filename.split("/") + + # Split and return the last path component + return parts[-1] if filename else "" # def get_hash(data) -> hashlib._Hash: diff --git a/BlocksScreen/lib/panels/widgets/filesPage.py b/BlocksScreen/lib/panels/widgets/filesPage.py index 238c5eed..faac28bd 100644 --- a/BlocksScreen/lib/panels/widgets/filesPage.py +++ b/BlocksScreen/lib/panels/widgets/filesPage.py @@ -7,6 +7,9 @@ from lib.utils.icon_button import IconButton from lib.utils.list_button import ListCustomButton from PyQt6 import QtCore, QtGui, QtWidgets +from lib.utils.blocks_frame import BlocksCustomFrame + +from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem logger = logging.getLogger("logs/BlocksScreen.log") @@ -35,7 +38,10 @@ class FilesPage(QtWidgets.QWidget): directories: list = [] def __init__(self, parent) -> None: - super().__init__(parent) + super().__init__() + #VM + self.model = EntryListModel() + self.entry_delegate = EntryDelegate() self._setupUI() self.setMouseTracking(True) self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) @@ -51,6 +57,12 @@ def __init__(self, parent) -> None: lambda value: self.listWidget.verticalScrollBar().setValue(value) ) self.back_btn.clicked.connect(self.reset_dir) + + self.entry_delegate.item_selected.connect(self._on_item_selected) + + @QtCore.pyqtSlot(ListItem, name="on-item-selected") + def _on_item_selected(self, item: ListItem) -> None: + logger.debug("Item Selected") @QtCore.pyqtSlot(name="reset-dir") def reset_dir(self) -> None: @@ -65,8 +77,8 @@ def showEvent(self, a0: QtGui.QShowEvent) -> None: def on_file_list(self, file_list: list) -> None: self.files_data.clear() self.file_list = file_list - # if self.isVisible(): # Only build the list when directories come - # self._build_file_list() + # if self.isVisible(): # Only build the list when directories come + # self._build_file_list() @QtCore.pyqtSlot(list, name="on-dirs") def on_directories(self, directories_data: list) -> None: @@ -109,26 +121,35 @@ def on_fileinfo(self, filedata: dict) -> None: time_str = f"{hours}h {minutes}m" else: time_str = f"{minutes}m" + + + + name = helper_methods.get_file_loc(filename) + item = ListItem( + text=name[:-6], + right_text=f"{filament_type} - {time_str}", + right_icon=QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg"), + left_icon=None, + callback=lambda: self._fileItemClicked(item), + selected=False, + allow_check=False, + _lfontsize=17, + _rfontsize=12, + height=80, + notificate=False + ) + + self.model.add_item(item) - list_items = [ - self.listWidget.item(i) for i in range(self.listWidget.count()) - ] - if not list_items: - return - for list_item in list_items: - item_widget = self.listWidget.itemWidget(list_item) - if item_widget.text() in filename: - item_widget.setRightText(f"{filament_type} - {time_str}") - @QtCore.pyqtSlot(QtWidgets.QListWidgetItem, name="file-item-clicked") - def _fileItemClicked(self, item: QtWidgets.QListWidgetItem) -> None: + @QtCore.pyqtSlot(ListItem,str, name="file-item-clicked") + def _fileItemClicked(self, item: ListItem,path:str ) -> None: """Slot for List Item clicked Args: item (QListWidgetItem): Clicked item """ if item: - widget = self.listWidget.itemWidget(item) for file in self.file_list: path = ( file.get("path") @@ -137,7 +158,7 @@ def _fileItemClicked(self, item: QtWidgets.QListWidgetItem) -> None: ) if not path: return - if widget.text() in path: + if item.text in path: file_path = ( path if not self.curr_dir @@ -150,21 +171,22 @@ def _fileItemClicked(self, item: QtWidgets.QListWidgetItem) -> None: ), # Defaults to Nothing ) - @QtCore.pyqtSlot(QtWidgets.QListWidgetItem, str, name="dir-item-clicked") def _dirItemClicked( - self, item: QtWidgets.QListWidgetItem, directory: str + self, directory: str ) -> None: self.curr_dir = self.curr_dir + directory self.request_dir_info[str].emit(self.curr_dir) def _build_file_list(self) -> None: """Inserts the currently available gcode files on the QListWidget""" - self.listWidget.blockSignals(True) - self.listWidget.clear() - if not self.file_list and not self.directories: + #self.listWidget.blockSignals(True) + self.model.clear() + self.entry_delegate.clear() + + if not self.file_list and not self.directories and os.path.islink(self.curr_dir): self._add_placeholder() return - self.listWidget.setSpacing(35) + if self.directories or self.curr_dir != "": if self.curr_dir != "" and self.curr_dir != "/": self._add_back_folder_entry() @@ -177,50 +199,48 @@ def _build_file_list(self) -> None: ) for item in sorted_list: self._add_file_list_item(item) + self._add_spacer() self._setup_scrollbar() - self.listWidget.blockSignals(False) - self.repaint() + #self.listWidget.blockSignals(False) + self.listWidget.repaint() def _add_directory_list_item(self, dir_data: dict) -> None: dir_name = dir_data.get("dirname", "") if not dir_name: return - button = ListCustomButton() - button.setText(str(dir_data.get("dirname"))) - button.setSecondPixmap( - QtGui.QPixmap(":/ui/media/btn_icons/folderIcon.svg") - ) - button.setMinimumSize(600, 80) - button.setMaximumSize(700, 80) - button.setLeftFontSize(17) - button.setRightFontSize(12) - list_item = QtWidgets.QListWidgetItem() - list_item.setSizeHint(button.sizeHint()) - self.listWidget.addItem(list_item) - self.listWidget.setItemWidget(list_item, button) - button.clicked.connect( - lambda: self._dirItemClicked(list_item, "/" + dir_name) - ) + item = ListItem( + text=str(dir_name), + left_icon=QtGui.QPixmap(":/ui/media/btn_icons/folderIcon.svg"), + right_text="", + selected=False, + callback=lambda name=dir_name: self._dirItemClicked("/" + str(name)), + allow_check=False, + _lfontsize=17, + _rfontsize=12, + height=80 + ) + self.model.add_item(item) def _add_back_folder_entry(self) -> None: - button = ListCustomButton() - button.setText("Go Back") - button.setSecondPixmap( - QtGui.QPixmap(":/ui/media/btn_icons/back_folder.svg") - ) - button.setMinimumSize(600, 80) - button.setMaximumSize(700, 80) - button.setLeftFontSize(17) - button.setRightFontSize(12) - list_item = QtWidgets.QListWidgetItem() - list_item.setSizeHint(button.sizeHint()) - self.listWidget.addItem(list_item) - self.listWidget.setItemWidget(list_item, button) go_back_path = os.path.dirname(self.curr_dir) if go_back_path == "/": go_back_path = "" - button.clicked.connect(lambda: (self._on_goback_dir(go_back_path))) + + item = ListItem( + text="Go Back", + right_text="", + right_icon=None, + left_icon=QtGui.QPixmap(":/ui/media/btn_icons/back_folder.svg"), + callback= lambda: self._on_goback_dir(go_back_path), + selected=False, + allow_check=False, + _lfontsize=17, + _rfontsize=12, + height=80, + notificate=False + ) + self.model.add_item(item) @QtCore.pyqtSlot(str, str, name="on-goback-dir") def _on_goback_dir(self, directory) -> None: @@ -239,23 +259,10 @@ def _add_file_list_item(self, file_data_item) -> None: if not name.endswith(".gcode"): # Only list .gcode files, all else ignore return - button = ListCustomButton() - button.setText(name[:-6]) - button.setPixmap( - QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg") - ) - button.setMinimumSize(600, 80) - button.setMaximumSize(700, 80) - button.setLeftFontSize(17) - button.setRightFontSize(12) - list_item = QtWidgets.QListWidgetItem() - list_item.setSizeHint(button.sizeHint()) - self.listWidget.addItem(list_item) - self.listWidget.setItemWidget(list_item, button) - button.clicked.connect(lambda: self._fileItemClicked(list_item)) file_path = ( name if not self.curr_dir else str(self.curr_dir + "/" + name) ).removeprefix("/") + self.request_file_metadata.emit(file_path.removeprefix("/")) self.request_file_info.emit(file_path.removeprefix("/")) @@ -264,29 +271,14 @@ def _add_spacer(self) -> None: spacer_widget = QtWidgets.QWidget() spacer_widget.setFixedHeight(10) spacer_item.setSizeHint(spacer_widget.sizeHint()) - self.listWidget.addItem(spacer_item) + #self.listWidget.addItem(spacer_item) def _add_placeholder(self) -> None: - self.listWidget.setSpacing(-1) - placeholder_label = QtWidgets.QLabel("No Files found") - font = QtGui.QFont() - font.setPointSize(25) - placeholder_label.setFont(font) - placeholder_label.setStyleSheet("color: gray;") - placeholder_label.setAlignment( - QtCore.Qt.AlignmentFlag.AlignHCenter - | QtCore.Qt.AlignmentFlag.AlignVCenter - ) - placeholder_label.setMinimumSize( - QtCore.QSize(self.listWidget.width(), self.listWidget.height()) - ) self.scrollbar.hide() - placeholder_item = QtWidgets.QListWidgetItem() - placeholder_item.setSizeHint( - QtCore.QSize(self.listWidget.width(), self.listWidget.height()) - ) - self.listWidget.addItem(placeholder_item) - self.listWidget.setItemWidget(placeholder_item, placeholder_label) + self.listWidget.hide() + + self.label.show() + def _handle_scrollbar(self, value): # Block signals to avoid recursion @@ -316,6 +308,7 @@ def _setupUI(self): sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) self.setMinimumSize(QtCore.QSize(710, 400)) + #self.setMaximumSize(QtCore.QSize(500, 400)) font = QtGui.QFont() font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) self.setFont(font) @@ -358,9 +351,17 @@ def _setupUI(self): self.line.setObjectName("line") self.verticalLayout_5.addWidget(self.line) self.fp_content_layout = QtWidgets.QHBoxLayout() - self.fp_content_layout.setContentsMargins(0, 0, 0, 0) + #self.fp_content_layout.setContentsMargins(0, 0, 0, 0) self.fp_content_layout.setObjectName("fp_content_layout") - self.listWidget = QtWidgets.QListWidget(parent=self) + #self.setMinimumSize(QtCore.QSize(800, 500)) + + + + #Listwidget + self.listWidget = QtWidgets.QListView(parent=self) + self.listWidget.setModel(self.model) + self.listWidget.setItemDelegate(self.entry_delegate) + self.listWidget.setSpacing(5) self.listWidget.setProperty("showDropIndicator", False) self.listWidget.setProperty("selectionMode", "NoSelection") self.listWidget.setStyleSheet("background: transparent;") @@ -406,13 +407,27 @@ def _setupUI(self): QtWidgets.QScroller.scroller(self.listWidget).setScrollerProperties( scroller_props ) + font = QtGui.QFont() font.setPointSize(25) - placeholder_item = QtWidgets.QListWidgetItem() - placeholder_item.setSizeHint( + #placeholder_item = QtWidgets.QListWidgetItem() + #placeholder_item.setSizeHint( + # QtCore.QSize(self.listWidget.width(), self.listWidget.height()) + #) + self.label = QtWidgets.QLabel("No Files found") + # self.label.setBuddy(self.listWidget) + self.label.setFont(font) + self.label.setStyleSheet("color: gray;") + self.label.setMinimumSize( QtCore.QSize(self.listWidget.width(), self.listWidget.height()) ) + self.label.setAlignment( + QtCore.Qt.AlignmentFlag.AlignHCenter + | QtCore.Qt.AlignmentFlag.AlignVCenter + ) + self.fp_content_layout.addWidget(self.listWidget) + self.fp_content_layout.addWidget(self.label) self.scrollbar = CustomScrollBar() self.fp_content_layout.addWidget(self.scrollbar) self.verticalLayout_5.addLayout(self.fp_content_layout) @@ -420,3 +435,6 @@ def _setupUI(self): QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents, True ) self.scroller = QtWidgets.QScroller.scroller(self.listWidget) + self.label.hide() + + From b1eaafc9f8a2bab54c0d7ce34d2706ebff845844 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Wed, 26 Nov 2025 04:07:27 +0000 Subject: [PATCH 4/8] requirements.txt: security update to the requests package Signed-off-by: Guilherme Costa --- scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/requirements.txt b/scripts/requirements.txt index c6526130..c9ba6c54 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -7,7 +7,7 @@ pefile==2023.2.7 PyQt6==6.7.1 PyQt6-Qt6==6.7.2 PyQt6_sip==13.8.0 -requests==2.32.3 +requests==2.32.5 sdbus==0.12.0 sdbus-networkmanager==2.0.0 typing==3.7.4.3 From 89b5bfbb206a783f05e94ddba35a3f02a2f77dd9 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Wed, 26 Nov 2025 12:10:46 +0000 Subject: [PATCH 5/8] filesPage.py: refactor concluded, scrollbar bugfix Signed-off-by: Guilherme Costa --- BlocksScreen/lib/panels/widgets/filesPage.py | 57 +++++++------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/filesPage.py b/BlocksScreen/lib/panels/widgets/filesPage.py index faac28bd..324a53fa 100644 --- a/BlocksScreen/lib/panels/widgets/filesPage.py +++ b/BlocksScreen/lib/panels/widgets/filesPage.py @@ -77,8 +77,8 @@ def showEvent(self, a0: QtGui.QShowEvent) -> None: def on_file_list(self, file_list: list) -> None: self.files_data.clear() self.file_list = file_list - # if self.isVisible(): # Only build the list when directories come - # self._build_file_list() + if self.isVisible(): # Only build the list when directories come + self._build_file_list() @QtCore.pyqtSlot(list, name="on-dirs") def on_directories(self, directories_data: list) -> None: @@ -130,7 +130,7 @@ def on_fileinfo(self, filedata: dict) -> None: right_text=f"{filament_type} - {time_str}", right_icon=QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg"), left_icon=None, - callback=lambda: self._fileItemClicked(item), + callback=lambda namelam=filename: self._fileItemClicked(namelam), selected=False, allow_check=False, _lfontsize=17, @@ -142,35 +142,21 @@ def on_fileinfo(self, filedata: dict) -> None: self.model.add_item(item) - @QtCore.pyqtSlot(ListItem,str, name="file-item-clicked") - def _fileItemClicked(self, item: ListItem,path:str ) -> None: + @QtCore.pyqtSlot(str, name="file-item-clicked") + def _fileItemClicked(self, filename: str) -> None: """Slot for List Item clicked Args: - item (QListWidgetItem): Clicked item + filename (str): Clicked item path """ - if item: - for file in self.file_list: - path = ( - file.get("path") - if "path" in file.keys() - else file.get("filename") - ) - if not path: - return - if item.text in path: - file_path = ( - path - if not self.curr_dir - else str(self.curr_dir + "/" + path) - ) - self.file_selected.emit( - str(file_path.removeprefix("/")), + self.file_selected.emit( + str(filename.removeprefix("/")), self.files_data.get( - file_path.removeprefix("/") + filename.removeprefix("/") ), # Defaults to Nothing ) + def _dirItemClicked( self, directory: str ) -> None: @@ -199,10 +185,8 @@ def _build_file_list(self) -> None: ) for item in sorted_list: self._add_file_list_item(item) - - self._add_spacer() + self._setup_scrollbar() - #self.listWidget.blockSignals(False) self.listWidget.repaint() def _add_directory_list_item(self, dir_data: dict) -> None: @@ -266,13 +250,6 @@ def _add_file_list_item(self, file_data_item) -> None: self.request_file_metadata.emit(file_path.removeprefix("/")) self.request_file_info.emit(file_path.removeprefix("/")) - def _add_spacer(self) -> None: - spacer_item = QtWidgets.QListWidgetItem() - spacer_widget = QtWidgets.QWidget() - spacer_widget.setFixedHeight(10) - spacer_item.setSizeHint(spacer_widget.sizeHint()) - #self.listWidget.addItem(spacer_item) - def _add_placeholder(self) -> None: self.scrollbar.hide() self.listWidget.hide() @@ -287,6 +264,9 @@ def _handle_scrollbar(self, value): self.scrollbar.blockSignals(False) def _setup_scrollbar(self) -> None: + idx = self.model.index(0, 0) + + rect = self.listWidget.rectForIndex(idx) self.scrollbar.setMinimum( self.listWidget.verticalScrollBar().minimum() ) @@ -431,10 +411,11 @@ def _setupUI(self): self.scrollbar = CustomScrollBar() self.fp_content_layout.addWidget(self.scrollbar) self.verticalLayout_5.addLayout(self.fp_content_layout) - self.scrollbar.setAttribute( - QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents, True - ) - self.scroller = QtWidgets.QScroller.scroller(self.listWidget) + #self.scrollbar.setAttribute( + # QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents, True + #) + #self.scroller = QtWidgets.QScroller.scroller(self.listWidget) + self.scrollbar.show() self.label.hide() From 67064ecec224e99d83976bd5111695ac7f9a7545 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Tue, 2 Dec 2025 12:39:41 +0000 Subject: [PATCH 6/8] helper_method.py: Change naming of a method from get_file_loc to get_file_name Signed-off-by: Guilherme Costa --- BlocksScreen/helper_methods.py | 5 ++++- BlocksScreen/lib/panels/widgets/filesPage.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/BlocksScreen/helper_methods.py b/BlocksScreen/helper_methods.py index 9a336efb..5bacd74c 100644 --- a/BlocksScreen/helper_methods.py +++ b/BlocksScreen/helper_methods.py @@ -303,7 +303,10 @@ def check_file_on_path( return os.path.exists(_filepath) -def get_file_loc(filename: typing.Optional[str]) -> str: +def get_file_loc(filename) -> pathlib.Path: + ... + +def get_file_name(filename: typing.Optional[str]) -> str: # If filename is None or empty, return empty string instead of None if not filename: return "" diff --git a/BlocksScreen/lib/panels/widgets/filesPage.py b/BlocksScreen/lib/panels/widgets/filesPage.py index 324a53fa..571826b1 100644 --- a/BlocksScreen/lib/panels/widgets/filesPage.py +++ b/BlocksScreen/lib/panels/widgets/filesPage.py @@ -124,7 +124,7 @@ def on_fileinfo(self, filedata: dict) -> None: - name = helper_methods.get_file_loc(filename) + name = helper_methods.get_file_name(filename) item = ListItem( text=name[:-6], right_text=f"{filament_type} - {time_str}", From 634cf8c29444d0693f6809a27c31923308cbac53 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Tue, 2 Dec 2025 14:48:34 +0000 Subject: [PATCH 7/8] filesPage.py: code cleanup, small docstring generation and add missing commented lines Signed-off-by: Guilherme Costa --- BlocksScreen/lib/panels/widgets/filesPage.py | 42 ++++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/filesPage.py b/BlocksScreen/lib/panels/widgets/filesPage.py index 571826b1..86f9c2f4 100644 --- a/BlocksScreen/lib/panels/widgets/filesPage.py +++ b/BlocksScreen/lib/panels/widgets/filesPage.py @@ -5,9 +5,7 @@ import helper_methods from lib.utils.blocks_Scrollbar import CustomScrollBar from lib.utils.icon_button import IconButton -from lib.utils.list_button import ListCustomButton from PyQt6 import QtCore, QtGui, QtWidgets -from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem @@ -39,7 +37,6 @@ class FilesPage(QtWidgets.QWidget): def __init__(self, parent) -> None: super().__init__() - #VM self.model = EntryListModel() self.entry_delegate = EntryDelegate() self._setupUI() @@ -62,6 +59,14 @@ def __init__(self, parent) -> None: @QtCore.pyqtSlot(ListItem, name="on-item-selected") def _on_item_selected(self, item: ListItem) -> None: + """Slot called when a list item is selected in the UI. + This method is connected to the `item_selected` signal of the entry delegate. + It handles the selection of a `ListItem` and is intended to be overridden + or customized for each specific item type, allowing different behavior + depending on the item. + Args: + item : ListItem The item that was selected by the user. + """ logger.debug("Item Selected") @QtCore.pyqtSlot(name="reset-dir") @@ -91,6 +96,7 @@ def on_delete_file(self, filename: str) -> None: ... @QtCore.pyqtSlot(dict, name="on-fileinfo") def on_fileinfo(self, filedata: dict) -> None: + """Method called per file to contruct file entry to the list""" if not filedata or not self.isVisible(): return filename = filedata.get("filename", "") @@ -121,9 +127,7 @@ def on_fileinfo(self, filedata: dict) -> None: time_str = f"{hours}h {minutes}m" else: time_str = f"{minutes}m" - - - + name = helper_methods.get_file_name(filename) item = ListItem( text=name[:-6], @@ -160,15 +164,15 @@ def _fileItemClicked(self, filename: str) -> None: def _dirItemClicked( self, directory: str ) -> None: + """Method that changes the current view in the list """ self.curr_dir = self.curr_dir + directory self.request_dir_info[str].emit(self.curr_dir) def _build_file_list(self) -> None: """Inserts the currently available gcode files on the QListWidget""" - #self.listWidget.blockSignals(True) + self.listWidget.blockSignals(True) self.model.clear() self.entry_delegate.clear() - if not self.file_list and not self.directories and os.path.islink(self.curr_dir): self._add_placeholder() return @@ -187,9 +191,11 @@ def _build_file_list(self) -> None: self._add_file_list_item(item) self._setup_scrollbar() + self.listWidget.blockSignals(False) self.listWidget.repaint() def _add_directory_list_item(self, dir_data: dict) -> None: + """Method that adds directories to the list """ dir_name = dir_data.get("dirname", "") if not dir_name: return @@ -207,6 +213,7 @@ def _add_directory_list_item(self, dir_data: dict) -> None: self.model.add_item(item) def _add_back_folder_entry(self) -> None: + """Method to insert in the list the "Go back" item """ go_back_path = os.path.dirname(self.curr_dir) if go_back_path == "/": go_back_path = "" @@ -253,7 +260,6 @@ def _add_file_list_item(self, file_data_item) -> None: def _add_placeholder(self) -> None: self.scrollbar.hide() self.listWidget.hide() - self.label.show() @@ -288,7 +294,6 @@ def _setupUI(self): sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) self.setMinimumSize(QtCore.QSize(710, 400)) - #self.setMaximumSize(QtCore.QSize(500, 400)) font = QtGui.QFont() font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) self.setFont(font) @@ -331,13 +336,8 @@ def _setupUI(self): self.line.setObjectName("line") self.verticalLayout_5.addWidget(self.line) self.fp_content_layout = QtWidgets.QHBoxLayout() - #self.fp_content_layout.setContentsMargins(0, 0, 0, 0) + self.fp_content_layout.setContentsMargins(0, 0, 0, 0) self.fp_content_layout.setObjectName("fp_content_layout") - #self.setMinimumSize(QtCore.QSize(800, 500)) - - - - #Listwidget self.listWidget = QtWidgets.QListView(parent=self) self.listWidget.setModel(self.model) self.listWidget.setItemDelegate(self.entry_delegate) @@ -349,7 +349,6 @@ def _setupUI(self): self.listWidget.setUniformItemSizes(True) self.listWidget.setObjectName("listWidget") self.listWidget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - self.listWidget.setDefaultDropAction(QtCore.Qt.DropAction.IgnoreAction) self.listWidget.setSelectionBehavior( QtWidgets.QAbstractItemView.SelectionBehavior.SelectItems ) @@ -390,12 +389,7 @@ def _setupUI(self): font = QtGui.QFont() font.setPointSize(25) - #placeholder_item = QtWidgets.QListWidgetItem() - #placeholder_item.setSizeHint( - # QtCore.QSize(self.listWidget.width(), self.listWidget.height()) - #) self.label = QtWidgets.QLabel("No Files found") - # self.label.setBuddy(self.listWidget) self.label.setFont(font) self.label.setStyleSheet("color: gray;") self.label.setMinimumSize( @@ -411,10 +405,6 @@ def _setupUI(self): self.scrollbar = CustomScrollBar() self.fp_content_layout.addWidget(self.scrollbar) self.verticalLayout_5.addLayout(self.fp_content_layout) - #self.scrollbar.setAttribute( - # QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents, True - #) - #self.scroller = QtWidgets.QScroller.scroller(self.listWidget) self.scrollbar.show() self.label.hide() From 77cb5aa1e1b7e651ceee236e543f488aedbef215 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Tue, 2 Dec 2025 14:54:55 +0000 Subject: [PATCH 8/8] filesPage.py: remove unused lines of code Signed-off-by: Guilherme Costa --- BlocksScreen/lib/panels/widgets/filesPage.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/filesPage.py b/BlocksScreen/lib/panels/widgets/filesPage.py index 86f9c2f4..c9ec7211 100644 --- a/BlocksScreen/lib/panels/widgets/filesPage.py +++ b/BlocksScreen/lib/panels/widgets/filesPage.py @@ -270,9 +270,6 @@ def _handle_scrollbar(self, value): self.scrollbar.blockSignals(False) def _setup_scrollbar(self) -> None: - idx = self.model.index(0, 0) - - rect = self.listWidget.rectForIndex(idx) self.scrollbar.setMinimum( self.listWidget.verticalScrollBar().minimum() )