Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ jobs:
--mainExe ${{ matrix.main_exe }} \
--packTitle "${{ env.VELOPACK_APP_TITLE }}" \
--channel ${{ inputs.channel }}-${{ matrix.platform }} \
--shortcutLocations StartMenuRoot \
--outputDir releases

- name: Upload release artifacts
Expand Down
66 changes: 33 additions & 33 deletions pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ build = [
"pyinstaller>=6.19.0",
]
lint = [
"ruff>=0.15.6",
"pyrefly>=0.57.0",
"ruff>=0.15.7",
"pyrefly>=0.57.1",
]
test = [
"pytest>=9.0.2",
"pytest-cov>=7.0.0",
"pytest-cov>=7.1.0",
"pytest-mock>=3.15.1",
]

Expand Down
26 changes: 23 additions & 3 deletions synodic_client/application/screen/plugin_row.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from synodic_client.application.screen.spinner import SpinnerCanvas
from synodic_client.application.theme import (
FILTER_CHIP_STYLE,
PLUGIN_CHECK_STYLE,
PLUGIN_KIND_HEADER_STYLE,
PLUGIN_PROVIDER_NAME_STYLE,
PLUGIN_PROVIDER_RUNTIME_TAG_DEFAULT_STYLE,
Expand Down Expand Up @@ -138,6 +139,9 @@ class PluginProviderHeader(QFrame):
auto_update_toggled = Signal(str, bool)
"""Emitted with ``(plugin_name, enabled)`` when the auto-update toggle changes."""

check_requested = Signal(str)
"""Emitted with the plugin name when the manual check-for-updates button is clicked."""

update_requested = Signal(str)
"""Emitted with the plugin name when the per-plugin *Update* button is clicked."""

Expand All @@ -159,6 +163,7 @@ def __init__(
self._runtime_tag = ''
self._signal_key = plugin.name
self._update_btn: QPushButton | None = None
self._check_btn: QPushButton | None = None
self._checking_spinner: _RowSpinner | None = None

self._layout = QHBoxLayout(self)
Expand Down Expand Up @@ -230,8 +235,8 @@ def _build_controls(
auto_update: bool,
has_updates: bool,
) -> None:
"""Build Auto/Update control buttons."""
toggle_btn = QPushButton('Auto')
"""Build auto-update toggle, check, and Update control buttons."""
toggle_btn = QPushButton('\u21ba')
toggle_btn.setCheckable(True)
toggle_btn.setChecked(auto_update)
toggle_btn.setStyleSheet(PLUGIN_TOGGLE_STYLE)
Expand All @@ -241,6 +246,15 @@ def _build_controls(
)
layout.addWidget(toggle_btn)

check_btn = QPushButton('\u27f3')
check_btn.setStyleSheet(PLUGIN_CHECK_STYLE)
check_btn.setToolTip('Check for updates now')
check_btn.clicked.connect(
lambda: self.check_requested.emit(self._signal_key),
)
self._check_btn = check_btn
layout.addWidget(check_btn)

self._checking_spinner = _RowSpinner(self)
layout.addWidget(self._checking_spinner)

Expand All @@ -258,6 +272,8 @@ def _build_controls(
toggle_btn.setEnabled(False)
toggle_btn.setChecked(False)
toggle_btn.setToolTip('Not installed \u2014 cannot auto-update')
check_btn.setEnabled(False)
check_btn.setToolTip('Not installed \u2014 cannot check for updates')
update_btn.setEnabled(False)
update_btn.setToolTip('Not installed \u2014 cannot update')

Expand All @@ -281,10 +297,14 @@ def set_checking(self, checking: bool) -> None:
return
if checking:
self._checking_spinner.start()
if self._check_btn is not None:
self._check_btn.hide()
if self._update_btn is not None:
self._update_btn.hide()
else:
self._checking_spinner.stop()
if self._check_btn is not None:
self._check_btn.show()

def set_error(self, message: str) -> None:
"""Show a transient inline error that auto-hides after ~5 seconds."""
Expand Down Expand Up @@ -443,7 +463,7 @@ def _build_controls(self, layout: QHBoxLayout, data: PluginRowData) -> None:

def _build_toggle(self, layout: QHBoxLayout, data: PluginRowData) -> None:
"""Add the auto-update toggle button."""
toggle_btn = QPushButton('Auto')
toggle_btn = QPushButton('\u21ba')
toggle_btn.setCheckable(True)
toggle_btn.setChecked(data.auto_update)
toggle_btn.setStyleSheet(PLUGIN_ROW_TOGGLE_STYLE)
Expand Down
5 changes: 5 additions & 0 deletions synodic_client/application/screen/screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ class ToolsView(QWidget):
update_all_requested = Signal()
"""Emitted when the global *Update All* button is clicked."""

plugin_check_requested = Signal(str)
"""Emitted with a plugin name when its manual check-for-updates button is clicked."""

plugin_update_requested = Signal(str)
"""Emitted with a plugin name when its per-plugin *Update* button is clicked."""

Expand Down Expand Up @@ -495,6 +498,7 @@ def _sort_key(rt: RuntimePackageResult) -> tuple[int, str]:
)
provider.set_runtime(rt.tag, label=tag_text)
provider.auto_update_toggled.connect(self._on_auto_update_toggled)
provider.check_requested.connect(self.plugin_check_requested.emit)
provider.update_requested.connect(self.plugin_update_requested.emit)
self._insert_section_widget(provider)

Expand Down Expand Up @@ -558,6 +562,7 @@ def _build_plugin_section(
parent=self._container,
)
provider.auto_update_toggled.connect(self._on_auto_update_toggled)
provider.check_requested.connect(self.plugin_check_requested.emit)
provider.update_requested.connect(self.plugin_update_requested.emit)
self._insert_section_widget(provider)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ def _on_periodic_tool_update(self) -> None:
def connect_tools_view(self, tools_view: ToolsView) -> None:
"""Wire ToolsView signals once the view is lazily created."""
tools_view.update_all_requested.connect(self.on_tool_update)
tools_view.plugin_check_requested.connect(self.on_single_plugin_update)
tools_view.plugin_update_requested.connect(self.on_single_plugin_update)
tools_view.package_update_requested.connect(self.on_single_package_update)
tools_view.package_remove_requested.connect(self.on_single_package_remove)
Expand Down
43 changes: 30 additions & 13 deletions synodic_client/application/theme.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,16 @@
"""Host-tool annotation label (e.g. "→ pdm") for injected packages."""

PLUGIN_ROW_TOGGLE_STYLE = (
'QPushButton { padding: 1px 4px; border: 1px solid palette(mid); border-radius: 2px;'
' font-size: 10px; min-width: 36px; max-width: 36px; }'
'QPushButton:checked { background: #89d185; color: black; }'
'QPushButton:disabled { color: palette(mid); border-color: palette(mid); background: transparent; }'
'QPushButton:checked:disabled { background: transparent; color: palette(mid); }'
'QPushButton { padding: 0px; border: 1px solid palette(mid); border-radius: 11px;'
' font-size: 14px; min-width: 22px; max-width: 22px; min-height: 22px; max-height: 22px;'
' color: palette(mid); background: transparent; }'
'QPushButton:hover { border-color: palette(light); color: palette(light); }'
'QPushButton:checked { background: #89d185; color: black; border-color: #89d185; }'
'QPushButton:checked:hover { background: #a0d896; border-color: #a0d896; }'
'QPushButton:disabled { color: palette(dark); border-color: palette(dark); background: transparent; }'
'QPushButton:checked:disabled { background: transparent; color: palette(dark); border-color: palette(dark); }'
)
"""Small inline auto-update toggle for individual package rows."""
"""Small circular auto-update toggle (↺ icon) for individual package rows."""

PLUGIN_ROW_UPDATE_STYLE = (
'QPushButton { padding: 1px 4px; border: 1px solid palette(mid); border-radius: 2px;'
Expand Down Expand Up @@ -345,14 +348,28 @@
)
"""Filter toggle button style when an active filter is in effect."""

# Retained from previous design — auto-update & per-plugin update buttons
# Auto-update toggle button for plugin provider header rows — circular, stateful
PLUGIN_TOGGLE_STYLE = (
'QPushButton { padding: 2px 8px; border: 1px solid palette(mid); border-radius: 3px;'
' min-width: 60px; max-width: 60px; }'
'QPushButton:checked { background: #89d185; color: black; }'
'QPushButton:disabled { color: palette(mid); border-color: palette(mid); background: transparent; }'
'QPushButton:checked:disabled { background: transparent; color: palette(mid); }'
)
'QPushButton { padding: 0px; border: 1px solid palette(mid); border-radius: 12px;'
' font-size: 15px; min-width: 24px; max-width: 24px; min-height: 24px; max-height: 24px;'
' color: palette(mid); background: transparent; }'
'QPushButton:hover { border-color: palette(light); color: palette(light); }'
'QPushButton:checked { background: #89d185; color: black; border-color: #89d185; }'
'QPushButton:checked:hover { background: #a0d896; border-color: #a0d896; }'
'QPushButton:disabled { color: palette(dark); border-color: palette(dark); background: transparent; }'
'QPushButton:checked:disabled { background: transparent; color: palette(dark); border-color: palette(dark); }'
)

# Manual check-for-updates button for plugin provider header rows — rect, one-shot action
PLUGIN_CHECK_STYLE = (
'QPushButton { padding: 0px; border: 1px solid palette(mid); border-radius: 3px;'
' font-size: 15px; min-width: 24px; max-width: 24px; min-height: 24px; max-height: 24px;'
' color: palette(mid); background: transparent; }'
'QPushButton:hover { border-color: #569cd6; color: #569cd6; }'
'QPushButton:pressed { background: rgba(86, 156, 214, 0.15); }'
'QPushButton:disabled { color: palette(dark); border-color: palette(dark); background: transparent; }'
)
"""One-shot check-for-updates icon button used in the plugin provider header."""

PLUGIN_UPDATE_STYLE = (
'QPushButton { padding: 2px 8px; border: 1px solid palette(mid); border-radius: 3px;'
Expand Down
Loading