[drape] Remember navigation mode between sessions

Signed-off-by: Leonardo Bishop <me@leonardobishop.net>
This commit is contained in:
Leonardo Bishop
2026-01-10 13:55:20 +00:00
committed by Konstantin Pastbin
parent 2b6cd0db54
commit f9485d44f5
10 changed files with 107 additions and 29 deletions

View File

@@ -19,6 +19,7 @@ using namespace std::placeholders;
namespace
{
std::string_view constexpr kLocationStateMode = "LastLocationStateMode";
std::string_view constexpr kPreferredRoutingMode = "PreferredRoutingMode";
std::string_view constexpr kLastEnterBackground = "LastEnterBackground";
} // namespace
@@ -39,16 +40,20 @@ DrapeEngine::DrapeEngine(Params && params)
m_requestedTiles = make_unique_dp<RequestedTiles>();
using namespace location;
EMyPositionMode mode = PendingPosition;
if (settings::Get(kLocationStateMode, mode) && mode == FollowAndRotate)
EMyPositionMode lastMode = PendingPosition;
if (settings::Get(kLocationStateMode, lastMode) && lastMode == FollowAndRotate)
{
// If the screen rect setting in follow and rotate mode is missing or invalid, it could cause
// invalid animations, so the follow and rotate mode should be discarded.
m2::AnyRectD rect;
if (!(settings::Get("ScreenClipRect", rect) && df::GetWorldRect().IsRectInside(rect.GetGlobalRect())))
mode = Follow;
lastMode = Follow;
}
EMyPositionMode preferredRoutingMode;
if (!settings::Get(kPreferredRoutingMode, preferredRoutingMode))
preferredRoutingMode = FollowAndRotate;
if (!settings::Get(kLastEnterBackground, m_startBackgroundTime))
m_startBackgroundTime = base::Timer::LocalTime();
@@ -65,9 +70,10 @@ DrapeEngine::DrapeEngine(Params && params)
// effects.push_back(PostprocessRenderer::Antialiasing);
//}
MyPositionController::Params mpParams(mode, base::Timer::LocalTime() - m_startBackgroundTime, params.m_hints,
MyPositionController::Params mpParams(lastMode, preferredRoutingMode,
base::Timer::LocalTime() - m_startBackgroundTime, params.m_hints,
params.m_isRoutingActive, params.m_isAutozoomEnabled,
std::bind(&DrapeEngine::MyPositionModeChanged, this, _1, _2));
std::bind(&DrapeEngine::MyPositionModeChanged, this, _1, _2, _3));
FrontendRenderer::Params frParams(
params.m_apiVersion, make_ref(m_threadCommutator), params.m_factory, make_ref(m_textureManager),
@@ -404,9 +410,11 @@ void DrapeEngine::ModelViewChanged(ScreenBase const & screen)
m_modelViewChangedHandler(screen);
}
void DrapeEngine::MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive)
void DrapeEngine::MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive, bool shouldPersistMode)
{
settings::Set(kLocationStateMode, mode);
if (shouldPersistMode && routingActive)
settings::Set(kPreferredRoutingMode, mode);
if (m_myPositionModeChanged)
m_myPositionModeChanged(mode, routingActive);
}
@@ -458,6 +466,12 @@ void DrapeEngine::SwitchMyPositionNextMode()
MessagePriority::Normal);
}
void DrapeEngine::StartPendingPositionMode()
{
m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<StartPendingPositionModeMessage>(),
MessagePriority::Normal);
}
void DrapeEngine::LoseLocation()
{
using Mode = ChangeMyPositionModeMessage::EChangeType;

View File

@@ -157,6 +157,7 @@ public:
void SetGpsInfo(location::GpsInfo const & info, bool isNavigable, double distToNextTurn, double speedLimit,
location::RouteMatchingInfo const & routeInfo);
void SwitchMyPositionNextMode();
void StartPendingPositionMode();
void LoseLocation();
void StopLocationFollow();
@@ -250,7 +251,7 @@ private:
void AddUserEvent(drape_ptr<UserEvent> && e);
void PostUserEvent(drape_ptr<UserEvent> && e);
void ModelViewChanged(ScreenBase const & screen);
void MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive);
void MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive, bool shouldPersistMode);
void TapEvent(TapInfo const & tapInfo);
void UserPositionChanged(m2::PointD const & position, bool hasPosition);

View File

@@ -425,6 +425,12 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
break;
}
case Message::Type::StartPendingPositionMode:
{
m_myPositionController->StartPendingPositionMode();
break;
}
case Message::Type::CompassInfo:
{
ref_ptr<CompassInfoMessage> msg = message;

View File

@@ -33,6 +33,7 @@ std::string DebugPrint(Message::Type msgType)
case Message::Type::MapShapesRecache: return "MapShapesRecache";
case Message::Type::MapShapes: return "MapShapes";
case Message::Type::ChangeMyPositionMode: return "ChangeMyPositionMode";
case Message::Type::StartPendingPositionMode: return "StartPendingPositionMode";
case Message::Type::CompassInfo: return "CompassInfo";
case Message::Type::GpsInfo: return "GpsInfo";
case Message::Type::SelectObject: return "SelectObject";

View File

@@ -34,6 +34,7 @@ public:
MapShapesRecache,
MapShapes,
ChangeMyPositionMode,
StartPendingPositionMode,
CompassInfo,
GpsInfo,
SelectObject,

View File

@@ -459,6 +459,12 @@ private:
EChangeType const m_changeType;
};
class StartPendingPositionModeMessage : public Message
{
public:
Type GetType() const override { return Type::StartPendingPositionMode; }
};
class CompassInfoMessage : public Message
{
public:

View File

@@ -9,6 +9,7 @@
#include "geometry/mercator.hpp"
#include "platform/location.hpp"
#include "platform/measurement_utils.hpp"
#include "base/math.hpp"
@@ -203,8 +204,10 @@ MyPositionController::MyPositionController(Params && params, ref_ptr<DrapeNotifi
m_mode = NotFollowNoPosition;
}
m_preferredRoutingMode = params.m_preferredRoutingMode;
if (m_modeChangeCallback)
m_modeChangeCallback(m_mode, m_isInRouting);
m_modeChangeCallback(m_mode, m_isInRouting, false);
}
void MyPositionController::UpdatePosition()
@@ -398,7 +401,11 @@ void MyPositionController::NextMode(ScreenBase const & screen)
// In routing not-follow -> follow-and-rotate, otherwise not-follow -> follow.
if (m_mode == location::NotFollow)
{
ChangeMode(m_isInRouting ? location::FollowAndRotate : location::Follow);
if ((IsRotationAvailable() || m_isInRouting) && m_preferredRoutingMode == location::FollowAndRotate)
ChangeMode(location::FollowAndRotate, true);
else
ChangeMode(location::Follow, true);
UpdateViewport(preferredZoomLevel);
return;
}
@@ -409,7 +416,7 @@ void MyPositionController::NextMode(ScreenBase const & screen)
{
if (IsRotationAvailable() || m_isInRouting)
{
ChangeMode(location::FollowAndRotate);
ChangeMode(location::FollowAndRotate, true);
UpdateViewport(preferredZoomLevel);
}
return;
@@ -420,11 +427,20 @@ void MyPositionController::NextMode(ScreenBase const & screen)
{
if (m_isInRouting && screen.isPerspective())
preferredZoomLevel = static_cast<int>(GetZoomLevel(ScreenBase::GetStartPerspectiveScale() * 1.1));
ChangeMode(location::Follow);
ChangeMode(location::Follow, true);
ChangeModelView(m_position, 0.0, m_visiblePixelRect.Center(), preferredZoomLevel);
}
}
void MyPositionController::StartPendingPositionMode()
{
if (m_mode == location::NotFollowNoPosition)
{
ChangeMode(location::PendingPosition);
return;
}
}
void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool isNavigable, double distanceToNextTurn,
double speedLimit, ScreenBase const & screen)
{
@@ -478,8 +494,7 @@ void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool
if (!m_isPositionAssigned)
{
location::EMyPositionMode newMode = m_desiredInitMode;
ChangeMode(newMode);
ChangeMode(m_isInRouting ? m_preferredRoutingMode : m_desiredInitMode, true);
if (!m_hints.m_isFirstLaunch || !AnimationSystem::Instance().AnimationExists(Animation::Object::MapPlane))
{
@@ -497,14 +512,14 @@ void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool
}
else if (m_mode == location::PendingPosition)
{
if (m_isInRouting)
if (m_isInRouting && m_preferredRoutingMode == location::FollowAndRotate)
{
ChangeMode(location::FollowAndRotate);
ChangeMode(location::FollowAndRotate, true);
UpdateViewport(kMaxScaleZoomLevel);
}
else
{
ChangeMode(location::Follow);
ChangeMode(location::Follow, true);
if (m_hints.m_isFirstLaunch)
{
if (!AnimationSystem::Instance().AnimationExists(Animation::Object::MapPlane))
@@ -523,15 +538,15 @@ void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool
}
else if (m_mode == location::NotFollowNoPosition)
{
if (m_isInRouting)
if (m_isInRouting && m_preferredRoutingMode == location::FollowAndRotate)
{
ChangeMode(location::FollowAndRotate);
ChangeMode(location::FollowAndRotate, true);
UpdateViewport(kMaxScaleZoomLevel);
}
else
{
// Here we silently get the position and go to NotFollow mode.
ChangeMode(location::NotFollow);
ChangeMode(location::NotFollow, true);
}
}
@@ -653,13 +668,24 @@ void MyPositionController::SetDirection(double bearing)
}
void MyPositionController::ChangeMode(location::EMyPositionMode newMode)
{
ChangeMode(newMode, false);
}
void MyPositionController::ChangeMode(location::EMyPositionMode newMode, bool shouldPersist)
{
if (m_isInRouting && (m_mode != newMode) && (newMode == location::FollowAndRotate))
ResetBlockAutoZoomTimer();
m_mode = newMode;
// We should remember this mode if the user intentionally caused the mode change
// (e.g. tapping the mode button)
if (m_isInRouting && shouldPersist)
m_preferredRoutingMode = newMode;
if (m_modeChangeCallback)
m_modeChangeCallback(m_mode, m_isInRouting);
m_modeChangeCallback(m_mode, m_isInRouting, shouldPersist);
}
bool MyPositionController::IsWaitingForLocation() const
@@ -690,7 +716,8 @@ void MyPositionController::OnEnterForeground(double backgroundTime)
// When location was active during previous session the app will try to follow the user.
if (m_mode == location::NotFollow)
{
ChangeMode(m_isInRouting ? location::FollowAndRotate : location::Follow);
ChangeMode((m_isInRouting && m_preferredRoutingMode == location::FollowAndRotate) ? location::FollowAndRotate
: location::Follow);
UpdateViewport(kDoNotChangeZoom);
}
@@ -876,9 +903,17 @@ void MyPositionController::ActivateRouting(int zoomLevel, bool enableAutoZoom, b
m_isArrowGluedInRouting = isArrowGlued;
m_enableAutoZoomInRouting = enableAutoZoom;
ChangeMode(location::FollowAndRotate);
ChangeModelView(m_position, m_isDirectionAssigned ? m_drawDirection : 0.0, GetRoutingRotationPixelCenter(),
zoomLevel, [this](ref_ptr<Animation> anim) { UpdateViewport(kDoNotChangeZoom); });
if (m_preferredRoutingMode == location::Follow)
{
ChangeMode(location::Follow);
ChangeModelView(m_position, kDoNotChangeZoom);
}
else
{
ChangeMode(location::FollowAndRotate);
ChangeModelView(m_position, m_isDirectionAssigned ? m_drawDirection : 0.0, GetRoutingRotationPixelCenter(),
zoomLevel, [this](ref_ptr<Animation> anim) { UpdateViewport(kDoNotChangeZoom); });
}
ResetRoutingNotFollowTimer();
}
}
@@ -919,7 +954,7 @@ void MyPositionController::CheckNotFollowRouting()
CHECK_ON_TIMEOUT(m_routingNotFollowNotifyId, kMaxNotFollowRoutingTimeSec, CheckNotFollowRouting);
if (m_routingNotFollowTimer.ElapsedSeconds() >= kMaxNotFollowRoutingTimeSec)
{
ChangeMode(location::FollowAndRotate);
ChangeMode(m_preferredRoutingMode);
UpdateViewport(kDoNotChangeZoom);
}
}

View File

@@ -22,6 +22,8 @@ namespace df
{
using TAnimationCreator = std::function<drape_ptr<Animation>(ref_ptr<Animation>)>;
using TMyPositionModeChanged = std::function<void(location::EMyPositionMode, bool, bool)>;
class DrapeNotifier;
class MyPositionController
@@ -49,9 +51,10 @@ public:
struct Params
{
Params(location::EMyPositionMode initMode, double timeInBackground, Hints const & hints, bool isRoutingActive,
bool isAutozoomEnabled, location::TMyPositionModeChanged && fn)
Params(location::EMyPositionMode initMode, location::EMyPositionMode preferredRoutingMode, double timeInBackground,
Hints const & hints, bool isRoutingActive, bool isAutozoomEnabled, TMyPositionModeChanged && fn)
: m_initMode(initMode)
, m_preferredRoutingMode(preferredRoutingMode)
, m_timeInBackground(timeInBackground)
, m_hints(hints)
, m_isRoutingActive(isRoutingActive)
@@ -60,11 +63,12 @@ public:
{}
location::EMyPositionMode m_initMode;
location::EMyPositionMode m_preferredRoutingMode;
double m_timeInBackground;
Hints m_hints;
bool m_isRoutingActive;
bool m_isAutozoomEnabled;
location::TMyPositionModeChanged m_myPositionModeCallback;
TMyPositionModeChanged m_myPositionModeCallback;
};
MyPositionController(Params && params, ref_ptr<DrapeNotifier> notifier);
@@ -112,6 +116,7 @@ public:
void NextMode(ScreenBase const & screen);
void LoseLocation();
location::EMyPositionMode GetCurrentMode() const { return m_mode; }
void StartPendingPositionMode();
void OnEnterForeground(double backgroundTime);
void OnEnterBackground();
@@ -134,6 +139,7 @@ public:
void UpdateRoutingOffsetY(bool useDefault, int offsetY);
private:
void ChangeMode(location::EMyPositionMode newMode, bool persist);
void ChangeMode(location::EMyPositionMode newMode);
void SetDirection(double bearing);
@@ -163,7 +169,8 @@ private:
location::EMyPositionMode m_mode;
location::EMyPositionMode m_desiredInitMode;
location::TMyPositionModeChanged m_modeChangeCallback;
location::EMyPositionMode m_preferredRoutingMode;
TMyPositionModeChanged m_modeChangeCallback;
Hints m_hints;
bool m_isInRouting = false;

View File

@@ -206,6 +206,12 @@ void Framework::SwitchMyPositionNextMode()
m_drapeEngine->SwitchMyPositionNextMode();
}
void Framework::StartPendingPositionMode()
{
if (m_drapeEngine != nullptr)
m_drapeEngine->StartPendingPositionMode();
}
void Framework::SetMyPositionModeListener(TMyPositionModeChanged && fn)
{
m_myPositionListener = std::move(fn);

View File

@@ -390,6 +390,7 @@ public:
void OnLocationUpdate(location::GpsInfo const & info);
void OnCompassUpdate(location::CompassInfo const & info);
void SwitchMyPositionNextMode();
void StartPendingPositionMode();
/// Should be set before Drape initialization. Guarantees that fn is called in main thread context.
void SetMyPositionModeListener(location::TMyPositionModeChanged && fn);