Separated the AutoConnectUpdate class more drastically

pull/123/head
Hieromon Ikasamo 6 years ago
parent a0c21a19dd
commit d36d8282bc
  1. 7
      src/AutoConnect.h
  2. 68
      src/AutoConnectUpdate.cpp
  3. 66
      src/AutoConnectUpdate.h
  4. 18
      src/AutoConnectUpdatePage.h

@ -35,10 +35,8 @@ using WebServerClass = WebServer;
// The realization of AutoConnectUpdate is effective only by the explicit
// definition of AUTOCONNECT_USE_UPDATE
#ifdef AUTOCONNECT_USE_UPDATE
#include "AutoConnectUpdate.h"
class AutoConnectUpdate; // Reference to avoid circular
#endif
/**< A type to save established credential at WiFi.begin automatically. */
typedef enum AC_SAVECREDENTIAL {
@ -274,11 +272,8 @@ class AutoConnect {
std::unique_ptr<AutoConnectAux> _aux;
String _auxUri; /**< Last accessed AutoConnectAux */
String _prevUri; /**< Previous generated page uri */
#ifdef AUTOCONNECT_USE_UPDATE
/** Available updater, only reset by AutoConnectUpdate::attach is valid */
std::unique_ptr<AutoConnectUpdate> _update;
#endif
/** Saved configurations */
AutoConnectConfig _apConfig;
@ -380,9 +375,7 @@ class AutoConnect {
#endif
friend class AutoConnectAux;
#ifdef AUTOCONNECT_USE_UPDATE
friend class AutoConnectUpdate;
#endif
};
#endif // _AUTOCONNECT_H_

@ -7,6 +7,10 @@
* @copyright MIT license.
*/
#include "AutoConnectDefs.h"
#ifdef AUTOCONNECT_USE_UPDATE
#include <functional>
#include <type_traits>
#include "AutoConnectUpdate.h"
@ -14,16 +18,16 @@
#include "AutoConnectJsonDefs.h"
/**
* The AutoConnectUpdate class inherits from the HTTPupdate class. The
* The AutoConnectUpdateAct class inherits from the HTTPupdate class. The
* update server corresponding to this class needs a simple script
* based on an HTTP server. It is somewhat different from the advanced
* updater script offered by Arduino core of ESP8266.
* The equipment required for the update server for the
* AutoConnectUpdate class is as follows:
* AutoConnectUpdateAct class is as follows:
*
* The catalog script:
* The update server URI /catalog is a script process that responds to
* queries from the AutoConnectUpdate class. The catalog script accepts
* queries from the AutoConnectUpdateAct class. The catalog script accepts
* the queries such as '/catalog?op=list&path='.
* - op:
* An op parameter speicies the query operation. In the current
@ -54,7 +58,7 @@
* - type:
* The type of the file. It defines either directory, file or bin.
* The bin means that the file is a sketch binary, and the
* AutoConnectUpdate class recognizes only files type bin as
* AutoConnectUpdateAct class recognizes only files type bin as
* available update files.
* - path:
* A path parameter specifies the path on the server storing
@ -85,17 +89,17 @@ namespace AutoConnectUtil {
AC_HAS_FUNC(onProgress);
template<typename T>
typename std::enable_if<AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdate::AC_UPDATEDIALOG_t>::type onProgress(T& updater, std::function<void(size_t, size_t)> fn) {
typename std::enable_if<AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdateAct::AC_UPDATEDIALOG_t>::type onProgress(T& updater, std::function<void(size_t, size_t)> fn) {
updater.onProgress(fn);
AC_DBG("Updater keeps callback\n");
return AutoConnectUpdate::UPDATEDIALOG_METER;
return AutoConnectUpdateAct::UPDATEDIALOG_METER;
}
template<typename T>
typename std::enable_if<!AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdate::AC_UPDATEDIALOG_t>::type onProgress(T& updater, std::function<void(size_t, size_t)> fn) {
typename std::enable_if<!AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdateAct::AC_UPDATEDIALOG_t>::type onProgress(T& updater, std::function<void(size_t, size_t)> fn) {
(void)(updater);
(void)(fn);
return AutoConnectUpdate::UPDATEDIALOG_LOADER;
return AutoConnectUpdateAct::UPDATEDIALOG_LOADER;
}
}
@ -103,7 +107,7 @@ typename std::enable_if<!AutoConnectUtil::has_func_onProgress<T>::value, AutoCon
* A destructor. Release the update processing dialogue page generated
* as AutoConnectAux.
*/
AutoConnectUpdate::~AutoConnectUpdate() {
AutoConnectUpdateAct::~AutoConnectUpdateAct() {
_catalog.reset(nullptr);
_progress.reset(nullptr);
_result.reset(nullptr);
@ -112,13 +116,13 @@ AutoConnectUpdate::~AutoConnectUpdate() {
}
/**
* Attach the AutoConnectUpdate to the AutoConnect which constitutes
* Attach the AutoConnectUpdateAct to the AutoConnect which constitutes
* the bedrock of the update process. This function creates dialog pages
* for update operation as an instance of AutoConnectAux and joins to
* the AutoConnect which is the bedrock of the process.
* @param portal A reference of AutoConnect
*/
void AutoConnectUpdate::attach(AutoConnect& portal) {
void AutoConnectUpdateAct::attach(AutoConnect& portal) {
AutoConnectAux* updatePage;
updatePage = new AutoConnectAux(String(FPSTR(_auxCatalog.uri)), String(FPSTR(_auxCatalog.title)), _auxCatalog.menu);
@ -133,9 +137,9 @@ void AutoConnectUpdate::attach(AutoConnect& portal) {
_buildAux(updatePage, &_auxResult, lengthOf(_elmResult));
_result.reset(updatePage);
_result->chunk = PB_ByteStream;
_catalog->on(std::bind(&AutoConnectUpdate::_onCatalog, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD);
_progress->on(std::bind(&AutoConnectUpdate::_onUpdate, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD);
_result->on(std::bind(&AutoConnectUpdate::_onResult, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD);
_catalog->on(std::bind(&AutoConnectUpdateAct::_onCatalog, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD);
_progress->on(std::bind(&AutoConnectUpdateAct::_onUpdate, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD);
_result->on(std::bind(&AutoConnectUpdateAct::_onResult, this, std::placeholders::_1, std::placeholders::_2), AC_EXIT_AHEAD);
portal.join(*_catalog.get());
portal.join(*_progress.get());
@ -143,14 +147,14 @@ void AutoConnectUpdate::attach(AutoConnect& portal) {
_status = UPDATE_IDLE;
// Attach this to the AutoConnectUpdate
// Attach this to the AutoConnectUpdateAct
portal._update.reset(this);
AC_DBG("AutoConnectUpdate attached\n");
if (WiFi.status() == WL_CONNECTED)
enable();
// Register the callback to inform the update progress
_dialog = AutoConnectUtil::onProgress<UpdateVariedClass>(Update, std::bind(&AutoConnectUpdate::_inProgress, this, std::placeholders::_1, std::placeholders::_2));
_dialog = AutoConnectUtil::onProgress<UpdateVariedClass>(Update, std::bind(&AutoConnectUpdateAct::_inProgress, this, std::placeholders::_1, std::placeholders::_2));
// Adjust the client dialog pattern according to the callback validity
// of the UpdateClass.
AutoConnectElement* loader = _progress->getElement(String(F("loader")));
@ -177,9 +181,9 @@ void AutoConnectUpdate::attach(AutoConnect& portal) {
/**
* Detach the update item from the current AutoConnect menu.
* AutoConnectUpdate still active.
* AutoConnectUpdateAct still active.
*/
void AutoConnectUpdate::disable(void) {
void AutoConnectUpdateAct::disable(void) {
if (_catalog) {
_catalog->menu(false);
if (_WiFiClient)
@ -189,10 +193,10 @@ void AutoConnectUpdate::disable(void) {
}
/**
* Make AutoConnectUpdate class available by incorporating the update
* Make AutoConnectUpdateAct class available by incorporating the update
* function into the menu.
*/
void AutoConnectUpdate::enable(void) {
void AutoConnectUpdateAct::enable(void) {
if (_catalog) {
_catalog->menu(true);
_status = UPDATE_IDLE;
@ -201,7 +205,7 @@ void AutoConnectUpdate::enable(void) {
}
}
void AutoConnectUpdate::handleUpdate(void) {
void AutoConnectUpdateAct::handleUpdate(void) {
// Purge WiFiClient instances that have exceeded their retention
// period to avoid running out of memory.
if (_WiFiClient) {
@ -214,7 +218,7 @@ void AutoConnectUpdate::handleUpdate(void) {
if (isEnable()) {
if (WiFi.status() == WL_CONNECTED) {
// Evaluate the processing status of AutoConnectUpdate and
// Evaluate the processing status of AutoConnectUpdateAct and
// execute it accordingly. It is only this process point that
// requests update processing.
if (_status == UPDATE_START) {
@ -238,7 +242,7 @@ void AutoConnectUpdate::handleUpdate(void) {
}
}
// If WiFi is not connected, disables the update menu.
// However, the AutoConnectUpdate class stills active.
// However, the AutoConnectUpdateAct class stills active.
else
disable();
}
@ -249,7 +253,7 @@ void AutoConnectUpdate::handleUpdate(void) {
* fetch the result.
* @return AC_UPDATESTATUS_t
*/
AC_UPDATESTATUS_t AutoConnectUpdate::update(void) {
AC_UPDATESTATUS_t AutoConnectUpdateAct::update(void) {
// Start update
String uriBin = uri + '/' + _binName;
if (_binName.length()) {
@ -296,7 +300,7 @@ AC_UPDATESTATUS_t AutoConnectUpdate::update(void) {
* @param page Pre-defined ACPage_t
* @param elementNum Number of AutoConnectElements to configure.
*/
void AutoConnectUpdate::_buildAux(AutoConnectAux* aux, const AutoConnectUpdate::ACPage_t* page, const size_t elementNum) {
void AutoConnectUpdateAct::_buildAux(AutoConnectAux* aux, const AutoConnectUpdateAct::ACPage_t* page, const size_t elementNum) {
for (size_t n = 0; n < elementNum; n++) {
if (page->element[n].type == AC_Element) {
AutoConnectElement* element = new AutoConnectElement;
@ -341,7 +345,7 @@ void AutoConnectUpdate::_buildAux(AutoConnectAux* aux, const AutoConnectUpdate::
* @param args A reference of the PageArgument of the PageBuilder
* @return Additional string to the page but it always null.
*/
String AutoConnectUpdate::_onCatalog(AutoConnectAux& catalog, PageArgument& args) {
String AutoConnectUpdateAct::_onCatalog(AutoConnectAux& catalog, PageArgument& args) {
AC_UNUSED(args);
HTTPClient httpClient;
@ -448,13 +452,13 @@ String AutoConnectUpdate::_onCatalog(AutoConnectAux& catalog, PageArgument& args
* @param args A reference of the PageArgument of the PageBuilder
* @return Additional string to the page but it always null.
*/
String AutoConnectUpdate::_onUpdate(AutoConnectAux& progress, PageArgument& args) {
String AutoConnectUpdateAct::_onUpdate(AutoConnectAux& progress, PageArgument& args) {
AC_UNUSED(args);
// launch the WebSocket server
_ws.reset(new WebSocketsServer(AUTOCONNECT_WEBSOCKETPORT));
if (_ws) {
_ws->begin();
_ws->onEvent(std::bind(&AutoConnectUpdate::_wsEvent, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
_ws->onEvent(std::bind(&AutoConnectUpdateAct::_wsEvent, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
}
else
AC_DBG("WebSocketsServer allocation failed\n");
@ -480,7 +484,7 @@ String AutoConnectUpdate::_onUpdate(AutoConnectAux& progress, PageArgument& args
* @param args A reference of the PageArgument of the PageBuilder
* @return Additional string to the page but it always null.
*/
String AutoConnectUpdate::_onResult(AutoConnectAux& result, PageArgument& args) {
String AutoConnectUpdateAct::_onResult(AutoConnectAux& result, PageArgument& args) {
AC_UNUSED(args);
String resForm;
String resColor;
@ -518,7 +522,7 @@ String AutoConnectUpdate::_onResult(AutoConnectAux& result, PageArgument& args)
return String("");
}
void AutoConnectUpdate::_inProgress(size_t amount, size_t size) {
void AutoConnectUpdateAct::_inProgress(size_t amount, size_t size) {
if (_ws) {
_amount = amount;
_binSize = size;
@ -527,7 +531,7 @@ void AutoConnectUpdate::_inProgress(size_t amount, size_t size) {
}
}
void AutoConnectUpdate::_wsEvent(uint8_t client, WStype_t event, uint8_t* payload, size_t length) {
void AutoConnectUpdateAct::_wsEvent(uint8_t client, WStype_t event, uint8_t* payload, size_t length) {
AC_DBG("WS client:%d event(%d)\n", client, event);
if (event == WStype_CONNECTED) {
_wsConnected = true;
@ -537,3 +541,5 @@ void AutoConnectUpdate::_wsEvent(uint8_t client, WStype_t event, uint8_t* payloa
else if (event == WStype_DISCONNECTED)
_wsConnected = false;
}
#endif // !AUTOCONNECT_USE_UPDATE

@ -29,6 +29,11 @@
#ifndef _AUTOCONNECTUPDATE_H_
#define _AUTOCONNECTUPDATE_H_
#include "AutoConnectDefs.h"
#ifdef AUTOCONNECT_USE_UPDATE
#ifndef AUTOCONNECT_USE_JSON
#define AUTOCONNECT_USE_JSON
#endif
#include <memory>
#define NO_GLOBAL_HTTPUPDATE
#if defined(ARDUINO_ARCH_ESP8266)
@ -41,11 +46,10 @@ using HTTPUpdateClass = ESP8266HTTPUpdate;
using HTTPUpdateClass = HTTPUpdate;
#endif
#include <WebSocketsServer.h>
#include "AutoConnectDefs.h"
#if defined(AUTOCONNECT_USE_UPDATE)
#ifndef AUTOCONNECT_USE_JSON
#define AUTOCONNECT_USE_JSON
#endif
// Quote the true AutoConnectUpdate class according to AUTOCONNECT_USE_UPDATE.
#define AutoConnectUpdate AutoConnectUpdateAct
#else // !AUTOCONNECT_USE_UPDATE!
#define AutoConnectUpdate AutoConnectUpdateVoid
#endif
#include "AutoConnect.h"
@ -66,27 +70,54 @@ typedef enum AC_UPDATESTATUS {
UPDATE_FAIL /**< Update fails */
} AC_UPDATESTATUS_t;
class AutoConnectUpdate : public HTTPUpdateClass {
class AutoConnectUpdateVoid {
public:
explicit AutoConnectUpdateVoid(const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT) {
AC_UNUSED(host);
AC_UNUSED(port);
AC_UNUSED(uri);
AC_UNUSED(timeout);
}
AutoConnectUpdateVoid(AutoConnect& portal, const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT) {
AC_UNUSED(portal);
AC_UNUSED(host);
AC_UNUSED(port);
AC_UNUSED(uri);
AC_UNUSED(timeout);
}
virtual ~AutoConnectUpdateVoid() {}
virtual void attach(AutoConnect& portal) { AC_UNUSED(portal); }
virtual void enable(void) {}
virtual void disable(void) {}
virtual void handleUpdate(void) {}
virtual bool isEnable(void) { return false; }
virtual AC_UPDATESTATUS_t status(void) { return UPDATE_IDLE; }
virtual AC_UPDATESTATUS_t update(void) { return UPDATE_IDLE; }
};
#ifdef AUTOCONNECT_USE_UPDATE
class AutoConnectUpdateAct : public AutoConnectUpdateVoid, public HTTPUpdateClass {
public:
explicit AutoConnectUpdate(const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT)
explicit AutoConnectUpdateAct(const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT)
: HTTPUpdateClass(timeout), host(host), port(port), uri(uri), _status(UPDATE_IDLE), _binName(String()), _period(0) {
UPDATE_SETLED(LOW); /**< LED blinking during the update that is the default. */
rebootOnUpdate(false); /**< Default reboot mode */
}
AutoConnectUpdate(AutoConnect& portal, const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT)
AutoConnectUpdateAct(AutoConnect& portal, const String& host = String(""), const uint16_t port = AUTOCONNECT_UPDATE_PORT, const String& uri = String("."), const int timeout = AUTOCONNECT_UPDATE_TIMEOUT)
: HTTPUpdateClass(timeout), host(host), port(port), uri(uri), _status(UPDATE_IDLE), _binName(String()), _period(0) {
UPDATE_SETLED(LOW);
rebootOnUpdate(false);
attach(portal);
}
~AutoConnectUpdate();
void attach(AutoConnect& portal); /**< Attach the update class to AutoConnect */
void enable(void); /**< Enable the AutoConnectUpdate */
void disable(void); /**< Disable the AutoConnectUpdate */
void handleUpdate(void); /**< Behaves the update process */
bool isEnable(void) { return _catalog ? _catalog->isMenu() : false; } /**< Returns current updater effectiveness */
AC_UPDATESTATUS_t status(void) { return _status; } /**< reports the current update behavior status */
AC_UPDATESTATUS_t update(void); /**< behaves update */
~AutoConnectUpdateAct();
void attach(AutoConnect& portal) override; /**< Attach the update class to AutoConnect */
void enable(void) override; /**< Enable the AutoConnectUpdateAct */
void disable(void) override; /**< Disable the AutoConnectUpdateAct */
void handleUpdate(void) override; /**< Behaves the update process */
bool isEnable(void) override { return _catalog ? _catalog->isMenu() : false; } /**< Returns current updater effectiveness */
AC_UPDATESTATUS_t status(void) override { return _status; } /**< reports the current update behavior status */
AC_UPDATESTATUS_t update(void) override; /**< behaves update */
String host; /**< Available URL of Update Server */
uint16_t port; /**< Port number of the update server */
@ -117,7 +148,7 @@ class AutoConnectUpdate : public HTTPUpdateClass {
template<typename T, size_t N> constexpr
size_t lengthOf(T(&)[N]) noexcept { return N; }
void _buildAux(AutoConnectAux* aux, const AutoConnectUpdate::ACPage_t* page, const size_t elementNum);
void _buildAux(AutoConnectAux* aux, const AutoConnectUpdateAct::ACPage_t* page, const size_t elementNum);
String _onCatalog(AutoConnectAux& catalog, PageArgument& args);
String _onUpdate(AutoConnectAux& update, PageArgument& args);
String _onResult(AutoConnectAux& result, PageArgument& args);
@ -151,4 +182,5 @@ class AutoConnectUpdate : public HTTPUpdateClass {
static const ACElementProp_t _elmResult[] PROGMEM;
};
#endif // !AUTOCONNECT_USE_UPDATE
#endif // _AUTOCONNECTUPDATE_H_

@ -13,7 +13,7 @@
// Define the AUTOCONNECT_URI_UPDATE page to select the sketch binary
// for update and order update execution.
const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmCatalog[] PROGMEM = {
const AutoConnectUpdateAct::ACElementProp_t AutoConnectUpdateAct::_elmCatalog[] PROGMEM = {
{ AC_Element, "binSty", "<style type\"text/css\">.bins{display:grid;font-size:14px;grid-gap:10px 0;grid-template-columns:1em repeat(4,max-content);overflow-x:auto}.bins input[type=radio]{-moz-appearance:radio;-webkit-appearance:radio;margin:0;vertical-align:middle}.noorder .bins label,span{margin:0 .5em 0 .5em;padding:0;text-align:left}</style>", nullptr },
{ AC_Text, "caption", nullptr, nullptr },
{ AC_Element, "c1", "<div class=\"bins\">", nullptr },
@ -21,13 +21,13 @@ const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmCatalog[] PROGME
{ AC_Element, "c1", "</div>", nullptr },
{ AC_Submit, "update", "UPDATE", AUTOCONNECT_URI_UPDATE_ACT }
};
const AutoConnectUpdate::ACPage_t AutoConnectUpdate::_auxCatalog PROGMEM = {
AUTOCONNECT_URI_UPDATE, "Update", false, AutoConnectUpdate::_elmCatalog
const AutoConnectUpdateAct::ACPage_t AutoConnectUpdateAct::_auxCatalog PROGMEM = {
AUTOCONNECT_URI_UPDATE, "Update", false, AutoConnectUpdateAct::_elmCatalog
};
// Define the AUTOCONNECT_URI_UPDATE_ACT page to display during the
// update process.
const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmProgress[] PROGMEM = {
const AutoConnectUpdateAct::ACElementProp_t AutoConnectUpdateAct::_elmProgress[] PROGMEM = {
{ AC_Element, "loader", "<style>.loader{border:2px solid #f3f3f3;border-radius:50%;border-top:2px solid #555;width:12px;height:12px;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style>", nullptr },
{ AC_Element, "c1", "<div style=\"display:inline-block\">", nullptr },
{ AC_Element, "binname", nullptr, nullptr },
@ -49,17 +49,17 @@ const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmProgress[] PROGM
{ AC_Element, "inprogress_loader", "function incr(pv){}", nullptr },
{ AC_Element, "c9", "</script>", nullptr }
};
const AutoConnectUpdate::ACPage_t AutoConnectUpdate::_auxProgress PROGMEM = {
AUTOCONNECT_URI_UPDATE_ACT, "Update", false, AutoConnectUpdate::_elmProgress
const AutoConnectUpdateAct::ACPage_t AutoConnectUpdateAct::_auxProgress PROGMEM = {
AUTOCONNECT_URI_UPDATE_ACT, "Update", false, AutoConnectUpdateAct::_elmProgress
};
// Definition of the AUTOCONNECT_URI_UPDATE_RESULT page to notify update results
const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmResult[] PROGMEM = {
const AutoConnectUpdateAct::ACElementProp_t AutoConnectUpdateAct::_elmResult[] PROGMEM = {
{ AC_Text, "status", nullptr, nullptr },
{ AC_Element, "restart", "<script type=\"text/javascript\">setTimeout(\"location.href='" AUTOCONNECT_HOMEURI "'\",1000*10);</script>", nullptr }
};
const AutoConnectUpdate::ACPage_t AutoConnectUpdate::_auxResult PROGMEM = {
AUTOCONNECT_URI_UPDATE_RESULT, "Update", false, AutoConnectUpdate::_elmResult
const AutoConnectUpdateAct::ACPage_t AutoConnectUpdateAct::_auxResult PROGMEM = {
AUTOCONNECT_URI_UPDATE_RESULT, "Update", false, AutoConnectUpdateAct::_elmResult
};
#endif // _AUTOCONNECTUPDATEPAGE_H

Loading…
Cancel
Save