diff options
author | Arsentiy Milchakov <milcars@mapswithme.com> | 2018-08-28 13:26:51 +0300 |
---|---|---|
committer | Tatiana Yan <tatiana.kondakova@gmail.com> | 2018-08-30 13:09:25 +0300 |
commit | 856f90dd0ca941b586264ad2f5cda9e046979c39 (patch) | |
tree | 68667d2ce550027e0124b135aa909d17049b5856 /map | |
parent | 6e77783f85d79d2b5e554f6eee10e54c1396e1a0 (diff) |
[tips] Tips are added
Diffstat (limited to 'map')
-rw-r--r-- | map/CMakeLists.txt | 2 | ||||
-rw-r--r-- | map/framework.cpp | 18 | ||||
-rw-r--r-- | map/framework.hpp | 15 | ||||
-rw-r--r-- | map/tips_api.cpp | 144 | ||||
-rw-r--r-- | map/tips_api.hpp | 44 |
5 files changed, 221 insertions, 2 deletions
diff --git a/map/CMakeLists.txt b/map/CMakeLists.txt index 667095dc12..98bb3e228d 100644 --- a/map/CMakeLists.txt +++ b/map/CMakeLists.txt @@ -94,6 +94,8 @@ set( subscription.hpp taxi_delegate.cpp taxi_delegate.hpp + tips_api.cpp + tips_api.hpp track.cpp track.hpp traffic_manager.cpp diff --git a/map/framework.cpp b/map/framework.cpp index 6aa632eacd..44b35bd789 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -3660,3 +3660,21 @@ booking::AvailabilityParams Framework::GetLastBookingAvailabilityParams() const { return m_bookingAvailabilityParams; } + +TipsApi const & Framework::GetTipsApi() const +{ + return m_tipsApi; +} + +bool Framework::HaveTransit(m2::PointD const & pt) const +{ + auto const & dataSource = m_model.GetDataSource(); + MwmSet::MwmId const mwmId = + dataSource.GetMwmIdByCountryFile(platform::CountryFile(m_infoGetter->GetRegionCountryId(pt))); + + MwmSet::MwmHandle handle = m_model.GetDataSource().GetMwmHandleById(mwmId); + if (!handle.IsAlive()) + return false; + + return handle.GetValue<MwmValue>()->m_cont.IsExist(TRANSIT_FILE_TAG); +} diff --git a/map/framework.hpp b/map/framework.hpp index 1e7c740cfe..6e403a64dd 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -16,6 +16,7 @@ #include "map/search_api.hpp" #include "map/search_mark.hpp" #include "map/subscription.hpp" +#include "map/tips_api.hpp" #include "map/track.hpp" #include "map/traffic_manager.hpp" #include "map/transit/transit_reader.hpp" @@ -57,6 +58,8 @@ #include "partners_api/taxi_engine.hpp" #include "partners_api/viator_api.hpp" +#include "eye/eye_info.hpp" + #include "platform/country_defines.hpp" #include "platform/location.hpp" #include "platform/platform.hpp" @@ -129,7 +132,9 @@ struct FrameworkParams {} }; -class Framework : public SearchAPI::Delegate, public RoutingManager::Delegate +class Framework : public SearchAPI::Delegate, + public RoutingManager::Delegate, + public TipsApi::Delegate { DISALLOW_COPY(Framework); @@ -283,7 +288,7 @@ public: void ShowNode(storage::TCountryId const & countryId); /// Checks, whether the country which contains the specified point is loaded. - bool IsCountryLoaded(m2::PointD const & pt) const; + bool IsCountryLoaded(m2::PointD const & pt) const override; /// Checks, whether the country is loaded. bool IsCountryLoadedByName(string const & name) const; //@} @@ -876,4 +881,10 @@ public: private: std::unique_ptr<Subscription> m_subscription; + TipsApi m_tipsApi; + +public: + TipsApi const & GetTipsApi() const; + + bool HaveTransit(m2::PointD const & pt) const override; }; diff --git a/map/tips_api.cpp b/map/tips_api.cpp new file mode 100644 index 0000000000..6d0bd8fed0 --- /dev/null +++ b/map/tips_api.cpp @@ -0,0 +1,144 @@ +#include "map/tips_api.hpp" + +#include "eye/eye.hpp" + +#include "platform/platform.hpp" + +#include <array> +#include <utility> + +using namespace eye; + +namespace +{ +// The app shouldn't show any screen at all more frequently than once in 3 days. +auto const kShowAnyTipPeriod = std::chrono::hours(24) * 3; +// The app shouldn't show the same screen more frequently than 1 month. +auto const kShowSameTipPeriod = std::chrono::hours(24) * 30; +// If a user clicks on the action areas (highlighted or blue button) +// the appropriate screen will never be shown again. +size_t const kActionClicksCountToDisable = 1; +// If a user clicks 3 times on the button GOT IT the appropriate screen will never be shown again. +size_t const kGotitClicksCountToDisable = 3; + +size_t ToIndex(Tips::Type type) +{ + return static_cast<size_t>(type); +} + +TipsApi::Tip GetTipImpl(TipsApi::Duration showAnyTipPeriod, TipsApi::Duration showSameTipPeriod, + TipsApi::Conditions const & triggers) +{ + auto const info = Eye::Instance().GetInfo(); + auto const & tips = info->m_tips; + auto const totalTipsCount = static_cast<size_t>(Tips::Type::Count); + + if (Clock::now() - tips.m_lastShown <= showAnyTipPeriod) + return {}; + + // If some tips are never shown. + if (tips.m_shownTips.size() < totalTipsCount) + { + using Candidate = std::pair<Tips::Type, bool>; + std::array<Candidate, totalTipsCount> candidates; + for (size_t i = 0; i < totalTipsCount; ++i) + { + candidates[i] = {static_cast<Tips::Type>(i), true}; + } + + for (auto const & shownTip : tips.m_shownTips) + { + candidates[ToIndex(shownTip.m_type)].second = false; + } + + for (auto const & c : candidates) + { + if (c.second && triggers[ToIndex(c.first)]()) + return c.first; + } + } + + for (auto const & shownTip : tips.m_shownTips) + { + if (shownTip.m_eventCounters.Get(Tips::Event::ActionClicked) < kActionClicksCountToDisable && + shownTip.m_eventCounters.Get(Tips::Event::GotitClicked) < kGotitClicksCountToDisable && + Clock::now() - shownTip.m_lastShown > showSameTipPeriod && + triggers[ToIndex(shownTip.m_type)]()) + { + return shownTip.m_type; + } + } + + return {}; +} +} // namespace + +// static +TipsApi::Duration TipsApi::GetShowAnyTipPeriod() +{ + return kShowAnyTipPeriod; +} + +// static +TipsApi::Duration TipsApi::GetShowSameTipPeriod() +{ + return kShowSameTipPeriod; +} + +// static +size_t TipsApi::GetActionClicksCountToDisable() +{ + return kActionClicksCountToDisable; +} + +// static +size_t TipsApi::GetGotitClicksCountToDisable() +{ + return kGotitClicksCountToDisable; +} + +TipsApi::TipsApi() +{ + m_conditions = + {{ + // Condition for Tips::Type::BookmarksCatalog type. + [] { return GetPlatform().ConnectionStatus() != Platform::EConnectionType::CONNECTION_NONE; }, + // Condition for Tips::Type::BookingHotels type. + [] { return true; }, + // Condition for Tips::Type::DiscoverButton type. + [this] + { + auto const pos = m_delegate->GetCurrentPosition(); + if (!pos.is_initialized()) + return false; + + return m_delegate->IsCountryLoaded(pos.get()); + }, + // Condition for Tips::Type::MapsLayers type. + [this] + { + auto const pos = m_delegate->GetCurrentPosition(); + if (!pos.is_initialized()) + return false; + + return m_delegate->HaveTransit(pos.get()); + } + }}; +} + +void TipsApi::SetDelegate(std::unique_ptr<Delegate> delegate) +{ + m_delegate = std::move(delegate); +} + +TipsApi::Tip TipsApi::GetTip() const +{ + return GetTipImpl(GetShowAnyTipPeriod(), GetShowSameTipPeriod(), m_conditions); +} + +// static +TipsApi::Tip TipsApi::GetTipForTesting(Duration showAnyTipPeriod, Duration showSameTipPeriod, + Conditions const & triggers) +{ + return GetTipImpl(showAnyTipPeriod, showSameTipPeriod, triggers); +} diff --git a/map/tips_api.hpp b/map/tips_api.hpp new file mode 100644 index 0000000000..a9ed04799d --- /dev/null +++ b/map/tips_api.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "eye/eye_info.hpp" + +#include <array> +#include <chrono> +#include <functional> +#include <memory> + +#include <boost/optional.hpp> + +class TipsApi +{ +public: + using Tip = boost::optional<eye::Tips::Type>; + using Duration = std::chrono::duration<uint64_t>; + using Condition = std::function<bool()>; + using Conditions = std::array<Condition, static_cast<size_t>(eye::Tips::Type::Count)>; + + class Delegate + { + public: + virtual boost::optional<m2::PointD> GetCurrentPosition() const = 0; + virtual bool IsCountryLoaded(m2::PointD const & pt) const = 0; + virtual bool HaveTransit(m2::PointD const & pt) const = 0; + }; + + static Duration GetShowAnyTipPeriod(); + static Duration GetShowSameTipPeriod(); + static size_t GetActionClicksCountToDisable(); + static size_t GetGotitClicksCountToDisable(); + + TipsApi(); + + void SetDelegate(std::unique_ptr<Delegate> delegate); + Tip GetTip() const; + + static Tip GetTipForTesting(Duration showAnyTipPeriod, Duration showSameTipPeriod, + Conditions const & triggers); + +private: + std::unique_ptr<Delegate> m_delegate; + Conditions m_conditions; +}; |