forked from organicmaps/organicmaps
[eye][tips] Additional requirements are supported
This commit is contained in:
parent
7af77c0e44
commit
2ac5023f78
11 changed files with 533 additions and 32 deletions
|
@ -363,7 +363,6 @@ Framework::Framework(FrameworkParams const & params)
|
|||
bind(&Framework::GetMwmIdByName, this, _1),
|
||||
bind(&Framework::ReadFeatures, this, _1, _2),
|
||||
bind(&Framework::GetFeatureByID, this, _1, _2))
|
||||
, m_startForegroundTime(0.0)
|
||||
, m_storage(platform::migrate::NeedMigrate() ? COUNTRIES_OBSOLETE_FILE : COUNTRIES_FILE)
|
||||
, m_enabledDiffs(params.m_enableDiffs)
|
||||
, m_isRenderingEnabled(true)
|
||||
|
@ -392,8 +391,6 @@ Framework::Framework(FrameworkParams const & params)
|
|||
, m_subscription(std::make_unique<Subscription>())
|
||||
, m_tipsApi(static_cast<TipsApi::Delegate &>(*this))
|
||||
{
|
||||
m_startBackgroundTime = my::Timer::LocalTime();
|
||||
|
||||
// Editor should be initialized from the main thread to set its ThreadChecker.
|
||||
// However, search calls editor upon initialization thus setting the lazy editor's ThreadChecker
|
||||
// to a wrong thread. So editor should be initialiazed before serach.
|
||||
|
@ -1353,7 +1350,7 @@ void Framework::EnterBackground()
|
|||
void Framework::EnterForeground()
|
||||
{
|
||||
m_startForegroundTime = my::Timer::LocalTime();
|
||||
if (m_drapeEngine != nullptr)
|
||||
if (m_drapeEngine != nullptr && m_startBackgroundTime != 0.0)
|
||||
{
|
||||
auto const timeInBackground = m_startForegroundTime - m_startBackgroundTime;
|
||||
m_drapeEngine->SetTimeInBackground(timeInBackground);
|
||||
|
@ -3680,3 +3677,8 @@ bool Framework::HaveTransit(m2::PointD const & pt) const
|
|||
|
||||
return handle.GetValue<MwmValue>()->m_cont.IsExist(TRANSIT_FILE_TAG);
|
||||
}
|
||||
|
||||
double Framework::GetLastBackgroundTime() const
|
||||
{
|
||||
return m_startBackgroundTime;
|
||||
}
|
||||
|
|
|
@ -193,8 +193,8 @@ protected:
|
|||
|
||||
drape_ptr<df::DrapeEngine> m_drapeEngine;
|
||||
|
||||
double m_startForegroundTime;
|
||||
double m_startBackgroundTime;
|
||||
double m_startForegroundTime = 0.0;
|
||||
double m_startBackgroundTime = 0.0;
|
||||
|
||||
StorageDownloadingPolicy m_storageDownloadingPolicy;
|
||||
storage::Storage m_storage;
|
||||
|
@ -890,4 +890,5 @@ public:
|
|||
|
||||
// TipsApi::Delegate override.
|
||||
bool HaveTransit(m2::PointD const & pt) const override;
|
||||
double GetLastBackgroundTime() const override;
|
||||
};
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#include "metrics/metrics_tests_support/eye_for_testing.hpp"
|
||||
|
||||
#include "metrics/eye.hpp"
|
||||
#include "metrics/eye_info.hpp"
|
||||
|
||||
#include "base/timer.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
@ -15,6 +18,30 @@ using namespace eye;
|
|||
|
||||
namespace
|
||||
{
|
||||
class TipsApiDelegate : public TipsApi::Delegate
|
||||
{
|
||||
public:
|
||||
void SetLastBackgroundTime(double lastBackgroundTime)
|
||||
{
|
||||
m_lastBackgroundTime = lastBackgroundTime;
|
||||
}
|
||||
|
||||
// TipsApi::Delegate overrides:
|
||||
boost::optional<m2::PointD> GetCurrentPosition() const override
|
||||
{
|
||||
return boost::optional<m2::PointD>();
|
||||
}
|
||||
|
||||
bool IsCountryLoaded(m2::PointD const & pt) const override { return false; }
|
||||
|
||||
bool HaveTransit(m2::PointD const & pt) const override { return false; }
|
||||
|
||||
double GetLastBackgroundTime() const override { return m_lastBackgroundTime; }
|
||||
|
||||
private:
|
||||
double m_lastBackgroundTime = 0.0;
|
||||
};
|
||||
|
||||
void MakeLastShownTipAvailableByTime()
|
||||
{
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
|
@ -26,26 +53,27 @@ void MakeLastShownTipAvailableByTime()
|
|||
}
|
||||
|
||||
boost::optional<eye::Tip::Type> GetTipForTesting(TipsApi::Duration showAnyTipPeriod,
|
||||
TipsApi::Duration showSameTipPeriod)
|
||||
TipsApi::Duration showSameTipPeriod,
|
||||
TipsApiDelegate const & delegate)
|
||||
{
|
||||
// Do not use additional conditions for testing.
|
||||
TipsApi::Conditions conditions =
|
||||
{{
|
||||
// Condition for Tips::Type::BookmarksCatalog type.
|
||||
[] { return true; },
|
||||
[] (eye::Info const & info) { return true; },
|
||||
// Condition for Tips::Type::BookingHotels type.
|
||||
[] { return true; },
|
||||
[] (eye::Info const & info) { return true; },
|
||||
// Condition for Tips::Type::DiscoverButton type.
|
||||
[] { return true; },
|
||||
[] (eye::Info const & info) { return true; },
|
||||
// Condition for Tips::Type::MapsLayers type.
|
||||
[] { return true; }
|
||||
[] (eye::Info const & info) { return true; }
|
||||
}};
|
||||
return TipsApi::GetTipForTesting(showAnyTipPeriod, showSameTipPeriod, conditions);
|
||||
return TipsApi::GetTipForTesting(showAnyTipPeriod, showSameTipPeriod, delegate, conditions);
|
||||
}
|
||||
|
||||
boost::optional<eye::Tip::Type> GetTipForTesting()
|
||||
{
|
||||
return GetTipForTesting(TipsApi::GetShowAnyTipPeriod(), TipsApi::GetShowSameTipPeriod());
|
||||
return GetTipForTesting(TipsApi::GetShowAnyTipPeriod(), TipsApi::GetShowSameTipPeriod(), {});
|
||||
}
|
||||
|
||||
void ShowTipWithClickCountTest(Tip::Event eventType, size_t maxClickCount)
|
||||
|
@ -114,7 +142,7 @@ UNIT_CLASS_TEST(ScopedEyeForTesting, ShowFirstTip_Test)
|
|||
|
||||
for (size_t i = 0; i < totalTipsCount; ++i)
|
||||
{
|
||||
auto tip = GetTipForTesting({}, TipsApi::GetShowSameTipPeriod());
|
||||
auto tip = GetTipForTesting({}, TipsApi::GetShowSameTipPeriod(), {});
|
||||
|
||||
TEST(tip.is_initialized(), ());
|
||||
TEST_NOT_EQUAL(tip.get(), Tip::Type::Count, ());
|
||||
|
@ -145,4 +173,15 @@ UNIT_CLASS_TEST(ScopedEyeForTesting, ShowTipAndGotitClicked_Test)
|
|||
{
|
||||
ShowTipWithClickCountTest(Tip::Event::GotitClicked, TipsApi::GetGotitClicksCountToDisable());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(ScopedEyeForTesting, ShowTipAfterWarmStart)
|
||||
{
|
||||
TipsApiDelegate d;
|
||||
d.SetLastBackgroundTime(my::Timer::LocalTime());
|
||||
auto tip = GetTipForTesting({}, TipsApi::GetShowSameTipPeriod(), d);
|
||||
TEST(!tip.is_initialized(), ());
|
||||
d.SetLastBackgroundTime(my::Timer::LocalTime() - TipsApi::ShowTipAfterCollapsingPeriod().count());
|
||||
tip = GetTipForTesting({}, TipsApi::GetShowSameTipPeriod(), d);
|
||||
TEST(tip.is_initialized(), ());
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "base/timer.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
using namespace eye;
|
||||
|
@ -14,21 +17,35 @@ namespace
|
|||
auto constexpr kShowAnyTipPeriod = std::chrono::hours(24) * 3;
|
||||
// The app shouldn't show the same screen more frequently than 1 month.
|
||||
auto constexpr kShowSameTipPeriod = std::chrono::hours(24) * 30;
|
||||
// Every current trigger for a tips screen can be activated at the start of the application by
|
||||
// default and if the app was inactive more then 12 hours.
|
||||
auto constexpr kShowTipAfterCollapsingPeriod = std::chrono::seconds(12 * 60 * 60);
|
||||
// If a user clicks on the action areas (highlighted or blue button)
|
||||
// the appropriate screen will never be shown again.
|
||||
size_t constexpr kActionClicksCountToDisable = 1;
|
||||
// If a user clicks 3 times on the button GOT IT the appropriate screen will never be shown again.
|
||||
size_t constexpr kGotitClicksCountToDisable = 3;
|
||||
|
||||
size_t ToIndex(Tip::Type type)
|
||||
template <typename T, std::enable_if_t<std::is_enum<T>::value> * = nullptr>
|
||||
size_t ToIndex(T type)
|
||||
{
|
||||
return static_cast<size_t>(type);
|
||||
}
|
||||
|
||||
boost::optional<eye::Tip::Type> GetTipImpl(TipsApi::Duration showAnyTipPeriod,
|
||||
TipsApi::Duration showSameTipPeriod,
|
||||
TipsApi::Conditions const & triggers)
|
||||
TipsApi::Delegate const & delegate,
|
||||
TipsApi::Conditions const & conditions)
|
||||
{
|
||||
auto const lastBackgroundTime = delegate.GetLastBackgroundTime();
|
||||
if (lastBackgroundTime != 0.0)
|
||||
{
|
||||
auto const timeInBackground =
|
||||
static_cast<uint64_t>(my::Timer::LocalTime() - lastBackgroundTime);
|
||||
if (timeInBackground < kShowTipAfterCollapsingPeriod.count())
|
||||
return {};
|
||||
}
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & tips = info->m_tips;
|
||||
auto constexpr totalTipsCount = static_cast<size_t>(Tip::Type::Count);
|
||||
|
@ -60,7 +77,7 @@ boost::optional<eye::Tip::Type> GetTipImpl(TipsApi::Duration showAnyTipPeriod,
|
|||
|
||||
for (auto const & c : candidates)
|
||||
{
|
||||
if (c.second && triggers[ToIndex(c.first)]())
|
||||
if (c.second && conditions[ToIndex(c.first)](*info))
|
||||
return c.first;
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +87,7 @@ boost::optional<eye::Tip::Type> GetTipImpl(TipsApi::Duration showAnyTipPeriod,
|
|||
if (shownTip.m_eventCounters.Get(Tip::Event::ActionClicked) < kActionClicksCountToDisable &&
|
||||
shownTip.m_eventCounters.Get(Tip::Event::GotitClicked) < kGotitClicksCountToDisable &&
|
||||
Clock::now() - shownTip.m_lastShownTime > showSameTipPeriod &&
|
||||
triggers[ToIndex(shownTip.m_type)]())
|
||||
conditions[ToIndex(shownTip.m_type)](*info))
|
||||
{
|
||||
return shownTip.m_type;
|
||||
}
|
||||
|
@ -92,6 +109,12 @@ TipsApi::Duration TipsApi::GetShowSameTipPeriod()
|
|||
return kShowSameTipPeriod;
|
||||
}
|
||||
|
||||
// static
|
||||
TipsApi::Duration TipsApi::ShowTipAfterCollapsingPeriod()
|
||||
{
|
||||
return kShowTipAfterCollapsingPeriod;
|
||||
};
|
||||
|
||||
// static
|
||||
size_t TipsApi::GetActionClicksCountToDisable()
|
||||
{
|
||||
|
@ -110,12 +133,26 @@ TipsApi::TipsApi(Delegate const & delegate)
|
|||
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]
|
||||
[] (eye::Info const & info)
|
||||
{
|
||||
return info.m_bookmarks.m_lastOpenedTime.time_since_epoch().count() == 0 &&
|
||||
GetPlatform().ConnectionStatus() != Platform::EConnectionType::CONNECTION_NONE;
|
||||
},
|
||||
// Condition for Tips::Type::BookingHotels type.
|
||||
[] (eye::Info const & info)
|
||||
{
|
||||
return info.m_booking.m_lastFilterUsedTime.time_since_epoch().count() == 0;
|
||||
},
|
||||
// Condition for Tips::Type::DiscoverButton type.
|
||||
[this] (eye::Info const & info)
|
||||
{
|
||||
auto const eventsCount = ToIndex(Discovery::Event::Count);
|
||||
for (size_t i = 0; i < eventsCount; ++i)
|
||||
{
|
||||
if (info.m_discovery.m_eventCounters.Get(static_cast<Discovery::Event>(i)) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const pos = m_delegate.GetCurrentPosition();
|
||||
if (!pos.is_initialized())
|
||||
return false;
|
||||
|
@ -123,8 +160,17 @@ TipsApi::TipsApi(Delegate const & delegate)
|
|||
return m_delegate.IsCountryLoaded(pos.get());
|
||||
},
|
||||
// Condition for Tips::Type::MapsLayers type.
|
||||
[this]
|
||||
[this] (eye::Info const & info)
|
||||
{
|
||||
for (auto const & layer : info.m_layers)
|
||||
{
|
||||
if (layer.m_type == Layer::PublicTransport &&
|
||||
layer.m_lastTimeUsed.time_since_epoch().count() != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto const pos = m_delegate.GetCurrentPosition();
|
||||
if (!pos.is_initialized())
|
||||
return false;
|
||||
|
@ -136,13 +182,14 @@ TipsApi::TipsApi(Delegate const & delegate)
|
|||
|
||||
boost::optional<eye::Tip::Type> TipsApi::GetTip() const
|
||||
{
|
||||
return GetTipImpl(GetShowAnyTipPeriod(), GetShowSameTipPeriod(), m_conditions);
|
||||
return GetTipImpl(GetShowAnyTipPeriod(), GetShowSameTipPeriod(), m_delegate, m_conditions);
|
||||
}
|
||||
|
||||
// static
|
||||
boost::optional<eye::Tip::Type> TipsApi::GetTipForTesting(Duration showAnyTipPeriod,
|
||||
Duration showSameTipPeriod,
|
||||
TipsApi::Delegate const & delegate,
|
||||
Conditions const & triggers)
|
||||
{
|
||||
return GetTipImpl(showAnyTipPeriod, showSameTipPeriod, triggers);
|
||||
return GetTipImpl(showAnyTipPeriod, showSameTipPeriod, delegate, triggers);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ class TipsApi
|
|||
{
|
||||
public:
|
||||
using Duration = std::chrono::duration<uint64_t>;
|
||||
using Condition = std::function<bool()>;
|
||||
using Condition = std::function<bool(eye::Info const & info)>;
|
||||
using Conditions = std::array<Condition, static_cast<size_t>(eye::Tip::Type::Count)>;
|
||||
|
||||
class Delegate
|
||||
|
@ -27,10 +27,12 @@ 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;
|
||||
virtual double GetLastBackgroundTime() const = 0;
|
||||
};
|
||||
|
||||
static Duration GetShowAnyTipPeriod();
|
||||
static Duration GetShowSameTipPeriod();
|
||||
static Duration ShowTipAfterCollapsingPeriod();
|
||||
static size_t GetActionClicksCountToDisable();
|
||||
static size_t GetGotitClicksCountToDisable();
|
||||
|
||||
|
@ -40,6 +42,7 @@ public:
|
|||
|
||||
static boost::optional<eye::Tip::Type> GetTipForTesting(Duration showAnyTipPeriod,
|
||||
Duration showSameTipPeriod,
|
||||
TipsApi::Delegate const & delegate,
|
||||
Conditions const & triggers);
|
||||
|
||||
private:
|
||||
|
|
115
metrics/eye.cpp
115
metrics/eye.cpp
|
@ -100,6 +100,76 @@ void Eye::AppendTip(Tip::Type type, Tip::Event event)
|
|||
Save(editableInfo);
|
||||
}
|
||||
|
||||
void Eye::UpdateBookingFilterUsedTime()
|
||||
{
|
||||
auto const info = m_info.Get();
|
||||
auto editableInfo = std::make_shared<Info>(*info);
|
||||
|
||||
editableInfo->m_booking.m_lastFilterUsedTime = Clock::now();
|
||||
|
||||
Save(editableInfo);
|
||||
}
|
||||
|
||||
void Eye::UpdateBoomarksCatalogShownTime()
|
||||
{
|
||||
auto const info = m_info.Get();
|
||||
auto editableInfo = std::make_shared<Info>(*info);
|
||||
|
||||
editableInfo->m_bookmarks.m_lastOpenedTime = Clock::now();
|
||||
|
||||
Save(editableInfo);
|
||||
}
|
||||
|
||||
void Eye::UpdateDiscoveryShownTime()
|
||||
{
|
||||
auto const info = m_info.Get();
|
||||
auto editableInfo = std::make_shared<Info>(*info);
|
||||
|
||||
editableInfo->m_discovery.m_lastOpenedTime = Clock::now();
|
||||
|
||||
Save(editableInfo);
|
||||
}
|
||||
|
||||
void Eye::IncrementDiscoveryItem(Discovery::Event event)
|
||||
{
|
||||
auto const info = m_info.Get();
|
||||
auto editableInfo = std::make_shared<Info>(*info);
|
||||
|
||||
editableInfo->m_discovery.m_lastClickedTime = Clock::now();
|
||||
editableInfo->m_discovery.m_eventCounters.Increment(event);
|
||||
|
||||
Save(editableInfo);
|
||||
}
|
||||
|
||||
void Eye::AppendLayer(Layer::Type type)
|
||||
{
|
||||
auto const info = m_info.Get();
|
||||
auto editableInfo = std::make_shared<Info>(*info);
|
||||
auto & editableLayers = editableInfo->m_layers;
|
||||
|
||||
auto it = std::find_if(editableLayers.begin(), editableLayers.end(), [type](Layer const & layer)
|
||||
{
|
||||
return layer.m_type == type;
|
||||
});
|
||||
|
||||
if (it != editableLayers.end())
|
||||
{
|
||||
++it->m_useCount;
|
||||
it->m_lastTimeUsed = Clock::now();
|
||||
}
|
||||
else
|
||||
{
|
||||
Layer layer;
|
||||
layer.m_type = type;
|
||||
|
||||
++layer.m_useCount;
|
||||
layer.m_lastTimeUsed = Clock::now();
|
||||
editableLayers.emplace_back(std::move(layer));
|
||||
}
|
||||
|
||||
Save(editableInfo);
|
||||
}
|
||||
|
||||
// Eye::Event methods ------------------------------------------------------------------------------
|
||||
// static
|
||||
void Eye::Event::TipShown(Tip::Type type, Tip::Event event)
|
||||
|
@ -109,4 +179,49 @@ void Eye::Event::TipShown(Tip::Type type, Tip::Event event)
|
|||
Instance().AppendTip(type, event);
|
||||
});
|
||||
}
|
||||
|
||||
// static
|
||||
void Eye::Event::BookingFilterUsed()
|
||||
{
|
||||
GetPlatform().RunTask(Platform::Thread::File, []
|
||||
{
|
||||
Instance().UpdateBookingFilterUsedTime();
|
||||
});
|
||||
}
|
||||
|
||||
// static
|
||||
void Eye::Event::BoomarksCatalogShown()
|
||||
{
|
||||
GetPlatform().RunTask(Platform::Thread::File, []
|
||||
{
|
||||
Instance().UpdateBoomarksCatalogShownTime();
|
||||
});
|
||||
}
|
||||
|
||||
// static
|
||||
void Eye::Event::DiscoveryShown()
|
||||
{
|
||||
GetPlatform().RunTask(Platform::Thread::File, []
|
||||
{
|
||||
Instance().UpdateDiscoveryShownTime();
|
||||
});
|
||||
}
|
||||
|
||||
// static
|
||||
void Eye::Event::DiscoveryItemClicked(Discovery::Event event)
|
||||
{
|
||||
GetPlatform().RunTask(Platform::Thread::File, [event]
|
||||
{
|
||||
Instance().IncrementDiscoveryItem(event);
|
||||
});
|
||||
}
|
||||
|
||||
// static
|
||||
void Eye::Event::LayerUsed(Layer::Type type)
|
||||
{
|
||||
GetPlatform().RunTask(Platform::Thread::File, [type]
|
||||
{
|
||||
Instance().AppendLayer(type);
|
||||
});
|
||||
}
|
||||
} // namespace eye
|
||||
|
|
|
@ -21,6 +21,11 @@ public:
|
|||
{
|
||||
public:
|
||||
static void TipShown(Tip::Type type, Tip::Event event);
|
||||
static void BookingFilterUsed();
|
||||
static void BoomarksCatalogShown();
|
||||
static void DiscoveryShown();
|
||||
static void DiscoveryItemClicked(Discovery::Event event);
|
||||
static void LayerUsed(Layer::Type type);
|
||||
};
|
||||
|
||||
static Eye & Instance();
|
||||
|
@ -34,6 +39,11 @@ private:
|
|||
|
||||
// Event processing:
|
||||
void AppendTip(Tip::Type type, Tip::Event event);
|
||||
void UpdateBookingFilterUsedTime();
|
||||
void UpdateBoomarksCatalogShownTime();
|
||||
void UpdateDiscoveryShownTime();
|
||||
void IncrementDiscoveryItem(Discovery::Event event);
|
||||
void AppendLayer(Layer::Type type);
|
||||
|
||||
base::AtomicSharedPtr<Info> m_info;
|
||||
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
#include "base/visitor.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace eye
|
||||
|
@ -67,6 +68,64 @@ enum class Version : int8_t
|
|||
using Clock = std::chrono::system_clock;
|
||||
using Time = Clock::time_point;
|
||||
|
||||
struct Booking
|
||||
{
|
||||
DECLARE_VISITOR(visitor(m_lastFilterUsedTime, "last_filter_used_time"))
|
||||
|
||||
Time m_lastFilterUsedTime;
|
||||
};
|
||||
|
||||
struct Bookmarks
|
||||
{
|
||||
DECLARE_VISITOR(visitor(m_lastOpenedTime, "last_use_time"))
|
||||
|
||||
Time m_lastOpenedTime;
|
||||
};
|
||||
|
||||
struct Discovery
|
||||
{
|
||||
enum class Event
|
||||
{
|
||||
HotelsClicked,
|
||||
AttractionsClicked,
|
||||
CafesClicked,
|
||||
LocalsClicked,
|
||||
|
||||
MoreHotelsClicked,
|
||||
MoreAttractionsClicked,
|
||||
MoreCafesClicked,
|
||||
MoreLocalsClicked,
|
||||
|
||||
Count
|
||||
};
|
||||
|
||||
DECLARE_VISITOR(visitor(m_eventCounters, "event_counters"),
|
||||
visitor(m_lastOpenedTime, "last_opened_time"),
|
||||
visitor(m_lastClickedTime, "last_clicked_time"))
|
||||
|
||||
Counters<Event, uint32_t> m_eventCounters;
|
||||
Time m_lastOpenedTime;
|
||||
Time m_lastClickedTime;
|
||||
};
|
||||
|
||||
struct Layer
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
TrafficJams,
|
||||
PublicTransport
|
||||
};
|
||||
|
||||
DECLARE_VISITOR(visitor(m_type, "type"), visitor(m_useCount, "use_count"),
|
||||
visitor(m_lastTimeUsed, "last_time_used"))
|
||||
|
||||
Type m_type;
|
||||
uint64_t m_useCount = 0;
|
||||
Time m_lastTimeUsed;
|
||||
};
|
||||
|
||||
using Layers = std::vector<Layer>;
|
||||
|
||||
struct Tip
|
||||
{
|
||||
// The order is important.
|
||||
|
@ -102,8 +161,14 @@ using Tips = std::vector<Tip>;
|
|||
struct InfoV0
|
||||
{
|
||||
static Version GetVersion() { return Version::V0; }
|
||||
DECLARE_VISITOR(visitor(m_tips, "tips"))
|
||||
DECLARE_VISITOR(visitor(m_booking, "booking"), visitor(m_bookmarks, "bookmarks"),
|
||||
visitor(m_discovery, "discovery"), visitor(m_layers, "layers"),
|
||||
visitor(m_tips, "tips"))
|
||||
|
||||
Booking m_booking;
|
||||
Bookmarks m_bookmarks;
|
||||
Discovery m_discovery;
|
||||
Layers m_layers;
|
||||
Tips m_tips;
|
||||
};
|
||||
|
||||
|
|
|
@ -50,6 +50,18 @@ Time GetLastShownTipTime(Tips const & tips)
|
|||
|
||||
return lastShownTime;
|
||||
}
|
||||
|
||||
Time GetLastShownLayerTime(Layers const & layers)
|
||||
{
|
||||
Time lastUsedTime;
|
||||
for (auto const & layer : layers)
|
||||
{
|
||||
if (lastUsedTime < layer.m_lastTimeUsed)
|
||||
lastUsedTime = layer.m_lastTimeUsed;
|
||||
}
|
||||
|
||||
return lastUsedTime;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(Eye_SerdesTest)
|
||||
|
@ -139,3 +151,175 @@ UNIT_CLASS_TEST(ScopedEyeForTesting, AppendTipTest)
|
|||
TEST_NOT_EQUAL(prevShowTime, lastShownTipTime, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(ScopedEyeForTesting, UpdateBookingFilterUsedTimeTest)
|
||||
{
|
||||
auto const initialInfo = Eye::Instance().GetInfo();
|
||||
auto const & initialBooking = initialInfo->m_booking;
|
||||
|
||||
TEST_EQUAL(initialBooking.m_lastFilterUsedTime, Time(), ());
|
||||
|
||||
EyeForTesting::UpdateBookingFilterUsedTime();
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & booking = info->m_booking;
|
||||
|
||||
TEST_NOT_EQUAL(initialBooking.m_lastFilterUsedTime, booking.m_lastFilterUsedTime, ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(ScopedEyeForTesting, UpdateBoomarksCatalogShownTimeTest)
|
||||
{
|
||||
auto const initialInfo = Eye::Instance().GetInfo();
|
||||
auto const & initialBookmarks = initialInfo->m_bookmarks;
|
||||
|
||||
TEST_EQUAL(initialBookmarks.m_lastOpenedTime, Time(), ());
|
||||
|
||||
EyeForTesting::UpdateBoomarksCatalogShownTime();
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & bookmarks = info->m_bookmarks;
|
||||
|
||||
TEST_NOT_EQUAL(initialBookmarks.m_lastOpenedTime, bookmarks.m_lastOpenedTime, ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(ScopedEyeForTesting, UpdateDiscoveryShownTimeTest)
|
||||
{
|
||||
auto const initialInfo = Eye::Instance().GetInfo();
|
||||
auto const & initialDiscovery = initialInfo->m_discovery;
|
||||
|
||||
TEST_EQUAL(initialDiscovery.m_lastOpenedTime, Time(), ());
|
||||
|
||||
EyeForTesting::UpdateDiscoveryShownTime();
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & discovery = info->m_discovery;
|
||||
|
||||
TEST_NOT_EQUAL(initialDiscovery.m_lastOpenedTime, discovery.m_lastOpenedTime, ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(ScopedEyeForTesting, IncrementDiscoveryItemTest)
|
||||
{
|
||||
auto const initialInfo = Eye::Instance().GetInfo();
|
||||
auto const & initialDiscovery = initialInfo->m_discovery;
|
||||
|
||||
TEST_EQUAL(initialDiscovery.m_lastClickedTime, Time(), ());
|
||||
TEST_EQUAL(initialDiscovery.m_eventCounters.Get(Discovery::Event::AttractionsClicked), 0, ());
|
||||
TEST_EQUAL(initialDiscovery.m_eventCounters.Get(Discovery::Event::CafesClicked), 0, ());
|
||||
TEST_EQUAL(initialDiscovery.m_eventCounters.Get(Discovery::Event::HotelsClicked), 0, ());
|
||||
TEST_EQUAL(initialDiscovery.m_eventCounters.Get(Discovery::Event::LocalsClicked), 0, ());
|
||||
TEST_EQUAL(initialDiscovery.m_eventCounters.Get(Discovery::Event::MoreAttractionsClicked), 0, ());
|
||||
TEST_EQUAL(initialDiscovery.m_eventCounters.Get(Discovery::Event::MoreCafesClicked), 0, ());
|
||||
TEST_EQUAL(initialDiscovery.m_eventCounters.Get(Discovery::Event::MoreHotelsClicked), 0, ());
|
||||
TEST_EQUAL(initialDiscovery.m_eventCounters.Get(Discovery::Event::MoreLocalsClicked), 0, ());
|
||||
|
||||
{
|
||||
EyeForTesting::IncrementDiscoveryItem(Discovery::Event::CafesClicked);
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & discovery = info->m_discovery;
|
||||
|
||||
TEST_NOT_EQUAL(initialDiscovery.m_lastClickedTime, discovery.m_lastClickedTime, ());
|
||||
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::AttractionsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::CafesClicked), 1, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::HotelsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::LocalsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreAttractionsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreCafesClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreHotelsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreLocalsClicked), 0, ());
|
||||
}
|
||||
|
||||
{
|
||||
EyeForTesting::IncrementDiscoveryItem(Discovery::Event::CafesClicked);
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & discovery = info->m_discovery;
|
||||
|
||||
TEST_NOT_EQUAL(initialDiscovery.m_lastClickedTime, discovery.m_lastClickedTime, ());
|
||||
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::AttractionsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::CafesClicked), 2, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::HotelsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::LocalsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreAttractionsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreCafesClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreHotelsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreLocalsClicked), 0, ());
|
||||
}
|
||||
|
||||
{
|
||||
EyeForTesting::IncrementDiscoveryItem(Discovery::Event::CafesClicked);
|
||||
EyeForTesting::IncrementDiscoveryItem(Discovery::Event::HotelsClicked);
|
||||
EyeForTesting::IncrementDiscoveryItem(Discovery::Event::MoreLocalsClicked);
|
||||
EyeForTesting::IncrementDiscoveryItem(Discovery::Event::MoreHotelsClicked);
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & discovery = info->m_discovery;
|
||||
|
||||
TEST_NOT_EQUAL(initialDiscovery.m_lastClickedTime, discovery.m_lastClickedTime, ());
|
||||
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::AttractionsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::CafesClicked), 3, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::HotelsClicked), 1, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::LocalsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreAttractionsClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreCafesClicked), 0, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreHotelsClicked), 1, ());
|
||||
TEST_EQUAL(discovery.m_eventCounters.Get(Discovery::Event::MoreLocalsClicked), 1, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(ScopedEyeForTesting, AppendLayerTest)
|
||||
{
|
||||
{
|
||||
auto const initialInfo = Eye::Instance().GetInfo();
|
||||
auto const & initialLayers = initialInfo->m_layers;
|
||||
|
||||
TEST(initialLayers.empty(), ());
|
||||
TEST_EQUAL(GetLastShownLayerTime(initialLayers), Time(), ());
|
||||
}
|
||||
Time prevShowTime;
|
||||
{
|
||||
EyeForTesting::AppendLayer(Layer::Type::PublicTransport);
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & layers = info->m_layers;
|
||||
auto const prevShowTime = GetLastShownLayerTime(layers);
|
||||
|
||||
TEST_EQUAL(layers.size(), 1, ());
|
||||
TEST_NOT_EQUAL(layers[0].m_lastTimeUsed, Time(), ());
|
||||
TEST_EQUAL(layers[0].m_type, Layer::Type::PublicTransport, ());
|
||||
TEST_EQUAL(layers[0].m_useCount, 1, ());
|
||||
TEST_NOT_EQUAL(prevShowTime, Time(), ());
|
||||
}
|
||||
{
|
||||
EyeForTesting::AppendLayer(Layer::Type::TrafficJams);
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & layers = info->m_layers;
|
||||
auto const lastShownLayerTime = GetLastShownLayerTime(layers);
|
||||
|
||||
TEST_EQUAL(layers.size(), 2, ());
|
||||
TEST_NOT_EQUAL(layers[1].m_lastTimeUsed, Time(), ());
|
||||
TEST_EQUAL(layers[1].m_type, Layer::Type::TrafficJams, ());
|
||||
TEST_EQUAL(layers[1].m_useCount, 1, ());
|
||||
TEST_EQUAL(layers[1].m_lastTimeUsed, lastShownLayerTime, ());
|
||||
TEST_NOT_EQUAL(prevShowTime, lastShownLayerTime, ());
|
||||
prevShowTime = lastShownLayerTime;
|
||||
}
|
||||
{
|
||||
EyeForTesting::AppendLayer(Layer::Type::TrafficJams);
|
||||
|
||||
auto const info = Eye::Instance().GetInfo();
|
||||
auto const & layers = info->m_layers;
|
||||
auto const lastShownLayerTime = GetLastShownLayerTime(layers);
|
||||
|
||||
TEST_EQUAL(layers.size(), 2, ());
|
||||
TEST_NOT_EQUAL(layers[1].m_lastTimeUsed, Time(), ());
|
||||
TEST_EQUAL(layers[1].m_type, Layer::Type::TrafficJams, ());
|
||||
TEST_EQUAL(layers[1].m_useCount, 2, ());
|
||||
TEST_EQUAL(layers[1].m_lastTimeUsed, lastShownLayerTime, ());
|
||||
TEST_NOT_EQUAL(prevShowTime, lastShownLayerTime, ());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,12 @@ void EyeForTesting::ResetEye()
|
|||
my::DeleteFileX(path);
|
||||
}
|
||||
|
||||
// static
|
||||
void EyeForTesting::SetInfo(Info const & info)
|
||||
{
|
||||
Eye::Instance().m_info.Set(std::make_shared<Info>(info));
|
||||
}
|
||||
|
||||
// static
|
||||
void EyeForTesting::AppendTip(Tip::Type type, Tip::Event event)
|
||||
{
|
||||
|
@ -27,8 +33,32 @@ void EyeForTesting::AppendTip(Tip::Type type, Tip::Event event)
|
|||
}
|
||||
|
||||
// static
|
||||
void EyeForTesting::SetInfo(Info const & info)
|
||||
void EyeForTesting::UpdateBookingFilterUsedTime()
|
||||
{
|
||||
Eye::Instance().m_info.Set(std::make_shared<Info>(info));
|
||||
Eye::Instance().UpdateBookingFilterUsedTime();
|
||||
}
|
||||
|
||||
// static
|
||||
void EyeForTesting::UpdateBoomarksCatalogShownTime()
|
||||
{
|
||||
Eye::Instance().UpdateBoomarksCatalogShownTime();
|
||||
}
|
||||
|
||||
// static
|
||||
void EyeForTesting::UpdateDiscoveryShownTime()
|
||||
{
|
||||
Eye::Instance().UpdateDiscoveryShownTime();
|
||||
}
|
||||
|
||||
// static
|
||||
void EyeForTesting::IncrementDiscoveryItem(Discovery::Event event)
|
||||
{
|
||||
Eye::Instance().IncrementDiscoveryItem(event);
|
||||
}
|
||||
|
||||
// static
|
||||
void EyeForTesting::AppendLayer(Layer::Type type)
|
||||
{
|
||||
Eye::Instance().AppendLayer(type);
|
||||
}
|
||||
} // namespace eye
|
||||
|
|
|
@ -8,8 +8,13 @@ class EyeForTesting
|
|||
{
|
||||
public:
|
||||
static void ResetEye();
|
||||
static void AppendTip(Tip::Type type, Tip::Event event);
|
||||
static void SetInfo(Info const & info);
|
||||
static void AppendTip(Tip::Type type, Tip::Event event);
|
||||
static void UpdateBookingFilterUsedTime();
|
||||
static void UpdateBoomarksCatalogShownTime();
|
||||
static void UpdateDiscoveryShownTime();
|
||||
static void IncrementDiscoveryItem(Discovery::Event event);
|
||||
static void AppendLayer(Layer::Type type);
|
||||
};
|
||||
|
||||
class ScopedEyeForTesting
|
||||
|
|
Loading…
Add table
Reference in a new issue