diff --git a/TTW_Bot.pro b/TTW_Bot.pro index ed4cfd8..7add8b8 100644 --- a/TTW_Bot.pro +++ b/TTW_Bot.pro @@ -22,6 +22,7 @@ INCLUDEPATH += $$PWD SOURCES += \ commandprocessor.cpp \ + countermanager.cpp \ emoteprovider.cpp \ fcolorsetting.cpp \ fcreatechat.cpp \ @@ -54,6 +55,7 @@ SOURCES += \ HEADERS += \ badge.h \ commandprocessor.h \ + countermanager.h \ emoteprovider.h \ fcolorsetting.h \ fcreatechat.h \ diff --git a/commandprocessor.cpp b/commandprocessor.cpp index bcc07ec..1518740 100644 --- a/commandprocessor.cpp +++ b/commandprocessor.cpp @@ -108,6 +108,7 @@ QString CommandProcessor::processCommand(const QString &sender, const QString &f response = parseTextFiles(response); response = parseBan(response, sender); response = parseAPI(response, sender); + response = parseCounters(response); if (response.contains("[AI]", Qt::CaseInsensitive)) { response = parseAI(response, parameters); @@ -214,6 +215,24 @@ QString CommandProcessor::parseTextFiles(const QString &response) return result; } +QString CommandProcessor::parseCounters(const QString &response) +{ + QString result = response; + // Используем ленивый квантификатор +? + QRegularExpression regex("\\|\\)([^\\)]+?)\\|\\)"); + QRegularExpressionMatchIterator matches = regex.globalMatch(response); + + while (matches.hasNext()) { + QRegularExpressionMatch match = matches.next(); + QString counterName = match.captured(1); + int count = m_context.counterManager->getCount(counterName); + QString countStr = QString::number(count); + result.replace("|)" + counterName + "|)", countStr); + } + + return result; +} + QString CommandProcessor::parseRandomGroups(const QString &response) { QString result = response; diff --git a/commandprocessor.h b/commandprocessor.h index ab7d28c..79c6886 100644 --- a/commandprocessor.h +++ b/commandprocessor.h @@ -6,6 +6,7 @@ #include #include #include +#include "countermanager.h" #include "mediafilemanager.h" #include "user_manager.h" #include "ttw_api.h" @@ -34,6 +35,7 @@ public: RandomResponses* randomResponses = nullptr; MediaFileManager* mediaFileManager = nullptr; NeuralTemplateManager *neuralTemplateManager = nullptr; + CounterManager* counterManager = nullptr; QString channel; int notifyVolume = 50; }; @@ -67,6 +69,7 @@ private: QString parseAPI(const QString &response, const QString &sender); QString parseAI(const QString &response, const QString &question); QString parseNeuralTemplates(const QString &response, const QString &sender, const QString ¶meters); + QString parseCounters(const QString &response); QString extractParameters(const QString &fullCommand); QString getUsernameByIndex(QString userIndex) const; diff --git a/countermanager.cpp b/countermanager.cpp new file mode 100644 index 0000000..da7a84e --- /dev/null +++ b/countermanager.cpp @@ -0,0 +1,215 @@ +// countermanager.cpp +#include "countermanager.h" +#include +#include + +CounterManager::CounterManager(QObject *parent) + : QObject(parent) + , m_database(nullptr) +{ +} + +CounterManager::~CounterManager() +{ + if (m_database) { + saveToDatabase(); + } +} + +bool CounterManager::initialize(uDataBase *database) +{ + if (!database || !database->isConnected()) { + qWarning() << "CounterManager: База данных не подключена"; + return false; + } + + m_database = database; + return loadFromDatabase(); +} + +bool CounterManager::addCounter(const QString &name, int initialValue) +{ + if (name.isEmpty()) { + qWarning() << "CounterManager: Нельзя добавить счётчик с пустым именем"; + return false; + } + + if (contains(name)) { + qWarning() << "CounterManager: Счётчик с именем" << name << "уже существует"; + return false; + } + + Counter newCounter(name, initialValue); + m_counters.append(newCounter); + + if (!saveToDatabase()) { + m_counters.removeLast(); + return false; + } + + emit counterAdded(name, initialValue); + emit dataChanged(); + return true; +} + +bool CounterManager::removeCounter(const QString &name) +{ + int index = findIndex(name); + if (index == -1) { + qWarning() << "CounterManager: Счётчик" << name << "не найден"; + return false; + } + + Counter removed = m_counters.at(index); + m_counters.removeAt(index); + + if (!saveToDatabase()) { + m_counters.insert(index, removed); + return false; + } + + emit counterRemoved(name); + emit dataChanged(); + return true; +} + +bool CounterManager::updateCounter(const QString &oldName, const QString &newName, int newValue) +{ + int index = findIndex(oldName); + if (index == -1) { + qWarning() << "CounterManager: Счётчик" << oldName << "не найден"; + return false; + } + + if (oldName != newName && contains(newName)) { + qWarning() << "CounterManager: Имя" << newName << "уже занято"; + return false; + } + + Counter oldCounter = m_counters.at(index); + m_counters[index].name = newName; + m_counters[index].count = newValue; + + if (!saveToDatabase()) { + m_counters[index] = oldCounter; + return false; + } + + emit counterUpdated(oldName, newName); + emit dataChanged(); + return true; +} + +bool CounterManager::incrementCounter(const QString &name, int step) +{ + int index = findIndex(name); + if (index == -1) return false; + + m_counters[index].count += step; + if (!saveToDatabase()) { + m_counters[index].count -= step; // откат + return false; + } + + emit counterIncremented(name, m_counters[index].count); + emit dataChanged(); + return true; +} + +bool CounterManager::decrementCounter(const QString &name, int step) +{ + return incrementCounter(name, -step); +} + +int CounterManager::getCount(const QString &name) const +{ + int index = findIndex(name); + return (index != -1) ? m_counters.at(index).count : 0; +} + +void CounterManager::processMessage(const QString &message) +{ + for (const Counter &c : m_counters) { + if (message.contains(c.name, Qt::CaseInsensitive)) { + // Увеличиваем счётчик, но без повторного сохранения после каждого (один общий save) + // Здесь мы меняем значение, но сохраним после цикла, чтобы не делать много запросов + // Для простоты используем incrementCounter, который сам сохраняет, но это будет много раз. + // Лучше собрать имена, которые нужно увеличить, а потом применить. + // Но в данном случае можно просто вызывать incrementCounter, это не критично. + incrementCounter(c.name); + } + } +} + +bool CounterManager::contains(const QString &name) const +{ + return findIndex(name) != -1; +} + +bool CounterManager::saveToDatabase() +{ + if (!m_database) { + qWarning() << "CounterManager: База данных не установлена"; + return false; + } + + QTableWidget tempTable; + QStringList headers = {"Имя", "Значение"}; + tempTable.setColumnCount(2); + tempTable.setHorizontalHeaderLabels(headers); + tempTable.setRowCount(m_counters.size()); + + for (int i = 0; i < m_counters.size(); ++i) { + const Counter &c = m_counters.at(i); + tempTable.setItem(i, 0, new QTableWidgetItem(c.name)); + tempTable.setItem(i, 1, new QTableWidgetItem(QString::number(c.count))); + } + tempTable.setObjectName("sgCounters"); + // Сохраняем через общий метод (предполагаем, что таблица в БД называется "sgCounters") + m_database->SaveTableWidget(&tempTable); + return true; +} + +bool CounterManager::loadFromDatabase() +{ + if (!m_database) { + qWarning() << "CounterManager: База данных не установлена"; + return false; + } + + QTableWidget tempTable; + QStringList headers = {"Имя", "Значение"}; + tempTable.setColumnCount(2); + tempTable.setHorizontalHeaderLabels(headers); + tempTable.setObjectName("sgCounters"); + m_database->LoadTableWidget(&tempTable); + + m_counters.clear(); + for (int row = 0; row < tempTable.rowCount(); ++row) { + QTableWidgetItem *nameItem = tempTable.item(row, 0); + QTableWidgetItem *valueItem = tempTable.item(row, 1); + + if (!nameItem || !valueItem) continue; + + QString name = nameItem->text().trimmed(); + if (name.isEmpty()) continue; + + bool ok; + int value = valueItem->text().toInt(&ok); + if (!ok) continue; + + m_counters.append(Counter(name, value)); + } + + emit dataChanged(); + return true; +} + +int CounterManager::findIndex(const QString &name) const +{ + for (int i = 0; i < m_counters.size(); ++i) { + if (m_counters.at(i).name == name) + return i; + } + return -1; +} diff --git a/countermanager.h b/countermanager.h new file mode 100644 index 0000000..fd5f278 --- /dev/null +++ b/countermanager.h @@ -0,0 +1,64 @@ +// countermanager.h +#ifndef COUNTERMANAGER_H +#define COUNTERMANAGER_H + +#include +#include +#include +#include "udatabase.h" + +class CounterManager : public QObject +{ + Q_OBJECT + +public: + struct Counter { + QString name; + int count; + + Counter() : count(0) {} + Counter(const QString& n, int c = 0) : name(n), count(c) {} + + bool operator==(const QString& otherName) const { return name == otherName; } + }; + + explicit CounterManager(QObject *parent = nullptr); + ~CounterManager(); + + // Инициализация с базой данных + bool initialize(uDataBase *database); + + // Управление счетчиками + bool addCounter(const QString &name, int initialValue = 0); + bool removeCounter(const QString &name); + bool updateCounter(const QString &oldName, const QString &newName, int newValue); + bool incrementCounter(const QString &name, int step = 1); + bool decrementCounter(const QString &name, int step = 1); + int getCount(const QString &name) const; + + // Обработка сообщения: увеличивает счётчики, чьи имена встречаются в тексте + void processMessage(const QString &message); + + // Получение всех счётчиков + QVector getAllCounters() const { return m_counters; } + bool contains(const QString &name) const; + + // Сохранение/загрузка в БД + bool saveToDatabase(); + bool loadFromDatabase(); + +signals: + void dataChanged(); + void counterAdded(const QString &name, int value); + void counterRemoved(const QString &name); + void counterUpdated(const QString &oldName, const QString &newName); + void counterIncremented(const QString &name, int newValue); + +private: + uDataBase *m_database; + QVector m_counters; + + int findIndex(const QString &name) const; +}; + +#endif // COUNTERMANAGER_H diff --git a/emoteprovider.cpp b/emoteprovider.cpp index ab4b2cb..f1f0db1 100644 --- a/emoteprovider.cpp +++ b/emoteprovider.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include // EmoteProvider implementation EmoteProvider::EmoteProvider(QObject *parent) @@ -416,3 +418,52 @@ void SevenTVProvider::parseCustomResponse(const QByteArray &data, const QString QString("Loaded %1 custom emotes for user %2").arg(m_emotes.size()).arg(userId), LOG_INFO); } + +QString BTTVProvider::cleanMessage(const QString& message) const +{ + if (m_emotes.isEmpty()) + return message; + + // Собираем все коды эмоций в множество для быстрого поиска + QSet codes; + for (const BTTVEmote& emote : m_emotes) { + codes.insert(emote.code); + } + + // Разбиваем сообщение на токены (слова и не-слова) + QRegularExpression wordSplitter("(\\w+|[^\\w]+)"); + QRegularExpressionMatchIterator it = wordSplitter.globalMatch(message); + QStringList parts; + while (it.hasNext()) { + QRegularExpressionMatch match = it.next(); + QString token = match.captured(0); + // Если токен состоит только из букв/цифр и является кодом эмоции – пропускаем + if (token[0].isLetterOrNumber() && codes.contains(token)) + continue; + parts.append(token); + } + return parts.join(""); +} + +QString SevenTVProvider::cleanMessage(const QString& message) const +{ + if (m_emotes.isEmpty()) + return message; + + QSet codes; + for (const SevenTVEmote& emote : m_emotes) { + codes.insert(emote.code); + } + + QRegularExpression wordSplitter("(\\w+|[^\\w]+)"); + QRegularExpressionMatchIterator it = wordSplitter.globalMatch(message); + QStringList parts; + while (it.hasNext()) { + QRegularExpressionMatch match = it.next(); + QString token = match.captured(0); + if (token[0].isLetterOrNumber() && codes.contains(token)) + continue; + parts.append(token); + } + return parts.join(""); +} diff --git a/emoteprovider.h b/emoteprovider.h index f38aadc..8ca210d 100644 --- a/emoteprovider.h +++ b/emoteprovider.h @@ -47,6 +47,7 @@ public: virtual void fetchGlobal() = 0; virtual void fetchCustom(const QString &userId) = 0; virtual QString getEmoteUrl(const QString &emoteName) = 0; + virtual QString cleanMessage(const QString& message) const = 0; signals: void emotesLoaded(); @@ -71,6 +72,7 @@ public: void fetchGlobal() override; void fetchCustom(const QString &userId) override; QString getEmoteUrl(const QString &emoteName) override; + QString cleanMessage(const QString& message) const override; private slots: void onGlobalReplyFinished(QNetworkReply *reply); @@ -95,6 +97,7 @@ public: void fetchGlobal() override; void fetchCustom(const QString &userId) override; QString getEmoteUrl(const QString &emoteName) override; + QString cleanMessage(const QString& message) const override; private slots: void onGlobalReplyFinished(QNetworkReply *reply); diff --git a/object_script.TTW_Bot.Debug b/object_script.TTW_Bot.Debug index b36e3b1..4820324 100644 --- a/object_script.TTW_Bot.Debug +++ b/object_script.TTW_Bot.Debug @@ -1,4 +1,5 @@ debug/commandprocessor.o +debug/countermanager.o debug/emoteprovider.o debug/fcolorsetting.o debug/fcreatechat.o @@ -28,6 +29,7 @@ debug/webserverchat.o debug/webservernotify.o debug/websocketclient.o debug/moc_commandprocessor.o +debug/moc_countermanager.o debug/moc_emoteprovider.o debug/moc_fcolorsetting.o debug/moc_fcreatechat.o diff --git a/object_script.TTW_Bot.Release b/object_script.TTW_Bot.Release index 7feb5a6..fc8e454 100644 --- a/object_script.TTW_Bot.Release +++ b/object_script.TTW_Bot.Release @@ -1,4 +1,5 @@ release/commandprocessor.o +release/countermanager.o release/emoteprovider.o release/fcolorsetting.o release/fcreatechat.o @@ -28,6 +29,7 @@ release/webserverchat.o release/webservernotify.o release/websocketclient.o release/moc_commandprocessor.o +release/moc_countermanager.o release/moc_emoteprovider.o release/moc_fcolorsetting.o release/moc_fcreatechat.o diff --git a/ugeneral.cpp b/ugeneral.cpp index 7c16879..4ea0ce4 100644 --- a/ugeneral.cpp +++ b/ugeneral.cpp @@ -407,6 +407,22 @@ void uGeneral::initializeManagers() ui->widget_3->setManagerType(FSingleGrid::TemplateManager); ui->widget_3->setDatabase(db); + m_counterManager = new CounterManager(this); + if (db) { + m_counterManager->initialize(db); + } + + // Настраиваем таблицу счётчиков (предполагаем, что она уже есть в .ui с objectName "sgCounters") + setupCountersTable(); + + // Подключаем сигналы для обновления таблицы при изменениях + connect(m_counterManager, &CounterManager::dataChanged, this, &uGeneral::updateCountersTable); + connect(m_counterManager, &CounterManager::counterAdded, this, [this](const QString&, int) { updateCountersTable(); }); + connect(m_counterManager, &CounterManager::counterRemoved, this, [this](const QString&) { updateCountersTable(); }); + connect(m_counterManager, &CounterManager::counterUpdated, this, [this](const QString&, const QString&) { updateCountersTable(); }); + connect(m_counterManager, &CounterManager::counterIncremented, this, [this](const QString&, int) { updateCountersTable(); }); + + m_commandProcessor = new CommandProcessor(this); if (db) { @@ -428,9 +444,46 @@ void uGeneral::initializeManagers() context.mediaFileManager = m_SoundFiles; context.channel = ui->edtChannel->text(); context.notifyVolume = ui->tbNotifyVolume->value(); - + context.counterManager = m_counterManager; m_commandProcessor->setContext(context); } + + +} + + + +void uGeneral::setupCountersTable(){ + // Предполагаем, что sgCounters уже есть в ui + ui->sgCounters->setColumnCount(2); + QStringList headers; + headers << "Счётчик" << "Значение"; + ui->sgCounters->setHorizontalHeaderLabels(headers); + ui->sgCounters->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->sgCounters->setSelectionMode(QAbstractItemView::SingleSelection); + ui->sgCounters->setEditTriggers(QAbstractItemView::NoEditTriggers); + ui->sgCounters->horizontalHeader()->setStretchLastSection(true); + ui->sgCounters->setColumnWidth(0, 200); + ui->sgCounters->setColumnWidth(1, 80); + + updateCountersTable(); +} + +void uGeneral::updateCountersTable() +{ + + ui->sgCounters->setRowCount(0); + ui->cbCounters->clear(); + if (!m_counterManager) return; + + QVector counters = m_counterManager->getAllCounters(); + for (const auto &c : counters) { + int row = ui->sgCounters->rowCount(); + ui->sgCounters->insertRow(row); + ui->sgCounters->setItem(row, 0, new QTableWidgetItem(c.name)); + ui->sgCounters->setItem(row, 1, new QTableWidgetItem(QString::number(c.count))); + ui->cbCounters->addItem(c.name); + } } void uGeneral::loadCommandsFromTableWidget() @@ -742,6 +795,7 @@ uGeneral::~uGeneral() delete m_neuralTemplateManager; m_neuralTemplateManager = nullptr; } + delete m_counterManager; delete m_createNotifyDialog; delete m_createChatDialog; delete ui; @@ -1740,7 +1794,8 @@ void uGeneral::initializeNotificationSounds() } } -void uGeneral::handleNewMessage(const QString &message){ +void uGeneral::handleNewMessage(const QString &message) +{ TwitchMessage msg = TwitchMessage::parse(message); QString userId = m_userManager->checkUser(msg.displayName, msg); @@ -1754,8 +1809,30 @@ void uGeneral::handleNewMessage(const QString &message){ QString processedMessage = processTwitchMessage(msg); QString formattedNickname = formatNicknameWithBadges(msg); - addChatMessage(formattedNickname, processedMessage); + if (m_counterManager) { + m_counterManager->processMessage(msg.message); // или cleanedText + } + QString cleanedText = cleanMessageFromAllEmotes(msg.message); + // Удаляем ссылки (опционально) + cleanedText.remove(QRegularExpression("https?://\\S+")); + cleanedText = cleanedText.trimmed(); + + // Проверяем наличие русских букв + bool hasRussian = false; + for (const QChar& ch : cleanedText) { + if (ch.unicode() >= 0x0400 && ch.unicode() <= 0x04FF) { + hasRussian = true; + break; + } + } + + if (!hasRussian && !cleanedText.isEmpty()) { + // Здесь нужно вызвать перевод (например, через API) + // sendToTranslate(cleanedText); + LogManager::instance()->debug("uGeneral", "handleNewMessage", + "Требуется перевод: " + cleanedText); + } if (msg.message.startsWith("!!!")) { QString cleanedMessage = msg.message.mid(3); @@ -1766,6 +1843,14 @@ void uGeneral::handleNewMessage(const QString &message){ } } +QString uGeneral::cleanMessageFromAllEmotes(const QString& message) const +{ + QString cleaned = message; + cleaned = bttvProvider.cleanMessage(cleaned); + cleaned = sevenTVProvider.cleanMessage(cleaned); + return cleaned; +} + void uGeneral::processUserCommand(const QString &username, const QString &commandText) { if (!m_commandProcessor || !m_userManager) return; @@ -1972,11 +2057,6 @@ void uGeneral::disconnectFromTwitch() setTwitchConnected(false); } -void uGeneral::execCommand(const QString &sender, const QString &message) -{ - LogManager::instance()->debug("uGeneral", "execCommand", - QString("Обработка команды от %1: %2").arg(sender).arg(message)); -} void uGeneral::on_lbRandomGroup_itemClicked(QListWidgetItem *item) { @@ -3026,3 +3106,87 @@ void uGeneral::on_btnRmWebService_clicked() .arg(serviceName)); } } + +void uGeneral::on_sgCounters_cellClicked(int row, int column) +{ + Q_UNUSED(column); + QString name = ui->sgCounters->item(row, 0)->text(); + int value = ui->sgCounters->item(row, 1)->text().toInt(); + ui->edtWordCounter->setText(name); + ui->sbStartCounter->setValue(value); +} + + +void uGeneral::on_sgCounters_cellDoubleClicked(int row, int column) +{ + +} + + +void uGeneral::on_btnCounterAdd_clicked() +{ + QString name = ui->edtWordCounter->text().trimmed(); // предположим, есть поле ввода + if (name.isEmpty()) { + QMessageBox::warning(this, "Ошибка", "Введите название счётчика!"); + return; + } + + int initial = ui->sbStartCounter->value(); // спинбокс для начального значения + if (m_counterManager->addCounter(name, initial)) { + ui->edtWordCounter->clear(); + ui->sbStartCounter->setValue(0); + updateCountersTable(); + } else { + QMessageBox::warning(this, "Ошибка", "Не удалось добавить счётчик (возможно, уже существует)"); + } +} + + +void uGeneral::on_btnCounterDelete_clicked() +{ + int row = ui->sgCounters->currentRow(); + if (row < 0) { + QMessageBox::warning(this, "Ошибка", "Выберите счётчик для удаления!"); + return; + } + + QString name = ui->sgCounters->item(row, 0)->text(); + if (m_counterManager->removeCounter(name)) { + updateCountersTable(); + } +} + + +void uGeneral::on_btnCounterEdit_clicked() +{ + int row = ui->sgCounters->currentRow(); + if (row < 0) { + QMessageBox::warning(this, "Ошибка", "Выберите счётчик для редактирования!"); + return; + } + + QString oldName = ui->sgCounters->item(row, 0)->text(); + QString newName = ui->edtWordCounter->text().trimmed(); + int newValue = ui->sbStartCounter->value(); + + if (newName.isEmpty()) { + QMessageBox::warning(this, "Ошибка", "Введите новое название счётчика!"); + return; + } + + if (m_counterManager->updateCounter(oldName, newName, newValue)) { + ui->edtWordCounter->clear(); + ui->sbStartCounter->setValue(0); + updateCountersTable(); + } else { + QMessageBox::warning(this, "Ошибка", "Не удалось обновить счётчик"); + } +} + + +void uGeneral::on_btnCounterAtoText_clicked() +{ + QTextCursor cursor = ui->textBrowser->textCursor(); + cursor.insertText("|)" + ui->cbCounters->currentText() + "|)"); +} + diff --git a/ugeneral.h b/ugeneral.h index 6fcca96..7522c0c 100644 --- a/ugeneral.h +++ b/ugeneral.h @@ -10,6 +10,7 @@ #include #include #include "commandprocessor.h" +#include "countermanager.h" #include "fcreatechat.h" #include "fcreatenotify.h" #include "logmanager.h" @@ -141,11 +142,6 @@ private slots: void handleConnected(); void handleDisconnected(); - // ======================================================================== - // СЛОТЫ ДЛЯ РАБОТЫ С КОМАНДАМИ И ОТВЕТАМИ - // ======================================================================== - void execCommand(const QString &sender, const QString &message); - // ======================================================================== // СЛОТЫ ДЛЯ РАБОТЫ С ИСКУССТВЕННЫМ ИНТЕЛЛЕКТОМ @@ -346,6 +342,18 @@ private slots: void on_btnRmWebService_clicked(); + void on_sgCounters_cellClicked(int row, int column); + + void on_sgCounters_cellDoubleClicked(int row, int column); + + void on_btnCounterAdd_clicked(); + + void on_btnCounterDelete_clicked(); + + void on_btnCounterEdit_clicked(); + + void on_btnCounterAtoText_clicked(); + public slots: // Установка статуса подключения к Twitch void setTwitchConnected(bool connected); @@ -363,6 +371,7 @@ private: uLink *fLinkForm; // Форма ссылок TTTVAuth *TTVAuth; // Данные авторизации Twitch UserManager *m_userManager; // Менеджер пользователей + CounterManager *m_counterManager; CommandProcessor* m_commandProcessor; // Процессор команд WebSocketClient *m_twitchClient; // WebSocket клиент для Twitch UserWidget* m_userWidget; // Виджет пользователя @@ -405,8 +414,8 @@ private: int findNotificationServerRow(HttpServer *server); int findChatServerRow(HttpServerChat *server); QString generateServerId() const; - - + void setupCountersTable(); + void updateCountersTable(); // Текущие настройки для формы QVariantMap m_currentSettings; @@ -481,6 +490,8 @@ private: void loadNeuralTemplatesFromTableWidget(); void processUserCommand(const QString &username, const QString &commandText); void sendChatResponse(const QString &response); + + QString cleanMessageFromAllEmotes(const QString& message) const; }; #endif // UGENERAL_H diff --git a/ugeneral.ui b/ugeneral.ui index 82fcf5a..a2b8716 100644 --- a/ugeneral.ui +++ b/ugeneral.ui @@ -42,7 +42,7 @@ Qt::LeftToRight - 6 + 2 false @@ -974,6 +974,9 @@ + + + @@ -1417,141 +1420,267 @@ - - - Таймеры сообщений + + + 0 - - - - - 0 - - - 4 - - - - Вкл - - - - - Сообщение - - - - - Интервал (мин) - - - - - О - - - - - - + + + + Таймеры сообщений + + - - - Сообщение: + + + 0 + + 4 + + + + Вкл + + + + + Сообщение + + + + + Интервал (мин) + + + + + О + + - + + + + + Сообщение: + + + + + + + + + + Интервал: + + + + + + + 10 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - Интервал: - - - - - - - 10 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + + Добавить + + + + ../../../Downloads/ico/add.png../../../Downloads/ico/add.png + + + + + + + Изменить + + + + ../../../Downloads/ico/edit.png../../../Downloads/ico/edit.png + + + + + + + Удалить + + + + ../../../Downloads/ico/minus-sign_3485999.png../../../Downloads/ico/minus-sign_3485999.png + + + + + + + Тест + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + 2 + + + Счетчики + + - - - Добавить - - - - ../../../Downloads/ico/add.png../../../Downloads/ico/add.png - + + + + Слово или фраза + + + + + Количество + + - - - Изменить + + + 0 - - - ../../../Downloads/ico/edit.png../../../Downloads/ico/edit.png - - + + + + Слово: + + + + + + + + + + Количество: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - Удалить + + + 0 - - - ../../../Downloads/ico/minus-sign_3485999.png../../../Downloads/ico/minus-sign_3485999.png - - - - - - - Тест - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + Добавить + + + + + + + Изменить + + + + + + + Удалить + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - + + +