Implement location sending on macOS.
This commit is contained in:
parent
2a5071b66c
commit
025ab40687
8 changed files with 155 additions and 18 deletions
|
@ -37,17 +37,21 @@ var LocationPicker = {
|
||||||
document.getElementsByTagName('html')[0].style = styles;
|
document.getElementsByTagName('html')[0].style = styles;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
init: function (token, center, bounds) {
|
init: function (params) {
|
||||||
mapboxgl.accessToken = token;
|
mapboxgl.accessToken = params.token;
|
||||||
|
if (params.protocol) {
|
||||||
|
mapboxgl.config.API_URL = params.protocol + '://domain/api.mapbox.com';
|
||||||
|
}
|
||||||
|
|
||||||
var options = { container: 'map' };
|
var options = { container: 'map' };
|
||||||
|
var center = params.center;
|
||||||
if (center) {
|
if (center) {
|
||||||
center = [center[1], center[0]];
|
center = [center[1], center[0]];
|
||||||
options.center = center;
|
options.center = center;
|
||||||
options.zoom = LocationPicker.startZoom;
|
options.zoom = LocationPicker.startZoom;
|
||||||
} else if (bounds) {
|
} else if (params.bounds) {
|
||||||
options.bounds = bounds;
|
options.bounds = params.bounds;
|
||||||
center = new mapboxgl.LngLatBounds(bounds).getCenter();
|
center = new mapboxgl.LngLatBounds(params.bounds).getCenter();
|
||||||
} else {
|
} else {
|
||||||
center = [0, 0];
|
center = [0, 0];
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ GeoLocation ResolveCurrentCountryLocation() {
|
||||||
void ResolveCurrentGeoLocation(Fn<void(GeoLocation)> callback) {
|
void ResolveCurrentGeoLocation(Fn<void(GeoLocation)> callback) {
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
return ResolveCurrentExactLocation([done = std::move(callback)](
|
return ResolveCurrentExactLocation([done = std::move(callback)](
|
||||||
GeoLocation result) {
|
GeoLocation result) {
|
||||||
done(result.accuracy != GeoLocationAccuracy::Failed
|
done(result.accuracy != GeoLocationAccuracy::Failed
|
||||||
? result
|
? result
|
||||||
: ResolveCurrentCountryLocation());
|
: ResolveCurrentCountryLocation());
|
||||||
|
|
|
@ -9,10 +9,111 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "core/current_geo_location.h"
|
#include "core/current_geo_location.h"
|
||||||
|
|
||||||
|
#include <CoreLocation/CoreLocation.h>
|
||||||
|
|
||||||
|
@interface LocationDelegate : NSObject<CLLocationManagerDelegate>
|
||||||
|
|
||||||
|
- (id) initWithCallback:(Fn<void(Core::GeoLocation)>)callback;
|
||||||
|
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations;
|
||||||
|
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error;
|
||||||
|
- (void) locationManager:(CLLocationManager *) manager didChangeAuthorizationStatus:(CLAuthorizationStatus) status;
|
||||||
|
- (void) dealloc;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation LocationDelegate {
|
||||||
|
CLLocationManager *_manager;
|
||||||
|
Fn<void(Core::GeoLocation)> _callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) fail {
|
||||||
|
[_manager stopUpdatingLocation];
|
||||||
|
|
||||||
|
const auto onstack = _callback;
|
||||||
|
[self release];
|
||||||
|
|
||||||
|
onstack({});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) processWithStatus:(CLAuthorizationStatus)status {
|
||||||
|
switch (status) {
|
||||||
|
case kCLAuthorizationStatusNotDetermined:
|
||||||
|
if (@available(macOS 10.15, *)) {
|
||||||
|
[_manager requestWhenInUseAuthorization];
|
||||||
|
} else {
|
||||||
|
[_manager startUpdatingLocation];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kCLAuthorizationStatusAuthorizedAlways:
|
||||||
|
[_manager startUpdatingLocation];
|
||||||
|
return;
|
||||||
|
case kCLAuthorizationStatusRestricted:
|
||||||
|
case kCLAuthorizationStatusDenied:
|
||||||
|
default:
|
||||||
|
[self fail];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithCallback:(Fn<void(Core::GeoLocation)>)callback {
|
||||||
|
if (self = [super init]) {
|
||||||
|
_callback = std::move(callback);
|
||||||
|
_manager = [[CLLocationManager alloc] init];
|
||||||
|
_manager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
|
||||||
|
_manager.delegate = self;
|
||||||
|
if ([CLLocationManager locationServicesEnabled]) {
|
||||||
|
if (@available(macOS 11, *)) {
|
||||||
|
[self processWithStatus:[_manager authorizationStatus]];
|
||||||
|
} else {
|
||||||
|
[self processWithStatus:[CLLocationManager authorizationStatus]];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[self fail];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation*>*)locations {
|
||||||
|
[_manager stopUpdatingLocation];
|
||||||
|
|
||||||
|
auto result = Core::GeoLocation();
|
||||||
|
if ([locations count] > 0) {
|
||||||
|
const auto coordinate = [locations lastObject].coordinate;
|
||||||
|
result.accuracy = Core::GeoLocationAccuracy::Exact;
|
||||||
|
result.point = QPointF(coordinate.latitude, coordinate.longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto onstack = _callback;
|
||||||
|
[self release];
|
||||||
|
|
||||||
|
onstack(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
|
||||||
|
if (error.code != kCLErrorLocationUnknown) {
|
||||||
|
[self fail];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) locationManager:(CLLocationManager *) manager didChangeAuthorizationStatus:(CLAuthorizationStatus) status {
|
||||||
|
[self processWithStatus:status];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
if (_manager) {
|
||||||
|
_manager.delegate = nil;
|
||||||
|
[_manager release];
|
||||||
|
}
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback) {
|
void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback) {
|
||||||
callback({});
|
[[LocationDelegate alloc] initWithCallback:std::move(callback)];
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
|
@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "styles/style_window.h"
|
#include "styles/style_window.h"
|
||||||
|
|
||||||
|
#include <QtCore/QFile>
|
||||||
#include <QtCore/QJsonDocument>
|
#include <QtCore/QJsonDocument>
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
#include <QtCore/QJsonValue>
|
#include <QtCore/QJsonValue>
|
||||||
|
@ -27,6 +28,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
const auto kProtocolOverride = "mapboxapihelper";
|
||||||
|
#else // Q_OS_MAC
|
||||||
|
const auto kProtocolOverride = "";
|
||||||
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
Core::GeoLocation LastExactLocation;
|
Core::GeoLocation LastExactLocation;
|
||||||
QString MapsProviderToken;
|
QString MapsProviderToken;
|
||||||
|
|
||||||
|
@ -35,9 +42,9 @@ QString MapsProviderToken;
|
||||||
return "null";
|
return "null";
|
||||||
}
|
}
|
||||||
return "["_q
|
return "["_q
|
||||||
+ QByteArray::number(LastExactLocation.point.x() - 1)
|
+ QByteArray::number(LastExactLocation.point.x())
|
||||||
+ ","_q
|
+ ","_q
|
||||||
+ QByteArray::number(LastExactLocation.point.y() - 1)
|
+ QByteArray::number(LastExactLocation.point.y())
|
||||||
+ "]"_q;
|
+ "]"_q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +196,7 @@ void LocationPicker::setupWebview(const Descriptor &descriptor) {
|
||||||
Webview::WindowConfig{
|
Webview::WindowConfig{
|
||||||
.opaqueBg = st::windowBg->c,
|
.opaqueBg = st::windowBg->c,
|
||||||
.storageId = descriptor.storageId,
|
.storageId = descriptor.storageId,
|
||||||
|
.dataProtocolOverride = kProtocolOverride,
|
||||||
});
|
});
|
||||||
const auto raw = _webview.get();
|
const auto raw = _webview.get();
|
||||||
|
|
||||||
|
@ -293,18 +301,25 @@ void LocationPicker::initMap() {
|
||||||
const auto token = MapsProviderToken.toUtf8();
|
const auto token = MapsProviderToken.toUtf8();
|
||||||
const auto center = DefaultCenter();
|
const auto center = DefaultCenter();
|
||||||
const auto bounds = DefaultBounds();
|
const auto bounds = DefaultBounds();
|
||||||
const auto arguments = "'" + token + "', " + center + ", " + bounds;
|
const auto protocol = *kProtocolOverride
|
||||||
_webview->eval("LocationPicker.init(" + arguments + ");");
|
? "'"_q + kProtocolOverride + "'"
|
||||||
|
: "null";
|
||||||
|
const auto params = "token: '" + token + "'"
|
||||||
|
+ ", center: " + center
|
||||||
|
+ ", bounds: " + bounds
|
||||||
|
+ ", protocol: " + protocol;
|
||||||
|
_webview->eval("LocationPicker.init({ " + params + " });");
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocationPicker::resolveCurrentLocation() {
|
void LocationPicker::resolveCurrentLocation() {
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
const auto window = _window.get();
|
const auto window = _window.get();
|
||||||
ResolveCurrentGeoLocation(crl::guard(window, [=](GeoLocation location) {
|
ResolveCurrentGeoLocation(crl::guard(window, [=](GeoLocation location) {
|
||||||
if (location) {
|
if (location.accuracy != GeoLocationAccuracy::Exact) {
|
||||||
LastExactLocation = location;
|
return;
|
||||||
}
|
}
|
||||||
if (_webview && location.accuracy == GeoLocationAccuracy::Exact) {
|
LastExactLocation = location;
|
||||||
|
if (_webview) {
|
||||||
const auto point = QByteArray::number(location.point.x())
|
const auto point = QByteArray::number(location.point.x())
|
||||||
+ ","_q
|
+ ","_q
|
||||||
+ QByteArray::number(location.point.y());
|
+ QByteArray::number(location.point.y());
|
||||||
|
@ -327,7 +342,10 @@ void LocationPicker::processKey(
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocationPicker::close() {
|
void LocationPicker::close() {
|
||||||
_window->close();
|
crl::on_main(this, [=] {
|
||||||
|
_window = nullptr;
|
||||||
|
delete this;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocationPicker::minimize() {
|
void LocationPicker::minimize() {
|
||||||
|
|
|
@ -12,12 +12,20 @@
|
||||||
<string>Icon.icns</string>
|
<string>Icon.icns</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>@bundle_identifier_plist@</string>
|
<string>@bundle_identifier_plist@</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>@output_name@</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>@desktop_app_version_string@</string>
|
<string>@desktop_app_version_string@</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -39,16 +47,18 @@
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.social-networking</string>
|
<string>public.app-category.social-networking</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>@CMAKE_OSX_DEPLOYMENT_TARGET@</string>
|
|
||||||
<key>LSFileQuarantineEnabled</key>
|
<key>LSFileQuarantineEnabled</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>@CMAKE_OSX_DEPLOYMENT_TARGET@</string>
|
||||||
<key>NOTE</key>
|
<key>NOTE</key>
|
||||||
<string></string>
|
<string></string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>We need access to your microphone so that you can record voice messages and make calls.</string>
|
<string>We need access to your microphone so that you can record voice messages and make calls.</string>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>We need access to your camera so that you can record video messages and make video calls.</string>
|
<string>We need access to your camera so that you can record video messages and make video calls.</string>
|
||||||
|
<key>NSLocationUsageDescription</key>
|
||||||
|
<string>We need access to your location so that you can send your current locations.</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||||
|
|
|
@ -18,5 +18,7 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.device.camera</key>
|
<key>com.apple.security.device.camera</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.personal-information.location</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -6,5 +6,7 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.device.camera</key>
|
<key>com.apple.security.device.camera</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.personal-information.location</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
2
cmake
2
cmake
|
@ -1 +1 @@
|
||||||
Subproject commit 4a4bc4cd34b3ade038541a2b8b2c79f05393d67b
|
Subproject commit 78b441c9c6ad8a14a8f97a28825babcadc6bf781
|
Loading…
Reference in a new issue