[Scummvm-git-logs] scummvm master -> 7798c2af9fb2bd458ce36ed46003c1cfd7d59b0f
sev-
noreply at scummvm.org
Sat Apr 8 14:20:21 UTC 2023
This automated email contains information about 13 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
3606a75db1 NETWORKING: Move getPreparedContents() to Common::JSON
ab22e61938 NETWORKING: Add "generic" mode to Reader
09484e8eff NETWORKING: Add HandlerUtils::makeResponseStreamFromString()
978c0b3c99 NETWORKING: Janitorial (FilesPageHandler)
b4dd48f395 CLOUD: Add new flow (WIP)
24407665ab CLOUD: Add new flow constructors for OD, Box, GD
f08da80efa CLOUD: Add another connectStorage() version
f3149a9b5d CLOUD: Add new connection wizard
538303e408 GUI: Fix CloudConnectionWizard warnings
67580ee293 GUI: Regenerate themes .zips
cc38b31ae7 CLOUD: Janitorial
14b85a41dc GUI: CloudConnectionWizard I18N
7798c2af9f CLOUD: Prepare #4860 to merge
Commit: 3606a75db19eef9cf3a37e674ac7aa62e62718d7
https://github.com/scummvm/scummvm/commit/3606a75db19eef9cf3a37e674ac7aa62e62718d7
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
NETWORKING: Move getPreparedContents() to Common::JSON
Made the method that prepares the JSON received via network static and moved to Common::JSON, so it could be used not only in CurlJsonRequest.
Changed paths:
backends/networking/curl/curljsonrequest.cpp
backends/networking/curl/curljsonrequest.h
common/formats/json.cpp
common/formats/json.h
diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp
index 6b56f9b2e84..9ead14e8b4b 100644
--- a/backends/networking/curl/curljsonrequest.cpp
+++ b/backends/networking/curl/curljsonrequest.cpp
@@ -39,27 +39,6 @@ CurlJsonRequest::~CurlJsonRequest() {
delete[] _buffer;
}
-char *CurlJsonRequest::getPreparedContents() {
- //write one more byte in the end
- byte zero[1] = {0};
- _contentsStream.write(zero, 1);
-
- //replace all "bad" bytes with '.' character
- byte *result = _contentsStream.getData();
- uint32 size = _contentsStream.size();
- for (uint32 i = 0; i < size; ++i) {
- if (result[i] == '\n')
- result[i] = ' '; //yeah, kinda stupid
- else if (result[i] < 0x20 || result[i] > 0x7f)
- result[i] = '.';
- }
-
- //make it zero-terminated string
- result[size - 1] = '\0';
-
- return (char *)result;
-}
-
void CurlJsonRequest::handle() {
if (!_stream) _stream = makeStream();
@@ -70,7 +49,7 @@ void CurlJsonRequest::handle() {
warning("CurlJsonRequest: unable to write all the bytes into MemoryWriteStreamDynamic");
if (_stream->eos()) {
- char *contents = getPreparedContents();
+ char *contents = Common::JSON::getPreparedContents(_contentsStream);
Common::JSONValue *json = Common::JSON::parse(contents);
if (json) {
finishJson(json); //it's JSON even if's not 200 OK? That's fine!..
diff --git a/backends/networking/curl/curljsonrequest.h b/backends/networking/curl/curljsonrequest.h
index 5685481a6a8..16877a4dd52 100644
--- a/backends/networking/curl/curljsonrequest.h
+++ b/backends/networking/curl/curljsonrequest.h
@@ -40,9 +40,6 @@ protected:
Common::MemoryWriteStreamDynamic _contentsStream;
byte *_buffer;
- /** Prepares raw bytes from _contentsStream to be parsed with Common::JSON::parse(). */
- char *getPreparedContents();
-
/** Sets FINISHED state and passes the JSONValue * into user's callback in JsonResponse. */
virtual void finishJson(Common::JSONValue *json);
diff --git a/common/formats/json.cpp b/common/formats/json.cpp
index a5e087e85aa..74986c13919 100644
--- a/common/formats/json.cpp
+++ b/common/formats/json.cpp
@@ -63,6 +63,27 @@ namespace Common {
*/
JSON::JSON() {}
+char *JSON::getPreparedContents(Common::MemoryWriteStreamDynamic &stream) {
+ // write one more byte in the end
+ byte zero[1] = {0};
+ stream.write(zero, 1);
+
+ // replace all "bad" bytes with '.' character
+ byte *result = stream.getData();
+ uint32 size = stream.size();
+ for (uint32 i = 0; i < size; ++i) {
+ if (result[i] == '\n')
+ result[i] = ' '; // yeah, kinda stupid
+ else if (result[i] < 0x20 || result[i] > 0x7f)
+ result[i] = '.';
+ }
+
+ // make it zero-terminated string
+ result[size - 1] = '\0';
+
+ return (char *)result;
+}
+
/**
* Parses a complete JSON encoded string (UNICODE input version)
*
diff --git a/common/formats/json.h b/common/formats/json.h
index 1025aebde67..8fecf9fc529 100644
--- a/common/formats/json.h
+++ b/common/formats/json.h
@@ -49,6 +49,7 @@
#include "common/array.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
+#include "common/memstream.h"
#include "common/str.h"
// Win32 incompatibilities
@@ -151,6 +152,9 @@ class JSON {
friend class JSONValue;
public:
+ /** Prepares raw bytes in a given stream to be parsed with Common::JSON::parse(). */
+ static char *getPreparedContents(Common::MemoryWriteStreamDynamic &stream);
+
static JSONValue *parse(const char *data);
static String stringify(const JSONValue *value);
protected:
Commit: ab22e619386eaff81e11e6a815244c2f95b48200
https://github.com/scummvm/scummvm/commit/ab22e619386eaff81e11e6a815244c2f95b48200
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
NETWORKING: Add "generic" mode to Reader
Local webserver's helper class, Reader, supported simple GET requests and POST form/multipart ones. The code for the latter was a bit specific, and didn't allow handling more generic POST requests.
This change adds ReaderMode enum, with RM_HTTP_GENERIC mode, that allows such generic requests to be handled. In Networking::Client class, that uses Reader, readContent() was renamed to readFirstContent(), and corresponds to previously existing POST form/multipart mode. readContent() should now be used for generic POST requests handling.
Changed paths:
backends/networking/sdl_net/client.cpp
backends/networking/sdl_net/client.h
backends/networking/sdl_net/reader.cpp
backends/networking/sdl_net/reader.h
backends/networking/sdl_net/uploadfileclienthandler.cpp
diff --git a/backends/networking/sdl_net/client.cpp b/backends/networking/sdl_net/client.cpp
index b0b71edaf19..5fbe4f30719 100644
--- a/backends/networking/sdl_net/client.cpp
+++ b/backends/networking/sdl_net/client.cpp
@@ -103,6 +103,15 @@ void Client::readHeaders() {
bool Client::readContent(Common::WriteStream *stream) {
if (!readMoreIfNeeded())
return false;
+ _reader.setMode(RM_HTTP_GENERIC);
+ _reader.setContent(_stream);
+ return _reader.readContent(stream);
+}
+
+bool Client::readFirstContent(Common::WriteStream *stream) {
+ if (!readMoreIfNeeded())
+ return false;
+ _reader.setMode(RM_POST_FORM_MULTIPART);
_reader.setContent(_stream);
return _reader.readFirstContent(stream);
}
diff --git a/backends/networking/sdl_net/client.h b/backends/networking/sdl_net/client.h
index 1dde6d975cd..3afd40b1304 100644
--- a/backends/networking/sdl_net/client.h
+++ b/backends/networking/sdl_net/client.h
@@ -91,6 +91,7 @@ public:
void open(SDLNet_SocketSet set, TCPsocket socket);
void readHeaders();
bool readContent(Common::WriteStream *stream);
+ bool readFirstContent(Common::WriteStream *stream);
bool readBlockHeaders(Common::WriteStream *stream);
bool readBlockContent(Common::WriteStream *stream);
void setHandler(ClientHandler *handler);
diff --git a/backends/networking/sdl_net/reader.cpp b/backends/networking/sdl_net/reader.cpp
index a95e1d2c0e2..346fff00229 100644
--- a/backends/networking/sdl_net/reader.cpp
+++ b/backends/networking/sdl_net/reader.cpp
@@ -29,6 +29,7 @@ namespace Networking {
Reader::Reader() {
_state = RS_NONE;
+ _mode = RM_HTTP_GENERIC;
_content = nullptr;
_bytesLeft = 0;
@@ -398,7 +399,51 @@ bool Reader::readFirstHeaders() {
return false;
}
+bool Reader::readContent(Common::WriteStream* stream) {
+ if (_mode != RM_HTTP_GENERIC) {
+ warning("Reader::readContent(): bad mode");
+ return false;
+ }
+
+ if (_state != RS_READING_CONTENT) {
+ warning("Reader::readContent(): bad state");
+ return false;
+ }
+
+ if (!bytesLeft())
+ return false;
+
+ byte buffer[1024];
+ while (_availableBytes > 0) {
+ uint32 bytesRead = _content->read(&buffer, 1024);
+ _availableBytes -= bytesRead;
+ _bytesLeft -= bytesRead;
+
+ if (stream)
+ if (stream->write(buffer, bytesRead) != bytesRead) {
+ warning("Reader::readContent(): failed to write buffer to stream");
+ return false;
+ }
+
+ if (_availableBytes == 0)
+ _allContentRead = true;
+
+ if (!bytesLeft())
+ break;
+ }
+
+ if (stream)
+ stream->flush();
+
+ return _allContentRead;
+}
+
bool Reader::readFirstContent(Common::WriteStream *stream) {
+ if (_mode != RM_POST_FORM_MULTIPART) {
+ warning("Reader::readFirstContent(): bad mode");
+ return false;
+ }
+
if (_state != RS_READING_CONTENT) {
warning("Reader::readFirstContent(): bad state");
return false;
@@ -409,6 +454,11 @@ bool Reader::readFirstContent(Common::WriteStream *stream) {
}
bool Reader::readBlockHeaders(Common::WriteStream *stream) {
+ if (_mode != RM_POST_FORM_MULTIPART) {
+ warning("Reader::readBlockHeaders(): bad mode");
+ return false;
+ }
+
if (_state != RS_READING_HEADERS) {
warning("Reader::readBlockHeaders(): bad state");
return false;
@@ -421,6 +471,11 @@ bool Reader::readBlockHeaders(Common::WriteStream *stream) {
}
bool Reader::readBlockContent(Common::WriteStream *stream) {
+ if (_mode != RM_POST_FORM_MULTIPART) {
+ warning("Reader::readBlockContent(): bad mode");
+ return false;
+ }
+
if (_state != RS_READING_CONTENT) {
warning("Reader::readBlockContent(): bad state");
return false;
@@ -450,6 +505,8 @@ bool Reader::readBlockContent(Common::WriteStream *stream) {
uint32 Reader::bytesLeft() const { return _bytesLeft; }
+void Reader::setMode(ReaderMode mode) { _mode = mode; }
+
void Reader::setContent(Common::MemoryReadWriteStream *stream) {
_content = stream;
_bytesLeft = stream->size() - stream->pos();
diff --git a/backends/networking/sdl_net/reader.h b/backends/networking/sdl_net/reader.h
index 52f2b5cfdbd..1a10b21adad 100644
--- a/backends/networking/sdl_net/reader.h
+++ b/backends/networking/sdl_net/reader.h
@@ -39,6 +39,11 @@ enum ReaderState {
RS_READING_CONTENT
};
+enum ReaderMode {
+ RM_HTTP_GENERIC,
+ RM_POST_FORM_MULTIPART
+};
+
/**
* This is a helper class for Client.
*
@@ -73,6 +78,7 @@ enum ReaderState {
class Reader {
ReaderState _state;
+ ReaderMode _mode;
Common::MemoryReadWriteStream *_content;
uint32 _bytesLeft;
@@ -119,10 +125,12 @@ public:
Reader &operator=(Reader &r);
bool readFirstHeaders(); //true when ended reading
+ bool readContent(Common::WriteStream *stream); //true when ended reading
bool readFirstContent(Common::WriteStream *stream); //true when ended reading
bool readBlockHeaders(Common::WriteStream *stream); //true when ended reading
bool readBlockContent(Common::WriteStream *stream); //true when ended reading
+ void setMode(ReaderMode mode);
void setContent(Common::MemoryReadWriteStream *stream);
bool badRequest() const;
diff --git a/backends/networking/sdl_net/uploadfileclienthandler.cpp b/backends/networking/sdl_net/uploadfileclienthandler.cpp
index 6ab70509f39..bc1b186c156 100644
--- a/backends/networking/sdl_net/uploadfileclienthandler.cpp
+++ b/backends/networking/sdl_net/uploadfileclienthandler.cpp
@@ -48,7 +48,7 @@ void UploadFileClientHandler::handle(Client *client) {
while (true) {
switch (_state) {
case UFH_READING_CONTENT:
- if (client->readContent(nullptr)) {
+ if (client->readFirstContent(nullptr)) {
_state = UFH_READING_BLOCK_HEADERS;
continue;
}
Commit: 09484e8effd6b2c8fe9f62bcd82e058d03231f6c
https://github.com/scummvm/scummvm/commit/09484e8effd6b2c8fe9f62bcd82e058d03231f6c
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
NETWORKING: Add HandlerUtils::makeResponseStreamFromString()
Just a small helper method to make a Common::SeekableReadStream for local webserver's handlers from Common::String contents.
Changed paths:
backends/networking/sdl_net/handlerutils.cpp
backends/networking/sdl_net/handlerutils.h
diff --git a/backends/networking/sdl_net/handlerutils.cpp b/backends/networking/sdl_net/handlerutils.cpp
index a4f8a3e2481..908c191fa12 100644
--- a/backends/networking/sdl_net/handlerutils.cpp
+++ b/backends/networking/sdl_net/handlerutils.cpp
@@ -25,6 +25,7 @@
#include "common/archive.h"
#include "common/config-manager.h"
#include "common/file.h"
+#include "common/memstream.h"
#include "common/translation.h"
#include "common/compression/unzip.h"
@@ -97,6 +98,12 @@ Common::String HandlerUtils::readEverythingFromStream(Common::SeekableReadStream
return result;
}
+Common::SeekableReadStream *HandlerUtils::makeResponseStreamFromString(Common::String response) {
+ byte *data = new byte[response.size()];
+ memcpy(data, response.c_str(), response.size());
+ return new Common::MemoryReadStream(data, response.size(), DisposeAfterUse::YES);
+}
+
Common::String HandlerUtils::normalizePath(const Common::String &path) {
Common::String normalized;
bool slash = false;
diff --git a/backends/networking/sdl_net/handlerutils.h b/backends/networking/sdl_net/handlerutils.h
index b4622f71eb7..11d9fcc83c0 100644
--- a/backends/networking/sdl_net/handlerutils.h
+++ b/backends/networking/sdl_net/handlerutils.h
@@ -33,6 +33,7 @@ public:
static Common::ArchiveMemberList listArchive();
static Common::SeekableReadStream *getArchiveFile(Common::String name);
static Common::String readEverythingFromStream(Common::SeekableReadStream *const stream);
+ static Common::SeekableReadStream *makeResponseStreamFromString(Common::String response);
static Common::String normalizePath(const Common::String &path);
static bool hasForbiddenCombinations(const Common::String &path);
Commit: 978c0b3c99e29bc677189687fe32798565d51c9c
https://github.com/scummvm/scummvm/commit/978c0b3c99e29bc677189687fe32798565d51c9c
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
NETWORKING: Janitorial (FilesPageHandler)
Changed paths:
backends/networking/sdl_net/handlers/filespagehandler.cpp
diff --git a/backends/networking/sdl_net/handlers/filespagehandler.cpp b/backends/networking/sdl_net/handlers/filespagehandler.cpp
index c0f331b66bb..b8e332ce43e 100644
--- a/backends/networking/sdl_net/handlers/filespagehandler.cpp
+++ b/backends/networking/sdl_net/handlers/filespagehandler.cpp
@@ -204,7 +204,7 @@ void FilesPageHandler::handle(Client &client) {
"</html>";
Common::String itemTemplate = "<tr><td><img src=\"icons/{icon}\"/></td><td><a href=\"{link}\">{name}</a></td><td>{size}</td></tr>\n"; //TODO: load this template too?
- // load stylish response page from the archive
+ // load stylish response page from the archive
Common::SeekableReadStream *const stream = HandlerUtils::getArchiveFile(FILES_PAGE_NAME);
if (stream)
response = HandlerUtils::readEverythingFromStream(stream);
@@ -218,7 +218,7 @@ void FilesPageHandler::handle(Client &client) {
return;
}
- //these occur twice:
+ //some of these occur twice:
replace(response, "{create_directory_button}", _("Create directory").encode());
replace(response, "{create_directory_button}", _("Create directory").encode());
replace(response, "{path}", encodeDoubleQuotes(client.queryParameter("path")));
Commit: b4dd48f3956fd4432aa209b0b1f282a8948bc0d7
https://github.com/scummvm/scummvm/commit/b4dd48f3956fd4432aa209b0b1f282a8948bc0d7
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
CLOUD: Add new flow (WIP)
- allow OPTIONS HTTP method to be handled by local webserver;
- add /connect_cloud endpoint;
- add new DropboxStorage constructor that works with JSON response instead of requesting that via shortcode;
- add CloudManager::connectStorage() overload for this new JSON flow.
/connect_cloud endpoint allows cross-origin request (via CORS HTTP headers) from cloud.scummvm.org, so user's browser sends the JSON response directly to ScummVM app, instead of the app requesting that response from the site.
This commit is WIP, introducing a new constructor for Dropbox only, and not changing the GUI part at all.
Changed paths:
A backends/networking/sdl_net/handlers/connectcloudhandler.cpp
A backends/networking/sdl_net/handlers/connectcloudhandler.h
backends/cloud/cloudmanager.cpp
backends/cloud/cloudmanager.h
backends/cloud/dropbox/dropboxstorage.cpp
backends/cloud/dropbox/dropboxstorage.h
backends/module.mk
backends/networking/sdl_net/localwebserver.cpp
backends/networking/sdl_net/localwebserver.h
backends/networking/sdl_net/reader.cpp
diff --git a/backends/cloud/cloudmanager.cpp b/backends/cloud/cloudmanager.cpp
index 251674174ec..22de5d4686b 100644
--- a/backends/cloud/cloudmanager.cpp
+++ b/backends/cloud/cloudmanager.cpp
@@ -282,6 +282,31 @@ void CloudManager::connectStorage(uint32 index, Common::String code, Networking:
// thus, no memory leak happens
}
+void CloudManager::connectStorage(uint32 index, Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb) {
+ freeStorages();
+
+ switch (index) {
+ case kStorageDropboxId:
+ new Dropbox::DropboxStorage(codeFlowJson, cb);
+ break;
+ case kStorageOneDriveId:
+ //new OneDrive::OneDriveStorage(code, cb); // TODO: more clouds
+ break;
+ case kStorageGoogleDriveId:
+ //new GoogleDrive::GoogleDriveStorage(code, cb);
+ break;
+ case kStorageBoxId:
+ //new Box::BoxStorage(code, cb);
+ break;
+ default:
+ break;
+ }
+ // in these constructors Storages request token using the passed code // TODO: rewrite
+ // when the token is received, they call replaceStorage()
+ // or removeStorage(), if some error occurred
+ // thus, no memory leak happens
+}
+
void CloudManager::disconnectStorage(uint32 index) {
if (index >= kStorageTotal)
error("CloudManager::disconnectStorage: invalid index passed");
diff --git a/backends/cloud/cloudmanager.h b/backends/cloud/cloudmanager.h
index a0d36b87602..a591120d9c0 100644
--- a/backends/cloud/cloudmanager.h
+++ b/backends/cloud/cloudmanager.h
@@ -24,6 +24,7 @@
#include "backends/cloud/storage.h"
#include "backends/cloud/cloudicon.h"
+#include "backends/networking/curl/curljsonrequest.h"
#include "common/array.h"
#include "common/singleton.h"
@@ -207,6 +208,16 @@ public:
*/
void connectStorage(uint32 index, Common::String code, Networking::ErrorCallback cb = nullptr);
+ /**
+ * Replace Storage which has given index with a
+ * storage created with given JSON response.
+ *
+ * @param index Storage's index
+ * @param codeFlowJson OAuth2 code flow JSON response (acquired from cloud.scummvm.org)
+ * @param cb callback to notify of success or error
+ */
+ void connectStorage(uint32 index, Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb = nullptr);
+
/**
* Remove Storage with a given index from config.
*
diff --git a/backends/cloud/dropbox/dropboxstorage.cpp b/backends/cloud/dropbox/dropboxstorage.cpp
index d406eaf9d4b..585e7e72cf1 100644
--- a/backends/cloud/dropbox/dropboxstorage.cpp
+++ b/backends/cloud/dropbox/dropboxstorage.cpp
@@ -46,6 +46,10 @@ DropboxStorage::DropboxStorage(Common::String code, Networking::ErrorCallback cb
getAccessToken(code, cb);
}
+DropboxStorage::DropboxStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb) : BaseStorage() {
+ codeFlowComplete(cb, codeFlowJson);
+}
+
DropboxStorage::~DropboxStorage() {}
Common::String DropboxStorage::cloudProvider() { return "dropbox"; }
diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h
index 40b34f183da..1933430a591 100644
--- a/backends/cloud/dropbox/dropboxstorage.h
+++ b/backends/cloud/dropbox/dropboxstorage.h
@@ -51,6 +51,10 @@ protected:
public:
/** This constructor uses OAuth code flow to get tokens. */
DropboxStorage(Common::String code, Networking::ErrorCallback cb);
+
+ /** This constructor uses JSON acquired via OAuth code flow to get tokens. */
+ DropboxStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb);
+
virtual ~DropboxStorage();
/**
diff --git a/backends/module.mk b/backends/module.mk
index 14a052db777..b6885089340 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -28,7 +28,6 @@ MODULE_OBJS := \
timer/default/default-timer.o
ifdef USE_CLOUD
-
ifdef USE_LIBCURL
MODULE_OBJS += \
cloud/basestorage.o \
@@ -101,6 +100,15 @@ MODULE_OBJS += \
networking/sdl_net/uploadfileclienthandler.o
endif
+ifdef USE_CLOUD
+ifdef USE_LIBCURL
+ifdef USE_SDL_NET
+MODULE_OBJS += \
+ networking/sdl_net/handlers/connectcloudhandler.o
+endif
+endif
+endif
+
# ENet networking source files.
ifdef USE_ENET
MODULE_OBJS += \
diff --git a/backends/networking/sdl_net/handlers/connectcloudhandler.cpp b/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
new file mode 100644
index 00000000000..fe2e01ace21
--- /dev/null
+++ b/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
@@ -0,0 +1,137 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "backends/networking/sdl_net/handlers/connectcloudhandler.h"
+#include "backends/fs/fs-factory.h"
+#include "backends/cloud/cloudmanager.h"
+#include "backends/networking/curl/curljsonrequest.h"
+#include "backends/networking/sdl_net/getclienthandler.h"
+#include "backends/networking/sdl_net/handlerutils.h"
+#include "backends/networking/sdl_net/localwebserver.h"
+#include "backends/networking/sdl_net/reader.h"
+#include "common/formats/json.h"
+#include "common/memstream.h"
+#include "common/translation.h"
+#include "common/callback.h"
+
+namespace Networking {
+
+ConnectCloudHandler::ConnectCloudHandler() {}
+
+ConnectCloudHandler::~ConnectCloudHandler() {}
+
+void ConnectCloudHandler::handle(Client &client) {
+ client.setHandler(new ConnectCloudClientHandler(this));
+}
+
+//
+
+ConnectCloudClientHandler::ConnectCloudClientHandler(const ConnectCloudHandler *cloudHandler):
+ _cloudHandler(cloudHandler), _clientContent(DisposeAfterUse::YES), _client(nullptr) {}
+
+ConnectCloudClientHandler::~ConnectCloudClientHandler() {}
+
+void ConnectCloudClientHandler::respond(Client &client, Common::String response, long responseCode) const {
+ Common::SeekableReadStream *responseStream = HandlerUtils::makeResponseStreamFromString(response);
+ GetClientHandler *responseHandler = new GetClientHandler(responseStream);
+ responseHandler->setResponseCode(responseCode);
+ responseHandler->setHeader("Access-Control-Allow-Origin", "https://cloud.scummvm.org");
+ responseHandler->setHeader("Access-Control-Allow-Methods", "POST");
+ responseHandler->setHeader("Access-Control-Allow-Headers", "Content-Type");
+
+ client.setHandler(responseHandler);
+}
+
+void ConnectCloudClientHandler::respondWithJson(Client &client, bool error, Common::String message, long responseCode) const {
+ Common::JSONObject response;
+ response.setVal("error", new Common::JSONValue(error));
+ response.setVal("message", new Common::JSONValue(message));
+
+ Common::JSONValue json = response;
+ respond(client, json.stringify(true), responseCode);
+}
+
+void ConnectCloudClientHandler::handleError(Client &client, Common::String message, long responseCode) const {
+ respondWithJson(client, true, message, responseCode);
+}
+
+void ConnectCloudClientHandler::handleSuccess(Client &client, Common::String message) const {
+ respondWithJson(client, false, message);
+}
+
+/// public
+
+void ConnectCloudClientHandler::handle(Client *client) {
+ if (client == nullptr) {
+ warning("ConnectCloudClientHandler::handle(): empty client pointer");
+ return;
+ }
+
+ _client = client;
+
+ if (client->method() == "OPTIONS") {
+ respond(*client, "", 200);
+ return;
+ }
+
+ if (client->method() != "POST") {
+ handleError(*client, "Method Not Allowed", 405);
+ return;
+ }
+
+ if (_clientContent.size() > SUSPICIOUS_CONTENT_SIZE) {
+ handleError(*client, "Bad Request", 400);
+ return;
+ }
+
+ if (!client->readContent(&_clientContent))
+ return;
+
+ char *contents = Common::JSON::getPreparedContents(_clientContent);
+ Common::JSONValue *json = Common::JSON::parse(contents);
+ if (json == nullptr) {
+ handleError(*client, "Not Acceptable", 406);
+ return;
+ }
+
+ Networking::JsonResponse jsonResponse(nullptr, json);
+ CloudMan.connectStorage(
+ Cloud::kStorageDropboxId, jsonResponse, // TODO: determine the correct id
+ new Common::Callback<ConnectCloudClientHandler, Networking::ErrorResponse>(this, &ConnectCloudClientHandler::storageConnectionCallback)
+ );
+}
+
+void ConnectCloudClientHandler::storageConnectionCallback(Networking::ErrorResponse response) {
+ if (response.failed || response.interrupted) {
+ Common::String message = "Failed to connect storage.";
+ if (response.failed) {
+ message += " Context: ";
+ message += response.response.c_str();
+ }
+
+ handleError(*_client, message, 200);
+ return;
+ }
+
+ handleSuccess(*_client, "Storage connected.");
+}
+
+} // End of namespace Networking
diff --git a/backends/networking/sdl_net/handlers/connectcloudhandler.h b/backends/networking/sdl_net/handlers/connectcloudhandler.h
new file mode 100644
index 00000000000..02edf1b2b5b
--- /dev/null
+++ b/backends/networking/sdl_net/handlers/connectcloudhandler.h
@@ -0,0 +1,65 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_NETWORKING_SDL_NET_CONNECTCLOUDHANDLER_H
+#define BACKENDS_NETWORKING_SDL_NET_CONNECTCLOUDHANDLER_H
+
+#include "backends/networking/sdl_net/handlers/basehandler.h"
+#include "backends/networking/sdl_net/client.h"
+#include "backends/networking/curl/request.h"
+#include "common/memstream.h"
+
+namespace Networking {
+
+class ConnectCloudHandler: public BaseHandler {
+ void handleError(Client &client, Common::String message) const;
+ void setJsonResponseHandler(Client &client, Common::String type, Common::String message) const;
+
+public:
+ ConnectCloudHandler();
+ virtual ~ConnectCloudHandler();
+
+ virtual void handle(Client &client);
+ virtual bool minimalModeSupported() { return true; }
+};
+
+class ConnectCloudClientHandler : public ClientHandler {
+ const ConnectCloudHandler *_cloudHandler;
+ Common::MemoryWriteStreamDynamic _clientContent;
+ Client *_client;
+ static const int32 SUSPICIOUS_CONTENT_SIZE = 512 * 1024; // 512 KB should be enough for any cloud JSON
+
+ void respond(Client &client, Common::String response, long responseCode = 200) const;
+ void respondWithJson(Client &client, bool error, Common::String message, long responseCode = 200) const;
+ void handleError(Client &client, Common::String message, long responseCode) const;
+ void handleSuccess(Client &client, Common::String message) const;
+ void storageConnectionCallback(Networking::ErrorResponse response);
+
+public:
+ ConnectCloudClientHandler(const ConnectCloudHandler* cloudHandler);
+ virtual ~ConnectCloudClientHandler();
+
+ virtual void handle(Client *client);
+};
+
+} // End of namespace Networking
+
+#endif
diff --git a/backends/networking/sdl_net/localwebserver.cpp b/backends/networking/sdl_net/localwebserver.cpp
index eef3d5573f5..7bae7035c12 100644
--- a/backends/networking/sdl_net/localwebserver.cpp
+++ b/backends/networking/sdl_net/localwebserver.cpp
@@ -74,6 +74,11 @@ LocalWebserver::LocalWebserver(): _set(nullptr), _serverSocket(nullptr), _timerS
addPathHandler("/upload", &_uploadFileHandler);
addPathHandler("/list", &_listAjaxHandler);
addPathHandler("/filesAJAX", &_filesAjaxPageHandler);
+#ifdef USE_CLOUD
+#ifdef USE_LIBCURL
+ addPathHandler("/connect_cloud", &_connectCloudHandler);
+#endif // USE_LIBCURL
+#endif // USE_CLOUD
_defaultHandler = &_resourceHandler;
}
diff --git a/backends/networking/sdl_net/localwebserver.h b/backends/networking/sdl_net/localwebserver.h
index 74d7567829d..ec52f017ebf 100644
--- a/backends/networking/sdl_net/localwebserver.h
+++ b/backends/networking/sdl_net/localwebserver.h
@@ -37,6 +37,12 @@
#include "common/singleton.h"
#include "common/scummsys.h"
+#ifdef USE_CLOUD
+#ifdef USE_LIBCURL
+#include "backends/networking/sdl_net/handlers/connectcloudhandler.h"
+#endif // USE_LIBCURL
+#endif // USE_CLOUD
+
namespace Common {
class SeekableReadStream;
}
@@ -69,6 +75,11 @@ class LocalWebserver : public Common::Singleton<LocalWebserver> {
UploadFileHandler _uploadFileHandler;
ListAjaxHandler _listAjaxHandler;
FilesAjaxPageHandler _filesAjaxPageHandler;
+#ifdef USE_CLOUD
+#ifdef USE_LIBCURL
+ ConnectCloudHandler _connectCloudHandler;
+#endif // USE_LIBCURL
+#endif // USE_CLOUD
ResourceHandler _resourceHandler;
uint32 _idlingFrames;
Common::Mutex _handleMutex;
diff --git a/backends/networking/sdl_net/reader.cpp b/backends/networking/sdl_net/reader.cpp
index 346fff00229..3b780c55194 100644
--- a/backends/networking/sdl_net/reader.cpp
+++ b/backends/networking/sdl_net/reader.cpp
@@ -218,7 +218,7 @@ void Reader::parseFirstLine(const Common::String &headersToParse) {
}
//check that method is supported
- if (methodParsed != "GET" && methodParsed != "PUT" && methodParsed != "POST")
+ if (methodParsed != "GET" && methodParsed != "PUT" && methodParsed != "POST" && methodParsed != "OPTIONS")
bad = true;
//check that HTTP/<VERSION> is OK
Commit: 24407665ab3c39573de9f8098e18fcb220ac4c13
https://github.com/scummvm/scummvm/commit/24407665ab3c39573de9f8098e18fcb220ac4c13
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
CLOUD: Add new flow constructors for OD, Box, GD
Changed paths:
backends/cloud/box/boxstorage.cpp
backends/cloud/box/boxstorage.h
backends/cloud/cloudmanager.cpp
backends/cloud/dropbox/dropboxstorage.h
backends/cloud/googledrive/googledrivestorage.cpp
backends/cloud/googledrive/googledrivestorage.h
backends/cloud/onedrive/onedrivestorage.cpp
backends/cloud/onedrive/onedrivestorage.h
diff --git a/backends/cloud/box/boxstorage.cpp b/backends/cloud/box/boxstorage.cpp
index 8baee35c0b8..c7c2ba8193b 100644
--- a/backends/cloud/box/boxstorage.cpp
+++ b/backends/cloud/box/boxstorage.cpp
@@ -48,6 +48,10 @@ BoxStorage::BoxStorage(Common::String code, Networking::ErrorCallback cb) {
getAccessToken(code, cb);
}
+BoxStorage::BoxStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb) {
+ codeFlowComplete(cb, codeFlowJson);
+}
+
BoxStorage::~BoxStorage() {}
Common::String BoxStorage::cloudProvider() { return "box"; }
diff --git a/backends/cloud/box/boxstorage.h b/backends/cloud/box/boxstorage.h
index 38e4fbac271..ba758cffedf 100644
--- a/backends/cloud/box/boxstorage.h
+++ b/backends/cloud/box/boxstorage.h
@@ -55,6 +55,10 @@ protected:
public:
/** This constructor uses OAuth code flow to get tokens. */
BoxStorage(Common::String code, Networking::ErrorCallback cb);
+
+ /** This constructor extracts tokens from JSON acquired via OAuth code flow. */
+ BoxStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb);
+
virtual ~BoxStorage();
/**
diff --git a/backends/cloud/cloudmanager.cpp b/backends/cloud/cloudmanager.cpp
index 22de5d4686b..cf3ccee973a 100644
--- a/backends/cloud/cloudmanager.cpp
+++ b/backends/cloud/cloudmanager.cpp
@@ -290,19 +290,19 @@ void CloudManager::connectStorage(uint32 index, Networking::JsonResponse codeFlo
new Dropbox::DropboxStorage(codeFlowJson, cb);
break;
case kStorageOneDriveId:
- //new OneDrive::OneDriveStorage(code, cb); // TODO: more clouds
+ new OneDrive::OneDriveStorage(codeFlowJson, cb);
break;
case kStorageGoogleDriveId:
- //new GoogleDrive::GoogleDriveStorage(code, cb);
+ new GoogleDrive::GoogleDriveStorage(codeFlowJson, cb);
break;
case kStorageBoxId:
- //new Box::BoxStorage(code, cb);
+ new Box::BoxStorage(codeFlowJson, cb);
break;
default:
break;
}
- // in these constructors Storages request token using the passed code // TODO: rewrite
- // when the token is received, they call replaceStorage()
+ // in these constructors Storages extract tokens from the passed JSON
+ // they call replaceStorage(), if the tokens are found,
// or removeStorage(), if some error occurred
// thus, no memory leak happens
}
diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h
index 1933430a591..f9821d0965d 100644
--- a/backends/cloud/dropbox/dropboxstorage.h
+++ b/backends/cloud/dropbox/dropboxstorage.h
@@ -52,7 +52,7 @@ public:
/** This constructor uses OAuth code flow to get tokens. */
DropboxStorage(Common::String code, Networking::ErrorCallback cb);
- /** This constructor uses JSON acquired via OAuth code flow to get tokens. */
+ /** This constructor extracts tokens from JSON acquired via OAuth code flow. */
DropboxStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb);
virtual ~DropboxStorage();
diff --git a/backends/cloud/googledrive/googledrivestorage.cpp b/backends/cloud/googledrive/googledrivestorage.cpp
index 5d5ddc3a292..9f252729c3d 100644
--- a/backends/cloud/googledrive/googledrivestorage.cpp
+++ b/backends/cloud/googledrive/googledrivestorage.cpp
@@ -49,6 +49,10 @@ GoogleDriveStorage::GoogleDriveStorage(Common::String code, Networking::ErrorCal
getAccessToken(code, cb);
}
+GoogleDriveStorage::GoogleDriveStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb) {
+ codeFlowComplete(cb, codeFlowJson);
+}
+
GoogleDriveStorage::~GoogleDriveStorage() {}
Common::String GoogleDriveStorage::cloudProvider() { return "gdrive"; }
diff --git a/backends/cloud/googledrive/googledrivestorage.h b/backends/cloud/googledrive/googledrivestorage.h
index 1b14bbdf888..414a8b531d2 100644
--- a/backends/cloud/googledrive/googledrivestorage.h
+++ b/backends/cloud/googledrive/googledrivestorage.h
@@ -58,6 +58,10 @@ protected:
public:
/** This constructor uses OAuth code flow to get tokens. */
GoogleDriveStorage(Common::String code, Networking::ErrorCallback cb);
+
+ /** This constructor extracts tokens from JSON acquired via OAuth code flow. */
+ GoogleDriveStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb);
+
virtual ~GoogleDriveStorage();
/**
diff --git a/backends/cloud/onedrive/onedrivestorage.cpp b/backends/cloud/onedrive/onedrivestorage.cpp
index ac800e45e05..883d2398758 100644
--- a/backends/cloud/onedrive/onedrivestorage.cpp
+++ b/backends/cloud/onedrive/onedrivestorage.cpp
@@ -48,6 +48,10 @@ OneDriveStorage::OneDriveStorage(Common::String code, Networking::ErrorCallback
getAccessToken(code, cb);
}
+OneDriveStorage::OneDriveStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb) {
+ codeFlowComplete(cb, codeFlowJson);
+}
+
OneDriveStorage::~OneDriveStorage() {}
Common::String OneDriveStorage::cloudProvider() { return "onedrive"; }
diff --git a/backends/cloud/onedrive/onedrivestorage.h b/backends/cloud/onedrive/onedrivestorage.h
index 0656c60ae02..09cd0fafb21 100644
--- a/backends/cloud/onedrive/onedrivestorage.h
+++ b/backends/cloud/onedrive/onedrivestorage.h
@@ -55,6 +55,10 @@ protected:
public:
/** This constructor uses OAuth code flow to get tokens. */
OneDriveStorage(Common::String code, Networking::ErrorCallback cb);
+
+ /** This constructor extracts tokens from JSON acquired via OAuth code flow. */
+ OneDriveStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb);
+
virtual ~OneDriveStorage();
/**
Commit: f08da80efafad26edd851a73af5520e20aa25466
https://github.com/scummvm/scummvm/commit/f08da80efafad26edd851a73af5520e20aa25466
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
CLOUD: Add another connectStorage() version
This new version looks for "storage" key in JSON and uses it to determine which storage needs to be connected.
Changed paths:
backends/cloud/basestorage.cpp
backends/cloud/cloudmanager.cpp
backends/cloud/cloudmanager.h
backends/networking/sdl_net/handlers/connectcloudhandler.cpp
diff --git a/backends/cloud/basestorage.cpp b/backends/cloud/basestorage.cpp
index 8c00d5eac32..534283b5392 100644
--- a/backends/cloud/basestorage.cpp
+++ b/backends/cloud/basestorage.cpp
@@ -56,11 +56,13 @@ void BaseStorage::codeFlowComplete(Networking::ErrorCallback callback, Networkin
if (json == nullptr) {
debug(9, "BaseStorage::codeFlowComplete: got NULL instead of JSON!");
success = false;
+ callbackMessage = "Incorrect JSON.";
}
if (success && !json->isObject()) {
debug(9, "BaseStorage::codeFlowComplete: passed JSON is not an object!");
success = false;
+ callbackMessage = "Incorrect JSON.";
}
Common::JSONObject result;
@@ -70,6 +72,7 @@ void BaseStorage::codeFlowComplete(Networking::ErrorCallback callback, Networkin
warning("BaseStorage: bad response, no 'error' attribute passed");
debug(9, "%s", json->stringify(true).c_str());
success = false;
+ callbackMessage = "Incorrect JSON.";
}
}
@@ -87,6 +90,7 @@ void BaseStorage::codeFlowComplete(Networking::ErrorCallback callback, Networkin
warning("BaseStorage: bad response, no 'oauth' attribute passed");
debug(9, "%s", json->stringify(true).c_str());
success = false;
+ callbackMessage = "Incorrect JSON.";
}
Common::JSONObject oauth;
@@ -98,6 +102,7 @@ void BaseStorage::codeFlowComplete(Networking::ErrorCallback callback, Networkin
warning("BaseStorage: bad response, no 'access_token' or 'refresh_token' attribute passed");
debug(9, "%s", json->stringify(true).c_str());
success = false;
+ callbackMessage = "Incorrect JSON.";
}
}
diff --git a/backends/cloud/cloudmanager.cpp b/backends/cloud/cloudmanager.cpp
index cf3ccee973a..f5773f5ad29 100644
--- a/backends/cloud/cloudmanager.cpp
+++ b/backends/cloud/cloudmanager.cpp
@@ -24,6 +24,7 @@
#include "backends/cloud/dropbox/dropboxstorage.h"
#include "backends/cloud/onedrive/onedrivestorage.h"
#include "backends/cloud/googledrive/googledrivestorage.h"
+#include "common/formats/json.h"
#include "common/translation.h"
#include "common/config-manager.h"
#include "common/str.h"
@@ -307,6 +308,41 @@ void CloudManager::connectStorage(uint32 index, Networking::JsonResponse codeFlo
// thus, no memory leak happens
}
+bool CloudManager::connectStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb) {
+ Common::JSONValue *json = (Common::JSONValue *)codeFlowJson.value;
+ if (json == nullptr || !json->isObject()) {
+ return false;
+ }
+
+ Common::JSONObject result = json->asObject();
+ if (!result.contains("storage")) {
+ return false;
+ }
+
+ Common::JSONValue *storageValue = result.getVal("storage");
+ if (!storageValue->isString()) {
+ return false;
+ }
+
+ uint32 storageId = kStorageNoneId;
+ Common::String storage = storageValue->asString();
+ if (storage == "dropbox")
+ storageId = kStorageDropboxId;
+ else if (storage == "onedrive")
+ storageId = kStorageOneDriveId;
+ else if (storage == "gdrive")
+ storageId = kStorageGoogleDriveId;
+ else if (storage == "box")
+ storageId = kStorageBoxId;
+
+ if (storageId == kStorageNoneId) {
+ return false;
+ }
+
+ connectStorage(storageId, codeFlowJson, cb);
+ return true;
+}
+
void CloudManager::disconnectStorage(uint32 index) {
if (index >= kStorageTotal)
error("CloudManager::disconnectStorage: invalid index passed");
diff --git a/backends/cloud/cloudmanager.h b/backends/cloud/cloudmanager.h
index a591120d9c0..a26cda935dc 100644
--- a/backends/cloud/cloudmanager.h
+++ b/backends/cloud/cloudmanager.h
@@ -218,6 +218,17 @@ public:
*/
void connectStorage(uint32 index, Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb = nullptr);
+ /**
+ * From given JSON response, extract Storage index
+ * and replace Storage that has this index with a
+ * storage created with given JSON.
+ *
+ * @param codeFlowJson OAuth2 code flow JSON response (acquired from cloud.scummvm.org)
+ * @param cb callback to notify of success or error
+ * @returns whether Storage index was found and is correct
+ */
+ bool connectStorage(Networking::JsonResponse codeFlowJson, Networking::ErrorCallback cb = nullptr);
+
/**
* Remove Storage with a given index from config.
*
diff --git a/backends/networking/sdl_net/handlers/connectcloudhandler.cpp b/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
index fe2e01ace21..fe2f9c30287 100644
--- a/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
+++ b/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
@@ -112,11 +112,12 @@ void ConnectCloudClientHandler::handle(Client *client) {
return;
}
+ Networking::ErrorCallback callback = new Common::Callback<ConnectCloudClientHandler, Networking::ErrorResponse>(this, &ConnectCloudClientHandler::storageConnectionCallback);
Networking::JsonResponse jsonResponse(nullptr, json);
- CloudMan.connectStorage(
- Cloud::kStorageDropboxId, jsonResponse, // TODO: determine the correct id
- new Common::Callback<ConnectCloudClientHandler, Networking::ErrorResponse>(this, &ConnectCloudClientHandler::storageConnectionCallback)
- );
+ if (!CloudMan.connectStorage(jsonResponse, callback)) { // JSON doesn't have "storage" in it or it was invalid
+ delete callback;
+ handleError(*client, "Not Acceptable", 406);
+ }
}
void ConnectCloudClientHandler::storageConnectionCallback(Networking::ErrorResponse response) {
Commit: f3149a9b5d7f927cf60faedc404fe7c07b921a09
https://github.com/scummvm/scummvm/commit/f3149a9b5d7f927cf60faedc404fe7c07b921a09
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
CLOUD: Add new connection wizard
- remove Options widgets of the old wizard;
- add CloudConnectionWizard dialog;
- remove old widgets and add new ones in the layouts;
- update local webserver to allow passing a callback that needs to be called if storage was connected via /connect_cloud.
Changed paths:
A gui/cloudconnectionwizard.cpp
A gui/cloudconnectionwizard.h
backends/networking/sdl_net/handlers/connectcloudhandler.cpp
backends/networking/sdl_net/handlers/connectcloudhandler.h
backends/networking/sdl_net/localwebserver.h
gui/module.mk
gui/options.cpp
gui/options.h
gui/themes/common/highres_layout.stx
gui/themes/common/lowres_layout.stx
gui/themes/residualvm.zip
gui/themes/scummclassic.zip
gui/themes/scummclassic/classic_layout.stx
gui/themes/scummclassic/classic_layout_lowres.stx
gui/themes/scummmodern.zip
gui/themes/scummremastered.zip
diff --git a/backends/networking/sdl_net/handlers/connectcloudhandler.cpp b/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
index fe2f9c30287..dc57db64531 100644
--- a/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
+++ b/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
@@ -34,7 +34,7 @@
namespace Networking {
-ConnectCloudHandler::ConnectCloudHandler() {}
+ConnectCloudHandler::ConnectCloudHandler() : _storageConnectionCallback(nullptr) {}
ConnectCloudHandler::~ConnectCloudHandler() {}
@@ -42,6 +42,11 @@ void ConnectCloudHandler::handle(Client &client) {
client.setHandler(new ConnectCloudClientHandler(this));
}
+void ConnectCloudHandler::storageConnected(const Networking::ErrorResponse &response) const {
+ if (_storageConnectionCallback)
+ (*_storageConnectionCallback)(response);
+}
+
//
ConnectCloudClientHandler::ConnectCloudClientHandler(const ConnectCloudHandler *cloudHandler):
@@ -129,10 +134,11 @@ void ConnectCloudClientHandler::storageConnectionCallback(Networking::ErrorRespo
}
handleError(*_client, message, 200);
- return;
+ } else {
+ handleSuccess(*_client, "Storage connected.");
}
-
- handleSuccess(*_client, "Storage connected.");
+
+ _cloudHandler->storageConnected(response);
}
} // End of namespace Networking
diff --git a/backends/networking/sdl_net/handlers/connectcloudhandler.h b/backends/networking/sdl_net/handlers/connectcloudhandler.h
index 02edf1b2b5b..0740d55e0fb 100644
--- a/backends/networking/sdl_net/handlers/connectcloudhandler.h
+++ b/backends/networking/sdl_net/handlers/connectcloudhandler.h
@@ -33,12 +33,17 @@ class ConnectCloudHandler: public BaseHandler {
void handleError(Client &client, Common::String message) const;
void setJsonResponseHandler(Client &client, Common::String type, Common::String message) const;
+ Networking::ErrorCallback _storageConnectionCallback;
+
public:
ConnectCloudHandler();
virtual ~ConnectCloudHandler();
virtual void handle(Client &client);
virtual bool minimalModeSupported() { return true; }
+
+ void setStorageConnectionCallback(Networking::ErrorCallback cb) { _storageConnectionCallback = cb; }
+ void storageConnected(const Networking::ErrorResponse& response) const;
};
class ConnectCloudClientHandler : public ClientHandler {
diff --git a/backends/networking/sdl_net/localwebserver.h b/backends/networking/sdl_net/localwebserver.h
index ec52f017ebf..aa27f4245f6 100644
--- a/backends/networking/sdl_net/localwebserver.h
+++ b/backends/networking/sdl_net/localwebserver.h
@@ -109,6 +109,12 @@ public:
bool isRunning();
static uint32 getPort();
+#ifdef USE_CLOUD
+#ifdef USE_LIBCURL
+ void setStorageConnectionCallback(Networking::ErrorCallback cb) { _connectCloudHandler.setStorageConnectionCallback(cb); }
+#endif // USE_LIBCURL
+#endif // USE_CLOUD
+
static void setClientGetHandler(Client &client, Common::String response, long code = 200, const char *mimeType = nullptr);
static void setClientGetHandler(Client &client, Common::SeekableReadStream *responseStream, long code = 200, const char *mimeType = nullptr);
static void setClientRedirectHandler(Client &client, Common::String response, Common::String location, const char *mimeType = nullptr);
diff --git a/gui/cloudconnectionwizard.cpp b/gui/cloudconnectionwizard.cpp
new file mode 100644
index 00000000000..c20d29a5a05
--- /dev/null
+++ b/gui/cloudconnectionwizard.cpp
@@ -0,0 +1,656 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "gui/cloudconnectionwizard.h"
+
+#include "backends/cloud/cloudmanager.h"
+
+#ifdef USE_SDL_NET
+#include "backends/networking/sdl_net/localwebserver.h"
+#endif // USE_SDL_NET
+
+#include "common/formats/json.h"
+#include "common/memstream.h"
+#include "common/translation.h"
+
+#include "gui/browser.h"
+#include "gui/shaderbrowser-dialog.h"
+#include "gui/themebrowser.h"
+#include "gui/message.h"
+#include "gui/gui-manager.h"
+#include "gui/options.h"
+#include "gui/widget.h"
+#include "gui/widgets/edittext.h"
+#include "gui/widgets/popup.h"
+#include "gui/widgets/scrollcontainer.h"
+#include "gui/widgets/tab.h"
+#include "gui/ThemeEval.h"
+
+namespace GUI {
+
+enum {
+ kCloudConnectionWizardQuickModeButtonCmd = 'WQMb',
+ kCloudConnectionWizardManualModeButtonCmd = 'WMMb',
+ kCloudConnectionWizardBackButtonCmd = 'WSBb',
+ kCloudConnectionWizardNextButtonCmd = 'WSNb',
+ kCloudConnectionWizardRunServerButtonCmd = 'WRSb',
+ kCloudConnectionWizardOpenUrlStorageCmd = 'WOUb',
+ kCloudConnectionWizardReflowCmd = 'WRFb',
+ kCloudConnectionWizardPasteCodeCmd = 'WPCb',
+};
+
+CloudConnectionWizard::CloudConnectionWizard() :
+ Dialog("GlobalOptions_Cloud_ConnectionWizard"),
+ _currentStep(Step::NONE), _switchToSuccess(false), _switchToFailure(false),
+ _connecting(false) {
+ _backgroundType = GUI::ThemeEngine::kDialogBackgroundPlain;
+
+ _headlineLabel = new StaticTextWidget(this, "GlobalOptions_Cloud_ConnectionWizard.Headline", Common::U32String());
+ _closeButton = new ButtonWidget(this, "GlobalOptions_Cloud_ConnectionWizard.CancelButton", _("Cancel"), Common::U32String(), kCloseCmd);
+ _prevStepButton = nullptr;
+ _nextStepButton = nullptr;
+ _label0 = nullptr;
+ _label1 = nullptr;
+ _label2 = nullptr;
+ _label3 = nullptr;
+ _button0 = nullptr;
+
+ _container = nullptr;
+ _quickModeButton = nullptr;
+ _quickModeLabel = nullptr;
+ _manualModeButton = nullptr;
+ _codeBox = nullptr;
+
+ showStep(Step::MODE_SELECT);
+
+ _callback = new Common::Callback<CloudConnectionWizard, Networking::ErrorResponse>(this, &CloudConnectionWizard::storageConnectionCallback);
+}
+
+CloudConnectionWizard::~CloudConnectionWizard() {
+#ifdef USE_SDL_NET
+ LocalServer.setStorageConnectionCallback(nullptr);
+#endif // USE_SDL_NET
+
+ delete _callback;
+}
+
+void CloudConnectionWizard::showStep(Step newStep) {
+ if (newStep == _currentStep)
+ return;
+
+ switch (_currentStep) {
+ case Step::MODE_SELECT:
+ hideStepModeSelect();
+ break;
+
+ case Step::QUICK_MODE_STEP_1:
+ hideStepQuickMode1();
+ break;
+
+ case Step::QUICK_MODE_STEP_2:
+ hideStepQuickMode2();
+ break;
+
+ case Step::QUICK_MODE_SUCCESS:
+ hideStepQuickModeSuccess();
+ break;
+
+ case Step::MANUAL_MODE_STEP_1:
+ hideStepManualMode1();
+ break;
+
+ case Step::MANUAL_MODE_STEP_2:
+ hideStepManualMode2();
+ break;
+
+ case Step::MANUAL_MODE_FAILURE:
+ hideStepManualModeFailure();
+ break;
+
+ case Step::MANUAL_MODE_SUCCESS:
+ hideStepManualModeSuccess();
+ break;
+ }
+
+ _currentStep = newStep;
+
+ switch (_currentStep) {
+ case Step::MODE_SELECT:
+ showStepModeSelect();
+ break;
+
+ case Step::QUICK_MODE_STEP_1:
+ showStepQuickMode1();
+ break;
+
+ case Step::QUICK_MODE_STEP_2:
+ showStepQuickMode2();
+ break;
+
+ case Step::QUICK_MODE_SUCCESS:
+ showStepQuickModeSuccess();
+ break;
+
+ case Step::MANUAL_MODE_STEP_1:
+ showStepManualMode1();
+ break;
+
+ case Step::MANUAL_MODE_STEP_2:
+ showStepManualMode2();
+ break;
+
+ case Step::MANUAL_MODE_FAILURE:
+ showStepManualModeFailure();
+ break;
+
+ case Step::MANUAL_MODE_SUCCESS:
+ showStepManualModeSuccess();
+ break;
+ }
+
+ reflowLayout();
+ g_gui.scheduleTopDialogRedraw();
+}
+
+// mode select
+
+void CloudConnectionWizard::showStepModeSelect() {
+ _headlineLabel->setLabel(_("Cloud Connection Wizard"));
+ showContainer("ConnectionWizard_ModeSelect");
+
+ _quickModeButton = new ButtonWidget(_container, "ConnectionWizard_ModeSelect.QuickModeButton", _("Quick mode"), Common::U32String(), kCloudConnectionWizardQuickModeButtonCmd);
+ _manualModeButton = new ButtonWidget(_container, "ConnectionWizard_ModeSelect.ManualModeButton", _("Manual mode"), Common::U32String(), kCloudConnectionWizardManualModeButtonCmd);
+
+#ifdef USE_SDL_NET
+ _quickModeLabel = new StaticTextWidget(_container, "ConnectionWizard_ModeSelect.QuickModeHint", _("Will ask you to run Local Webserver"));
+#else
+ _quickModeLabel = new StaticTextWidget(_container, "ConnectionWizard_ModeSelect.QuickModeHint", _("Requires Local Webserver feature"), Common::U32String(), ThemeEngine::kFontStyleNormal);
+ _quickModeLabel->setEnabled(false);
+ _quickModeButton->setEnabled(false);
+#endif // USE_SDL_NET
+}
+
+void CloudConnectionWizard::hideStepModeSelect() {
+ hideContainer();
+ removeWidgetChecked(_quickModeButton);
+ removeWidgetChecked(_manualModeButton);
+ removeWidgetChecked(_quickModeLabel);
+}
+
+// quick mode
+
+void CloudConnectionWizard::showStepQuickMode1() {
+ _headlineLabel->setLabel(_("Quick Mode: Step 1"));
+ showContainer("ConnectionWizard_QuickModeStep1");
+ showBackButton();
+ showNextButton();
+
+ _label0 = new StaticTextWidget(_container, "ConnectionWizard_QuickModeStep1.Line1", _("In this mode, Local Webserver must be running,"));
+ _label1 = new StaticTextWidget(_container, "ConnectionWizard_QuickModeStep1.Line2", _("so your browser could forward data to ScummVM"));
+
+ _button0 = new ButtonWidget(_container, "ConnectionWizard_QuickModeStep1.RunServerButton", Common::U32String(), Common::U32String(), kCloudConnectionWizardRunServerButtonCmd);
+ _label2 = new StaticTextWidget(_container, "ConnectionWizard_QuickModeStep1.ServerInfoLabel", Common::U32String());
+
+ refreshStepQuickMode1();
+}
+
+void CloudConnectionWizard::refreshStepQuickMode1(bool displayAsStopped) {
+ bool serverIsRunning = false;
+#ifdef USE_SDL_NET
+ serverIsRunning = LocalServer.isRunning();
+#endif // USE_SDL_NET
+ if (displayAsStopped)
+ serverIsRunning = false;
+
+ if (_nextStepButton)
+ _nextStepButton->setEnabled(serverIsRunning);
+
+ if (_button0) {
+ _button0->setLabel(_(serverIsRunning ? "Stop server" : "Run server"));
+ _button0->setTooltip(_(serverIsRunning ? "Stop local webserver" : "Run local webserver"));
+ }
+
+ if (_label2) {
+ _label2->setLabel(serverIsRunning ? LocalServer.getAddress() : _("Not running"));
+ }
+}
+
+void CloudConnectionWizard::hideStepQuickMode1() {
+ hideContainer();
+ hideBackButton();
+ hideNextButton();
+ removeWidgetChecked(_label0);
+ removeWidgetChecked(_label1);
+ removeWidgetChecked(_button0);
+ removeWidgetChecked(_label2);
+}
+
+void CloudConnectionWizard::showStepQuickMode2() {
+ _headlineLabel->setLabel(_("Quick Mode: Step 2"));
+ showContainer("ConnectionWizard_QuickModeStep2");
+ showBackButton();
+
+ _label0 = new StaticTextWidget(_container, "ConnectionWizard_QuickModeStep2.Line1", _("Now, open this link in your browser:"));
+ _button0 = new ButtonWidget(_container, "ConnectionWizard_QuickModeStep2.OpenLinkButton", Common::U32String("https://cloud.scummvm.org/"), _("Open URL"), kCloudConnectionWizardOpenUrlStorageCmd);
+
+ _label1 = new StaticTextWidget(_container, "ConnectionWizard_QuickModeStep2.Line2", _("It will automatically pass the data to ScummVM,"));
+ _label2 = new StaticTextWidget(_container, "ConnectionWizard_QuickModeStep2.Line3", _("and warn you should there be any errors."));
+ _label3 = new StaticTextWidget(_container, "ConnectionWizard_QuickModeStep2.Line4", Common::U32String(), Common::U32String(), ThemeEngine::kFontStyleNormal);
+
+#ifdef USE_SDL_NET
+ _label3->setLabel(_("Local Webserver address: ") + Common::U32String(LocalServer.getAddress()));
+ _label3->setEnabled(false);
+#endif // USE_SDL_NET
+}
+
+void CloudConnectionWizard::hideStepQuickMode2() {
+ hideContainer();
+ hideBackButton();
+ removeWidgetChecked(_label0);
+ removeWidgetChecked(_button0);
+ removeWidgetChecked(_label1);
+ removeWidgetChecked(_label2);
+ removeWidgetChecked(_label3);
+}
+
+void CloudConnectionWizard::showStepQuickModeSuccess() {
+ _headlineLabel->setLabel(_("Quick Mode: Success"));
+ showContainer("ConnectionWizard_Success");
+ _closeButton->setVisible(false);
+
+ _label0 = new StaticTextWidget(_container, "ConnectionWizard_Success.Line1", _("You cloud storage has been connected!"));
+ _button0 = new ButtonWidget(this, "GlobalOptions_Cloud_ConnectionWizard.FinishButton", _("Finish"), Common::U32String(), kCloseCmd);
+}
+
+void CloudConnectionWizard::hideStepQuickModeSuccess() {
+ hideContainer();
+ _closeButton->setVisible(true);
+ removeWidgetChecked(_label0);
+ removeWidgetChecked(_button0);
+}
+
+// manual mode
+
+void CloudConnectionWizard::showStepManualMode1() {
+ _headlineLabel->setLabel(_("Manual Mode: Step 1"));
+ showContainer("ConnectionWizard_ManualModeStep1");
+ showBackButton();
+ showNextButton();
+
+ _label0 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep1.Line1", _("Open this link in your browser:"));
+ _button0 = new ButtonWidget(_container, "ConnectionWizard_ManualModeStep1.OpenLinkButton", Common::U32String("https://cloud.scummvm.org/"), _("Open URL"), kCloudConnectionWizardOpenUrlStorageCmd);
+
+ _label1 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep1.Line2", _("When it fails to pass the code to ScummVM,"));
+ _label2 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep1.Line3", _("find it on Troubleshooting section of the page,"));
+ _label3 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep1.Line4", _("and go to the next step here."));
+}
+
+void CloudConnectionWizard::hideStepManualMode1() {
+ hideContainer();
+ hideBackButton();
+ hideNextButton();
+ removeWidgetChecked(_label0);
+ removeWidgetChecked(_button0);
+ removeWidgetChecked(_label1);
+ removeWidgetChecked(_label2);
+ removeWidgetChecked(_label3);
+}
+
+void CloudConnectionWizard::showStepManualMode2() {
+ _headlineLabel->setLabel(_("Manual Mode: Step 2"));
+ showContainer("ConnectionWizard_ManualModeStep2");
+ showBackButton();
+ showNextButton();
+
+ _label0 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep2.Line1", _("Copy the code from your browser here and press Next:"));
+ _codeBox = new EditTextWidget(_container, "ConnectionWizard_ManualModeStep2.CodeBox", Common::U32String(), Common::U32String(), 0, 0, ThemeEngine::kFontStyleConsole);
+ _button0 = new ButtonWidget(_container, "ConnectionWizard_ManualModeStep2.PasteButton", _("Paste"), _("Paste code from clipboard"), kCloudConnectionWizardPasteCodeCmd);
+ _label1 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep2.Line2", Common::U32String());
+}
+
+void CloudConnectionWizard::hideStepManualMode2() {
+ hideContainer();
+ _closeButton->setEnabled(true);
+ hideBackButton();
+ hideNextButton();
+ removeWidgetChecked(_label0);
+ removeWidgetChecked(_codeBox);
+ removeWidgetChecked(_button0);
+ removeWidgetChecked(_label1);
+}
+
+void CloudConnectionWizard::showStepManualModeFailure() {
+ _headlineLabel->setLabel(_("Manual Mode: Something went wrong"));
+ showContainer("ConnectionWizard_Failure");
+ showBackButton();
+
+ _label0 = new StaticTextWidget(_container, "ConnectionWizard_Failure.Line1", _("Cloud storage was not connected."));
+ _label1 = new StaticTextWidget(_container, "ConnectionWizard_Failure.Line2", _("Make sure you copied the code correctly and try again."));
+ _label2 = new StaticTextWidget(_container, "ConnectionWizard_Failure.Line3", _("It it doesn't work, try from the beginning."));
+ _label3 = new StaticTextWidget(_container, "ConnectionWizard_Failure.Line4", _("Error message: ") + _errorMessage, Common::U32String(), ThemeEngine::kFontStyleNormal);
+ _label3->setEnabled(false);
+}
+
+void CloudConnectionWizard::hideStepManualModeFailure() {
+ hideContainer();
+ hideBackButton();
+ removeWidgetChecked(_label0);
+ removeWidgetChecked(_label1);
+ removeWidgetChecked(_label2);
+ removeWidgetChecked(_label3);
+}
+
+void CloudConnectionWizard::showStepManualModeSuccess() {
+ _headlineLabel->setLabel(_("Manual Mode: Success"));
+ showContainer("ConnectionWizard_Success");
+ _closeButton->setVisible(false);
+
+ _label0 = new StaticTextWidget(_container, "ConnectionWizard_Success.Line1", _("Your cloud storage has been connected!"));
+ _button0 = new ButtonWidget(this, "GlobalOptions_Cloud_ConnectionWizard.FinishButton", _("Finish"), Common::U32String(), kCloseCmd);
+}
+
+void CloudConnectionWizard::hideStepManualModeSuccess() {
+ hideContainer();
+ _closeButton->setVisible(true);
+ removeWidgetChecked(_label0);
+ removeWidgetChecked(_button0);
+}
+
+// utils
+
+void CloudConnectionWizard::showContainer(const Common::String &dialogName) {
+ _container = new ScrollContainerWidget(this, "GlobalOptions_Cloud_ConnectionWizard.Container", dialogName, kCloudConnectionWizardReflowCmd);
+ _container->setTarget(this);
+ _container->setBackgroundType(ThemeEngine::kWidgetBackgroundNo);
+}
+
+void CloudConnectionWizard::hideContainer() {
+ removeWidgetChecked(_container);
+}
+
+void CloudConnectionWizard::showBackButton() {
+ _prevStepButton = new ButtonWidget(this, "GlobalOptions_Cloud_ConnectionWizard.PrevButton", _("Back"), Common::U32String(), kCloudConnectionWizardBackButtonCmd);
+}
+
+void CloudConnectionWizard::hideBackButton() {
+ removeWidgetChecked(_prevStepButton);
+}
+
+void CloudConnectionWizard::showNextButton() {
+ _nextStepButton = new ButtonWidget(this, "GlobalOptions_Cloud_ConnectionWizard.NextButton", _("Next"), Common::U32String(), kCloudConnectionWizardNextButtonCmd);
+}
+
+void CloudConnectionWizard::hideNextButton() {
+ removeWidgetChecked(_nextStepButton);
+}
+
+void CloudConnectionWizard::removeWidgetChecked(ScrollContainerWidget *&widget) {
+ if (widget) {
+ removeWidget(widget);
+ widget = nullptr;
+ }
+}
+
+void CloudConnectionWizard::removeWidgetChecked(ButtonWidget *&widget) {
+ if (widget) {
+ removeWidget(widget);
+ widget = nullptr;
+ }
+}
+
+void CloudConnectionWizard::removeWidgetChecked(StaticTextWidget *&widget) {
+ if (widget) {
+ removeWidget(widget);
+ widget = nullptr;
+ }
+}
+
+void CloudConnectionWizard::removeWidgetChecked(EditTextWidget *&widget) {
+ if (widget) {
+ removeWidget(widget);
+ widget = nullptr;
+ }
+}
+
+// logic
+
+void CloudConnectionWizard::storageConnectionCallback(Networking::ErrorResponse response) {
+ if (response.failed || response.interrupted) {
+ return;
+ }
+
+ _switchToSuccess = true;
+}
+
+void CloudConnectionWizard::manualModeConnect() {
+ if (_connecting)
+ return;
+
+ if (_label1)
+ _label1->setLabel(Common::U32String());
+
+ // get the code entered
+ Common::String code = "";
+ if (_codeBox)
+ code = _codeBox->getEditString().encode();
+ if (code.size() == 0)
+ return;
+
+ // warn about other Storage working
+ if (CloudMan.isWorking()) {
+ bool cancel = true;
+
+ MessageDialog alert(_("Another Storage is working now. Do you want to interrupt it?"), _("Yes"), _("No"));
+ if (alert.runModal() == GUI::kMessageOK) {
+ if (CloudMan.isDownloading())
+ CloudMan.cancelDownload();
+ if (CloudMan.isSyncing())
+ CloudMan.cancelSync();
+
+ // I believe it still would return `true` here, but just in case
+ if (CloudMan.isWorking()) {
+ MessageDialog alert2(_("Wait until current Storage finishes up and try again."));
+ alert2.runModal();
+ } else {
+ cancel = false;
+ }
+ }
+
+ if (cancel) {
+ return;
+ }
+ }
+
+ // parse JSON and display message if failed
+ Common::MemoryWriteStreamDynamic jsonStream(DisposeAfterUse::YES);
+ jsonStream.write(code.c_str(), code.size());
+ char *contents = Common::JSON::getPreparedContents(jsonStream);
+ Common::JSONValue *json = Common::JSON::parse(contents);
+ if (json == nullptr) {
+ if (_label1)
+ _label1->setLabel(_("There is likely a mistake in the code."));
+ return;
+ }
+
+ // pass JSON to the manager
+ _connecting = true;
+ Networking::ErrorCallback callback = new Common::Callback<CloudConnectionWizard, Networking::ErrorResponse>(this, &CloudConnectionWizard::manualModeStorageConnectionCallback);
+ Networking::JsonResponse jsonResponse(nullptr, json);
+ if (!CloudMan.connectStorage(jsonResponse, callback)) { // no "storage" in JSON (or invalid one)
+ _connecting = false;
+ delete callback;
+ if (_label1)
+ _label1->setLabel(_("There is likely a mistake in the code."));
+ return;
+ }
+
+ // disable UI
+ if (_codeBox)
+ _codeBox->setEnabled(false);
+ if (_button0)
+ _button0->setEnabled(false);
+ if (_closeButton)
+ _closeButton->setEnabled(false);
+ if (_prevStepButton)
+ _prevStepButton->setEnabled(false);
+ if (_nextStepButton)
+ _nextStepButton->setEnabled(false);
+}
+
+void CloudConnectionWizard::manualModeStorageConnectionCallback(Networking::ErrorResponse response) {
+ if (response.failed || response.interrupted) {
+ if (response.failed) {
+ _errorMessage = _(response.response.c_str());
+ } else {
+ _errorMessage = _("Interrupted.");
+ }
+
+ _switchToFailure = true;
+ return;
+ }
+
+ _switchToSuccess = true;
+}
+
+// public
+
+void CloudConnectionWizard::open() {
+ Dialog::open();
+#ifdef USE_SDL_NET
+ LocalServer.setStorageConnectionCallback(_callback);
+#endif // USE_SDL_NET
+}
+
+void CloudConnectionWizard::close() {
+#ifdef USE_SDL_NET
+ LocalServer.setStorageConnectionCallback(nullptr);
+#endif // USE_SDL_NET
+ Dialog::close();
+}
+
+void CloudConnectionWizard::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kCloudConnectionWizardQuickModeButtonCmd:
+ showStep(Step::QUICK_MODE_STEP_1);
+ break;
+
+ case kCloudConnectionWizardManualModeButtonCmd:
+ showStep(Step::MANUAL_MODE_STEP_1);
+ break;
+
+ case kCloudConnectionWizardRunServerButtonCmd:
+#ifdef USE_SDL_NET
+ if (LocalServer.isRunning()) {
+ LocalServer.stopOnIdle();
+ refreshStepQuickMode1(true);
+ } else {
+ LocalServer.start();
+ refreshStepQuickMode1();
+ }
+#endif // USE_SDL_NET
+ break;
+
+ case kCloudConnectionWizardOpenUrlStorageCmd:
+ if (!g_system->openUrl("https://cloud.scummvm.org/")) {
+ MessageDialog alert(_("Failed to open URL!\nPlease navigate to this page manually."));
+ alert.runModal();
+ }
+ break;
+
+ case kCloudConnectionWizardPasteCodeCmd:
+ if (g_system->hasTextInClipboard()) {
+ Common::U32String message = g_system->getTextFromClipboard();
+ if (!message.empty()) {
+ _codeBox->setEditString(message);
+ }
+ }
+ break;
+
+ case kCloudConnectionWizardNextButtonCmd:
+ switch (_currentStep) {
+ case Step::QUICK_MODE_STEP_1:
+ showStep(Step::QUICK_MODE_STEP_2);
+ break;
+
+ case Step::MANUAL_MODE_STEP_1:
+ showStep(Step::MANUAL_MODE_STEP_2);
+ break;
+
+ case Step::MANUAL_MODE_STEP_2:
+ manualModeConnect();
+ break;
+ }
+ break;
+
+ case kCloudConnectionWizardBackButtonCmd:
+ switch (_currentStep) {
+ case Step::QUICK_MODE_STEP_1:
+ case Step::MANUAL_MODE_STEP_1:
+ showStep(Step::MODE_SELECT);
+ break;
+
+ case Step::QUICK_MODE_STEP_2:
+ showStep(Step::QUICK_MODE_STEP_1);
+ break;
+
+ case Step::MANUAL_MODE_STEP_2:
+ showStep(Step::MANUAL_MODE_STEP_1);
+ break;
+
+ case Step::MANUAL_MODE_FAILURE:
+ showStep(Step::MANUAL_MODE_STEP_2);
+ break;
+ }
+ break;
+
+ default:
+ Dialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void CloudConnectionWizard::handleTickle() {
+ if (_connecting && _currentStep == Step::MANUAL_MODE_STEP_2) {
+ bool switched = false;
+
+ if (_switchToFailure) {
+ showStep(Step::MANUAL_MODE_FAILURE);
+ switched = true;
+ } else if (_switchToSuccess) {
+ showStep(Step::MANUAL_MODE_SUCCESS);
+ switched = true;
+ }
+
+ if (switched) {
+ _switchToFailure = false;
+ _switchToSuccess = false;
+ _connecting = false;
+ }
+ }
+
+ if (_switchToSuccess) {
+ showStep(Step::QUICK_MODE_SUCCESS);
+ _switchToSuccess = false;
+ }
+
+ Dialog::handleTickle();
+}
+
+} // End of namespace GUI
diff --git a/gui/cloudconnectionwizard.h b/gui/cloudconnectionwizard.h
new file mode 100644
index 00000000000..e44b3705b08
--- /dev/null
+++ b/gui/cloudconnectionwizard.h
@@ -0,0 +1,137 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef GUI_CLOUDCONNECTIONWIZARD_H
+#define GUI_CLOUDCONNECTIONWIZARD_H
+
+#include "backends/networking/curl/request.h"
+#include "common/str.h"
+#include "common/ustr.h"
+#include "gui/dialog.h"
+
+namespace GUI {
+class ScrollContainerWidget;
+class StaticTextWidget;
+class ButtonWidget;
+class EditTextWidget;
+
+class CloudConnectionWizard : public Dialog {
+ enum class Step {
+ NONE,
+ MODE_SELECT,
+ QUICK_MODE_STEP_1,
+ QUICK_MODE_STEP_2,
+ QUICK_MODE_SUCCESS,
+ MANUAL_MODE_STEP_1,
+ MANUAL_MODE_STEP_2,
+ MANUAL_MODE_FAILURE,
+ MANUAL_MODE_SUCCESS
+ };
+
+ // wizard flow
+ Step _currentStep;
+ bool _switchToSuccess;
+ bool _switchToFailure;
+
+ // state
+ Networking::ErrorCallback _callback;
+ bool _connecting;
+ Common::U32String _errorMessage;
+
+ // common and generic widgets
+ StaticTextWidget *_headlineLabel;
+ ButtonWidget *_closeButton;
+ ButtonWidget *_prevStepButton;
+ ButtonWidget *_nextStepButton;
+ StaticTextWidget *_label0;
+ StaticTextWidget *_label1;
+ StaticTextWidget *_label2;
+ StaticTextWidget *_label3;
+ ButtonWidget *_button0;
+
+ // specific widgets
+ ScrollContainerWidget *_container;
+ ButtonWidget *_quickModeButton;
+ StaticTextWidget *_quickModeLabel;
+ ButtonWidget *_manualModeButton;
+ EditTextWidget *_codeBox;
+
+ // wizard flow
+ void showStep(Step newStep);
+
+ void showStepModeSelect();
+ void hideStepModeSelect();
+
+ void showStepQuickMode1();
+ void refreshStepQuickMode1(bool displayAsStopped = false);
+ void hideStepQuickMode1();
+
+ void showStepQuickMode2();
+ void hideStepQuickMode2();
+
+ void showStepQuickModeSuccess();
+ void hideStepQuickModeSuccess();
+
+ void showStepManualMode1();
+ void hideStepManualMode1();
+
+ void showStepManualMode2();
+ void hideStepManualMode2();
+
+ void showStepManualModeFailure();
+ void hideStepManualModeFailure();
+
+ void showStepManualModeSuccess();
+ void hideStepManualModeSuccess();
+
+ // widgets utils
+ void showContainer(const Common::String &dialogName);
+ void hideContainer();
+
+ void showBackButton();
+ void hideBackButton();
+
+ void showNextButton();
+ void hideNextButton();
+
+ void removeWidgetChecked(ScrollContainerWidget *&widget);
+ void removeWidgetChecked(ButtonWidget *&widget);
+ void removeWidgetChecked(StaticTextWidget *&widget);
+ void removeWidgetChecked(EditTextWidget *&widget);
+
+ // logic
+ void storageConnectionCallback(Networking::ErrorResponse response);
+ void manualModeConnect();
+ void manualModeStorageConnectionCallback(Networking::ErrorResponse response);
+
+public:
+ CloudConnectionWizard();
+ ~CloudConnectionWizard() override;
+
+ void open() override;
+ void close() override;
+ void handleCommand(CommandSender *sender, uint32 cmd, uint32 data) override;
+ void handleTickle() override;
+};
+
+} // End of namespace GUI
+
+#endif
diff --git a/gui/module.mk b/gui/module.mk
index 28a854cb0bb..4edf3dcd4ca 100644
--- a/gui/module.mk
+++ b/gui/module.mk
@@ -47,6 +47,7 @@ MODULE_OBJS := \
ifdef USE_CLOUD
ifdef USE_LIBCURL
MODULE_OBJS += \
+ cloudconnectionwizard.o \
downloaddialog.o \
downloadpacksdialog.o \
remotebrowser.o
diff --git a/gui/options.cpp b/gui/options.cpp
index 3c8e1b52855..2002ff989b1 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -58,6 +58,7 @@
#ifdef USE_CLOUD
#ifdef USE_LIBCURL
#include "backends/cloud/cloudmanager.h"
+#include "gui/cloudconnectionwizard.h"
#include "gui/downloaddialog.h"
#include "gui/downloadpacksdialog.h"
#endif
@@ -129,12 +130,11 @@ enum {
kDownloadStorageCmd = 'dlst',
kRunServerCmd = 'rnsv',
kCloudTabContainerReflowCmd = 'ctcr',
+ kOpenCloudConnectionWizardCmd = 'OpCW',
kServerPortClearCmd = 'spcl',
kChooseRootDirCmd = 'chrp',
kRootPathClearCmd = 'clrp',
- kConnectStorageCmd = 'Cnnt',
kOpenUrlStorageCmd = 'OpUr',
- kPasteCodeStorageCmd = 'PsCd',
kDisconnectStorageCmd = 'DcSt',
kEnableStorageCmd = 'EnSt'
};
@@ -2149,13 +2149,7 @@ GlobalOptionsDialog::GlobalOptionsDialog(LauncherDialog *launcher)
_connectingStorage = false;
_storageWizardNotConnectedHint = nullptr;
- _storageWizardOpenLinkHint = nullptr;
- _storageWizardLink = nullptr;
- _storageWizardCodeHint = nullptr;
- _storageWizardCodeBox = nullptr;
- _storageWizardPasteButton = nullptr;
_storageWizardConnectButton = nullptr;
- _storageWizardConnectionStatusHint = nullptr;
_redrawCloudTab = false;
#endif
#ifdef USE_SDL_NET
@@ -2690,9 +2684,9 @@ void GlobalOptionsDialog::addCloudControls(GuiObject *boss, const Common::String
_storagePopUp->setSelected(_selectedStorageIndex);
if (lowres)
- _storageDisabledHint = new StaticTextWidget(boss, prefix + "StorageDisabledHint", _c("4. Storage is not yet enabled. Verify that username is correct and enable it:", "lowres"));
+ _storageDisabledHint = new StaticTextWidget(boss, prefix + "StorageDisabledHint", _c("Storage is not yet enabled. Verify that username is correct and enable it:", "lowres"));
else
- _storageDisabledHint = new StaticTextWidget(boss, prefix + "StorageDisabledHint", _("4. Storage is not yet enabled. Verify that username is correct and enable it:"));
+ _storageDisabledHint = new StaticTextWidget(boss, prefix + "StorageDisabledHint", _("Storage is not yet enabled. Verify that username is correct and enable it:"));
_storageEnableButton = new ButtonWidget(boss, prefix + "StorageEnableButton", _("Enable storage"), _("Confirm you want to use this account for this storage"), kEnableStorageCmd);
_storageUsernameDesc = new StaticTextWidget(boss, prefix + "StorageUsernameDesc", _("Username:"), _("Username used by this storage"));
@@ -2722,19 +2716,10 @@ void GlobalOptionsDialog::addCloudControls(GuiObject *boss, const Common::String
_storageDisconnectButton = new ButtonWidget(boss, prefix + "DisconnectButton", _("Disconnect"), _("Stop using this storage on this device"), kDisconnectStorageCmd);
if (lowres)
- _storageWizardNotConnectedHint = new StaticTextWidget(boss, prefix + "StorageWizardNotConnectedHint", _c("This storage is not connected yet! To connect,", "lowres"));
+ _storageWizardNotConnectedHint = new StaticTextWidget(boss, prefix + "StorageWizardNotConnectedHint", _c("This storage is not connected yet!", "lowres"));
else
- _storageWizardNotConnectedHint = new StaticTextWidget(boss, prefix + "StorageWizardNotConnectedHint", _("This storage is not connected yet! To connect,"));
- _storageWizardOpenLinkHint = new StaticTextWidget(boss, prefix + "StorageWizardOpenLinkHint", _("1. Open this link:"));
- _storageWizardLink = new ButtonWidget(boss, prefix + "StorageWizardLink", Common::U32String("https://cloud.scummvm.org/"), _("Open URL"), kOpenUrlStorageCmd);
- if (lowres)
- _storageWizardCodeHint = new StaticTextWidget(boss, prefix + "StorageWizardCodeHint", _c("2. Get the code and enter it here:", "lowres"));
- else
- _storageWizardCodeHint = new StaticTextWidget(boss, prefix + "StorageWizardCodeHint", _("2. Get the code and enter it here:"));
- _storageWizardCodeBox = new EditTextWidget(boss, prefix + "StorageWizardCodeBox", Common::U32String(), Common::U32String(), 0, 0, ThemeEngine::kFontStyleConsole);
- _storageWizardPasteButton = new ButtonWidget(boss, prefix + "StorageWizardPasteButton", _("Paste"), _("Paste code from clipboard"), kPasteCodeStorageCmd);
- _storageWizardConnectButton = new ButtonWidget(boss, prefix + "StorageWizardConnectButton", _("3. Connect"), _("Connect your cloud storage account"), kConnectStorageCmd);
- _storageWizardConnectionStatusHint = new StaticTextWidget(boss, prefix + "StorageWizardConnectionStatusHint", Common::U32String("..."));
+ _storageWizardNotConnectedHint = new StaticTextWidget(boss, prefix + "StorageWizardNotConnectedHint", _("This storage is not connected yet!"));
+ _storageWizardConnectButton = new ButtonWidget(boss, prefix + "StorageWizardConnectButton", _("Connect"), _("Connect your cloud storage account"), kOpenCloudConnectionWizardCmd);
setupCloudTab();
}
@@ -3320,9 +3305,14 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
setupCloudTab();
break;
}
+ case kOpenCloudConnectionWizardCmd: {
+ CloudConnectionWizard wizard;
+ wizard.runModal();
+ setupCloudTab();
+ reflowLayout();
+ break;
+ }
case kStoragePopUpCmd: {
- if (_storageWizardCodeBox)
- _storageWizardCodeBox->setEditString(Common::U32String());
// update container's scrollbar
reflowLayout();
break;
@@ -3370,61 +3360,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
}
break;
}
- case kPasteCodeStorageCmd: {
- if (g_system->hasTextInClipboard()) {
- Common::U32String message = g_system->getTextFromClipboard();
- if (!message.empty()) {
- _storageWizardCodeBox->setEditString(message);
- _redrawCloudTab = true;
- }
- }
- break;
- }
- case kConnectStorageCmd: {
- Common::String code = "";
- if (_storageWizardCodeBox)
- code = _storageWizardCodeBox->getEditString().encode();
- if (code.size() == 0)
- return;
-
- if (CloudMan.isWorking()) {
- bool cancel = true;
-
- MessageDialog alert(_("Another Storage is working now. Do you want to interrupt it?"), _("Yes"), _("No"));
- if (alert.runModal() == GUI::kMessageOK) {
- if (CloudMan.isDownloading())
- CloudMan.cancelDownload();
- if (CloudMan.isSyncing())
- CloudMan.cancelSync();
-
- // I believe it still would return `true` here, but just in case
- if (CloudMan.isWorking()) {
- MessageDialog alert2(_("Wait until current Storage finishes up and try again."));
- alert2.runModal();
- } else {
- cancel = false;
- }
- }
-
- if (cancel) {
- return;
- }
- }
-
- if (_storageWizardConnectionStatusHint)
- _storageWizardConnectionStatusHint->setLabel(_("Connecting..."));
- CloudMan.connectStorage(
- _selectedStorageIndex, code,
- new Common::Callback<GlobalOptionsDialog, Networking::ErrorResponse>(this, &GlobalOptionsDialog::storageConnectionCallback)
- );
- _connectingStorage = true;
- _redrawCloudTab = true;
- break;
- }
case kDisconnectStorageCmd: {
- if (_storageWizardCodeBox)
- _storageWizardCodeBox->setEditString(Common::U32String());
-
if (_selectedStorageIndex == CloudMan.getStorageIndex() && CloudMan.isWorking()) {
bool cancel = true;
@@ -3682,28 +3618,10 @@ void GlobalOptionsDialog::setupCloudTab() {
shown = (!shownConnectedInfo && shown);
bool wizardEnabled = !_connectingStorage;
if (_storageWizardNotConnectedHint) _storageWizardNotConnectedHint->setVisible(shown);
- if (_storageWizardOpenLinkHint) _storageWizardOpenLinkHint->setVisible(shown);
- if (_storageWizardLink) {
- _storageWizardLink->setVisible(shown);
- _storageWizardLink->setEnabled(g_system->hasFeature(OSystem::kFeatureOpenUrl) && wizardEnabled);
- }
- if (_storageWizardCodeHint) _storageWizardCodeHint->setVisible(shown);
- if (_storageWizardCodeBox) {
- _storageWizardCodeBox->setVisible(shown);
- _storageWizardCodeBox->setEnabled(wizardEnabled);
- }
- if (_storageWizardPasteButton) {
- _storageWizardPasteButton->setVisible(shown && g_system->hasFeature(OSystem::kFeatureClipboardSupport));
- _storageWizardPasteButton->setEnabled(wizardEnabled);
- }
if (_storageWizardConnectButton) {
_storageWizardConnectButton->setVisible(shown);
_storageWizardConnectButton->setEnabled(wizardEnabled);
}
- if (_storageWizardConnectionStatusHint) {
- _storageWizardConnectionStatusHint->setVisible(shown && _storageWizardConnectionStatusHint->getLabel() != "...");
- _storageWizardConnectionStatusHint->setEnabled(wizardEnabled);
- }
if (!shownConnectedInfo) {
if (!g_gui.xmlEval()->getWidgetData("GlobalOptions_Cloud_Container.StorageDisabledHint", x, y, w, h))
@@ -3714,13 +3632,7 @@ void GlobalOptionsDialog::setupCloudTab() {
shiftUp = y - shiftUp;
shiftWidget(_storageWizardNotConnectedHint, "GlobalOptions_Cloud_Container.StorageWizardNotConnectedHint", 0, -shiftUp);
- shiftWidget(_storageWizardOpenLinkHint, "GlobalOptions_Cloud_Container.StorageWizardOpenLinkHint", 0, -shiftUp);
- shiftWidget(_storageWizardLink, "GlobalOptions_Cloud_Container.StorageWizardLink", 0, -shiftUp);
- shiftWidget(_storageWizardCodeHint, "GlobalOptions_Cloud_Container.StorageWizardCodeHint", 0, -shiftUp);
- shiftWidget(_storageWizardCodeBox, "GlobalOptions_Cloud_Container.StorageWizardCodeBox", 0, -shiftUp);
- shiftWidget(_storageWizardPasteButton, "GlobalOptions_Cloud_Container.StorageWizardPasteButton", 0, -shiftUp);
shiftWidget(_storageWizardConnectButton, "GlobalOptions_Cloud_Container.StorageWizardConnectButton", 0, -shiftUp);
- shiftWidget(_storageWizardConnectionStatusHint, "GlobalOptions_Cloud_Container.StorageWizardConnectionStatusHint", 0, -shiftUp);
}
}
@@ -3791,25 +3703,6 @@ void GlobalOptionsDialog::reflowNetworkTabLayout() {
#endif // USE_SDL_NET
#ifdef USE_LIBCURL
-void GlobalOptionsDialog::storageConnectionCallback(Networking::ErrorResponse response) {
- Common::U32String message("...");
- if (!response.failed && !response.interrupted) {
- // success
- g_system->displayMessageOnOSD(_("Storage connected."));
- } else {
- message = _("Failed to connect storage.");
- if (response.failed) {
- message = _("Failed to connect storage: ") + _(response.response.c_str());
- }
- }
-
- if (_storageWizardConnectionStatusHint)
- _storageWizardConnectionStatusHint->setLabel(message);
-
- _redrawCloudTab = true;
- _connectingStorage = false;
-}
-
void GlobalOptionsDialog::storageSavesSyncedCallback(Cloud::Storage::BoolResponse response) {
_redrawCloudTab = true;
}
diff --git a/gui/options.h b/gui/options.h
index b1e7ccf3856..e195e3e3482 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -350,20 +350,13 @@ protected:
bool _connectingStorage;
StaticTextWidget *_storageWizardNotConnectedHint;
- StaticTextWidget *_storageWizardOpenLinkHint;
- StaticTextWidget *_storageWizardLink;
- StaticTextWidget *_storageWizardCodeHint;
- EditTextWidget *_storageWizardCodeBox;
- ButtonWidget *_storageWizardPasteButton;
- ButtonWidget *_storageWizardConnectButton;
- StaticTextWidget *_storageWizardConnectionStatusHint;
+ ButtonWidget *_storageWizardConnectButton;
bool _redrawCloudTab;
void addCloudControls(GuiObject *boss, const Common::String &prefix, bool lowres);
void setupCloudTab();
void shiftWidget(Widget *widget, const char *widgetName, int32 xOffset, int32 yOffset);
- void storageConnectionCallback(Networking::ErrorResponse response);
void storageSavesSyncedCallback(Cloud::Storage::BoolResponse response);
void storageErrorCallback(Networking::ErrorResponse response);
#endif // USE_LIBCURL
diff --git a/gui/themes/common/highres_layout.stx b/gui/themes/common/highres_layout.stx
index 065c39c38d2..10b53ae11e9 100644
--- a/gui/themes/common/highres_layout.stx
+++ b/gui/themes/common/highres_layout.stx
@@ -1129,45 +1129,10 @@
height = 'Globals.Line.Height'
/>
</layout>
- <layout type = 'horizontal' padding = '0, 0, -4, 0' spacing = '10' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, 2, 0' spacing = '4'>
- <widget name = 'StorageWizardOpenLinkHint'
- width = '96'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, 1, 0' spacing = '4'>
- <widget name = 'StorageWizardLink'
- width = '192'
- height = 'Globals.Line.Height'
- />
- </layout>
- </layout>
- <layout type = 'horizontal' padding = '0, 0, -2, 0' spacing = '10' align = 'center'>
- <widget name = 'StorageWizardCodeHint'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, -2, 0' spacing = '2'>
- <widget name = 'StorageWizardCodeBox'
- width = '108'
- height = '24'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, -2, 0' spacing = '2'>
- <widget name = 'StorageWizardPasteButton'
- type = 'Button'
- />
- </layout>
- </layout>
<layout type = 'horizontal' padding = '0, 0, -2, 0' spacing = '10' align = 'center'>
<widget name = 'StorageWizardConnectButton'
type = 'Button'
/>
- <widget name = 'StorageWizardConnectionStatusHint'
- height = 'Globals.Line.Height'
- />
</layout>
</layout>
</dialog>
@@ -1292,95 +1257,182 @@
</dialog>
<dialog name = 'GlobalOptions_Cloud_ConnectionWizard' overlays = 'Dialog.GlobalOptions' shading = 'dim'>
- <layout type = 'vertical' padding = '0, 0, 0, 0'>
+ <layout type = 'vertical' padding = '16, 16, 16, 8' spacing = '0'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+
+ <space size = '16' />
+
<widget name = 'Container'/>
+ <space />
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '12'>
+ <space />
+ <widget name = 'CancelButton'
+ type = 'Button'
+ />
+ <widget name = 'PrevButton'
+ type = 'Button'
+ />
+ <widget name = 'NextButton'
+ type = 'Button'
+ />
+ <widget name = 'FinishButton'
+ type = 'Button'
+ />
+ </layout>
</layout>
</dialog>
- <dialog name = 'GlobalOptions_Cloud_ConnectionWizard_Container' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container'>
- <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '0'>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '6'>
- <widget name = 'Picture'
- width = '109'
- height = '109'
- />
- <widget name = 'OpenUrlButton'
- type = 'Button'
- />
- <widget name = 'PasteCodeButton'
- type = 'Button'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '6'>
- <widget name = 'Headline'
- height = 'Globals.Line.Height'
- />
- <space size = '4' />
- <widget name = 'NavigateLine'
- height = 'Globals.Line.Height'
- />
- <widget name = 'URLLine'
- height = 'Globals.Line.Height'
- />
- <space size = '4' />
- <widget name = 'ReturnLine1'
- height = 'Globals.Line.Height'
- />
- <widget name = 'ReturnLine2'
- height = 'Globals.Line.Height'
- />
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CodeBox1'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox2'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox3'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox4'
- width = '70'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CodeBox5'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox6'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox7'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox8'
- width = '70'
- height = 'Globals.Line.Height'
- />
- </layout>
- <widget name = 'MessageLine'
- height = 'Globals.Line.Height'
- />
- <space size = '6' />
- </layout>
+ <dialog name = 'ConnectionWizard_ModeSelect' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '0' align = 'center'>
+ <widget name = 'QuickModeButton'
+ type = 'Button'
+ />
+ <space size = '12' />
+ <widget name = 'QuickModeHint'
+ height = 'Globals.Line.Height'
+ />
</layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
- <widget name = 'CancelButton'
+
+ <layout type = 'horizontal' padding = '0, 0, 8, 0' spacing = '0' align = 'center'>
+ <widget name = 'ManualModeButton'
type = 'Button'
/>
- <space />
- <widget name = 'ConnectButton'
+ </layout>
+
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_QuickModeStep1' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <layout type = 'vertical' padding = '0, 0, 0, 16' spacing = '0' align = 'center'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '0' align = 'center'>
+ <widget name = 'RunServerButton'
type = 'Button'
/>
+ <space size = '12' />
+ <widget name = 'ServerInfoLabel'
+ height = 'Globals.Line.Height'
+ />
</layout>
+
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_QuickModeStep2' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <layout type = 'vertical' padding = '0, 0, 0, 16' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+ <widget name = 'OpenLinkButton'
+ width = '192'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+
+ <layout type = 'vertical' padding = '0, 0, 0, 12' spacing = '0' align = 'center'>
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_ManualModeStep1' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'OpenLinkButton'
+ width = '192'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '16' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_ManualModeStep2' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'CodeBox'
+ height = '24'
+ />
+ <space size = '4' />
+
+ <widget name = 'PasteButton'
+ height = '24'
+ />
+ <space size = '8' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_Failure' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '16' />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_Success' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
</layout>
</dialog>
diff --git a/gui/themes/common/lowres_layout.stx b/gui/themes/common/lowres_layout.stx
index 61dbb31368f..8be4441b29f 100644
--- a/gui/themes/common/lowres_layout.stx
+++ b/gui/themes/common/lowres_layout.stx
@@ -995,45 +995,10 @@
height = 'Globals.Line.Height'
/>
</layout>
- <layout type = 'horizontal' padding = '0, 0, -3, 0' spacing = '6' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, 1, 0' spacing = '2'>
- <widget name = 'StorageWizardOpenLinkHint'
- width = '90'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, 1, 0' spacing = '4'>
- <widget name = 'StorageWizardLink'
- width = '150'
- height = 'Globals.Line.Height'
- />
- </layout>
- </layout>
- <layout type = 'horizontal' padding = '0, 0, -2, 0' spacing = '6' align = 'center'>
- <widget name = 'StorageWizardCodeHint'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, -2, 0' spacing = '2'>
- <widget name = 'StorageWizardCodeBox'
- width = '72'
- height = '16'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, -2, 0' spacing = '2'>
- <widget name = 'StorageWizardPasteButton'
- type = 'Button'
- />
- </layout>
- </layout>
<layout type = 'horizontal' padding = '0, 0, -2, 0' spacing = '6' align = 'center'>
<widget name = 'StorageWizardConnectButton'
type = 'Button'
/>
- <widget name = 'StorageWizardConnectionStatusHint'
- height = 'Globals.Line.Height'
- />
</layout>
</layout>
</dialog>
@@ -1160,93 +1125,179 @@
</dialog>
<dialog name = 'GlobalOptions_Cloud_ConnectionWizard' overlays = 'Dialog.GlobalOptions' shading = 'dim'>
- <layout type = 'vertical' padding = '0, 0, 0, 0'>
+ <layout type = 'vertical' padding = '8, 8, 8, 4' spacing = '0'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+
<widget name = 'Container'/>
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6'>
+ <space />
+ <widget name = 'CancelButton'
+ type = 'Button'
+ />
+ <widget name = 'PrevButton'
+ type = 'Button'
+ />
+ <widget name = 'NextButton'
+ type = 'Button'
+ />
+ <widget name = 'FinishButton'
+ type = 'Button'
+ />
+ </layout>
</layout>
</dialog>
- <dialog name = 'GlobalOptions_Cloud_ConnectionWizard_Container' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container'>
- <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
- <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '4'>
- <widget name = 'Headline'
- height = 'Globals.Line.Height'
- />
- <space size = '2' />
- <widget name = 'NavigateLine'
- height = 'Globals.Line.Height'
+ <dialog name = 'ConnectionWizard_ModeSelect' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '0' align = 'center'>
+ <widget name = 'QuickModeButton'
+ type = 'Button'
/>
- <widget name = 'URLLine'
+ <space size = '6' />
+ <widget name = 'QuickModeHint'
height = 'Globals.Line.Height'
/>
- <space size = '2' />
- <widget name = 'ReturnLine1'
- height = 'Globals.Line.Height'
+ </layout>
+
+ <layout type = 'horizontal' padding = '0, 0, 4, 0' spacing = '0' align = 'center'>
+ <widget name = 'ManualModeButton'
+ type = 'Button'
/>
- <widget name = 'ReturnLine2'
- height = 'Globals.Line.Height'
+ </layout>
+
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_QuickModeStep1' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '0' align = 'center'>
+ <widget name = 'RunServerButton'
+ type = 'Button'
/>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CodeBox1'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox2'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox3'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox4'
- width = '60'
- height = '16'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CodeBox5'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox6'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox7'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox8'
- width = '60'
- height = '16'
- />
- </layout>
- <widget name = 'MessageLine'
+ <space size = '6' />
+ <widget name = 'ServerInfoLabel'
height = 'Globals.Line.Height'
/>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'OpenUrlButton'
- type = 'Button'
- />
- <widget name = 'PasteCodeButton'
- type = 'Button'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CancelButton'
- type = 'Button'
- />
- <space />
- <widget name = 'ConnectButton'
- type = 'Button'
- />
- </layout>
- <space size = '6' />
- <widget name = 'Picture' width = '1' height = '1' />
</layout>
</layout>
</dialog>
+ <dialog name = 'ConnectionWizard_QuickModeStep2' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'OpenLinkButton'
+ width = '160'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_ManualModeStep1' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'OpenLinkButton'
+ width = '160'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_ManualModeStep2' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'CodeBox'
+ height = '16'
+ />
+ <space size = '4' />
+
+ <widget name = 'PasteButton'
+ height = '16'
+ />
+ <space size = '8' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_Failure' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_Success' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
<dialog name='GlobalOptions_Accessibility' overlays='Dialog.GlobalOptions.TabWidget'>
<layout type='vertical' padding='16,16,16,16' spacing='16'>
<widget name='TTSCheckbox'
diff --git a/gui/themes/residualvm.zip b/gui/themes/residualvm.zip
index 57d896bc885..13ffeaf0201 100644
Binary files a/gui/themes/residualvm.zip and b/gui/themes/residualvm.zip differ
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 2665c98afdd..dc24cb45761 100644
Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index eac32d2102e..a3934aa47a2 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -897,45 +897,10 @@
height = 'Globals.Line.Height'
/>
</layout>
- <layout type = 'horizontal' padding = '0, 0, -2, 0' spacing = '10' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, 2, 0' spacing = '4'>
- <widget name = 'StorageWizardOpenLinkHint'
- width = '106'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, 1, 0' spacing = '4'>
- <widget name = 'StorageWizardLink'
- width = '192'
- height = 'Globals.Line.Height'
- />
- </layout>
- </layout>
- <layout type = 'horizontal' padding = '0, 0, -2, 0' spacing = '10' align = 'center'>
- <widget name = 'StorageWizardCodeHint'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, -2, 0' spacing = '2'>
- <widget name = 'StorageWizardCodeBox'
- width = '108'
- height = '24'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, -2, 0' spacing = '2'>
- <widget name = 'StorageWizardPasteButton'
- type = 'Button'
- />
- </layout>
- </layout>
<layout type = 'horizontal' padding = '0, 0, -2, 0' spacing = '10' align = 'center'>
<widget name = 'StorageWizardConnectButton'
type = 'Button'
/>
- <widget name = 'StorageWizardConnectionStatusHint'
- height = 'Globals.Line.Height'
- />
</layout>
</layout>
</dialog>
@@ -1060,95 +1025,182 @@
</dialog>
<dialog name = 'GlobalOptions_Cloud_ConnectionWizard' overlays = 'Dialog.GlobalOptions' shading = 'dim'>
- <layout type = 'vertical' padding = '0, 0, 0, 0'>
+ <layout type = 'vertical' padding = '16, 16, 16, 8' spacing = '0'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+
+ <space size = '16' />
+
<widget name = 'Container'/>
+ <space />
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '12'>
+ <space />
+ <widget name = 'CancelButton'
+ type = 'Button'
+ />
+ <widget name = 'PrevButton'
+ type = 'Button'
+ />
+ <widget name = 'NextButton'
+ type = 'Button'
+ />
+ <widget name = 'FinishButton'
+ type = 'Button'
+ />
+ </layout>
</layout>
</dialog>
- <dialog name = 'GlobalOptions_Cloud_ConnectionWizard_Container' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container'>
- <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '0'>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '6'>
- <widget name = 'Picture'
- width = '109'
- height = '109'
- />
- <widget name = 'OpenUrlButton'
- type = 'Button'
- />
- <widget name = 'PasteCodeButton'
- type = 'Button'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '6'>
- <widget name = 'Headline'
- height = 'Globals.Line.Height'
- />
- <space size = '4' />
- <widget name = 'NavigateLine'
- height = 'Globals.Line.Height'
- />
- <widget name = 'URLLine'
- height = 'Globals.Line.Height'
- />
- <space size = '4' />
- <widget name = 'ReturnLine1'
- height = 'Globals.Line.Height'
- />
- <widget name = 'ReturnLine2'
- height = 'Globals.Line.Height'
- />
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CodeBox1'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox2'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox3'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox4'
- width = '70'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CodeBox5'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox6'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox7'
- width = '70'
- height = 'Globals.Line.Height'
- />
- <widget name = 'CodeBox8'
- width = '70'
- height = 'Globals.Line.Height'
- />
- </layout>
- <widget name = 'MessageLine'
- height = 'Globals.Line.Height'
- />
- <space size = '6' />
- </layout>
+ <dialog name = 'ConnectionWizard_ModeSelect' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '0' align = 'center'>
+ <widget name = 'QuickModeButton'
+ type = 'Button'
+ />
+ <space size = '12' />
+ <widget name = 'QuickModeHint'
+ height = 'Globals.Line.Height'
+ />
</layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
- <widget name = 'CancelButton'
+
+ <layout type = 'horizontal' padding = '0, 0, 8, 0' spacing = '0' align = 'center'>
+ <widget name = 'ManualModeButton'
type = 'Button'
/>
- <space />
- <widget name = 'ConnectButton'
+ </layout>
+
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_QuickModeStep1' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <layout type = 'vertical' padding = '0, 0, 0, 16' spacing = '0' align = 'center'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '0' align = 'center'>
+ <widget name = 'RunServerButton'
type = 'Button'
/>
+ <space size = '12' />
+ <widget name = 'ServerInfoLabel'
+ height = 'Globals.Line.Height'
+ />
</layout>
+
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_QuickModeStep2' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <layout type = 'vertical' padding = '0, 0, 0, 16' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+ <widget name = 'OpenLinkButton'
+ width = '192'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+
+ <layout type = 'vertical' padding = '0, 0, 0, 12' spacing = '0' align = 'center'>
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_ManualModeStep1' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'OpenLinkButton'
+ width = '192'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '16' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_ManualModeStep2' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'CodeBox'
+ height = '24'
+ />
+ <space size = '4' />
+
+ <widget name = 'PasteButton'
+ height = '24'
+ />
+ <space size = '8' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_Failure' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '16' />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_Success' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
</layout>
</dialog>
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index fd8150c97aa..0d47f07848a 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -917,45 +917,10 @@
height = 'Globals.Line.Height'
/>
</layout>
- <layout type = 'horizontal' padding = '0, 0, -3, 0' spacing = '6' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, 1, 0' spacing = '2'>
- <widget name = 'StorageWizardOpenLinkHint'
- width = '90'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, 1, 0' spacing = '4'>
- <widget name = 'StorageWizardLink'
- width = '150'
- height = 'Globals.Line.Height'
- />
- </layout>
- </layout>
- <layout type = 'horizontal' padding = '0, 0, -2, 0' spacing = '6' align = 'center'>
- <widget name = 'StorageWizardCodeHint'
- height = 'Globals.Line.Height'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
- <layout type = 'vertical' padding = '0, 0, -2, 0' spacing = '2'>
- <widget name = 'StorageWizardCodeBox'
- width = '72'
- height = '16'
- />
- </layout>
- <layout type = 'vertical' padding = '0, 0, -2, 0' spacing = '2'>
- <widget name = 'StorageWizardPasteButton'
- type = 'Button'
- />
- </layout>
- </layout>
<layout type = 'horizontal' padding = '0, 0, -2, 0' spacing = '6' align = 'center'>
<widget name = 'StorageWizardConnectButton'
type = 'Button'
/>
- <widget name = 'StorageWizardConnectionStatusHint'
- height = 'Globals.Line.Height'
- />
</layout>
</layout>
</dialog>
@@ -1082,92 +1047,179 @@
</dialog>
<dialog name = 'GlobalOptions_Cloud_ConnectionWizard' overlays = 'Dialog.GlobalOptions' shading = 'dim'>
- <layout type = 'vertical' padding = '0, 0, 0, 0'>
+ <layout type = 'vertical' padding = '8, 8, 8, 4' spacing = '0'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+
<widget name = 'Container'/>
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6'>
+ <space />
+ <widget name = 'CancelButton'
+ type = 'Button'
+ />
+ <widget name = 'PrevButton'
+ type = 'Button'
+ />
+ <widget name = 'NextButton'
+ type = 'Button'
+ />
+ <widget name = 'FinishButton'
+ type = 'Button'
+ />
+ </layout>
</layout>
</dialog>
- <dialog name = 'GlobalOptions_Cloud_ConnectionWizard_Container' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container'>
- <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
- <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '4'>
- <widget name = 'Headline'
- height = 'Globals.Line.Height'
- />
- <space size = '2' />
- <widget name = 'NavigateLine'
- height = 'Globals.Line.Height'
+ <dialog name = 'ConnectionWizard_ModeSelect' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '0' align = 'center'>
+ <widget name = 'QuickModeButton'
+ type = 'Button'
/>
- <widget name = 'URLLine'
+ <space size = '6' />
+ <widget name = 'QuickModeHint'
height = 'Globals.Line.Height'
/>
- <space size = '2' />
- <widget name = 'ReturnLine1'
- height = 'Globals.Line.Height'
+ </layout>
+
+ <layout type = 'horizontal' padding = '0, 0, 4, 0' spacing = '0' align = 'center'>
+ <widget name = 'ManualModeButton'
+ type = 'Button'
/>
- <widget name = 'ReturnLine2'
- height = 'Globals.Line.Height'
+ </layout>
+
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_QuickModeStep1' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '0' align = 'center'>
+ <widget name = 'RunServerButton'
+ type = 'Button'
/>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CodeBox1'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox2'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox3'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox4'
- width = '60'
- height = '16'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CodeBox5'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox6'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox7'
- width = '60'
- height = '16'
- />
- <widget name = 'CodeBox8'
- width = '60'
- height = '16'
- />
- </layout>
- <widget name = 'MessageLine'
+ <space size = '6' />
+ <widget name = 'ServerInfoLabel'
height = 'Globals.Line.Height'
/>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'OpenUrlButton'
- type = 'Button'
- />
- <widget name = 'PasteCodeButton'
- type = 'Button'
- />
- </layout>
- <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '4' align = 'center'>
- <widget name = 'CancelButton'
- type = 'Button'
- />
- <space />
- <widget name = 'ConnectButton'
- type = 'Button'
- />
- </layout>
- <space size = '6' />
- <widget name = 'Picture' width = '1' height = '1' />
</layout>
</layout>
</dialog>
+
+ <dialog name = 'ConnectionWizard_QuickModeStep2' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'OpenLinkButton'
+ width = '160'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_ManualModeStep1' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'OpenLinkButton'
+ width = '160'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_ManualModeStep2' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '4' />
+
+ <widget name = 'CodeBox'
+ height = '16'
+ />
+ <space size = '4' />
+
+ <widget name = 'PasteButton'
+ height = '16'
+ />
+ <space size = '8' />
+
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_Failure' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line2'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Line3'
+ height = 'Globals.Line.Height'
+ />
+ <space size = '8' />
+ <widget name = 'Line4'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ConnectionWizard_Success' overlays = 'GlobalOptions_Cloud_ConnectionWizard.Container' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '0'>
+ <widget name = 'Line1'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </dialog>
+
<dialog name='GlobalOptions_Accessibility' overlays='Dialog.GlobalOptions.TabWidget'>
<layout type='vertical' padding='16,16,16,16' spacing='16'>
<widget name='TTSCheckbox'
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index a39d6f8d129..d8f3b8d4142 100644
Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ
diff --git a/gui/themes/scummremastered.zip b/gui/themes/scummremastered.zip
index 4c4a2bba5d7..5085320ebcb 100644
Binary files a/gui/themes/scummremastered.zip and b/gui/themes/scummremastered.zip differ
Commit: 538303e408eae551c0a049f4c4844d4131ed7f25
https://github.com/scummvm/scummvm/commit/538303e408eae551c0a049f4c4844d4131ed7f25
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
GUI: Fix CloudConnectionWizard warnings
Changed paths:
gui/cloudconnectionwizard.cpp
diff --git a/gui/cloudconnectionwizard.cpp b/gui/cloudconnectionwizard.cpp
index c20d29a5a05..675af2ad93b 100644
--- a/gui/cloudconnectionwizard.cpp
+++ b/gui/cloudconnectionwizard.cpp
@@ -97,6 +97,9 @@ void CloudConnectionWizard::showStep(Step newStep) {
return;
switch (_currentStep) {
+ case Step::NONE:
+ break;
+
case Step::MODE_SELECT:
hideStepModeSelect();
break;
@@ -133,6 +136,9 @@ void CloudConnectionWizard::showStep(Step newStep) {
_currentStep = newStep;
switch (_currentStep) {
+ case Step::NONE:
+ break;
+
case Step::MODE_SELECT:
showStepModeSelect();
break;
@@ -228,8 +234,9 @@ void CloudConnectionWizard::refreshStepQuickMode1(bool displayAsStopped) {
_button0->setTooltip(_(serverIsRunning ? "Stop local webserver" : "Run local webserver"));
}
- if (_label2) {
- _label2->setLabel(serverIsRunning ? LocalServer.getAddress() : _("Not running"));
+ if (_label2) {
+ Common::U32String address = LocalServer.getAddress();
+ _label2->setLabel(serverIsRunning ? address : _("Not running"));
}
}
@@ -597,6 +604,9 @@ void CloudConnectionWizard::handleCommand(CommandSender *sender, uint32 cmd, uin
case Step::MANUAL_MODE_STEP_2:
manualModeConnect();
break;
+
+ default:
+ break;
}
break;
@@ -618,6 +628,9 @@ void CloudConnectionWizard::handleCommand(CommandSender *sender, uint32 cmd, uin
case Step::MANUAL_MODE_FAILURE:
showStep(Step::MANUAL_MODE_STEP_2);
break;
+
+ default:
+ break;
}
break;
Commit: 67580ee293f927b479a4eeb44e938774622a3b0d
https://github.com/scummvm/scummvm/commit/67580ee293f927b479a4eeb44e938774622a3b0d
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
GUI: Regenerate themes .zips
Changed paths:
gui/themes/residualvm.zip
gui/themes/scummclassic.zip
gui/themes/scummmodern.zip
gui/themes/scummremastered.zip
diff --git a/gui/themes/residualvm.zip b/gui/themes/residualvm.zip
index 13ffeaf0201..563e44f721f 100644
Binary files a/gui/themes/residualvm.zip and b/gui/themes/residualvm.zip differ
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index dc24cb45761..4d335a54eb5 100644
Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index d8f3b8d4142..d9c57eaee2b 100644
Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ
diff --git a/gui/themes/scummremastered.zip b/gui/themes/scummremastered.zip
index 5085320ebcb..fc5b4fe487a 100644
Binary files a/gui/themes/scummremastered.zip and b/gui/themes/scummremastered.zip differ
Commit: cc38b31ae7ce4b7280691214a2290a999bbd16ce
https://github.com/scummvm/scummvm/commit/cc38b31ae7ce4b7280691214a2290a999bbd16ce
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
CLOUD: Janitorial
- rename JSON::getPreparedContents() to JSON::untaintContents();
- minor changes to ConnectCloudClientHandler and CloudConnectionWizard.
Changed paths:
backends/networking/curl/curljsonrequest.cpp
backends/networking/sdl_net/handlers/connectcloudhandler.cpp
backends/networking/sdl_net/handlers/connectcloudhandler.h
common/formats/json.cpp
common/formats/json.h
gui/cloudconnectionwizard.cpp
diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp
index 9ead14e8b4b..fb62d07d094 100644
--- a/backends/networking/curl/curljsonrequest.cpp
+++ b/backends/networking/curl/curljsonrequest.cpp
@@ -49,7 +49,7 @@ void CurlJsonRequest::handle() {
warning("CurlJsonRequest: unable to write all the bytes into MemoryWriteStreamDynamic");
if (_stream->eos()) {
- char *contents = Common::JSON::getPreparedContents(_contentsStream);
+ char *contents = Common::JSON::untaintContents(_contentsStream);
Common::JSONValue *json = Common::JSON::parse(contents);
if (json) {
finishJson(json); //it's JSON even if's not 200 OK? That's fine!..
diff --git a/backends/networking/sdl_net/handlers/connectcloudhandler.cpp b/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
index dc57db64531..d457e100233 100644
--- a/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
+++ b/backends/networking/sdl_net/handlers/connectcloudhandler.cpp
@@ -110,7 +110,7 @@ void ConnectCloudClientHandler::handle(Client *client) {
if (!client->readContent(&_clientContent))
return;
- char *contents = Common::JSON::getPreparedContents(_clientContent);
+ char *contents = Common::JSON::untaintContents(_clientContent);
Common::JSONValue *json = Common::JSON::parse(contents);
if (json == nullptr) {
handleError(*client, "Not Acceptable", 406);
@@ -120,6 +120,7 @@ void ConnectCloudClientHandler::handle(Client *client) {
Networking::ErrorCallback callback = new Common::Callback<ConnectCloudClientHandler, Networking::ErrorResponse>(this, &ConnectCloudClientHandler::storageConnectionCallback);
Networking::JsonResponse jsonResponse(nullptr, json);
if (!CloudMan.connectStorage(jsonResponse, callback)) { // JSON doesn't have "storage" in it or it was invalid
+ delete json;
delete callback;
handleError(*client, "Not Acceptable", 406);
}
diff --git a/backends/networking/sdl_net/handlers/connectcloudhandler.h b/backends/networking/sdl_net/handlers/connectcloudhandler.h
index 0740d55e0fb..d3dcb7bb711 100644
--- a/backends/networking/sdl_net/handlers/connectcloudhandler.h
+++ b/backends/networking/sdl_net/handlers/connectcloudhandler.h
@@ -50,7 +50,7 @@ class ConnectCloudClientHandler : public ClientHandler {
const ConnectCloudHandler *_cloudHandler;
Common::MemoryWriteStreamDynamic _clientContent;
Client *_client;
- static const int32 SUSPICIOUS_CONTENT_SIZE = 512 * 1024; // 512 KB should be enough for any cloud JSON
+ static const int32 SUSPICIOUS_CONTENT_SIZE = 640 * 1024; // 640K ought to be enough for anybody
void respond(Client &client, Common::String response, long responseCode = 200) const;
void respondWithJson(Client &client, bool error, Common::String message, long responseCode = 200) const;
diff --git a/common/formats/json.cpp b/common/formats/json.cpp
index 74986c13919..5696617c587 100644
--- a/common/formats/json.cpp
+++ b/common/formats/json.cpp
@@ -63,7 +63,7 @@ namespace Common {
*/
JSON::JSON() {}
-char *JSON::getPreparedContents(Common::MemoryWriteStreamDynamic &stream) {
+char *JSON::untaintContents(Common::MemoryWriteStreamDynamic &stream) {
// write one more byte in the end
byte zero[1] = {0};
stream.write(zero, 1);
diff --git a/common/formats/json.h b/common/formats/json.h
index 8fecf9fc529..f0ef4e392e1 100644
--- a/common/formats/json.h
+++ b/common/formats/json.h
@@ -153,7 +153,7 @@ class JSON {
public:
/** Prepares raw bytes in a given stream to be parsed with Common::JSON::parse(). */
- static char *getPreparedContents(Common::MemoryWriteStreamDynamic &stream);
+ static char *untaintContents(Common::MemoryWriteStreamDynamic &stream);
static JSONValue *parse(const char *data);
static String stringify(const JSONValue *value);
diff --git a/gui/cloudconnectionwizard.cpp b/gui/cloudconnectionwizard.cpp
index 675af2ad93b..2c72a084780 100644
--- a/gui/cloudconnectionwizard.cpp
+++ b/gui/cloudconnectionwizard.cpp
@@ -31,18 +31,11 @@
#include "common/memstream.h"
#include "common/translation.h"
-#include "gui/browser.h"
-#include "gui/shaderbrowser-dialog.h"
-#include "gui/themebrowser.h"
#include "gui/message.h"
#include "gui/gui-manager.h"
-#include "gui/options.h"
#include "gui/widget.h"
#include "gui/widgets/edittext.h"
-#include "gui/widgets/popup.h"
#include "gui/widgets/scrollcontainer.h"
-#include "gui/widgets/tab.h"
-#include "gui/ThemeEval.h"
namespace GUI {
@@ -455,7 +448,7 @@ void CloudConnectionWizard::manualModeConnect() {
_label1->setLabel(Common::U32String());
// get the code entered
- Common::String code = "";
+ Common::String code;
if (_codeBox)
code = _codeBox->getEditString().encode();
if (code.size() == 0)
@@ -489,13 +482,8 @@ void CloudConnectionWizard::manualModeConnect() {
// parse JSON and display message if failed
Common::MemoryWriteStreamDynamic jsonStream(DisposeAfterUse::YES);
jsonStream.write(code.c_str(), code.size());
- char *contents = Common::JSON::getPreparedContents(jsonStream);
+ char *contents = Common::JSON::untaintContents(jsonStream);
Common::JSONValue *json = Common::JSON::parse(contents);
- if (json == nullptr) {
- if (_label1)
- _label1->setLabel(_("There is likely a mistake in the code."));
- return;
- }
// pass JSON to the manager
_connecting = true;
@@ -503,6 +491,7 @@ void CloudConnectionWizard::manualModeConnect() {
Networking::JsonResponse jsonResponse(nullptr, json);
if (!CloudMan.connectStorage(jsonResponse, callback)) { // no "storage" in JSON (or invalid one)
_connecting = false;
+ delete json;
delete callback;
if (_label1)
_label1->setLabel(_("There is likely a mistake in the code."));
Commit: 14b85a41dc1458ceb85f5502620dcfc7cdce532e
https://github.com/scummvm/scummvm/commit/14b85a41dc1458ceb85f5502620dcfc7cdce532e
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
GUI: CloudConnectionWizard I18N
Changed paths:
gui/cloudconnectionwizard.cpp
po/POTFILES
diff --git a/gui/cloudconnectionwizard.cpp b/gui/cloudconnectionwizard.cpp
index 2c72a084780..b11f1661a2b 100644
--- a/gui/cloudconnectionwizard.cpp
+++ b/gui/cloudconnectionwizard.cpp
@@ -223,8 +223,8 @@ void CloudConnectionWizard::refreshStepQuickMode1(bool displayAsStopped) {
_nextStepButton->setEnabled(serverIsRunning);
if (_button0) {
- _button0->setLabel(_(serverIsRunning ? "Stop server" : "Run server"));
- _button0->setTooltip(_(serverIsRunning ? "Stop local webserver" : "Run local webserver"));
+ _button0->setLabel(serverIsRunning ? _("Stop server") : _("Run server"));
+ _button0->setTooltip(serverIsRunning ? _("Stop local webserver") : _("Run local webserver"));
}
if (_label2) {
@@ -298,7 +298,7 @@ void CloudConnectionWizard::showStepManualMode1() {
_label0 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep1.Line1", _("Open this link in your browser:"));
_button0 = new ButtonWidget(_container, "ConnectionWizard_ManualModeStep1.OpenLinkButton", Common::U32String("https://cloud.scummvm.org/"), _("Open URL"), kCloudConnectionWizardOpenUrlStorageCmd);
- _label1 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep1.Line2", _("When it fails to pass the code to ScummVM,"));
+ _label1 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep1.Line2", _("When it fails to pass JSON code to ScummVM,"));
_label2 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep1.Line3", _("find it on Troubleshooting section of the page,"));
_label3 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep1.Line4", _("and go to the next step here."));
}
@@ -320,7 +320,7 @@ void CloudConnectionWizard::showStepManualMode2() {
showBackButton();
showNextButton();
- _label0 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep2.Line1", _("Copy the code from your browser here and press Next:"));
+ _label0 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep2.Line1", _("Copy JSON code from browser here and press Next:"));
_codeBox = new EditTextWidget(_container, "ConnectionWizard_ManualModeStep2.CodeBox", Common::U32String(), Common::U32String(), 0, 0, ThemeEngine::kFontStyleConsole);
_button0 = new ButtonWidget(_container, "ConnectionWizard_ManualModeStep2.PasteButton", _("Paste"), _("Paste code from clipboard"), kCloudConnectionWizardPasteCodeCmd);
_label1 = new StaticTextWidget(_container, "ConnectionWizard_ManualModeStep2.Line2", Common::U32String());
@@ -343,7 +343,7 @@ void CloudConnectionWizard::showStepManualModeFailure() {
showBackButton();
_label0 = new StaticTextWidget(_container, "ConnectionWizard_Failure.Line1", _("Cloud storage was not connected."));
- _label1 = new StaticTextWidget(_container, "ConnectionWizard_Failure.Line2", _("Make sure you copied the code correctly and try again."));
+ _label1 = new StaticTextWidget(_container, "ConnectionWizard_Failure.Line2", _("Make sure JSON code was copied correctly and retry."));
_label2 = new StaticTextWidget(_container, "ConnectionWizard_Failure.Line3", _("It it doesn't work, try from the beginning."));
_label3 = new StaticTextWidget(_container, "ConnectionWizard_Failure.Line4", _("Error message: ") + _errorMessage, Common::U32String(), ThemeEngine::kFontStyleNormal);
_label3->setEnabled(false);
@@ -494,7 +494,8 @@ void CloudConnectionWizard::manualModeConnect() {
delete json;
delete callback;
if (_label1)
- _label1->setLabel(_("There is likely a mistake in the code."));
+ // I18N: JSON is name of the format, this message is displayed if user entered something incorrect to the text field
+ _label1->setLabel(_("JSON code contents is malformed."));
return;
}
@@ -514,8 +515,14 @@ void CloudConnectionWizard::manualModeConnect() {
void CloudConnectionWizard::manualModeStorageConnectionCallback(Networking::ErrorResponse response) {
if (response.failed || response.interrupted) {
if (response.failed) {
+ const char *knownErrorMessages[] = {
+ _s("OK"),
+ _s("Incorrect JSON.") // see "cloud/basestorage.cpp"
+ };
+
_errorMessage = _(response.response.c_str());
} else {
+ // I18N: error message displayed on 'Manual Mode: Failure' step of 'Cloud Connection Wizard', describing that storage connection process was interrupted
_errorMessage = _("Interrupted.");
}
diff --git a/po/POTFILES b/po/POTFILES
index 94916e3d883..ec8ca4788f1 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -1,6 +1,7 @@
gui/about.cpp
gui/browser.cpp
gui/chooser.cpp
+gui/cloudconnectionwizard.cpp
gui/downloaddialog.cpp
gui/downloadpacksdialog.cpp
gui/editgamedialog.cpp
Commit: 7798c2af9fb2bd458ce36ed46003c1cfd7d59b0f
https://github.com/scummvm/scummvm/commit/7798c2af9fb2bd458ce36ed46003c1cfd7d59b0f
Author: Alexander Tkachov (alexander at tkachov.ru)
Date: 2023-04-08T16:20:11+02:00
Commit Message:
CLOUD: Prepare #4860 to merge
- regenerate themes .zips;
- minor cleanup.
Changed paths:
backends/cloud/basestorage.cpp
gui/themes/residualvm.zip
gui/themes/scummclassic.zip
gui/themes/scummmodern.zip
gui/themes/scummremastered.zip
diff --git a/backends/cloud/basestorage.cpp b/backends/cloud/basestorage.cpp
index 534283b5392..eaeb808c32f 100644
--- a/backends/cloud/basestorage.cpp
+++ b/backends/cloud/basestorage.cpp
@@ -107,7 +107,6 @@ void BaseStorage::codeFlowComplete(Networking::ErrorCallback callback, Networkin
}
if (success) {
- debug(9, "%s", json->stringify(true).c_str()); // TODO: remove when done testing against cloud.scummvm.org
_token = oauth.getVal("access_token")->asString();
if (requiresRefreshToken) {
_refreshToken = oauth.getVal("refresh_token")->asString();
diff --git a/gui/themes/residualvm.zip b/gui/themes/residualvm.zip
index 563e44f721f..0ad0beb47e3 100644
Binary files a/gui/themes/residualvm.zip and b/gui/themes/residualvm.zip differ
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 4d335a54eb5..46756171068 100644
Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index d9c57eaee2b..69e3f3bf607 100644
Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ
diff --git a/gui/themes/scummremastered.zip b/gui/themes/scummremastered.zip
index fc5b4fe487a..948486025ef 100644
Binary files a/gui/themes/scummremastered.zip and b/gui/themes/scummremastered.zip differ
More information about the Scummvm-git-logs
mailing list