Implement location sending on macOS.

This commit is contained in:
John Preston 2024-07-05 21:25:25 +04:00
parent 2a5071b66c
commit 025ab40687
8 changed files with 155 additions and 18 deletions

View file

@ -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];
} }

View file

@ -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());

View file

@ -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

View file

@ -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() {

View file

@ -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>

View file

@ -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>

View file

@ -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

@ -1 +1 @@
Subproject commit 4a4bc4cd34b3ade038541a2b8b2c79f05393d67b Subproject commit 78b441c9c6ad8a14a8f97a28825babcadc6bf781