Added copy-to-clipboard button in recording transcribe widget (#1370)

This commit is contained in:
Anantharaman R 2026-02-06 23:59:58 +05:30 committed by GitHub
commit 156ec35246
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 140 additions and 0 deletions

View file

@ -16,6 +16,7 @@ from PyQt6.QtWidgets import (
QFormLayout,
QHBoxLayout,
QMessageBox,
QApplication,
QPushButton,
QComboBox,
QLabel,
@ -209,6 +210,9 @@ class RecordingTranscriberWidget(QWidget):
self.presentation_options_bar = self.create_presentation_options_bar()
layout.insertWidget(3, self.presentation_options_bar)
self.presentation_options_bar.hide()
self.copy_actions_bar = self.create_copy_actions_bar()
layout.addWidget(self.copy_actions_bar) # Add at the bottom
self.copy_actions_bar.hide()
def create_presentation_options_bar(self) -> QWidget:
"""Crete the presentation options bar widget"""
@ -286,6 +290,56 @@ class RecordingTranscriberWidget(QWidget):
return bar
def create_copy_actions_bar(self) -> QWidget:
"""Create the copy actions bar widget"""
bar = QWidget(self)
layout = QHBoxLayout(bar)
layout.setContentsMargins(5, 5, 5, 5)
layout.setSpacing(10)
layout.addStretch() # Push button to the right
self.copy_transcript_button = QPushButton(_("Copy"), bar)
self.copy_transcript_button.setToolTip(_("Copy transcription to clipboard"))
self.copy_transcript_button.clicked.connect(self.on_copy_transcript_clicked)
layout.addWidget(self.copy_transcript_button)
return bar
def on_copy_transcript_clicked(self):
"""Handle copy transcript button click"""
transcript_text = self.transcription_text_box.toPlainText().strip()
if not transcript_text:
self.copy_transcript_button.setText(_("Nothing to copy!"))
QTimer.singleShot(1500, lambda: self.copy_transcript_button.setText(_("Copy")))
return
app = QApplication.instance()
if app is None:
logging.warning("QApplication instance not available; clipboard disabled")
self.copy_transcript_button.setText(_("Copy failed"))
QTimer.singleShot(1500, lambda: self.copy_transcript_button.setText(_("Copy")))
return
clipboard = app.clipboard()
if clipboard is None:
logging.warning("Clipboard not available")
self.copy_transcript_button.setText(_("Copy failed"))
QTimer.singleShot(1500, lambda: self.copy_transcript_button.setText(_("Copy")))
return
try:
clipboard.setText(transcript_text)
except Exception as e:
logging.warning("Clipboard error: %s", e)
self.copy_transcript_button.setText(_("Copy failed"))
QTimer.singleShot(1500, lambda: self.copy_transcript_button.setText(_("Copy")))
return
self.copy_transcript_button.setText(_("Copied!"))
QTimer.singleShot(2000, lambda: self.copy_transcript_button.setText(_("Copy")))
def on_show_presentation_clicked(self):
"""Handle click on 'Show in new window' button"""
if self.presentation_window is None or not self.presentation_window.isVisible():
@ -464,6 +518,8 @@ class RecordingTranscriberWidget(QWidget):
self.transcription_options_group_box.setEnabled(False)
self.audio_devices_combo_box.setEnabled(False)
self.presentation_options_bar.show()
self.copy_actions_bar.hide()
else: # RecordingStatus.RECORDING
self.stop_recording()
self.set_recording_status_stopped()
@ -574,6 +630,7 @@ class RecordingTranscriberWidget(QWidget):
self.transcription_options_group_box.setEnabled(True)
self.audio_devices_combo_box.setEnabled(True)
self.presentation_options_bar.hide()
self.copy_actions_bar.show() #added this here
def on_download_model_error(self, error: str):
self.reset_model_download()

View file

@ -470,6 +470,89 @@ class TestRecordingTranscriberWidgetPresentation:
time.sleep(0.5)
widget.close()
@pytest.mark.timeout(60)
def test_on_copy_transcript_clicked_with_text(self, qtbot: QtBot):
with (
patch("sounddevice.InputStream", side_effect=MockInputStream),
patch("sounddevice.check_input_settings"),
patch(
"buzz.transcriber.recording_transcriber.RecordingTranscriber.get_device_sample_rate",
return_value=16_000,
),
):
mock_clipboard = MagicMock()
mock_app = MagicMock()
mock_app.clipboard.return_value = mock_clipboard
widget = RecordingTranscriberWidget(custom_sounddevice=MockSoundDevice())
qtbot.add_widget(widget)
widget.transcription_text_box.setPlainText("Hello world")
widget.copy_actions_bar.show()
with patch("buzz.widgets.recording_transcriber_widget.QApplication.instance",
return_value=mock_app):
widget.on_copy_transcript_clicked()
mock_clipboard.setText.assert_called_once_with("Hello world")
assert widget.copy_transcript_button.text() == _("Copied!")
time.sleep(0.5)
widget.close()
@pytest.mark.timeout(60)
def test_on_copy_transcript_clicked_without_text(self, qtbot: QtBot):
"""Test that copy button handles empty transcript gracefully"""
with (
patch("sounddevice.InputStream", side_effect=MockInputStream),
patch("sounddevice.check_input_settings"),
patch("buzz.transcriber.recording_transcriber.RecordingTranscriber.get_device_sample_rate",
return_value=16_000),
):
widget = RecordingTranscriberWidget(
custom_sounddevice=MockSoundDevice()
)
qtbot.add_widget(widget)
widget.transcription_text_box.setPlainText("")
widget.copy_actions_bar.show()
widget.on_copy_transcript_clicked()
assert widget.copy_transcript_button.text() == _("Nothing to copy!")
time.sleep(0.5)
widget.close()
@pytest.mark.timeout(60)
def test_copy_actions_bar_hidden_when_recording_starts(self, qtbot: QtBot):
"""Test that copy actions bar hides when recording starts"""
with (
patch("sounddevice.InputStream", side_effect=MockInputStream),
patch("sounddevice.check_input_settings"),
patch("buzz.transcriber.recording_transcriber.RecordingTranscriber.get_device_sample_rate",
return_value=16_000),
):
widget = RecordingTranscriberWidget(
custom_sounddevice=MockSoundDevice()
)
widget.device_sample_rate = 16_000
qtbot.add_widget(widget)
widget.copy_actions_bar.show()
assert not widget.copy_actions_bar.isHidden()
# Mock start_recording to prevent actual recording threads from starting
widget.current_status = widget.RecordingStatus.STOPPED
with patch.object(widget, 'start_recording'):
widget.on_record_button_clicked()
assert widget.copy_actions_bar.isHidden()
time.sleep(0.5)
widget.close()
@pytest.mark.timeout(60)
def test_on_bg_color_clicked(self, qtbot: QtBot):
"""Test that background color button opens color dialog and saves selection"""