summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/yuzu/CMakeLists.txt3
-rw-r--r--src/yuzu/applets/qt_amiibo_manager.cpp247
-rw-r--r--src/yuzu/applets/qt_amiibo_manager.h93
-rw-r--r--src/yuzu/applets/qt_amiibo_manager.ui491
-rw-r--r--src/yuzu/main.cpp23
-rw-r--r--src/yuzu/main.h9
6 files changed, 865 insertions, 1 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 5cc1fbf32..8571d9c7c 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -18,6 +18,9 @@ add_executable(yuzu
18 about_dialog.cpp 18 about_dialog.cpp
19 about_dialog.h 19 about_dialog.h
20 aboutdialog.ui 20 aboutdialog.ui
21 applets/qt_amiibo_manager.cpp
22 applets/qt_amiibo_manager.h
23 applets/qt_amiibo_manager.ui
21 applets/qt_controller.cpp 24 applets/qt_controller.cpp
22 applets/qt_controller.h 25 applets/qt_controller.h
23 applets/qt_controller.ui 26 applets/qt_controller.ui
diff --git a/src/yuzu/applets/qt_amiibo_manager.cpp b/src/yuzu/applets/qt_amiibo_manager.cpp
new file mode 100644
index 000000000..9c7b15d06
--- /dev/null
+++ b/src/yuzu/applets/qt_amiibo_manager.cpp
@@ -0,0 +1,247 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <thread>
6#include <fmt/format.h>
7#include <nlohmann/json.hpp>
8
9#include "common/assert.h"
10#include "common/string_util.h"
11#include "core/hle/service/nfp/nfp_device.h"
12#include "core/hle/service/nfp/nfp_result.h"
13#include "input_common/drivers/virtual_amiibo.h"
14#include "input_common/main.h"
15#include "ui_qt_amiibo_manager.h"
16#include "web_service/web_backend.h"
17#include "yuzu/applets/qt_amiibo_manager.h"
18#include "yuzu/main.h"
19
20QtAmiiboManagerDialog::QtAmiiboManagerDialog(QWidget* parent,
21 Core::Frontend::CabinetParameters parameters_,
22 InputCommon::InputSubsystem* input_subsystem_,
23 std::shared_ptr<Service::NFP::NfpDevice> nfp_device_)
24 : QDialog(parent), ui(std::make_unique<Ui::QtAmiiboManagerDialog>()),
25 input_subsystem{input_subsystem_}, nfp_device{nfp_device_},
26 parameters(std::move(parameters_)) {
27 ui->setupUi(this);
28
29 LoadInfo();
30
31 resize(0, 0);
32}
33
34QtAmiiboManagerDialog::~QtAmiiboManagerDialog() = default;
35
36int QtAmiiboManagerDialog::exec() {
37 if (!is_initalized) {
38 return QDialog::Rejected;
39 }
40 return QDialog::exec();
41}
42
43std::string QtAmiiboManagerDialog::GetName() {
44 return ui->amiiboCustomNameValue->text().toStdString();
45}
46
47void QtAmiiboManagerDialog::LoadInfo() {
48 if (input_subsystem->GetVirtualAmiibo()->ReloadAmiibo() !=
49 InputCommon::VirtualAmiibo::Info::Success) {
50 return;
51 }
52
53 if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
54 nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
55 return;
56 }
57 nfp_device->Mount(Service::NFP::MountTarget::All);
58
59 Service::NFP::ModelInfo model_info{};
60 const auto model_result = nfp_device->GetModelInfo(model_info);
61
62 if (model_result.IsSuccess()) {
63 const auto amiibo_id =
64 fmt::format("{:04x}{:02x}{:02x}{:04x}{:02x}02", Common::swap16(model_info.character_id),
65 model_info.character_variant, model_info.amiibo_type,
66 model_info.model_number, model_info.series);
67 LOG_ERROR(Input, "{}", amiibo_id);
68 LoadAmiiboApiInfo(amiibo_id);
69 }
70
71 LoadAmiiboData();
72 LoadAmiiboGameInfo();
73
74 ui->amiiboDirectoryValue->setText(
75 QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath()));
76
77 SetManagerDescription();
78 is_initalized = true;
79}
80
81void QtAmiiboManagerDialog::LoadAmiiboApiInfo(std::string amiibo_id) {
82 WebService::Client client{"https://amiiboapi.com", {}, {}};
83 WebService::Client image_client{"https://raw.githubusercontent.com", {}, {}};
84 const auto url_path = fmt::format("/api/amiibo/?id={}", amiibo_id);
85
86 const auto amiibo_json = client.GetJson(url_path, true).returned_data;
87 if (amiibo_json.empty()) {
88 ui->amiiboImageLabel->setVisible(false);
89 ui->amiiboInfoGroup->setVisible(false);
90 return;
91 }
92
93 std::string amiibo_series{};
94 std::string amiibo_name{};
95 std::string amiibo_image_url{};
96 std::string amiibo_type{};
97
98 const auto parsed_amiibo_json_json = nlohmann::json::parse(amiibo_json).at("amiibo");
99 parsed_amiibo_json_json.at("amiiboSeries").get_to(amiibo_series);
100 parsed_amiibo_json_json.at("name").get_to(amiibo_name);
101 parsed_amiibo_json_json.at("image").get_to(amiibo_image_url);
102 parsed_amiibo_json_json.at("type").get_to(amiibo_type);
103
104 ui->amiiboSeriesValue->setText(QString::fromStdString(amiibo_series));
105 ui->amiiboNameValue->setText(QString::fromStdString(amiibo_name));
106 ui->amiiboTypeValue->setText(QString::fromStdString(amiibo_type));
107
108 if (amiibo_image_url.size() < 34) {
109 ui->amiiboImageLabel->setVisible(false);
110 }
111
112 const auto image_url_path = amiibo_image_url.substr(34, amiibo_image_url.size() - 34);
113 const auto image_data = image_client.GetImage(image_url_path, true).returned_data;
114
115 if (image_data.empty()) {
116 ui->amiiboImageLabel->setVisible(false);
117 }
118
119 QPixmap pixmap;
120 pixmap.loadFromData(reinterpret_cast<const u8*>(image_data.data()),
121 static_cast<uint>(image_data.size()));
122 pixmap = pixmap.scaled(250, 350, Qt::AspectRatioMode::KeepAspectRatio,
123 Qt::TransformationMode::SmoothTransformation);
124 ui->amiiboImageLabel->setPixmap(pixmap);
125}
126
127void QtAmiiboManagerDialog::LoadAmiiboData() {
128 Service::NFP::RegisterInfo register_info{};
129 Service::NFP::CommonInfo common_info{};
130 const auto register_result = nfp_device->GetRegisterInfo(register_info);
131 const auto common_result = nfp_device->GetCommonInfo(common_info);
132
133 if (register_result.IsFailure()) {
134 ui->creationDateValue->setDisabled(true);
135 ui->modificationDateValue->setDisabled(true);
136 ui->amiiboCustomNameValue->setReadOnly(false);
137 ui->amiiboOwnerValue->setReadOnly(false);
138 return;
139 }
140
141 if (parameters.mode == Service::NFP::CabinetMode::StartNicknameAndOwnerSettings) {
142 ui->creationDateValue->setDisabled(true);
143 ui->modificationDateValue->setDisabled(true);
144 }
145
146 const auto amiibo_name = std::string(register_info.amiibo_name.data());
147 const auto owner_name = Common::UTF16ToUTF8(register_info.mii_char_info.name.data());
148 const auto creation_date =
149 QDate(register_info.creation_date.year, register_info.creation_date.month,
150 register_info.creation_date.day);
151
152 ui->amiiboCustomNameValue->setText(QString::fromStdString(amiibo_name));
153 ui->amiiboOwnerValue->setText(QString::fromStdString(owner_name));
154 ui->amiiboCustomNameValue->setReadOnly(true);
155 ui->amiiboOwnerValue->setReadOnly(true);
156 ui->creationDateValue->setDate(creation_date);
157
158 if (common_result.IsFailure()) {
159 ui->modificationDateValue->setDisabled(true);
160 return;
161 }
162
163 const auto modification_date =
164 QDate(common_info.last_write_date.year, common_info.last_write_date.month,
165 common_info.last_write_date.day);
166 ui->modificationDateValue->setDate(modification_date);
167}
168
169void QtAmiiboManagerDialog::LoadAmiiboGameInfo() {
170 u32 application_area_id{};
171 const auto application_result = nfp_device->GetApplicationAreaId(application_area_id);
172
173 if (application_result.IsFailure()) {
174 ui->gameIdValue->setVisible(false);
175 ui->gameIdLabel->setText(tr("No game data present"));
176 return;
177 }
178
179 SetGameDataName(application_area_id);
180}
181
182void QtAmiiboManagerDialog::SetGameDataName(u32 application_area_id) {
183 const std::array<std::pair<u32, QString>, 12> game_name_list = {
184 // 3ds, wii u
185 std::pair<u32, QString>{0x10110E00, QStringLiteral("Super Smash Bros (3DS/WiiU)")},
186 {0x00132600, QStringLiteral("Mario & Luigi: Paper Jam")},
187 {0x0014F000, QStringLiteral("Animal Crossing: Happy Home Designer")},
188 {0x00152600, QStringLiteral("Chibi-Robo!: Zip Lash")},
189 {0x10161f00, QStringLiteral("Mario Party 10")},
190 {0x1019C800, QStringLiteral("The Legend of Zelda: Twilight Princess HD")},
191 // switch
192 {0x10162B00, QStringLiteral("Splatoon 2")},
193 {0x1016e100, QStringLiteral("Shovel Knight: Treasure Trove")},
194 {0x1019C800, QStringLiteral("The Legend of Zelda: Breath of the Wild")},
195 {0x34F80200, QStringLiteral("Super Smash Bros. Ultimate")},
196 {0x38600500, QStringLiteral("Splatoon 3")},
197 {0x3B440400, QStringLiteral("The Legend of Zelda: Link's Awakening")},
198 };
199
200 for (const auto& [game_id, game_name] : game_name_list) {
201 if (application_area_id == game_id) {
202 ui->gameIdValue->setText(game_name);
203 return;
204 }
205 }
206
207 const auto application_area_string = fmt::format("{:016x}", application_area_id);
208 ui->gameIdValue->setText(QString::fromStdString(application_area_string));
209}
210
211void QtAmiiboManagerDialog::SetManagerDescription() {
212 switch (parameters.mode) {
213 case Service::NFP::CabinetMode::StartFormatter:
214 ui->cabinetActionDescriptionLabel->setText(
215 tr("The following amiibo data will be formated:"));
216 break;
217 case Service::NFP::CabinetMode::StartGameDataEraser:
218 ui->cabinetActionDescriptionLabel->setText(tr("The following game data will removed:"));
219 break;
220 case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings:
221 ui->cabinetActionDescriptionLabel->setText(tr("Set nickname and owner:"));
222 break;
223 case Service::NFP::CabinetMode::StartRestorer:
224 ui->cabinetActionDescriptionLabel->setText(tr("Do you wish to restore this amiibo:"));
225 break;
226 }
227}
228
229QtAmiiboManager::QtAmiiboManager(GMainWindow& parent) {
230 connect(this, &QtAmiiboManager::MainWindowShowAmiiboManager, &parent,
231 &GMainWindow::AmiiboManagerShowDialog, Qt::QueuedConnection);
232 connect(&parent, &GMainWindow::AmiiboManagerFinished, this,
233 &QtAmiiboManager::MainWindowFinished, Qt::QueuedConnection);
234}
235
236QtAmiiboManager::~QtAmiiboManager() = default;
237
238void QtAmiiboManager::ShowCabinetApplet(std::function<void(bool, const std::string&)> callback_,
239 const Core::Frontend::CabinetParameters& parameters,
240 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
241 callback = std::move(callback_);
242 emit MainWindowShowAmiiboManager(parameters, nfp_device);
243}
244
245void QtAmiiboManager::MainWindowFinished(bool is_success, std::string name) {
246 callback(is_success, name);
247}
diff --git a/src/yuzu/applets/qt_amiibo_manager.h b/src/yuzu/applets/qt_amiibo_manager.h
new file mode 100644
index 000000000..3f5866ed7
--- /dev/null
+++ b/src/yuzu/applets/qt_amiibo_manager.h
@@ -0,0 +1,93 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <memory>
8#include <QDialog>
9#include "core/frontend/applets/cabinet.h"
10
11class GMainWindow;
12class QCheckBox;
13class QComboBox;
14class QDialogButtonBox;
15class QGroupBox;
16class QLabel;
17
18class InputProfiles;
19
20namespace InputCommon {
21class InputSubsystem;
22}
23
24namespace Ui {
25class QtAmiiboManagerDialog;
26}
27
28namespace Core {
29class System;
30}
31
32namespace Core::HID {
33class HIDCore;
34enum class NpadStyleIndex : u8;
35} // namespace Core::HID
36
37namespace Service::NFP {
38class NfpDevice;
39} // namespace Service::NFP
40
41class QtAmiiboManagerDialog final : public QDialog {
42 Q_OBJECT
43
44public:
45 explicit QtAmiiboManagerDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_,
46 InputCommon::InputSubsystem* input_subsystem_,
47 std::shared_ptr<Service::NFP::NfpDevice> nfp_device_);
48 ~QtAmiiboManagerDialog() override;
49
50 int exec() override;
51
52 std::string GetName();
53
54private:
55 void LoadInfo();
56 void LoadAmiiboApiInfo(std::string amiibo_id);
57 void LoadAmiiboData();
58 void LoadAmiiboGameInfo();
59 void SetGameDataName(u32 application_area_id);
60 void SetManagerDescription();
61
62 std::unique_ptr<Ui::QtAmiiboManagerDialog> ui;
63
64 InputCommon::InputSubsystem* input_subsystem;
65 std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
66
67 // Parameters sent in from the backend HLE applet.
68 Core::Frontend::CabinetParameters parameters;
69
70 // If false amiibo manager failed to load
71 bool is_initalized{};
72};
73
74class QtAmiiboManager final : public QObject, public Core::Frontend::CabinetApplet {
75 Q_OBJECT
76
77public:
78 explicit QtAmiiboManager(GMainWindow& parent);
79 ~QtAmiiboManager() override;
80
81 void ShowCabinetApplet(std::function<void(bool, const std::string&)> callback_,
82 const Core::Frontend::CabinetParameters& parameters,
83 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
84
85signals:
86 void MainWindowShowAmiiboManager(const Core::Frontend::CabinetParameters& parameters,
87 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const;
88
89private:
90 void MainWindowFinished(bool is_success, std::string name);
91
92 mutable std::function<void(bool, const std::string&)> callback;
93};
diff --git a/src/yuzu/applets/qt_amiibo_manager.ui b/src/yuzu/applets/qt_amiibo_manager.ui
new file mode 100644
index 000000000..eb6eabe59
--- /dev/null
+++ b/src/yuzu/applets/qt_amiibo_manager.ui
@@ -0,0 +1,491 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>QtAmiiboManagerDialog</class>
4 <widget class="QDialog" name="QtAmiiboManagerDialog">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>839</width>
10 <height>500</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Amiibo Manager</string>
15 </property>
16 <property name="styleSheet">
17 <string notr="true"/>
18 </property>
19 <layout class="QVBoxLayout" name="verticalLayout" stretch="0">
20 <property name="leftMargin">
21 <number>0</number>
22 </property>
23 <property name="topMargin">
24 <number>0</number>
25 </property>
26 <property name="rightMargin">
27 <number>0</number>
28 </property>
29 <property name="bottomMargin">
30 <number>0</number>
31 </property>
32 <item>
33 <widget class="QWidget" name="mainControllerApplet" native="true">
34 <layout class="QVBoxLayout" name="verticalLayout_1" stretch="0,3,0">
35 <property name="spacing">
36 <number>0</number>
37 </property>
38 <property name="leftMargin">
39 <number>0</number>
40 </property>
41 <property name="topMargin">
42 <number>0</number>
43 </property>
44 <property name="rightMargin">
45 <number>0</number>
46 </property>
47 <property name="bottomMargin">
48 <number>0</number>
49 </property>
50 <item>
51 <widget class="QWidget" name="topControllerApplet" native="true">
52 <layout class="QHBoxLayout" name="horizontalLayout">
53 <property name="spacing">
54 <number>10</number>
55 </property>
56 <property name="leftMargin">
57 <number>20</number>
58 </property>
59 <property name="topMargin">
60 <number>15</number>
61 </property>
62 <property name="rightMargin">
63 <number>0</number>
64 </property>
65 <property name="bottomMargin">
66 <number>15</number>
67 </property>
68 <item>
69 <widget class="QLabel" name="cabinetActionDescriptionLabel">
70 <property name="font">
71 <font>
72 <pointsize>12</pointsize>
73 <weight>75</weight>
74 <bold>true</bold>
75 </font>
76 </property>
77 <property name="text">
78 <string/>
79 </property>
80 <property name="alignment">
81 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
82 </property>
83 <property name="wordWrap">
84 <bool>false</bool>
85 </property>
86 </widget>
87 </item>
88 <item>
89 <spacer name="horizontalSpacer_2">
90 <property name="orientation">
91 <enum>Qt::Horizontal</enum>
92 </property>
93 <property name="sizeHint" stdset="0">
94 <size>
95 <width>40</width>
96 <height>20</height>
97 </size>
98 </property>
99 </spacer>
100 </item>
101 </layout>
102 </widget>
103 </item>
104 <item>
105 <widget class="QWidget" name="middleControllerApplet" native="true">
106 <layout class="QVBoxLayout" name="verticalLayout_3">
107 <property name="spacing">
108 <number>0</number>
109 </property>
110 <property name="leftMargin">
111 <number>0</number>
112 </property>
113 <property name="topMargin">
114 <number>0</number>
115 </property>
116 <property name="rightMargin">
117 <number>0</number>
118 </property>
119 <property name="bottomMargin">
120 <number>0</number>
121 </property>
122 <item>
123 <layout class="QHBoxLayout" name="horizontalLayout_2">
124 <property name="leftMargin">
125 <number>20</number>
126 </property>
127 <property name="rightMargin">
128 <number>15</number>
129 </property>
130 <item>
131 <widget class="QLabel" name="amiiboImageLabel">
132 <property name="minimumSize">
133 <size>
134 <width>250</width>
135 <height>350</height>
136 </size>
137 </property>
138 <property name="maximumSize">
139 <size>
140 <width>236</width>
141 <height>350</height>
142 </size>
143 </property>
144 <property name="text">
145 <string/>
146 </property>
147 <property name="alignment">
148 <set>Qt::AlignCenter</set>
149 </property>
150 </widget>
151 </item>
152 <item>
153 <layout class="QVBoxLayout" name="verticalLayout_4">
154 <property name="leftMargin">
155 <number>20</number>
156 </property>
157 <property name="topMargin">
158 <number>8</number>
159 </property>
160 <property name="bottomMargin">
161 <number>15</number>
162 </property>
163 <item>
164 <widget class="QGroupBox" name="amiiboInfoGroup">
165 <property name="title">
166 <string>Amiibo Info</string>
167 </property>
168 <layout class="QVBoxLayout" name="verticalLayout_5">
169 <item>
170 <layout class="QGridLayout" name="gridLayout_1">
171 <item row="0" column="0">
172 <widget class="QLabel" name="amiiboSeriesLabel">
173 <property name="text">
174 <string>Series</string>
175 </property>
176 </widget>
177 </item>
178 <item row="0" column="1">
179 <widget class="QLineEdit" name="amiiboSeriesValue">
180 <property name="sizePolicy">
181 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
182 <horstretch>0</horstretch>
183 <verstretch>0</verstretch>
184 </sizepolicy>
185 </property>
186 <property name="readOnly">
187 <bool>true</bool>
188 </property>
189 </widget>
190 </item>
191 <item row="1" column="0">
192 <widget class="QLabel" name="amiiboTypeLabel">
193 <property name="text">
194 <string>Type</string>
195 </property>
196 </widget>
197 </item>
198 <item row="1" column="1">
199 <widget class="QLineEdit" name="amiiboTypeValue">
200 <property name="sizePolicy">
201 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
202 <horstretch>0</horstretch>
203 <verstretch>0</verstretch>
204 </sizepolicy>
205 </property>
206 <property name="readOnly">
207 <bool>true</bool>
208 </property>
209 </widget>
210 </item>
211 <item row="2" column="0">
212 <widget class="QLabel" name="amiiboNameLabel">
213 <property name="text">
214 <string>Name</string>
215 </property>
216 </widget>
217 </item>
218 <item row="2" column="1">
219 <widget class="QLineEdit" name="amiiboNameValue">
220 <property name="sizePolicy">
221 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
222 <horstretch>0</horstretch>
223 <verstretch>0</verstretch>
224 </sizepolicy>
225 </property>
226 <property name="readOnly">
227 <bool>true</bool>
228 </property>
229 </widget>
230 </item>
231 </layout>
232 </item>
233 </layout>
234 </widget>
235 </item>
236 <item>
237 <widget class="QGroupBox" name="amiiboDataGroup">
238 <property name="title">
239 <string>Amiibo Data</string>
240 </property>
241 <layout class="QVBoxLayout" name="verticalLayout_6">
242 <item>
243 <layout class="QGridLayout" name="gridLayout_2">
244 <item row="0" column="0">
245 <widget class="QLabel" name="amiiboCustomNameLabel">
246 <property name="text">
247 <string>Custom Name</string>
248 </property>
249 </widget>
250 </item>
251 <item row="0" column="1">
252 <widget class="QLineEdit" name="amiiboCustomNameValue">
253 <property name="sizePolicy">
254 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
255 <horstretch>0</horstretch>
256 <verstretch>0</verstretch>
257 </sizepolicy>
258 </property>
259 <property name="maxLength">
260 <number>10</number>
261 </property>
262 </widget>
263 </item>
264 <item row="1" column="0">
265 <widget class="QLabel" name="amiiboOwnerLabel">
266 <property name="text">
267 <string>Owner</string>
268 </property>
269 </widget>
270 </item>
271 <item row="1" column="1">
272 <widget class="QLineEdit" name="amiiboOwnerValue">
273 <property name="sizePolicy">
274 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
275 <horstretch>0</horstretch>
276 <verstretch>0</verstretch>
277 </sizepolicy>
278 </property>
279 <property name="maxLength">
280 <number>10</number>
281 </property>
282 </widget>
283 </item>
284 <item row="2" column="0">
285 <widget class="QLabel" name="creationDateLabel">
286 <property name="text">
287 <string>Creation Date</string>
288 </property>
289 </widget>
290 </item>
291 <item row="2" column="1">
292 <widget class="QDateTimeEdit" name="creationDateValue">
293 <property name="readOnly">
294 <bool>true</bool>
295 </property>
296 <property name="minimumDate">
297 <date>
298 <year>1970</year>
299 <month>1</month>
300 <day>1</day>
301 </date>
302 </property>
303 <property name="displayFormat">
304 <string>dd/MM/yyyy</string>
305 </property>
306 </widget>
307 </item>
308 <item row="3" column="0">
309 <widget class="QLabel" name="modificationDateLabel">
310 <property name="text">
311 <string>Modification Date</string>
312 </property>
313 </widget>
314 </item>
315 <item row="3" column="1">
316 <widget class="QDateTimeEdit" name="modificationDateValue">
317 <property name="readOnly">
318 <bool>true</bool>
319 </property>
320 <property name="minimumDate">
321 <date>
322 <year>1970</year>
323 <month>1</month>
324 <day>1</day>
325 </date>
326 </property>
327 <property name="displayFormat">
328 <string>dd/MM/yyyy </string>
329 </property>
330 </widget>
331 </item>
332 </layout>
333 </item>
334 </layout>
335 </widget>
336 </item>
337 <item>
338 <widget class="QGroupBox" name="gameDataGroup">
339 <property name="minimumSize">
340 <size>
341 <width>500</width>
342 <height>0</height>
343 </size>
344 </property>
345 <property name="title">
346 <string>Game Data</string>
347 </property>
348 <layout class="QGridLayout" name="gridLayout_3">
349 <item row="0" column="0">
350 <widget class="QLabel" name="gameIdLabel">
351 <property name="text">
352 <string>Game Id</string>
353 </property>
354 </widget>
355 </item>
356 <item row="0" column="1">
357 <widget class="QLineEdit" name="gameIdValue">
358 <property name="sizePolicy">
359 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
360 <horstretch>0</horstretch>
361 <verstretch>0</verstretch>
362 </sizepolicy>
363 </property>
364 <property name="readOnly">
365 <bool>true</bool>
366 </property>
367 </widget>
368 </item>
369 </layout>
370 </widget>
371 </item>
372 <item>
373 <widget class="QGroupBox" name="MountAmiiboGroup">
374 <property name="minimumSize">
375 <size>
376 <width>500</width>
377 <height>0</height>
378 </size>
379 </property>
380 <property name="title">
381 <string>Mount Amiibo</string>
382 </property>
383 <layout class="QGridLayout" name="gridLayout_4">
384 <item row="0" column="3">
385 <widget class="QToolButton" name="amiiboDirectoryButton">
386 <property name="text">
387 <string>...</string>
388 </property>
389 </widget>
390 </item>
391 <item row="0" column="1">
392 <spacer name="horizontalSpacer">
393 <property name="orientation">
394 <enum>Qt::Horizontal</enum>
395 </property>
396 <property name="sizeType">
397 <enum>QSizePolicy::Maximum</enum>
398 </property>
399 <property name="sizeHint" stdset="0">
400 <size>
401 <width>60</width>
402 <height>20</height>
403 </size>
404 </property>
405 </spacer>
406 </item>
407 <item row="0" column="0">
408 <widget class="QLabel" name="amiiboDirectoryLabel">
409 <property name="text">
410 <string>File Path</string>
411 </property>
412 </widget>
413 </item>
414 <item row="0" column="2">
415 <widget class="QLineEdit" name="amiiboDirectoryValue"/>
416 </item>
417 </layout>
418 </widget>
419 </item>
420 <item>
421 <spacer name="verticalSpacer">
422 <property name="orientation">
423 <enum>Qt::Vertical</enum>
424 </property>
425 <property name="sizeHint" stdset="0">
426 <size>
427 <width>20</width>
428 <height>40</height>
429 </size>
430 </property>
431 </spacer>
432 </item>
433 </layout>
434 </item>
435 </layout>
436 </item>
437 </layout>
438 </widget>
439 </item>
440 <item>
441 <widget class="QWidget" name="bottomControllerApplet" native="true">
442 <layout class="QHBoxLayout" name="horizontalLayout_6">
443 <property name="spacing">
444 <number>15</number>
445 </property>
446 <property name="leftMargin">
447 <number>15</number>
448 </property>
449 <property name="topMargin">
450 <number>8</number>
451 </property>
452 <property name="rightMargin">
453 <number>20</number>
454 </property>
455 <property name="bottomMargin">
456 <number>8</number>
457 </property>
458 <item alignment="Qt::AlignBottom">
459 <widget class="QDialogButtonBox" name="buttonBox">
460 <property name="enabled">
461 <bool>true</bool>
462 </property>
463 <property name="standardButtons">
464 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
465 </property>
466 </widget>
467 </item>
468 </layout>
469 </widget>
470 </item>
471 </layout>
472 </widget>
473 </item>
474 </layout>
475 </widget>
476 <resources/>
477 <connections>
478 <connection>
479 <sender>buttonBox</sender>
480 <signal>accepted()</signal>
481 <receiver>QtAmiiboManagerDialog</receiver>
482 <slot>accept()</slot>
483 </connection>
484 <connection>
485 <sender>buttonBox</sender>
486 <signal>rejected()</signal>
487 <receiver>QtAmiiboManagerDialog</receiver>
488 <slot>reject()</slot>
489 </connection>
490 </connections>
491</ui>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 27c9e1f32..27266cae3 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -15,6 +15,7 @@
15#endif 15#endif
16 16
17// VFS includes must be before glad as they will conflict with Windows file api, which uses defines. 17// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
18#include "applets/qt_amiibo_manager.h"
18#include "applets/qt_controller.h" 19#include "applets/qt_controller.h"
19#include "applets/qt_error.h" 20#include "applets/qt_error.h"
20#include "applets/qt_profile_select.h" 21#include "applets/qt_profile_select.h"
@@ -550,6 +551,11 @@ void GMainWindow::RegisterMetaTypes() {
550 551
551 // Register applet types 552 // Register applet types
552 553
554 // Cabinet Applet
555 qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters");
556 qRegisterMetaType<std::shared_ptr<Service::NFP::NfpDevice>>(
557 "std::shared_ptr<Service::NFP::NfpDevice>");
558
553 // Controller Applet 559 // Controller Applet
554 qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); 560 qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
555 561
@@ -571,6 +577,21 @@ void GMainWindow::RegisterMetaTypes() {
571 qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus"); 577 qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus");
572} 578}
573 579
580void GMainWindow::AmiiboManagerShowDialog(const Core::Frontend::CabinetParameters& parameters,
581 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) {
582 QtAmiiboManagerDialog dialog(this, parameters, input_subsystem.get(), nfp_device);
583
584 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
585 Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
586 dialog.setWindowModality(Qt::WindowModal);
587 if (dialog.exec() == QDialog::Rejected) {
588 emit AmiiboManagerFinished(false, {});
589 return;
590 }
591
592 emit AmiiboManagerFinished(true, dialog.GetName());
593}
594
574void GMainWindow::ControllerSelectorReconfigureControllers( 595void GMainWindow::ControllerSelectorReconfigureControllers(
575 const Core::Frontend::ControllerParameters& parameters) { 596 const Core::Frontend::ControllerParameters& parameters) {
576 QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system); 597 QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system);
@@ -1548,7 +1569,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1548 system->SetFilesystem(vfs); 1569 system->SetFilesystem(vfs);
1549 1570
1550 system->SetAppletFrontendSet({ 1571 system->SetAppletFrontendSet({
1551 nullptr, // Amiibo Manager 1572 std::make_unique<QtAmiiboManager>(*this), // Amiibo Manager
1552 std::make_unique<QtControllerSelector>(*this), // Controller Selector 1573 std::make_unique<QtControllerSelector>(*this), // Controller Selector
1553 std::make_unique<QtErrorDisplay>(*this), // Error Display 1574 std::make_unique<QtErrorDisplay>(*this), // Error Display
1554 nullptr, // Mii Editor 1575 nullptr, // Mii Editor
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index b73f550dd..2724ecd52 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -55,6 +55,7 @@ class System;
55} // namespace Core 55} // namespace Core
56 56
57namespace Core::Frontend { 57namespace Core::Frontend {
58struct CabinetParameters;
58struct ControllerParameters; 59struct ControllerParameters;
59struct InlineAppearParameters; 60struct InlineAppearParameters;
60struct InlineTextParameters; 61struct InlineTextParameters;
@@ -82,6 +83,10 @@ enum class SwkbdReplyType : u32;
82enum class WebExitReason : u32; 83enum class WebExitReason : u32;
83} // namespace Service::AM::Applets 84} // namespace Service::AM::Applets
84 85
86namespace Service::NFP {
87class NfpDevice;
88} // namespace Service::NFP
89
85namespace Ui { 90namespace Ui {
86class MainWindow; 91class MainWindow;
87} 92}
@@ -149,6 +154,8 @@ signals:
149 154
150 void UpdateInstallProgress(); 155 void UpdateInstallProgress();
151 156
157 void AmiiboManagerFinished(bool is_success, std::string name);
158
152 void ControllerSelectorReconfigureFinished(); 159 void ControllerSelectorReconfigureFinished();
153 160
154 void ErrorDisplayFinished(); 161 void ErrorDisplayFinished();
@@ -170,6 +177,8 @@ public slots:
170 void OnExecuteProgram(std::size_t program_index); 177 void OnExecuteProgram(std::size_t program_index);
171 void OnExit(); 178 void OnExit();
172 void OnSaveConfig(); 179 void OnSaveConfig();
180 void AmiiboManagerShowDialog(const Core::Frontend::CabinetParameters& parameters,
181 std::shared_ptr<Service::NFP::NfpDevice> nfp_device);
173 void ControllerSelectorReconfigureControllers( 182 void ControllerSelectorReconfigureControllers(
174 const Core::Frontend::ControllerParameters& parameters); 183 const Core::Frontend::ControllerParameters& parameters);
175 void SoftwareKeyboardInitialize( 184 void SoftwareKeyboardInitialize(