~aleteoryx/muditaos

d731a85dfa26747b26378bd3f641b0c0f2b8a3c2 — Przemyslaw Brudny 4 years ago 264b84f
[EGD-7920] GUI fixes after deleting/add contact

After deleting/add a contact from the calllog, sms options,
and sms thread options, we return to the start screen
of the current application
M module-apps/application-calllog/ApplicationCallLog.cpp => module-apps/application-calllog/ApplicationCallLog.cpp +4 -0
@@ 92,6 92,10 @@ namespace app
        windowsFactory.attach(window::name::option_window, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::OptionWindow>(app, name);
        });
        windowsFactory.attach(calllog::settings::CallLogOptionsStr,
                              [](ApplicationCommon *app, const std::string &name) {
                                  return std::make_unique<gui::CalllogWindowOptions>(app, name);
                              });
        windowsFactory.attach(calllog::settings::DialogYesNoStr, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::DialogYesNo>(app, name);
        });

M module-apps/application-calllog/data/CallLogInternals.hpp => module-apps/application-calllog/data/CallLogInternals.hpp +1 -0
@@ 37,6 37,7 @@ namespace calllog
        inline constexpr auto MainWindowStr    = gui::name::window::main_window;
        inline constexpr auto DetailsWindowStr = "DetailsWindow";
        inline constexpr auto DialogYesNoStr   = "DialogYesNo";
        inline constexpr auto CallLogOptionsStr = "CallLogOptions";

    } // namespace settings
} // namespace calllog

M module-apps/application-calllog/windows/CallLogDetailsWindow.cpp => module-apps/application-calllog/windows/CallLogDetailsWindow.cpp +2 -2
@@ 225,8 225,8 @@ namespace gui
        if (inputEvent.isShortRelease(KeyCode::KEY_LF)) {
            auto app = dynamic_cast<app::ApplicationCallLog *>(application);
            assert(app != nullptr);
            app->switchWindow(window::name::option_window,
                              std::make_unique<gui::OptionsWindowOptions>(calllogWindowOptions(app, record)));
            app->switchWindow(calllog::settings::CallLogOptionsStr,
                              std::make_unique<calllog::CallLogSwitchData>(record));

            return true;
        }

M module-apps/application-calllog/windows/CallLogOptionsWindow.cpp => module-apps/application-calllog/windows/CallLogOptionsWindow.cpp +60 -18
@@ 2,30 2,72 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "CallLogOptionsWindow.hpp"
#include "data/CallLogSwitchData.hpp"
#include "data/CallLogInternals.hpp"

#include <i18n/i18n.hpp>
#include <OptionContact.hpp>
#include <OptionWindow.hpp>

std::list<gui::Option> calllogWindowOptions(app::ApplicationCallLog *app, const CalllogRecord &record)
namespace gui
{
    std::list<gui::Option> options;
    if (record.presentation != PresentationType::PR_UNKNOWN) {
        auto contactRecord = DBServiceAPI::MatchContactByPhoneNumber(app, record.phoneNumber);
        if (!contactRecord || !contactRecord->isValid() || contactRecord->isTemporary()) {
            ContactRecord newRecord;
            newRecord.numbers.emplace_back(record.phoneNumber);
            options.emplace_back(gui::Option{
                std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Add, newRecord)});

    CalllogWindowOptions::CalllogWindowOptions(app::ApplicationCommon *app, std::string windowName)
        : OptionWindow(app, windowName)
    {}

    void CalllogWindowOptions::onBeforeShow(gui::ShowMode mode, gui::SwitchData *data)
    {
        if (auto message = dynamic_cast<calllog::CallLogSwitchData *>(data)) {
            record = message->getRecord();
        }

        auto currentRecordValid = getRecordValid();

        if (recordValidCode == gui::option::OptionRecordValidity::Uninitialized ||
            recordValidCode == currentRecordValid) {
            options = calllogWindowOptions(dynamic_cast<app::ApplicationCallLog *>(application), record);
            optionsList->rebuildList(listview::RebuildType::InPlace);
        }
        else {
            options.emplace_back(gui::Option{
                std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Details, *contactRecord)});
            application->switchWindow(calllog::settings::MainWindowStr);
        }

        recordValidCode = currentRecordValid;
    }

    gui::option::OptionRecordValidity CalllogWindowOptions::getRecordValid()
    {
        auto contact = DBServiceAPI::MatchContactByPhoneNumber(application, record.phoneNumber);
        return contact == nullptr ? gui::option::OptionRecordValidity::Invalid
                                  : (contact->isTemporary() ? gui::option::OptionRecordValidity::Invalid
                                                            : gui::option::OptionRecordValidity::Valid);
    }

    std::list<Option> CalllogWindowOptions::calllogWindowOptions(app::ApplicationCallLog *app,
                                                                 const CalllogRecord &record)
    {
        std::list<gui::Option> options;
        if (record.presentation != PresentationType::PR_UNKNOWN) {
            auto contactRecord = DBServiceAPI::MatchContactByPhoneNumber(app, record.phoneNumber);
            if (!contactRecord || !contactRecord->isValid() || contactRecord->isTemporary()) {
                ContactRecord newRecord;
                newRecord.numbers.emplace_back(record.phoneNumber);
                options.emplace_back(gui::Option{
                    std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Add, newRecord)});
            }
            else {
                options.emplace_back(gui::Option{std::make_unique<gui::option::Contact>(
                    app, gui::option::ContactOperation::Details, *contactRecord)});
            }
        }

        // add option delete call option
        options.push_back(gui::Option(
            utils::translate("app_calllog_options_delete_call"),
            [=](gui::Item &item) { return app->removeCalllogEntry(record); },
            gui::option::Arrow::Disabled));
        return options;
    }

    // add option delete call option
    options.push_back(gui::Option(
        utils::translate("app_calllog_options_delete_call"),
        [=](gui::Item &item) { return app->removeCalllogEntry(record); },
        gui::option::Arrow::Disabled));
    return options;
};
} // namespace gui

M module-apps/application-calllog/windows/CallLogOptionsWindow.hpp => module-apps/application-calllog/windows/CallLogOptionsWindow.hpp +21 -4
@@ 3,8 3,25 @@

#pragma once

#include "ApplicationCallLog.hpp"
#include "Interface/CalllogRecord.hpp"
#include "OptionWindow.hpp"
#include <ApplicationCallLog.hpp>
#include <Interface/CalllogRecord.hpp>
#include <OptionWindow.hpp>

std::list<gui::Option> calllogWindowOptions(app::ApplicationCallLog *appl, const CalllogRecord &record);
namespace gui
{

    class CalllogWindowOptions : public OptionWindow
    {
      public:
        explicit CalllogWindowOptions(app::ApplicationCommon *app, std::string windowName);
        void onBeforeShow(ShowMode mode, SwitchData *data) override;

      private:
        CalllogRecord record;
        gui::option::OptionRecordValidity recordValidCode{gui::option::OptionRecordValidity::Uninitialized};

        std::list<Option> calllogWindowOptions(app::ApplicationCallLog *app, const CalllogRecord &record);
        gui::option::OptionRecordValidity getRecordValid();
    };

} // namespace gui

M module-apps/application-messages/ApplicationMessages.cpp => module-apps/application-messages/ApplicationMessages.cpp +7 -0
@@ 10,6 10,7 @@
#include "SMSTemplatesWindow.hpp"
#include "SMSTextToSearch.hpp"
#include "SMSThreadViewWindow.hpp"
#include "ThreadWindowOptions.hpp"

#include <Dialog.hpp>
#include <DialogMetadata.hpp>


@@ 129,6 130,12 @@ namespace app
        windowsFactory.attach(window::name::option_window, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::OptionWindow>(app, name);
        });
        windowsFactory.attach(gui::name::window::thread_options, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::ThreadWindowOptions>(app, name);
        });
        windowsFactory.attach(gui::name::window::sms_options, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::SmsWindowOptions>(app, name);
        });
        windowsFactory.attach(gui::name::window::dialog, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::Dialog>(app, name);
        });

M module-apps/application-messages/data/SMSdata.hpp => module-apps/application-messages/data/SMSdata.hpp +18 -0
@@ 7,6 7,7 @@
#include <SMSTemplateRecord.hpp>
#include <ContactRecord.hpp>
#include <ThreadRecord.hpp>
#include <SMSRecord.hpp>
#include <Database/Database.hpp>
#include <memory>
#include <string>


@@ 23,6 24,23 @@ class SMSThreadData : public gui::SwitchData
    {}
};

class SMSSwitchData : public gui::SwitchData
{
  protected:
    SMSRecord record;

  public:
    SMSSwitchData() = delete;
    explicit SMSSwitchData(SMSRecord record) : record(std::move(record))
    {}
    ~SMSSwitchData() override = default;

    [[nodiscard]] auto getRecord() const noexcept -> const SMSRecord &
    {
        return record;
    };
};

class SMSRequest : public gui::SwitchData
{
  protected:

M module-apps/application-messages/include/application-messages/Constants.hpp => module-apps/application-messages/include/application-messages/Constants.hpp +2 -0
@@ 15,6 15,8 @@ namespace gui::name::window
    inline constexpr auto dialog            = "Dialog";
    inline constexpr auto new_sms           = "NewSMS";
    inline constexpr auto thread_sms_search = "SMSSearch";
    inline constexpr auto thread_options    = "ThreadOptions";
    inline constexpr auto sms_options       = "SMSOptions";
    inline constexpr auto sms_templates     = "SMSTemplates";
    inline constexpr auto thread_view       = "ThreadViewWindow";


M module-apps/application-messages/models/ThreadsModel.cpp => module-apps/application-messages/models/ThreadsModel.cpp +2 -5
@@ 49,15 49,12 @@ auto ThreadsModel::getItem(gui::Order order) -> gui::ListItem *
    };

    item->inputCallback = [this, item](gui::Item &, const gui::InputEvent &event) {
        auto app = dynamic_cast<app::ApplicationMessages *>(application);
        assert(app);
        if (!event.isShortRelease()) {
            return false;
        }
        if (event.is(gui::KeyCode::KEY_LF)) {
            application->switchWindow(
                window::name::option_window,
                std::make_unique<gui::OptionsWindowOptions>(threadWindowOptions(app, item->getThreadItem().get())));
            application->switchWindow(gui::name::window::thread_options,
                                      std::make_unique<SMSThreadData>(item->getThreadItem()));
        }
        return false;
    };

M module-apps/application-messages/widgets/SMSOutputWidget.cpp => module-apps/application-messages/widgets/SMSOutputWidget.cpp +2 -2
@@ 10,6 10,7 @@
#include <OptionWindow.hpp>
#include <Style.hpp>
#include <time/time_conversion_factory.hpp>
#include <SMSdata.hpp>

namespace gui
{


@@ 87,8 88,7 @@ namespace gui
                LOG_INFO("Message activated!");
                auto app = dynamic_cast<app::ApplicationMessages *>(application);
                assert(app != nullptr);
                app->switchWindow(window::name::option_window,
                                  std::make_unique<gui::OptionsWindowOptions>(smsWindowOptions(app, *record)));
                app->switchWindow(gui::name::window::sms_options, std::make_unique<SMSSwitchData>(*record));
                return true;
            }
            return false;

M module-apps/application-messages/windows/MessagesMainWindow.cpp => module-apps/application-messages/windows/MessagesMainWindow.cpp +2 -0
@@ 131,6 131,8 @@ namespace gui
        DBServiceAPI::GetQuery(application,
                               db::Interface::Name::Notifications,
                               std::make_unique<db::query::notifications::Clear>(NotificationsRecord::Key::Sms));

        list->rebuildList();
    }

    bool MessagesMainWindow::onInput(const InputEvent &inputEvent)

M module-apps/application-messages/windows/OptionsMessages.cpp => module-apps/application-messages/windows/OptionsMessages.cpp +77 -40
@@ 14,55 14,92 @@

#include <memory>

std::list<gui::Option> smsWindowOptions(app::ApplicationMessages *app, const SMSRecord &record)
namespace gui
{
    auto contact = DBServiceAPI::MatchContactByPhoneNumber(app, record.number);
    if (contact == nullptr) {
        return {};
    }
    const auto isTempContact = contact->isTemporary();

    std::list<gui::Option> options;
    if (record.type == SMSType::FAILED) {
        options.emplace_back(utils::translate("sms_resend_failed"), [=, &record](gui::Item &item) {
            app->resendSms(record);
            app->returnToPreviousWindow();
            return true;
        });
    }
    SmsWindowOptions::SmsWindowOptions(app::ApplicationCommon *app, std::string windowName)
        : OptionWindow(app, windowName)
    {}

    void SmsWindowOptions::onBeforeShow(gui::ShowMode mode, gui::SwitchData *data)
    {
        if (auto message = dynamic_cast<SMSSwitchData *>(data)) {
            record = message->getRecord();
        }

    if (isTempContact) {
        options.emplace_back(
            gui::Option{std::make_unique<gui::option::Call>(app, record.number.getFormatted(), record.number)});
        ContactRecord newContact;
        newContact.numbers.emplace_back(record.number);
        options.emplace_back(
            gui::Option{std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Add, newContact)});
        auto currentRecordValid = getRecordValid();

        if (recordValidCode == gui::option::OptionRecordValidity::Uninitialized ||
            recordValidCode == currentRecordValid) {
            options = smsWindowOptions(dynamic_cast<app::ApplicationMessages *>(application), record);
            optionsList->rebuildList(listview::RebuildType::InPlace);
        }
        else {
            application->switchWindow(gui::name::window::main_window);
        }

        recordValidCode = currentRecordValid;
    }
    else {
        options.emplace_back(
            gui::Option{std::make_unique<gui::option::Call>(app, contact->getFormattedName(), record.number)});
        options.emplace_back(
            gui::Option{std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Details, *contact)});

    gui::option::OptionRecordValidity SmsWindowOptions::getRecordValid()
    {
        auto contact = DBServiceAPI::MatchContactByPhoneNumber(application, record.number);
        return contact == nullptr ? gui::option::OptionRecordValidity::Invalid
                                  : (contact->isTemporary() ? gui::option::OptionRecordValidity::Invalid
                                                            : gui::option::OptionRecordValidity::Valid);
    }

    options.emplace_back(UTF8(utils::translate("sms_forward_message")), [=](gui::Item &item) {
        std::unique_ptr<gui::SwitchData> data = std::make_unique<SMSTextData>(record.body);
        app->switchWindow(gui::name::window::new_sms, std::move(data));
        return true;
    });
    std::list<Option> SmsWindowOptions::smsWindowOptions(app::ApplicationMessages *app, const SMSRecord &record)
    {
        auto contact = DBServiceAPI::MatchContactByPhoneNumber(app, record.number);
        if (contact == nullptr) {
            return {};
        }
        const auto isTempContact = contact->isTemporary();

    options.emplace_back(UTF8(utils::translate("sms_copy")), [=](gui::Item &item) {
        Clipboard::getInstance().copy(record.body);
        app->returnToPreviousWindow();
        return true;
    });
        std::list<gui::Option> options;
        if (record.type == SMSType::FAILED) {
            options.emplace_back(utils::translate("sms_resend_failed"), [=, &record](gui::Item &item) {
                app->resendSms(record);
                app->returnToPreviousWindow();
                return true;
            });
        }

    options.emplace_back(UTF8(utils::translate("sms_delete_message")),
                         [=](gui::Item &item) { return app->removeSms(record); });
        if (isTempContact) {
            options.emplace_back(
                gui::Option{std::make_unique<gui::option::Call>(app, record.number.getFormatted(), record.number)});
            ContactRecord newContact;
            newContact.numbers.emplace_back(record.number);
            options.emplace_back(gui::Option{
                std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Add, newContact)});
        }
        else {
            options.emplace_back(
                gui::Option{std::make_unique<gui::option::Call>(app, contact->getFormattedName(), record.number)});
            options.emplace_back(gui::Option{
                std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Details, *contact)});
        }

    return options;
}
        options.emplace_back(UTF8(utils::translate("sms_forward_message")), [=](gui::Item &item) {
            std::unique_ptr<gui::SwitchData> data = std::make_unique<SMSTextData>(record.body);
            app->switchWindow(gui::name::window::new_sms, std::move(data));
            return true;
        });

        options.emplace_back(UTF8(utils::translate("sms_copy")), [=](gui::Item &item) {
            Clipboard::getInstance().copy(record.body);
            app->returnToPreviousWindow();
            return true;
        });

        options.emplace_back(UTF8(utils::translate("sms_delete_message")),
                             [=](gui::Item &item) { return app->removeSms(record); });

        return options;
    }

} // namespace gui

std::list<gui::Option> newMessageWindowOptions(app::ApplicationMessages *app,
                                               const std::string &requestingWindow,

M module-apps/application-messages/windows/OptionsMessages.hpp => module-apps/application-messages/windows/OptionsMessages.hpp +19 -1
@@ 5,10 5,28 @@

#include "ApplicationMessages.hpp"

#include <OptionWindow.hpp>
#include <Interface/SMSRecord.hpp>
#include <Option.hpp>

std::list<gui::Option> smsWindowOptions(app::ApplicationMessages *app, const SMSRecord &record);
namespace gui
{

    class SmsWindowOptions : public OptionWindow
    {
      public:
        explicit SmsWindowOptions(app::ApplicationCommon *app, std::string windowName);
        void onBeforeShow(ShowMode mode, SwitchData *data) override;

      private:
        SMSRecord record;
        gui::option::OptionRecordValidity recordValidCode{gui::option::OptionRecordValidity::Uninitialized};

        std::list<gui::Option> smsWindowOptions(app::ApplicationMessages *app, const SMSRecord &record);
        gui::option::OptionRecordValidity getRecordValid();
    };

} // namespace gui

/// @brief options for New Message Window
///

M module-apps/application-messages/windows/ThreadWindowOptions.cpp => module-apps/application-messages/windows/ThreadWindowOptions.cpp +78 -43
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ThreadWindowOptions.hpp"
#include "data/SMSdata.hpp"

#include <i18n/i18n.hpp>
#include <log/log.hpp>


@@ 9,55 10,89 @@
#include <OptionContact.hpp>
#include <OptionWindow.hpp>

std::list<gui::Option> threadWindowOptions(app::ApplicationMessages *app, const ThreadRecord *record)
namespace gui
{
    assert(record != nullptr);
    auto number  = DBServiceAPI::NumberByID(app, record->numberID);
    auto contact = DBServiceAPI::MatchContactByNumberID(app, record->numberID);
    if (!contact->isValid()) {
        return {};
    }
    const auto isTempContact = contact->isTemporary();

    std::list<gui::Option> options;
    if (isTempContact) {
        options.emplace_back(gui::Option{std::make_unique<gui::option::Call>(app, number.getFormatted(), number)});
    ThreadWindowOptions::ThreadWindowOptions(app::ApplicationCommon *app, std::string windowName)
        : OptionWindow(app, windowName)
    {}

        ContactRecord newContact;
        newContact.numbers.emplace_back(number);
        options.emplace_back(
            gui::Option{std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Add, newContact)});
    }
    else {
        options.emplace_back(
            gui::Option{std::make_unique<gui::option::Call>(app, contact->getFormattedName(), number)});
        options.emplace_back(
            gui::Option{std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Details, *contact)});
    }
    void ThreadWindowOptions::onBeforeShow(gui::ShowMode mode, gui::SwitchData *data)
    {
        if (auto message = dynamic_cast<SMSThreadData *>(data)) {
            thread = message->thread;
        }

    if (record->isUnread()) {
        options.emplace_back(gui::Option{utils::translate("sms_mark_read"), [=](gui::Item &item) {
                                             app->markSmsThreadAsRead(record->ID);
                                             app->returnToPreviousWindow();
                                             return true;
                                         }});
        auto currentThreadValid = getThreadValid();

        if (threadValidCode == gui::option::OptionRecordValidity::Uninitialized ||
            threadValidCode == currentThreadValid) {
            options = threadWindowOptions(dynamic_cast<app::ApplicationMessages *>(application), thread.get());
            optionsList->rebuildList(listview::RebuildType::InPlace);
        }
        else {
            application->returnToPreviousWindow();
        }

        threadValidCode = currentThreadValid;
    }
    else {
        options.emplace_back(gui::Option{utils::translate("sms_mark_unread"), [=](gui::Item &item) {
                                             app->markSmsThreadAsUnread(record->ID);
                                             app->returnToPreviousWindow();
                                             return true;
                                         }});

    gui::option::OptionRecordValidity ThreadWindowOptions::getThreadValid()
    {
        auto contact = DBServiceAPI::MatchContactByNumberID(application, thread->numberID);
        return contact == nullptr ? gui::option::OptionRecordValidity::Invalid
                                  : (contact->isTemporary() ? gui::option::OptionRecordValidity::Invalid
                                                            : gui::option::OptionRecordValidity::Valid);
    }

    options.emplace_back(gui::Option{utils::translate("sms_delete_conversation"), [=](gui::Item &item) {
                                         LOG_INFO("Removing sms thread!");
                                         return app->removeSmsThread(record);
                                     }});
    std::list<Option> ThreadWindowOptions::threadWindowOptions(app::ApplicationMessages *app,
                                                               const ThreadRecord *record)
    {
        assert(record != nullptr);
        auto number  = DBServiceAPI::NumberByID(app, record->numberID);
        auto contact = DBServiceAPI::MatchContactByNumberID(app, record->numberID);
        if (!contact->isValid()) {
            return {};
        }
        const auto isTempContact = contact->isTemporary();

        std::list<gui::Option> options;
        if (isTempContact) {
            options.emplace_back(gui::Option{std::make_unique<gui::option::Call>(app, number.getFormatted(), number)});

            ContactRecord newContact;
            newContact.numbers.emplace_back(number);
            options.emplace_back(gui::Option{
                std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Add, newContact)});
        }
        else {
            options.emplace_back(
                gui::Option{std::make_unique<gui::option::Call>(app, contact->getFormattedName(), number)});
            options.emplace_back(gui::Option{
                std::make_unique<gui::option::Contact>(app, gui::option::ContactOperation::Details, *contact)});
        }

        if (record->isUnread()) {
            options.emplace_back(gui::Option{utils::translate("sms_mark_read"), [=](gui::Item &item) {
                                                 app->markSmsThreadAsRead(record->ID);
                                                 app->returnToPreviousWindow();
                                                 return true;
                                             }});
        }
        else {
            options.emplace_back(gui::Option{utils::translate("sms_mark_unread"), [=](gui::Item &item) {
                                                 app->markSmsThreadAsUnread(record->ID);
                                                 app->returnToPreviousWindow();
                                                 return true;
                                             }});
        }

    // TODO
    // shouldn't this be in show contact details actually? it would be much easier too
    // {utils::translate("sms_add_to_contacts"), [=](gui::Item &item) { return true; }},
        options.emplace_back(gui::Option{utils::translate("sms_delete_conversation"), [=](gui::Item &item) {
                                             LOG_INFO("Removing sms thread!");
                                             return app->removeSmsThread(record);
                                         }});

        return options;
    }

    return options;
};
} // namespace gui

M module-apps/application-messages/windows/ThreadWindowOptions.hpp => module-apps/application-messages/windows/ThreadWindowOptions.hpp +16 -3
@@ 5,11 5,24 @@

#include "ApplicationMessages.hpp"

#include <OptionWindow.hpp>
#include <Interface/ThreadRecord.hpp>

namespace gui
{
    class Option;
}

std::list<gui::Option> threadWindowOptions(app::ApplicationMessages *appl, const ThreadRecord *record);
    class ThreadWindowOptions : public OptionWindow
    {
      public:
        explicit ThreadWindowOptions(app::ApplicationCommon *app, std::string windowName);
        void onBeforeShow(ShowMode mode, SwitchData *data) override;

      private:
        std::shared_ptr<ThreadRecord> thread;
        gui::option::OptionRecordValidity threadValidCode{gui::option::OptionRecordValidity::Uninitialized};

        std::list<Option> threadWindowOptions(app::ApplicationMessages *app, const ThreadRecord *record);
        gui::option::OptionRecordValidity getThreadValid();
    };

} // namespace gui

M module-apps/application-phonebook/data/PhonebookItemData.hpp => module-apps/application-phonebook/data/PhonebookItemData.hpp +14 -7
@@ 12,23 12,30 @@

class PhonebookItemData : public gui::SwitchData
{
    std::string text;
    std::shared_ptr<ContactRecord> contact = nullptr;

  public:
    enum class RequestType
    {
        Internal,
        External
    };

    PhonebookItemData() = default;
    explicit PhonebookItemData(std::shared_ptr<ContactRecord> contact, const std::string &text = "")
        : text(text), contact(std::move(contact)){};
    explicit PhonebookItemData(std::shared_ptr<ContactRecord> contact, RequestType requestType = RequestType::Internal)
        : requestType(requestType), contact(std::move(contact)){};

    std::shared_ptr<ContactRecord> getContact() const
    {
        return contact;
    }

    const std::string &getText() const noexcept
    RequestType getRequestType() const noexcept
    {
        return text;
        return requestType;
    }

  private:
    RequestType requestType                = RequestType::Internal;
    std::shared_ptr<ContactRecord> contact = nullptr;
};

class PhonebookSearchResultsData : public gui::SwitchData

M module-apps/application-phonebook/windows/PhonebookContactDetails.cpp => module-apps/application-phonebook/windows/PhonebookContactDetails.cpp +5 -1
@@ 62,6 62,10 @@ namespace gui
            bodyList->rebuildList();
        }

        if (auto message = dynamic_cast<PhonebookItemData *>(data); message != nullptr) {
            requestType = message->getRequestType();
        }

        setTitle(contact->getFormattedName(ContactRecord::NameFormatType::Title));

        if (contact->speeddial.length() != 0u) {


@@ 123,7 127,7 @@ namespace gui
        }

        if (inputEvent.isShortRelease(KeyCode::KEY_LF)) {
            std::unique_ptr<gui::SwitchData> data = std::make_unique<PhonebookItemData>(contact);
            std::unique_ptr<gui::SwitchData> data = std::make_unique<PhonebookItemData>(contact, requestType);
            application->switchWindow(
                gui::window::name::contact_options, gui::ShowMode::GUI_SHOW_INIT, std::move(data));


M module-apps/application-phonebook/windows/PhonebookContactDetails.hpp => module-apps/application-phonebook/windows/PhonebookContactDetails.hpp +1 -0
@@ 28,6 28,7 @@ namespace gui
        void destroyInterface() override;

      private:
        PhonebookItemData::RequestType requestType               = PhonebookItemData::RequestType::Internal;
        std::shared_ptr<ContactRecord> contact                   = nullptr;
        ContactFlagsWidget *contactFlagsWidget                   = nullptr;
        std::shared_ptr<ContactDetailsModel> contactDetailsModel = nullptr;

M module-apps/application-phonebook/windows/PhonebookContactOptions.cpp => module-apps/application-phonebook/windows/PhonebookContactOptions.cpp +20 -12
@@ 10,6 10,7 @@

#include <memory>
#include <service-db/DBServiceAPI.hpp>
#include <service-appmgr/Controller.hpp>

namespace gui
{


@@ 25,7 26,8 @@ namespace gui
            LOG_WARN("Received null pointer");
            return false;
        }
        contact = item->getContact();
        contact     = item->getContact();
        requestType = item->getRequestType();
        clearOptions();
        addOptions(contactOptionsList());



@@ 104,17 106,23 @@ namespace gui
            break;
        }

        auto metaData = std::make_unique<gui::DialogMetadataMessage>(
            gui::DialogMetadata{contact->getFormattedName(ContactRecord::NameFormatType::Title),
                                "info_big_circle_W_G",
                                dialogText,
                                "",
                                [=]() -> bool {
                                    auto data                        = std::make_unique<SwitchData>();
                                    data->ignoreCurrentWindowOnStack = true;
                                    this->application->switchWindow(gui::name::window::main_window, std::move(data));
                                    return true;
                                }});
        auto metaData                        = std::make_unique<gui::DialogMetadataMessage>(gui::DialogMetadata{
            contact->getFormattedName(ContactRecord::NameFormatType::Title),
            "info_big_circle_W_G",
            dialogText,
            "",
            [=]() -> bool {
                if (requestType == PhonebookItemData::RequestType::External) {
                    app::manager::Controller::switchBack(application);
                }
                else {
                    auto data                        = std::make_unique<SwitchData>();
                    data->ignoreCurrentWindowOnStack = true;
                    this->application->switchWindow(gui::name::window::main_window, std::move(data));
                }

                return true;
            }});
        metaData->ignoreCurrentWindowOnStack = true;
        application->switchWindow(gui::window::name::dialog_confirm, std::move(metaData));
        return true;

M module-apps/application-phonebook/windows/PhonebookContactOptions.hpp => module-apps/application-phonebook/windows/PhonebookContactOptions.hpp +2 -0
@@ 4,6 4,7 @@
#pragma once

#include "OptionWindow.hpp"
#include "application-phonebook/data/PhonebookItemData.hpp"

#include <ContactRecord.hpp>



@@ 17,6 18,7 @@ namespace gui
        auto handleSwitchData(SwitchData *data) -> bool override;

      private:
        PhonebookItemData::RequestType requestType = PhonebookItemData::RequestType::Internal;
        enum class NotificationType
        {
            Block,

M module-apps/apps-common/options/OptionStyle.hpp => module-apps/apps-common/options/OptionStyle.hpp +7 -0
@@ 35,6 35,13 @@ namespace gui::option
        Text
    };

    enum class OptionRecordValidity
    {
        Uninitialized,
        Invalid,
        Valid
    };

    namespace window
    {
        inline constexpr gui::Length option_left_margin       = 10;

M module-apps/apps-common/options/type/OptionContact.cpp => module-apps/apps-common/options/type/OptionContact.cpp +2 -1
@@ 42,7 42,8 @@ namespace gui::option
                                       ContactOperation contactOperation,
                                       const ContactRecord &contactRecord)
    {
        auto data = std::make_unique<PhonebookItemData>(std::make_shared<ContactRecord>(contactRecord));
        auto data = std::make_unique<PhonebookItemData>(std::make_shared<ContactRecord>(contactRecord),
                                                        PhonebookItemData::RequestType::External);

        switch (contactOperation) {
        case ContactOperation::Add: {