diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 12affbd858..9eab29b3eb 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -99,6 +99,8 @@ add_executable(citra-qt
multiplayer/lobby.cpp
multiplayer/message.h
multiplayer/message.cpp
+ multiplayer/moderation_dialog.cpp
+ multiplayer/moderation_dialog.h
multiplayer/state.cpp
multiplayer/state.h
multiplayer/validation.h
@@ -135,6 +137,7 @@ set(UIS
multiplayer/chat_room.ui
multiplayer/client_room.ui
multiplayer/host_room.ui
+ multiplayer/moderation_dialog.ui
aboutdialog.ui
cheats.ui
hotkeys.ui
diff --git a/src/citra_qt/multiplayer/client_room.cpp b/src/citra_qt/multiplayer/client_room.cpp
index 16f9a58d7d..54b4dc55e1 100644
--- a/src/citra_qt/multiplayer/client_room.cpp
+++ b/src/citra_qt/multiplayer/client_room.cpp
@@ -13,6 +13,7 @@
#include "citra_qt/game_list_p.h"
#include "citra_qt/multiplayer/client_room.h"
#include "citra_qt/multiplayer/message.h"
+#include "citra_qt/multiplayer/moderation_dialog.h"
#include "citra_qt/multiplayer/state.h"
#include "common/logging/log.h"
#include "core/announce_multiplayer_session.h"
@@ -42,11 +43,23 @@ ClientRoomWindow::ClientRoomWindow(QWidget* parent)
connect(ui->disconnect, &QPushButton::pressed, [this] { Disconnect(); });
ui->disconnect->setDefault(false);
ui->disconnect->setAutoDefault(false);
+ connect(ui->moderation, &QPushButton::clicked, [this] {
+ ModerationDialog dialog(this);
+ dialog.exec();
+ });
+ ui->moderation->setDefault(false);
+ ui->moderation->setAutoDefault(false);
UpdateView();
}
ClientRoomWindow::~ClientRoomWindow() = default;
+void ClientRoomWindow::SetModPerms(bool is_mod) {
+ ui->moderation->setVisible(is_mod);
+ ui->moderation->setDefault(false);
+ ui->moderation->setAutoDefault(false);
+}
+
void ClientRoomWindow::RetranslateUi() {
ui->retranslateUi(this);
ui->chat->RetranslateUi();
diff --git a/src/citra_qt/multiplayer/client_room.h b/src/citra_qt/multiplayer/client_room.h
index 47add6f518..7d4f2b238d 100644
--- a/src/citra_qt/multiplayer/client_room.h
+++ b/src/citra_qt/multiplayer/client_room.h
@@ -18,6 +18,7 @@ public:
~ClientRoomWindow();
void RetranslateUi();
+ void SetModPerms(bool is_mod);
public slots:
void OnRoomUpdate(const Network::RoomInformation&);
diff --git a/src/citra_qt/multiplayer/client_room.ui b/src/citra_qt/multiplayer/client_room.ui
index 22b969d3b4..97e88b502d 100644
--- a/src/citra_qt/multiplayer/client_room.ui
+++ b/src/citra_qt/multiplayer/client_room.ui
@@ -41,6 +41,16 @@
+ -
+
+
+ Moderation...
+
+
+ false
+
+
+
-
diff --git a/src/citra_qt/multiplayer/moderation_dialog.cpp b/src/citra_qt/multiplayer/moderation_dialog.cpp
new file mode 100644
index 0000000000..def084666a
--- /dev/null
+++ b/src/citra_qt/multiplayer/moderation_dialog.cpp
@@ -0,0 +1,113 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include
+#include
+#include "citra_qt/multiplayer/moderation_dialog.h"
+#include "network/network.h"
+#include "network/room_member.h"
+#include "ui_moderation_dialog.h"
+
+namespace Column {
+enum {
+ SUBJECT,
+ TYPE,
+ COUNT,
+};
+}
+
+ModerationDialog::ModerationDialog(QWidget* parent)
+ : QDialog(parent), ui(std::make_unique()) {
+ ui->setupUi(this);
+
+ qRegisterMetaType();
+
+ if (auto member = Network::GetRoomMember().lock()) {
+ callback_handle_status_message = member->BindOnStatusMessageReceived(
+ [this](const Network::StatusMessageEntry& status_message) {
+ emit StatusMessageReceived(status_message);
+ });
+ connect(this, &ModerationDialog::StatusMessageReceived, this,
+ &ModerationDialog::OnStatusMessageReceived);
+ callback_handle_ban_list = member->BindOnBanListReceived(
+ [this](const Network::Room::BanList& ban_list) { emit BanListReceived(ban_list); });
+ connect(this, &ModerationDialog::BanListReceived, this, &ModerationDialog::PopulateBanList);
+ }
+
+ // Initialize the UI
+ model = new QStandardItemModel(ui->ban_list_view);
+ model->insertColumns(0, Column::COUNT);
+ model->setHeaderData(Column::SUBJECT, Qt::Horizontal, tr("Subject"));
+ model->setHeaderData(Column::TYPE, Qt::Horizontal, tr("Type"));
+
+ ui->ban_list_view->setModel(model);
+
+ // Load the ban list in background
+ LoadBanList();
+
+ connect(ui->refresh, &QPushButton::clicked, this, [this] { LoadBanList(); });
+ connect(ui->unban, &QPushButton::clicked, this, [this] {
+ auto index = ui->ban_list_view->currentIndex();
+ SendUnbanRequest(model->item(index.row(), 0)->text());
+ });
+ connect(ui->ban_list_view, &QTreeView::clicked, [this] { ui->unban->setEnabled(true); });
+}
+
+ModerationDialog::~ModerationDialog() {
+ if (callback_handle_status_message) {
+ if (auto room = Network::GetRoomMember().lock()) {
+ room->Unbind(callback_handle_status_message);
+ }
+ }
+
+ if (callback_handle_ban_list) {
+ if (auto room = Network::GetRoomMember().lock()) {
+ room->Unbind(callback_handle_ban_list);
+ }
+ }
+}
+
+void ModerationDialog::LoadBanList() {
+ if (auto room = Network::GetRoomMember().lock()) {
+ ui->refresh->setEnabled(false);
+ ui->refresh->setText(tr("Refreshing"));
+ ui->unban->setEnabled(false);
+ room->RequestBanList();
+ }
+}
+
+void ModerationDialog::PopulateBanList(const Network::Room::BanList& ban_list) {
+ model->removeRows(0, model->rowCount());
+ for (const auto& username : ban_list.first) {
+ QStandardItem* subject_item = new QStandardItem(QString::fromStdString(username));
+ QStandardItem* type_item = new QStandardItem(tr("Forum Username"));
+ model->invisibleRootItem()->appendRow({subject_item, type_item});
+ }
+ for (const auto& ip : ban_list.second) {
+ QStandardItem* subject_item = new QStandardItem(QString::fromStdString(ip));
+ QStandardItem* type_item = new QStandardItem(tr("IP Address"));
+ model->invisibleRootItem()->appendRow({subject_item, type_item});
+ }
+ for (int i = 0; i < Column::COUNT - 1; ++i) {
+ ui->ban_list_view->resizeColumnToContents(i);
+ }
+ ui->refresh->setEnabled(true);
+ ui->refresh->setText(tr("Refresh"));
+ ui->unban->setEnabled(false);
+}
+
+void ModerationDialog::SendUnbanRequest(const QString& subject) {
+ if (auto room = Network::GetRoomMember().lock()) {
+ room->SendModerationRequest(Network::IdModUnban, subject.toStdString());
+ }
+}
+
+void ModerationDialog::OnStatusMessageReceived(const Network::StatusMessageEntry& status_message) {
+ if (status_message.type != Network::IdMemberBanned &&
+ status_message.type != Network::IdAddressUnbanned)
+ return;
+
+ // Update the ban list for ban/unban
+ LoadBanList();
+}
diff --git a/src/citra_qt/multiplayer/moderation_dialog.h b/src/citra_qt/multiplayer/moderation_dialog.h
new file mode 100644
index 0000000000..d10083d5b8
--- /dev/null
+++ b/src/citra_qt/multiplayer/moderation_dialog.h
@@ -0,0 +1,42 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+#include
+#include
+#include "network/room.h"
+#include "network/room_member.h"
+
+namespace Ui {
+class ModerationDialog;
+}
+
+class QStandardItemModel;
+
+class ModerationDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ModerationDialog(QWidget* parent = nullptr);
+ ~ModerationDialog();
+
+signals:
+ void StatusMessageReceived(const Network::StatusMessageEntry&);
+ void BanListReceived(const Network::Room::BanList&);
+
+private:
+ void LoadBanList();
+ void PopulateBanList(const Network::Room::BanList& ban_list);
+ void SendUnbanRequest(const QString& subject);
+ void OnStatusMessageReceived(const Network::StatusMessageEntry& status_message);
+
+ std::unique_ptr ui;
+ QStandardItemModel* model;
+ Network::RoomMember::CallbackHandle callback_handle_status_message;
+ Network::RoomMember::CallbackHandle callback_handle_ban_list;
+};
+
+Q_DECLARE_METATYPE(Network::Room::BanList);
diff --git a/src/citra_qt/multiplayer/moderation_dialog.ui b/src/citra_qt/multiplayer/moderation_dialog.ui
new file mode 100644
index 0000000000..808d994142
--- /dev/null
+++ b/src/citra_qt/multiplayer/moderation_dialog.ui
@@ -0,0 +1,84 @@
+
+
+ ModerationDialog
+
+
+ Moderation
+
+
+
+ 0
+ 0
+ 500
+ 300
+
+
+
+
-
+
+
+ Ban List
+
+
+
-
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Refreshing
+
+
+ false
+
+
+
+ -
+
+
+ Unban
+
+
+ false
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ QDialogButtonBox::Ok
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ ModerationDialog
+ accept()
+
+
+
+
diff --git a/src/citra_qt/multiplayer/state.cpp b/src/citra_qt/multiplayer/state.cpp
index 14b2bd7ecd..996af55b33 100644
--- a/src/citra_qt/multiplayer/state.cpp
+++ b/src/citra_qt/multiplayer/state.cpp
@@ -226,6 +226,12 @@ void MultiplayerState::OnOpenNetworkRoom() {
if (client_room == nullptr) {
client_room = new ClientRoomWindow(this);
}
+ const std::string host_username = member->GetRoomInformation().host_username;
+ if (host_username.empty()) {
+ client_room->SetModPerms(false);
+ } else {
+ client_room->SetModPerms(member->GetUsername() == host_username);
+ }
BringWidgetToFront(client_room);
return;
}
diff --git a/src/citra_qt/multiplayer/state.h b/src/citra_qt/multiplayer/state.h
index 78a36865bf..a49288e834 100644
--- a/src/citra_qt/multiplayer/state.h
+++ b/src/citra_qt/multiplayer/state.h
@@ -66,6 +66,7 @@ private:
QAction* show_room;
std::shared_ptr announce_multiplayer_session;
Network::RoomMember::State current_state = Network::RoomMember::State::Uninitialized;
+ bool has_mod_perms = false;
Network::RoomMember::CallbackHandle state_callback_handle;
Network::RoomMember::CallbackHandle error_callback_handle;
};