WIP: Remove local ads - WIP DON'T MERGE #165

Closed
rtsisyk wants to merge 1 commit from rt-remove-local-ads into master
119 changed files with 42 additions and 4911 deletions

View file

@ -306,7 +306,6 @@ add_subdirectory(generator/mwm_diff)
add_subdirectory(geometry)
add_subdirectory(indexer)
add_subdirectory(kml)
add_subdirectory(local_ads)
add_subdirectory(map)
add_subdirectory(metrics)
add_subdirectory(partners_api)

View file

@ -41770,10 +41770,6 @@ colors {
name: "RouteMaskPedestrian"
color: 2147483648
}
value {
name: "LocalAdsSecondaryTextOutline"
color: 16777215
}
value {
name: "BookmarkGreen"
color: 3968060
@ -41900,13 +41896,6 @@ colors {
name: "TransitTransferInnerMarker"
color: 16777215
}
value {
name: "LocalAdsPrimaryText"
}
value {
name: "LocalAdsPrimaryTextOutline"
color: 16777215
}
value {
name: "BookmarkPurple"
color: 10167474
@ -41942,9 +41931,6 @@ colors {
name: "RouteMarkPrimaryTextOutline"
color: 16777215
}
value {
name: "LocalAdsSecondaryText"
}
value {
name: "Route"
color: 34815

View file

@ -42162,9 +42162,6 @@ colors {
name: "RouteMaskPedestrian"
color: 2147483648
}
value {
name: "LocalAdsSecondaryTextOutline"
}
value {
name: "BookmarkGreen"
color: 3968060
@ -42290,13 +42287,6 @@ colors {
name: "TransitTransferInnerMarker"
color: 8947848
}
value {
name: "LocalAdsPrimaryText"
color: 8947848
}
value {
name: "LocalAdsPrimaryTextOutline"
}
value {
name: "BookmarkPurple"
color: 10167474
@ -42332,10 +42322,6 @@ colors {
value {
name: "RouteMarkPrimaryTextOutline"
}
value {
name: "LocalAdsSecondaryText"
color: 8947848
}
value {
name: "Route"
color: 34815

View file

@ -1,129 +0,0 @@
02001_hospital-l
02002_veterinary-l
02003_pharmacy-l
03001_restaurant-l
03002_bar-l
03003_beer-l
03004_fastfood-l
03005_cafe-l
04001_tourism-l
04002_viewpoint-l
04004_museum-l
04005_gallery-l
04006_zoo-l
04007_theatre-l
04008_cinema-l
04009_casino-l
04010_toilets-l
04021_stadium-l
05001_hotel-l
05002_motel-l
05003_alpine_hut-l
05004_caravan_site-l
05005_apartment-l
05006_hostel-l
06001_convenience-l
06002_marketplace-l
06003_kiosk-l
06004_grocery-l
06005_shop-l
06006_department_store-l
06007_electronics-l
06008_florist-l
06009_shop-bicycle-l
06010_jewelry-l
06011_beauty-l
06012_bakery-l
06013_gift-l
06014_furniture-l
06015_garden_center-l
06016_greengrocer-l
06017_shoes-l
06018_computer-l
06019_hardware-l
06020_doityourself-l
06021_sweets-l
06022_toys-l
06023_butcher-l
06024_mobile_phone-l
06025_optician-l
06026_sports-l
06027_chemist-l
06028_clothes-l
06029_book-shop-l
06030_petshop-l
06031_photo-shop-l
06032_copyshop-l
06033_seafood-shop-l
06034_ticket-shop-l
06035_outdoor-shop-l
06036_alcohol-l
06037_hand-l
06038_car_shop-l
06039_motorcycle_shop-l
06040_travel_agency_shop-l
06041_stationery_shop-l
06042_newsagent-l
06043_ice_cream-l
06044_funeral_directors-l
06045_media-l
06046_music-l
06047_erotic-l
07001_atm-l
07002_bank-l
07003_banknote-l
07004_office-financial-l
08001_fuel-l
08002_charging-station-l
08003_car-repair-l
08004_tire-repair-l
08005_car-sharing-l
08006_car-part-l
08007_car-wash-l
09001_bicycle-l
09002_swimming-l
09003_baseball-l
09004_tennis-l
09005_basketball-l
09006_america-football-l
09007_soccer-l
09008_golf-l
09009_pitch-l
09010_skiing-l
09011_cricket-l
09012_bowls-l
09013_curling-l
09014_diving-l
09015_archery-l
09016_australian-football-l
09017_climbing-l
09018_gym-l
09019_equestrian-l
09020_theme_park-l
0_burger-king
10001_kindergarten-l
10002_school-l
10003_college-l
10004_library-l
10005_mail-l
10008_historic-ship-l
10012_public-building-l
10013_hairdresser-l
10014_taxi-l
10015_office-l
10016_remains-l
10017_lighthouse-l
10022_laundry-l
10024_dentist-l
10025_bookmaker-l
10026_lawyer-l
10027_sauna-l
10028_picnic-l
10029_campsite-l
10030_hunting-tower-l
10031_bbq-l
10032_cemetery-l
10033_beach-l
10034_dog_park-l
10035_home-l
10036_vending-l

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 KiB

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 978 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 KiB

After

Width:  |  Height:  |  Size: 317 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 931 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 KiB

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 555 KiB

After

Width:  |  Height:  |  Size: 447 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 360 KiB

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 903 KiB

After

Width:  |  Height:  |  Size: 637 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 847 KiB

After

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 KiB

After

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 KiB

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 997 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 KiB

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 KiB

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View file

@ -114,7 +114,6 @@ Some of these contain their own README files.
* `installer` - long-abandoned installer for Windows.
* `iphone` - iOS UI.
* `kml` - manipulation of KML files.
* `local_ads` -
* `mapshot` - generate screenshots of maps, specified by coordinates and zoom level.
* `metrics` -
* `openlr` -

View file

@ -27,7 +27,6 @@ Currently available modules and setup's:
|-------------|----------------------------------------|
| pygen | generator/pygen/setup.py |
| pykmlib | kml/pykmlib/setup.py |
| pylocal_ads | local_ads/pylocal_ads/setup.py |
| pymvm_diff | generator/mwm_diff/pymwm_diff/setup.py |
| pysearch | search/pysearch/setup.py |
| pytracking | tracking/pytracking/setup.py |

View file

@ -42,7 +42,7 @@ float const kGlyphAreaMultiplier = 1.2f;
float const kGlyphAreaCoverage = 0.9f;
std::string const kDefaultSymbolsTexture = "symbols";
std::string const kSymbolTextures[] = { kDefaultSymbolsTexture, "symbols-ad" };
std::string const kSymbolTextures[] = { kDefaultSymbolsTexture };
uint32_t const kDefaultSymbolsIndex = 0;
namespace

View file

@ -1493,12 +1493,6 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView, bool activeFram
}
}
{
StencilWriterGuard guard(make_ref(m_postprocessRenderer), m_context);
RenderOverlayLayer(modelView);
RenderUserMarksLayer(modelView, DepthLayer::LocalAdsMarkLayer);
}
m_gpsTrackRenderer->RenderTrack(m_context, make_ref(m_gpuProgramManager), modelView, m_currentZoomLevel,
m_frameValues);
@ -1886,7 +1880,6 @@ void FrontendRenderer::RenderFrame()
void FrontendRenderer::BuildOverlayTree(ScreenBase const & modelView)
{
static std::vector<DepthLayer> layers = {DepthLayer::OverlayLayer,
DepthLayer::LocalAdsMarkLayer,
DepthLayer::NavigationLayer,
DepthLayer::RoutingBottomMarkLayer,
DepthLayer::RoutingMarkLayer};

View file

@ -151,7 +151,6 @@ bool RenderGroup::IsUserMark() const
depthLayer == DepthLayer::RoutingMarkLayer ||
depthLayer == DepthLayer::GuidesBottomMarkLayer ||
depthLayer == DepthLayer::GuidesMarkLayer ||
depthLayer == DepthLayer::LocalAdsMarkLayer ||
depthLayer == DepthLayer::SearchMarkLayer;
}

View file

@ -9,7 +9,6 @@ std::array<drape_ptr<RenderStateExtension>, static_cast<size_t>(DepthLayer::Laye
make_unique_dp<RenderStateExtension>(DepthLayer::Geometry3dLayer),
make_unique_dp<RenderStateExtension>(DepthLayer::UserLineLayer),
make_unique_dp<RenderStateExtension>(DepthLayer::OverlayLayer),
make_unique_dp<RenderStateExtension>(DepthLayer::LocalAdsMarkLayer),
make_unique_dp<RenderStateExtension>(DepthLayer::TransitSchemeLayer),
make_unique_dp<RenderStateExtension>(DepthLayer::UserMarkLayer),
make_unique_dp<RenderStateExtension>(DepthLayer::NavigationLayer),

View file

@ -16,7 +16,6 @@ enum class DepthLayer : uint8_t
Geometry3dLayer,
UserLineLayer,
OverlayLayer,
LocalAdsMarkLayer,
TransitSchemeLayer,
UserMarkLayer,
NavigationLayer,
@ -60,7 +59,6 @@ inline std::string DebugPrint(DepthLayer layer)
case DepthLayer::Geometry3dLayer: return "Geometry3dLayer";
case DepthLayer::UserLineLayer: return "UserLineLayer";
case DepthLayer::OverlayLayer: return "OverlayLayer";
case DepthLayer::LocalAdsMarkLayer: return "LocalAdsMarkLayer";
case DepthLayer::TransitSchemeLayer: return "TransitSchemeLayer";
case DepthLayer::UserMarkLayer: return "UserMarkLayer";
case DepthLayer::NavigationLayer: return "NavigationLayer";

View file

@ -1,12 +1,5 @@
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, PlacePageDataLocalAdsStatus) {
PlacePageDataLocalAdsStatusNotAvailable,
PlacePageDataLocalAdsStatusCandidate,
PlacePageDataLocalAdsStatusCustomer,
PlacePageDataLocalAdsStatusHidden
};
@class OpeningHours;
NS_ASSUME_NONNULL_BEGIN
@ -24,9 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
@property(nonatomic, readonly, nullable) NSString *address;
@property(nonatomic, readonly, nullable) NSString *rawCoordinates;
@property(nonatomic, readonly, nullable) NSString *formattedCoordinates;
@property(nonatomic, readonly, nullable) NSString *localAdsUrl;
@property(nonatomic, readonly) BOOL wifiAvailable;
@property(nonatomic, readonly) PlacePageDataLocalAdsStatus localAdsStatus;
@end

View file

@ -7,19 +7,6 @@
using namespace place_page;
using namespace osm;
static PlacePageDataLocalAdsStatus convertLocalAdsStatus(LocalAdsStatus status) {
switch (status) {
case LocalAdsStatus::NotAvailable:
return PlacePageDataLocalAdsStatusNotAvailable;
case LocalAdsStatus::Candidate:
return PlacePageDataLocalAdsStatusCandidate;
case LocalAdsStatus::Customer:
return PlacePageDataLocalAdsStatusCustomer;
case LocalAdsStatus::Hidden:
return PlacePageDataLocalAdsStatusHidden;
}
}
@implementation PlacePageInfoData
@end
@ -71,8 +58,6 @@ static PlacePageDataLocalAdsStatus convertLocalAdsStatus(LocalAdsStatus status)
_address = rawData.GetAddress().empty() ? nil : @(rawData.GetAddress().c_str());
_rawCoordinates = @(rawData.GetFormattedCoordinate(true).c_str());
_formattedCoordinates = @(rawData.GetFormattedCoordinate(false).c_str());
_localAdsStatus = convertLocalAdsStatus(rawData.GetLocalAdsStatus());
_localAdsUrl = rawData.GetLocalAdsUrl().empty() ? nil : @(rawData.GetLocalAdsUrl().c_str());
}
return self;
}

View file

@ -33,7 +33,6 @@
#import "MWMDiscoveryController.h"
#import "MWMEditorHelper.h"
#import "MWMFrameworkListener.h"
#import "MWMGeoTrackerCore.h"
#import "MWMKeyboard.h"
#import "MWMLocationManager.h"
#import "MWMLocationModeListener.h"

View file

@ -1,7 +0,0 @@
final class Geo: NSObject {
@objc
static func geoTracker() -> IGeoTracker {
let trackerCore = MWMGeoTrackerCore()
return GeoTracker(trackerCore: trackerCore)
}
}

View file

@ -1,5 +0,0 @@
@objc
protocol IGeoTracker: AnyObject {
func startTracking()
func endTracking()
}

View file

@ -1,15 +0,0 @@
#import "IMWMGeoTrackerZone.h"
NS_ASSUME_NONNULL_BEGIN
@protocol IMWMGeoTrackerCore
- (NSArray<id<IMWMGeoTrackerZone>> *)geoZonesForLat:(CLLocationDegrees)lat
lon:(CLLocationDegrees)lon
accuracy:(CLLocationAccuracy) accuracy;
- (void)logEnterZone:(id<IMWMGeoTrackerZone>)zone location:(CLLocation *)location;
@end
NS_ASSUME_NONNULL_END

View file

@ -1,11 +0,0 @@
NS_ASSUME_NONNULL_BEGIN
@protocol IMWMGeoTrackerZone<NSObject>
@property (nonatomic, readonly) CLLocationDegrees latitude;
@property (nonatomic, readonly) CLLocationDegrees longitude;
@property (nonatomic, readonly) NSString *identifier;
@end
NS_ASSUME_NONNULL_END

View file

@ -1,66 +0,0 @@
class GeoTracker: NSObject, IGeoTracker {
private let trackerCore: IMWMGeoTrackerCore
private let locationManager = CLLocationManager()
private var trackingZones: [String : IMWMGeoTrackerZone]?
private var zoneTrackers: [String : GeoZoneTracker] = [:]
init(trackerCore: IMWMGeoTrackerCore) {
self.trackerCore = trackerCore
super.init()
locationManager.delegate = self
}
deinit {
locationManager.delegate = nil
}
@objc
func startTracking() {
if CLLocationManager.significantLocationChangeMonitoringAvailable() {
locationManager.startMonitoringSignificantLocationChanges()
}
}
@objc
func endTracking() {
locationManager.stopMonitoringSignificantLocationChanges()
}
}
extension GeoTracker: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
locationManager.monitoredRegions.forEach {
locationManager.stopMonitoring(for: $0)
}
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
let zones = trackerCore.geoZones(forLat: location.coordinate.latitude,
lon: location.coordinate.longitude,
accuracy: location.horizontalAccuracy)
zones.forEach {
locationManager.startMonitoring(
for: CLCircularRegion(center: CLLocationCoordinate2DMake($0.latitude, $0.longitude),
radius: 100,
identifier: $0.identifier))
}
trackingZones = zones.reduce(into: [:]) { $0[$1.identifier] = $1 }
}
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if let zone = trackingZones?[region.identifier] {
let zoneTracker = GeoZoneTracker(zone, trackerCore: trackerCore)
zoneTracker.startTracking()
zoneTrackers[region.identifier] = zoneTracker
}
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
if let zoneTracker = zoneTrackers[region.identifier] {
zoneTracker.stopTracking()
zoneTrackers[region.identifier] = nil
}
}
}

View file

@ -1,39 +0,0 @@
class GeoZoneTracker: NSObject {
let geoZone: IMWMGeoTrackerZone
let trackerCore: IMWMGeoTrackerCore
let locationManager = CLLocationManager()
init(_ zone: IMWMGeoTrackerZone, trackerCore: IMWMGeoTrackerCore) {
self.geoZone = zone
self.trackerCore = trackerCore
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.distanceFilter = 10
super.init()
locationManager.delegate = self
}
deinit {
stopTracking()
locationManager.delegate = nil
}
func startTracking() {
locationManager.startUpdatingLocation()
}
func stopTracking() {
locationManager.stopUpdatingLocation()
}
}
extension GeoZoneTracker: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let visitedLocation = locations.filter({
$0.horizontalAccuracy <= 30 &&
$0.distance(from: CLLocation(latitude: geoZone.latitude, longitude: geoZone.longitude)) <= 20
}).first {
trackerCore.logEnter(geoZone, location: visitedLocation)
stopTracking()
}
}
}

View file

@ -1,9 +0,0 @@
#import "IMWMGeoTrackerCore.h"
NS_ASSUME_NONNULL_BEGIN
@interface MWMGeoTrackerCore : NSObject<IMWMGeoTrackerCore>
@end
NS_ASSUME_NONNULL_END

View file

@ -1,74 +0,0 @@
#import "MWMGeoTrackerCore.h"
#include "map/framework_light.hpp"
@interface MWMGeoTrackerZone: NSObject<IMWMGeoTrackerZone>
@property (nonatomic, readwrite) NSString *identifier;
- (instancetype)initWithCampaignFeature:(CampaignFeature const &)feature;
- (CampaignFeature const &)feature;
@end
@implementation MWMGeoTrackerZone {
CampaignFeature _feature;
}
- (instancetype)initWithCampaignFeature:(CampaignFeature const &)feature {
self = [super init];
if (self) {
_feature = feature;
_identifier = [NSUUID UUID].UUIDString;
}
return self;
}
- (CLLocationDegrees)latitude {
return _feature.m_lat;
}
- (CLLocationDegrees)longitude {
return _feature.m_lon;
}
- (CampaignFeature const &)feature {
return _feature;
}
@end
@implementation MWMGeoTrackerCore
- (NSArray<id<IMWMGeoTrackerZone>> *)geoZonesForLat:(CLLocationDegrees)lat
lon:(CLLocationDegrees)lon
accuracy:(CLLocationAccuracy)accuracy {
lightweight::Framework f(lightweight::REQUEST_TYPE_LOCAL_ADS_FEATURES);
auto campainFeatures = f.GetLocalAdsFeatures(lat, lon, accuracy, 20);
NSMutableArray * result = [NSMutableArray array];
for (auto const & cf : campainFeatures) {
[result addObject:[[MWMGeoTrackerZone alloc] initWithCampaignFeature:cf]];
}
return [result copy];
}
- (void)logEnterZone:(id<IMWMGeoTrackerZone>)zone location:(CLLocation *)location {
NSAssert([zone isKindOfClass:MWMGeoTrackerZone.class], @"zone must be of MWMGeoTrackerZone type");
MWMGeoTrackerZone * geoZone = (MWMGeoTrackerZone *)zone;
auto feature = geoZone.feature;
lightweight::Framework f(lightweight::REQUEST_TYPE_LOCAL_ADS_STATISTICS);
local_ads::Event event(local_ads::EventType::Visit,
feature.m_mwmVersion,
feature.m_countryId,
feature.m_featureIndex,
0,
local_ads::Clock::now(),
location.coordinate.latitude,
location.coordinate.longitude,
location.horizontalAccuracy);
f.GetLocalAdsStatistics()->RegisterEvent(std::move(event));
}
@end

View file

@ -129,7 +129,6 @@ void setShowLocationAlert(BOOL needShow) {
@property(nonatomic) Observers * observers;
@property(nonatomic) MWMLocationFrameworkUpdate frameworkUpdateMode;
@property(nonatomic) location::TLocationSource locationSource;
@property(nonatomic) id<IGeoTracker> geoTracker;
@end
@ -153,7 +152,6 @@ void setShowLocationAlert(BOOL needShow) {
if (self)
{
_observers = [Observers weakObjectsHashTable];
_geoTracker = [Geo geoTracker];
}
return self;
}
@ -479,7 +477,6 @@ void setShowLocationAlert(BOOL needShow) {
if ([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
[locationManager requestAlwaysAuthorization];
[locationManager startUpdatingLocation];
[self.geoTracker startTracking];
setPermissionRequested();
if ([CLLocationManager headingAvailable])
[locationManager startUpdatingHeading];

View file

@ -78,7 +78,6 @@
341F09841C20138100F18AC5 /* libpugixml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 341F09831C20138100F18AC5 /* libpugixml.a */; };
34201E091DC0DC7300D24118 /* libpartners_api.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DDB4BC31DAB98F000F4D021 /* libpartners_api.a */; };
34201E0C1DC0E33100D24118 /* libtracking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 34201E0B1DC0E33100D24118 /* libtracking.a */; };
342639361EA0E60A0025EB89 /* local_ads_symbols.txt in Resources */ = {isa = PBXBuildFile; fileRef = 450703081E9E6CF000E8C029 /* local_ads_symbols.txt */; };
342CC5F21C2D7730005F3FE5 /* MWMAuthorizationLoginViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 342CC5F01C2D7730005F3FE5 /* MWMAuthorizationLoginViewController.mm */; };
342EE4121C43DAA7009F6A49 /* MWMAuthorizationWebViewLoginViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 342EE4101C43DAA7009F6A49 /* MWMAuthorizationWebViewLoginViewController.mm */; };
343064411E9FDC7300DC7665 /* SearchIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3430643F1E9FDC7300DC7665 /* SearchIndex.swift */; };
@ -287,7 +286,6 @@
4586D0E71F4813AB00DF9CE5 /* libmwm_diff.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4586D0E61F4813AB00DF9CE5 /* libmwm_diff.a */; };
4598438621394CFD00F8CAB2 /* MetalPerformanceShaders.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4598438521394CFD00F8CAB2 /* MetalPerformanceShaders.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
45CBCCBA20590AAB006B55C2 /* libkml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 45CBCCBB20590AAB006B55C2 /* libkml.a */; };
45FFD65D1E965EBE00DB854E /* liblocal_ads.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 45FFD65C1E965EBE00DB854E /* liblocal_ads.a */; };
4701A93D243A917900B87683 /* TouchTransparentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4701A93C243A917800B87683 /* TouchTransparentView.swift */; };
4707E4B12372FE860017DF6E /* PlacePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707E4AF2372FE860017DF6E /* PlacePageViewController.swift */; };
4707E4B42372FF480017DF6E /* PlacePage.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4707E4B32372FF480017DF6E /* PlacePage.storyboard */; };
@ -369,11 +367,6 @@
47A6F3C4235F47B90053FBA4 /* CitySubscriptionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 47A6F3C1235F47B90053FBA4 /* CitySubscriptionViewController.xib */; };
47A6F3C5235F47B90053FBA4 /* BookmarksSubscriptionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A6F3C2235F47B90053FBA4 /* BookmarksSubscriptionButton.swift */; };
47AEF8402231249E00D20538 /* categories_brands.txt in Resources */ = {isa = PBXBuildFile; fileRef = 47AEF83F2231249E00D20538 /* categories_brands.txt */; };
47B06DED21B696C20094CCAD /* GeoTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47B06DEC21B696C20094CCAD /* GeoTracker.swift */; };
47B06DF021B697230094CCAD /* MWMGeoTrackerCore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47B06DEF21B697230094CCAD /* MWMGeoTrackerCore.mm */; };
47B06DF921B95F5E0094CCAD /* IGeoTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47B06DF821B95F5E0094CCAD /* IGeoTracker.swift */; };
47B06DFE21B965950094CCAD /* Geo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47B06DFD21B965950094CCAD /* Geo.swift */; };
47B06E0021BAAC270094CCAD /* GeoZoneTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47B06DFF21BAAC270094CCAD /* GeoZoneTracker.swift */; };
47B505542136B0C2009CBB55 /* DiscoveryTutorialBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = 47B505522136AB41009CBB55 /* DiscoveryTutorialBlur.xib */; };
47B505552136B0CF009CBB55 /* SearchTutorialBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = 47B505532136AD69009CBB55 /* SearchTutorialBlur.xib */; };
47B9065221C7FA400079C85E /* MWMWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 47B9064921C7FA3B0079C85E /* MWMWebImage.m */; };
@ -1377,7 +1370,6 @@
408645FB21495EB1000A4A1D /* categories_cuisines.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = categories_cuisines.txt; path = ../../data/categories_cuisines.txt; sourceTree = "<group>"; };
4501B1922077C35A001B9173 /* resources-xxxhdpi_clear */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "resources-xxxhdpi_clear"; path = "../../data/resources-xxxhdpi_clear"; sourceTree = "<group>"; };
4501B1932077C35A001B9173 /* resources-xxxhdpi_dark */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "resources-xxxhdpi_dark"; path = "../../data/resources-xxxhdpi_dark"; sourceTree = "<group>"; };
450703081E9E6CF000E8C029 /* local_ads_symbols.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = local_ads_symbols.txt; path = ../../data/local_ads_symbols.txt; sourceTree = "<group>"; };
450B5C822355F50200E9019E /* libweb_api.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libweb_api.a; sourceTree = BUILT_PRODUCTS_DIR; };
451950391B7A3E070085DA05 /* patterns.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = patterns.txt; path = ../../data/patterns.txt; sourceTree = "<group>"; };
452FCA3A1B6A3DF7007019AB /* colors.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = colors.txt; path = ../../data/colors.txt; sourceTree = "<group>"; };
@ -1391,7 +1383,6 @@
4598438521394CFD00F8CAB2 /* MetalPerformanceShaders.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalPerformanceShaders.framework; path = System/Library/Frameworks/MetalPerformanceShaders.framework; sourceTree = SDKROOT; };
4598438921394D7700F8CAB2 /* shaders_metal.metallib */ = {isa = PBXFileReference; explicitFileType = "archive.metal-library"; path = shaders_metal.metallib; sourceTree = BUILT_PRODUCTS_DIR; };
45CBCCBB20590AAB006B55C2 /* libkml.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libkml.a; sourceTree = BUILT_PRODUCTS_DIR; };
45FFD65C1E965EBE00DB854E /* liblocal_ads.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liblocal_ads.a; path = "/Users/r.kuznetsov/Dev/Projects/omim/xcode/local_ads/../../../omim-build/xcode/Debug/liblocal_ads.a"; sourceTree = "<absolute>"; };
46F26CD610F623BA00ECCA39 /* EAGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = EAGLView.h; sourceTree = "<group>"; };
46F26CD710F623BA00ECCA39 /* EAGLView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = EAGLView.mm; sourceTree = "<group>"; };
46F8A2EB10EB63040045521A /* MapViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = MapViewController.h; sourceTree = "<group>"; };
@ -1481,14 +1472,6 @@
47A6F3C1235F47B90053FBA4 /* CitySubscriptionViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CitySubscriptionViewController.xib; sourceTree = "<group>"; };
47A6F3C2235F47B90053FBA4 /* BookmarksSubscriptionButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksSubscriptionButton.swift; sourceTree = "<group>"; };
47AEF83F2231249E00D20538 /* categories_brands.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = categories_brands.txt; path = ../../data/categories_brands.txt; sourceTree = "<group>"; };
47B06DEC21B696C20094CCAD /* GeoTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoTracker.swift; sourceTree = "<group>"; };
47B06DEE21B697230094CCAD /* MWMGeoTrackerCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMGeoTrackerCore.h; sourceTree = "<group>"; };
47B06DEF21B697230094CCAD /* MWMGeoTrackerCore.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMGeoTrackerCore.mm; sourceTree = "<group>"; };
47B06DF821B95F5E0094CCAD /* IGeoTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IGeoTracker.swift; sourceTree = "<group>"; };
47B06DFA21B960080094CCAD /* IMWMGeoTrackerCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMWMGeoTrackerCore.h; sourceTree = "<group>"; };
47B06DFB21B960CE0094CCAD /* IMWMGeoTrackerZone.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMWMGeoTrackerZone.h; sourceTree = "<group>"; };
47B06DFD21B965950094CCAD /* Geo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Geo.swift; sourceTree = "<group>"; };
47B06DFF21BAAC270094CCAD /* GeoZoneTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoZoneTracker.swift; sourceTree = "<group>"; };
47B505522136AB41009CBB55 /* DiscoveryTutorialBlur.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DiscoveryTutorialBlur.xib; sourceTree = "<group>"; };
47B505532136AD69009CBB55 /* SearchTutorialBlur.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SearchTutorialBlur.xib; sourceTree = "<group>"; };
47B9064921C7FA3B0079C85E /* MWMWebImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMWebImage.m; sourceTree = "<group>"; };
@ -2180,7 +2163,6 @@
34E6F2DB1F459C05008E14F9 /* GLKit.framework in Frameworks */,
F6F8E3C51EF8469700F2DE8F /* libugc.a in Frameworks */,
3488B03B1E9D13EF0068AFD8 /* UserNotifications.framework in Frameworks */,
45FFD65D1E965EBE00DB854E /* liblocal_ads.a in Frameworks */,
34D1B6F11E95096B0057E9C7 /* libicu.a in Frameworks */,
671E78D31E6A423300B2859B /* librouting_common.a in Frameworks */,
67B78B471E422E0A0018E590 /* MobileCoreServices.framework in Frameworks */,
@ -2370,7 +2352,6 @@
34D1B6F01E95096B0057E9C7 /* libicu.a */,
6741AAAE1BF356B9002C974C /* libindexer.a */,
6741AAAF1BF356B9002C974C /* libjansson.a */,
45FFD65C1E965EBE00DB854E /* liblocal_ads.a */,
6741AAB11BF356B9002C974C /* libmap.a */,
340DC82B1C4E72C700EAA2CC /* liboauthcpp.a */,
6741AAB31BF356B9002C974C /* libopening_hours.a */,
@ -2520,7 +2501,6 @@
340475291E081A4600C92850 /* Location */ = {
isa = PBXGroup;
children = (
47B06DEB21B6962D0094CCAD /* GeoTracker */,
3404752A1E081A4600C92850 /* MWMLocationHelpers.h */,
3404752B1E081A4600C92850 /* MWMLocationManager.h */,
3404752C1E081A4600C92850 /* MWMLocationManager.mm */,
@ -3389,29 +3369,6 @@
path = Metrics;
sourceTree = "<group>";
};
47B06DEB21B6962D0094CCAD /* GeoTracker */ = {
isa = PBXGroup;
children = (
47B06DFD21B965950094CCAD /* Geo.swift */,
47B06DFC21B965450094CCAD /* Impl */,
47B06DF821B95F5E0094CCAD /* IGeoTracker.swift */,
47B06DFB21B960CE0094CCAD /* IMWMGeoTrackerZone.h */,
47B06DFA21B960080094CCAD /* IMWMGeoTrackerCore.h */,
);
path = GeoTracker;
sourceTree = "<group>";
};
47B06DFC21B965450094CCAD /* Impl */ = {
isa = PBXGroup;
children = (
47B06DEC21B696C20094CCAD /* GeoTracker.swift */,
47B06DFF21BAAC270094CCAD /* GeoZoneTracker.swift */,
47B06DEE21B697230094CCAD /* MWMGeoTrackerCore.h */,
47B06DEF21B697230094CCAD /* MWMGeoTrackerCore.mm */,
);
path = Impl;
sourceTree = "<group>";
};
47B9064821C7FA100079C85E /* WebImage */ = {
isa = PBXGroup;
children = (
@ -4864,7 +4821,6 @@
EEFE7C1212F8C9E1006AF8C3 /* fonts_blacklist.txt */,
EEFE7C1312F8C9E1006AF8C3 /* fonts_whitelist.txt */,
BB7626B41E8559980031D71C /* icudt57l.dat */,
450703081E9E6CF000E8C029 /* local_ads_symbols.txt */,
F623DA6A1C9C2731006A3436 /* opening_hours_how_to_edit.html */,
FA85F632145DDDC20090E1A0 /* packed_polygons.bin */,
451950391B7A3E070085DA05 /* patterns.txt */,
@ -5119,7 +5075,6 @@
F6E2FDF51E097BA00083EBEC /* MWMOpeningHoursAddScheduleTableViewCell.xib in Resources */,
CD96C70D22A681C400DB7CFE /* DiscoveryGuideCell.xib in Resources */,
F6E2FDFB1E097BA00083EBEC /* MWMOpeningHoursAllDayTableViewCell.xib in Resources */,
342639361EA0E60A0025EB89 /* local_ads_symbols.txt in Resources */,
4554B6EC1E55F0EF0084017F /* drules_proto_vehicle_clear.bin in Resources */,
47CA68F2250B54AF00671019 /* BookmarkCell.xib in Resources */,
337F98A321D37B5800C8AC27 /* SearchHistoryViewController.xib in Resources */,
@ -5353,7 +5308,6 @@
993DF12123F6BDB100AC231A /* UIViewControllerRenderer.swift in Sources */,
34D3AFF61E37A36A004100F9 /* UICollectionView+Cells.swift in Sources */,
4767CDA420AAF66B00BD8166 /* NSAttributedString+HTML.swift in Sources */,
47B06DFE21B965950094CCAD /* Geo.swift in Sources */,
6741A9A91BF340DE002C974C /* MWMDefaultAlert.mm in Sources */,
990F33B624BC915200D0F426 /* SearchActionBarView.swift in Sources */,
99514BBA23E82B450085D3A7 /* ElevationProfileViewController.swift in Sources */,
@ -5617,7 +5571,6 @@
3444DFD21F17620C00E73099 /* MWMMapWidgetsHelper.mm in Sources */,
348A8DFB1F66775A00D83026 /* RatingViewSettings.swift in Sources */,
3472B5E1200F86C800DC6CD5 /* MWMEditorHelper.mm in Sources */,
47B06DF021B697230094CCAD /* MWMGeoTrackerCore.mm in Sources */,
99B6A74C2362F5AA002C94CB /* PromoButton.swift in Sources */,
99F3EB1123F418C900C713F8 /* PlacePageBuilder.swift in Sources */,
4735008A23A83CF700661A95 /* DownloadedMapsDataSource.swift in Sources */,
@ -5738,7 +5691,6 @@
F6E2FF4E1E097BA00083EBEC /* MWMAboutController.m in Sources */,
993F5512237C622700545511 /* DeepLinkFileStrategy.swift in Sources */,
47EF73FE247056A600D32AB8 /* GuidesGalleryCell.swift in Sources */,
47B06DF921B95F5E0094CCAD /* IGeoTracker.swift in Sources */,
CDCA27812243F59800167D87 /* CarPlayRouter.swift in Sources */,
99CB34BD2369EAAC001D28AD /* TermsOfUsePresenter.swift in Sources */,
34F5E0D41E3F254800B1C415 /* UIView+Hierarchy.swift in Sources */,
@ -5905,7 +5857,6 @@
3488B01A1E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */,
6741AA281BF340DE002C974C /* MWMAlert.mm in Sources */,
F6E2FF571E097BA00083EBEC /* MWMMobileInternetViewController.m in Sources */,
47B06E0021BAAC270094CCAD /* GeoZoneTracker.swift in Sources */,
99A906DD23F6F7030005872B /* AddReviewViewController.swift in Sources */,
993DF11323F6BDB100AC231A /* UITableViewRenderer.swift in Sources */,
3404F4952028A1B80090E401 /* BMCPermissionsCell.swift in Sources */,
@ -5923,7 +5874,6 @@
99A906E023F6F7030005872B /* RatingSummaryViewController.swift in Sources */,
993F550D237C622700545511 /* DeepLinkLeadStrategy.swift in Sources */,
337F98B221D3BAE600C8AC27 /* SearchCategoriesViewController.swift in Sources */,
47B06DED21B696C20094CCAD /* GeoTracker.swift in Sources */,
349FC54B1F680DAE00968C9F /* ExpandableReviewSettings.swift in Sources */,
F6E2FE0A1E097BA00083EBEC /* MWMOpeningHoursDeleteScheduleTableViewCell.mm in Sources */,
3454D7DA1E07F045004AF2AD /* UILabel+RuntimeAttributes.m in Sources */,
@ -6070,9 +6020,7 @@
DEVELOPMENT_TEAM = W55CJ2SCF7;
"EXCLUDED_SOURCE_FILE_NAMES[sdk=iphonesimulator*]" = MetalContextFactory.mm;
"EXCLUDED_SOURCE_FILE_NAMES[sdk=macosx*]" = MetalContextFactory.mm;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
);
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_SWIFT_FLAGS = "$(inherited)";
};
@ -6089,9 +6037,7 @@
DEVELOPMENT_TEAM = W55CJ2SCF7;
"EXCLUDED_SOURCE_FILE_NAMES[sdk=iphonesimulator*]" = MetalContextFactory.mm;
"EXCLUDED_SOURCE_FILE_NAMES[sdk=macosx*]" = MetalContextFactory.mm;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
);
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_SWIFT_FLAGS = "$(inherited)";
};
@ -6119,9 +6065,7 @@
"$(OMIM_ROOT)/3party/jansson/src",
);
INFOPLIST_FILE = OMaps.plist;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_CFLAGS = (
"$(inherited)",
"-Wall",

View file

@ -53,7 +53,6 @@ protocol PlacePageInfoViewControllerDelegate: AnyObject {
func didPressCall()
func didPressWebsite()
func didPressEmail()
func didPressLocalAd()
}
class PlacePageInfoViewController: UIViewController {
@ -78,7 +77,6 @@ class PlacePageInfoViewController: UIViewController {
private var wifiView: InfoItemViewController?
private var addressView: InfoItemViewController?
private var coordinatesView: InfoItemViewController?
private var localAdsButton: UIButton?
var placePageInfoData: PlacePageInfoData!
weak var delegate: PlacePageInfoViewControllerDelegate?
@ -158,35 +156,10 @@ class PlacePageInfoViewController: UIViewController {
coordinatesView?.accessoryImage.image = UIImage(named: "ic_placepage_change")
coordinatesView?.accessoryImage.isHidden = false
coordinatesView?.canShowMenu = true
// switch placePageInfoData.localAdsStatus {
// case .candidate:
// localAdsButton = createLocalAdsButton(L("create_campaign_button"))
// case .customer:
// localAdsButton = createLocalAdsButton(L("view_campaign_button"))
// case .notAvailable, .hidden:
// coordinatesView?.separatorView.isHidden = true
// @unknown default:
// fatalError()
// }
}
// MARK: private
@objc private func onLocalAdsButton(_ sender: UIButton) {
delegate?.didPressLocalAd()
}
private func createLocalAdsButton(_ title: String) -> UIButton {
let button = UIButton()
button.setTitle(title, for: .normal)
button.styleName = "FlatNormalTransButtonBig"
button.heightAnchor.constraint(equalToConstant: 44).isActive = true
stackView.addArrangedSubview(button)
button.addTarget(self, action: #selector(onLocalAdsButton(_:)), for: .touchUpInside)
return button
}
private func createInfoItem(_ info: String,
icon: UIImage?,
style: Style = .regular,

View file

@ -52,10 +52,6 @@ extension PlacePageInteractor: PlacePageInfoViewControllerDelegate {
func didPressEmail() {
}
func didPressLocalAd() {
MWMPlacePageManagerHelper.openLocalAdsURL(placePageData)
}
}
// MARK: - WikiDescriptionViewControllerDelegate

View file

@ -444,23 +444,6 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type)
[[MapViewController sharedController].navigationController pushViewController:vc animated:YES];
}
- (void)openLocalAdsURL:(PlacePageData *)data {
NSURL *url = [NSURL URLWithString:data.infoData.localAdsUrl];
if (!url)
return;
auto const & feature = GetFramework().GetCurrentPlacePageInfo().GetID();
[Statistics logEvent:kStatPlacePageOwnershipButtonClick
withParameters:@{
@"mwm_name" : @(feature.GetMwmName().c_str()),
@"mwm_version" : @(feature.GetMwmVersion()),
@"feature_id" : @(feature.m_index)
}
atLocation:[MWMLocationManager lastLocation]];
[self.ownerViewController openUrl:url];
}
- (void)openWebsite:(PlacePageData *)data {
NSURL *url = [NSURL URLWithString:data.infoData.website];
if (url) {

View file

@ -16,7 +16,6 @@
+ (void)addPlace:(CLLocationCoordinate2D)coordinate;
+ (void)orderTaxi:(PlacePageData *)data;
+ (void)taxiShown:(PlacePageData *)data;
+ (void)openLocalAdsURL:(PlacePageData *)data;
+ (void)openWebsite:(PlacePageData *)data;
+ (void)call:(PlacePageData *)data;
+ (void)showAllFacilities:(PlacePageData *)data;

View file

@ -18,7 +18,6 @@
- (void)addPlace:(CLLocationCoordinate2D)coordinate;
- (void)orderTaxi:(PlacePageData *)data;
- (void)logTaxiShown:(PlacePageData *)data;
- (void)openLocalAdsURL:(PlacePageData *)data;
- (void)openWebsite:(PlacePageData *)data;
- (void)call:(PlacePageData *)data;
- (void)showAllFacilities:(PlacePageData *)data;
@ -83,10 +82,6 @@
[[MWMMapViewControlsManager manager].placePageManager logTaxiShown:data];
}
+ (void)openLocalAdsURL:(PlacePageData *)data {
[[MWMMapViewControlsManager manager].placePageManager openLocalAdsURL:data];
}
+ (void)openWebsite:(PlacePageData *)data {
[[MWMMapViewControlsManager manager].placePageManager openWebsite:data];
}

View file

@ -125,9 +125,7 @@ bool PopularityHasHigherPriority(bool hasPosition, double distanceInMeters)
self.popularView.hidden = !showPopular;
}
if (productInfo.m_isLocalAdsCustomer)
[self setStyleAndApply: @"SearchCellAds"];
else if (isAvailable)
if (isAvailable)
[self setStyleAndApply: @"SearchCellAvaliable"];
else
[self setStyleAndApply: @"Background"];

View file

@ -1,26 +0,0 @@
project(local_ads)
include_directories(
${OMIM_ROOT}/3party/jansson/src
)
set(
SRC
campaign.hpp
campaign_serialization.cpp
campaign_serialization.hpp
config.hpp
event.cpp
event.hpp
file_helpers.cpp
file_helpers.hpp
icons_info.cpp
icons_info.hpp
statistics.cpp
statistics.hpp
)
omim_add_library(${PROJECT_NAME} ${SRC})
omim_add_pybindings_subdirectory(pylocal_ads)
omim_add_test_subdirectory(local_ads_tests)

View file

@ -1,50 +0,0 @@
#pragma once
#include "local_ads/icons_info.hpp"
#include <cstdint>
#include <string>
namespace local_ads
{
struct Campaign
{
// Constructor for data Version::v1
Campaign(uint32_t featureId, uint16_t iconId, uint8_t daysBeforeExpired)
: m_featureId(featureId), m_iconId(iconId), m_daysBeforeExpired(daysBeforeExpired)
{
}
// Constructor for data Version::v2
Campaign(uint32_t featureId, uint16_t iconId, uint8_t daysBeforeExpired, uint8_t zoomLevel,
uint8_t priority)
: m_featureId(featureId)
, m_iconId(iconId)
, m_daysBeforeExpired(daysBeforeExpired)
, m_minZoomLevel(zoomLevel)
, m_priority(priority)
{
}
std::string GetIconName() const { return IconsInfo::Instance().GetIcon(m_iconId); }
uint32_t m_featureId = 0;
uint16_t m_iconId = 0;
// Supported values range: 0-255. In case when accurate value is more than 255, we expect updated
// data will be received during this time interval. For ex. accurate value is 365, in this case
// first 110 days this field will store value 255.
uint8_t m_daysBeforeExpired = 0;
// Supported values range: 10-17.
uint8_t m_minZoomLevel = 16;
// Supported values range: 0-7
uint8_t m_priority = 0;
};
inline bool operator==(Campaign const & a, Campaign const & b)
{
return a.m_featureId == b.m_featureId &&
a.m_iconId == b.m_iconId &&
a.m_daysBeforeExpired == b.m_daysBeforeExpired &&
a.m_minZoomLevel == b.m_minZoomLevel &&
a.m_priority == b.m_priority;
}
} // namespace local_ads

View file

@ -1,238 +0,0 @@
#include "local_ads/campaign_serialization.hpp"
#include "coding/byte_stream.hpp"
#include "coding/reader.hpp"
#include "coding/varint.hpp"
#include "coding/write_to_sink.hpp"
#include "base/exception.hpp"
#include "base/logging.hpp"
#include "base/stl_helpers.hpp"
#include <climits>
#include <cstdint>
#include <type_traits>
#include <vector>
namespace
{
using namespace local_ads;
DECLARE_EXCEPTION(UnknownVersion, RootException);
auto const kHalfByteShift = CHAR_BIT / 2;
auto const kHalfByteMaxValue = 15;
auto const kLowerMask = 0x0F;
auto const kUpperMask = 0xF0;
auto const kMinZoomLevel = 10;
auto const kMaxZoomLevel = 17;
auto const kMaxPriority = 7;
template <typename Integral, typename Source,
std::enable_if_t<std::is_integral<Integral>::value, void *> = nullptr>
std::vector<Integral> ReadVarUintArray(Source & s, size_t chunksNumber)
{
std::vector<Integral> result;
for (size_t i = 0; i < chunksNumber; ++i)
result.emplace_back(static_cast<Integral>(ReadVarUint<uint64_t>(s)));
return result;
}
template <typename Integral, typename Source>
std::vector<Integral> ReadArray(Source & s, size_t chunksNumber)
{
std::vector<Integral> result;
for (size_t i = 0; i < chunksNumber; ++i)
{
result.emplace_back(ReadPrimitiveFromSource<Integral>(s));
}
return result;
}
std::vector<uint8_t> SerializeV1(std::vector<Campaign> const & campaigns)
{
std::vector<uint8_t> buff;
PushBackByteSink<decltype(buff)> dst(buff);
WriteToSink(dst, Version::V1);
WriteToSink(dst, campaigns.size());
for (auto const & c : campaigns)
WriteVarUint(dst, c.m_featureId);
for (auto const & c : campaigns)
WriteVarUint(dst, c.m_iconId);
for (auto const & c : campaigns)
WriteVarUint(dst, c.m_daysBeforeExpired);
return buff;
}
std::vector<Campaign> DeserializeV1(std::vector<uint8_t> const & bytes)
{
ReaderSource<MemReaderWithExceptions> src({bytes.data(), bytes.size()});
CHECK_EQUAL(ReadPrimitiveFromSource<Version>(src), Version::V1, ());
size_t const chunksNumber = static_cast<size_t>(ReadPrimitiveFromSource<uint64_t>(src));
auto const featureIds = ReadVarUintArray<uint32_t>(src, chunksNumber);
auto const icons = ReadVarUintArray<uint16_t>(src, chunksNumber);
auto const expirations = ReadVarUintArray<uint8_t>(src, chunksNumber);
std::vector<Campaign> campaigns;
campaigns.reserve(chunksNumber);
for (size_t i = 0; i < chunksNumber; ++i)
{
campaigns.emplace_back(featureIds[i], icons[i], expirations[i]);
}
return campaigns;
}
uint8_t ZoomIndex(uint8_t zoomValue) { return zoomValue - kMinZoomLevel; }
uint8_t ZoomValue(uint8_t zoomIndex) { return zoomIndex + kMinZoomLevel; }
uint8_t PackZoomAndPriority(uint8_t minZoomLevel, uint8_t priority)
{
UNUSED_VALUE(kMaxZoomLevel);
UNUSED_VALUE(kMaxPriority);
UNUSED_VALUE(kHalfByteMaxValue);
ASSERT_GREATER_OR_EQUAL(minZoomLevel, kMinZoomLevel, ("Unsupported zoom level"));
ASSERT_LESS_OR_EQUAL(minZoomLevel, kMaxZoomLevel, ("Unsupported zoom level"));
ASSERT_LESS_OR_EQUAL(priority, kMaxPriority, ("Unsupported priority value"));
auto const zoomIndex = ZoomIndex(minZoomLevel);
ASSERT_LESS_OR_EQUAL(zoomIndex, kHalfByteMaxValue, ());
ASSERT_LESS_OR_EQUAL(priority, kHalfByteMaxValue, ());
// Pack zoom and priority into single byte.
return (zoomIndex & kLowerMask) | ((priority << kHalfByteShift) & kUpperMask);
}
uint8_t UnpackZoom(uint8_t src)
{
return ZoomValue(src & kLowerMask);
}
uint8_t UnpackPriority(uint8_t src)
{
return (src >> kHalfByteShift) & kLowerMask;
}
std::vector<uint8_t> SerializeV2(std::vector<Campaign> const & campaigns)
{
std::vector<uint8_t> buff;
PushBackByteSink<decltype(buff)> dst(buff);
WriteToSink(dst, Version::V2);
WriteToSink(dst, campaigns.size());
for (auto const & c : campaigns)
WriteVarUint(dst, c.m_featureId);
for (auto const & c : campaigns)
WriteVarUint(dst, c.m_iconId);
for (auto const & c : campaigns)
WriteVarUint(dst, c.m_daysBeforeExpired);
for (auto const & c : campaigns)
WriteToSink(dst, PackZoomAndPriority(c.m_minZoomLevel, c.m_priority));
return buff;
}
std::vector<Campaign> DeserializeV2(std::vector<uint8_t> const & bytes)
{
ReaderSource<MemReaderWithExceptions> src({bytes.data(), bytes.size()});
CHECK_EQUAL(ReadPrimitiveFromSource<Version>(src), Version::V2, ());
size_t const chunksNumber = static_cast<size_t>(ReadPrimitiveFromSource<uint64_t>(src));
auto const featureIds = ReadVarUintArray<uint32_t>(src, chunksNumber);
auto const icons = ReadVarUintArray<uint16_t>(src, chunksNumber);
auto const expirations = ReadVarUintArray<uint8_t>(src, chunksNumber);
auto const zoomAndPriority = ReadArray<uint8_t>(src, chunksNumber);
std::vector<Campaign> campaigns;
campaigns.reserve(chunksNumber);
for (size_t i = 0; i < chunksNumber; ++i)
{
campaigns.emplace_back(featureIds[i], icons[i], expirations[i],
UnpackZoom(zoomAndPriority[i]),
UnpackPriority(zoomAndPriority[i]));
ASSERT_GREATER_OR_EQUAL(campaigns.back().m_minZoomLevel, kMinZoomLevel,
("Unsupported zoom level"));
ASSERT_LESS_OR_EQUAL(campaigns.back().m_minZoomLevel, kMaxZoomLevel,
("Unsupported zoom level"));
ASSERT_LESS_OR_EQUAL(campaigns.back().m_priority, kMaxPriority, ("Unsupported priority value"));
}
return campaigns;
}
} // namespace
namespace local_ads
{
std::vector<uint8_t> Serialize(std::vector<Campaign> const & campaigns, Version const version)
{
try
{
switch (version)
{
case Version::V1: return SerializeV1(campaigns);
case Version::V2: return SerializeV2(campaigns);
default: MYTHROW(UnknownVersion, (version));
}
}
catch (RootException const & e)
{
LOG(LERROR, ("Cannot to serialize campaigns", e.what(), e.Msg()));
}
return {};
}
std::vector<uint8_t> Serialize(std::vector<Campaign> const & campaigns)
{
return Serialize(campaigns, Version::Latest);
}
std::vector<Campaign> Deserialize(std::vector<uint8_t> const & bytes)
{
try
{
ReaderSource<MemReaderWithExceptions> src({bytes.data(), bytes.size()});
auto const version = ReadPrimitiveFromSource<Version>(src);
switch (version)
{
case Version::V1: return DeserializeV1(bytes);
case Version::V2: return DeserializeV2(bytes);
default: MYTHROW(UnknownVersion, (version));
}
}
catch (RootException const & e)
{
LOG(LERROR, ("Cannot to deserialize received data", e.what(), e.Msg()));
}
catch (std::bad_alloc const & e)
{
LOG(LERROR, ("Cannot to allocate memory for local ads campaigns", e.what()));
}
return {};
}
std::string DebugPrint(local_ads::Version version)
{
using local_ads::Version;
switch (version)
{
case Version::Unknown: return "Unknown";
case Version::V1: return "Version 1";
case Version::V2: return "Version 2";
default: ASSERT(false, ("Unknown version"));
}
return {};
}
} // namespace local_ads

View file

@ -1,26 +0,0 @@
#pragma once
#include "local_ads/campaign.hpp"
#include <cstdint>
#include <vector>
namespace local_ads
{
enum class Version
{
Unknown = -1,
// March 2017 (store feature ids and icon ids as varints, use one byte for days before
// expiration).
V1 = 0,
// August 2017 (store zoom level and priority as 0-7 values in one byte).
V2 = 1,
Latest = V2
};
std::vector<uint8_t> Serialize(std::vector<Campaign> const & campaigns, Version const version);
std::vector<uint8_t> Serialize(std::vector<Campaign> const & campaigns);
std::vector<Campaign> Deserialize(std::vector<uint8_t> const & bytes);
std::string DebugPrint(local_ads::Version version);
} // namespace local_ads

View file

@ -1,7 +0,0 @@
#pragma once
// Use local ads servers for development.
//#define DEV_LOCAL_ADS_SERVER
// Use stage local ads servers.
//#define STAGE_LOCAL_ADS_SERVER

View file

@ -1,60 +0,0 @@
#include "local_ads/event.hpp"
#include "base/math.hpp"
#include <sstream>
namespace local_ads
{
Event::Event(EventType type, int64_t mwmVersion, std::string const & countryId, uint32_t featureId,
uint8_t zoomLevel, Timestamp const & timestamp, double latitude, double longitude,
uint16_t accuracyInMeters)
: m_type(type)
, m_mwmVersion(mwmVersion)
, m_countryId(countryId)
, m_featureId(featureId)
, m_zoomLevel(zoomLevel)
, m_timestamp(timestamp)
, m_latitude(latitude)
, m_longitude(longitude)
, m_accuracyInMeters(accuracyInMeters)
{
}
bool Event::operator<(Event const & event) const
{
if (m_mwmVersion != event.m_mwmVersion)
return m_mwmVersion < event.m_mwmVersion;
if (m_countryId != event.m_countryId)
return m_countryId < event.m_countryId;
return m_timestamp < event.m_timestamp;
}
bool Event::operator==(Event const & event) const
{
double const kEps = 1e-5;
using namespace std::chrono;
return m_type == event.m_type && m_mwmVersion == event.m_mwmVersion &&
m_countryId == event.m_countryId && m_featureId == event.m_featureId &&
m_zoomLevel == event.m_zoomLevel &&
base::AlmostEqualAbs(m_latitude, event.m_latitude, kEps) &&
base::AlmostEqualAbs(m_longitude, event.m_longitude, kEps) &&
m_accuracyInMeters == event.m_accuracyInMeters &&
duration_cast<seconds>(m_timestamp - event.m_timestamp).count() == 0;
}
std::string DebugPrint(Event const & event)
{
using namespace std::chrono;
std::ostringstream s;
s << "[Type:" << static_cast<uint32_t>(event.m_type) << "; Country: " << event.m_countryId
<< "; Version: " << event.m_mwmVersion << "; FID: " << event.m_featureId
<< "; Zoom: " << static_cast<uint32_t>(event.m_zoomLevel)
<< "; Ts: " << duration_cast<std::chrono::seconds>(event.m_timestamp.time_since_epoch()).count()
<< "; LatLon: " << event.m_latitude << ", " << event.m_longitude
<< "; Accuracy: " << event.m_accuracyInMeters << "]";
return s.str();
}
} // namespace local_ads

View file

@ -1,41 +0,0 @@
#pragma once
#include <chrono>
#include <string>
namespace local_ads
{
using Clock = std::chrono::system_clock;
using Timestamp = Clock::time_point;
enum class EventType
{
ShowPoint = 0,
OpenInfo,
ClickedPhone,
ClickedWebsite,
Visit
};
struct Event
{
EventType m_type;
int64_t m_mwmVersion;
std::string m_countryId;
uint32_t m_featureId;
uint8_t m_zoomLevel;
Timestamp m_timestamp;
double m_latitude;
double m_longitude;
uint16_t m_accuracyInMeters;
Event(EventType type, int64_t mwmVersion, std::string const & countryId, uint32_t featureId,
uint8_t zoomLevel, Timestamp const & timestamp, double latitude, double longitude,
uint16_t accuracyInMeters);
bool operator<(Event const & event) const;
bool operator==(Event const & event) const;
};
std::string DebugPrint(Event const & event);
} // namespace local_ads

View file

@ -1,54 +0,0 @@
#include "local_ads/file_helpers.hpp"
#include "coding/reader.hpp"
#include "coding/string_utf8_multilang.hpp"
#include "coding/write_to_sink.hpp"
#include "base/assert.hpp"
#include <cstddef>
namespace local_ads
{
void WriteCountryName(FileWriter & writer, std::string const & countryName)
{
ASSERT(!countryName.empty(), ());
utils::WriteString(writer, countryName);
}
void WriteZigZag(FileWriter & writer, int64_t duration)
{
uint64_t const encoded = bits::ZigZagEncode(duration);
WriteToSink(writer, encoded);
}
void WriteRawData(FileWriter & writer, std::vector<uint8_t> const & rawData)
{
auto const size = static_cast<size_t>(rawData.size());
WriteToSink(writer, size);
writer.Write(rawData.data(), size);
}
std::string ReadCountryName(ReaderSource<FileReader> & src)
{
std::string countryName;
utils::ReadString<decltype(src), true>(src, countryName);
return countryName;
}
int64_t ReadZigZag(ReaderSource<FileReader> & src)
{
uint64_t const value = ReadPrimitiveFromSource<uint64_t>(src);
return bits::ZigZagDecode(value);
}
std::vector<uint8_t> ReadRawData(ReaderSource<FileReader> & src)
{
uint64_t const size = ReadPrimitiveFromSource<uint64_t>(src);
if (static_cast<uint64_t>(src.Size()) < size)
MYTHROW(Reader::SizeException, (src.Pos(), size));
std::vector<uint8_t> bytes(static_cast<size_t>(size));
src.Read(bytes.data(), bytes.size());
return bytes;
}
} // namespace local_ads

View file

@ -1,40 +0,0 @@
#pragma once
#include "local_ads/event.hpp"
#include "coding/file_reader.hpp"
#include "coding/file_writer.hpp"
#include <chrono>
#include <cstdint>
#include <string>
#include <vector>
namespace local_ads
{
void WriteCountryName(FileWriter & writer, std::string const & countryName);
void WriteZigZag(FileWriter & writer, int64_t duration);
template <typename Duration>
void WriteTimestamp(FileWriter & writer, Timestamp ts)
{
int64_t const d = std::chrono::duration_cast<Duration>(ts.time_since_epoch()).count();
WriteZigZag(writer, d);
}
void WriteRawData(FileWriter & writer, std::vector<uint8_t> const & rawData);
std::string ReadCountryName(ReaderSource<FileReader> & src);
int64_t ReadZigZag(ReaderSource<FileReader> & src);
template <typename Duration>
Timestamp ReadTimestamp(ReaderSource<FileReader> & src)
{
int64_t const d = ReadZigZag(src);
return Timestamp(Duration(d));
}
std::vector<uint8_t> ReadRawData(ReaderSource<FileReader> & src);
} // namespace local_ads

View file

@ -1,73 +0,0 @@
#include "local_ads/icons_info.hpp"
#include "coding/reader.hpp"
#include "platform/platform.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include <functional>
namespace
{
char const kDelimiter = '_';
void ParseIconsFile(std::string const & iconsFile,
std::function<void(std::string const &)> const & handler)
{
ASSERT(handler != nullptr, ());
try
{
std::string fileData;
ReaderPtr<Reader>(GetPlatform().GetReader(iconsFile)).ReadAsString(fileData);
strings::Tokenize(fileData, "\n", [&handler](std::string const & str) {
if (!str.empty())
handler(str);
});
}
catch (Reader::Exception const & e)
{
LOG(LWARNING, ("Error reading file ", iconsFile, " : ", e.what()));
}
}
} // namespace
namespace local_ads
{
IconsInfo & IconsInfo::Instance()
{
static IconsInfo iconsInfo;
return iconsInfo;
}
void IconsInfo::SetSourceFile(std::string const & fileName)
{
std::map<uint16_t, std::string> icons;
ParseIconsFile(fileName, [&icons](std::string const & icon) {
auto const pos = icon.find(kDelimiter);
if (pos == std::string::npos)
return;
uint32_t index;
if (!strings::to_uint(icon.substr(0, pos), index))
index = 0;
icons[static_cast<uint16_t>(index)] = icon;
});
{
std::lock_guard<std::mutex> lock(m_mutex);
m_fileName = fileName;
std::swap(m_icons, icons);
}
}
std::string IconsInfo::GetIcon(uint16_t index) const
{
std::lock_guard<std::mutex> lock(m_mutex);
auto const it = m_icons.find(index);
if (it == m_icons.end())
return {};
return it->second;
}
} // namespace local_ads

View file

@ -1,30 +0,0 @@
#pragma once
#include "base/macros.hpp"
#include <cstdint>
#include <map>
#include <mutex>
#include <string>
namespace local_ads
{
class IconsInfo
{
public:
static IconsInfo & Instance();
void SetSourceFile(std::string const & fileName);
std::string GetIcon(uint16_t index) const;
private:
IconsInfo() = default;
~IconsInfo() {}
std::string m_fileName;
std::map<uint16_t, std::string> m_icons;
mutable std::mutex m_mutex;
DISALLOW_COPY_AND_MOVE(IconsInfo);
};
} // namespace local_ads

View file

@ -1,26 +0,0 @@
project(local_ads_tests)
set(
SRC
campaign_serialization_test.cpp
file_helpers_tests.cpp
statistics_tests.cpp
)
omim_add_test(${PROJECT_NAME} ${SRC})
omim_link_libraries(
${PROJECT_NAME}
local_ads
platform_tests_support
platform
coding
geometry
base
jansson
oauthcpp
stats_client
${LIBZ}
)
link_qt5_core(${PROJECT_NAME})

View file

@ -1,94 +0,0 @@
#include "testing/testing.hpp"
#include "local_ads/campaign_serialization.hpp"
#include <limits>
#include <random>
#include <vector>
using namespace local_ads;
namespace
{
template <typename T>
using Limits = typename std::numeric_limits<T>;
bool TestSerialization(std::vector<Campaign> const & cs, Version const v)
{
auto const bytes = Serialize(cs, v);
return cs == Deserialize(bytes);
}
std::vector<Campaign> GenerateCampaignsV1(size_t number)
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<uint32_t> featureIds(1, Limits<uint32_t>::max());
std::uniform_int_distribution<> icons(1, Limits<uint16_t>::max());
std::uniform_int_distribution<> expirationDays(1, Limits<uint8_t>::max());
std::vector<Campaign> cs;
while (number--)
{
auto const fid = featureIds(gen);
auto const iconid = icons(gen);
auto const days = expirationDays(gen);
cs.emplace_back(fid, iconid, days);
}
return cs;
}
std::vector<Campaign> GenerateCampaignsV2(size_t number)
{
int kSeed = 42;
std::mt19937 gen(kSeed);
std::uniform_int_distribution<uint32_t> featureIds(1, Limits<uint32_t>::max());
std::uniform_int_distribution<> icons(1, Limits<uint16_t>::max());
std::uniform_int_distribution<> expirationDays(1, Limits<uint8_t>::max());
std::uniform_int_distribution<> zoomLevels(10, 17);
std::uniform_int_distribution<> priorities(0, 7);
std::vector<Campaign> cs;
while (number--)
{
auto const fid = featureIds(gen);
auto const iconid = icons(gen);
auto const days = expirationDays(gen);
auto const zoom = zoomLevels(gen);
auto const priority = priorities(gen);
cs.emplace_back(fid, iconid, days, zoom, priority);
}
return cs;
}
} // namspace
UNIT_TEST(Serialization_Smoke)
{
TEST(TestSerialization({
{0, 0, 0},
{Limits<uint32_t>::max(), Limits<uint16_t>::max(), Limits<uint8_t>::max()},
{120003, 456, 15}
}, Version::V1), ());
TEST(TestSerialization({
{0, 0, 0, 10, 0},
{Limits<uint32_t>::max(), Limits<uint16_t>::max(), Limits<uint8_t>::max()},
{1000, 100, 255, 17, 7},
{120003, 456, 15, 13, 6}
}, Version::V2), ());
TEST(TestSerialization({
{241925, 6022, 255, 16, 6},
{241927, 6036, 255, 16, 0},
{164169, 3004, 255, 15, 0},
{164172, 3001, 255, 15, 7}
}, Version::V2), ());
TEST(TestSerialization(GenerateCampaignsV1(100), Version::V1), ());
TEST(TestSerialization(GenerateCampaignsV1(1000), Version::V1), ());
TEST(TestSerialization(GenerateCampaignsV1(10000), Version::V1), ());
TEST(TestSerialization(GenerateCampaignsV2(100), Version::V2), ());
TEST(TestSerialization(GenerateCampaignsV2(1000), Version::V2), ());
TEST(TestSerialization(GenerateCampaignsV2(10000), Version::V2), ());
}

View file

@ -1,75 +0,0 @@
#include "testing/testing.hpp"
#include "local_ads/file_helpers.hpp"
#include "base/file_name_utils.hpp"
#include "platform/platform_tests_support/scoped_file.hpp"
using namespace local_ads;
using namespace std;
using platform::tests_support::ScopedFile;
UNIT_TEST(LocalAdsHelpers_Read_Write_Country_Name)
{
ScopedFile testFile("la_tests.dat", ScopedFile::Mode::Create);
string const countryName = "Russia_Moscow";
{
FileWriter writer(testFile.GetFullPath());
WriteCountryName(writer, countryName);
}
string result;
{
FileReader reader(testFile.GetFullPath());
ReaderSource<FileReader> src(reader);
result = ReadCountryName(src);
}
TEST_EQUAL(result, countryName, ());
}
UNIT_TEST(LocalAdsHelpers_Read_Write_Timestamp)
{
ScopedFile testFile("la_tests.dat", ScopedFile::Mode::Create);
auto ts = local_ads::Clock::now();
{
FileWriter writer(testFile.GetFullPath());
WriteTimestamp<chrono::hours>(writer, ts);
WriteTimestamp<chrono::seconds>(writer, ts);
}
local_ads::Timestamp resultInHours;
local_ads::Timestamp resultInSeconds;
{
FileReader reader(testFile.GetFullPath());
ReaderSource<FileReader> src(reader);
resultInHours = ReadTimestamp<chrono::hours>(src);
resultInSeconds = ReadTimestamp<chrono::seconds>(src);
}
TEST_EQUAL(chrono::duration_cast<chrono::hours>(ts - resultInHours).count(), 0, ());
TEST_EQUAL(chrono::duration_cast<chrono::seconds>(ts - resultInSeconds).count(), 0, ());
}
UNIT_TEST(LocalAdsHelpers_Read_Write_RawData)
{
ScopedFile testFile("la_tests.dat", ScopedFile::Mode::Create);
vector<uint8_t> rawData = {1, 2, 3, 4, 5};
{
FileWriter writer(testFile.GetFullPath());
WriteRawData(writer, rawData);
}
vector<uint8_t> result;
{
FileReader reader(testFile.GetFullPath());
ReaderSource<FileReader> src(reader);
result = ReadRawData(src);
}
TEST_EQUAL(rawData, result, ());
}

View file

@ -1,164 +0,0 @@
#include "testing/testing.hpp"
#include "local_ads/statistics.hpp"
#include "base/file_name_utils.hpp"
namespace
{
class StatisticsGuard
{
public:
explicit StatisticsGuard(local_ads::Statistics & statistics) : m_statistics(statistics) {}
~StatisticsGuard()
{
m_statistics.CleanupAfterTesting();
}
private:
local_ads::Statistics & m_statistics;
};
} // namespace
using namespace std::chrono;
using ET = local_ads::EventType;
using TS = local_ads::Timestamp;
UNIT_TEST(LocalAdsStatistics_Read_Write_Simple)
{
local_ads::Statistics statistics;
StatisticsGuard guard(statistics);
std::list<local_ads::Event> events;
// type, mwmVersion, countryId, featureId, zoomLevel, timestamp, latitude, longitude, accuracyInMeters
events.emplace_back(ET::ShowPoint, 123456, "Moscow", 111, 15, TS(minutes(5)), 30.0, 64.0, 10);
events.emplace_back(ET::ShowPoint, 123456, "Moscow", 222, 13, TS(minutes(10)), 20.0, 14.0, 20);
events.emplace_back(ET::OpenInfo, 123456, "Moscow", 111, 17, TS(minutes(15)), 53.0, 54.0, 10000);
std::string unusedFileName;
auto unprocessedEvents = statistics.WriteEventsForTesting(events, unusedFileName);
TEST_EQUAL(unprocessedEvents.size(), 0, ());
TEST_EQUAL(statistics.ReadEventsForTesting("Moscow_123456.dat"), events, ());
}
UNIT_TEST(LocalAdsStatistics_Write_With_Unprocessed)
{
local_ads::Statistics statistics;
StatisticsGuard guard(statistics);
std::list<local_ads::Event> events;
events.emplace_back(ET::ShowPoint, 123456, "Moscow", 111, 15, TS(minutes(5)), 0.0, 0.0, 10);
events.emplace_back(ET::ShowPoint, 123456, "Moscow", 222, 13, TS(minutes(10)), 20.0, 14.0, 20);
events.emplace_back(ET::OpenInfo, 123456, "Moscow", 111, 17, TS(minutes(15)), 15.0, 14.0, 20);
std::string fileNameToRebuild;
auto unprocessedEvents = statistics.WriteEventsForTesting(events, fileNameToRebuild);
TEST_EQUAL(unprocessedEvents.size(), 0, ());
TEST(fileNameToRebuild.empty(), ());
std::list<local_ads::Event> events2;
events2.emplace_back(ET::ShowPoint, 123456, "Moscow", 333, 15, TS(minutes(1)), 1.0, 89.0, 20);
events2.emplace_back(ET::ShowPoint, 123456, "Moscow", 444, 15, TS(minutes(20)), 30.0, 13.0, 15);
auto unprocessedEvents2 = statistics.WriteEventsForTesting(events2, fileNameToRebuild);
std::list<local_ads::Event> expectedUnprocessedEvents = events2;
expectedUnprocessedEvents.sort();
base::GetNameFromFullPath(fileNameToRebuild);
TEST_EQUAL(fileNameToRebuild, "Moscow_123456.dat", ());
TEST_EQUAL(expectedUnprocessedEvents, unprocessedEvents2, ());
}
UNIT_TEST(LocalAdsStatistics_Process_With_Rebuild)
{
local_ads::Statistics statistics;
StatisticsGuard guard(statistics);
std::list<local_ads::Event> events;
events.emplace_back(ET::ShowPoint, 123456, "Moscow", 111, 15, TS(minutes(5)), 50.0, 14.0, 20);
events.emplace_back(ET::ShowPoint, 123456, "Moscow", 222, 13, TS(minutes(10)), 69.0, 67.0, 100);
events.emplace_back(ET::OpenInfo, 123456, "Moscow", 111, 17, TS(minutes(15)), 45.0, 80.0, 34);
std::string unused;
statistics.WriteEventsForTesting(events, unused);
TEST_EQUAL(statistics.ReadEventsForTesting("Moscow_123456.dat"), events, ());
std::list<local_ads::Event> events2;
events2.emplace_back(ET::ShowPoint, 123456, "Moscow", 333, 15, TS(minutes(1)), 20.0, 14.0, 12);
events2.emplace_back(ET::ShowPoint, 123456, "Moscow", 444, 15, TS(minutes(20)), 30.0, 56.0, 3535);
statistics.ProcessEventsForTesting(events2);
std::list<local_ads::Event> expectedResult = events;
expectedResult.insert(expectedResult.end(), events2.begin(), events2.end());
expectedResult.sort();
TEST_EQUAL(statistics.ReadEventsForTesting("Moscow_123456.dat"), expectedResult, ());
}
UNIT_TEST(LocalAdsStatistics_Process_With_Clipping)
{
local_ads::Statistics statistics;
StatisticsGuard guard(statistics);
std::list<local_ads::Event> events;
events.emplace_back(ET::ShowPoint, 123456, "Moscow", 111, 15, TS(minutes(5)), 20.0, 14.0, 12);
events.emplace_back(ET::ShowPoint, 123456, "Moscow", 222, 13, TS(minutes(10)), 69.0, 67.0, 100);
events.emplace_back(ET::OpenInfo, 123456, "Moscow", 111, 17, TS(minutes(25 * 60 + 15)), 20.0,
14.0, 20);
std::string unused;
statistics.WriteEventsForTesting(events, unused);
TEST_EQUAL(statistics.ReadEventsForTesting("Moscow_123456.dat"), events, ());
std::list<local_ads::Event> events2;
events2.emplace_back(ET::ShowPoint, 123456, "Moscow", 333, 15, TS(minutes(24 * 183 * 60 + 50)),
20.0, 14.0, 20);
statistics.ProcessEventsForTesting(events2);
std::list<local_ads::Event> expectedResult;
expectedResult.push_back(local_ads::Event(events.back()));
expectedResult.insert(expectedResult.end(), events2.begin(), events2.end());
expectedResult.sort();
TEST_EQUAL(statistics.ReadEventsForTesting("Moscow_123456.dat"), expectedResult, ());
}
UNIT_TEST(LocalAdsStatistics_Process_Complex)
{
local_ads::Statistics statistics;
StatisticsGuard guard(statistics);
std::list<local_ads::Event> events;
events.emplace_back(ET::ShowPoint, 123456, "Moscow", 111, 15, TS(minutes(5)), 20.0, 14.0, 20);
events.emplace_back(ET::ShowPoint, 123456, "Minsk", 222, 13, TS(minutes(10)), 30.0, 14.0, 20);
events.emplace_back(ET::OpenInfo, 123456, "Minsk", 111, 17, TS(minutes(25)), 40.0, 14.0, 20);
events.emplace_back(ET::OpenInfo, 123456, "Minsk", 111, 17, TS(minutes(25 * 60 + 15)), 20.0, 14.0,
20);
std::string unused;
statistics.WriteEventsForTesting(events, unused);
std::list<local_ads::Event> expectedResult1;
expectedResult1.push_back(local_ads::Event(events.front()));
TEST_EQUAL(statistics.ReadEventsForTesting("Moscow_123456.dat"), expectedResult1, ());
std::list<local_ads::Event> expectedResult2 = events;
expectedResult2.erase(expectedResult2.begin());
TEST_EQUAL(statistics.ReadEventsForTesting("Minsk_123456.dat"), expectedResult2, ());
std::list<local_ads::Event> events2;
events2.emplace_back(ET::ShowPoint, 123456, "Moscow", 333, 15, TS(minutes(100)), 20.0, 14.0, 20);
events2.emplace_back(ET::ShowPoint, 123456, "Minsk", 333, 15, TS(minutes(24 * 183 * 60 + 50)),
20.0, 14.0, 20);
statistics.ProcessEventsForTesting(events2);
expectedResult1.push_back(local_ads::Event(events2.front()));
TEST_EQUAL(statistics.ReadEventsForTesting("Moscow_123456.dat"), expectedResult1, ());
expectedResult2.clear();
expectedResult2.push_back(local_ads::Event(events.back()));
expectedResult2.push_back(local_ads::Event(events2.back()));
TEST_EQUAL(statistics.ReadEventsForTesting("Minsk_123456.dat"), expectedResult2, ());
}

View file

@ -1,23 +0,0 @@
project(pylocal_ads)
set(
SRC
bindings.cpp
)
include_directories(${CMAKE_BINARY_DIR})
omim_add_library(${PROJECT_NAME} MODULE ${SRC})
omim_link_libraries(
${PROJECT_NAME}
${Boost_LIBRARIES}
local_ads
base
)
if (PLATFORM_MAC)
omim_link_libraries(${PROJECT_NAME} "-Wl,-undefined,dynamic_lookup")
endif()
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")

View file

@ -1,77 +0,0 @@
#include "local_ads/campaign.hpp"
#include "local_ads/campaign_serialization.hpp"
// This header should be included due to a python compilation error.
// pyport.h overwrites defined macros and replaces it with its own.
// However, in the OS X c++ libraries, these are not macros but functions,
// hence the error. See https://bugs.python.org/issue10910
#include <locale>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreorder"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-local-typedef"
#endif
#include "pyhelpers/module_version.hpp"
#include "pyhelpers/vector_uint8.hpp"
#include "pyhelpers/vector_list_conversion.hpp"
#include <boost/python.hpp>
#include <boost/python/enum.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#pragma GCC diagnostic pop
using namespace local_ads;
namespace
{
std::vector<uint8_t> PySerialize(boost::python::list const & cs, Version const version)
{
auto const campaigns = pyhelpers::PythonListToStdVector<Campaign>(cs);
return Serialize(campaigns, version);
}
boost::python::list PyDeserialize(std::vector<uint8_t> const & blob)
{
auto const campaigns = Deserialize(blob);
return pyhelpers::StdVectorToPythonList(campaigns);
}
} // namespace
BOOST_PYTHON_MODULE(pylocal_ads)
{
using namespace boost::python;
scope().attr("__version__") = PYBINDINGS_VERSION;
// Register the to-python converters.
to_python_converter<std::vector<uint8_t>, vector_uint8t_to_str>();
vector_uint8t_from_python_str();
class_<Campaign>("Campaign", init<uint32_t, uint16_t, uint8_t, uint8_t, uint8_t>())
.def(init<uint32_t, uint16_t, uint8_t>())
.def_readonly("m_featureId", &Campaign::m_featureId)
.def_readonly("m_iconId", &Campaign::m_iconId)
.def_readonly("m_daysBeforeExpired", &Campaign::m_daysBeforeExpired)
.def_readonly("m_minZoomLevel", &Campaign::m_minZoomLevel)
.def_readonly("m_priority", &Campaign::m_priority);
class_<std::vector<Campaign>>("CampaignList")
.def(vector_indexing_suite<std::vector<Campaign>>());
enum_<Version>("Version")
.value("UNKNOWN", Version::Unknown)
.value("V1", Version::V1)
.value("V2", Version::V2)
.value("LATEST", Version::Latest)
.export_values();
def("serialize", PySerialize);
def("deserialize", PyDeserialize);
}

View file

@ -1,49 +0,0 @@
import unittest
from pylocal_ads import (Campaign, Version, serialize, deserialize)
class PyLocalAdsTest(unittest.TestCase):
def assert_equal_campaigns(self, lhs, rhs):
self.assertEqual(len(lhs), len(rhs))
for i in range(0, len(lhs)):
self.assertEqual(lhs[i].m_featureId, rhs[i].m_featureId)
self.assertEqual(lhs[i].m_iconId, rhs[i].m_iconId)
self.assertEqual(lhs[i].m_daysBeforeExpired, rhs[i].m_daysBeforeExpired)
self.assertEqual(lhs[i].m_minZoomLevel, rhs[i].m_minZoomLevel)
self.assertEqual(lhs[i].m_priority, rhs[i].m_priority)
def test_smoke(self):
campaigns_v1 = [
Campaign(10, 10, 10),
Campaign(1000, 100, 20),
Campaign(120003, 456, 15)
]
campaigns_v2 = [
Campaign(10, 10, 10, 10, 0),
Campaign(1000, 100, 20, 17, 7),
Campaign(120003, 456, 15, 13, 6)
]
serialized = serialize(campaigns_v1, Version.V1)
result_v1 = deserialize(serialized)
self.assert_equal_campaigns(campaigns_v1, result_v1)
serialized = serialize(campaigns_v2, Version.V2)
result_v2 = deserialize(serialized)
self.assert_equal_campaigns(campaigns_v2, result_v2)
serialized = serialize(campaigns_v2, Version.LATEST)
result_latest = deserialize(serialized)
self.assert_equal_campaigns(campaigns_v2, result_latest)
self.assert_equal_campaigns(result_v2, result_latest)
if __name__ == "__main__":
unittest.main()

View file

@ -1,13 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
module_dir = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.join(module_dir, '..', '..'))
from pyhelpers.setup import setup_omim_pybinding
NAME = "pylocal_ads"
setup_omim_pybinding(name=NAME)

View file

@ -1,584 +0,0 @@
#include "local_ads/statistics.hpp"
#include "local_ads/config.hpp"
#include "local_ads/file_helpers.hpp"
#include "platform/http_client.hpp"
#include "platform/network_policy.hpp"
#include "platform/platform.hpp"
#include "coding/file_writer.hpp"
#include "coding/point_coding.hpp"
#include "coding/url.hpp"
#include "coding/write_to_sink.hpp"
#include "coding/zlib.hpp"
#include "geometry/mercator.hpp"
#include "base/assert.hpp"
#include "base/exception.hpp"
#include "base/file_name_utils.hpp"
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include "private.h"
#include <functional>
#include <memory>
#include <sstream>
#include <utility>
#include "3party/Alohalytics/src/alohalytics.h"
#include "3party/jansson/myjansson.hpp"
namespace
{
std::string const kStatisticsFolderName = "local_ads_stats";
std::string const kStatisticsExt = ".dat";
uint64_t constexpr kMaxFilesSizeInBytes = 10 * 1024 * 1024;
float const kEventsDisposingRate = 0.2f;
auto constexpr kSendingTimeout = std::chrono::hours(1);
int64_t constexpr kEventMaxLifetimeInSeconds = 24 * 183 * 3600; // About half of year.
auto constexpr kDeletionPeriod = std::chrono::hours(24);
std::string const kStatisticsServer = LOCAL_ADS_STATISTICS_SERVER_URL;
void WriteMetadata(FileWriter & writer, std::string const & countryId, int64_t mwmVersion,
local_ads::Timestamp const & ts)
{
local_ads::WriteCountryName(writer, countryId);
local_ads::WriteZigZag(writer, mwmVersion);
local_ads::WriteTimestamp<std::chrono::seconds>(writer, ts);
}
void ReadMetadata(ReaderSource<FileReader> & src, std::string & countryId, int64_t & mwmVersion,
local_ads::Timestamp & ts)
{
countryId = local_ads::ReadCountryName(src);
mwmVersion = local_ads::ReadZigZag(src);
ts = local_ads::ReadTimestamp<std::chrono::seconds>(src);
}
void WritePackedData(FileWriter & writer, local_ads::Statistics::PackedData && packedData)
{
WriteToSink(writer, packedData.m_eventType);
WriteToSink(writer, packedData.m_zoomLevel);
WriteToSink(writer, packedData.m_featureIndex);
WriteToSink(writer, packedData.m_seconds);
local_ads::WriteZigZag(writer, packedData.m_mercator);
WriteToSink(writer, packedData.m_accuracy);
}
template <typename ToDo>
void ReadPackedData(ReaderSource<FileReader> & src, ToDo && toDo)
{
using PackedData = local_ads::Statistics::PackedData;
std::string countryId;
int64_t mwmVersion;
local_ads::Timestamp baseTimestamp;
ReadMetadata(src, countryId, mwmVersion, baseTimestamp);
while (src.Size() > 0)
{
PackedData data;
data.m_eventType = ReadPrimitiveFromSource<uint8_t>(src);
data.m_zoomLevel = ReadPrimitiveFromSource<uint8_t>(src);
data.m_featureIndex = ReadPrimitiveFromSource<uint32_t>(src);
data.m_seconds = ReadPrimitiveFromSource<uint32_t>(src);
data.m_mercator = local_ads::ReadZigZag(src);
data.m_accuracy = ReadPrimitiveFromSource<uint16_t>(src);
toDo(std::move(data), countryId, mwmVersion, baseTimestamp);
}
}
template <typename ToDo>
void FilterEvents(std::list<local_ads::Event> const & events, std::string const & countryId,
int64_t mwmVersion, ToDo && toDo)
{
for (auto const & event : events)
{
if (event.m_countryId != countryId || event.m_mwmVersion != mwmVersion)
continue;
toDo(event);
}
}
local_ads::Timestamp GetMinTimestamp(std::list<local_ads::Event> const & events,
std::string const & countryId, int64_t mwmVersion)
{
local_ads::Timestamp minTimestamp = local_ads::Timestamp::max();
FilterEvents(events, countryId, mwmVersion, [&minTimestamp](local_ads::Event const & event)
{
if (event.m_timestamp < minTimestamp)
minTimestamp = event.m_timestamp;
});
return minTimestamp;
}
local_ads::Timestamp GetMaxTimestamp(std::list<local_ads::Event> const & events,
std::string const & countryId, int64_t mwmVersion)
{
local_ads::Timestamp maxTimestamp = local_ads::Timestamp::min();
FilterEvents(events, countryId, mwmVersion, [&maxTimestamp](local_ads::Event const & event)
{
if (event.m_timestamp > maxTimestamp)
maxTimestamp = event.m_timestamp;
});
return maxTimestamp;
}
std::string GetPath(std::string const & fileName)
{
return base::JoinPath(GetPlatform().SettingsDir(), kStatisticsFolderName, fileName);
}
std::string GetPath(local_ads::Event const & event)
{
return GetPath(event.m_countryId + "_" + strings::to_string(event.m_mwmVersion) + kStatisticsExt);
}
std::string StatisticsFolder()
{
return GetPath("");
}
void CreateDirIfNotExist()
{
std::string const statsFolder = StatisticsFolder();
if (!GetPlatform().IsFileExistsByFullPath(statsFolder) && !Platform::MkDirChecked(statsFolder))
MYTHROW(FileSystemException, ("Unable to find or create directory", statsFolder));
}
std::list<local_ads::Event> ReadEvents(std::string const & fileName)
{
std::list<local_ads::Event> result;
if (!GetPlatform().IsFileExistsByFullPath(fileName))
return result;
try
{
FileReader reader(fileName);
ReaderSource<FileReader> src(reader);
ReadPackedData(src, [&result](local_ads::Statistics::PackedData && data,
std::string const & countryId, int64_t mwmVersion,
local_ads::Timestamp const & baseTimestamp) {
auto const mercatorPt = Int64ToPointObsolete(data.m_mercator, kPointCoordBits);
result.emplace_back(static_cast<local_ads::EventType>(data.m_eventType), mwmVersion, countryId,
data.m_featureIndex, data.m_zoomLevel,
baseTimestamp + std::chrono::seconds(data.m_seconds),
mercator::YToLat(mercatorPt.y), mercator::XToLon(mercatorPt.x), data.m_accuracy);
});
}
catch (Reader::Exception const & ex)
{
LOG(LWARNING, ("Error reading file:", fileName, ex.Msg()));
}
return result;
}
std::string MakeRemoteURL(std::string const & userId, std::string const & name, int64_t version)
{
if (kStatisticsServer.empty())
return {};
std::ostringstream ss;
ss << kStatisticsServer << "/";
ss << url::UrlEncode(userId) << "/";
ss << version << "/";
ss << url::UrlEncode(name);
return ss.str();
}
std::vector<uint8_t> SerializeForServer(std::list<local_ads::Event> const & events,
std::string const & userId)
{
using namespace std::chrono;
ASSERT(!events.empty(), ());
auto root = base::NewJSONObject();
ToJSONObject(*root, "userId", userId);
ToJSONObject(*root, "countryId", events.front().m_countryId);
ToJSONObject(*root, "mwmVersion", events.front().m_mwmVersion);
auto eventsNode = base::NewJSONArray();
for (auto const & event : events)
{
auto eventNode = base::NewJSONObject();
auto s = duration_cast<seconds>(event.m_timestamp.time_since_epoch()).count();
ToJSONObject(*eventNode, "type", static_cast<uint8_t>(event.m_type));
ToJSONObject(*eventNode, "timestamp", static_cast<int64_t>(s));
ToJSONObject(*eventNode, "featureId", static_cast<int32_t>(event.m_featureId));
ToJSONObject(*eventNode, "zoomLevel", event.m_zoomLevel);
ToJSONObject(*eventNode, "latitude", event.m_latitude);
ToJSONObject(*eventNode, "longitude", event.m_longitude);
ToJSONObject(*eventNode, "accuracyInMeters", event.m_accuracyInMeters);
json_array_append_new(eventsNode.get(), eventNode.release());
}
json_object_set_new(root.get(), "events", eventsNode.release());
std::unique_ptr<char, JSONFreeDeleter> buffer(
json_dumps(root.get(), JSON_COMPACT | JSON_ENSURE_ASCII));
std::vector<uint8_t> result;
using Deflate = coding::ZLib::Deflate;
Deflate deflate(Deflate::Format::ZLib, Deflate::Level::BestCompression);
deflate(buffer.get(), strlen(buffer.get()), std::back_inserter(result));
return result;
}
bool CanUpload()
{
auto const connectionStatus = GetPlatform().ConnectionStatus();
if (connectionStatus == Platform::EConnectionType::CONNECTION_WIFI)
return true;
return connectionStatus == Platform::EConnectionType::CONNECTION_WWAN &&
platform::GetCurrentNetworkPolicy().CanUse();
}
} // namespace
namespace local_ads
{
Statistics::Statistics()
: m_userId(GetPlatform().UniqueIdHash())
{}
void Statistics::Startup()
{
m_isEnabled = true;
GetPlatform().RunTask(Platform::Thread::File, [this]
{
IndexMetadata();
SendToServer();
});
}
void Statistics::RegisterEvent(Event && event)
{
if (!m_isEnabled)
return;
RegisterEvents({std::move(event)});
}
void Statistics::RegisterEvents(std::list<Event> && events)
{
if (!m_isEnabled)
return;
GetPlatform().RunTask(Platform::Thread::File,
std::bind(&Statistics::ProcessEvents, this, std::move(events)));
}
void Statistics::RegisterEventSync(Event && event)
{
std::list<Event> events = {std::move(event)};
ProcessEvents(events);
}
void Statistics::SetEnabled(bool isEnabled)
{
m_isEnabled = isEnabled;
}
std::list<Event> Statistics::WriteEvents(std::list<Event> & events, std::string & fileNameToRebuild)
{
try
{
CreateDirIfNotExist();
if (m_metadataCache.empty())
IndexMetadata();
std::unique_ptr<FileWriter> writer;
events.sort();
auto eventIt = events.begin();
for (; eventIt != events.end(); ++eventIt)
{
Event const & event = *eventIt;
MetadataKey const key = std::make_pair(event.m_countryId, event.m_mwmVersion);
auto it = m_metadataCache.find(key);
// Get metadata.
Metadata metadata;
bool needWriteMetadata = false;
if (it == m_metadataCache.end())
{
metadata.m_timestamp = GetMinTimestamp(events, event.m_countryId, event.m_mwmVersion);
metadata.m_fileName = GetPath(event);
m_metadataCache[key] = metadata;
needWriteMetadata = true;
}
else
{
metadata = it->second;
}
if (writer == nullptr || writer->GetName() != metadata.m_fileName)
{
writer = std::make_unique<FileWriter>(
metadata.m_fileName,
needWriteMetadata ? FileWriter::OP_WRITE_TRUNCATE : FileWriter::OP_APPEND);
}
if (needWriteMetadata)
WriteMetadata(*writer, event.m_countryId, event.m_mwmVersion, metadata.m_timestamp);
// Check if timestamp is out of date. In this case we have to rebuild events package.
using namespace std::chrono;
int64_t const s = duration_cast<seconds>(event.m_timestamp - metadata.m_timestamp).count();
if (s < 0 || s > kEventMaxLifetimeInSeconds)
{
fileNameToRebuild = writer->GetName();
// Return unprocessed events.
std::list<Event> unprocessedEvents;
unprocessedEvents.splice(unprocessedEvents.end(), events, eventIt, events.end());
return unprocessedEvents;
}
PackedData data;
data.m_featureIndex = event.m_featureId;
data.m_seconds = static_cast<uint32_t>(s);
data.m_zoomLevel = event.m_zoomLevel;
data.m_eventType = static_cast<uint8_t>(event.m_type);
auto const mercatorPt = mercator::FromLatLon(event.m_latitude, event.m_longitude);
data.m_mercator = PointToInt64Obsolete(mercatorPt, kPointCoordBits);
data.m_accuracy = event.m_accuracyInMeters;
WritePackedData(*writer, std::move(data));
}
}
catch (RootException const & ex)
{
LOG(LWARNING, (ex.Msg()));
}
return std::list<Event>();
}
void Statistics::ProcessEvents(std::list<Event> & events)
{
bool needRebuild;
do
{
std::string fileNameToRebuild;
auto unprocessedEvents = WriteEvents(events, fileNameToRebuild);
needRebuild = !unprocessedEvents.empty();
if (!needRebuild)
break;
// The first event in the list is cause of writing interruption.
Event event = unprocessedEvents.front();
// Read events and merge with unprocessed ones.
std::list<Event> newEvents = ReadEvents(fileNameToRebuild);
newEvents.splice(newEvents.end(), std::move(unprocessedEvents));
newEvents.sort();
// Clip obsolete events.
auto constexpr kLifetime = std::chrono::seconds(kEventMaxLifetimeInSeconds);
auto const maxTimestamp = GetMaxTimestamp(newEvents, event.m_countryId, event.m_mwmVersion);
auto newMinTimestamp = maxTimestamp - kLifetime + kDeletionPeriod;
for (auto eventIt = newEvents.begin(); eventIt != newEvents.end();)
{
if (eventIt->m_countryId == event.m_countryId &&
eventIt->m_mwmVersion == event.m_mwmVersion && eventIt->m_timestamp < newMinTimestamp)
{
eventIt = newEvents.erase(eventIt);
}
else
{
++eventIt;
}
}
// Update run-time cache and delete rebuilding file.
m_metadataCache.erase(MetadataKey(event.m_countryId, event.m_mwmVersion));
FileWriter::DeleteFileX(fileNameToRebuild);
std::swap(events, newEvents);
} while (needRebuild);
}
void Statistics::SendToServer()
{
if (!m_isEnabled)
return;
if (CanUpload())
{
for (auto it = m_metadataCache.begin(); it != m_metadataCache.end(); ++it)
{
auto metadataKey = it->first;
auto metadata = it->second;
GetPlatform().RunTask(Platform::Thread::Network, [this, metadataKey = std::move(metadataKey),
metadata = std::move(metadata)]() mutable
{
SendFileWithMetadata(std::move(metadataKey), std::move(metadata));
});
}
}
// Send every |kSendingTimeout|.
GetPlatform().RunDelayedTask(Platform::Thread::File, kSendingTimeout, [this]
{
SendToServer();
});
}
void Statistics::SendFileWithMetadata(MetadataKey && metadataKey, Metadata && metadata)
{
std::string const url = MakeRemoteURL(m_userId, metadataKey.first, metadataKey.second);
if (url.empty())
return;
std::list<Event> events = ReadEvents(metadata.m_fileName);
if (events.empty())
return;
std::string contentType = "application/octet-stream";
std::string contentEncoding = "";
std::vector<uint8_t> bytes = SerializeForServer(events, m_userId);
ASSERT(!bytes.empty(), ());
platform::HttpClient request(url);
request.SetTimeout(5); // timeout in seconds
#ifdef DEV_LOCAL_ADS_SERVER
request.LoadHeaders(true);
request.SetRawHeader("Host", "localads-statistics.maps.me");
#endif
request.SetBodyData(std::string(bytes.begin(), bytes.end()), contentType, "POST",
contentEncoding);
request.SetRawHeader("User-Agent", GetPlatform().GetAppUserAgent());
if (request.RunHttpRequest() && request.ErrorCode() == 200)
{
GetPlatform().RunTask(Platform::Thread::File, [this, metadataKey = std::move(metadataKey),
metadata = std::move(metadata)]
{
FileWriter::DeleteFileX(metadata.m_fileName);
m_metadataCache.erase(metadataKey);
});
}
else
{
LOG(LWARNING, ("Sending statistics failed:", "URL:", url, "Error code:", request.ErrorCode(),
metadataKey.first, metadataKey.second));
}
}
std::list<Event> Statistics::WriteEventsForTesting(std::list<Event> const & events,
std::string & fileNameToRebuild)
{
std::list<Event> mutableEvents = events;
return WriteEvents(mutableEvents, fileNameToRebuild);
}
void Statistics::IndexMetadata()
{
std::vector<std::string> files;
GetPlatform().GetFilesByExt(StatisticsFolder(), kStatisticsExt, files);
for (auto const & filename : files)
ExtractMetadata(GetPath(filename));
BalanceMemory();
}
void Statistics::ExtractMetadata(std::string const & fileName)
{
ASSERT(GetPlatform().IsFileExistsByFullPath(fileName), ());
try
{
std::string countryId;
int64_t mwmVersion;
Timestamp baseTimestamp;
{
FileReader reader(fileName);
ReaderSource<FileReader> src(reader);
ReadMetadata(src, countryId, mwmVersion, baseTimestamp);
}
auto const expectedFileName =
GetPath(countryId + "_" + strings::to_string(mwmVersion) + kStatisticsExt);
if (fileName != expectedFileName)
{
alohalytics::TStringMap const info = {
{"expectedFilename", expectedFileName},
{"actualFilename", fileName},
};
alohalytics::LogEvent("localAdsBadFile", info);
}
MetadataKey const key = std::make_pair(countryId, mwmVersion);
auto it = m_metadataCache.find(key);
if (it != m_metadataCache.end())
{
// The only statistics file for countryId + mwmVersion must exist.
if (it->second.m_timestamp < baseTimestamp)
FileWriter::DeleteFileX(it->second.m_fileName);
else
FileWriter::DeleteFileX(fileName);
}
m_metadataCache[key] = Metadata(fileName, baseTimestamp);
}
catch (Reader::Exception const & ex)
{
LOG(LWARNING, ("Error reading file:", fileName, ex.Msg()));
}
}
void Statistics::BalanceMemory()
{
std::map<MetadataKey, uint64_t> sizeInBytes;
uint64_t totalSize = 0;
for (auto const & metadata : m_metadataCache)
{
FileReader reader(metadata.second.m_fileName);
sizeInBytes[metadata.first] = reader.Size();
totalSize += reader.Size();
}
if (totalSize < kMaxFilesSizeInBytes)
return;
auto constexpr kPackedDataSize =
sizeof(PackedData::m_featureIndex) + sizeof(PackedData::m_seconds) +
sizeof(PackedData::m_accuracy) + sizeof(PackedData::m_mercator) +
sizeof(PackedData::m_zoomLevel) + sizeof(PackedData::m_eventType);
for (auto const & metadata : sizeInBytes)
{
auto const disposingSize = static_cast<uint64_t>(metadata.second * kEventsDisposingRate);
auto const disposingCount = disposingSize / kPackedDataSize;
std::string fileName = m_metadataCache[metadata.first].m_fileName;
std::list<Event> events = ReadEvents(fileName);
m_metadataCache.erase(metadata.first);
FileWriter::DeleteFileX(fileName);
if (events.size() <= disposingCount)
continue;
events.sort();
auto it = events.begin();
std::advance(it, static_cast<size_t>(disposingCount));
events.erase(events.begin(), it);
std::string fileNameToRebuild;
WriteEvents(events, fileNameToRebuild);
ASSERT(fileNameToRebuild.empty(), ());
}
}
std::list<Event> Statistics::ReadEventsForTesting(std::string const & fileName)
{
return ReadEvents(GetPath(fileName));
}
void Statistics::ProcessEventsForTesting(std::list<Event> const & events)
{
std::list<Event> mutableEvents = events;
ProcessEvents(mutableEvents);
}
void Statistics::CleanupAfterTesting()
{
std::string const statsFolder = StatisticsFolder();
if (GetPlatform().IsFileExistsByFullPath(statsFolder))
GetPlatform().RmDirRecursively(statsFolder);
}
} // namespace local_ads

View file

@ -1,77 +0,0 @@
#pragma once
#include "local_ads/event.hpp"
#include "base/thread.hpp"
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <functional>
#include <list>
#include <map>
#include <string>
#include <vector>
namespace local_ads
{
using ServerSerializer =
std::function<std::vector<uint8_t>(std::list<Event> const & events, std::string const & userId,
std::string & contentType, std::string & contentEncoding)>;
class Statistics final
{
public:
struct PackedData
{
int64_t m_mercator = 0;
uint32_t m_featureIndex = 0;
uint32_t m_seconds = 0;
uint16_t m_accuracy = 0;
uint8_t m_eventType = 0;
uint8_t m_zoomLevel = 0;
};
Statistics();
void Startup();
void RegisterEvent(Event && event);
void RegisterEvents(std::list<Event> && events);
// Save the event synchronously (for lightweight frawework only).
void RegisterEventSync(Event && event);
void SetEnabled(bool isEnabled);
std::list<Event> WriteEventsForTesting(std::list<Event> const & events,
std::string & fileNameToRebuild);
std::list<Event> ReadEventsForTesting(std::string const & fileName);
void ProcessEventsForTesting(std::list<Event> const & events);
void CleanupAfterTesting();
private:
using MetadataKey = std::pair<std::string, int64_t>;
struct Metadata
{
std::string m_fileName;
Timestamp m_timestamp;
Metadata() = default;
Metadata(std::string const & fileName, Timestamp const & timestamp)
: m_fileName(fileName), m_timestamp(timestamp)
{}
};
void IndexMetadata();
void ExtractMetadata(std::string const & fileName);
void BalanceMemory();
std::list<Event> WriteEvents(std::list<Event> & events, std::string & fileNameToRebuild);
void ProcessEvents(std::list<Event> & events);
void SendToServer();
void SendFileWithMetadata(MetadataKey && metadataKey, Metadata && metadata);
std::string const m_userId;
bool m_isEnabled = false;
std::map<MetadataKey, Metadata> m_metadataCache;
};
} // namespace local_ads

View file

@ -85,11 +85,6 @@ set(
isolines_manager.hpp
layers_statistics.cpp
layers_statistics.hpp
local_ads_manager.cpp
local_ads_manager.hpp
local_ads_mark.cpp
local_ads_mark.hpp
local_ads_supported_types.cpp
mwm_url.cpp
mwm_url.hpp
notifications/notification_manager.cpp

View file

@ -1,6 +1,5 @@
#include "map/bookmark_manager.hpp"
#include "map/api_mark_point.hpp"
#include "map/local_ads_mark.hpp"
#include "map/routing_mark.hpp"
#include "map/search_api.hpp"
#include "map/search_mark.hpp"

View file

@ -269,7 +269,6 @@ void Framework::OnLocationUpdate(GpsInfo const & info)
#endif
m_routingManager.OnLocationUpdate(rInfo);
m_localAdsManager.OnLocationUpdate(rInfo, GetDrawScale());
}
void Framework::OnCompassUpdate(CompassInfo const & info)
@ -306,11 +305,6 @@ TrafficManager & Framework::GetTrafficManager()
return m_trafficManager;
}
LocalAdsManager & Framework::GetLocalAdsManager()
{
return m_localAdsManager;
}
TransitReadManager & Framework::GetTransitManager()
{
return m_transitManager;
@ -358,7 +352,6 @@ void Framework::OnViewportChanged(ScreenBase const & screen)
GetBookmarkManager().UpdateViewport(m_currentModelView);
m_trafficManager.UpdateViewport(m_currentModelView);
m_localAdsManager.UpdateViewport(m_currentModelView);
m_transitManager.UpdateViewport(m_currentModelView);
m_isolinesManager.UpdateViewport(m_currentModelView);
m_guidesManager.UpdateViewport(m_currentModelView);
@ -368,11 +361,7 @@ void Framework::OnViewportChanged(ScreenBase const & screen)
}
Framework::Framework(FrameworkParams const & params)
: m_localAdsManager(bind(&Framework::GetMwmsByRect, this, _1, true /* rough */),
bind(&Framework::GetMwmIdByName, this, _1),
bind(&Framework::ReadFeatures, this, _1, _2),
bind(&Framework::GetMapObjectByID, this, _1))
, m_enabledDiffs(params.m_enableDiffs)
: m_enabledDiffs(params.m_enableDiffs)
, m_isRenderingEnabled(true)
, m_transitManager(m_featuresFetcher.GetDataSource(),
[this](FeatureCallback const & fn, vector<FeatureID> const & features) {
@ -502,14 +491,6 @@ Framework::Framework(FrameworkParams const & params)
GetSearchAPI().LoadCitiesBoundaries();
GetSearchAPI().CacheWorldLocalities();
// Local ads manager should be initialized after storage initialization.
if (params.m_enableLocalAds)
{
auto const isActive = m_purchase->IsSubscriptionActive(SubscriptionType::RemoveAds);
m_localAdsManager.Startup(m_bmManager.get(), !isActive);
m_purchase->RegisterSubscription(&m_localAdsManager);
}
m_routingManager.SetRouterImpl(RouterType::Vehicle);
UpdateMinBuildingsTapZoom();
@ -665,7 +646,6 @@ void Framework::OnCountryFileDownloaded(storage::CountryId const & countryId,
m_trafficManager.Invalidate();
m_transitManager.Invalidate();
m_isolinesManager.Invalidate();
m_localAdsManager.OnDownloadCountry(countryId);
InvalidateRect(rect);
GetSearchAPI().ClearCaches();
}
@ -700,7 +680,6 @@ void Framework::OnMapDeregistered(platform::LocalCountryFile const & localFile)
{
auto action = [this, localFile]
{
m_localAdsManager.OnMwmDeregistered(localFile);
m_transitManager.OnMwmDeregistered(localFile);
m_isolinesManager.OnMwmDeregistered(localFile);
m_trafficManager.OnMwmDeregistered(localFile);
@ -1007,20 +986,6 @@ void Framework::FillInfoFromFeatureType(FeatureType & ft, place_page::Info & inf
!info.IsNotEditableSponsored() && isMapVersionEditable;
info.SetCanEditOrAdd(canEditOrAdd);
if (m_localAdsManager.IsSupportedType(info.GetTypes()))
{
info.SetLocalAdsUrl(m_localAdsManager.GetCompanyUrl(ft.GetID()));
auto status = m_localAdsManager.HasAds(ft.GetID()) ? place_page::LocalAdsStatus::Customer
: place_page::LocalAdsStatus::Candidate;
if (status == place_page::LocalAdsStatus::Customer && !m_localAdsManager.HasVisualization(ft.GetID()))
status = place_page::LocalAdsStatus::Hidden;
info.SetLocalAdsStatus(status);
}
else
{
info.SetLocalAdsStatus(place_page::LocalAdsStatus::NotAvailable);
}
auto const latlon = mercator::ToLatLon(feature::GetCenter(ft));
ASSERT(m_taxiEngine, ());
info.SetReachableByTaxiProviders(m_taxiEngine->GetProvidersAtPos(latlon));
@ -1837,17 +1802,16 @@ void Framework::FillSearchResultsMarks(search::Results::ConstIter begin,
if (r.m_details.m_isSponsoredHotel)
{
mark->SetBookingType(isFeature && m_localAdsManager.HasVisualization(r.GetFeatureID()) /* hasLocalAds */);
mark->SetBookingType();
mark->SetRating(r.m_details.m_hotelRating);
mark->SetPricing(r.m_details.m_hotelPricing);
}
else if (isFeature)
{
bool const hasLocalAds = m_localAdsManager.HasVisualization(r.GetFeatureID());
if (r.m_details.m_isHotel)
mark->SetHotelType(hasLocalAds);
mark->SetHotelType();
else
mark->SetFromType(r.GetFeatureType(), hasLocalAds);
mark->SetFromType(r.GetFeatureType());
auto product = GetProductInfo(r);
if (product.m_ugcRating != search::ProductInfo::kInvalidRating)
mark->SetRating(product.m_ugcRating);
@ -1930,22 +1894,6 @@ void Framework::CreateDrapeEngine(ref_ptr<dp::GraphicsContextFactory> contextFac
{
if (events.empty())
return;
list<local_ads::Event> statEvents;
for (auto const & event : events)
{
auto const & mwmInfo = event.m_feature.m_mwmId.GetInfo();
if (!mwmInfo || !m_localAdsManager.HasAds(event.m_feature))
continue;
statEvents.emplace_back(local_ads::EventType::ShowPoint,
mwmInfo->GetVersion(), mwmInfo->GetCountryName(),
event.m_feature.m_index, event.m_zoomLevel, event.m_timestamp,
mercator::YToLat(event.m_myPosition.y),
mercator::XToLon(event.m_myPosition.x),
static_cast<uint16_t>(event.m_gpsAccuracy));
}
m_localAdsManager.GetStatistics().RegisterEvents(std::move(statEvents));
};
auto onGraphicsContextInitialized = [this]()
@ -2035,7 +1983,6 @@ void Framework::CreateDrapeEngine(ref_ptr<dp::GraphicsContextFactory> contextFac
m_transitManager.SetDrapeEngine(make_ref(m_drapeEngine));
m_isolinesManager.SetDrapeEngine(make_ref(m_drapeEngine));
m_guidesManager.SetDrapeEngine(make_ref(m_drapeEngine));
m_localAdsManager.SetDrapeEngine(make_ref(m_drapeEngine));
m_searchMarks.SetDrapeEngine(make_ref(m_drapeEngine));
InvalidateUserMarks();
@ -2069,7 +2016,6 @@ void Framework::OnRecoverSurface(int width, int height, bool recreateContextDepe
m_trafficManager.OnRecoverSurface();
m_transitManager.Invalidate();
m_isolinesManager.Invalidate();
m_localAdsManager.Invalidate();
}
void Framework::OnDestroySurface()
@ -2104,7 +2050,6 @@ void Framework::DestroyDrapeEngine()
m_transitManager.SetDrapeEngine(nullptr);
m_isolinesManager.SetDrapeEngine(nullptr);
m_guidesManager.SetDrapeEngine(nullptr);
m_localAdsManager.SetDrapeEngine(nullptr);
m_searchMarks.SetDrapeEngine(nullptr);
GetBookmarkManager().SetDrapeEngine(nullptr);
@ -2211,7 +2156,6 @@ void Framework::SetMapStyle(MapStyle mapStyle)
if (m_drapeEngine != nullptr)
m_drapeEngine->UpdateMapStyle();
InvalidateUserMarks();
m_localAdsManager.Invalidate();
UpdateMinBuildingsTapZoom();
}
@ -2721,7 +2665,6 @@ std::optional<place_page::Info> Framework::BuildPlacePageInfo(
return {};
outInfo.SetBuildInfo(buildInfo);
outInfo.SetAdsEngine(m_adsEngine.get());
if (buildInfo.IsUserMarkMatchingEnabled())
{
@ -4063,8 +4006,6 @@ search::ProductInfo Framework::GetProductInfo(search::Result const & result) con
search::ProductInfo productInfo;
productInfo.m_isLocalAdsCustomer = m_localAdsManager.HasVisualization(result.GetFeatureID());
auto const ugc = m_ugcApi->GetLoader().GetUGC(result.GetFeatureID());
productInfo.m_ugcRating = ugc.m_totalRating;

View file

@ -11,7 +11,6 @@
#include "map/features_fetcher.hpp"
#include "map/guides_manager.hpp"
#include "map/isolines_manager.hpp"
#include "map/local_ads_manager.hpp"
#include "map/mwm_url.hpp"
#include "map/notifications/notification_manager.hpp"
#include "map/place_page_info.hpp"
@ -142,14 +141,12 @@ class NotificationCandidate;
struct FrameworkParams
{
bool m_enableLocalAds = true;
bool m_enableDiffs = true;
size_t m_numSearchAPIThreads = 1;
FrameworkParams() = default;
FrameworkParams(bool enableLocalAds, bool enableDiffs)
: m_enableLocalAds(enableLocalAds)
, m_enableDiffs(enableDiffs)
FrameworkParams(bool enableDiffs)
: m_enableDiffs(enableDiffs)
{}
};
@ -199,8 +196,6 @@ protected:
// search::Engine and, therefore, destroyed after search::Engine.
std::unique_ptr<storage::CountryInfoGetter> m_infoGetter;
LocalAdsManager m_localAdsManager;
// The order matters here: ugc::Api should be destroyed after
// SearchAPI and notifications::NotificationManager.
std::unique_ptr<ugc::Api> m_ugcApi;
@ -772,8 +767,6 @@ public:
TrafficManager & GetTrafficManager();
LocalAdsManager & GetLocalAdsManager();
TransitReadManager & GetTransitManager();
IsolinesManager & GetIsolinesManager();

View file

@ -47,18 +47,6 @@ Framework::Framework(RequestTypeMask request) : m_request(request)
request ^= REQUEST_TYPE_LOCATION;
}
if (request & REQUEST_TYPE_LOCAL_ADS_FEATURES)
{
m_localAdsFeaturesReader = std::make_unique<LocalAdsFeaturesReader>();
request ^= REQUEST_TYPE_LOCAL_ADS_FEATURES;
}
if (request & REQUEST_TYPE_LOCAL_ADS_STATISTICS)
{
m_localAdsStatistics = std::make_unique<Statistics>();
request ^= REQUEST_TYPE_LOCAL_ADS_STATISTICS;
}
if (request & REQUEST_TYPE_NOTIFICATION)
{
request ^= REQUEST_TYPE_NOTIFICATION;
@ -105,21 +93,6 @@ CountryInfoReader::Info Framework::GetLocation(m2::PointD const & pt) const
return m_countryInfoReader->GetMwmInfo(pt);
}
std::vector<CampaignFeature> Framework::GetLocalAdsFeatures(double lat, double lon,
double radiusInMeters, uint32_t maxCount)
{
ASSERT(m_request & REQUEST_TYPE_LOCAL_ADS_FEATURES, (m_request));
CHECK(m_localAdsFeaturesReader, ());
return m_localAdsFeaturesReader->GetCampaignFeatures(lat, lon, radiusInMeters, maxCount);
}
Statistics * Framework::GetLocalAdsStatistics()
{
ASSERT(m_request & REQUEST_TYPE_LOCAL_ADS_STATISTICS, (m_request));
CHECK(m_localAdsStatistics, ());
return m_localAdsStatistics.get();
}
notifications::Notification Framework::GetNotification() const
{
// Do not disturb from 9p.m. to 10 a.m.

View file

@ -1,7 +1,6 @@
#pragma once
#include "map/bookmark_manager.hpp"
#include "map/local_ads_manager.hpp"
#include "map/notifications/notification_manager.hpp"
#include "map/user.hpp"
@ -33,8 +32,8 @@ enum RequestType
// and takes much time. For example it takes ~50ms on LG Nexus 5, ~100ms on Samsung A5, ~200ms on
// Fly IQ4403.
REQUEST_TYPE_LOCATION = 1u << 4,
REQUEST_TYPE_LOCAL_ADS_FEATURES = 1u << 5,
REQUEST_TYPE_LOCAL_ADS_STATISTICS = 1u << 6,
// REQUEST_TYPE_LOCAL_ADS_FEATURES = 1u << 5,
// REQUEST_TYPE_LOCAL_ADS_STATISTICS = 1u << 6,
REQUEST_TYPE_NOTIFICATION = 1u << 7,
};
@ -64,9 +63,6 @@ public:
size_t GetNumberOfUnsentEdits() const;
bool IsBookmarksCloudEnabled() const;
CountryInfoReader::Info GetLocation(m2::PointD const & pt) const;
std::vector<CampaignFeature> GetLocalAdsFeatures(double lat, double lon, double radiusInMeters,
uint32_t maxCount);
Statistics * GetLocalAdsStatistics();
notifications::Notification GetNotification() const;
private:
@ -77,8 +73,6 @@ private:
size_t m_numberOfUnsentEdits = 0;
bool m_bookmarksCloudEnabled = false;
std::unique_ptr<CountryInfoReader> m_countryInfoReader;
std::unique_ptr<LocalAdsFeaturesReader> m_localAdsFeaturesReader;
std::unique_ptr<Statistics> m_localAdsStatistics;
};
std::string FeatureParamsToString(int64_t mwmVersion, std::string const & countryId, uint32_t featureIndex);

View file

@ -1,965 +0,0 @@
#include "map/local_ads_manager.hpp"
#include "map/bookmark_manager.hpp"
#include "map/local_ads_mark.hpp"
#include "local_ads/campaign_serialization.hpp"
#include "local_ads/config.hpp"
#include "local_ads/file_helpers.hpp"
#include "local_ads/icons_info.hpp"
#include "drape_frontend/drape_engine.hpp"
#include "drape_frontend/visual_params.hpp"
#include "indexer/feature_algo.hpp"
#include "indexer/feature_data.hpp"
#include "indexer/scales.hpp"
#include "platform/http_client.hpp"
#include "platform/marketing_service.hpp"
#include "platform/platform.hpp"
#include "platform/preferred_languages.hpp"
#include "platform/settings.hpp"
#include "coding/point_coding.hpp"
#include "coding/string_utf8_multilang.hpp"
#include "coding/url.hpp"
#include "base/file_name_utils.hpp"
#include "private.h"
#include <array>
#include <cstring>
#include <limits>
#include <sstream>
using namespace base;
namespace
{
std::array<char const * const, 5> const kMarketingParameters = {{marketing::kFrom, marketing::kType, marketing::kName,
marketing::kContent, marketing::kKeyword}};
std::string const kServerUrl = LOCAL_ADS_SERVER_URL;
std::string const kCampaignPageUrl = LOCAL_ADS_COMPANY_PAGE_URL;
std::string const kCampaignFile = "local_ads_campaigns.dat";
std::string const kCampaignFeaturesFile = "local_ads_features.dat";
std::string const kLocalAdsSymbolsFile = "local_ads_symbols.txt";
auto constexpr kWWanUpdateTimeout = std::chrono::hours(12);
uint8_t constexpr kRequestMinZoomLevel = 12;
auto constexpr kFailedDownloadingTimeout = std::chrono::seconds(2);
auto constexpr kMaxDownloadingAttempts = 5;
auto constexpr kHiddenFeaturePriority = 1;
auto constexpr kMinCheckInterval = std::chrono::minutes(1);
double constexpr kMinCheckDistanceInMeters = 5.0;
double constexpr kMinSearchRadiusInMeters = 20.0;
double constexpr kMaxAllowableAccuracyInMeters = 20.0;
uint32_t constexpr kMaxHitCount = 3;
void SerializeCampaign(FileWriter & writer, std::string const & countryName,
LocalAdsManager::Timestamp const & ts,
std::vector<uint8_t> const & rawData)
{
local_ads::WriteCountryName(writer, countryName);
local_ads::WriteTimestamp<std::chrono::hours>(writer, ts);
local_ads::WriteRawData(writer, rawData);
}
void DeserializeCampaign(ReaderSource<FileReader> & src, std::string & countryName,
LocalAdsManager::Timestamp & ts, std::vector<uint8_t> & rawData)
{
countryName = local_ads::ReadCountryName(src);
ts = local_ads::ReadTimestamp<std::chrono::hours>(src);
rawData = local_ads::ReadRawData(src);
}
std::string GetPath(std::string const & fileName)
{
return base::JoinPath(GetPlatform().SettingsDir(), fileName);
}
std::string MakeCampaignDownloadingURL(MwmSet::MwmId const & mwmId)
{
if (kServerUrl.empty() || !mwmId.IsAlive())
return {};
std::ostringstream ss;
auto const campaignDataVersion = static_cast<uint32_t>(local_ads::Version::Latest);
ss << kServerUrl << "/"
<< campaignDataVersion << "/"
<< mwmId.GetInfo()->GetVersion() << "/"
<< url::UrlEncode(mwmId.GetInfo()->GetCountryName()) << ".ads";
return ss.str();
}
std::string GetCustomIcon(osm::MapObject const & mapObject)
{
auto const & metadata = mapObject.GetMetadata();
auto const websiteStr = metadata.Get(feature::Metadata::FMD_WEBSITE);
if (websiteStr.find("burgerking") != std::string::npos)
return "0_burger-king";
auto const bannerUrl = metadata.Get(feature::Metadata::FMD_BANNER_URL);
if (bannerUrl.find("mcarthurglen") != std::string::npos)
return "partner1-l";
if (bannerUrl.find("sixt") != std::string::npos)
return "partner2-l";
if (bannerUrl.find("azbuka_vkusa") != std::string::npos)
return "partner12-l";
return {};
}
std::string MakeCampaignPageURL(FeatureID const & featureId)
{
if (kCampaignPageUrl.empty() || !featureId.m_mwmId.IsAlive())
return {};
std::ostringstream ss;
ss << kCampaignPageUrl << "/" << featureId.m_mwmId.GetInfo()->GetVersion() << "/"
<< url::UrlEncode(featureId.m_mwmId.GetInfo()->GetCountryName()) << "/" << featureId.m_index;
url::Params params;
params.reserve(kMarketingParameters.size());
for (auto const & key : kMarketingParameters)
{
std::string value;
if (!marketing::Settings::Get(key, value))
continue;
params.push_back({key, value});
}
return url::Make(ss.str(), params);
}
} // namespace
namespace features_cache
{
enum class Version : uint8_t
{
V0 = 0,
Latest = V0
};
struct PackedCampaignFeature
{
PackedCampaignFeature() = default;
PackedCampaignFeature(uint32_t featureIndex, int64_t mercator)
: m_featureIndex(featureIndex)
, m_mercator(mercator)
{}
uint32_t m_featureIndex = 0;
int64_t m_mercator = 0;
};
void SerializeVersion(FileWriter & writer, Version version)
{
WriteToSink(writer, static_cast<uint8_t>(version));
}
void SerializeMwmData(FileWriter & writer, std::string const & countryId, int64_t mwmVersion)
{
local_ads::WriteCountryName(writer, countryId);
local_ads::WriteZigZag(writer, mwmVersion);
}
void SerializePackedFeatures(FileWriter & writer, std::vector<PackedCampaignFeature> const & packedFeatures)
{
auto const featuresCount = static_cast<uint32_t>(packedFeatures.size());
WriteToSink(writer, featuresCount);
for (auto const & data : packedFeatures)
{
WriteToSink(writer, data.m_featureIndex);
local_ads::WriteZigZag(writer, data.m_mercator);
}
}
Version DeserializeVersion(ReaderSource<FileReader> & src)
{
return static_cast<Version>(ReadPrimitiveFromSource<uint8_t>(src));
}
void DeserializeMwmData(ReaderSource<FileReader> & src, std::string & countryId, int64_t & mwmVersion)
{
countryId = local_ads::ReadCountryName(src);
mwmVersion = local_ads::ReadZigZag(src);
}
void DeserializePackedFeatures(ReaderSource<FileReader> & src, std::vector<PackedCampaignFeature> & packedFeatures)
{
auto const featuresCount = ReadPrimitiveFromSource<uint32_t>(src);
packedFeatures.clear();
packedFeatures.reserve(static_cast<size_t>(featuresCount));
for (uint32_t i = 0; i < featuresCount; ++i)
{
PackedCampaignFeature data;
data.m_featureIndex = ReadPrimitiveFromSource<uint32_t>(src);
data.m_mercator = local_ads::ReadZigZag(src);
packedFeatures.push_back(data);
}
}
} // namespace features_cache
LocalAdsManager::LocalAdsManager(GetMwmsByRectFn && getMwmsByRectFn,
GetMwmIdByNameFn && getMwmIdByName,
ReadFeaturesFn && readFeaturesFn,
GetMapObjectByIdFn && getMapObjectByIdFn)
: m_getMwmsByRectFn(std::move(getMwmsByRectFn))
, m_getMwmIdByNameFn(std::move(getMwmIdByName))
, m_readFeaturesFn(std::move(readFeaturesFn))
, m_getMapObjectByIdFn(std::move(getMapObjectByIdFn))
, m_isStarted(false)
, m_bmManager(nullptr)
{
CHECK(m_getMwmsByRectFn != nullptr, ());
CHECK(m_getMwmIdByNameFn != nullptr, ());
CHECK(m_readFeaturesFn != nullptr, ());
CHECK(m_getMapObjectByIdFn != nullptr, ());
}
void LocalAdsManager::Startup(BookmarkManager * bmManager, bool isEnabled)
{
m_isEnabled = isEnabled;
FillSupportedTypes();
m_bmManager = bmManager;
if (isEnabled)
Start();
}
void LocalAdsManager::Start()
{
m_isStarted = true;
GetPlatform().RunTask(Platform::Thread::File, [this]
{
local_ads::IconsInfo::Instance().SetSourceFile(kLocalAdsSymbolsFile);
std::string const campaignFile = GetPath(kCampaignFile);
// Read persistence data.
ReadCampaignFile(campaignFile);
InvalidateImpl();
});
m_statistics.Startup();
}
void LocalAdsManager::SetDrapeEngine(ref_ptr<df::DrapeEngine> engine)
{
m_drapeEngine.Set(engine);
UpdateFeaturesCache({});
}
void LocalAdsManager::UpdateViewport(ScreenBase const & screen)
{
auto const connectionStatus = GetPlatform().ConnectionStatus();
if (!m_isStarted || !m_isEnabled || kServerUrl.empty() ||
connectionStatus == Platform::EConnectionType::CONNECTION_NONE ||
df::GetZoomLevel(screen.GetScale()) < kRequestMinZoomLevel)
{
return;
}
// This function must be called on UI-thread.
auto mwms = m_getMwmsByRectFn(screen.ClipRect());
if (mwms.empty())
return;
if (m_lastMwms == mwms)
return;
m_lastMwms = mwms;
// Request local ads campaigns.
GetPlatform().RunTask(Platform::Thread::File, [this, mwms = std::move(mwms)]()
{
RequestCampaigns(mwms);
});
}
void LocalAdsManager::RequestCampaigns(std::vector<MwmSet::MwmId> const & mwmIds)
{
auto const connectionStatus = GetPlatform().ConnectionStatus();
std::vector<MwmSet::MwmId> requestedCampaigns;
{
std::lock_guard<std::mutex> lock(m_campaignsMutex);
for (auto const & mwm : mwmIds)
{
auto info = mwm.GetInfo();
if (!info)
continue;
// Skip currently downloading mwms.
if (m_downloadingMwms.find(mwm) != m_downloadingMwms.cend())
continue;
// Skip downloading request if maximum attempts count has been reached or
// we are waiting for new attempt.
auto const failedDownloadsIt = m_failedDownloads.find(mwm);
if (failedDownloadsIt != m_failedDownloads.cend() && !failedDownloadsIt->second.CanRetry())
continue;
std::string const & mwmName = info->GetCountryName();
auto campaignIt = m_campaigns.find(mwmName);
if (campaignIt == m_campaigns.end())
{
requestedCampaigns.push_back(mwm);
m_downloadingMwms.insert(mwm);
continue;
}
// If a campaign has not been requested from server this session.
if (!campaignIt->second)
{
auto const it = m_info.find(mwmName);
bool needUpdateByTimeout = (connectionStatus == Platform::EConnectionType::CONNECTION_WIFI);
if (!needUpdateByTimeout && it != m_info.end())
needUpdateByTimeout = local_ads::Clock::now() > (it->second.m_created + kWWanUpdateTimeout);
if (needUpdateByTimeout || it == m_info.end())
{
requestedCampaigns.push_back(mwm);
m_downloadingMwms.insert(mwm);
}
}
}
}
if (requestedCampaigns.empty())
return;
std::set<Request> requests;
for (auto const & campaign : requestedCampaigns)
requests.insert(std::make_pair(campaign, RequestType::Download));
ProcessRequests(std::move(requests));
}
bool LocalAdsManager::DownloadCampaign(MwmSet::MwmId const & mwmId, std::vector<uint8_t> & bytes)
{
bytes.clear();
std::string const url = MakeCampaignDownloadingURL(mwmId);
if (url.empty())
return true; // In this case empty result is valid.
// Skip already downloaded campaigns.
auto const & countryName = mwmId.GetInfo()->GetCountryName();
{
std::lock_guard<std::mutex> lock(m_campaignsMutex);
auto const it = m_campaigns.find(countryName);
if (it != m_campaigns.cend() && it->second)
return false;
}
platform::HttpClient request(url);
request.SetTimeout(5); // timeout in seconds
request.SetRawHeader("User-Agent", GetPlatform().GetAppUserAgent());
bool const success = request.RunHttpRequest() && request.ErrorCode() == 200;
std::lock_guard<std::mutex> lock(m_campaignsMutex);
m_downloadingMwms.erase(mwmId);
if (!success)
{
bool const isAbsent = request.ErrorCode() == 404;
auto const it = m_failedDownloads.find(mwmId);
if (it == m_failedDownloads.cend())
{
m_failedDownloads.insert(std::make_pair(mwmId, BackoffStats(std::chrono::steady_clock::now(),
kFailedDownloadingTimeout,
1 /* m_attemptsCount */, isAbsent)));
}
else
{
// Here we increase timeout multiplying by 2.
it->second.m_currentTimeout = std::chrono::seconds(it->second.m_currentTimeout.count() * 2);
it->second.m_attemptsCount++;
it->second.m_fileIsAbsent = isAbsent;
}
return false;
}
m_failedDownloads.erase(mwmId);
auto const & response = request.ServerResponse();
bytes.assign(response.cbegin(), response.cend());
return true;
}
void LocalAdsManager::ProcessRequests(std::set<Request> && requests)
{
GetPlatform().RunTask(Platform::Thread::Network, [this, requests = std::move(requests)]
{
for (auto const & request : requests)
{
auto const & mwm = request.first;
auto const & type = request.second;
if (!mwm.GetInfo())
continue;
std::string const & countryName = mwm.GetInfo()->GetCountryName();
if (type == RequestType::Download)
{
// Download campaign data from server.
CampaignInfo info;
info.m_created = local_ads::Clock::now();
if (!DownloadCampaign(mwm, info.m_data))
continue;
// Parse data and recreate marks.
ClearLocalAdsForMwm(mwm);
if (!info.m_data.empty())
{
auto campaignData = ParseCampaign(info.m_data, mwm, info.m_created, m_getMapObjectByIdFn);
if (!campaignData.empty())
{
UpdateFeaturesCache(ReadCampaignFeatures(campaignData));
CreateLocalAdsMarks(std::move(campaignData));
}
}
std::lock_guard<std::mutex> lock(m_campaignsMutex);
m_campaigns[countryName] = true;
m_info[countryName] = info;
}
else if (type == RequestType::Delete)
{
std::lock_guard<std::mutex> lock(m_campaignsMutex);
m_campaigns.erase(countryName);
m_info.erase(countryName);
ClearLocalAdsForMwm(mwm);
}
}
auto const campaignFile = GetPath(kCampaignFile);
auto const featureFile = GetPath(kCampaignFeaturesFile);
// Save data persistently.
GetPlatform().RunTask(Platform::Thread::File, [this, campaignFile, featureFile]
{
WriteCampaignFile(campaignFile);
WriteFeaturesFile(featureFile);
});
});
}
void LocalAdsManager::OnDownloadCountry(std::string const & countryName)
{
m_lastMwms.clear();
GetPlatform().RunTask(Platform::Thread::File, [this, countryName]
{
std::lock_guard<std::mutex> lock(m_campaignsMutex);
m_campaigns.erase(countryName);
m_info.erase(countryName);
});
}
void LocalAdsManager::OnMwmDeregistered(platform::LocalCountryFile const & countryFile)
{
m_lastMwms.clear();
MwmSet::MwmId mwmId;
{
std::lock_guard<std::mutex> lock(m_featuresCacheMutex);
for (auto const & cachedMwm : m_featuresCache)
{
if (cachedMwm.first.m_mwmId.IsDeregistered(countryFile))
{
mwmId = cachedMwm.first.m_mwmId;
break;
}
}
}
if (!mwmId.GetInfo())
return;
GetPlatform().RunTask(Platform::Thread::File, [this, mwmId]
{
ProcessRequests({std::make_pair(mwmId, RequestType::Delete)});
});
}
void LocalAdsManager::ReadCampaignFile(std::string const & campaignFile)
{
if (!GetPlatform().IsFileExistsByFullPath(campaignFile))
return;
std::lock_guard<std::mutex> lock(m_campaignsMutex);
try
{
FileReader reader(campaignFile);
ReaderSource<FileReader> src(reader);
while (src.Size() > 0)
{
std::string countryName;
CampaignInfo info;
DeserializeCampaign(src, countryName, info.m_created, info.m_data);
m_info[countryName] = info;
m_campaigns[countryName] = false;
}
}
catch (Reader::Exception const & ex)
{
LOG(LWARNING, ("Error reading file:", campaignFile, ex.Msg()));
FileWriter::DeleteFileX(campaignFile);
m_info.clear();
m_campaigns.clear();
}
}
void LocalAdsManager::WriteCampaignFile(std::string const & campaignFile)
{
std::lock_guard<std::mutex> lock(m_campaignsMutex);
try
{
FileWriter writer(campaignFile);
for (auto const & info : m_info)
SerializeCampaign(writer, info.first, info.second.m_created, info.second.m_data);
}
catch (RootException const & ex)
{
LOG(LWARNING, ("Error writing file:", campaignFile, ex.Msg()));
}
}
void LocalAdsManager::WriteFeaturesFile(std::string const & featuresFile)
{
std::lock_guard<std::mutex> lock(m_featuresCacheMutex);
try
{
FileWriter writer(featuresFile);
features_cache::SerializeVersion(writer, features_cache::Version::V0);
MwmSet::MwmId lastMwm;
std::vector<features_cache::PackedCampaignFeature> packedData;
for (auto const & entry : m_featuresCache)
{
FeatureID const & fid = entry.first;
if (lastMwm != fid.m_mwmId && !packedData.empty())
{
features_cache::SerializeMwmData(writer, lastMwm.GetInfo()->GetCountryName(), lastMwm.GetInfo()->GetVersion());
features_cache::SerializePackedFeatures(writer, packedData);
packedData.clear();
}
lastMwm = fid.m_mwmId;
packedData.emplace_back(fid.m_index,
PointToInt64Obsolete(entry.second.m_position, kPointCoordBits));
}
if (!packedData.empty())
{
features_cache::SerializeMwmData(writer, lastMwm.GetInfo()->GetCountryName(), lastMwm.GetInfo()->GetVersion());
features_cache::SerializePackedFeatures(writer, packedData);
}
}
catch (RootException const & ex)
{
LOG(LWARNING, ("Error writing file:", featuresFile, ex.Msg()));
}
}
void LocalAdsManager::Invalidate()
{
m_lastMwms.clear();
GetPlatform().RunTask(Platform::Thread::File, [this]
{
InvalidateImpl();
});
}
void LocalAdsManager::InvalidateImpl()
{
DeleteAllLocalAdsMarks();
m_drapeEngine.SafeCall(&df::DrapeEngine::RemoveAllCustomFeatures);
CampaignData campaignData;
{
std::lock_guard<std::mutex> lock(m_campaignsMutex);
for (auto const & info : m_info)
{
auto data = ParseCampaign(info.second.m_data, m_getMwmIdByNameFn(info.first),
info.second.m_created, m_getMapObjectByIdFn);
campaignData.insert(data.begin(), data.end());
}
}
UpdateFeaturesCache(ReadCampaignFeatures(campaignData));
CreateLocalAdsMarks(std::move(campaignData));
}
LocalAdsManager::CampaignData LocalAdsManager::ParseCampaign(std::vector<uint8_t> const & rawData,
MwmSet::MwmId const & mwmId,
Timestamp timestamp,
GetMapObjectByIdFn const & getMapObjectByIdFn) const
{
ASSERT(getMapObjectByIdFn != nullptr, ());
CampaignData data;
auto campaigns = local_ads::Deserialize(rawData);
for (local_ads::Campaign const & campaign : campaigns)
{
FeatureID featureId(mwmId, campaign.m_featureId);
if (!featureId.IsValid())
continue;
if (campaign.m_priority == kHiddenFeaturePriority)
{
data.insert(std::make_pair(featureId, nullptr));
continue;
}
std::string iconName = campaign.GetIconName();
auto const expiration = timestamp + std::chrono::hours(24 * campaign.m_daysBeforeExpired);
if (iconName.empty() || local_ads::Clock::now() > expiration)
continue;
auto const mapObject = getMapObjectByIdFn(featureId);
if (mapObject.GetID().IsValid())
{
auto const customIcon = GetCustomIcon(mapObject);
if (!customIcon.empty())
iconName = customIcon;
}
auto markData = std::make_shared<LocalAdsMarkData>();
markData->m_symbolName = iconName;
markData->m_minZoomLevel = campaign.m_minZoomLevel;
data.insert(std::make_pair(featureId, std::move(markData)));
}
return data;
}
void LocalAdsManager::CreateLocalAdsMarks(CampaignData && campaignData)
{
// Here we copy campaign data, because we can create user marks only from UI thread.
GetPlatform().RunTask(Platform::Thread::Gui, [this, campaignData = std::move(campaignData)]()
{
if (m_bmManager == nullptr)
return;
auto editSession = m_bmManager->GetEditSession();
for (auto const & data : campaignData)
{
if (data.second == nullptr)
continue;
auto * mark = editSession.CreateUserMark<LocalAdsMark>(data.second->m_position);
mark->SetData(LocalAdsMarkData(*data.second));
mark->SetFeatureId(data.first);
}
});
}
void LocalAdsManager::DeleteLocalAdsMarks(MwmSet::MwmId const & mwmId)
{
GetPlatform().RunTask(Platform::Thread::Gui, [this, mwmId]()
{
if (m_bmManager == nullptr)
return;
m_bmManager->GetEditSession().DeleteUserMarks<LocalAdsMark>(UserMark::Type::LOCAL_ADS,
[&mwmId](LocalAdsMark const * mark)
{
return mark->GetFeatureID().m_mwmId == mwmId;
});
});
}
void LocalAdsManager::DeleteAllLocalAdsMarks()
{
GetPlatform().RunTask(Platform::Thread::Gui, [this]()
{
if (m_bmManager == nullptr)
return;
m_bmManager->GetEditSession().ClearGroup(UserMark::Type::LOCAL_ADS);
});
}
LocalAdsManager::FeaturesCache LocalAdsManager::ReadCampaignFeatures(CampaignData & campaignData) const
{
ASSERT(m_readFeaturesFn != nullptr, ());
LocalAdsManager::FeaturesCache cache;
std::vector<FeatureID> features;
features.reserve(campaignData.size());
for (auto const & data : campaignData)
features.push_back(data.first);
auto const deviceLang = StringUtf8Multilang::GetLangIndex(languages::GetCurrentNorm());
m_readFeaturesFn(
[&campaignData, &cache, deviceLang](FeatureType & ft) {
auto it = campaignData.find(ft.GetID());
CHECK(it != campaignData.end(), ());
LocalAdsManager::CacheEntry entry;
entry.m_position = feature::GetCenter(ft, scales::GetUpperScale());
entry.m_isVisibleOnMap = it->second != nullptr;
if (it->second != nullptr)
{
it->second->m_position = entry.m_position;
ft.GetPreferredNames(true /* allowTranslit */, deviceLang, it->second->m_mainText, it->second->m_auxText);
}
cache.insert(std::make_pair(it->first, entry));
},
features);
return cache;
}
void LocalAdsManager::UpdateFeaturesCache(FeaturesCache && features)
{
df::CustomFeatures customFeatures;
{
std::lock_guard<std::mutex> lock(m_featuresCacheMutex);
if (!features.empty())
m_featuresCache.insert(features.begin(), features.end());
for (auto const & entry : m_featuresCache)
customFeatures.insert(std::make_pair(entry.first, entry.second.m_isVisibleOnMap));
}
m_drapeEngine.SafeCall(&df::DrapeEngine::SetCustomFeatures, std::move(customFeatures));
}
void LocalAdsManager::ClearLocalAdsForMwm(MwmSet::MwmId const & mwmId)
{
// Clear feature cache.
{
std::lock_guard<std::mutex> lock(m_featuresCacheMutex);
for (auto it = m_featuresCache.begin(); it != m_featuresCache.end();)
{
if (it->first.m_mwmId == mwmId)
it = m_featuresCache.erase(it);
else
++it;
}
}
// Remove custom features in graphics engine.
m_drapeEngine.SafeCall(&df::DrapeEngine::RemoveCustomFeatures, mwmId);
// Delete marks.
DeleteLocalAdsMarks(mwmId);
}
bool LocalAdsManager::HasAds(FeatureID const & featureId) const
{
std::lock_guard<std::mutex> lock(m_featuresCacheMutex);
return m_featuresCache.find(featureId) != m_featuresCache.cend();
}
bool LocalAdsManager::HasVisualization(FeatureID const & featureId) const
{
std::lock_guard<std::mutex> lock(m_featuresCacheMutex);
auto const it = m_featuresCache.find(featureId);
if (it == m_featuresCache.cend())
return false;
return it->second.m_isVisibleOnMap;
}
bool LocalAdsManager::IsSupportedType(feature::TypesHolder const & types) const
{
return m_supportedTypes.Contains(types);
}
std::string LocalAdsManager::GetCompanyUrl(FeatureID const & featureId) const
{
return MakeCampaignPageURL(featureId);
}
void LocalAdsManager::OnSubscriptionChanged(SubscriptionType type, bool isActive)
{
if (type != SubscriptionType::RemoveAds)
return;
bool enabled = !isActive;
if (m_isEnabled == enabled)
return;
m_isEnabled = enabled;
m_lastMwms.clear();
if (enabled)
{
if (!m_isStarted)
Start();
else
Invalidate();
}
else
{
GetPlatform().RunTask(Platform::Thread::File, [this]
{
// Clear campaigns data.
{
std::lock_guard<std::mutex> lock(m_campaignsMutex);
m_campaigns.clear();
m_info.clear();
m_failedDownloads.clear();
m_downloadingMwms.clear();
}
// Clear features cache.
{
std::lock_guard<std::mutex> lock(m_featuresCacheMutex);
m_featuresCache.clear();
}
// Clear all graphics.
DeleteAllLocalAdsMarks();
m_drapeEngine.SafeCall(&df::DrapeEngine::RemoveAllCustomFeatures);
});
// Disable statistics collection.
m_statistics.SetEnabled(false);
}
}
void LocalAdsManager::OnLocationUpdate(location::GpsInfo const & info, int zoomLevel)
{
if (!m_isEnabled)
return;
if (info.m_horizontalAccuracy > kMaxAllowableAccuracyInMeters)
return;
if (std::chrono::steady_clock::now() < (m_lastCheckTime + kMinCheckInterval))
return;
auto const pt = mercator::FromLatLon(info.m_latitude, info.m_longitude);
if ((m_foundFeatureHitCount == 0 || m_foundFeatureHitCount == kMaxHitCount) &&
mercator::DistanceOnEarth(m_lastCheckedPos, pt) < kMinCheckDistanceInMeters)
{
return;
}
auto const radius = std::max(info.m_horizontalAccuracy, kMinSearchRadiusInMeters);
auto searchRect = mercator::RectByCenterXYAndSizeInMeters(pt, radius);
FeatureID fid;
{
std::lock_guard<std::mutex> lock(m_featuresCacheMutex);
double minDist = std::numeric_limits<double>::max();
for (auto const & pair : m_featuresCache)
{
auto const & pos = pair.second.m_position;
if (!searchRect.IsPointInside(pos))
continue;
auto const dist = mercator::DistanceOnEarth(pos, pt);
if (dist < radius && dist < minDist)
{
minDist = dist;
fid = pair.first;
}
}
}
m_lastCheckTime = std::chrono::steady_clock::now();
m_lastCheckedPos = pt;
if (fid.IsValid())
{
m_statistics.RegisterEvent(local_ads::Event(local_ads::EventType::Visit, fid.m_mwmId.GetInfo()->GetVersion(),
fid.m_mwmId.GetInfo()->GetCountryName(), fid.m_index,
static_cast<uint8_t>(zoomLevel), local_ads::Clock::now(),
info.m_latitude, info.m_longitude,
static_cast<uint16_t>(info.m_horizontalAccuracy)));
if (m_lastFoundFeature != fid)
m_foundFeatureHitCount = 1;
else if (m_foundFeatureHitCount < kMaxHitCount)
++m_foundFeatureHitCount;
}
else
{
m_foundFeatureHitCount = 0;
}
m_lastFoundFeature = fid;
}
bool LocalAdsManager::BackoffStats::CanRetry() const
{
return !m_fileIsAbsent && m_attemptsCount < kMaxDownloadingAttempts &&
std::chrono::steady_clock::now() > (m_lastDownloading + m_currentTimeout);
}
namespace lightweight
{
void LocalAdsFeaturesReader::ReadCampaignFeaturesFile()
{
m_features.clear();
std::string const featuresFile = GetPath(kCampaignFeaturesFile);
try
{
FileReader reader(featuresFile);
ReaderSource<FileReader> src(reader);
auto const version = features_cache::DeserializeVersion(src);
if (version != features_cache::Version::V0)
return;
std::string countryId;
int64_t mwmVersion;
std::vector<features_cache::PackedCampaignFeature> packedData;
while (src.Size() > 0)
{
features_cache::DeserializeMwmData(src, countryId, mwmVersion);
features_cache::DeserializePackedFeatures(src, packedData);
for (auto const & data : packedData)
{
auto const pos = Int64ToPointObsolete(data.m_mercator, kPointCoordBits);
m_features.push_back(CampaignFeature(mwmVersion, countryId, data.m_featureIndex,
mercator::YToLat(pos.y), mercator::XToLon(pos.x)));
}
}
}
catch (Reader::Exception const & ex)
{
LOG(LWARNING, ("Error reading file:", featuresFile, ex.Msg()));
FileWriter::DeleteFileX(featuresFile);
}
}
std::vector<CampaignFeature> LocalAdsFeaturesReader::GetCampaignFeatures(double lat, double lon, double radiusInMeters,
uint32_t maxCount)
{
if (!m_initialized)
{
ReadCampaignFeaturesFile();
m_initialized = true;
}
if (m_features.empty())
return {};
auto const pt = mercator::FromLatLon(lat, lon);
auto searchRect = mercator::RectByCenterXYAndSizeInMeters(pt, radiusInMeters);
std::multimap<uint32_t, CampaignFeature> sortedFeatures;
for (auto const & f : m_features)
{
auto const pos = mercator::FromLatLon(f.m_lat, f.m_lon);
if (!searchRect.IsPointInside(pos))
continue;
auto const dist = static_cast<uint32_t>(mercator::DistanceOnEarth(pos, pt));
sortedFeatures.insert(std::make_pair(dist, f));
}
std::vector<CampaignFeature> filteredFeatures;
filteredFeatures.reserve(std::min(sortedFeatures.size(), static_cast<size_t>(maxCount)));
for (auto const & pair : sortedFeatures)
{
filteredFeatures.push_back(pair.second);
if (filteredFeatures.size() == maxCount)
break;
}
return filteredFeatures;
}
void Statistics::RegisterEvent(local_ads::Event && event)
{
m_statistics.RegisterEventSync(std::move(event));
}
} // namespace lightweight

View file

@ -1,216 +0,0 @@
#pragma once
#include "map/purchase.hpp"
#include "local_ads/statistics.hpp"
#include "drape_frontend/custom_features_context.hpp"
#include "drape_frontend/drape_engine_safe_ptr.hpp"
#include "drape/pointers.hpp"
#include "geometry/rect2d.hpp"
#include "geometry/screenbase.hpp"
#include "indexer/feature.hpp"
#include "indexer/ftypes_mapping.hpp"
#include "indexer/map_object.hpp"
#include "indexer/mwm_set.hpp"
#include "platform/location.hpp"
#include "base/thread.hpp"
#include <atomic>
#include <chrono>
#include <functional>
#include <map>
#include <mutex>
#include <set>
#include <string>
#include <vector>
namespace feature
{
class TypesHolder;
}
class BookmarkManager;
struct LocalAdsMarkData;
struct CampaignFeature
{
CampaignFeature() = default;
CampaignFeature(int64_t const & mwmVersion, std::string const & countryId, uint32_t featureIndex,
double lat, double lon)
: m_mwmVersion(mwmVersion), m_countryId(countryId), m_featureIndex(featureIndex), m_lat(lat), m_lon(lon) {}
int64_t m_mwmVersion = FeatureID::kInvalidMwmVersion;
std::string m_countryId;
uint32_t m_featureIndex = 0;
double m_lat = 0.0;
double m_lon = 0.0;
};
class LocalAdsManager : public SubscriptionListener
{
public:
using GetMwmsByRectFn = std::function<std::vector<MwmSet::MwmId>(m2::RectD const &)>;
using GetMwmIdByNameFn = std::function<MwmSet::MwmId(std::string const &)>;
using ReadFeatureTypeFn = std::function<void(FeatureType &)>;
using ReadFeaturesFn = std::function<void(ReadFeatureTypeFn const &,
std::vector<FeatureID> const & features)>;
using GetMapObjectByIdFn = std::function<osm::MapObject(FeatureID const &)>;
using OnCampaignFeaturesFn = std::function<void(std::vector<FeatureID> const & features)>;
using Timestamp = local_ads::Timestamp;
LocalAdsManager(GetMwmsByRectFn && getMwmsByRectFn, GetMwmIdByNameFn && getMwmIdByName,
ReadFeaturesFn && readFeaturesFn, GetMapObjectByIdFn && getMapObjectByIdFn);
void Startup(BookmarkManager * bmManager, bool isEnabled);
void SetDrapeEngine(ref_ptr<df::DrapeEngine> engine);
void UpdateViewport(ScreenBase const & screen);
void OnDownloadCountry(std::string const & countryName);
void OnMwmDeregistered(platform::LocalCountryFile const & countryFile);
void Invalidate();
local_ads::Statistics & GetStatistics() { return m_statistics; }
local_ads::Statistics const & GetStatistics() const { return m_statistics; }
bool HasAds(FeatureID const & featureId) const;
bool HasVisualization(FeatureID const & featureId) const;
bool IsSupportedType(feature::TypesHolder const & types) const;
std::string GetCompanyUrl(FeatureID const & featureId) const;
void OnSubscriptionChanged(SubscriptionType type, bool isActive) override;
void OnLocationUpdate(location::GpsInfo const & info, int zoomLevel);
private:
enum class RequestType
{
Download,
Delete
};
using Request = std::pair<MwmSet::MwmId, RequestType>;
struct CacheEntry
{
bool m_isVisibleOnMap = false;
m2::PointD m_position;
};
using FeaturesCache = std::map<FeatureID, CacheEntry>;
void Start();
void InvalidateImpl();
void ProcessRequests(std::set<Request> && campaignMwms);
void ReadCampaignFile(std::string const & campaignFile);
void WriteCampaignFile(std::string const & campaignFile);
void WriteFeaturesFile(std::string const & featuresFile);
using CampaignData = std::map<FeatureID, std::shared_ptr<LocalAdsMarkData>>;
CampaignData ParseCampaign(std::vector<uint8_t> const & rawData, MwmSet::MwmId const & mwmId,
Timestamp timestamp, GetMapObjectByIdFn const & getMapObjectByIdFn) const;
FeaturesCache ReadCampaignFeatures(CampaignData & campaignData) const;
void CreateLocalAdsMarks(CampaignData && campaignData);
void DeleteLocalAdsMarks(MwmSet::MwmId const & mwmId);
void DeleteAllLocalAdsMarks();
void UpdateFeaturesCache(FeaturesCache && features);
void ClearLocalAdsForMwm(MwmSet::MwmId const &mwmId);
void FillSupportedTypes();
// Returned value means if downloading process finished correctly or was interrupted
// by some reason.
bool DownloadCampaign(MwmSet::MwmId const & mwmId, std::vector<uint8_t> & bytes);
void RequestCampaigns(std::vector<MwmSet::MwmId> const & mwmIds);
GetMwmsByRectFn const m_getMwmsByRectFn;
GetMwmIdByNameFn const m_getMwmIdByNameFn;
ReadFeaturesFn const m_readFeaturesFn;
GetMapObjectByIdFn const m_getMapObjectByIdFn;
std::atomic<bool> m_isStarted;
BookmarkManager * m_bmManager;
df::DrapeEngineSafePtr m_drapeEngine;
std::map<std::string, bool> m_campaigns;
struct CampaignInfo
{
Timestamp m_created;
std::vector<uint8_t> m_data;
};
std::map<std::string, CampaignInfo> m_info;
std::mutex m_campaignsMutex;
FeaturesCache m_featuresCache;
mutable std::mutex m_featuresCacheMutex;
ftypes::HashSetMatcher<uint32_t> m_supportedTypes;
struct BackoffStats
{
BackoffStats() = default;
BackoffStats(std::chrono::steady_clock::time_point lastDownloading,
std::chrono::seconds currentTimeout,
uint8_t attemptsCount, bool fileIsAbsent)
: m_lastDownloading(lastDownloading)
, m_currentTimeout(currentTimeout)
, m_attemptsCount(attemptsCount)
, m_fileIsAbsent(fileIsAbsent)
{}
std::chrono::steady_clock::time_point m_lastDownloading = {};
std::chrono::seconds m_currentTimeout = std::chrono::seconds(0);
uint8_t m_attemptsCount = 0;
bool m_fileIsAbsent = false;
bool CanRetry() const;
};
std::map<MwmSet::MwmId, BackoffStats> m_failedDownloads;
std::set<MwmSet::MwmId> m_downloadingMwms;
std::vector<MwmSet::MwmId> m_lastMwms;
local_ads::Statistics m_statistics;
std::atomic<bool> m_isEnabled = false;
m2::PointD m_lastCheckedPos;
std::chrono::steady_clock::time_point m_lastCheckTime;
FeatureID m_lastFoundFeature;
uint32_t m_foundFeatureHitCount = 0;
};
namespace lightweight
{
class LocalAdsFeaturesReader
{
public:
std::vector<CampaignFeature> GetCampaignFeatures(double lat, double lon,
double radiusInMeters, uint32_t maxCount);
private:
void ReadCampaignFeaturesFile();
bool m_initialized = false;
std::vector<CampaignFeature> m_features;
};
class Statistics
{
public:
void RegisterEvent(local_ads::Event && event);
private:
local_ads::Statistics m_statistics;
};
} // namespace lightweight

View file

@ -1,67 +0,0 @@
#include "map/local_ads_mark.hpp"
#include "drape_frontend/color_constants.hpp"
#include <utility>
namespace
{
static std::string const kLocalAdsPrimaryText = "LocalAdsPrimaryText";
static std::string const kLocalAdsPrimaryTextOutline = "LocalAdsPrimaryTextOutline";
static std::string const kLocalAdsSecondaryText = "LocalAdsSecondaryText";
static std::string const kLocalAdsSecondaryTextOutline = "LocalAdsSecondaryTextOutline";
float const kLocalAdsPrimaryTextSize = 11.0f;
float const kLocalAdsSecondaryTextSize = 10.0f;
float const kSecondaryOffsetY = 2.0;
} // namespace
LocalAdsMark::LocalAdsMark(m2::PointD const & ptOrg)
: UserMark(ptOrg, Type::LOCAL_ADS)
{
m_titleDecl.m_anchor = dp::Top;
m_titleDecl.m_primaryTextFont.m_color = df::GetColorConstant(kLocalAdsPrimaryText);
m_titleDecl.m_primaryTextFont.m_outlineColor = df::GetColorConstant(kLocalAdsPrimaryTextOutline);
m_titleDecl.m_primaryTextFont.m_size = kLocalAdsPrimaryTextSize;
m_titleDecl.m_secondaryTextFont.m_color = df::GetColorConstant(kLocalAdsSecondaryText);
m_titleDecl.m_secondaryTextFont.m_outlineColor = df::GetColorConstant(kLocalAdsSecondaryTextOutline);
m_titleDecl.m_secondaryTextFont.m_size = kLocalAdsSecondaryTextSize;
m_titleDecl.m_secondaryOffset = m2::PointF(0, kSecondaryOffsetY);
}
drape_ptr<df::UserPointMark::SymbolNameZoomInfo> LocalAdsMark::GetSymbolNames() const
{
auto symbol = make_unique_dp<SymbolNameZoomInfo>();
symbol->insert(std::make_pair(1 /* zoomLevel */, m_data.m_symbolName));
return symbol;
}
df::DepthLayer LocalAdsMark::GetDepthLayer() const
{
return df::DepthLayer::LocalAdsMarkLayer;
}
drape_ptr<df::UserPointMark::TitlesInfo> LocalAdsMark::GetTitleDecl() const
{
auto titles = make_unique_dp<TitlesInfo>();
titles->push_back(m_titleDecl);
return titles;
}
void LocalAdsMark::SetData(LocalAdsMarkData && data)
{
SetDirty();
m_data = std::move(data);
m_titleDecl.m_primaryText = m_data.m_mainText;
if (!m_titleDecl.m_primaryText.empty())
m_titleDecl.m_secondaryText = m_data.m_auxText;
else
m_titleDecl.m_secondaryText.clear();
}
void LocalAdsMark::SetFeatureId(FeatureID const & id)
{
SetDirty();
m_featureId = id;
}

View file

@ -1,42 +0,0 @@
#pragma once
#include "map/user_mark_layer.hpp"
#include <cstdint>
#include <limits>
#include <string>
struct LocalAdsMarkData
{
m2::PointD m_position = m2::PointD::Zero();
std::string m_symbolName;
uint8_t m_minZoomLevel = 1;
std::string m_mainText;
std::string m_auxText;
uint16_t m_priority = std::numeric_limits<uint16_t>::max();
};
class LocalAdsMark : public UserMark
{
public:
explicit LocalAdsMark(m2::PointD const & ptOrg);
df::DepthLayer GetDepthLayer() const override;
drape_ptr<SymbolNameZoomInfo> GetSymbolNames() const override;
drape_ptr<TitlesInfo> GetTitleDecl() const override;
uint16_t GetPriority() const override { return m_data.m_priority; }
bool SymbolIsPOI() const override { return true; }
bool HasTitlePriority() const override { return true; }
int GetMinZoom() const override { return static_cast<int>(m_data.m_minZoomLevel); }
FeatureID GetFeatureID() const override { return m_featureId; }
void SetData(LocalAdsMarkData && data);
void SetFeatureId(FeatureID const & id);
private:
LocalAdsMarkData m_data;
FeatureID m_featureId;
dp::TitleDecl m_titleDecl;
};

View file

@ -1,96 +0,0 @@
#include "map/local_ads_manager.hpp"
#include <initializer_list>
void LocalAdsManager::FillSupportedTypes()
{
m_supportedTypes.Append<std::initializer_list<std::initializer_list<char const *>>>(
{{"amenity", "atm"},
{"amenity", "bank"},
{"amenity", "bar"},
{"amenity", "bbq"},
{"amenity", "bicycle_parking"},
{"amenity", "bicycle_rental"},
{"amenity", "brothel"},
{"amenity", "bureau_de_change"},
{"amenity", "cafe"},
{"amenity", "car_rental"},
{"amenity", "car_sharing"},
{"amenity", "car_wash"},
{"amenity", "casino"},
{"amenity", "charging_station"},
{"amenity", "childcare"},
{"amenity", "cinema"},
{"amenity", "clinic"},
{"amenity", "college"},
{"amenity", "community_centre"},
{"amenity", "courthouse"},
{"amenity", "dentist"},
{"amenity", "doctors"},
{"amenity", "fast_food"},
{"amenity", "fuel"},
{"amenity", "grave_yard"},
{"amenity", "hospital"},
{"amenity", "hunting_stand"},
{"amenity", "kindergarten"},
{"amenity", "library"},
{"amenity", "marketplace"},
{"amenity", "nightclub"},
{"amenity", "parking"},
{"amenity", "pharmacy"},
{"amenity", "post_office"},
{"amenity", "pub"},
{"amenity", "public_bookcase"},
{"amenity", "recycling"},
{"amenity", "restaurant"},
{"amenity", "school"},
{"amenity", "shelter"},
{"amenity", "taxi"},
{"amenity", "telephone"},
{"amenity", "theatre"},
{"amenity", "toilets"},
{"amenity", "townhall"},
{"amenity", "university"},
{"amenity", "vending_machine"},
{"amenity", "veterinary"},
{"amenity", "waste_disposal"},
{"craft"},
{"historic", "castle"},
{"historic", "museum"},
{"historic", "ship"},
{"leisure", "fitness_centre"},
{"leisure", "sauna"},
{"leisure", "sports_centre"},
{"man_made", "lighthouse"},
{"office"},
{"shop"},
{"sponsored", "booking"},
{"sport"},
{"tourism", "alpine_hut"},
{"tourism", "apartment"},
{"tourism", "artwork"},
{"tourism", "attraction"},
{"tourism", "camp_site"},
{"tourism", "caravan_site"},
{"tourism", "chalet"},
{"tourism", "gallery"},
{"tourism", "guest_house"},
{"tourism", "hostel"},
{"tourism", "hotel"},
{"tourism", "information", "office"},
{"tourism", "motel"},
{"tourism", "museum"},
{"tourism", "picnic_site"},
{"tourism", "resort"},
{"tourism", "viewpoint"},
{"tourism", "zoo"}});
}

View file

@ -57,7 +57,6 @@ omim_link_libraries(
ugc
partners_api
web_api
local_ads
kml
editor
indexer

View file

@ -34,7 +34,7 @@ namespace
{
using Runner = Platform::ThreadRunner;
static FrameworkParams const kFrameworkParams(false /* m_enableLocalAds */, false /* m_enableDiffs */);
static FrameworkParams const kFrameworkParams(false /* m_enableDiffs */);
char const * kmlString =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"

View file

@ -30,7 +30,7 @@ using namespace std;
UNIT_TEST(CountriesNamesTest)
{
Framework f(FrameworkParams(false /* m_enableLocalAds */, false /* m_enableDiffs */));
Framework f(FrameworkParams(false /* m_enableDiffs */));
auto & storage = f.GetStorage();
auto const & synonyms = storage.GetCountryNameSynonyms();

View file

@ -18,7 +18,7 @@ using namespace std;
UNIT_TEST(Framework_ForEachFeatureAtPoint_And_Others)
{
Framework frm(FrameworkParams(false /* m_enableLocalAds */, false /* m_enableDiffs */));
Framework frm(FrameworkParams(false /* m_enableDiffs */));
frm.DeregisterAllMaps();
frm.RegisterMap(platform::LocalCountryFile::MakeForTesting("minsk-pass"));

View file

@ -26,15 +26,6 @@ struct LightFrameworkTest
TEST_EQUAL(f.GetNumberOfUnsentUGC(), 0, ());
TEST(!f.IsUserAuthenticated(), ());
}
{
Framework f(REQUEST_TYPE_LOCAL_ADS_FEATURES | REQUEST_TYPE_LOCAL_ADS_STATISTICS);
auto const features = f.GetLocalAdsFeatures(0.0 /* lat */, 0.0 /* lon */,
100 /* radiusInMeters */, 0 /* maxCount */);
auto stats = f.GetLocalAdsStatistics();
TEST(stats != nullptr, ());
TEST_EQUAL(features.size(), 0, ());
}
}
};
} // namespace lightweight

View file

@ -26,7 +26,7 @@ using namespace url_scheme;
namespace
{
using UrlType = ParsedMapApi::UrlType;
static FrameworkParams const kFrameworkParams(false /* m_enableLocalAds */, false /* m_enableDiffs */);
static FrameworkParams const kFrameworkParams(false /* m_enableDiffs */);
void ToMercatoToLatLon(double & lat, double & lon)
{

View file

@ -273,10 +273,8 @@ UNIT_TEST(PowerManager_OnBatteryLevelChanged)
TEST_EQUAL(subscriber.m_onFacilityEvents[3].m_state, false, ());
TEST_EQUAL(subscriber.m_onFacilityEvents[4].m_facility, Facility::UgcUploading, ());
TEST_EQUAL(subscriber.m_onFacilityEvents[4].m_state, false, ());
TEST_EQUAL(subscriber.m_onFacilityEvents[5].m_facility, Facility::LocalAdsDataDownloading, ());
TEST_EQUAL(subscriber.m_onFacilityEvents[5].m_facility, Facility::AdsDownloading, ());
TEST_EQUAL(subscriber.m_onFacilityEvents[5].m_state, false, ());
TEST_EQUAL(subscriber.m_onFacilityEvents[6].m_facility, Facility::AdsDownloading, ());
TEST_EQUAL(subscriber.m_onFacilityEvents[6].m_state, false, ());
subscriber.m_onShemeEvents.clear();
subscriber.m_onFacilityEvents.clear();

View file

@ -53,14 +53,6 @@ enum class SponsoredType
PromoCatalogOutdoor,
};
enum class LocalAdsStatus
{
NotAvailable,
Candidate,
Customer,
Hidden
};
enum class LocalsStatus
{
NotAvailable,
@ -274,13 +266,6 @@ public:
void SetLocalsPageUrl(std::string const & url) { m_localsUrl = url; }
std::string const & GetLocalsPageUrl() const { return m_localsUrl; }
/// Local ads
void SetLocalAdsStatus(LocalAdsStatus status) { m_localAdsStatus = status; }
LocalAdsStatus GetLocalAdsStatus() const { return m_localAdsStatus; }
void SetLocalAdsUrl(std::string const & url) { m_localAdsUrl = url; }
std::string const & GetLocalAdsUrl() const { return m_localAdsUrl; }
void SetAdsEngine(ads::Engine * const engine) { m_adsEngine = engine; }
/// Routing
void SetRouteMarkType(RouteMarkType type) { m_routeMarkType = type; }
RouteMarkType GetRouteMarkType() const { return m_routeMarkType; }
@ -393,8 +378,6 @@ private:
/// Ads
std::vector<taxi::Provider::Type> m_reachableByProviders;
std::string m_localAdsUrl;
LocalAdsStatus m_localAdsStatus = LocalAdsStatus::NotAvailable;
/// Ads source.
ads::Engine * m_adsEngine = nullptr;
/// Sponsored type or None.

View file

@ -15,7 +15,7 @@ std::unordered_map<Scheme, FacilitiesState> const kSchemeToState =
{{
/* Buildings3d */ true, /* PerspectiveView */ true, /* TrackRecording */ true,
/* TrafficJams */ true, /* GpsTrackingForTraffic */ true, /* OsmEditsUploading */ true,
/* UgcUploading */ true, /* BookmarkCloudUploading */ true, /* LocalAdsDataDownloading */ true,
/* UgcUploading */ true, /* BookmarkCloudUploading */ true,
/* MapDownloader */ true, /* StatisticsUploading */ true, /* AdsDownloading */ true
}}
},
@ -24,7 +24,7 @@ std::unordered_map<Scheme, FacilitiesState> const kSchemeToState =
{{
/* Buildings3d */ true, /* PerspectiveView */ false, /* TrackRecording */ true,
/* TrafficJams */ true, /* GpsTrackingForTraffic */ true, /* OsmEditsUploading */ true,
/* UgcUploading */ true, /* BookmarkCloudUploading */ false, /* LocalAdsDataDownloading */ true,
/* UgcUploading */ true, /* BookmarkCloudUploading */ false,
/* MapDownloader */ true, /* StatisticsUploading */ true, /* AdsDownloading */ true
}}
},
@ -33,7 +33,7 @@ std::unordered_map<Scheme, FacilitiesState> const kSchemeToState =
{{
/* Buildings3d */ false, /* PerspectiveView */ false, /* TrackRecording */ false,
/* TrafficJams */ false, /* GpsTrackingForTraffic */ false, /* OsmEditsUploading */ false,
/* UgcUploading */ false, /* BookmarkCloudUploading */ false, /* LocalAdsDataDownloading */ true,
/* UgcUploading */ false, /* BookmarkCloudUploading */ false,
/* MapDownloader */ true, /* StatisticsUploading */ true, /* AdsDownloading */ true
}}
},
@ -46,7 +46,7 @@ std::unordered_map<AutoScheme, FacilitiesState> const kAutoSchemeToState =
{{
/* Buildings3d */ true, /* PerspectiveView */ true, /* TrackRecording */ true,
/* TrafficJams */ true, /* GpsTrackingForTraffic */ true, /* OsmEditsUploading */ true,
/* UgcUploading */ true, /* BookmarkCloudUploading */ true, /* LocalAdsDataDownloading */ true,
/* UgcUploading */ true, /* BookmarkCloudUploading */ true,
/* MapDownloader */ true, /* StatisticsUploading */ true, /* AdsDownloading */ true
}}
},
@ -55,7 +55,7 @@ std::unordered_map<AutoScheme, FacilitiesState> const kAutoSchemeToState =
{{
/* Buildings3d */ true, /* PerspectiveView */ false, /* TrackRecording */ true,
/* TrafficJams */ true, /* GpsTrackingForTraffic */ false, /* OsmEditsUploading */ true,
/* UgcUploading */ true, /* BookmarkCloudUploading */ false, /* LocalAdsDataDownloading */ true,
/* UgcUploading */ true, /* BookmarkCloudUploading */ false,
/* MapDownloader */ false, /* StatisticsUploading */ false, /* AdsDownloading */ true
}}
},
@ -64,7 +64,7 @@ std::unordered_map<AutoScheme, FacilitiesState> const kAutoSchemeToState =
{{
/* Buildings3d */ false, /* PerspectiveView */ false, /* TrackRecording */ false,
/* TrafficJams */ false, /* GpsTrackingForTraffic */ false, /* OsmEditsUploading */ false,
/* UgcUploading */ false, /* BookmarkCloudUploading */ false, /* LocalAdsDataDownloading */ false,
/* UgcUploading */ false, /* BookmarkCloudUploading */ false,
/* MapDownloader */ false, /* StatisticsUploading */ false, /* AdsDownloading */ false
}}
},
@ -98,7 +98,6 @@ std::string DebugPrint(Facility const facility)
case Facility::OsmEditsUploading: return "OsmEditsUploading";
case Facility::UgcUploading: return "UgcUploading";
case Facility::BookmarkCloudUploading: return "BookmarkCloudUploading";
case Facility::LocalAdsDataDownloading: return "LocalAdsDataDownloading";
case Facility::MapDownloader: return "MapDownloader";
case Facility::StatisticsUploading: return "StatisticsUploading";
case Facility::AdsDownloading: return "AdsDownloading";

View file

@ -18,7 +18,6 @@ enum class Facility : uint8_t
OsmEditsUploading,
UgcUploading,
BookmarkCloudUploading,
LocalAdsDataDownloading,
MapDownloader,
StatisticsUploading,
AdsDownloading,

View file

@ -82,7 +82,6 @@ std::string const kPriceChipDiscount = "price-chips-discount";
std::string const kPriceChipSelectedDiscount = "price-chips-selected-discount";
std::string const kRatedDefaultSearchIcon = "rated-default-search-result";
std::string const kRatedDefaultSearchIconAds = "local_ads_rated-default-search-result";
std::string const kBookingNoRatingSearchIcon = "norating-default-l";
std::string const & kOsmHotelSearchIcon = kBookingNoRatingSearchIcon;
@ -136,30 +135,23 @@ int constexpr kUGCBadgeMinZoomLevel = scales::GetUpperCountryScale();
int constexpr kGoodRatingZoomLevel = kWorldZoomLevel;
int constexpr kBadRatingZoomLevel = scales::GetUpperComfortScale();
std::string GetSymbol(SearchMarkType searchMarkType, bool hasLocalAds, bool hasRating)
std::string GetSymbol(SearchMarkType searchMarkType, bool hasRating)
{
if (searchMarkType == SearchMarkType::Default && hasRating)
return hasLocalAds ? kRatedDefaultSearchIconAds : kRatedDefaultSearchIcon;
return kRatedDefaultSearchIcon;
if (searchMarkType == SearchMarkType::Booking && !hasRating)
return kBookingNoRatingSearchIcon;
if (searchMarkType == SearchMarkType::Hotel && !hasLocalAds)
if (searchMarkType == SearchMarkType::Hotel)
return kOsmHotelSearchIcon;
auto const index = static_cast<size_t>(searchMarkType);
ASSERT_LESS(index, kSymbols.size(), ());
if (hasLocalAds)
return "local_ads_" + kSymbols[index];
return kSymbols[index];
}
bool HasLocalAdsVariant(SearchMarkType searchMarkType)
{
return searchMarkType != SearchMarkType::NotFound;
}
class SearchMarkTypeChecker
{
public:
@ -394,8 +386,6 @@ df::ColorConstant SearchMarkPoint::GetColorConstant() const
return m_isSelected ? "SearchmarkSelectedNotAvailable" : "SearchmarkNotAvailable";
if (m_isPreparing)
return "SearchmarkPreparing";
if (m_hasLocalAds)
return "RatingGood";
if (!HasRating())
return "RatingNone";
if (!HasGoodRating())
@ -526,27 +516,23 @@ void SearchMarkPoint::SetMatchedName(std::string const & name)
SetAttributeValue(m_matchedName, name);
}
void SearchMarkPoint::SetFromType(uint32_t type, bool hasLocalAds)
void SearchMarkPoint::SetFromType(uint32_t type)
{
SetAttributeValue(m_hasLocalAds, hasLocalAds);
SetAttributeValue(m_type, GetSearchMarkType(type));
}
void SearchMarkPoint::SetBookingType(bool hasLocalAds)
void SearchMarkPoint::SetBookingType()
{
SetAttributeValue(m_hasLocalAds, hasLocalAds);
SetAttributeValue(m_type, SearchMarkType::Booking);
}
void SearchMarkPoint::SetHotelType(bool hasLocalAds)
void SearchMarkPoint::SetHotelType()
{
SetAttributeValue(m_hasLocalAds, hasLocalAds);
SetAttributeValue(m_type, SearchMarkType::Hotel);
}
void SearchMarkPoint::SetNotFoundType()
{
SetAttributeValue(m_hasLocalAds, false);
SetAttributeValue(m_type, SearchMarkType::NotFound);
}
@ -624,7 +610,7 @@ std::string SearchMarkPoint::GetSymbolName() const
if (m_type >= SearchMarkType::Count)
{
ASSERT(false, ("Unknown search mark symbol."));
symbolName = GetSymbol(SearchMarkType::Default, false /* hasLocalAds */, HasRating());
symbolName = GetSymbol(SearchMarkType::Default, HasRating());
}
else
{
@ -635,11 +621,11 @@ std::string SearchMarkPoint::GetSymbolName() const
else if (m_isPreparing)
symbolName = kColoredmarkSmall;
else
symbolName = GetSymbol(m_type, m_hasLocalAds, HasRating());
symbolName = GetSymbol(m_type, HasRating());
}
else
{
symbolName = GetSymbol(m_type, m_hasLocalAds, HasRating());
symbolName = GetSymbol(m_type, HasRating());
}
}
@ -705,13 +691,8 @@ void SearchMarks::SetDrapeEngine(ref_ptr<df::DrapeEngine> engine)
for (uint32_t t = 0; t < searchMarkTypesCount; ++t)
{
auto const searchMarkType = static_cast<SearchMarkType>(t);
symbols.push_back(GetSymbol(searchMarkType, false /* hasLocalAds */, false /* isRated */));
symbols.push_back(GetSymbol(searchMarkType, false /* hasLocalAds */, true /* isRated */));
if (HasLocalAdsVariant(searchMarkType))
{
symbols.push_back(GetSymbol(searchMarkType, true /* hasLocalAds */, false /* isRated */));
symbols.push_back(GetSymbol(searchMarkType, true /* hasLocalAds */, true /* isRated */));
}
symbols.push_back(GetSymbol(searchMarkType, false /* isRated */));
symbols.push_back(GetSymbol(searchMarkType, true /* isRated */));
}
symbols.push_back(kColoredmarkSmall);
@ -725,7 +706,6 @@ void SearchMarks::SetDrapeEngine(ref_ptr<df::DrapeEngine> engine)
symbols.push_back(kPriceChipSelectedDiscount);
symbols.push_back(kRatedDefaultSearchIcon);
symbols.push_back(kRatedDefaultSearchIconAds);
symbols.push_back(kBookingNoRatingSearchIcon);

View file

@ -50,9 +50,9 @@ public:
std::string const & GetMatchedName() const { return m_matchedName; }
void SetMatchedName(std::string const & name);
void SetFromType(uint32_t type, bool hasLocalAds);
void SetBookingType(bool hasLocalAds);
void SetHotelType(bool hasLocalAds);
void SetFromType(uint32_t type);
void SetBookingType();
void SetHotelType();
void SetNotFoundType();
void SetPreparing(bool isPreparing);
@ -93,7 +93,6 @@ protected:
std::string GetBadgeName() const;
SearchMarkType m_type{};
bool m_hasLocalAds = false;
FeatureID m_featureID;
// Used to pass exact search result matched string into a place page.
std::string m_matchedName;

View file

@ -16,7 +16,6 @@ struct ProductInfo
static auto constexpr kInvalidRating = kInvalidRatingValue;
bool m_isLocalAdsCustomer = false;
float m_ugcRating = kInvalidRating;
};
}

View file

@ -105,7 +105,6 @@ std::string DebugPrint(UserMark::Type type)
case UserMark::Type::ROUTING: return "ROUTING";
case UserMark::Type::ROAD_WARNING: return "ROAD_WARNING";
case UserMark::Type::SPEED_CAM: return "SPEED_CAM";
case UserMark::Type::LOCAL_ADS: return "LOCAL_ADS";
case UserMark::Type::TRANSIT: return "TRANSIT";
case UserMark::Type::TRACK_INFO: return "TRACK_INFO";
case UserMark::Type::TRACK_SELECTION: return "TRACK_SELECTION";

Some files were not shown because too many files have changed in this diff Show more