~aleteoryx/muditaos

db4b41c56eba5ec898bbbdc23d6fbb7222653922 — Jakub Pyszczak 5 years ago 4d2eeeb
[EGD-5712] Volume popup added

There is need of popup window on volume key
pressed event. This PR handles:
Creating base popup window attached to
application desktop.
Creating volume window.
Audio key events logic implementation.
M image/assets/lang/English.json => image/assets/lang/English.json +4 -1
@@ 81,7 81,6 @@
  "duration_0hmin_0sec": "%0N:%0S",
  "duration_hour_0min_0sec": "%H:%0M:%0S",
  "brightness_text": "BRIGHTNESS",
  "volume_text": "VOLUME",
  "home_modes_connected": "CONNECTED",
  "home_modes_notdisturb": "DO NOT DISTURB",
  "home_modes_offline": "OFFLINE",


@@ 280,6 279,10 @@
  "app_desktop_clear": "CLEAR",
  "app_desktop_clear_all": "CLEAR ALL",
  "app_desktop_replay": "REPLY",
  "app_popup_volume_text": "VOLUME",
  "app_popup_music_volume_text": "MUSIC VOLUME",
  "app_popup_call_volume_text": "CALL VOLUME",
  "app_popup_muted_text": "MUTED",
  "app_call_call": "CALL",
  "app_call_clear": "CLEAR",
  "app_call_reject": "REJECT",

M module-apps/Application.cpp => module-apps/Application.cpp +22 -19
@@ 37,6 37,7 @@
#include <module-utils/time/DateAndTimeSettings.hpp>

#include <service-audio/AudioServiceAPI.hpp> // for GetOutputVolume
#include "popups/data/PopupData.hpp"

namespace gui
{


@@ 103,7 104,6 @@ namespace app
        connect(sevm::BatteryStatusChangeMessage(), [&](sys::Message *) { return handleBatteryStatusChange(); });
        connect(typeid(app::manager::DOMRequest),
                [&](sys::Message *msg) -> sys::MessagePointer { return handleGetDOM(msg); });

        connect(typeid(AppUpdateWindowMessage),
                [&](sys::Message *msg) -> sys::MessagePointer { return handleUpdateWindow(msg); });
    }


@@ 273,11 273,8 @@ namespace app
        else if (dynamic_cast<sevm::SIMMessage *>(msgl) != nullptr) {
            return handleSIMMessage(msgl);
        }
        else if (auto msg = dynamic_cast<AudioKeyPressedResponse *>(msgl)) {
            if (!msg->muted) {
                handleVolumePopup();
                return sys::msgHandled();
            }
        else if (dynamic_cast<AudioKeyPressedResponse *>(msgl) != nullptr) {
            return handleAudioKeyMessage(msgl);
        }
        return sys::msgNotHandled();
    }


@@ 529,6 526,25 @@ namespace app
        return sys::msgHandled();
    }

    sys::MessagePointer Application::handleAudioKeyMessage(sys::Message *msgl)
    {
        using namespace gui::popup;
        const auto msg = static_cast<AudioKeyPressedResponse *>(msgl);
        if (!msg->muted) {
            LOG_INFO("Playback: %s, volume: %s",
                     audio::str(msg->context.second).c_str(),
                     std::to_string(msg->volume).c_str());
            auto data = std::make_unique<gui::VolumePopupData>(msg->volume, msg->context);
            if (getCurrentWindow()->getName() == window::volume_window) {
                updateWindow(window::volume_window, std::move(data));
            }
            else {
                switchWindow(window::volume_window, std::move(data));
            }
        }
        return sys::msgHandled();
    }

    sys::ReturnCodes Application::InitHandler()
    {
        setState(State::INITIALIZING);


@@ 663,19 679,6 @@ namespace app
        }
    }

    bool Application::handleVolumePopup()
    {
        using namespace gui::popup;
        if (getCurrentWindow()->getName() == window::volume_window) {
            return true;
        }
        else if (windowsFactory.isRegistered(window::volume_window)) {
            switchWindow(window::volume_window);
            return true;
        }
        return false;
    }

    bool Application::popToWindow(const std::string &window)
    {
        if (window == gui::name::window::no_window) {

M module-apps/Application.hpp => module-apps/Application.hpp +1 -4
@@ 172,6 172,7 @@ namespace app
        sys::MessagePointer handleGetDOM(sys::Message *msgl);
        sys::MessagePointer handleAppFocusLost(sys::Message *msgl);
        sys::MessagePointer handleSIMMessage(sys::Message *msgl);
        sys::MessagePointer handleAudioKeyMessage(sys::Message *msgl);

        std::list<std::unique_ptr<app::GuiTimer>> gui_timers;
        std::unordered_map<manager::actions::ActionId, OnActionReceived> receivers;


@@ 324,10 325,6 @@ namespace app
        /// Method used to attach popups windows to application
        void attachPopups(const std::vector<gui::popup::ID> &popupsList);

        /// Individual popups handlers
      public:
        bool handleVolumePopup();

      public:
        /// @ingrup AppWindowStack
        /// get to the first time we entered this &window

M module-apps/CMakeLists.txt => module-apps/CMakeLists.txt +1 -0
@@ 29,6 29,7 @@ set( SOURCES
    "widgets/ButtonOnOff.cpp"
    "widgets/InputBox.cpp"
    "popups/VolumeWindow.cpp"
    "popups/WindowWithTimer.cpp"
    "windows/BrightnessWindow.cpp"
    "windows/HomeModesWindow.cpp"
    "widgets/BrightnessBox.cpp"

M module-apps/application-calculator/ApplicationCalculator.cpp => module-apps/application-calculator/ApplicationCalculator.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApplicationCalculator.hpp"

M module-apps/application-call/ApplicationCall.cpp => module-apps/application-call/ApplicationCall.cpp +1 -2
@@ 72,8 72,6 @@ namespace app
            showNotification(buttonAction, iconNoSim, textNoSim);
            return actionHandled();
        });

        attachPopups({gui::popup::ID::Volume});
    }

    //  number of seconds after end call to switch back to previous application


@@ 224,6 222,7 @@ namespace app
        windowsFactory.attach(app::window::name_dialogConfirm, [](Application *app, const std::string &name) {
            return std::make_unique<gui::DialogConfirm>(app, name);
        });
        attachPopups({gui::popup::ID::Volume});
    }

    bool ApplicationCall::showNotification(std::function<bool()> action,

M module-apps/application-meditation/ApplicationMeditation.cpp => module-apps/application-meditation/ApplicationMeditation.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApplicationMeditation.hpp"

M module-apps/application-music-player/ApplicationMusicPlayer.cpp => module-apps/application-music-player/ApplicationMusicPlayer.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApplicationMusicPlayer.hpp"

M module-apps/messages/AppMessage.hpp => module-apps/messages/AppMessage.hpp +6 -6
@@ 73,23 73,23 @@ namespace app
              data{std::move(data)}, returnApplication{returnApplication}, returnWindow{returnWindow} {};
        virtual ~AppSwitchMessage(){};

        std::string getTargetWindowName()
        [[nodiscard]] std::string getTargetWindowName() const
        {
            return targetWindow;
        };
        std::string getReturnWindowName()
        [[nodiscard]] std::string getReturnWindowName() const
        {
            return returnWindow;
        };
        std::unique_ptr<gui::SwitchData> &getData()
        [[nodiscard]] std::unique_ptr<gui::SwitchData> &getData()
        {
            return data;
        };
        std::string getTargetApplicationName()
        [[nodiscard]] std::string getTargetApplicationName() const
        {
            return targetApplication;
        };
        std::string getReturnApplicationName()
        [[nodiscard]] std::string getReturnApplicationName() const
        {
            return returnApplication;
        };


@@ 229,4 229,4 @@ namespace app
        AppLostFocusMessage() : AppMessage{MessageType::AppFocusLost}
        {}
    };
};     // namespace app
} // namespace app

M module-apps/popups/VolumeWindow.cpp => module-apps/popups/VolumeWindow.cpp +50 -38
@@ 1,13 1,14 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <module-gui/gui/input/InputEvent.hpp>
#include <i18n/i18n.hpp>
#include "VolumeWindow.hpp"
#include "popups/data/PopupData.hpp"

namespace gui
{
    VolumeWindow::VolumeWindow(app::Application *app, const std::string &name) : AppWindow(app, name)
    VolumeWindow::VolumeWindow(app::Application *app, const std::string &name) : WindowWithTimer(app, name)
    {
        buildInterface();
    }


@@ 19,7 20,7 @@ namespace gui
                               title->offset_h(),
                               style::window::default_body_width,
                               style::window::volume::title_height,
                               utils::localize.get(style::window::volume::title_key));
                               utils::localize.get(style::window::volume::base_title_key));

        volumeText->setPenWidth(style::window::default_border_no_focus_w);
        volumeText->setFont(style::window::font::mediumbold);


@@ 37,7 38,11 @@ namespace gui

    void VolumeWindow::buildInterface()
    {
        AppWindow::buildInterface();
        WindowWithTimer::buildInterface();

        bottomBar->setVisible(false);
        topBar->setVisible(false);

        addVolumeText();
        addVolumeBar();
    }


@@ 45,54 50,61 @@ namespace gui
    void VolumeWindow::rebuild()
    {}

    void VolumeWindow::destroyInterface()
    void VolumeWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        erase();
        WindowWithTimer::onBeforeShow(mode, data);
        const auto popupData = static_cast<VolumePopupData *>(data);
        volume               = popupData->getVolume();
        audioContext         = popupData->getAudioContext();
        if (volumeBar != nullptr) {
            volumeBar->setValue(volume);
        }
        if (volumeText != nullptr) {
            showProperText(audioContext, volume);
        }
    }

    VolumeWindow::~VolumeWindow()
    void VolumeWindow::showProperText(const AudioContext &audioContext, const audio::Volume volume) noexcept
    {
        destroyInterface();
        volumeText->setText(utils::localize.get(style::window::volume::base_title_key));
        const auto [profileType, playbackType] = audioContext;
        if (playbackType == audio::PlaybackType::Multimedia) {
            showMultimediaPlayback();
        }
        else if (profileType == audio::Profile::Type::RoutingBluetoothHSP ||
                 profileType == audio::Profile::Type::RoutingEarspeaker ||
                 profileType == audio::Profile::Type::RoutingHeadphones ||
                 profileType == audio::Profile::Type::RoutingLoudspeaker) {
            showCalling();
        }

        if (volume == 0) {
            showMuted();
        }
    }

    void VolumeWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    void VolumeWindow::showMultimediaPlayback() noexcept
    {
        updateGraph();
        volumeText->setText(utils::localize.get(style::window::volume::music_title_key));
    }

    bool VolumeWindow::onInput(const gui::InputEvent &inputEvent)
    void VolumeWindow::showCalling() noexcept
    {
        if (!inputEvent.isShortPress()) {
            return false;
        }
        volumeText->setText(utils::localize.get(style::window::volume::call_title_key));
    }

    void VolumeWindow::showMuted() noexcept
    {
        volumeText->setText(utils::localize.get(style::window::volume::mute_title_key));
    }

    bool VolumeWindow::onInput(const gui::InputEvent &inputEvent)
    {
        if ((inputEvent.isShortPress())) {
            switch (inputEvent.keyCode) {
            case KeyCode::KEY_VOLUP: {
                application->increaseCurrentVolume();
                updateGraph();
                return true;
            }
            case KeyCode::KEY_VOLDN: {
                application->decreaseCurrentVolume();
                updateGraph();
                return true;
            }
            case KeyCode::KEY_RF: {
                application->returnToPreviousWindow();
                return true;
            }
            default:
                break;
            if (inputEvent.keyCode == KeyCode::KEY_RF) {
                return false;
            }
        }

        return AppWindow::onInput(inputEvent);
    }

    void VolumeWindow::updateGraph()
    {
        application->getCurrentVolume(Volume);
        volumeBar->setValue(Volume);
    }
} // namespace gui

M module-apps/popups/VolumeWindow.hpp => module-apps/popups/VolumeWindow.hpp +20 -12
@@ 1,17 1,20 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "module-apps/Application.hpp"
#include "AppWindow.hpp"
#include "module-apps/widgets/BarGraph.hpp"
#include "Application.hpp"
#include "widgets/BarGraph.hpp"
#include "WindowWithTimer.hpp"
#include <functional>

namespace style::window::volume
{
    constexpr inline auto title_height = 33;
    constexpr inline auto title_key    = "volume_text";
    constexpr inline auto base_title_key  = "app_popup_volume_text";
    constexpr inline auto music_title_key = "app_popup_music_volume_text";
    constexpr inline auto call_title_key  = "app_popup_call_volume_text";
    constexpr inline auto mute_title_key  = "app_popup_muted_text";

    namespace bar
    {


@@ 22,26 25,31 @@ namespace style::window::volume
} // namespace style::window::volume
namespace gui
{
    class VolumeWindow : public AppWindow
    class VolumeWindow : public WindowWithTimer
    {
        using AudioContext = std::pair<audio::Profile::Type, audio::PlaybackType>;

      private:
        audio::Volume volume = 0;
        AudioContext audioContext;

        void showProperText(const AudioContext &audioContext, const audio::Volume volume) noexcept;
        void showMultimediaPlayback() noexcept;
        void showCalling() noexcept;
        void showMuted() noexcept;

      protected:
        Label *volumeText    = nullptr;
        VBarGraph *volumeBar = nullptr;
        audio::Volume Volume = 0;

        void updateGraph();

      public:
        VolumeWindow(app::Application *app, const std::string &name);

        ~VolumeWindow() override;

        void addVolumeText();
        void addVolumeBar();
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        bool onInput(const gui::InputEvent &inputEvent) override;
    };
}; // namespace gui

A module-apps/popups/WindowWithTimer.cpp => module-apps/popups/WindowWithTimer.cpp +62 -0
@@ 0,0 1,62 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "WindowWithTimer.hpp"
#include "Application.hpp"
#include "GuiTimer.hpp"

namespace gui
{
    namespace popup
    {
        constexpr auto timerName = "PopupTimer";
    } // namespace popup

    WindowWithTimer::WindowWithTimer(app::Application *app,
                                     const std::string &name,
                                     const std::chrono::milliseconds timeout)
        : AppWindow{app, name}
    {
        popupTimer    = app::GuiTimerFactory::createSingleShotTimer(application, this, popup::timerName, timeout);
        timerCallback = [this](Item &, sys::Timer &timer) {
            LOG_DEBUG("Delayed exit timer callback");
            application->returnToPreviousWindow();
            return true;
        };
    }

    void WindowWithTimer::resetTimer()
    {
        popupTimer.stop();
        popupTimer.start();
    }

    void WindowWithTimer::detachTimerIfExists()
    {
        if (popupTimer.isValid()) {
            popupTimer.stop();
            popupTimer.reset(nullptr);
        }
    }

    void WindowWithTimer::destroyInterface()
    {
        erase();
    }

    void WindowWithTimer::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        resetTimer();
    }

    WindowWithTimer::~WindowWithTimer()
    {
        destroyInterface();
        detachTimerIfExists();
    }

    bool WindowWithTimer::onInput(const gui::InputEvent &inputEvent)
    {
        return false;
    }
} // namespace gui

A module-apps/popups/WindowWithTimer.hpp => module-apps/popups/WindowWithTimer.hpp +28 -0
@@ 0,0 1,28 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "AppWindow.hpp"
#include <module-sys/Timers/TimerHandle.hpp>

namespace gui
{
    inline constexpr auto defautTimeout = std::chrono::milliseconds{3000};
    class WindowWithTimer : public gui::AppWindow
    {
      private:
        sys::TimerHandle popupTimer;
        void resetTimer();
        void detachTimerIfExists();

      public:
        explicit WindowWithTimer(app::Application *app,
                                 const std::string &name,
                                 const std::chrono::milliseconds timeout = defautTimeout);
        void destroyInterface() override;
        ~WindowWithTimer() override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        bool onInput(const gui::InputEvent &inputEvent) override;
    };
} // namespace gui

A module-apps/popups/data/PopupData.hpp => module-apps/popups/data/PopupData.hpp +33 -0
@@ 0,0 1,33 @@

// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include <SwitchData.hpp>

namespace gui
{
    class VolumePopupData : public SwitchData
    {
        using AudioContext = std::pair<audio::Profile::Type, audio::PlaybackType>;

      public:
        explicit VolumePopupData(const audio::Volume volume, const AudioContext audioContext)
            : SwitchData(), volume{volume}, audioContext{audioContext}
        {}

        [[nodiscard]] auto getVolume() const noexcept -> audio::Volume
        {
            return volume;
        }

        [[nodiscard]] auto getAudioContext() const noexcept -> AudioContext
        {
            return audioContext;
        }

      private:
        const audio::Volume volume;
        const AudioContext audioContext;
    };
} // namespace gui

M module-apps/widgets/BarGraph.cpp => module-apps/widgets/BarGraph.cpp +5 -5
@@ 18,7 18,7 @@ namespace gui
        setValue(absoluteValue);
    }

    auto BarGraph::createRectangle(uint32_t width, uint32_t height) const -> Rect *
    auto BarGraph::createRectangle(std::uint32_t width, std::uint32_t height) const -> Rect *
    {
        auto rectangle = new Rect(nullptr, 0, 0, 0, 0);
        rectangle->setMinimumSize(width, height);


@@ 38,10 38,10 @@ namespace gui
        }

        currentLevel = value;
        for (unsigned int i = 0; i < currentLevel; i++) {
        for (std::uint32_t i = 0; i < currentLevel; i++) {
            rectangles[i]->setFillColor(ColorFullBlack);
        }
        for (unsigned int i = currentLevel; i < numberOfRectangles; i++) {
        for (std::uint32_t i = currentLevel; i < numberOfRectangles; i++) {
            rectangles[i]->setFillColor(ColorFullWhite);
        }



@@ 69,7 69,7 @@ namespace gui
            rectangles.clear();
        }

        for (unsigned int i = 0; i < numberOfRectangles; i++) {
        for (std::uint32_t i = 0; i < numberOfRectangles; i++) {

            auto rectangle =
                createRectangle(style::bargraph::rect_axis_length_lrg, style::bargraph::rect_axis_length_sml);


@@ 103,7 103,7 @@ namespace gui
            rectangles.clear();
        }

        for (unsigned int i = 0; i <= numberOfRectangles; i++) {
        for (std::uint32_t i = 0; i <= numberOfRectangles; i++) {

            auto rectangle =
                createRectangle(style::bargraph::rect_axis_length_sml, style::bargraph::rect_axis_length_lrg);

M module-apps/widgets/BarGraph.hpp => module-apps/widgets/BarGraph.hpp +4 -4
@@ 20,15 20,15 @@ namespace gui
    {
      protected:
        std::vector<gui::Rect *> rectangles;
        uint32_t numberOfRectangles;
        uint32_t currentLevel = 0;
        std::uint32_t numberOfRectangles;
        std::uint32_t currentLevel = 0;

        [[nodiscard]] auto createRectangle(uint32_t width, uint32_t height) const -> Rect *;
        [[nodiscard]] auto createRectangle(std::uint32_t width, std::uint32_t height) const -> Rect *;

      public:
        void setPercentageValue(unsigned int value) override;

        [[nodiscard]] auto getValue() const -> uint32_t
        [[nodiscard]] auto getValue() const -> std::uint32_t
        {
            return currentLevel;
        }

M module-services/service-appmgr/Controller.cpp => module-services/service-appmgr/Controller.cpp +0 -1
@@ 41,7 41,6 @@ namespace app::manager

    auto Controller::switchBack(sys::Service *sender, std::unique_ptr<SwitchBackRequest> msg) -> bool
    {

        std::shared_ptr<SwitchBackRequest> switchMsg =
            msg ? std::move(msg) : std::make_shared<app::manager::SwitchBackRequest>(sender->GetName());
        return sender->bus.sendUnicast(switchMsg, ApplicationManager::ServiceName);