~aleteoryx/muditaos

f0fb9f51eff0b822a97019b0818c6853d3ad2e98 — KacperLewandowski 5 years ago 299be4d
[EGD-4103] Fix phone hanging when pressing '=' in calculator (#891)

Crush was caused when using std::to_string() on rt1051 to convert double (result from equation) to string.
Other methods f.e. using std::stringstream, sprintf also do not work.
Add own floating point converter to string.
M changelog.md => changelog.md +1 -0
@@ 21,6 21,7 @@

* `[GUI][messages]` Fixed not showing number on deleting temporary contact
* `[GUI]` Fixed filling Label with color
* `[calculator]` Fix phone hanging when pressing '='.

## [0.44.1 2020-10-30]


M module-apps/application-calculator/data/CalculatorUtility.cpp => module-apps/application-calculator/data/CalculatorUtility.cpp +2 -7
@@ 5,6 5,7 @@
#include "application-calculator/widgets/CalculatorStyle.hpp"
#include <module-utils/tinyexpr/tinyexpr.h>
#include <module-utils/i18/i18.hpp>
#include <Utils.hpp>
#include <cmath>

Result Calculator::calculate(std::string source)


@@ 13,13 14,7 @@ Result Calculator::calculate(std::string source)
    int error;
    double result = te_interp(source.c_str(), &error);
    if (error == 0 && !std::isinf(result) && !std::isnan(result)) {
        auto output = std::to_string(result);
        if (output.find_last_not_of('0') != std::string::npos) {
            output.erase(output.find_last_not_of('0') + 1);
        }
        if (output.find_last_not_of(style::calculator::symbols::strings::full_stop) != std::string::npos) {
            output.erase(output.find_last_not_of(style::calculator::symbols::strings::full_stop) + 1);
        }
        auto output = utils::to_string(result);
        if (utils::localize.get("app_calculator_decimal_separator") == style::calculator::symbols::strings::comma) {
            output.replace(output.find(style::calculator::symbols::strings::full_stop),
                           style::calculator::symbols::strings::full_stop.length(),

M module-apps/application-calculator/windows/CalculatorMainWindow.cpp => module-apps/application-calculator/windows/CalculatorMainWindow.cpp +4 -4
@@ 108,16 108,16 @@ namespace gui
        if (!mathOperationInput->getText().empty()) {

            if (lastCharIsSymbol && symbol != style::calculator::symbols::strings::minus) {
                mathOperationInput->setText(
                mathOperationInput->setRichText(
                    std::string(mathOperationInput->getText()).erase(mathOperationInput->getText().length() - 1) +
                    symbol.c_str());
            }
            else {
                mathOperationInput->setText(mathOperationInput->getText() + symbol);
                mathOperationInput->setRichText(mathOperationInput->getText() + symbol);
            }
        }
        else if (symbol == style::calculator::symbols::strings::minus) {
            mathOperationInput->setText(mathOperationInput->getText() + symbol);
            mathOperationInput->setRichText(mathOperationInput->getText() + symbol);
        }
    }



@@ 156,7 156,7 @@ namespace gui

        if (inputEvent.keyCode == gui::KeyCode::KEY_ENTER) {
            auto result = Calculator().calculate(std::string(mathOperationInput->getText()));
            mathOperationInput->setText(result.value);
            mathOperationInput->setRichText(result.value);
            clearInput = result.isError;
            return true;
        }

M module-utils/Utils.hpp => module-utils/Utils.hpp +51 -2
@@ 7,6 7,7 @@
#include <log/log.hpp>
#include <sstream>
#include <iomanip>
#include <cmath>

#define MAGIC_ENUM_RANGE_MAX 256
#include <magic_enum.hpp>


@@ 89,14 90,62 @@ namespace utils
        return rtrim(ltrim(s));
    }

    template <typename T> std::string to_string(T t, size_t minStringLength = 0)
    static inline std::string addLeadingZeros(std::string base, size_t minStringLength = 0)
    {
        if (base.length() >= minStringLength) {
            return base;
        }
        constexpr auto leadingDigit = '0';
        base.insert(0, minStringLength - base.length(), leadingDigit);
        return base;
    }

    template <typename T> std::string to_string(T t)
    {
        std::ostringstream ss;
        ss << std::setfill(leadingDigit) << std::setw(minStringLength) << t;
        ss << t;
        return ss.str();
    }

    template <> inline std::string to_string<long double>(long double t)
    {
        uint32_t precision = 6;
        int base           = static_cast<int>(t);
        long double frac   = (t - base) * pow(10, precision);
        auto baseAsStr     = std::to_string(base);
        if (t < 0) {
            frac *= -1;
            if (base == 0) {
                baseAsStr = "-0";
            }
        }
        auto fractionalPart = static_cast<unsigned long int>(roundl(frac));
        if (fractionalPart == 0) {
            if (baseAsStr == "-0") {
                return "0";
            }
            return baseAsStr;
        }
        auto fractionalAsStr = std::to_string(fractionalPart);
        if (fractionalAsStr.size() < precision) {
            fractionalAsStr.insert(0, precision - fractionalAsStr.size(), '0');
        }
        if (fractionalAsStr.find_last_not_of('0') != std::string::npos) {
            fractionalAsStr.erase(fractionalAsStr.find_last_not_of('0') + 1);
        }
        return baseAsStr + "." + fractionalAsStr;
    }

    template <> inline std::string to_string<float>(float t)
    {
        return to_string((long double)(t));
    }

    template <> inline std::string to_string<double>(double t)
    {
        return to_string((long double)(t));
    }

    template <typename T>[[nodiscard]] const std::string enumToString(const T &t)
    {
        static_assert(std::is_enum_v<T>);

M module-utils/test/unittest_utils.cpp => module-utils/test/unittest_utils.cpp +61 -0
@@ 208,3 208,64 @@ TEST_CASE("Swap endianness")
        REQUIRE(((as_long >> 8 * 0) & 0xFF) == ((as_long_swapped >> 8 * 3) & 0xFF));
    }
}

TEST_CASE("Floating point to string")
{
    SECTION("Double")
    {
        double test = 15.0965432456321;
        REQUIRE(utils::to_string(test) == "15.096543");
    }

    SECTION("Negative double")
    {
        double test = -15.0965432456321;
        REQUIRE(utils::to_string(test) == "-15.096543");
    }

    SECTION("Double between 0 and 1")
    {
        double test = 0.08654328765876;
        REQUIRE(utils::to_string(test) == "0.086543");
    }

    SECTION("Double between -1 and 0")
    {
        double test = -0.08654328765876;
        REQUIRE(utils::to_string(test) == "-0.086543");
    }

    SECTION("Float")
    {
        float test = 15.0543212;
        REQUIRE(utils::to_string(test) == "15.054321");
    }

    SECTION("Negative float")
    {
        float test = -15.0543212;
        REQUIRE(utils::to_string(test) == "-15.054321");
    }

    SECTION("Float between 0 and 1")
    {
        float test = 0.0453212;
        REQUIRE(utils::to_string(test) == "0.045321");
    }

    SECTION("Float between -1 and 0")
    {
        float test = -0.0453212;
        REQUIRE(utils::to_string(test) == "-0.045321");
    }
}

TEST_CASE("Fill leading digit in string")
{
    std::string test = "45";
    REQUIRE(utils::addLeadingZeros(test) == "45");
    REQUIRE(utils::addLeadingZeros(test, 1) == "45");
    REQUIRE(utils::addLeadingZeros(test, 2) == "45");
    REQUIRE(utils::addLeadingZeros(test, 3) == "045");
    REQUIRE(utils::addLeadingZeros(test, 4) == "0045");
}

M module-utils/time/time_conversion.cpp => module-utils/time/time_conversion.cpp +8 -4
@@ 264,10 264,14 @@ namespace utils
            utils::findAndReplaceAll(format, "%M", utils::to_string(minutes));
            utils::findAndReplaceAll(format, "%N", utils::to_string(hmminutes));
            utils::findAndReplaceAll(format, "%S", utils::to_string(seconds));
            utils::findAndReplaceAll(format, "%0H", utils::to_string(hours, numberOfLeadingDigits));
            utils::findAndReplaceAll(format, "%0M", utils::to_string(minutes, numberOfLeadingDigits));
            utils::findAndReplaceAll(format, "%0N", utils::to_string(hmminutes, numberOfLeadingDigits));
            utils::findAndReplaceAll(format, "%0S", utils::to_string(seconds, numberOfLeadingDigits));
            utils::findAndReplaceAll(
                format, "%0H", utils::addLeadingZeros(utils::to_string(hours), numberOfLeadingDigits));
            utils::findAndReplaceAll(
                format, "%0M", utils::addLeadingZeros(utils::to_string(minutes), numberOfLeadingDigits));
            utils::findAndReplaceAll(
                format, "%0N", utils::addLeadingZeros(utils::to_string(hmminutes), numberOfLeadingDigits));
            utils::findAndReplaceAll(
                format, "%0S", utils::addLeadingZeros(utils::to_string(seconds), numberOfLeadingDigits));
        }

        void Duration::calculate()