From 5d4c178103403a97dd1e63125f8115ffd3cf5dab Mon Sep 17 00:00:00 2001 From: rrandomsky Date: Wed, 23 Aug 2023 10:53:45 +0200 Subject: [PATCH] [MOS-1020] Fix for losing unsaved data Fix for losing unsaved data when the user click the BACK button while creating or editing note/contact. --- image/system_a/data/lang/Deutsch.json | 4 +- image/system_a/data/lang/English.json | 4 +- image/system_a/data/lang/Espanol.json | 4 +- image/system_a/data/lang/Francais.json | 4 +- image/system_a/data/lang/Polski.json | 4 +- image/system_a/data/lang/Svenska.json | 4 +- .../application-notes/ApplicationNotes.cpp | 4 + .../application-notes/ApplicationNotes.hpp | 3 +- .../windows/NoteEditWindow.cpp | 24 ++++ .../windows/NoteEditWindow.hpp | 1 + .../models/NewContactModel.cpp | 11 ++ .../models/NewContactModel.hpp | 1 + .../InputBoxWithLabelAndIconWidget.cpp | 8 +- .../widgets/InputLinesWithLabelWidget.cpp | 30 +++++ .../windows/PhonebookNewContact.cpp | 104 ++++++++++++------ .../windows/PhonebookNewContact.hpp | 2 + module-gui/gui/widgets/ListItem.hpp | 13 ++- pure_changelog.md | 1 + 18 files changed, 178 insertions(+), 48 deletions(-) diff --git a/image/system_a/data/lang/Deutsch.json b/image/system_a/data/lang/Deutsch.json index 5bf4600b3..1826689c2 100644 --- a/image/system_a/data/lang/Deutsch.json +++ b/image/system_a/data/lang/Deutsch.json @@ -716,5 +716,7 @@ "tethering_enable_question": "Sie sind mit dem Computer verbunden.
Tethering einschalten?
(einige Funktionen k\u00f6nnen deaktiviert sein)
", "tethering_menu_access_decline": "Tethering ist eingeschaltet.

Schalten Sie Tethering aus,
um auf das Men\u00fc zuzugreifen
", "tethering_phone_mode_change_prohibited": "Tethering ist eingeschaltet.

Andere Betriebsarten (Verbunden, DND,
Offline) werden von dieser Betriebsart \u00fcberlagert
und funktionieren nicht.
", - "tethering_turn_off_question": "Tethering ausschalten?" + "tethering_turn_off_question": "Tethering ausschalten?", + "unsaved_changes": "Ungespeicherte \u00c4nderungen", + "exit_without_saving": "M\u00f6chten Sie den Vorgang ohne Speichern beenden?" } diff --git a/image/system_a/data/lang/English.json b/image/system_a/data/lang/English.json index b21fdc3dd..1f632fc5a 100644 --- a/image/system_a/data/lang/English.json +++ b/image/system_a/data/lang/English.json @@ -727,5 +727,7 @@ "tethering_enable_question": "You're connected to the computer.
Turn tethering on?
(some functions may be disabled)
", "tethering_menu_access_decline": "Tethering is on.

To access menu,
turn tethering off.
", "tethering_phone_mode_change_prohibited": "Tethering is on.

Other modes (Connected, DND,
Offline) are overriden by this mode
and are not working.
", - "tethering_turn_off_question": "Turn tethering off?" + "tethering_turn_off_question": "Turn tethering off?", + "unsaved_changes": "Unsaved changes", + "exit_without_saving": "Do you want to exit

without saving?" } diff --git a/image/system_a/data/lang/Espanol.json b/image/system_a/data/lang/Espanol.json index 3bdb0d309..fda26f113 100644 --- a/image/system_a/data/lang/Espanol.json +++ b/image/system_a/data/lang/Espanol.json @@ -716,5 +716,7 @@ "tethering_enable_question": "Est\u00e1s conectado al ordenador.
\u00bfActivar el anclaje de red?
(algunas funciones podr\u00edan desactivarse)
", "tethering_menu_access_decline": "El anclaje de red est\u00e1 activado.

Para acceder al men\u00fa,
desactiva el tethering.
", "tethering_phone_mode_change_prohibited": "El anclaje de red est\u00e1 activado.

Este modo anula otros modos (Conectado, No molestar,
Desconectado)
y hace que dejen de funcionar.
", - "tethering_turn_off_question": "\u00bfDesactivar el anclaje de red?" + "tethering_turn_off_question": "\u00bfDesactivar el anclaje de red?", + "unsaved_changes": "Cambios no guardados", + "exit_without_saving": "\u00bfQuieres salir sin guardar?" } diff --git a/image/system_a/data/lang/Francais.json b/image/system_a/data/lang/Francais.json index 8219999cb..52880199b 100644 --- a/image/system_a/data/lang/Francais.json +++ b/image/system_a/data/lang/Francais.json @@ -687,5 +687,7 @@ "tethering_enable_question": "Vous \u00eates connect\u00e9 \u00e0 l'ordinateur.
Voulez-vous activer le partage de connexion?
(certaines fonctions peuvent \u00eatre d\u00e9sactiv\u00e9es)
", "tethering_menu_access_decline": "Le partage de connexion est activ\u00e9.

Pour acc\u00e9der au menu, veuillez
d\u00e9sactiver le partage de connextion.
", "tethering_phone_mode_change_prohibited": "Le partage de connexion est activ\u00e9.

Ce mode-ci remplace et d\u00e9sactive les autres modes
(Connect\u00e9, NPD, Hors ligne)
", - "tethering_turn_off_question": "Voulez-vous d\u00e9sactiver le partage de connexion?" + "tethering_turn_off_question": "Voulez-vous d\u00e9sactiver le partage de connexion?", + "unsaved_changes": "Modifications non enregistr\u00e9es", + "exit_without_saving": "Voulez-vous quitter sans sauvegarder ?" } diff --git a/image/system_a/data/lang/Polski.json b/image/system_a/data/lang/Polski.json index 14d38df14..bd31fe51f 100644 --- a/image/system_a/data/lang/Polski.json +++ b/image/system_a/data/lang/Polski.json @@ -715,5 +715,7 @@ "tethering_enable_question": "Po\u0142\u0105czono z komputerem.
W\u0142\u0105czy\u0107 tethering?
(Niekt\u00f3re funkcje mog\u0105 by\u0107 niedost\u0119pne)
", "tethering_menu_access_decline": "Tethering w\u0142\u0105czony.

Aby przej\u015b\u0107 do menu,
wy\u0142\u0105cz tethering.
", "tethering_phone_mode_change_prohibited": "Tethering w\u0142\u0105czony.

Ten tryb powoduje, \u017ce inne tryby (Po\u0142\u0105czony, Nie przeszkadza\u0107,
Offline) nie dzia\u0142aj\u0105.
", - "tethering_turn_off_question": "Wy\u0142\u0105czy\u0107 tethering?" + "tethering_turn_off_question": "Wy\u0142\u0105czy\u0107 tethering?", + "unsaved_changes": "Niezapisane zmiany", + "exit_without_saving": "Czy chcesz wyj\u015b\u0107

bez zapisywania?" } diff --git a/image/system_a/data/lang/Svenska.json b/image/system_a/data/lang/Svenska.json index 2d655f90d..4f30316d7 100644 --- a/image/system_a/data/lang/Svenska.json +++ b/image/system_a/data/lang/Svenska.json @@ -526,5 +526,7 @@ "tethering_menu_access_decline": "Internetdelning \u00e4r p\u00e5.

F\u00f6r att \u00f6ppna menyn,
st\u00e4ng av internetdelning.
", "tethering_phone_mode_change_prohibited": "Internetdelning \u00e4r p\u00e5.

Andra l\u00e4gen (ansluten, DND,
offline) \u00e5sidos\u00e4tts av detta
l\u00e4ge och fungerar inte.
", "tethering_turn_off_question": "St\u00e4nga av Internetdelning?", - "volume_text": "LJUDVOLYM" + "volume_text": "LJUDVOLYM", + "unsaved_changes": "Osparade \u00e4ndringar", + "exit_without_saving": "Vill du g\u00e5 h\u00e4rifr\u00e5n utan att spara?" } diff --git a/module-apps/application-notes/ApplicationNotes.cpp b/module-apps/application-notes/ApplicationNotes.cpp index e0d68de35..7f99a5b94 100644 --- a/module-apps/application-notes/ApplicationNotes.cpp +++ b/module-apps/application-notes/ApplicationNotes.cpp @@ -124,6 +124,10 @@ namespace app windowsFactory.attach(window::name::option_window, [](ApplicationCommon *app, const std::string &name) { return std::make_unique(app, name); }); + windowsFactory.attach(gui::name::window::notes_dialog_yes_no, + [](ApplicationCommon *app, const std::string &name) { + return std::make_unique(app, name); + }); attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, diff --git a/module-apps/application-notes/include/application-notes/ApplicationNotes.hpp b/module-apps/application-notes/include/application-notes/ApplicationNotes.hpp index 7c8384f68..b53fac357 100644 --- a/module-apps/application-notes/include/application-notes/ApplicationNotes.hpp +++ b/module-apps/application-notes/include/application-notes/ApplicationNotes.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -14,6 +14,7 @@ namespace gui::name::window inline constexpr auto notes_search_result = "NotesSearchResult"; inline constexpr auto note_dialog = "Dialog"; inline constexpr auto note_confirm_dialog = "ConfirmDialog"; + inline constexpr auto notes_dialog_yes_no = "DialogYesNo"; } // namespace gui::name::window namespace app diff --git a/module-apps/application-notes/windows/NoteEditWindow.cpp b/module-apps/application-notes/windows/NoteEditWindow.cpp index a69afe570..b0f2a4f4d 100644 --- a/module-apps/application-notes/windows/NoteEditWindow.cpp +++ b/module-apps/application-notes/windows/NoteEditWindow.cpp @@ -2,6 +2,7 @@ // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "NoteEditWindow.hpp" +#include "DialogMetadataMessage.hpp" #include @@ -155,6 +156,24 @@ namespace app::notes std::make_unique(noteEditOptions(application, edit))); } } + if (isCurrentTextDifferentThanSaved() && + (inputEvent.isShortRelease(gui::KeyCode::KEY_RF) || inputEvent.isLongRelease(gui::KeyCode::KEY_RF))) { + + // Show a popup warning about possible data loss + auto metaData = std::make_unique( + gui::DialogMetadata{utils::translate("unsaved_changes"), + "delete_128px_W_G", + utils::translate("exit_without_saving"), + "", + [=]() -> bool { + application->returnToPreviousWindow(); // To exit this popup + application->returnToPreviousWindow(); // To switch back to previous window + return true; + }}); + + application->switchWindow(gui::name::window::notes_dialog_yes_no, std::move(metaData)); + return true; + } return AppWindow::onInput(inputEvent); } @@ -169,4 +188,9 @@ namespace app::notes { return (edit != nullptr) ? edit->isEmpty() : true; } + + bool NoteEditWindow::isCurrentTextDifferentThanSaved() + { + return notesRecord->snippet != edit->getText(); + } } // namespace app::notes diff --git a/module-apps/application-notes/windows/NoteEditWindow.hpp b/module-apps/application-notes/windows/NoteEditWindow.hpp index 43ebd1676..f399718c4 100644 --- a/module-apps/application-notes/windows/NoteEditWindow.hpp +++ b/module-apps/application-notes/windows/NoteEditWindow.hpp @@ -42,6 +42,7 @@ namespace app::notes void setCharactersCount(std::uint32_t count); void setNoteText(const UTF8 &text); void saveNote(); + bool isCurrentTextDifferentThanSaved(); std::unique_ptr presenter; std::shared_ptr notesRecord; diff --git a/module-apps/application-phonebook/models/NewContactModel.cpp b/module-apps/application-phonebook/models/NewContactModel.cpp index 625606455..6fd9d73e7 100644 --- a/module-apps/application-phonebook/models/NewContactModel.cpp +++ b/module-apps/application-phonebook/models/NewContactModel.cpp @@ -235,3 +235,14 @@ void NewContactModel::openTextOptions(gui::Text *text) auto data = std::make_unique(text); application->switchWindow(gui::window::name::input_options, std::move(data)); } +bool NewContactModel::isAnyUnsavedChange(std::shared_ptr contactRecord) +{ + for (const auto &item : internalData) { + if (item->onCheckUnsavedChangeCallback) { + if (item->onCheckUnsavedChangeCallback(contactRecord)) { + return true; + } + } + } + return false; // there is no change between already provided data and saved ones +} diff --git a/module-apps/application-phonebook/models/NewContactModel.hpp b/module-apps/application-phonebook/models/NewContactModel.hpp index 43474d548..6e2304615 100644 --- a/module-apps/application-phonebook/models/NewContactModel.hpp +++ b/module-apps/application-phonebook/models/NewContactModel.hpp @@ -28,6 +28,7 @@ class NewContactModel : public app::InternalModel, publi void createData(); bool verifyData(); bool emptyData(); + bool isAnyUnsavedChange(std::shared_ptr contactRecord); [[nodiscard]] auto getRequestType() -> PhonebookItemData::RequestType; [[nodiscard]] auto requestRecordsCount() -> unsigned int override; diff --git a/module-apps/application-phonebook/widgets/InputBoxWithLabelAndIconWidget.cpp b/module-apps/application-phonebook/widgets/InputBoxWithLabelAndIconWidget.cpp index 01284a1c6..28f986fc8 100644 --- a/module-apps/application-phonebook/widgets/InputBoxWithLabelAndIconWidget.cpp +++ b/module-apps/application-phonebook/widgets/InputBoxWithLabelAndIconWidget.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "InputBoxWithLabelAndIconWidget.hpp" @@ -172,6 +172,9 @@ namespace gui onLoadCallback = [&](std::shared_ptr contact) { tickImage->visible = contact->isOnFavourites(); }; + onCheckUnsavedChangeCallback = [&](std::shared_ptr contact) { + return tickImage->visible != contact->isOnFavourites(); + }; } void InputBoxWithLabelAndIconWidget::addToICEHandler() { @@ -214,6 +217,9 @@ namespace gui }; onSaveCallback = [&](std::shared_ptr contact) { contact->addToIce(tickImage->visible); }; onLoadCallback = [&](std::shared_ptr contact) { tickImage->visible = contact->isOnIce(); }; + onCheckUnsavedChangeCallback = [&](std::shared_ptr contact) { + return tickImage->visible != contact->isOnIce(); + }; } } /* namespace gui */ diff --git a/module-apps/application-phonebook/widgets/InputLinesWithLabelWidget.cpp b/module-apps/application-phonebook/widgets/InputLinesWithLabelWidget.cpp index 6fc66ced5..192847188 100644 --- a/module-apps/application-phonebook/widgets/InputLinesWithLabelWidget.cpp +++ b/module-apps/application-phonebook/widgets/InputLinesWithLabelWidget.cpp @@ -163,6 +163,10 @@ namespace gui onSaveCallback = [&](std::shared_ptr contact) { contact->primaryName = inputText->getText(); }; onLoadCallback = [&](std::shared_ptr contact) { inputText->setText(contact->primaryName); }; onEmptyCallback = [&]() { return inputText->isEmpty(); }; + + onCheckUnsavedChangeCallback = [&](std::shared_ptr contact) { + return contact->primaryName != inputText->getText(); + }; } void InputLinesWithLabelWidget::secondNameHandler() { @@ -176,6 +180,10 @@ namespace gui }; onLoadCallback = [&](std::shared_ptr contact) { inputText->setText(contact->alternativeName); }; onEmptyCallback = [&]() { return inputText->isEmpty(); }; + + onCheckUnsavedChangeCallback = [&](std::shared_ptr contact) { + return contact->alternativeName != inputText->getText(); + }; } void InputLinesWithLabelWidget::numberHandler() { @@ -208,6 +216,11 @@ namespace gui }; onEmptyCallback = [&]() { return inputText->isEmpty(); }; + + onCheckUnsavedChangeCallback = [&](std::shared_ptr contact) { + std::string savedNumber = (!contact->numbers.empty()) ? (contact->numbers[0].number.getEntered()) : ""; + return savedNumber != std::string(inputText->getText()); + }; } void InputLinesWithLabelWidget::secondNumberHandler() { @@ -241,6 +254,11 @@ namespace gui }; onEmptyCallback = [&]() { return inputText->isEmpty(); }; + + onCheckUnsavedChangeCallback = [&](std::shared_ptr contact) { + std::string savedNumber = (contact->numbers.size() > 1) ? (contact->numbers[1].number.getEntered()) : ""; + return savedNumber != std::string(inputText->getText()); + }; } void InputLinesWithLabelWidget::emailHandler() { @@ -252,6 +270,10 @@ namespace gui onSaveCallback = [&](std::shared_ptr contact) { contact->mail = inputText->getText(); }; onLoadCallback = [&](std::shared_ptr contact) { inputText->setText(contact->mail); }; onEmptyCallback = [&]() { return inputText->isEmpty(); }; + + onCheckUnsavedChangeCallback = [&](std::shared_ptr contact) { + return contact->mail != inputText->getText(); + }; } void InputLinesWithLabelWidget::addressHandler() { @@ -262,6 +284,10 @@ namespace gui onSaveCallback = [&](std::shared_ptr contact) { contact->address = inputText->getText(); }; onLoadCallback = [&](std::shared_ptr contact) { inputText->setText(contact->address); }; + + onCheckUnsavedChangeCallback = [&](std::shared_ptr contact) { + return contact->address != inputText->getText(); + }; } void InputLinesWithLabelWidget::noteHandler() { @@ -272,6 +298,10 @@ namespace gui onSaveCallback = [&](std::shared_ptr contact) { contact->note = inputText->getText(); }; onLoadCallback = [&](std::shared_ptr contact) { inputText->setText(contact->note); }; + + onCheckUnsavedChangeCallback = [&](std::shared_ptr contact) { + return contact->note != inputText->getText(); + }; } } /* namespace gui */ diff --git a/module-apps/application-phonebook/windows/PhonebookNewContact.cpp b/module-apps/application-phonebook/windows/PhonebookNewContact.cpp index 92885afc7..188e7fdbb 100644 --- a/module-apps/application-phonebook/windows/PhonebookNewContact.cpp +++ b/module-apps/application-phonebook/windows/PhonebookNewContact.cpp @@ -115,6 +115,22 @@ namespace gui return true; } + void PhonebookNewContact::showDialogUnsavedChanges(std::function whereToGoOnYes) + { + // Show a popup warning about possible data loss + auto metaData = std::make_unique( + gui::DialogMetadata{utils::translate("unsaved_changes"), + "delete_128px_W_G", + utils::translate("exit_without_saving"), + "", + [=]() -> bool { + application->returnToPreviousWindow(); // To exit this popup + return whereToGoOnYes(); + }}); + + application->switchWindow(gui::window::name::dialog_yes_no, std::move(metaData)); + } + void PhonebookNewContact::setSaveButtonVisible(bool visible) { navBar->setActive(nav_bar::Side::Center, visible); @@ -135,14 +151,31 @@ namespace gui return true; } else if (!inputEvent.isShortRelease(KeyCode::KEY_RF) || !shouldCurrentAppBeIgnoredOnSwitchBack()) { + if (areUnsavedChanges()) { + if (inputEvent.isShortRelease(gui::KeyCode::KEY_RF) || inputEvent.isLongRelease(gui::KeyCode::KEY_RF)) { + showDialogUnsavedChanges([this]() { + application->returnToPreviousWindow(); + return true; + }); + return true; + } + } return AppWindow::onInput(inputEvent); } - return shouldCurrentAppBeIgnoredOnSwitchBack() - ? app::manager::Controller::switchBack( - application, - std::make_unique(nameOfPreviousApplication.value())) - : true; + auto returnWhenCurrentAppShouldBeIgnoredOnSwitchBack = [this]() { + return shouldCurrentAppBeIgnoredOnSwitchBack() + ? app::manager::Controller::switchBack( + application, + std::make_unique(nameOfPreviousApplication.value())) + : true; + }; + + if (areUnsavedChanges()) { + showDialogUnsavedChanges(returnWhenCurrentAppShouldBeIgnoredOnSwitchBack); + return true; + } + return returnWhenCurrentAppShouldBeIgnoredOnSwitchBack(); } auto PhonebookNewContact::verifyAndSave() -> bool @@ -207,38 +240,37 @@ namespace gui DBServiceAPI::MatchContactByPhoneNumber(application, duplicatedNumber, duplicatedNumberContactID); const auto oldContactRecord = (matchedContact != nullptr) ? *matchedContact : ContactRecord{}; - auto metaData = std::make_unique( - gui::DialogMetadata{duplicatedNumber.getFormatted(), - "info_128px_W_G", - text::RichTextParser() - .parse(utils::translate("app_phonebook_duplicate_numbers"), - nullptr, - gui::text::RichTextParser::TokenMap( - {{"$CONTACT_FORMATTED_NAME$", oldContactRecord.getFormattedName()}})) - ->getText(), - "", - [=]() -> bool { - if (contactAction == ContactAction::Add) { - contact->ID = oldContactRecord.ID; - } - if (!DBServiceAPI::ContactUpdate(application, *contact)) { - LOG_ERROR("Contact id=%" PRIu32 " update failed", contact->ID); - return false; - } + auto metaData = std::make_unique(gui::DialogMetadata{ + duplicatedNumber.getFormatted(), + "info_128px_W_G", + text::RichTextParser() + .parse(utils::translate("app_phonebook_duplicate_numbers"), + nullptr, + gui::text::RichTextParser::TokenMap( + {{"$CONTACT_FORMATTED_NAME$", oldContactRecord.getFormattedName()}})) + ->getText(), + "", + [=]() -> bool { + if (contactAction == ContactAction::Add) { + contact->ID = oldContactRecord.ID; + } + if (!DBServiceAPI::ContactUpdate(application, *contact)) { + LOG_ERROR("Contact id=%" PRIu32 " update failed", contact->ID); + return false; + } - /* Pop "Add contact" window from the stack so that clicking - * back button after saving the modified contact returns to - * contacts list, not to the "Add contact" window. */ - application->popWindow(gui::window::name::new_contact); + /* Pop "Add contact" window from the stack so that clicking + * back button after saving the modified contact returns to + * contacts list, not to the "Add contact" window. */ + application->popWindow(gui::window::name::new_contact); - /* Switch to contact details */ - auto switchData = - std::make_unique(contact, newContactModel->getRequestType()); - switchData->ignoreCurrentWindowOnStack = true; - application->switchWindow(gui::window::name::contact, std::move(switchData)); + /* Switch to contact details */ + auto switchData = std::make_unique(contact, newContactModel->getRequestType()); + switchData->ignoreCurrentWindowOnStack = true; + application->switchWindow(gui::window::name::contact, std::move(switchData)); - return true; - }}); + return true; + }}); application->switchWindow(gui::window::name::dialog_yes_no, std::move(metaData)); } @@ -301,5 +333,9 @@ namespace gui contactByID->front().primaryName.empty() and contactByID->front().alternativeName.empty() and contactByID->front().numbers.empty(); } + bool PhonebookNewContact::areUnsavedChanges() const + { + return newContactModel->isAnyUnsavedChange(contact); + } } // namespace gui diff --git a/module-apps/application-phonebook/windows/PhonebookNewContact.hpp b/module-apps/application-phonebook/windows/PhonebookNewContact.hpp index b48dddf53..3cd59a53d 100644 --- a/module-apps/application-phonebook/windows/PhonebookNewContact.hpp +++ b/module-apps/application-phonebook/windows/PhonebookNewContact.hpp @@ -38,9 +38,11 @@ namespace gui void showDialogDuplicatedNumber(const utils::PhoneNumber::View &duplicatedNumber, const std::uint32_t duplicatedNumberContactID = 0u); void showDialogDuplicatedSpeedDialNumber(); + void showDialogUnsavedChanges(std::function whereToGoOnYes = nullptr); void setSaveButtonVisible(bool visible); void showContactDeletedNotification(); bool checkIfContactWasDeletedDuringEditProcess() const; + bool areUnsavedChanges() const; std::shared_ptr contact = nullptr; std::shared_ptr newContactModel = nullptr; diff --git a/module-gui/gui/widgets/ListItem.hpp b/module-gui/gui/widgets/ListItem.hpp index ae260ba1f..88643c476 100644 --- a/module-gui/gui/widgets/ListItem.hpp +++ b/module-gui/gui/widgets/ListItem.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -22,10 +22,11 @@ namespace gui class ListItemWithCallbacks : public ListItem { public: - std::function onEmptyCallback = nullptr; - std::function onContentChangedCallback = nullptr; - std::function onVerifyCallback = nullptr; - std::function record)> onSaveCallback = nullptr; - std::function record)> onLoadCallback = nullptr; + std::function onEmptyCallback = nullptr; + std::function onContentChangedCallback = nullptr; + std::function onVerifyCallback = nullptr; + std::function record)> onSaveCallback = nullptr; + std::function record)> onLoadCallback = nullptr; + std::function record)> onCheckUnsavedChangeCallback = nullptr; }; } /* namespace gui */ diff --git a/pure_changelog.md b/pure_changelog.md index 59a440be7..e5a502bd0 100644 --- a/pure_changelog.md +++ b/pure_changelog.md @@ -37,6 +37,7 @@ * Fixed missing tethering icon on "Tethering is on" window * Fixed showing "Copy text" option in empty note * Fixed "Copy" option missing from the options list in "New message" window +* Fixed losing unsaved data on go back ## [1.7.2 2023-07-28]