mirror of
https://github.com/yusufipk/dikte.git
synced 2026-09-11 19:06:11 +00:00
fix: address settings width and overlay review
This commit is contained in:
@@ -272,13 +272,6 @@ class Overlay(QWidget):
|
|||||||
if self.below is not None and self.below.showing != self._stacked:
|
if self.below is not None and self.below.showing != self._stacked:
|
||||||
self._reposition()
|
self._reposition()
|
||||||
elif self.state in LIVE:
|
elif self.state in LIVE:
|
||||||
# Follow the screen the mouse is currently on. Checked every ten
|
|
||||||
# ticks (~333 ms) rather than every frame: screenAt() is cheap but
|
|
||||||
# the user's hand moves slowly, so there is no value in sampling it
|
|
||||||
# at 30 Hz.
|
|
||||||
self._screen_check_ticks = getattr(self, "_screen_check_ticks", 0) + 1
|
|
||||||
if self._screen_check_ticks >= 10:
|
|
||||||
self._screen_check_ticks = 0
|
|
||||||
current_screen = QApplication.screenAt(QCursor.pos())
|
current_screen = QApplication.screenAt(QCursor.pos())
|
||||||
if current_screen is not None and current_screen != self.screen():
|
if current_screen is not None and current_screen != self.screen():
|
||||||
self._reposition()
|
self._reposition()
|
||||||
|
|||||||
+19
-12
@@ -12,7 +12,7 @@ from PyQt6.QtWidgets import (
|
|||||||
QAbstractItemView, QAbstractSpinBox, QCheckBox, QComboBox, QDialog,
|
QAbstractItemView, QAbstractSpinBox, QCheckBox, QComboBox, QDialog,
|
||||||
QDialogButtonBox, QFileDialog, QFormLayout, QGroupBox, QHBoxLayout, QLabel,
|
QDialogButtonBox, QFileDialog, QFormLayout, QGroupBox, QHBoxLayout, QLabel,
|
||||||
QLineEdit, QListWidget, QListWidgetItem, QMenu, QMessageBox, QPlainTextEdit,
|
QLineEdit, QListWidget, QListWidgetItem, QMenu, QMessageBox, QPlainTextEdit,
|
||||||
QPushButton, QScrollArea, QSpinBox, QTabWidget, QVBoxLayout, QWidget, QSizePolicy,
|
QPushButton, QScrollArea, QSpinBox, QTabWidget, QVBoxLayout, QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
@@ -229,6 +229,8 @@ class LocalModelBox(QGroupBox):
|
|||||||
self._wanted = "" # the model to select once a list arrives
|
self._wanted = "" # the model to select once a list arrives
|
||||||
|
|
||||||
form = QFormLayout(self)
|
form = QFormLayout(self)
|
||||||
|
form.setFieldGrowthPolicy(
|
||||||
|
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
|
|
||||||
self.program_label = WrappedLabel()
|
self.program_label = WrappedLabel()
|
||||||
self.install_button = QPushButton(t("Download"))
|
self.install_button = QPushButton(t("Download"))
|
||||||
@@ -239,7 +241,6 @@ class LocalModelBox(QGroupBox):
|
|||||||
if self._repos is not None:
|
if self._repos is not None:
|
||||||
self.repo = QComboBox()
|
self.repo = QComboBox()
|
||||||
self.repo.setEditable(True)
|
self.repo.setEditable(True)
|
||||||
self.repo.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.repo.setToolTip(t("A Hugging Face repository of GGUF files. The "
|
self.repo.setToolTip(t("A Hugging Face repository of GGUF files. The "
|
||||||
"list is fetched; any other one can be typed in."))
|
"list is fetched; any other one can be typed in."))
|
||||||
self.repo.currentTextChanged.connect(self._repo_changed)
|
self.repo.currentTextChanged.connect(self._repo_changed)
|
||||||
@@ -679,6 +680,8 @@ class SettingsWindow(QDialog):
|
|||||||
def _general_tab(self):
|
def _general_tab(self):
|
||||||
page = QWidget()
|
page = QWidget()
|
||||||
form = QFormLayout(page)
|
form = QFormLayout(page)
|
||||||
|
form.setFieldGrowthPolicy(
|
||||||
|
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
|
|
||||||
self.ui_language = QComboBox()
|
self.ui_language = QComboBox()
|
||||||
for label, code in UI_LANGUAGES:
|
for label, code in UI_LANGUAGES:
|
||||||
@@ -704,7 +707,6 @@ class SettingsWindow(QDialog):
|
|||||||
# them: a stored one this desktop does not offer is kept as it is
|
# them: a stored one this desktop does not offer is kept as it is
|
||||||
# rather than quietly replaced by the first item on the list.
|
# rather than quietly replaced by the first item on the list.
|
||||||
self.paste_shortcut.setEditable(True)
|
self.paste_shortcut.setEditable(True)
|
||||||
self.paste_shortcut.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.paste_shortcut.addItems(paste.desktop().shortcuts)
|
self.paste_shortcut.addItems(paste.desktop().shortcuts)
|
||||||
self.paste_shortcut.setToolTip(t(
|
self.paste_shortcut.setToolTip(t(
|
||||||
"macOS asks for Accessibility permission the first time this is sent."
|
"macOS asks for Accessibility permission the first time this is sent."
|
||||||
@@ -792,6 +794,8 @@ class SettingsWindow(QDialog):
|
|||||||
|
|
||||||
stt = QGroupBox(t("Speech to text"))
|
stt = QGroupBox(t("Speech to text"))
|
||||||
stt_form = QFormLayout(stt)
|
stt_form = QFormLayout(stt)
|
||||||
|
stt_form.setFieldGrowthPolicy(
|
||||||
|
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
self.transcribe_provider = QComboBox()
|
self.transcribe_provider = QComboBox()
|
||||||
for label, value in TRANSCRIBE_PROVIDERS:
|
for label, value in TRANSCRIBE_PROVIDERS:
|
||||||
self.transcribe_provider.addItem(t(label), value)
|
self.transcribe_provider.addItem(t(label), value)
|
||||||
@@ -803,7 +807,6 @@ class SettingsWindow(QDialog):
|
|||||||
self.stt_form = stt_form
|
self.stt_form = stt_form
|
||||||
self.transcribe_model = QComboBox()
|
self.transcribe_model = QComboBox()
|
||||||
self.transcribe_model.setEditable(True)
|
self.transcribe_model.setEditable(True)
|
||||||
self.transcribe_model.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.refresh_transcribe_models = QPushButton(t("Fetch model list"))
|
self.refresh_transcribe_models = QPushButton(t("Fetch model list"))
|
||||||
self.refresh_transcribe_models.clicked.connect(self._load_transcribe_models)
|
self.refresh_transcribe_models.clicked.connect(self._load_transcribe_models)
|
||||||
self.transcribe_model_row = self._row(self.transcribe_model,
|
self.transcribe_model_row = self._row(self.transcribe_model,
|
||||||
@@ -854,6 +857,8 @@ class SettingsWindow(QDialog):
|
|||||||
|
|
||||||
orr = QGroupBox(t("Transcript cleanup"))
|
orr = QGroupBox(t("Transcript cleanup"))
|
||||||
orr_form = self.cleanup_form = QFormLayout(orr)
|
orr_form = self.cleanup_form = QFormLayout(orr)
|
||||||
|
orr_form.setFieldGrowthPolicy(
|
||||||
|
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
self.cleanup_enabled = QCheckBox(t("Clean the transcript with a model"))
|
self.cleanup_enabled = QCheckBox(t("Clean the transcript with a model"))
|
||||||
orr_form.addRow("", self.cleanup_enabled)
|
orr_form.addRow("", self.cleanup_enabled)
|
||||||
|
|
||||||
@@ -872,7 +877,6 @@ class SettingsWindow(QDialog):
|
|||||||
|
|
||||||
self.cleanup_model = QComboBox()
|
self.cleanup_model = QComboBox()
|
||||||
self.cleanup_model.setEditable(True)
|
self.cleanup_model.setEditable(True)
|
||||||
self.cleanup_model.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.cleanup_model.addItems(CLEANUP_MODELS)
|
self.cleanup_model.addItems(CLEANUP_MODELS)
|
||||||
self.refresh_models = QPushButton(t("Fetch model list"))
|
self.refresh_models = QPushButton(t("Fetch model list"))
|
||||||
self.refresh_models.clicked.connect(self._load_models)
|
self.refresh_models.clicked.connect(self._load_models)
|
||||||
@@ -884,14 +888,12 @@ class SettingsWindow(QDialog):
|
|||||||
# field, and only the row of whoever is chosen is on screen.
|
# field, and only the row of whoever is chosen is on screen.
|
||||||
self.cleanup_claude_model = QComboBox()
|
self.cleanup_claude_model = QComboBox()
|
||||||
self.cleanup_claude_model.setEditable(True)
|
self.cleanup_claude_model.setEditable(True)
|
||||||
self.cleanup_claude_model.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.cleanup_claude_model.addItems(CLEANUP_CLAUDE_MODELS)
|
self.cleanup_claude_model.addItems(CLEANUP_CLAUDE_MODELS)
|
||||||
self.cleanup_claude_model.setToolTip(_typed_model_note("Claude Code"))
|
self.cleanup_claude_model.setToolTip(_typed_model_note("Claude Code"))
|
||||||
orr_form.addRow(t("Model"), self.cleanup_claude_model)
|
orr_form.addRow(t("Model"), self.cleanup_claude_model)
|
||||||
|
|
||||||
self.cleanup_codex_model = QComboBox()
|
self.cleanup_codex_model = QComboBox()
|
||||||
self.cleanup_codex_model.setEditable(True)
|
self.cleanup_codex_model.setEditable(True)
|
||||||
self.cleanup_codex_model.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.cleanup_codex_model.addItems([t("Codex's own default")] + CODEX_MODELS)
|
self.cleanup_codex_model.addItems([t("Codex's own default")] + CODEX_MODELS)
|
||||||
self.cleanup_codex_model.setToolTip(_typed_model_note("Codex"))
|
self.cleanup_codex_model.setToolTip(_typed_model_note("Codex"))
|
||||||
orr_form.addRow(t("Model"), self.cleanup_codex_model)
|
orr_form.addRow(t("Model"), self.cleanup_codex_model)
|
||||||
@@ -1046,9 +1048,10 @@ class SettingsWindow(QDialog):
|
|||||||
# be worse than none.
|
# be worse than none.
|
||||||
self.claude_box = QGroupBox(t("Claude Code"))
|
self.claude_box = QGroupBox(t("Claude Code"))
|
||||||
claude_form = QFormLayout(self.claude_box)
|
claude_form = QFormLayout(self.claude_box)
|
||||||
|
claude_form.setFieldGrowthPolicy(
|
||||||
|
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
self.assistant_model = QComboBox()
|
self.assistant_model = QComboBox()
|
||||||
self.assistant_model.setEditable(True)
|
self.assistant_model.setEditable(True)
|
||||||
self.assistant_model.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.assistant_model.addItems(ASSISTANT_MODELS)
|
self.assistant_model.addItems(ASSISTANT_MODELS)
|
||||||
self.assistant_model.setToolTip(t(
|
self.assistant_model.setToolTip(t(
|
||||||
"A name like “sonnet” always means the newest model of that line. "
|
"A name like “sonnet” always means the newest model of that line. "
|
||||||
@@ -1064,9 +1067,10 @@ class SettingsWindow(QDialog):
|
|||||||
|
|
||||||
self.codex_box = QGroupBox(t("Codex"))
|
self.codex_box = QGroupBox(t("Codex"))
|
||||||
codex_form = QFormLayout(self.codex_box)
|
codex_form = QFormLayout(self.codex_box)
|
||||||
|
codex_form.setFieldGrowthPolicy(
|
||||||
|
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
self.assistant_codex_model = QComboBox()
|
self.assistant_codex_model = QComboBox()
|
||||||
self.assistant_codex_model.setEditable(True)
|
self.assistant_codex_model.setEditable(True)
|
||||||
self.assistant_codex_model.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.assistant_codex_model.addItem(t("Codex's own default"), "")
|
self.assistant_codex_model.addItem(t("Codex's own default"), "")
|
||||||
for name in CODEX_MODELS:
|
for name in CODEX_MODELS:
|
||||||
self.assistant_codex_model.addItem(name, name)
|
self.assistant_codex_model.addItem(name, name)
|
||||||
@@ -1080,9 +1084,10 @@ class SettingsWindow(QDialog):
|
|||||||
|
|
||||||
self.openrouter_box = QGroupBox("OpenRouter")
|
self.openrouter_box = QGroupBox("OpenRouter")
|
||||||
or_form = QFormLayout(self.openrouter_box)
|
or_form = QFormLayout(self.openrouter_box)
|
||||||
|
or_form.setFieldGrowthPolicy(
|
||||||
|
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
self.assistant_openrouter_model = QComboBox()
|
self.assistant_openrouter_model = QComboBox()
|
||||||
self.assistant_openrouter_model.setEditable(True)
|
self.assistant_openrouter_model.setEditable(True)
|
||||||
self.assistant_openrouter_model.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.assistant_openrouter_model.addItems(ASSISTANT_OR_MODELS)
|
self.assistant_openrouter_model.addItems(ASSISTANT_OR_MODELS)
|
||||||
or_form.addRow(t("Model"), self.assistant_openrouter_model)
|
or_form.addRow(t("Model"), self.assistant_openrouter_model)
|
||||||
or_note = QLabel(t(
|
or_note = QLabel(t(
|
||||||
@@ -1228,9 +1233,10 @@ class SettingsWindow(QDialog):
|
|||||||
|
|
||||||
models = QGroupBox(t("Minutes"))
|
models = QGroupBox(t("Minutes"))
|
||||||
models_form = QFormLayout(models)
|
models_form = QFormLayout(models)
|
||||||
|
models_form.setFieldGrowthPolicy(
|
||||||
|
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
self.meeting_model = QComboBox()
|
self.meeting_model = QComboBox()
|
||||||
self.meeting_model.setEditable(True)
|
self.meeting_model.setEditable(True)
|
||||||
self.meeting_model.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
self.meeting_model.addItems(MEETING_MODELS)
|
self.meeting_model.addItems(MEETING_MODELS)
|
||||||
models_form.addRow(t("Model"), self.meeting_model)
|
models_form.addRow(t("Model"), self.meeting_model)
|
||||||
self.meeting_reasoning = QComboBox()
|
self.meeting_reasoning = QComboBox()
|
||||||
@@ -1411,6 +1417,8 @@ class SettingsWindow(QDialog):
|
|||||||
# and two combination boxes starting at different places read as two
|
# and two combination boxes starting at different places read as two
|
||||||
# unrelated settings rather than the pair they are.
|
# unrelated settings rather than the pair they are.
|
||||||
form = QFormLayout()
|
form = QFormLayout()
|
||||||
|
form.setFieldGrowthPolicy(
|
||||||
|
QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||||
self._shortcut_row(
|
self._shortcut_row(
|
||||||
form, "toggle", t("Start and stop"),
|
form, "toggle", t("Start and stop"),
|
||||||
t("No global shortcut installed."), placeholder="Ctrl+Space",
|
t("No global shortcut installed."), placeholder="Ctrl+Space",
|
||||||
@@ -1561,7 +1569,6 @@ class SettingsWindow(QDialog):
|
|||||||
"""The field a global shortcut is typed or picked in."""
|
"""The field a global shortcut is typed or picked in."""
|
||||||
box = QComboBox()
|
box = QComboBox()
|
||||||
box.setEditable(True)
|
box.setEditable(True)
|
||||||
box.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
||||||
box.addItems(MAC_SHORTCUTS if hotkey.backend() == hotkey.MACOS
|
box.addItems(MAC_SHORTCUTS if hotkey.backend() == hotkey.MACOS
|
||||||
else SHORTCUTS)
|
else SHORTCUTS)
|
||||||
box.setCurrentText("")
|
box.setCurrentText("")
|
||||||
|
|||||||
+52
-1
@@ -12,7 +12,7 @@ import unittest
|
|||||||
from typing import ClassVar
|
from typing import ClassVar
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from PyQt6.QtCore import QPoint, QPointF, Qt
|
from PyQt6.QtCore import QPoint, QPointF, QRect, Qt
|
||||||
from PyQt6.QtGui import QWheelEvent
|
from PyQt6.QtGui import QWheelEvent
|
||||||
from PyQt6.QtWidgets import QApplication, QMessageBox
|
from PyQt6.QtWidgets import QApplication, QMessageBox
|
||||||
|
|
||||||
@@ -271,6 +271,46 @@ class Settings(DikteTest):
|
|||||||
self.assertEqual(shown, [provider])
|
self.assertEqual(shown, [provider])
|
||||||
self.assertFalse(box.isHidden())
|
self.assertFalse(box.isHidden())
|
||||||
|
|
||||||
|
def test_editable_boxes_live_in_forms_that_grow_the_field_column(self):
|
||||||
|
window = self.window(cfg.Config())
|
||||||
|
|
||||||
|
def contains(layout, target):
|
||||||
|
for index in range(layout.count()):
|
||||||
|
item = layout.itemAt(index)
|
||||||
|
widget = item.widget()
|
||||||
|
if widget is target or (widget is not None and
|
||||||
|
widget.isAncestorOf(target)):
|
||||||
|
return True
|
||||||
|
child = item.layout()
|
||||||
|
if child is not None and contains(child, target):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
forms = window.findChildren(settings_ui.QFormLayout)
|
||||||
|
boxes = [
|
||||||
|
window.paste_shortcut,
|
||||||
|
window.transcribe_model,
|
||||||
|
window.cleanup_model,
|
||||||
|
window.cleanup_claude_model,
|
||||||
|
window.cleanup_codex_model,
|
||||||
|
window.assistant_model,
|
||||||
|
window.assistant_codex_model,
|
||||||
|
window.assistant_openrouter_model,
|
||||||
|
window.meeting_model,
|
||||||
|
window.local_llm.repo,
|
||||||
|
*(box for box, _status, _missing in
|
||||||
|
window._shortcut_rows.values()),
|
||||||
|
]
|
||||||
|
for box in boxes:
|
||||||
|
form = next((candidate for candidate in forms
|
||||||
|
if contains(candidate, box)), None)
|
||||||
|
with self.subTest(box=box.objectName() or box.currentText()):
|
||||||
|
self.assertIsNotNone(form)
|
||||||
|
self.assertEqual(
|
||||||
|
form.fieldGrowthPolicy(),
|
||||||
|
settings_ui.QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow,
|
||||||
|
)
|
||||||
|
|
||||||
def test_codex_answering_refills_both_of_its_boxes(self):
|
def test_codex_answering_refills_both_of_its_boxes(self):
|
||||||
"""The list Codex gave replaces the built-in one, in both places, and
|
"""The list Codex gave replaces the built-in one, in both places, and
|
||||||
neither loses what was already picked."""
|
neither loses what was already picked."""
|
||||||
@@ -941,6 +981,17 @@ class Overlay(DikteTest):
|
|||||||
widget.show_recording()
|
widget.show_recording()
|
||||||
widget._reposition()
|
widget._reposition()
|
||||||
|
|
||||||
|
def test_a_live_indicator_follows_the_cursor_to_another_screen(self):
|
||||||
|
widget = self.overlay(corner="top-left")
|
||||||
|
widget.show_recording()
|
||||||
|
other_screen = mock.Mock()
|
||||||
|
other_screen.availableGeometry.return_value = QRect(1000, 200, 800, 600)
|
||||||
|
with mock.patch.object(QApplication, "screenAt",
|
||||||
|
return_value=other_screen):
|
||||||
|
widget._tick()
|
||||||
|
self.assertEqual(widget.pos(), QPoint(1000 + overlay_module.MARGIN,
|
||||||
|
200 + overlay_module.MARGIN))
|
||||||
|
|
||||||
def test_a_warning_and_an_error_both_show(self):
|
def test_a_warning_and_an_error_both_show(self):
|
||||||
widget = self.overlay()
|
widget = self.overlay()
|
||||||
widget.show_warning("cleanup failed")
|
widget.show_warning("cleanup failed")
|
||||||
|
|||||||
Reference in New Issue
Block a user