Add chat history keyboard scrolling and remove unused PTT setting
This commit is contained in:
1 parent
5870efdf04
commit
4f6808156f
10 files changed
+81
-31
No files matched your search
@@ -492,7 +492,7 @@ if(TARGET X11::X11)
|
||||
target_link_libraries(test_message_notification_x11 PRIVATE chatgui_notifications ${QT_TEST_LIB} X11::X11 pthread ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
add_executable(test_file_drop tests/test_file_drop.cpp src/inputbar.cpp src/audiorecorder.cpp src/audio_device.cpp src/sound_manager.cpp
|
||||
add_executable(test_file_drop tests/test_file_drop.cpp src/inputbar.cpp src/chatview.cpp src/audiorecorder.cpp src/audio_device.cpp src/sound_manager.cpp
|
||||
src/voicemessageencoder.cpp src/emojipanel.cpp src/emojitabbar.cpp src/emoji.cpp src/animtimer.cpp src/lottieicon.cpp
|
||||
src/voice_audio_io.cpp transport/miniaudio_impl.c transport/audio_diagnostics.cpp)
|
||||
target_include_directories(test_file_drop PRIVATE ${UTUN_INCLUDE_DIRS})
|
||||
|
||||
@@ -78,11 +78,6 @@ ChannelSettingsDialog::ChannelSettingsDialog(const QString& channelId, DbManager
|
||||
m_soundOnMessage->setToolTip(QCoreApplication::translate("ChatGui", "Play a notification sound when a message arrives in this channel."));
|
||||
layout->addWidget(m_soundOnMessage);
|
||||
|
||||
m_pttMode = new QCheckBox(QCoreApplication::translate("ChatGui", "Push-To-Talk (PTT) mode"), this);
|
||||
m_pttMode->setToolTip(QCoreApplication::translate("ChatGui", "Record voice messages with push-to-talk. (Coming soon)"));
|
||||
m_pttMode->setEnabled(false);
|
||||
layout->addWidget(m_pttMode);
|
||||
|
||||
layout->addStretch();
|
||||
|
||||
auto* btnLayout = new QHBoxLayout();
|
||||
@@ -116,8 +111,6 @@ ChannelSettingsDialog::ChannelSettingsDialog(const QString& channelId, DbManager
|
||||
m_autoPlayVoice->setChecked(m_db->getUiStateInt(autoPlayKey, 0) != 0);
|
||||
QString soundKey = QStringLiteral("ch_%1_sound_on_message").arg(channelId);
|
||||
m_soundOnMessage->setChecked(m_db->getUiStateInt(soundKey, 1) != 0);
|
||||
QString pttKey = QStringLiteral("ch_%1_ptt_mode").arg(channelId);
|
||||
m_pttMode->setChecked(m_db->getUiStateInt(pttKey, 0) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +131,6 @@ void ChannelSettingsDialog::onSave() {
|
||||
}
|
||||
};
|
||||
saveKey("auto_play_voice", m_autoPlayVoice->isChecked() ? 1 : 0);
|
||||
saveKey("ptt_mode", m_pttMode->isChecked() ? 1 : 0);
|
||||
|
||||
/* sound_on_message: сохранить + разослать пирам (троттлинг db_sync на сервере) */
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Локальные настройки выбранного канала: autoplay голосовых, звук сообщений и режим PTT. */
|
||||
/* Локальные настройки выбранного канала: autoplay голосовых и звук сообщений. */
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
@@ -20,5 +20,4 @@ private:
|
||||
DbManager* m_db;
|
||||
QCheckBox* m_autoPlayVoice;
|
||||
QCheckBox* m_soundOnMessage;
|
||||
QCheckBox* m_pttMode;
|
||||
};
|
||||
@@ -208,7 +208,32 @@ void ChatView::mouseReleaseEvent(QMouseEvent *event) {
|
||||
QListView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
bool ChatView::scrollWithKey(QKeyEvent *event) {
|
||||
if (event->modifiers() != Qt::NoModifier) return false;
|
||||
QAbstractSlider::SliderAction action;
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Up: action = QAbstractSlider::SliderSingleStepSub; break;
|
||||
case Qt::Key_Down: action = QAbstractSlider::SliderSingleStepAdd; break;
|
||||
case Qt::Key_PageUp: action = QAbstractSlider::SliderPageStepSub; break;
|
||||
case Qt::Key_PageDown: action = QAbstractSlider::SliderPageStepAdd; break;
|
||||
default: return false;
|
||||
}
|
||||
auto* bar = verticalScrollBar();
|
||||
const int before = bar->value();
|
||||
bar->triggerAction(action);
|
||||
GUI_DEBUG("history keyboard scroll: key=%d action=%d position=%d->%d range=%d..%d",
|
||||
event->key(), int(action), before, bar->value(), bar->minimum(), bar->maximum());
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatView::eventFilter(QObject *object, QEvent *event) {
|
||||
if (event->type() == QEvent::KeyPress && isVisible() && isEnabled() && scrollWithKey(static_cast<QKeyEvent*>(event))) return true;
|
||||
return QListView::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void ChatView::keyPressEvent(QKeyEvent *event) {
|
||||
if (scrollWithKey(event)) return;
|
||||
if (event == QKeySequence::Copy) {
|
||||
copySelection();
|
||||
return;
|
||||
|
||||
@@ -42,6 +42,8 @@ signals:
|
||||
void latestRequested();
|
||||
|
||||
protected:
|
||||
/* Up/Down/PgUp/PgDown от поля ввода и окна, установивших этот вид как eventFilter. */
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
bool viewportEvent(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
@@ -52,6 +54,8 @@ protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
|
||||
private:
|
||||
/* Прокрутить историю по клавише без модификаторов; true, если событие принято. Фокус сохраняется. */
|
||||
bool scrollWithKey(QKeyEvent *event);
|
||||
void copySelection();
|
||||
void updateScrollDownBtn();
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ InputBar::InputBar(EmojiPanel *emojiPanel, AudioRecorder *recorder, QWidget *par
|
||||
m_input->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_input->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_input->setTabChangesFocus(true);
|
||||
setFocusProxy(m_input);
|
||||
m_input->setStyleSheet(
|
||||
"QTextEdit { border: 1px solid palette(mid); border-radius: 6px;"
|
||||
" padding: 4px 8px; background: palette(base); }"
|
||||
|
||||
@@ -680,6 +680,8 @@ MessageList::MessageList(DbManager* db, AudioRecorder* recorder, QWidget *parent
|
||||
m_inputBar = new InputBar(m_emojiPanel, recorder, this);
|
||||
layout->addWidget(m_inputBar);
|
||||
m_inputBar->installFileDropTarget(m_view->viewport());
|
||||
m_inputBar->focusProxy()->installEventFilter(m_view);
|
||||
window()->installEventFilter(m_view);
|
||||
|
||||
connect(m_inputBar, &InputBar::sendMessage, this, [this](const QString &text, const QByteArray& reply, quint64 request) {
|
||||
if (!gui_bridge_get_inst() || !gui_bridge_is_uasync_ready()) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* Реальные Qt-события на viewport: drop только готовит вложение, отправку инициирует пользователь. */
|
||||
#include "../src/inputbar.h"
|
||||
#include "../src/chatview.h"
|
||||
#include "../../../lib/debug_config.h"
|
||||
extern "C" {
|
||||
#include "media_async/attachment_send.h"
|
||||
@@ -23,6 +24,10 @@ extern "C" {
|
||||
#include <QAbstractButton>
|
||||
#include <QPushButton>
|
||||
#include <QCheckBox>
|
||||
#include <QMainWindow>
|
||||
#include <QVBoxLayout>
|
||||
#include <QStringListModel>
|
||||
#include <QScrollBar>
|
||||
|
||||
static QString makeFile(const QTemporaryDir& dir, const QString& name, const QByteArray& contents = "test") {
|
||||
const QString path = dir.filePath(name);
|
||||
@@ -48,6 +53,48 @@ static bool dropUrls(QWidget* target, const QList<QUrl>& urls, bool process = tr
|
||||
class FileDropTest : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void historyKeyboardNavigation_data() {
|
||||
QTest::addColumn<int>("key");
|
||||
QTest::addColumn<int>("focus");
|
||||
for (int key : {Qt::Key_Up, Qt::Key_Down, Qt::Key_PageUp, Qt::Key_PageDown})
|
||||
for (int focus = 0; focus < 3; focus++)
|
||||
QTest::newRow(qPrintable(QStringLiteral("key-%1-focus-%2").arg(key).arg(focus))) << key << focus;
|
||||
}
|
||||
void historyKeyboardNavigation() {
|
||||
QFETCH(int, key); QFETCH(int, focus);
|
||||
QMainWindow window;
|
||||
auto* body = new QWidget(&window); auto* layout = new QVBoxLayout(body);
|
||||
auto* view = new ChatView(body); auto* input = new InputBar(nullptr, nullptr, body);
|
||||
layout->addWidget(view, 1); layout->addWidget(input); window.setCentralWidget(body);
|
||||
QStringList rows; for (int i = 0; i < 100; i++) rows.append(QString::number(i));
|
||||
QStringListModel model(rows); view->setModel(&model);
|
||||
view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
auto* editor = input->findChild<QTextEdit*>(); QVERIFY(editor); QCOMPARE(input->focusProxy(), editor);
|
||||
editor->installEventFilter(view); window.installEventFilter(view);
|
||||
const QString draft = QStringLiteral("first line\nsecond line\nthird line"); editor->setPlainText(draft);
|
||||
auto cursor = editor->textCursor(); cursor.setPosition(5); editor->setTextCursor(cursor);
|
||||
window.resize(600, 400); window.show(); window.activateWindow();
|
||||
QWidget* target = focus == 0 ? static_cast<QWidget*>(editor) : focus == 1 ? static_cast<QWidget*>(&window) : view;
|
||||
if (focus == 0) input->setFocus(); else target->setFocus();
|
||||
QTRY_COMPARE(QApplication::focusWidget(), target);
|
||||
auto* bar = view->verticalScrollBar(); QTRY_VERIFY(bar->maximum() > bar->pageStep() * 2);
|
||||
bar->setValue(bar->maximum() / 2);
|
||||
const int before = bar->value();
|
||||
const bool up = key == Qt::Key_Up || key == Qt::Key_PageUp;
|
||||
const int step = key == Qt::Key_Up || key == Qt::Key_Down ? bar->singleStep() : bar->pageStep();
|
||||
QTest::keyClick(target, static_cast<Qt::Key>(key));
|
||||
QCOMPARE(bar->value(), before + (up ? -step : step));
|
||||
QCOMPARE(QApplication::focusWidget(), target); QCOMPARE(editor->textCursor().position(), 5); QCOMPARE(editor->toPlainText(), draft);
|
||||
bar->setValue(up ? bar->minimum() : bar->maximum());
|
||||
const int boundary = bar->value(); QTest::keyClick(target, static_cast<Qt::Key>(key));
|
||||
QCOMPARE(bar->value(), boundary); QCOMPARE(editor->textCursor().position(), 5);
|
||||
if (focus == 0) {
|
||||
bar->setValue(before);
|
||||
QTest::keyClick(editor, Qt::Key_Down, Qt::ShiftModifier);
|
||||
QVERIFY(editor->textCursor().hasSelection()); QCOMPARE(bar->value(), before);
|
||||
QCOMPARE(editor->toPlainText(), draft); QCOMPARE(QApplication::focusWidget(), editor);
|
||||
}
|
||||
}
|
||||
void encryptedAttachmentCapturesTargetAndResetsChoice_data() {
|
||||
QTest::addColumn<bool>("picker");
|
||||
QTest::newRow("drop") << false; QTest::newRow("file-picker") << true;
|
||||
|
||||
@@ -1728,11 +1728,6 @@ with per-link BBR statistics</translation>
|
||||
<source>Public</source>
|
||||
<translation>Public</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/channelsettingsdialog.cpp" line="+4"/>
|
||||
<source>Push-To-Talk (PTT) mode</source>
|
||||
<translation>Push-To-Talk (PTT) mode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/nodespage.cpp" line="-14"/>
|
||||
<source>Query error</source>
|
||||
@@ -1805,11 +1800,6 @@ with per-link BBR statistics</translation>
|
||||
<source>Recipient: %1</source>
|
||||
<translation>Recipient: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/channelsettingsdialog.cpp" line="+1"/>
|
||||
<source>Record voice messages with push-to-talk. (Coming soon)</source>
|
||||
<translation>Record voice messages with push-to-talk. (Coming soon)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/audiodevicesettingspage.cpp" line="-81"/>
|
||||
<source>Recording device:</source>
|
||||
|
||||
@@ -1731,11 +1731,6 @@ with per-link BBR statistics</source>
|
||||
<source>Public</source>
|
||||
<translation>Публичный</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/channelsettingsdialog.cpp" line="+4"/>
|
||||
<source>Push-To-Talk (PTT) mode</source>
|
||||
<translation>Режим «нажми и говори» (PTT)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/nodespage.cpp" line="-14"/>
|
||||
<source>Query error</source>
|
||||
@@ -1808,11 +1803,6 @@ with per-link BBR statistics</source>
|
||||
<source>Recipient: %1</source>
|
||||
<translation>Получатель: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/channelsettingsdialog.cpp" line="+1"/>
|
||||
<source>Record voice messages with push-to-talk. (Coming soon)</source>
|
||||
<translation>Запись голосовых сообщений в режиме «нажми и говори». (Скоро)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/audiodevicesettingspage.cpp" line="-81"/>
|
||||
<source>Recording device:</source>
|
||||
|
||||
Reference in new issue
Block a user