+ награды за баллы
- создание - изменение - удаление - отображение
This commit is contained in:
@@ -53,6 +53,7 @@ SOURCES += \
|
||||
websocketclient.cpp
|
||||
|
||||
HEADERS += \
|
||||
action.h \
|
||||
badge.h \
|
||||
commandprocessor.h \
|
||||
countermanager.h \
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// action.h
|
||||
#ifndef ACTION_H
|
||||
#define ACTION_H
|
||||
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
|
||||
class Action {
|
||||
public:
|
||||
enum Type { KeyPress, Sound, Notification, File };
|
||||
virtual ~Action() = default;
|
||||
virtual Type type() const = 0;
|
||||
virtual void execute() = 0;
|
||||
virtual QVariantMap toJson() const = 0;
|
||||
virtual void fromJson(const QVariantMap &data) = 0;
|
||||
};
|
||||
|
||||
// Конкретные действия
|
||||
class KeyPressAction : public Action {
|
||||
public:
|
||||
Type type() const override { return KeyPress; }
|
||||
void execute() override;
|
||||
QVariantMap toJson() const override;
|
||||
void fromJson(const QVariantMap &data) override;
|
||||
private:
|
||||
int keyCode;
|
||||
Qt::KeyboardModifiers modifiers;
|
||||
};
|
||||
|
||||
class SoundAction : public Action {
|
||||
// ...
|
||||
};
|
||||
|
||||
// ... и т.д.
|
||||
#endif // ACTION_H
|
||||
+113
@@ -1,5 +1,6 @@
|
||||
#include "ttw_api.h"
|
||||
#include "qeventloop.h"
|
||||
#include "ttw_types.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
@@ -692,3 +693,115 @@ bool TTwAPI::validateTwitchToken(const QString &tokenName,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void TTwAPI::getCustomRewards(QVector<TCustomReward*> &rewards, bool onlyManageable)
|
||||
{
|
||||
QString roomId = getRoomId();
|
||||
if (roomId.isEmpty()) return;
|
||||
|
||||
QString url = "channel_points/custom_rewards?broadcaster_id=" + roomId;
|
||||
if (onlyManageable) {
|
||||
url += "&only_manageable_rewards=true";
|
||||
}
|
||||
|
||||
QString response = getTTW(url, m_clientId, true);
|
||||
if (response.isEmpty()) return;
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
|
||||
if (!doc.isObject()) return;
|
||||
|
||||
QJsonArray data = doc.object()["data"].toArray();
|
||||
for (const QJsonValue &val : data) {
|
||||
QJsonObject obj = val.toObject();
|
||||
TCustomReward *reward = new TCustomReward;
|
||||
reward->id = obj["id"].toString();
|
||||
reward->title = obj["title"].toString();
|
||||
reward->cost = obj["cost"].toInt();
|
||||
reward->prompt = obj["prompt"].toString();
|
||||
reward->isUserInputRequired = obj["is_user_input_required"].toBool();
|
||||
reward->isEnabled = obj["is_enabled"].toBool();
|
||||
// Для manageable запроса все награды по определению управляемы
|
||||
reward->isManagedByBroadcaster = onlyManageable;
|
||||
rewards.append(reward);
|
||||
}
|
||||
}
|
||||
|
||||
TCustomReward* TTwAPI::createCustomReward(const QString &title, const QString &cost,
|
||||
const QString &prompt, bool isUserInput)
|
||||
{
|
||||
QString roomId = getRoomId();
|
||||
if (roomId.isEmpty()) return nullptr;
|
||||
|
||||
QJsonObject body;
|
||||
body["title"] = title;
|
||||
body["cost"] = cost.toInt();
|
||||
if (!prompt.isEmpty()) body["prompt"] = prompt;
|
||||
body["is_user_input_required"] = isUserInput;
|
||||
// Можно добавить и другие параметры: is_enabled, color и т.д.
|
||||
|
||||
QJsonDocument doc(body);
|
||||
QString response = postTTW("channel_points/custom_rewards?broadcaster_id=" + roomId,
|
||||
m_clientId, doc.toJson(), true);
|
||||
if (response.isEmpty()) return nullptr;
|
||||
|
||||
QJsonDocument respDoc = QJsonDocument::fromJson(response.toUtf8());
|
||||
if (!respDoc.isObject()) return nullptr;
|
||||
|
||||
QJsonArray data = respDoc.object()["data"].toArray();
|
||||
if (data.isEmpty()) return nullptr;
|
||||
|
||||
QJsonObject obj = data[0].toObject();
|
||||
TCustomReward *reward = new TCustomReward;
|
||||
reward->id = obj["id"].toString();
|
||||
reward->title = obj["title"].toString();
|
||||
reward->cost = obj["cost"].toInt();
|
||||
reward->prompt = obj["prompt"].toString();
|
||||
reward->isUserInputRequired = obj["is_user_input_required"].toBool();
|
||||
reward->isEnabled = obj["is_enabled"].toBool();
|
||||
|
||||
return reward;
|
||||
}
|
||||
|
||||
void TTwAPI::updateCustomReward(TCustomReward* reward)
|
||||
{
|
||||
if (!reward) return;
|
||||
QString roomId = getRoomId();
|
||||
if (roomId.isEmpty()) return;
|
||||
|
||||
QJsonObject body;
|
||||
if (!reward->title.isEmpty()) body["title"] = reward->title;
|
||||
body["cost"] = reward->cost;
|
||||
if (!reward->prompt.isEmpty()) body["prompt"] = reward->prompt;
|
||||
body["is_user_input_required"] = reward->isUserInputRequired;
|
||||
body["is_enabled"] = reward->isEnabled;
|
||||
|
||||
QJsonDocument doc(body);
|
||||
patchTTW(QString("channel_points/custom_rewards?broadcaster_id=%1&id=%2")
|
||||
.arg(roomId, reward->id),
|
||||
m_clientId, doc.toJson(), true);
|
||||
}
|
||||
|
||||
bool TTwAPI::deleteCustomReward(const QString &id)
|
||||
{
|
||||
QString roomId = getRoomId();
|
||||
if (roomId.isEmpty()) return false;
|
||||
|
||||
deleteTTW("channel_points/custom_rewards?broadcaster_id=" + roomId + "&id=" + id,
|
||||
m_clientId, true);
|
||||
return true; // или проверка HTTP-статуса, но deleteTTW возвращает пустую строку при ошибке
|
||||
}
|
||||
|
||||
void TTwAPI::updateRedemptionStatus(TCustomRewardEvent* event)
|
||||
{
|
||||
// event содержит id награды, id redemption и новый статус (COMPLETED/CANCELED)
|
||||
QString roomId = getRoomId();
|
||||
if (roomId.isEmpty()) return;
|
||||
|
||||
QJsonObject body;
|
||||
body["status"] = event->status; // "COMPLETED" или "CANCELED"
|
||||
|
||||
QJsonDocument doc(body);
|
||||
patchTTW(QString("channel_points/custom_rewards/redemptions?broadcaster_id=%1&reward_id=%2&id=%3")
|
||||
.arg(roomId, event->rewardId, event->redemptionId),
|
||||
m_clientId, doc.toJson(), true);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
class TCustomReward;
|
||||
class TCustomRewardEvent;
|
||||
class ChatBadge;
|
||||
struct ChatBadge;
|
||||
class Emote;
|
||||
|
||||
class TTwAPI : public QObject
|
||||
@@ -53,14 +53,14 @@ public:
|
||||
void delVIP(const QString &id);
|
||||
|
||||
// Custom Rewards
|
||||
void getCustomRewards(QVector<TCustomReward*> &rewards);
|
||||
void getCustomRewards(QVector<TCustomReward*> &rewards, bool onlyManageable = false);
|
||||
TCustomReward* createCustomReward(const QString &title,
|
||||
const QString &cost,
|
||||
const QString &prompt = "",
|
||||
bool isUserInput = false);
|
||||
void updateCustomReward(TCustomReward* reward);
|
||||
void updateRedemptionStatus(TCustomRewardEvent* event);
|
||||
void deleteCustomReward(const QString &id);
|
||||
bool deleteCustomReward(const QString &id);
|
||||
|
||||
// Пользователи
|
||||
User getUserByLogin(const QString &login);
|
||||
|
||||
+2
-11
@@ -22,7 +22,7 @@ struct TCustomReward {
|
||||
bool isPaused;
|
||||
bool isInStock;
|
||||
bool shouldRedemptionsSkipRequestQueue;
|
||||
|
||||
bool isManagedByBroadcaster;
|
||||
TCustomReward()
|
||||
: cost(0)
|
||||
, isEnabled(true)
|
||||
@@ -48,21 +48,12 @@ struct TCustomRewardEvent {
|
||||
QString userInput;
|
||||
QString status;
|
||||
QDateTime redeemedAt;
|
||||
QString redemptionId;
|
||||
|
||||
TCustomRewardEvent() {}
|
||||
};
|
||||
|
||||
struct ChatBadge {
|
||||
QString setId;
|
||||
QString versionId;
|
||||
QString title;
|
||||
QString description;
|
||||
QString smallImageUrl;
|
||||
QString mediumImageUrl;
|
||||
QString largeImageUrl;
|
||||
|
||||
ChatBadge() {}
|
||||
};
|
||||
|
||||
struct Emote {
|
||||
QString id;
|
||||
|
||||
+287
-1
@@ -2,6 +2,7 @@
|
||||
#include "fcreatenotify.h"
|
||||
#include "filemanager.h"
|
||||
#include "logmanager.h"
|
||||
#include "ttw_types.h"
|
||||
#include "ui_ugeneral.h"
|
||||
#include <QStandardPaths>
|
||||
#include <QDesktopServices>
|
||||
@@ -187,7 +188,7 @@ void uGeneral::setupButtonIcons() {
|
||||
button->setIcon(tabIcons[11]);
|
||||
}
|
||||
}
|
||||
else if (buttonName.contains("edt")) {
|
||||
else if (buttonName.contains("edt") || (buttonName.contains("edit"))) {
|
||||
button->setIcon(tabIcons[10]);
|
||||
}
|
||||
else if (buttonName.contains("open")) {
|
||||
@@ -1805,6 +1806,12 @@ void uGeneral::handleNewMessage(const QString &message)
|
||||
if (m_userWidget) {
|
||||
m_userWidget->updateStatistics();
|
||||
}
|
||||
|
||||
if (ui->cbTextToSpeach->isChecked())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
playNotify(msg.isMod, msg.isVIP, msg.isSubscriber);
|
||||
|
||||
QString processedMessage = processTwitchMessage(msg);
|
||||
@@ -3190,3 +3197,282 @@ void uGeneral::on_btnCounterAtoText_clicked()
|
||||
cursor.insertText("|)" + ui->cbCounters->currentText() + "|)");
|
||||
}
|
||||
|
||||
|
||||
void uGeneral::on_btnCRGet_clicked()
|
||||
{
|
||||
// Очистка старых данных
|
||||
qDeleteAll(m_rewards);
|
||||
m_rewards.clear();
|
||||
|
||||
// 1. Получаем ВСЕ награды канала
|
||||
QVector<TCustomReward*> allRewards;
|
||||
twitchAPI->getCustomRewards(allRewards, false);
|
||||
|
||||
// 2. Получаем только управляемые ботом
|
||||
QVector<TCustomReward*> manageableRewards;
|
||||
twitchAPI->getCustomRewards(manageableRewards, true);
|
||||
|
||||
// 3. Формируем множество ID управляемых наград
|
||||
QSet<QString> manageableIds;
|
||||
for (auto *r : manageableRewards) {
|
||||
manageableIds.insert(r->id);
|
||||
}
|
||||
|
||||
// 4. Освобождаем manageableRewards (они больше не нужны)
|
||||
qDeleteAll(manageableRewards);
|
||||
manageableRewards.clear();
|
||||
|
||||
// 5. Проставляем флаг для всех наград
|
||||
for (auto *r : allRewards) {
|
||||
r->isManagedByBroadcaster = manageableIds.contains(r->id);
|
||||
}
|
||||
|
||||
// 6. Сохраняем в член класса
|
||||
m_rewards = allRewards;
|
||||
|
||||
// 7. Заполняем таблицу
|
||||
ui->sgCustomRewards->setRowCount(0);
|
||||
ui->sgCustomRewards->setColumnCount(3);
|
||||
QStringList headers = {"Название", "Цена", "Описание"};
|
||||
ui->sgCustomRewards->setHorizontalHeaderLabels(headers);
|
||||
ui->sgCustomRewards->setRowCount(m_rewards.size());
|
||||
|
||||
for (int row = 0; row < m_rewards.size(); ++row) {
|
||||
TCustomReward *reward = m_rewards[row];
|
||||
|
||||
QTableWidgetItem *nameItem = new QTableWidgetItem(reward->title);
|
||||
nameItem->setData(Qt::UserRole, reward->id);
|
||||
ui->sgCustomRewards->setItem(row, 0, nameItem);
|
||||
|
||||
QTableWidgetItem *costItem = new QTableWidgetItem(QString::number(reward->cost));
|
||||
ui->sgCustomRewards->setItem(row, 1, costItem);
|
||||
|
||||
QTableWidgetItem *descItem = new QTableWidgetItem(reward->prompt);
|
||||
ui->sgCustomRewards->setItem(row, 2, descItem);
|
||||
|
||||
// Устанавливаем цвет фона
|
||||
QColor bgColor = reward->isManagedByBroadcaster ? QColor(144,238,144) : QColor(255,200,200);
|
||||
nameItem->setForeground(bgColor);
|
||||
costItem->setForeground(bgColor);
|
||||
descItem->setForeground(bgColor);
|
||||
}
|
||||
|
||||
// Сбрасываем поля и кнопки
|
||||
ui->edtCRName->clear();
|
||||
ui->edtCRPrompt->clear();
|
||||
ui->sbCRCost->setValue(0);
|
||||
ui->btnCREdit->setEnabled(false);
|
||||
ui->btnCRDelete->setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
void uGeneral::on_sgCustomRewards_cellClicked(int row, int column)
|
||||
{
|
||||
// Получаем ID награды из первого столбца
|
||||
QTableWidgetItem *idItem = ui->sgCustomRewards->item(row, 0);
|
||||
if (!idItem) return;
|
||||
QString rewardId = idItem->data(Qt::UserRole).toString();
|
||||
|
||||
// Ищем объект награды в m_rewards по ID
|
||||
TCustomReward *reward = nullptr;
|
||||
for (auto *r : m_rewards) {
|
||||
if (r->id == rewardId) {
|
||||
reward = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!reward) return; // защита от ошибок
|
||||
|
||||
// Заполняем поля ввода
|
||||
ui->edtCRName->setText(reward->title);
|
||||
ui->edtCRPrompt->setText(reward->prompt);
|
||||
ui->sbCRCost->setValue(reward->cost);
|
||||
|
||||
// Активируем кнопки только если награда управляется ботом
|
||||
bool canEdit = reward->isManagedByBroadcaster;
|
||||
ui->btnCREdit->setEnabled(canEdit);
|
||||
ui->btnCRDelete->setEnabled(canEdit);
|
||||
}
|
||||
|
||||
|
||||
void uGeneral::on_sgCustomRewards_cellDoubleClicked(int row, int column)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uGeneral::on_btnCRAdd_clicked()
|
||||
{
|
||||
// 1. Получаем данные из интерфейса
|
||||
QString title = ui->edtCRName->text().trimmed();
|
||||
QString prompt = ui->edtCRPrompt->text().trimmed();
|
||||
int cost = ui->sbCRCost->value();
|
||||
|
||||
// 2. Простейшая валидация
|
||||
if (title.isEmpty()) {
|
||||
QMessageBox::warning(this, "Ошибка", "Название награды не может быть пустым.");
|
||||
return;
|
||||
}
|
||||
if (cost <= 0) {
|
||||
QMessageBox::warning(this, "Ошибка", "Стоимость должна быть больше 0.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Вызываем API для создания награды
|
||||
// Предполагаем, что чекбокс "Требуется ввод пользователя" отсутствует, ставим false
|
||||
TCustomReward *newReward = twitchAPI->createCustomReward(title, QString::number(cost), prompt, false);
|
||||
|
||||
if (!newReward) {
|
||||
QMessageBox::critical(this, "Ошибка", "Не удалось создать награду. Проверьте подключение к Twitch и права токена.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. Уведомляем пользователя об успехе
|
||||
QMessageBox::information(this, "Успех", "Награда успешно создана.");
|
||||
|
||||
// 5. Очищаем поля ввода (опционально)
|
||||
ui->edtCRName->clear();
|
||||
ui->edtCRPrompt->clear();
|
||||
ui->sbCRCost->setValue(0);
|
||||
|
||||
// 6. Обновляем список наград, чтобы новая появилась в таблице
|
||||
on_btnCRGet_clicked(); // перезагружает и обновляет таблицу
|
||||
|
||||
// Важно: newReward был создан в куче, но после вызова on_btnCRGet_clicked()
|
||||
// старые указатели будут удалены, а новые получены. Указатель newReward
|
||||
// становится недействительным, поэтому не используем его дальше.
|
||||
}
|
||||
|
||||
|
||||
void uGeneral::on_btnCREdit_clicked()
|
||||
{
|
||||
// 1. Проверяем, что выбрана строка в таблице
|
||||
int currentRow = ui->sgCustomRewards->currentRow();
|
||||
if (currentRow < 0) {
|
||||
QMessageBox::warning(this, "Ошибка", "Выберите награду для редактирования.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Извлекаем ID награды из первого столбца (хранится в Qt::UserRole)
|
||||
QTableWidgetItem *idItem = ui->sgCustomRewards->item(currentRow, 0);
|
||||
if (!idItem) return;
|
||||
QString rewardId = idItem->data(Qt::UserRole).toString();
|
||||
|
||||
// 3. Ищем объект награды в векторе m_rewards
|
||||
TCustomReward *reward = nullptr;
|
||||
for (auto *r : m_rewards) {
|
||||
if (r->id == rewardId) {
|
||||
reward = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!reward) {
|
||||
QMessageBox::critical(this, "Ошибка", "Не удалось найти данные награды.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. Проверяем, что награда управляется ботом (кнопка должна быть активна только для таких)
|
||||
if (!reward->isManagedByBroadcaster) {
|
||||
QMessageBox::warning(this, "Ошибка", "Нельзя редактировать награду, созданную не ботом.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Получаем новые значения из полей ввода
|
||||
QString newTitle = ui->edtCRName->text().trimmed();
|
||||
QString newPrompt = ui->edtCRPrompt->text().trimmed();
|
||||
int newCost = ui->sbCRCost->value();
|
||||
|
||||
// 6. Валидация
|
||||
if (newTitle.isEmpty()) {
|
||||
QMessageBox::warning(this, "Ошибка", "Название не может быть пустым.");
|
||||
return;
|
||||
}
|
||||
if (newCost <= 0) {
|
||||
QMessageBox::warning(this, "Ошибка", "Стоимость должна быть больше 0.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 7. Обновляем данные в объекте
|
||||
reward->title = newTitle;
|
||||
reward->prompt = newPrompt;
|
||||
reward->cost = newCost;
|
||||
|
||||
// 8. Вызываем API для обновления награды
|
||||
twitchAPI->updateCustomReward(reward); // предполагается, что метод возвращает void
|
||||
|
||||
// 9. Обновляем список наград (гарантирует синхронизацию с Twitch)
|
||||
on_btnCRGet_clicked();
|
||||
|
||||
// 10. Уведомляем пользователя об успехе
|
||||
QMessageBox::information(this, "Успех", "Награда обновлена.");
|
||||
}
|
||||
|
||||
|
||||
void uGeneral::on_btnCRDelete_clicked()
|
||||
{
|
||||
// 1. Проверяем, что выбрана строка в таблице
|
||||
int currentRow = ui->sgCustomRewards->currentRow();
|
||||
if (currentRow < 0) {
|
||||
QMessageBox::warning(this, "Ошибка", "Выберите награду для удаления.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Извлекаем ID награды из первого столбца
|
||||
QTableWidgetItem *idItem = ui->sgCustomRewards->item(currentRow, 0);
|
||||
if (!idItem) return;
|
||||
QString rewardId = idItem->data(Qt::UserRole).toString();
|
||||
|
||||
// 3. Находим объект награды в m_rewards (для проверки управляемости)
|
||||
TCustomReward *reward = nullptr;
|
||||
for (auto *r : m_rewards) {
|
||||
if (r->id == rewardId) {
|
||||
reward = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!reward) {
|
||||
QMessageBox::critical(this, "Ошибка", "Не удалось найти данные награды.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. Проверяем, что награда управляется ботом
|
||||
if (!reward->isManagedByBroadcaster) {
|
||||
QMessageBox::warning(this, "Ошибка", "Нельзя удалить награду, созданную не ботом.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Запрашиваем подтверждение
|
||||
QString title = reward->title;
|
||||
QMessageBox::StandardButton reply = QMessageBox::question(
|
||||
this,
|
||||
"Подтверждение удаления",
|
||||
QString("Вы уверены, что хотите удалить награду \"%1\"?").arg(title),
|
||||
QMessageBox::Yes | QMessageBox::No
|
||||
);
|
||||
|
||||
if (reply != QMessageBox::Yes) {
|
||||
return; // пользователь отменил
|
||||
}
|
||||
|
||||
// 6. Вызываем API для удаления
|
||||
bool success = twitchAPI->deleteCustomReward(rewardId); // предполагаем, что метод возвращает bool
|
||||
|
||||
if (!success) {
|
||||
QMessageBox::critical(this, "Ошибка", "Не удалось удалить награду. Проверьте подключение к Twitch и права токена.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 7. Уведомляем об успехе
|
||||
QMessageBox::information(this, "Успех", "Награда успешно удалена.");
|
||||
|
||||
// 8. Обновляем список наград (удалённая исчезнет)
|
||||
on_btnCRGet_clicked();
|
||||
|
||||
// 9. Сбрасываем поля ввода и отключаем кнопки (так как выбор пропал)
|
||||
ui->edtCRName->clear();
|
||||
ui->edtCRPrompt->clear();
|
||||
ui->sbCRCost->setValue(0);
|
||||
ui->btnCREdit->setEnabled(false);
|
||||
ui->btnCRDelete->setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
+13
-1
@@ -354,6 +354,18 @@ private slots:
|
||||
|
||||
void on_btnCounterAtoText_clicked();
|
||||
|
||||
void on_btnCRGet_clicked();
|
||||
|
||||
void on_sgCustomRewards_cellClicked(int row, int column);
|
||||
|
||||
void on_sgCustomRewards_cellDoubleClicked(int row, int column);
|
||||
|
||||
void on_btnCRAdd_clicked();
|
||||
|
||||
void on_btnCREdit_clicked();
|
||||
|
||||
void on_btnCRDelete_clicked();
|
||||
|
||||
public slots:
|
||||
// Установка статуса подключения к Twitch
|
||||
void setTwitchConnected(bool connected);
|
||||
@@ -383,7 +395,7 @@ private:
|
||||
QList<TimerInfo> m_timers; // Список таймеров
|
||||
int m_nextTimerId = 1; // Следующий ID таймера
|
||||
bool m_isTwitchConnected = false; // Статус подключения к Twitch
|
||||
|
||||
QVector<TCustomReward*> m_rewards;
|
||||
// Менеджеры веб-серверов
|
||||
QList<HttpServer*> m_notificationServers;
|
||||
QList<HttpServerChat*> m_chatServers;
|
||||
|
||||
+154
-3
@@ -42,7 +42,7 @@
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="tabsClosable">
|
||||
<bool>false</bool>
|
||||
@@ -878,7 +878,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbTextToSpeach">
|
||||
<property name="text">
|
||||
<string>Озвучить после !!!</string>
|
||||
<string>Игнорировать все сообщения</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -1087,7 +1087,158 @@
|
||||
<attribute name="title">
|
||||
<string>Навыки</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_tab_skills"/>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_tab_skills">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_17">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_12">
|
||||
<property name="title">
|
||||
<string>Баллы канала</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_28">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="sgCustomRewards"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_26">
|
||||
<property name="text">
|
||||
<string>Название:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edtCRName"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_27">
|
||||
<property name="text">
|
||||
<string>Описание:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="edtCRPrompt"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_28">
|
||||
<property name="text">
|
||||
<string>Цена:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="sbCRCost">
|
||||
<property name="maximum">
|
||||
<number>9999999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_11">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_19">
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCRAdd">
|
||||
<property name="text">
|
||||
<string>Добавить</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCREdit">
|
||||
<property name="text">
|
||||
<string>Изменить</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCRDelete">
|
||||
<property name="text">
|
||||
<string>Удалить</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCRGet">
|
||||
<property name="text">
|
||||
<string>Обновить</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_13">
|
||||
<property name="title">
|
||||
<string>Действия</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_30">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_29">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget_2"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_5">
|
||||
<property name="icon" stdset="0">
|
||||
|
||||
Reference in New Issue
Block a user