diff options
author | ExMix <rahuba.youri@mapswithme.com> | 2014-10-08 11:43:06 +0400 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 02:29:38 +0300 |
commit | e931bb160041774f98da8be98201f4c6d17f84b1 (patch) | |
tree | 37d340a825e9a96fe17869a957814a0f2337431f /map/country_status_display.cpp | |
parent | b0a390f1943873f12153e7bf0282198e9bc0ff43 (diff) |
[core] new download buttons from map view
Diffstat (limited to 'map/country_status_display.cpp')
-rw-r--r-- | map/country_status_display.cpp | 558 |
1 files changed, 352 insertions, 206 deletions
diff --git a/map/country_status_display.cpp b/map/country_status_display.cpp index 38db54d98f..91f37c6b16 100644 --- a/map/country_status_display.cpp +++ b/map/country_status_display.cpp @@ -1,14 +1,17 @@ #include "country_status_display.hpp" +#include "framework.hpp" #include "../gui/controller.hpp" +#include "../gui/button.hpp" #include "../gui/text_view.hpp" #include "../graphics/overlay_renderer.hpp" #include "../graphics/display_list.hpp" -#include "../storage/storage_defines.hpp" #include "../platform/platform.hpp" +#include "../base/thread.hpp" + #include "../base/string_format.hpp" #include "../std/bind.hpp" @@ -16,313 +19,456 @@ using namespace storage; -CountryStatusDisplay::Params::Params() - : m_storage(0) +CountryStatusDisplay::CountryStatusDisplay(Params const & p) + : gui::Element(p) + , m_activeMaps(p.m_activeMaps) { -} + m_activeMapsSlotID = m_activeMaps.AddListener(this); + gui::Button::Params bp; -string const CountryStatusDisplay::displayName() const -{ - if (!m_mapGroupName.empty()) - return m_mapName + " (" + m_mapGroupName + ")"; - else - return m_mapName; -} + bp.m_depth = depth(); + bp.m_minWidth = 200; + bp.m_minHeight = 40; + bp.m_position = graphics::EPosCenter; -template <class T1, class T2> -void CountryStatusDisplay::SetStatusMessage(string const & msgID, T1 const * t1, T2 const * t2) -{ - string msg = m_controller->GetStringsBundle()->GetString(msgID); - if (t1) + auto createButtonFn = [this](gui::Button::Params const & params) { - if (t2) - msg = strings::Format(msg, *t1, *t2); - else - { - msg = strings::Format(msg, *t1); + gui::Button * result = new gui::Button(params); + result->setIsVisible(false); + result->setOnClickListener(bind(&CountryStatusDisplay::OnButtonClicked, this, _1)); - size_t const count = msg.size(); - if (count > 0) - { - if (msg[count-1] == '\n') - msg.erase(count-1, 1); - } - } - } + result->setFont(EActive, graphics::FontDesc(16, graphics::Color(255, 255, 255, 255))); + result->setFont(EPressed, graphics::FontDesc(16, graphics::Color(255, 255, 255, 255))); - m_statusMsg->setIsVisible(true); - m_statusMsg->setText(msg); -} + result->setColor(EActive, graphics::Color(0, 0, 0, 0.6 * 255)); + result->setColor(EPressed, graphics::Color(0, 0, 0, 0.4 * 255)); -void CountryStatusDisplay::layout() -{ - m_downloadButton->setIsDirtyLayout(true); - m_statusMsg->setIsDirtyLayout(true); + return result; + }; + + m_primaryButton.reset(createButtonFn(bp)); + m_secondaryButton.reset(createButtonFn(bp)); + + gui::TextView::Params tp; + tp.m_depth = depth(); + tp.m_position = graphics::EPosCenter; + + m_label.reset(new gui::TextView(tp)); + m_label->setIsVisible(false); + m_label->setFont(gui::Element::EActive, graphics::FontDesc(18)); + + setIsVisible(false); } -void CountryStatusDisplay::purge() +CountryStatusDisplay::~CountryStatusDisplay() { - m_downloadButton->purge(); - m_statusMsg->purge(); + m_activeMaps.RemoveListener(m_activeMapsSlotID); } -void CountryStatusDisplay::cache() +void CountryStatusDisplay::SetCountryIndex(TIndex const & idx) { - m_downloadButton->setIsVisible(false); - m_statusMsg->setIsVisible(false); - setIsVisible(false); - - string const dn = displayName(); - - if (m_countryIdx.IsValid()) + if (m_countryIdx != idx) { - switch (m_countryStatus) - { - case TStatus::EInQueue: - { - SetStatusMessage<string, int>("country_status_added_to_queue", &dn); - break; - } + m_countryIdx = idx; - case TStatus::EDownloading: + if (m_countryIdx.IsValid()) { - int const percent = m_countryProgress.first * 100 / m_countryProgress.second; - SetStatusMessage<string, int>("country_status_downloading", &dn, &percent); - break; + m_countryStatus = m_activeMaps.GetCountryStatus(m_countryIdx); + m_displayMapName = m_activeMaps.GetFormatedCountryName(m_countryIdx); } - case TStatus::ENotDownloaded: - if (m_notEnoughSpace) - SetStatusMessage<int, int>("not_enough_free_space_on_sdcard"); - else - { - m_downloadButton->setIsVisible(true); - string const msg = m_controller->GetStringsBundle()->GetString("country_status_download"); - m_downloadButton->setText(strings::Format(msg, dn)); - } - break; - - case TStatus::EDownloadFailed: - { - m_downloadButton->setIsVisible(true); - m_downloadButton->setText(m_controller->GetStringsBundle()->GetString("try_again")); - SetStatusMessage<string, int>("country_status_download_failed", &dn); + Repaint(); + } +} - setPivot(pivot()); - break; - } +void CountryStatusDisplay::DownloadCurrentCountry(int options) +{ + // I don't know why this work, but it's terrible + // This method call only on android, from "AndroidUIThread" + DownloadCountry(options, false); +} - default: - return; - } - } +void CountryStatusDisplay::setIsVisible(bool isVisible) const +{ + if (isVisible && isVisible != TBase::isVisible()) + Repaint(); - setIsVisible(m_statusMsg->isVisible() || m_downloadButton->isVisible()); + TBase::setIsVisible(isVisible); } -void CountryStatusDisplay::CountryStatusChanged(TIndex const & idx) +void CountryStatusDisplay::setIsDirtyLayout(bool isDirty) const { - if (idx == m_countryIdx) - { - UpdateStatusAndProgress(); + TBase::setIsDirtyLayout(isDirty); + m_label->setIsDirtyLayout(isDirty); + m_primaryButton->setIsDirtyLayout(isDirty); + m_secondaryButton->setIsDirtyLayout(isDirty); - setIsDirtyLayout(true); - invalidate(); - } + if (isDirty) + SetVisibilityForState(); } -void CountryStatusDisplay::CountryProgress(TIndex const & idx, pair<int64_t, int64_t> const & progress) +void CountryStatusDisplay::draw(graphics::OverlayRenderer * r, + math::Matrix<double, 3, 3> const & m) const { - if ((m_countryIdx == idx) && (m_countryStatus == TStatus::EDownloading)) + if (isVisible()) { - m_countryProgress = progress; + Lock(); + checkDirtyLayout(); - setIsDirtyLayout(true); - invalidate(); + m_label->draw(r, m); + m_primaryButton->draw(r, m); + m_secondaryButton->draw(r, m); + Unlock(); } } -CountryStatusDisplay::CountryStatusDisplay(Params const & p) - : gui::Element(p), m_storage(p.m_storage) +void CountryStatusDisplay::layout() { - m_slotID = m_storage->Subscribe(bind(&CountryStatusDisplay::CountryStatusChanged, this, _1), - bind(&CountryStatusDisplay::CountryProgress, this, _1, _2)); - - using namespace graphics; + if (!isVisible()) + return; + SetContentForState(); - gui::Button::Params bp; + auto layoutFn = [] (gui::Element * e) + { + if (e->isVisible()) + e->layout(); + }; + + layoutFn(m_label.get()); + layoutFn(m_primaryButton.get()); + layoutFn(m_secondaryButton.get()); + + ComposeElementsForState(); + + // !!!! Hack !!!! + // ComposeElementsForState modify pivot point of elements. + // After setPivot all elements must be relayouted. + // For reduce "cache" operations we call layout secondary + layoutFn(m_label.get()); + layoutFn(m_primaryButton.get()); + layoutFn(m_secondaryButton.get()); +} - bp.m_depth = depth(); - bp.m_minWidth = 200; - bp.m_minHeight = 40; - bp.m_position = EPosCenter; +void CountryStatusDisplay::purge() +{ + m_label->purge(); + m_primaryButton->purge(); + m_secondaryButton->purge(); +} - m_downloadButton.reset(new gui::Button(bp)); - m_downloadButton->setOnClickListener(bind(&CountryStatusDisplay::downloadCountry, this)); - m_downloadButton->setIsVisible(false); - m_downloadButton->setPosition(EPosCenter); +void CountryStatusDisplay::cache() +{ + auto cacheFn = [](gui::Element * e) + { + if (e->isVisible()) + e->cache(); + }; - m_downloadButton->setFont(EActive, FontDesc(16, Color(255, 255, 255, 255))); - m_downloadButton->setFont(EPressed, FontDesc(16, Color(255, 255, 255, 255))); + cacheFn(m_label.get()); + cacheFn(m_primaryButton.get()); + cacheFn(m_secondaryButton.get()); +} - m_downloadButton->setColor(EActive, Color(Color(0, 0, 0, 0.6 * 255))); - m_downloadButton->setColor(EPressed, Color(Color(0, 0, 0, 0.4 * 255))); +m2::RectD CountryStatusDisplay::GetBoundRect() const +{ + ASSERT(isVisible(), ()); + m2::RectD r(pivot(), pivot()); - gui::TextView::Params tp; - tp.m_depth = depth(); + if (m_primaryButton->isVisible()) + r.Add(m_primaryButton->GetBoundRect()); + if (m_secondaryButton->isVisible()) + r.Add(m_secondaryButton->GetBoundRect()); - m_statusMsg.reset(new gui::TextView(tp)); + return r; +} - m_statusMsg->setIsVisible(false); - m_statusMsg->setPosition(EPosCenter); +void CountryStatusDisplay::setController(gui::Controller * controller) +{ + Element::setController(controller); + m_label->setController(controller); + m_primaryButton->setController(controller); + m_secondaryButton->setController(controller); +} - m_statusMsg->setFont(gui::Element::EActive, FontDesc(18)); +bool CountryStatusDisplay::onTapStarted(m2::PointD const & pt) +{ + return OnTapAction(bind(&gui::Button::onTapStarted, _1, _2), pt); +} - setIsVisible(false); +bool CountryStatusDisplay::onTapMoved(m2::PointD const & pt) +{ + return OnTapAction(bind(&gui::Button::onTapMoved, _1, _2), pt); +} - m_countryIdx = TIndex(); - m_countryStatus = TStatus::EUnknown; - m_notEnoughSpace = false; +bool CountryStatusDisplay::onTapEnded(m2::PointD const & pt) +{ + return OnTapAction(bind(&gui::Button::onTapEnded, _1, _2), pt); } -CountryStatusDisplay::~CountryStatusDisplay() +bool CountryStatusDisplay::onTapCancelled(m2::PointD const & pt) { - m_storage->Unsubscribe(m_slotID); + return OnTapAction(bind(&gui::Button::onTapCancelled, _1, _2), pt); } -void CountryStatusDisplay::downloadCountry() +void CountryStatusDisplay::CountryStatusChanged(ActiveMapsLayout::TGroup const & group, int position) { - if (GetPlatform().GetWritableStorageStatus(m_countryProgress.second) != Platform::STORAGE_OK) + TIndex index = m_activeMaps.GetCoreIndex(group, position); + if (m_countryIdx == index) { - m_notEnoughSpace = true; - - setIsDirtyLayout(true); - invalidate(); + Lock(); + m_countryStatus = m_activeMaps.GetCountryStatus(index); + Repaint(); + Unlock(); } - else - m_storage->DownloadCountry(m_countryIdx, storage::TMapOptions::EMapOnly); } -void CountryStatusDisplay::setDownloadListener(gui::Button::TOnClickListener const & l) +void CountryStatusDisplay::DownloadingProgressUpdate(ActiveMapsLayout::TGroup const & group, int position, LocalAndRemoteSizeT const & progress) { - m_downloadButton->setOnClickListener(l); + TIndex index = m_activeMaps.GetCoreIndex(group, position); + if (m_countryIdx == index) + { + Lock(); + m_countryStatus = m_activeMaps.GetCountryStatus(index); + m_progressSize = progress; + Repaint(); + Unlock(); + } } -void CountryStatusDisplay::UpdateStatusAndProgress() +template <class T1, class T2> +string CountryStatusDisplay::FormatStatusMessage(string const & msgID, T1 const * t1, T2 const * t2) { - // Actually right now actual status is getting from Framework. - // But here it's enough to get it from Storage because of we need only - // download progress statuses. - - using namespace storage; - - m_countryProgress = m_storage->CountrySizeInBytes(m_countryIdx); - - m_countryStatus = m_storage->CountryStatus(m_countryIdx); - if (m_countryStatus == TStatus::EUnknown) + string msg = m_controller->GetStringsBundle()->GetString(msgID); + if (t1) { - if (m_countryProgress.first > 0) - m_countryStatus = TStatus::EOnDisk; + if (t2) + msg = strings::Format(msg, *t1, *t2); else - m_countryStatus = TStatus::ENotDownloaded; + { + msg = strings::Format(msg, *t1); + + size_t const count = msg.size(); + if (count > 0) + { + if (msg[count-1] == '\n') + msg.erase(count-1, 1); + } + } } + + return msg; } -void CountryStatusDisplay::setCountryIndex(TIndex const & idx) +void CountryStatusDisplay::SetVisibilityForState() const { - if (m_countryIdx != idx) - { - m_countryIdx = idx; + uint8_t visibilityFlags = 0; + uint8_t const labelVisibility = 0x1; + uint8_t const primeVisibility = 0x2; + uint8_t const secondaryVisibility = 0x4; - if (m_countryIdx.IsValid()) + if (m_countryIdx.IsValid()) + { + switch (m_countryStatus) { - m_storage->GetGroupAndCountry(idx, m_mapGroupName, m_mapName); - LOG(LDEBUG, (m_mapName, m_mapGroupName)); - - UpdateStatusAndProgress(); - - m_notEnoughSpace = false; + case TStatus::EDownloadFailed: + visibilityFlags |= labelVisibility; + visibilityFlags |= primeVisibility; + break; + case TStatus::EDownloading: + case TStatus::EInQueue: + visibilityFlags |= labelVisibility; + break; + case TStatus::ENotDownloaded: + visibilityFlags |= labelVisibility; + visibilityFlags |= primeVisibility; + visibilityFlags |= secondaryVisibility; + break; + default: + break; } - - setIsDirtyLayout(true); - invalidate(); } + + m_label->setIsVisible(visibilityFlags & labelVisibility); + m_primaryButton->setIsVisible(visibilityFlags & primeVisibility); + m_secondaryButton->setIsVisible(visibilityFlags & secondaryVisibility); + + TBase::setIsVisible(m_label->isVisible() || m_primaryButton->isVisible() || m_secondaryButton->isVisible()); } -void CountryStatusDisplay::draw(graphics::OverlayRenderer *r, - math::Matrix<double, 3, 3> const & m) const +void CountryStatusDisplay::SetContentForState() { - if (isVisible()) - { - checkDirtyLayout(); + if (!isVisible()) + return; - if (m_downloadButton->isVisible()) - m_downloadButton->draw(r, m); - if (m_statusMsg->isVisible()) - m_statusMsg->draw(r, m); + switch (m_countryStatus) + { + case TStatus::EDownloadFailed: + case TStatus::EOutOfMemFailed: + SetContentForError(); + break; + case TStatus::ENotDownloaded: + SetContentForDownloadPropose(); + break; + case TStatus::EDownloading: + SetContentForProgress(); + break; + case TStatus::EInQueue: + SetContentForInQueue(); + break; + default: + break; } } -m2::RectD CountryStatusDisplay::GetBoundRect() const +void CountryStatusDisplay::SetContentForDownloadPropose() { - m2::RectD r(pivot(), pivot()); - if (m_downloadButton->isVisible()) - r.Add(m_downloadButton->GetBoundRect()); + ASSERT(m_label->isVisible(), ()); + ASSERT(m_primaryButton->isVisible(), ()); + ASSERT(m_secondaryButton->isVisible(), ()); + + LocalAndRemoteSizeT mapOnlySize = m_activeMaps.GetCountrySize(m_countryIdx, TMapOptions::EMapOnly); + LocalAndRemoteSizeT withRouting = m_activeMaps.GetCountrySize(m_countryIdx, TMapOptions::EMapWithCarRouting); + + m_label->setText(m_displayMapName); + int mbToDownload = mapOnlySize.second / (1024 * 1024); + m_primaryButton->setText(FormatStatusMessage<int, int>("country_status_download", &mbToDownload)); + mbToDownload = withRouting.second / (1024 * 1024); + m_secondaryButton->setText(FormatStatusMessage<int, int>("country_status_download_routing", &mbToDownload)); +} - return r; +void CountryStatusDisplay::SetContentForProgress() +{ + ASSERT(m_label->isVisible(), ()); + int const percent = m_progressSize.first * 100 / m_progressSize.second; + m_label->setText(FormatStatusMessage<string, int>("country_status_downloading", &m_displayMapName, &percent)); } -void CountryStatusDisplay::setController(gui::Controller * controller) +void CountryStatusDisplay::SetContentForInQueue() { - Element::setController(controller); - m_statusMsg->setController(controller); - m_downloadButton->setController(controller); + ASSERT(m_label->isVisible(), ()); + m_label->setText(FormatStatusMessage<string, int>("country_status_added_to_queue", &m_displayMapName)); } -void CountryStatusDisplay::setPivot(m2::PointD const & pv) +void CountryStatusDisplay::SetContentForError() { + ASSERT(m_label->isVisible(), ()); + ASSERT(m_primaryButton->isVisible(), ()); + if (m_countryStatus == TStatus::EDownloadFailed) + m_label->setText(FormatStatusMessage<string, int>("country_status_download_failed", &m_displayMapName)); + else + m_label->setText(FormatStatusMessage<int, int>("not_enough_free_space_on_sdcard")); + + m_primaryButton->setText(m_controller->GetStringsBundle()->GetString("try_again")); +} + +void CountryStatusDisplay::ComposeElementsForState() +{ + ASSERT(isVisible(), ()); + int visibleCount = 0; + auto visibleCheckFn = [&visibleCount](gui::Element const * e) + { + if (e->isVisible()) + ++visibleCount; + }; + + visibleCheckFn(m_label.get()); + visibleCheckFn(m_primaryButton.get()); + visibleCheckFn(m_secondaryButton.get()); + + ASSERT(visibleCount > 0, ()); + + m2::PointD const & pv = pivot(); + if (visibleCount == 1) + m_label->setPivot(pv); + else if (visibleCount == 2) { - size_t const buttonHeight = m_downloadButton->GetBoundRect().SizeY(); - size_t const statusHeight = m_statusMsg->GetBoundRect().SizeY(); - size_t const commonHeight = buttonHeight + statusHeight + 10 * visualScale(); + size_t const labelHeight = m_label->GetBoundRect().SizeY(); + size_t const buttonHeight = m_primaryButton->GetBoundRect().SizeY(); + size_t const commonHeight = buttonHeight + labelHeight + 10 * visualScale(); - m_downloadButton->setPivot(m2::PointD(pv.x, pv.y + commonHeight / 2 - buttonHeight / 2)); - m_statusMsg->setPivot(m2::PointD(pv.x, pv.y - commonHeight / 2 + statusHeight / 2)); + m_label->setPivot(m2::PointD(pv.x, pv.y - commonHeight / 2 + labelHeight / 2)); + m_primaryButton->setPivot(m2::PointD(pv.x, pv.y + commonHeight / 2 - buttonHeight / 2)); } else { - m_downloadButton->setPivot(pv); - m_statusMsg->setPivot(pv); + size_t const labelHeight = m_label->GetBoundRect().SizeY(); + size_t const primButtonHeight = m_primaryButton->GetBoundRect().SizeY(); + size_t const secButtonHeight = m_secondaryButton->GetBoundRect().SizeY(); + size_t const emptySpace = 10 * visualScale(); + + double const offsetFromCenter = (primButtonHeight / 2 + emptySpace); + + m_label->setPivot(m2::PointD(pv.x, pv.y - offsetFromCenter - labelHeight / 2)); + m_primaryButton->setPivot(pv); + m_secondaryButton->setPivot(m2::PointD(pv.x, pv.y + offsetFromCenter + secButtonHeight / 2.0)); } +} - gui::Element::setPivot(pv); +bool CountryStatusDisplay::OnTapAction(TTapActionFn const & action, const m2::PointD & pt) +{ + bool result = false; + if (m_primaryButton->isVisible() && m_primaryButton->hitTest(pt)) + result |= action(m_primaryButton, pt); + else if (m_secondaryButton->isVisible() && m_secondaryButton->hitTest(pt)) + result |= action(m_secondaryButton, pt); + + return result; } -bool CountryStatusDisplay::onTapStarted(m2::PointD const & pt) +void CountryStatusDisplay::OnButtonClicked(gui::Element const * button) { - if (m_downloadButton->isVisible()) - return m_downloadButton->onTapStarted(pt); - return false; + ASSERT(m_countryIdx.IsValid(), ()); + + TMapOptions options = TMapOptions::EMapOnly; + if (button == m_secondaryButton.get()) + options |= TMapOptions::ECarRouting; + + DownloadCountry(static_cast<int>(options)); } -bool CountryStatusDisplay::onTapMoved(m2::PointD const & pt) +void CountryStatusDisplay::DownloadCountry(int options, bool checkCallback) { - if (m_downloadButton->isVisible()) - return m_downloadButton->onTapMoved(pt); - return false; + ASSERT(m_countryIdx.IsValid(), ()); + if (checkCallback && m_downloadCallback) + m_downloadCallback(options); + else + { + if (IsStatusFailed()) + { + m_progressSize = m_activeMaps.GetDownloadableCountrySize(m_countryIdx); + m_activeMaps.RetryDownloading(m_countryIdx); + } + else + { + TMapOptions mapOptions = static_cast<TMapOptions>(options); + m_progressSize = m_activeMaps.GetCountrySize(m_countryIdx, mapOptions); + m_activeMaps.DownloadMap(m_countryIdx, mapOptions); + } + } } -bool CountryStatusDisplay::onTapEnded(m2::PointD const & pt) +void CountryStatusDisplay::Repaint() const { - if (m_downloadButton->isVisible()) - return m_downloadButton->onTapEnded(pt); - return false; + setIsDirtyLayout(true); + const_cast<CountryStatusDisplay *>(this)->invalidate(); } -bool CountryStatusDisplay::onTapCancelled(m2::PointD const & pt) +bool CountryStatusDisplay::IsStatusFailed() const +{ + return m_countryStatus == TStatus::EOutOfMemFailed || m_countryStatus == TStatus::EDownloadFailed; +} + +void CountryStatusDisplay::Lock() const +{ +#ifdef OMIM_OS_ANDROID + m_mutex.Lock(); +#endif +} + +void CountryStatusDisplay::Unlock() const { - if (m_downloadButton->isVisible()) - return m_downloadButton->onTapCancelled(pt); - return false; +#ifdef OMIM_OS_ANDROID + m_mutex.Unlock(); +#endif } |