File indexing completed on 2025-02-02 05:02:32
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "mapdownloadmanager.h" 0008 #include "reservationmanager.h" 0009 0010 #include "solidextras/networkstatus.h" 0011 0012 #include <KOSMIndoorMap/MapLoader> 0013 0014 #include <KItinerary/LocationUtil> 0015 #include <KItinerary/Place> 0016 #include <KItinerary/SortUtil> 0017 0018 #include <QDebug> 0019 #include <QTimer> 0020 0021 #include <cmath> 0022 0023 using namespace KItinerary; 0024 using SolidExtras::NetworkStatus; 0025 0026 MapDownloadManager::MapDownloadManager(QObject* parent) 0027 : QObject(parent) 0028 , m_netStatus(new NetworkStatus(this)) 0029 { 0030 connect(m_netStatus, &NetworkStatus::connectivityChanged, this, &MapDownloadManager::networkStatusChanged); 0031 connect(m_netStatus, &NetworkStatus::meteredChanged, this, &MapDownloadManager::networkStatusChanged); 0032 } 0033 0034 MapDownloadManager::~MapDownloadManager() = default; 0035 0036 void MapDownloadManager::setReservationManager(ReservationManager *resMgr) 0037 { 0038 m_resMgr = resMgr; 0039 0040 connect(m_resMgr, &ReservationManager::batchAdded, this, &MapDownloadManager::addAutomaticRequestForBatch); 0041 connect(m_resMgr, &ReservationManager::batchChanged, this, &MapDownloadManager::addAutomaticRequestForBatch); 0042 connect(m_resMgr, &ReservationManager::batchContentChanged, this, &MapDownloadManager::addAutomaticRequestForBatch); 0043 } 0044 0045 void MapDownloadManager::setAutomaticDownloadEnabled(bool enable) 0046 { 0047 m_autoDownloadEnabled = enable; 0048 if (canAutoDownload()) { 0049 download(); 0050 } 0051 } 0052 0053 static bool isRelevantTime(const QDateTime &dt) 0054 { 0055 const auto now = QDateTime::currentDateTime(); 0056 return dt > now && dt < now.addDays(14); 0057 } 0058 0059 void MapDownloadManager::download() 0060 { 0061 for (const auto &batchId : m_resMgr->batches()) { 0062 addRequestForBatch(batchId); 0063 } 0064 0065 qDebug() << m_pendingRequests.size() << "pending download requests" << m_netStatus->connectivity() << m_netStatus->metered(); 0066 downloadNext(); 0067 } 0068 0069 bool MapDownloadManager::canAutoDownload() const 0070 { 0071 return m_autoDownloadEnabled && m_netStatus->connectivity() != NetworkStatus::No && m_netStatus->metered() == NetworkStatus::No; 0072 } 0073 0074 void MapDownloadManager::addAutomaticRequestForBatch(const QString& batchId) 0075 { 0076 addRequestForBatch(batchId); 0077 if (canAutoDownload()) { 0078 QTimer::singleShot(std::chrono::seconds(5), this, &MapDownloadManager::downloadNext); 0079 } 0080 } 0081 0082 void MapDownloadManager::addRequestForBatch(const QString &batchId) 0083 { 0084 const auto res = m_resMgr->reservation(batchId); 0085 if (!LocationUtil::isLocationChange(res)) { 0086 return; 0087 } 0088 const auto arrTime = SortUtil::endDateTime(res); 0089 if (isRelevantTime(arrTime)) { 0090 const auto arr = LocationUtil::arrivalLocation(res); 0091 const auto arrGeo = LocationUtil::geo(arr); 0092 qDebug() << LocationUtil::name(arr) << arrGeo.latitude() << arrGeo.longitude(); 0093 addRequest(arrGeo.latitude(), arrGeo.longitude(), arrTime); 0094 } 0095 0096 const auto depTime = SortUtil::startDateTime(res); 0097 if (isRelevantTime(depTime)) { 0098 const auto dep = LocationUtil::departureLocation(res); 0099 const auto depGeo = LocationUtil::geo(dep); 0100 qDebug() << LocationUtil::name(dep) << depGeo.latitude() << depGeo.longitude(); 0101 addRequest(depGeo.latitude(), depGeo.longitude(), depTime); 0102 } 0103 } 0104 0105 void MapDownloadManager::addRequest(double lat, double lon, const QDateTime &cacheUntil) 0106 { 0107 if (std::isnan(lat) || std::isnan(lon)) { 0108 return; 0109 } 0110 0111 // check if we already have this cached 0112 for (auto it = m_cachedRequests.begin(); it != m_cachedRequests.end(); ++it) { 0113 if (LocationUtil::distance(lat, lon, (*it).lat, (*it).lon) > 10.0) { 0114 continue; 0115 } 0116 if ((*it).cacheUntil >= cacheUntil) { 0117 return; 0118 } 0119 m_cachedRequests.erase(it); 0120 break; 0121 } 0122 0123 // check if there is a pending request that would cover this 0124 for (auto &req : m_pendingRequests) { 0125 if (LocationUtil::distance(req.lat, req.lon, lat, lon) < 10.0) { 0126 req.cacheUntil = std::max(req.cacheUntil, cacheUntil); 0127 return; 0128 } 0129 } 0130 0131 m_pendingRequests.push_back({ lat, lon, cacheUntil }); 0132 } 0133 0134 void MapDownloadManager::downloadNext() 0135 { 0136 if (m_loader || m_pendingRequests.empty()) { 0137 return; 0138 } 0139 0140 m_currentRequest = std::move(m_pendingRequests.back()); 0141 m_pendingRequests.pop_back(); 0142 0143 m_loader = new KOSMIndoorMap::MapLoader(this); 0144 connect(m_loader, &KOSMIndoorMap::MapLoader::done, this, &MapDownloadManager::downloadFinished); 0145 m_loader->loadForCoordinate(m_currentRequest.lat, m_currentRequest.lon, m_currentRequest.cacheUntil); 0146 } 0147 0148 void MapDownloadManager::downloadFinished() 0149 { 0150 m_loader->deleteLater(); 0151 m_loader = nullptr; 0152 m_cachedRequests.push_back(std::move(m_currentRequest)); 0153 0154 if (m_pendingRequests.empty()) { 0155 Q_EMIT finished(); 0156 } else { 0157 downloadNext(); 0158 } 0159 } 0160 0161 void MapDownloadManager::networkStatusChanged() 0162 { 0163 if (canAutoDownload()) { 0164 downloadNext(); 0165 } 0166 } 0167 0168 #include "moc_mapdownloadmanager.cpp"