summaryrefslogtreecommitdiff
path: root/src/yuzu/configuration
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/configuration')
-rw-r--r--src/yuzu/configuration/config.cpp18
-rw-r--r--src/yuzu/configuration/configure.ui11
-rw-r--r--src/yuzu/configuration/configure_audio.cpp47
-rw-r--r--src/yuzu/configuration/configure_audio.h3
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp1
-rw-r--r--src/yuzu/configuration/configure_general.cpp2
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp44
-rw-r--r--src/yuzu/configuration/configure_input.cpp93
-rw-r--r--src/yuzu/configuration/configure_input.h3
-rw-r--r--src/yuzu/configuration/configure_input.ui28
-rw-r--r--src/yuzu/configuration/configure_web.cpp119
-rw-r--r--src/yuzu/configuration/configure_web.h38
-rw-r--r--src/yuzu/configuration/configure_web.ui206
13 files changed, 554 insertions, 59 deletions
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index d229225b4..650dd03c0 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -136,8 +136,18 @@ void Config::ReadValues() {
Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt();
qt_config->endGroup();
+ qt_config->beginGroup("WebService");
+ Settings::values.enable_telemetry = qt_config->value("enable_telemetry", true).toBool();
+ Settings::values.web_api_url =
+ qt_config->value("web_api_url", "https://api.yuzu-emu.org").toString().toStdString();
+ Settings::values.yuzu_username = qt_config->value("yuzu_username").toString().toStdString();
+ Settings::values.yuzu_token = qt_config->value("yuzu_token").toString().toStdString();
+ qt_config->endGroup();
+
qt_config->beginGroup("UI");
UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString();
+ UISettings::values.enable_discord_presence =
+ qt_config->value("enable_discord_presence", true).toBool();
qt_config->beginGroup("UIGameList");
UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool();
@@ -261,8 +271,16 @@ void Config::SaveValues() {
qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port);
qt_config->endGroup();
+ qt_config->beginGroup("WebService");
+ qt_config->setValue("enable_telemetry", Settings::values.enable_telemetry);
+ qt_config->setValue("web_api_url", QString::fromStdString(Settings::values.web_api_url));
+ qt_config->setValue("yuzu_username", QString::fromStdString(Settings::values.yuzu_username));
+ qt_config->setValue("yuzu_token", QString::fromStdString(Settings::values.yuzu_token));
+ qt_config->endGroup();
+
qt_config->beginGroup("UI");
qt_config->setValue("theme", UISettings::values.theme);
+ qt_config->setValue("enable_discord_presence", UISettings::values.enable_discord_presence);
qt_config->beginGroup("UIGameList");
qt_config->setValue("show_unknown", UISettings::values.show_unknown);
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index 20f120134..9b297df28 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -54,6 +54,11 @@
<string>Debug</string>
</attribute>
</widget>
+ <widget class="ConfigureWeb" name="webTab">
+ <attribute name="title">
+ <string>Web</string>
+ </attribute>
+ </widget>
</widget>
</item>
<item>
@@ -108,6 +113,12 @@
<header>configuration/configure_graphics.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>ConfigureWeb</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_web.h</header>
+ <container>1</container>
+ </customwidget>
</customwidgets>
<resources/>
<connections>
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index 6ea59f2a3..eb1da0f9e 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -21,9 +21,8 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
ui->output_sink_combo_box->addItem(sink_detail.id);
}
- connect(ui->volume_slider, &QSlider::valueChanged, [this] {
- ui->volume_indicator->setText(tr("%1 %").arg(ui->volume_slider->sliderPosition()));
- });
+ connect(ui->volume_slider, &QSlider::valueChanged, this,
+ &ConfigureAudio::setVolumeIndicatorText);
this->setConfiguration();
connect(ui->output_sink_combo_box,
@@ -37,32 +36,48 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
ConfigureAudio::~ConfigureAudio() = default;
void ConfigureAudio::setConfiguration() {
+ setOutputSinkFromSinkID();
+
+ // The device list cannot be pre-populated (nor listed) until the output sink is known.
+ updateAudioDevices(ui->output_sink_combo_box->currentIndex());
+
+ setAudioDeviceFromDeviceID();
+
+ ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
+ ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum());
+ setVolumeIndicatorText(ui->volume_slider->sliderPosition());
+}
+
+void ConfigureAudio::setOutputSinkFromSinkID() {
int new_sink_index = 0;
+
+ const QString sink_id = QString::fromStdString(Settings::values.sink_id);
for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
- if (ui->output_sink_combo_box->itemText(index).toStdString() == Settings::values.sink_id) {
+ if (ui->output_sink_combo_box->itemText(index) == sink_id) {
new_sink_index = index;
break;
}
}
- ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
- ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
-
- // The device list cannot be pre-populated (nor listed) until the output sink is known.
- updateAudioDevices(new_sink_index);
+ ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
+}
+void ConfigureAudio::setAudioDeviceFromDeviceID() {
int new_device_index = -1;
+
+ const QString device_id = QString::fromStdString(Settings::values.audio_device_id);
for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
- if (ui->audio_device_combo_box->itemText(index).toStdString() ==
- Settings::values.audio_device_id) {
+ if (ui->audio_device_combo_box->itemText(index) == device_id) {
new_device_index = index;
break;
}
}
+
ui->audio_device_combo_box->setCurrentIndex(new_device_index);
+}
- ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum());
- ui->volume_indicator->setText(tr("%1 %").arg(ui->volume_slider->sliderPosition()));
+void ConfigureAudio::setVolumeIndicatorText(int percentage) {
+ ui->volume_indicator->setText(tr("%1%", "Volume percentage (e.g. 50%)").arg(percentage));
}
void ConfigureAudio::applyConfiguration() {
@@ -81,10 +96,10 @@ void ConfigureAudio::updateAudioDevices(int sink_index) {
ui->audio_device_combo_box->clear();
ui->audio_device_combo_box->addItem(AudioCore::auto_device_name);
- std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString();
- std::vector<std::string> device_list = AudioCore::GetSinkDetails(sink_id).list_devices();
+ const std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString();
+ const std::vector<std::string> device_list = AudioCore::GetSinkDetails(sink_id).list_devices();
for (const auto& device : device_list) {
- ui->audio_device_combo_box->addItem(device.c_str());
+ ui->audio_device_combo_box->addItem(QString::fromStdString(device));
}
}
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 4f0af4163..207f9dfb3 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -26,6 +26,9 @@ public slots:
private:
void setConfiguration();
+ void setOutputSinkFromSinkID();
+ void setAudioDeviceFromDeviceID();
+ void setVolumeIndicatorText(int percentage);
std::unique_ptr<Ui::ConfigureAudio> ui;
};
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index daa4cc0d9..3905423e9 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -27,5 +27,6 @@ void ConfigureDialog::applyConfiguration() {
ui->graphicsTab->applyConfiguration();
ui->audioTab->applyConfiguration();
ui->debugTab->applyConfiguration();
+ ui->webTab->applyConfiguration();
Settings::Apply();
}
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 9292d9a42..f5db9e55b 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -13,7 +13,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ui->setupUi(this);
- for (auto theme : UISettings::themes) {
+ for (const auto& theme : UISettings::themes) {
ui->theme_combobox->addItem(theme.first, theme.second);
}
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 839d58f59..cd1549462 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -8,27 +8,7 @@
#include "ui_configure_graphics.h"
#include "yuzu/configuration/configure_graphics.h"
-ConfigureGraphics::ConfigureGraphics(QWidget* parent)
- : QWidget(parent), ui(new Ui::ConfigureGraphics) {
-
- ui->setupUi(this);
- this->setConfiguration();
-
- ui->frame_limit->setEnabled(Settings::values.use_frame_limit);
- connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit,
- &QSpinBox::setEnabled);
- connect(ui->bg_button, &QPushButton::clicked, this, [this] {
- const QColor new_bg_color = QColorDialog::getColor(bg_color);
- if (!new_bg_color.isValid())
- return;
- bg_color = new_bg_color;
- ui->bg_button->setStyleSheet(
- QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
- });
-}
-
-ConfigureGraphics::~ConfigureGraphics() = default;
-
+namespace {
enum class Resolution : int {
Auto,
Scale1x,
@@ -67,6 +47,28 @@ Resolution FromResolutionFactor(float factor) {
}
return Resolution::Auto;
}
+} // Anonymous namespace
+
+ConfigureGraphics::ConfigureGraphics(QWidget* parent)
+ : QWidget(parent), ui(new Ui::ConfigureGraphics) {
+
+ ui->setupUi(this);
+ this->setConfiguration();
+
+ ui->frame_limit->setEnabled(Settings::values.use_frame_limit);
+ connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit,
+ &QSpinBox::setEnabled);
+ connect(ui->bg_button, &QPushButton::clicked, this, [this] {
+ const QColor new_bg_color = QColorDialog::getColor(bg_color);
+ if (!new_bg_color.isValid())
+ return;
+ bg_color = new_bg_color;
+ ui->bg_button->setStyleSheet(
+ QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
+ });
+}
+
+ConfigureGraphics::~ConfigureGraphics() = default;
void ConfigureGraphics::setConfiguration() {
ui->resolution_factor_combobox->setCurrentIndex(
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index d29abb74b..94789c064 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -5,6 +5,7 @@
#include <algorithm>
#include <memory>
#include <utility>
+#include <QMenu>
#include <QMessageBox>
#include <QTimer>
#include "common/param_package.h"
@@ -128,33 +129,68 @@ ConfigureInput::ConfigureInput(QWidget* parent)
analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
- if (button_map[button_id])
- connect(button_map[button_id], &QPushButton::released, [=]() {
- handleClick(
- button_map[button_id],
- [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
- InputCommon::Polling::DeviceType::Button);
- });
+ if (!button_map[button_id])
+ continue;
+ button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(button_map[button_id], &QPushButton::released, [=]() {
+ handleClick(
+ button_map[button_id],
+ [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
+ InputCommon::Polling::DeviceType::Button);
+ });
+ connect(button_map[button_id], &QPushButton::customContextMenuRequested,
+ [=](const QPoint& menu_location) {
+ QMenu context_menu;
+ context_menu.addAction(tr("Clear"), [&] {
+ buttons_param[button_id].Clear();
+ button_map[button_id]->setText(tr("[not set]"));
+ });
+ context_menu.addAction(tr("Restore Default"), [&] {
+ buttons_param[button_id] = Common::ParamPackage{
+ InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
+ button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
+ });
+ context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
+ });
}
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
- if (analog_map_buttons[analog_id][sub_button_id] != nullptr) {
- connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released,
- [=]() {
- handleClick(analog_map_buttons[analog_id][sub_button_id],
- [=](const Common::ParamPackage& params) {
- SetAnalogButton(params, analogs_param[analog_id],
- analog_sub_buttons[sub_button_id]);
- },
- InputCommon::Polling::DeviceType::Button);
+ if (!analog_map_buttons[analog_id][sub_button_id])
+ continue;
+ analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
+ Qt::CustomContextMenu);
+ connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, [=]() {
+ handleClick(analog_map_buttons[analog_id][sub_button_id],
+ [=](const Common::ParamPackage& params) {
+ SetAnalogButton(params, analogs_param[analog_id],
+ analog_sub_buttons[sub_button_id]);
+ },
+ InputCommon::Polling::DeviceType::Button);
+ });
+ connect(analog_map_buttons[analog_id][sub_button_id],
+ &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
+ QMenu context_menu;
+ context_menu.addAction(tr("Clear"), [&] {
+ analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
+ analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
});
- }
+ context_menu.addAction(tr("Restore Default"), [&] {
+ Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
+ Config::default_analogs[analog_id][sub_button_id])};
+ SetAnalogButton(params, analogs_param[analog_id],
+ analog_sub_buttons[sub_button_id]);
+ analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
+ analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
+ });
+ context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
+ menu_location));
+ });
}
connect(analog_map_stick[analog_id], &QPushButton::released, [=]() {
- QMessageBox::information(
- this, "Information",
- "After pressing OK, first move your joystick horizontally, and then vertically.");
+ QMessageBox::information(this, tr("Information"),
+ tr("After pressing OK, first move your joystick horizontally, "
+ "and then vertically."));
handleClick(
analog_map_stick[analog_id],
[=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; },
@@ -162,6 +198,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
});
}
+ connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
timeout_timer->setSingleShot(true);
@@ -215,7 +252,21 @@ void ConfigureInput::restoreDefaults() {
}
}
updateButtonLabels();
- applyConfiguration();
+}
+
+void ConfigureInput::ClearAll() {
+ for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
+ if (button_map[button_id] && button_map[button_id]->isEnabled())
+ buttons_param[button_id].Clear();
+ }
+ for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
+ for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
+ if (analog_map_buttons[analog_id][sub_button_id] &&
+ analog_map_buttons[analog_id][sub_button_id]->isEnabled())
+ analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
+ }
+ }
+ updateButtonLabels();
}
void ConfigureInput::updateButtonLabels() {
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index a0bef86d5..d1198db81 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -72,6 +72,9 @@ private:
void loadConfiguration();
/// Restore all buttons to their default values.
void restoreDefaults();
+ /// Clear all input configuration
+ void ClearAll();
+
/// Update UI to reflect current configuration.
void updateButtonLabels();
diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index 8bfa5df62..8a019a693 100644
--- a/src/yuzu/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
@@ -695,6 +695,34 @@ Capture:</string>
</spacer>
</item>
<item>
+ <widget class="QPushButton" name="buttonClearAll">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string>Clear All</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QPushButton" name="buttonRestoreDefaults">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp
new file mode 100644
index 000000000..3c2ccb76f
--- /dev/null
+++ b/src/yuzu/configuration/configure_web.cpp
@@ -0,0 +1,119 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QIcon>
+#include <QMessageBox>
+#include <QtConcurrent/QtConcurrentRun>
+#include "core/settings.h"
+#include "core/telemetry_session.h"
+#include "ui_configure_web.h"
+#include "yuzu/configuration/configure_web.h"
+#include "yuzu/ui_settings.h"
+
+ConfigureWeb::ConfigureWeb(QWidget* parent)
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureWeb>()) {
+ ui->setupUi(this);
+ connect(ui->button_regenerate_telemetry_id, &QPushButton::clicked, this,
+ &ConfigureWeb::RefreshTelemetryID);
+ connect(ui->button_verify_login, &QPushButton::clicked, this, &ConfigureWeb::VerifyLogin);
+ connect(&verify_watcher, &QFutureWatcher<bool>::finished, this, &ConfigureWeb::OnLoginVerified);
+
+#ifndef USE_DISCORD_PRESENCE
+ ui->discord_group->setVisible(false);
+#endif
+ this->setConfiguration();
+}
+
+ConfigureWeb::~ConfigureWeb() = default;
+
+void ConfigureWeb::setConfiguration() {
+ ui->web_credentials_disclaimer->setWordWrap(true);
+ ui->telemetry_learn_more->setOpenExternalLinks(true);
+ ui->telemetry_learn_more->setText(
+ tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'><span style=\"text-decoration: "
+ "underline; color:#039be5;\">Learn more</span></a>"));
+
+ ui->web_signup_link->setOpenExternalLinks(true);
+ ui->web_signup_link->setText(
+ tr("<a href='https://profile.yuzu-emu.org/'><span style=\"text-decoration: underline; "
+ "color:#039be5;\">Sign up</span></a>"));
+ ui->web_token_info_link->setOpenExternalLinks(true);
+ ui->web_token_info_link->setText(
+ tr("<a href='https://yuzu-emu.org/wiki/yuzu-web-service/'><span style=\"text-decoration: "
+ "underline; color:#039be5;\">What is my token?</span></a>"));
+
+ ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry);
+ ui->edit_username->setText(QString::fromStdString(Settings::values.yuzu_username));
+ ui->edit_token->setText(QString::fromStdString(Settings::values.yuzu_token));
+ // Connect after setting the values, to avoid calling OnLoginChanged now
+ connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
+ connect(ui->edit_username, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
+ ui->label_telemetry_id->setText(
+ tr("Telemetry ID: 0x%1").arg(QString::number(Core::GetTelemetryId(), 16).toUpper()));
+ user_verified = true;
+
+ ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence);
+}
+
+void ConfigureWeb::applyConfiguration() {
+ Settings::values.enable_telemetry = ui->toggle_telemetry->isChecked();
+ UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked();
+ if (user_verified) {
+ Settings::values.yuzu_username = ui->edit_username->text().toStdString();
+ Settings::values.yuzu_token = ui->edit_token->text().toStdString();
+ } else {
+ QMessageBox::warning(this, tr("Username and token not verified"),
+ tr("Username and token were not verified. The changes to your "
+ "username and/or token have not been saved."));
+ }
+}
+
+void ConfigureWeb::RefreshTelemetryID() {
+ const u64 new_telemetry_id{Core::RegenerateTelemetryId()};
+ ui->label_telemetry_id->setText(
+ tr("Telemetry ID: 0x%1").arg(QString::number(new_telemetry_id, 16).toUpper()));
+}
+
+void ConfigureWeb::OnLoginChanged() {
+ if (ui->edit_username->text().isEmpty() && ui->edit_token->text().isEmpty()) {
+ user_verified = true;
+ ui->label_username_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16));
+ ui->label_token_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16));
+ } else {
+ user_verified = false;
+ ui->label_username_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16));
+ ui->label_token_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16));
+ }
+}
+
+void ConfigureWeb::VerifyLogin() {
+ ui->button_verify_login->setDisabled(true);
+ ui->button_verify_login->setText(tr("Verifying"));
+ verify_watcher.setFuture(
+ QtConcurrent::run([this, username = ui->edit_username->text().toStdString(),
+ token = ui->edit_token->text().toStdString()]() {
+ return Core::VerifyLogin(username, token);
+ }));
+}
+
+void ConfigureWeb::OnLoginVerified() {
+ ui->button_verify_login->setEnabled(true);
+ ui->button_verify_login->setText(tr("Verify"));
+ if (verify_watcher.result()) {
+ user_verified = true;
+ ui->label_username_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16));
+ ui->label_token_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16));
+ } else {
+ ui->label_username_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16));
+ ui->label_token_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16));
+ QMessageBox::critical(
+ this, tr("Verification failed"),
+ tr("Verification failed. Check that you have entered your username and token "
+ "correctly, and that your internet connection is working."));
+ }
+}
+
+void ConfigureWeb::retranslateUi() {
+ ui->retranslateUi(this);
+}
diff --git a/src/yuzu/configuration/configure_web.h b/src/yuzu/configuration/configure_web.h
new file mode 100644
index 000000000..7741ab95d
--- /dev/null
+++ b/src/yuzu/configuration/configure_web.h
@@ -0,0 +1,38 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QFutureWatcher>
+#include <QWidget>
+
+namespace Ui {
+class ConfigureWeb;
+}
+
+class ConfigureWeb : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit ConfigureWeb(QWidget* parent = nullptr);
+ ~ConfigureWeb();
+
+ void applyConfiguration();
+ void retranslateUi();
+
+public slots:
+ void RefreshTelemetryID();
+ void OnLoginChanged();
+ void VerifyLogin();
+ void OnLoginVerified();
+
+private:
+ void setConfiguration();
+
+ bool user_verified = true;
+ QFutureWatcher<bool> verify_watcher;
+
+ std::unique_ptr<Ui::ConfigureWeb> ui;
+};
diff --git a/src/yuzu/configuration/configure_web.ui b/src/yuzu/configuration/configure_web.ui
new file mode 100644
index 000000000..2f4b9dd73
--- /dev/null
+++ b/src/yuzu/configuration/configure_web.ui
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureWeb</class>
+ <widget class="QWidget" name="ConfigureWeb">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>926</width>
+ <height>561</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QGroupBox" name="groupBoxWebConfig">
+ <property name="title">
+ <string>yuzu Web Service</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayoutYuzuWebService">
+ <item>
+ <widget class="QLabel" name="web_credentials_disclaimer">
+ <property name="text">
+ <string>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayoutYuzuUsername">
+ <item row="2" column="3">
+ <widget class="QPushButton" name="button_verify_login">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::RightToLeft</enum>
+ </property>
+ <property name="text">
+ <string>Verify</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="web_signup_link">
+ <property name="text">
+ <string>Sign up</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3">
+ <widget class="QLineEdit" name="edit_username">
+ <property name="maxLength">
+ <number>36</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_token">
+ <property name="text">
+ <string>Token: </string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QLabel" name="label_token_verified">
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_username">
+ <property name="text">
+ <string>Username: </string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QLabel" name="label_username_verified">
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="3">
+ <widget class="QLineEdit" name="edit_token">
+ <property name="maxLength">
+ <number>36</number>
+ </property>
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="web_token_info_link">
+ <property name="text">
+ <string>What is my token?</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <spacer name="horizontalSpacer">
+ <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>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Telemetry</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="toggle_telemetry">
+ <property name="text">
+ <string>Share anonymous usage data with the yuzu team</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="telemetry_learn_more">
+ <property name="text">
+ <string>Learn more</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayoutTelemetryId">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_telemetry_id">
+ <property name="text">
+ <string>Telemetry ID:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QPushButton" name="button_regenerate_telemetry_id">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::RightToLeft</enum>
+ </property>
+ <property name="text">
+ <string>Regenerate</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="discord_group">
+ <property name="title">
+ <string>Discord Presence</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_21">
+ <item>
+ <widget class="QCheckBox" name="toggle_discordrpc">
+ <property name="text">
+ <string>Show Current Game in your Discord Status</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <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>
+ <resources/>
+ <connections/>
+</ui>