Initial location sending on Windows.

This commit is contained in:
John Preston 2024-07-04 12:18:30 +04:00
parent 2a63496054
commit 2a5071b66c
23 changed files with 1195 additions and 4 deletions

View file

@ -1614,6 +1614,7 @@ PRIVATE
qrc/telegram/animations.qrc
qrc/telegram/export.qrc
qrc/telegram/iv.qrc
qrc/telegram/picker.qrc
qrc/telegram/telegram.qrc
qrc/telegram/sounds.qrc
winrc/Telegram.rc

View file

@ -3194,6 +3194,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_unread_bar_some" = "Unread messages";
"lng_maps_point" = "Location";
"lng_maps_point_send" = "Send This Location";
"lng_live_location" = "Live Location";
"lng_live_location_now" = "updated just now";
"lng_live_location_minutes#one" = "updated {count} minute ago";

View file

@ -0,0 +1,60 @@
:root {
--font-sans: -apple-system, BlinkMacSystemFont, avenir next, avenir, Segoe UI Variable Text, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, tahoma, arial, sans-serif;
--font-serif: Iowan Old Style, Apple Garamond, Baskerville, Georgia, Times New Roman, Droid Serif, Times, Source Serif Pro, serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
--font-mono: Menlo, Cascadia Code, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
}
html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
body {
font-family: var(--font-sans);
font-size: 17px;
line-height: 25px;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
background-color: var(--td-window-bg);
color: var(--td-window-fg);
}
html.custom_scroll ::-webkit-scrollbar {
border-radius: 5px !important;
border: 3px solid transparent !important;
background-color: var(--td-scroll-bg) !important;
background-clip: content-box !important;
width: 10px !important;
}
html.custom_scroll ::-webkit-scrollbar:hover {
background-color: var(--td-scroll-bg-over) !important;
}
html.custom_scroll ::-webkit-scrollbar-thumb {
border-radius: 5px !important;
border: 3px solid transparent !important;
background-color: var(--td-scroll-bar-bg) !important;
background-clip: content-box !important;
}
html.custom_scroll ::-webkit-scrollbar-thumb:hover {
background-color: var(--td-scroll-bar-bg-over) !important;
}
#map {
position: relative;
width: 100%;
height: 100%;
}
#marker {
pointer-events: none;
display: flex;
z-index: 2;
position: absolute;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
}

View file

@ -0,0 +1,80 @@
var LocationPicker = {
startZoom: 14,
flySpeed: 2.4,
notify: function(message) {
if (window.external && window.external.invoke) {
window.external.invoke(JSON.stringify(message));
}
},
frameKeyDown: function (e) {
const keyW = (e.key === 'w')
|| (e.code === 'KeyW')
|| (e.keyCode === 87);
const keyQ = (e.key === 'q')
|| (e.code === 'KeyQ')
|| (e.keyCode === 81);
const keyM = (e.key === 'm')
|| (e.code === 'KeyM')
|| (e.keyCode === 77);
if ((e.metaKey || e.ctrlKey) && (keyW || keyQ || keyM)) {
e.preventDefault();
LocationPicker.notify({
event: 'keydown',
modifier: e.ctrlKey ? 'ctrl' : 'cmd',
key: keyW ? 'w' : keyQ ? 'q' : 'm',
});
} else if (e.key === 'Escape' || e.keyCode === 27) {
e.preventDefault();
LocationPicker.notify({
event: 'keydown',
key: 'escape',
});
}
},
updateStyles: function (styles) {
if (LocationPicker.styles !== styles) {
LocationPicker.styles = styles;
document.getElementsByTagName('html')[0].style = styles;
}
},
init: function (token, center, bounds) {
mapboxgl.accessToken = token;
var options = { container: 'map' };
if (center) {
center = [center[1], center[0]];
options.center = center;
options.zoom = LocationPicker.startZoom;
} else if (bounds) {
options.bounds = bounds;
center = new mapboxgl.LngLatBounds(bounds).getCenter();
} else {
center = [0, 0];
}
LocationPicker.map = new mapboxgl.Map(options);
const marker = new mapboxgl.Marker()
.setLngLat(center)
.addTo(LocationPicker.map);
const drop = document.getElementById('marker_drop');
const element = marker.getElement();
drop.innerHTML = element.innerHTML;
const offset = marker.getOffset();
drop.style.transform = 'translate(' + offset.x + 'px, ' + offset.y + 'px)';
marker.remove();
},
narrowTo: function (point) {
LocationPicker.map.flyTo({
center: [point[1], point[0]],
zoom: LocationPicker.startZoom,
speed: LocationPicker.flySpeed,
});
},
send: function () {
LocationPicker.notify({
event: 'send',
latitude: LocationPicker.map.getCenter().lat,
longitude: LocationPicker.map.getCenter().lng
});
}
};

View file

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/picker">
<file alias="picker.css">../../picker_html/picker.css</file>
<file alias="picker.js">../../picker_html/picker.js</file>
</qresource>
</RCC>

View file

@ -62,6 +62,85 @@ void InnerFillMessagePostFlags(
}
}
void SendSimpleMedia(SendAction action, MTPInputMedia inputMedia) {
const auto history = action.history;
const auto peer = history->peer;
const auto session = &history->session();
const auto api = &session->api();
action.clearDraft = false;
action.generateLocal = false;
api->sendAction(action);
const auto randomId = base::RandomValue<uint64>();
auto flags = NewMessageFlags(peer);
auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (action.replyTo) {
flags |= MessageFlag::HasReplyInfo;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
}
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, action.options);
InnerFillMessagePostFlags(action.options, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
const auto sendAs = action.options.sendAs;
const auto messageFromId = sendAs
? sendAs->id
: anonymousPost
? 0
: session->userPeerId();
if (sendAs) {
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
}
const auto messagePostAuthor = peer->isBroadcast()
? session->user()->name()
: QString();
if (action.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled;
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
}
if (action.options.effectId) {
sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
}
if (action.options.invertCaption) {
flags |= MessageFlag::InvertMedia;
sendFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
}
auto &histories = history->owner().histories();
histories.sendPreparedMessage(
history,
action.replyTo,
randomId,
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
MTP_flags(sendFlags),
peer->input,
Data::Histories::ReplyToPlaceholder(),
std::move(inputMedia),
MTPstring(),
MTP_long(randomId),
MTPReplyMarkup(),
MTPvector<MTPMessageEntity>(),
MTP_int(action.options.scheduled),
(sendAs ? sendAs->input : MTP_inputPeerEmpty()),
Data::ShortcutIdToMTP(session, action.options.shortcutId),
MTP_long(action.options.effectId)
), [=](const MTPUpdates &result, const MTP::Response &response) {
}, [=](const MTP::Error &error, const MTP::Response &response) {
api->sendMessageFail(error, peer, randomId);
});
api->finishForwarding(action);
}
template <typename MediaData>
void SendExistingMedia(
MessageToSend &&message,
@ -362,6 +441,33 @@ bool SendDice(MessageToSend &message) {
return true;
}
void SendLocation(SendAction action, float64 lat, float64 lon) {
SendSimpleMedia(
action,
MTP_inputMediaGeoPoint(
MTP_inputGeoPoint(
MTP_flags(0),
MTP_double(lat),
MTP_double(lon),
MTPint()))); // accuracy_radius
}
void SendVenue(SendAction action, Data::InputVenue venue) {
SendSimpleMedia(
action,
MTP_inputMediaVenue(
MTP_inputGeoPoint(
MTP_flags(0),
MTP_double(venue.lat),
MTP_double(venue.lon),
MTPint()), // accuracy_radius
MTP_string(venue.title),
MTP_string(venue.address),
MTP_string(venue.provider),
MTP_string(venue.id),
MTP_string(venue.venueType)));
}
void FillMessagePostFlags(
const SendAction &action,
not_null<PeerData*> peer,

View file

@ -7,15 +7,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Main {
class Session;
} // namespace Main
class History;
class PhotoData;
class DocumentData;
struct FilePrepareResult;
namespace Data {
struct InputVenue;
} // namespace Data
namespace Main {
class Session;
} // namespace Main
namespace Api {
struct MessageToSend;
@ -33,6 +37,13 @@ void SendExistingPhoto(
bool SendDice(MessageToSend &message);
// We can't create Data::LocationPoint() and use it
// for a local sending message, because we can't request
// map thumbnail in messages history without access hash.
void SendLocation(SendAction action, float64 lat, float64 lon);
void SendVenue(SendAction action, Data::InputVenue venue);
void FillMessagePostFlags(
const SendAction &action,
not_null<PeerData*> peer,

View file

@ -0,0 +1,50 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "core/current_geo_location.h"
#include "base/platform/base_platform_info.h"
#include "data/raw/raw_countries_bounds.h"
#include "platform/platform_current_geo_location.h"
namespace Core {
GeoLocation ResolveCurrentCountryLocation() {
const auto iso2 = Platform::SystemCountry().toUpper();
const auto &bounds = Raw::CountryBounds();
const auto i = bounds.find(iso2);
if (i == end(bounds)) {
return {
.accuracy = GeoLocationAccuracy::Failed,
};
}
return {
.point = {
(i->second.minLat + i->second.maxLat) / 2.,
(i->second.minLon + i->second.maxLon) / 2.,
},
.bounds = {
i->second.minLat,
i->second.minLon,
i->second.maxLat - i->second.minLat,
i->second.maxLon - i->second.minLon,
},
.accuracy = GeoLocationAccuracy::Country,
};
}
void ResolveCurrentGeoLocation(Fn<void(GeoLocation)> callback) {
using namespace Platform;
return ResolveCurrentExactLocation([done = std::move(callback)](
GeoLocation result) {
done(result.accuracy != GeoLocationAccuracy::Failed
? result
: ResolveCurrentCountryLocation());
});
}
} // namespace Core

View file

@ -0,0 +1,41 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Core {
enum class GeoLocationAccuracy : uchar {
Exact,
Country,
Failed,
};
struct GeoLocation {
QPointF point;
QRectF bounds;
GeoLocationAccuracy accuracy = GeoLocationAccuracy::Failed;
[[nodiscard]] bool exact() const {
return accuracy == GeoLocationAccuracy::Exact;
}
[[nodiscard]] bool country() const {
return accuracy == GeoLocationAccuracy::Country;
}
[[nodiscard]] bool failed() const {
return accuracy == GeoLocationAccuracy::Failed;
}
explicit operator bool() const {
return !failed();
}
};
[[nodiscard]] GeoLocation ResolveCurrentCountryLocation();
void ResolveCurrentGeoLocation(Fn<void(GeoLocation)> callback);
} // namespace Core

View file

@ -45,6 +45,16 @@ private:
};
struct InputVenue {
float64 lat = 0.;
float64 lon = 0.;
QString title;
QString address;
QString provider;
QString id;
QString venueType;
};
[[nodiscard]] GeoPointLocation ComputeLocation(const LocationPoint &point);
} // namespace Data

View file

@ -0,0 +1,193 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/raw/raw_countries_bounds.h"
// Source: https://github.com/sandstrom/country-bounding-boxes
namespace Raw {
const base::flat_map<QString, GeoBounds> &CountryBounds() {
static const auto result = base::flat_map<QString, GeoBounds>{
{ u"AF"_q, GeoBounds{ 60.53, 29.32, 75.16, 38.49 } },
{ u"AO"_q, GeoBounds{ 11.64, -17.93, 24.08, -4.44 } },
{ u"AL"_q, GeoBounds{ 19.3, 39.62, 21.02, 42.69 } },
{ u"AE"_q, GeoBounds{ 51.58, 22.5, 56.4, 26.06 } },
{ u"AR"_q, GeoBounds{ -73.42, -55.25, -53.63, -21.83 } },
{ u"AM"_q, GeoBounds{ 43.58, 38.74, 46.51, 41.25 } },
{ u"AQ"_q, GeoBounds{ -180.0, -90.0, 180.0, -63.27 } },
{ u"TF"_q, GeoBounds{ 68.72, -49.78, 70.56, -48.63 } },
{ u"AU"_q, GeoBounds{ 113.34, -43.63, 153.57, -10.67 } },
{ u"AT"_q, GeoBounds{ 9.48, 46.43, 16.98, 49.04 } },
{ u"AZ"_q, GeoBounds{ 44.79, 38.27, 50.39, 41.86 } },
{ u"BI"_q, GeoBounds{ 29.02, -4.5, 30.75, -2.35 } },
{ u"BE"_q, GeoBounds{ 2.51, 49.53, 6.16, 51.48 } },
{ u"BJ"_q, GeoBounds{ 0.77, 6.14, 3.8, 12.24 } },
{ u"BF"_q, GeoBounds{ -5.47, 9.61, 2.18, 15.12 } },
{ u"BD"_q, GeoBounds{ 88.08, 20.67, 92.67, 26.45 } },
{ u"BG"_q, GeoBounds{ 22.38, 41.23, 28.56, 44.23 } },
{ u"BS"_q, GeoBounds{ -78.98, 23.71, -77.0, 27.04 } },
{ u"BA"_q, GeoBounds{ 15.75, 42.65, 19.6, 45.23 } },
{ u"BY"_q, GeoBounds{ 23.2, 51.32, 32.69, 56.17 } },
{ u"BZ"_q, GeoBounds{ -89.23, 15.89, -88.11, 18.5 } },
{ u"BO"_q, GeoBounds{ -69.59, -22.87, -57.5, -9.76 } },
{ u"BR"_q, GeoBounds{ -73.99, -33.77, -34.73, 5.24 } },
{ u"BN"_q, GeoBounds{ 114.2, 4.01, 115.45, 5.45 } },
{ u"BT"_q, GeoBounds{ 88.81, 26.72, 92.1, 28.3 } },
{ u"BW"_q, GeoBounds{ 19.9, -26.83, 29.43, -17.66 } },
{ u"CF"_q, GeoBounds{ 14.46, 2.27, 27.37, 11.14 } },
{ u"CA"_q, GeoBounds{ -141.0, 41.68, -52.65, 73.23 } },
{ u"CH"_q, GeoBounds{ 6.02, 45.78, 10.44, 47.83 } },
{ u"CL"_q, GeoBounds{ -75.64, -55.61, -66.96, -17.58 } },
{ u"CN"_q, GeoBounds{ 73.68, 18.2, 135.03, 53.46 } },
{ u"CI"_q, GeoBounds{ -8.6, 4.34, -2.56, 10.52 } },
{ u"CM"_q, GeoBounds{ 8.49, 1.73, 16.01, 12.86 } },
{ u"CD"_q, GeoBounds{ 12.18, -13.26, 31.17, 5.26 } },
{ u"CG"_q, GeoBounds{ 11.09, -5.04, 18.45, 3.73 } },
{ u"CO"_q, GeoBounds{ -78.99, -4.3, -66.88, 12.44 } },
{ u"CR"_q, GeoBounds{ -85.94, 8.23, -82.55, 11.22 } },
{ u"CU"_q, GeoBounds{ -84.97, 19.86, -74.18, 23.19 } },
{ u"CY"_q, GeoBounds{ 32.26, 34.57, 34.0, 35.17 } },
{ u"CZ"_q, GeoBounds{ 12.24, 48.56, 18.85, 51.12 } },
{ u"DE"_q, GeoBounds{ 5.99, 47.3, 15.02, 54.98 } },
{ u"DJ"_q, GeoBounds{ 41.66, 10.93, 43.32, 12.7 } },
{ u"DK"_q, GeoBounds{ 8.09, 54.8, 12.69, 57.73 } },
{ u"DO"_q, GeoBounds{ -71.95, 17.6, -68.32, 19.88 } },
{ u"DZ"_q, GeoBounds{ -8.68, 19.06, 12.0, 37.12 } },
{ u"EC"_q, GeoBounds{ -80.97, -4.96, -75.23, 1.38 } },
{ u"EG"_q, GeoBounds{ 24.7, 22.0, 36.87, 31.59 } },
{ u"ER"_q, GeoBounds{ 36.32, 12.46, 43.08, 18.0 } },
{ u"ES"_q, GeoBounds{ -9.39, 35.95, 3.04, 43.75 } },
{ u"EE"_q, GeoBounds{ 23.34, 57.47, 28.13, 59.61 } },
{ u"ET"_q, GeoBounds{ 32.95, 3.42, 47.79, 14.96 } },
{ u"FI"_q, GeoBounds{ 20.65, 59.85, 31.52, 70.16 } },
{ u"FJ"_q, GeoBounds{ -180.0, -18.29, 180.0, -16.02 } },
{ u"FK"_q, GeoBounds{ -61.2, -52.3, -57.75, -51.1 } },
{ u"FR"_q, GeoBounds{ -5.0, 42.5, 9.56, 51.15 } },
{ u"GA"_q, GeoBounds{ 8.8, -3.98, 14.43, 2.33 } },
{ u"GB"_q, GeoBounds{ -7.57, 49.96, 1.68, 58.64 } },
{ u"GE"_q, GeoBounds{ 39.96, 41.06, 46.64, 43.55 } },
{ u"GH"_q, GeoBounds{ -3.24, 4.71, 1.06, 11.1 } },
{ u"GN"_q, GeoBounds{ -15.13, 7.31, -7.83, 12.59 } },
{ u"GM"_q, GeoBounds{ -16.84, 13.13, -13.84, 13.88 } },
{ u"GW"_q, GeoBounds{ -16.68, 11.04, -13.7, 12.63 } },
{ u"GQ"_q, GeoBounds{ 9.31, 1.01, 11.29, 2.28 } },
{ u"GR"_q, GeoBounds{ 20.15, 34.92, 26.6, 41.83 } },
{ u"GL"_q, GeoBounds{ -73.3, 60.04, -12.21, 83.65 } },
{ u"GT"_q, GeoBounds{ -92.23, 13.74, -88.23, 17.82 } },
{ u"GY"_q, GeoBounds{ -61.41, 1.27, -56.54, 8.37 } },
{ u"HN"_q, GeoBounds{ -89.35, 12.98, -83.15, 16.01 } },
{ u"HR"_q, GeoBounds{ 13.66, 42.48, 19.39, 46.5 } },
{ u"HT"_q, GeoBounds{ -74.46, 18.03, -71.62, 19.92 } },
{ u"HU"_q, GeoBounds{ 16.2, 45.76, 22.71, 48.62 } },
{ u"ID"_q, GeoBounds{ 95.29, -10.36, 141.03, 5.48 } },
{ u"IN"_q, GeoBounds{ 68.18, 7.97, 97.4, 35.49 } },
{ u"IE"_q, GeoBounds{ -9.98, 51.67, -6.03, 55.13 } },
{ u"IR"_q, GeoBounds{ 44.11, 25.08, 63.32, 39.71 } },
{ u"IQ"_q, GeoBounds{ 38.79, 29.1, 48.57, 37.39 } },
{ u"IS"_q, GeoBounds{ -24.33, 63.5, -13.61, 66.53 } },
{ u"IL"_q, GeoBounds{ 34.27, 29.5, 35.84, 33.28 } },
{ u"IT"_q, GeoBounds{ 6.75, 36.62, 18.48, 47.12 } },
{ u"JM"_q, GeoBounds{ -78.34, 17.7, -76.2, 18.52 } },
{ u"JO"_q, GeoBounds{ 34.92, 29.2, 39.2, 33.38 } },
{ u"JP"_q, GeoBounds{ 129.41, 31.03, 145.54, 45.55 } },
{ u"KZ"_q, GeoBounds{ 46.47, 40.66, 87.36, 55.39 } },
{ u"KE"_q, GeoBounds{ 33.89, -4.68, 41.86, 5.51 } },
{ u"KG"_q, GeoBounds{ 69.46, 39.28, 80.26, 43.3 } },
{ u"KH"_q, GeoBounds{ 102.35, 10.49, 107.61, 14.57 } },
{ u"KR"_q, GeoBounds{ 126.12, 34.39, 129.47, 38.61 } },
{ u"KW"_q, GeoBounds{ 46.57, 28.53, 48.42, 30.06 } },
{ u"LA"_q, GeoBounds{ 100.12, 13.88, 107.56, 22.46 } },
{ u"LB"_q, GeoBounds{ 35.13, 33.09, 36.61, 34.64 } },
{ u"LR"_q, GeoBounds{ -11.44, 4.36, -7.54, 8.54 } },
{ u"LY"_q, GeoBounds{ 9.32, 19.58, 25.16, 33.14 } },
{ u"LK"_q, GeoBounds{ 79.7, 5.97, 81.79, 9.82 } },
{ u"LS"_q, GeoBounds{ 27.0, -30.65, 29.33, -28.65 } },
{ u"LT"_q, GeoBounds{ 21.06, 53.91, 26.59, 56.37 } },
{ u"LU"_q, GeoBounds{ 5.67, 49.44, 6.24, 50.13 } },
{ u"LV"_q, GeoBounds{ 21.06, 55.62, 28.18, 57.97 } },
{ u"MA"_q, GeoBounds{ -17.02, 21.42, -1.12, 35.76 } },
{ u"MD"_q, GeoBounds{ 26.62, 45.49, 30.02, 48.47 } },
{ u"MG"_q, GeoBounds{ 43.25, -25.6, 50.48, -12.04 } },
{ u"MX"_q, GeoBounds{ -117.13, 14.54, -86.81, 32.72 } },
{ u"MK"_q, GeoBounds{ 20.46, 40.84, 22.95, 42.32 } },
{ u"ML"_q, GeoBounds{ -12.17, 10.1, 4.27, 24.97 } },
{ u"MM"_q, GeoBounds{ 92.3, 9.93, 101.18, 28.34 } },
{ u"ME"_q, GeoBounds{ 18.45, 41.88, 20.34, 43.52 } },
{ u"MN"_q, GeoBounds{ 87.75, 41.6, 119.77, 52.05 } },
{ u"MZ"_q, GeoBounds{ 30.18, -26.74, 40.78, -10.32 } },
{ u"MR"_q, GeoBounds{ -17.06, 14.62, -4.92, 27.4 } },
{ u"MW"_q, GeoBounds{ 32.69, -16.8, 35.77, -9.23 } },
{ u"MY"_q, GeoBounds{ 100.09, 0.77, 119.18, 6.93 } },
{ u"NA"_q, GeoBounds{ 11.73, -29.05, 25.08, -16.94 } },
{ u"NC"_q, GeoBounds{ 164.03, -22.4, 167.12, -20.11 } },
{ u"NE"_q, GeoBounds{ 0.3, 11.66, 15.9, 23.47 } },
{ u"NG"_q, GeoBounds{ 2.69, 4.24, 14.58, 13.87 } },
{ u"NI"_q, GeoBounds{ -87.67, 10.73, -83.15, 15.02 } },
{ u"NL"_q, GeoBounds{ 3.31, 50.8, 7.09, 53.51 } },
{ u"NO"_q, GeoBounds{ 4.99, 58.08, 31.29, 70.92 } },
{ u"NP"_q, GeoBounds{ 80.09, 26.4, 88.17, 30.42 } },
{ u"NZ"_q, GeoBounds{ 166.51, -46.64, 178.52, -34.45 } },
{ u"OM"_q, GeoBounds{ 52.0, 16.65, 59.81, 26.4 } },
{ u"PK"_q, GeoBounds{ 60.87, 23.69, 77.84, 37.13 } },
{ u"PA"_q, GeoBounds{ -82.97, 7.22, -77.24, 9.61 } },
{ u"PE"_q, GeoBounds{ -81.41, -18.35, -68.67, -0.06 } },
{ u"PH"_q, GeoBounds{ 117.17, 5.58, 126.54, 18.51 } },
{ u"PG"_q, GeoBounds{ 141.0, -10.65, 156.02, -2.5 } },
{ u"PL"_q, GeoBounds{ 14.07, 49.03, 24.03, 54.85 } },
{ u"PR"_q, GeoBounds{ -67.24, 17.95, -65.59, 18.52 } },
{ u"KP"_q, GeoBounds{ 124.27, 37.67, 130.78, 42.99 } },
{ u"PT"_q, GeoBounds{ -9.53, 36.84, -6.39, 42.28 } },
{ u"PY"_q, GeoBounds{ -62.69, -27.55, -54.29, -19.34 } },
{ u"QA"_q, GeoBounds{ 50.74, 24.56, 51.61, 26.11 } },
{ u"RO"_q, GeoBounds{ 20.22, 43.69, 29.63, 48.22 } },
{ u"RU"_q, GeoBounds{ -180.0, 41.15, 180.0, 81.25 } },
{ u"RW"_q, GeoBounds{ 29.02, -2.92, 30.82, -1.13 } },
{ u"SA"_q, GeoBounds{ 34.63, 16.35, 55.67, 32.16 } },
{ u"SD"_q, GeoBounds{ 21.94, 8.62, 38.41, 22.0 } },
{ u"SS"_q, GeoBounds{ 23.89, 3.51, 35.3, 12.25 } },
{ u"SN"_q, GeoBounds{ -17.63, 12.33, -11.47, 16.6 } },
{ u"SB"_q, GeoBounds{ 156.49, -10.83, 162.4, -6.6 } },
{ u"SL"_q, GeoBounds{ -13.25, 6.79, -10.23, 10.05 } },
{ u"SV"_q, GeoBounds{ -90.1, 13.15, -87.72, 14.42 } },
{ u"SO"_q, GeoBounds{ 40.98, -1.68, 51.13, 12.02 } },
{ u"RS"_q, GeoBounds{ 18.83, 42.25, 22.99, 46.17 } },
{ u"SR"_q, GeoBounds{ -58.04, 1.82, -53.96, 6.03 } },
{ u"SK"_q, GeoBounds{ 16.88, 47.76, 22.56, 49.57 } },
{ u"SI"_q, GeoBounds{ 13.7, 45.45, 16.56, 46.85 } },
{ u"SE"_q, GeoBounds{ 11.03, 55.36, 23.9, 69.11 } },
{ u"SZ"_q, GeoBounds{ 30.68, -27.29, 32.07, -25.66 } },
{ u"SY"_q, GeoBounds{ 35.7, 32.31, 42.35, 37.23 } },
{ u"TD"_q, GeoBounds{ 13.54, 7.42, 23.89, 23.41 } },
{ u"TG"_q, GeoBounds{ -0.05, 5.93, 1.87, 11.02 } },
{ u"TH"_q, GeoBounds{ 97.38, 5.69, 105.59, 20.42 } },
{ u"TJ"_q, GeoBounds{ 67.44, 36.74, 74.98, 40.96 } },
{ u"TM"_q, GeoBounds{ 52.5, 35.27, 66.55, 42.75 } },
{ u"TL"_q, GeoBounds{ 124.97, -9.39, 127.34, -8.27 } },
{ u"TT"_q, GeoBounds{ -61.95, 10.0, -60.9, 10.89 } },
{ u"TN"_q, GeoBounds{ 7.52, 30.31, 11.49, 37.35 } },
{ u"TR"_q, GeoBounds{ 26.04, 35.82, 44.79, 42.14 } },
{ u"TW"_q, GeoBounds{ 120.11, 21.97, 121.95, 25.3 } },
{ u"TZ"_q, GeoBounds{ 29.34, -11.72, 40.32, -0.95 } },
{ u"UG"_q, GeoBounds{ 29.58, -1.44, 35.04, 4.25 } },
{ u"UA"_q, GeoBounds{ 22.09, 44.36, 40.08, 52.34 } },
{ u"UY"_q, GeoBounds{ -58.43, -34.95, -53.21, -30.11 } },
{ u"US"_q, GeoBounds{ -125.0, 25.0, -66.96, 49.5 } },
{ u"UZ"_q, GeoBounds{ 55.93, 37.14, 73.06, 45.59 } },
{ u"VE"_q, GeoBounds{ -73.3, 0.72, -59.76, 12.16 } },
{ u"VN"_q, GeoBounds{ 102.17, 8.6, 109.34, 23.35 } },
{ u"VU"_q, GeoBounds{ 166.63, -16.6, 167.84, -14.63 } },
{ u"PS"_q, GeoBounds{ 34.93, 31.35, 35.55, 32.53 } },
{ u"YE"_q, GeoBounds{ 42.6, 12.59, 53.11, 19.0 } },
{ u"ZA"_q, GeoBounds{ 16.34, -34.82, 32.83, -22.09 } },
{ u"ZM"_q, GeoBounds{ 21.89, -17.96, 33.49, -8.24 } },
{ u"ZW"_q, GeoBounds{ 25.26, -22.27, 32.85, -15.51 } }
};
return result;
}
} // namespace Raw

View file

@ -0,0 +1,23 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <QtCore/QString>
namespace Raw {
struct GeoBounds {
double minLat = 0.;
double minLon = 0.;
double maxLat = 0.;
double maxLon = 0.;
};
[[nodiscard]] const base::flat_map<QString, GeoBounds> &CountryBounds();
} // namespace Raw

View file

@ -9,9 +9,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_blocked_peers.h"
#include "api/api_common.h"
#include "api/api_sending.h"
#include "base/qthelp_url.h"
#include "boxes/share_box.h"
#include "core/click_handler_types.h"
#include "core/shortcuts.h"
#include "data/data_bot_app.h"
#include "data/data_changes.h"
#include "data/data_user.h"
@ -28,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "iv/iv_instance.h"
#include "ui/boxes/confirm_box.h"
#include "ui/chat/attach/attach_bot_webview.h"
#include "ui/controls/location_picker.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/widgets/popup_menu.h"
@ -155,6 +158,10 @@ constexpr auto kRefreshBotsTimeout = 60 * 60 * crl::time(1000);
return result;
}
[[nodiscard]] QString ResolveMapsToken(not_null<Main::Session*> session) {
return u""_q;
}
void ShowChooseBox(
not_null<Window::SessionController*> controller,
PeerTypes types,
@ -1793,6 +1800,21 @@ void AttachWebView::toggleInMenu(
}).send();
}
void ChooseAndSendLocation(
not_null<Window::SessionController*> controller,
Api::SendAction action) {
const auto callback = [=](Ui::LocationInfo info) {
Api::SendLocation(action, info.lat, info.lon);
};
Ui::LocationPicker::Show({
.parent = controller->widget(),
.callback = crl::guard(controller, callback),
.quit = [] { Shortcuts::Launch(Shortcuts::Command::Quit); },
.storageId = controller->session().local().resolveStorageIdBots(),
.closeRequests = controller->content()->death(),
});
}
std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
not_null<QWidget*> parent,
not_null<Window::SessionController*> controller,
@ -1847,6 +1869,14 @@ std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
{ sendMenuType });
}, &st::menuIconCreatePoll);
}
const auto session = &controller->session();
const auto locationType = ChatRestriction::SendOther;
if (Data::CanSendAnyOf(peer, locationType)
&& Ui::LocationPicker::Available(ResolveMapsToken(session))) {
raw->addAction(tr::lng_maps_point(tr::now), [=] {
ChooseAndSendLocation(controller, actionFactory());
}, &st::menuIconAddress);
}
for (const auto &bot : bots->attachBots()) {
if (!bot.inAttachMenu
|| !PeerMatchesTypes(peer, bot.user, bot.types)) {

View file

@ -0,0 +1,18 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "platform/linux/current_geo_location_linux.h"
#include "core/current_geo_location.h"
namespace Platform {
void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback) {
callback({});
}
} // namespace Platform

View file

@ -0,0 +1,10 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "platform/platform_current_geo_location.h"

View file

@ -0,0 +1,10 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "platform/platform_current_geo_location.h"

View file

@ -0,0 +1,18 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "platform/mac/current_geo_location_mac.h"
#include "core/current_geo_location.h"
namespace Platform {
void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback) {
callback({});
}
} // namespace Platform

View file

@ -0,0 +1,18 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Core {
struct GeoLocation;
} // namespace Core
namespace Platform {
void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback);
} // namespace Platform

View file

@ -0,0 +1,59 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "platform/win/current_geo_location_win.h"
#include "base/platform/win/base_windows_winrt.h"
#include "core/current_geo_location.h"
#include <winrt/Windows.Devices.Geolocation.h>
#include <winrt/Windows.Foundation.h>
namespace Platform {
void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback) {
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Devices::Geolocation;
const auto success = base::WinRT::Try([&] {
Geolocator geolocator;
geolocator.DesiredAccuracy(PositionAccuracy::High);
if (geolocator.LocationStatus() == PositionStatus::NotAvailable) {
callback({});
return;
}
geolocator.GetGeopositionAsync().Completed([=](
IAsyncOperation<Geoposition> that,
AsyncStatus status) {
if (status != AsyncStatus::Completed) {
crl::on_main([=] {
callback({});
});
return;
}
const auto point = base::WinRT::Try([&] {
const auto coordinate = that.GetResults().Coordinate();
return coordinate.Point().Position();
});
crl::on_main([=] {
if (!point) {
callback({});
} else {
callback({
.point = { point->Latitude, point->Longitude },
.accuracy = Core::GeoLocationAccuracy::Exact,
});
}
});
});
});
if (!success) {
callback({});
}
}
} // namespace Platform

View file

@ -0,0 +1,10 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "platform/platform_current_geo_location.h"

View file

@ -0,0 +1,350 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ui/controls/location_picker.h"
#include "base/platform/base_platform_info.h"
#include "core/current_geo_location.h"
#include "lang/lang_keys.h"
#include "ui/widgets/rp_window.h"
#include "ui/widgets/buttons.h"
#include "webview/webview_data_stream_memory.h"
#include "webview/webview_embed.h"
#include "webview/webview_interface.h"
#include "styles/style_dialogs.h"
#include "styles/style_window.h"
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonValue>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
namespace Ui {
namespace {
Core::GeoLocation LastExactLocation;
QString MapsProviderToken;
[[nodiscard]] QByteArray DefaultCenter() {
if (!LastExactLocation) {
return "null";
}
return "["_q
+ QByteArray::number(LastExactLocation.point.x() - 1)
+ ","_q
+ QByteArray::number(LastExactLocation.point.y() - 1)
+ "]"_q;
}
[[nodiscard]] QByteArray DefaultBounds() {
const auto country = Core::ResolveCurrentCountryLocation();
if (!country) {
return "null";
}
return "[["_q
+ QByteArray::number(country.bounds.x())
+ ","_q
+ QByteArray::number(country.bounds.y())
+ "],["_q
+ QByteArray::number(country.bounds.x() + country.bounds.width())
+ ","_q
+ QByteArray::number(country.bounds.y() + country.bounds.height())
+ "]]"_q;
}
[[nodiscard]] QByteArray ComputeStyles() {
return "";
}
[[nodiscard]] QByteArray EscapeForAttribute(QByteArray value) {
return value
.replace('&', "&amp;")
.replace('"', "&quot;")
.replace('\'', "&#039;")
.replace('<', "&lt;")
.replace('>', "&gt;");
}
[[nodiscard]] QByteArray EscapeForScriptString(QByteArray value) {
return value
.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\'', "\\\'");
}
[[nodiscard]] QByteArray ReadResource(const QString &name) {
auto file = QFile(u":/picker/"_q + name);
return file.open(QIODevice::ReadOnly) ? file.readAll() : QByteArray();
}
[[nodiscard]] QByteArray PickerContent() {
return R"(<!DOCTYPE html>
<html style=")"
+ EscapeForAttribute(ComputeStyles())
+ R"(">
<head>
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/location/picker.js"></script>
<link rel="stylesheet" href="/location/picker.css" />
<script src='https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.css' rel='stylesheet' />
</head>
<body>
<div id="marker"><div id="marker_drop"></div></div>
<div id="map"></div>
<script>LocationPicker.notify({ event: 'ready' });</script>
</body>
</html>
)"_q;
}
} // namespace
LocationPicker::LocationPicker(Descriptor &&descriptor)
: _callback(std::move(descriptor.callback))
, _quit(std::move(descriptor.quit))
, _window(std::make_unique<RpWindow>())
, _updateStyles([=] {
const auto str = EscapeForScriptString(ComputeStyles());
if (_webview) {
_webview->eval("IV.updateStyles('" + str + "');");
}
}) {
std::move(
descriptor.closeRequests
) | rpl::start_with_next([=] {
_window = nullptr;
delete this;
}, _lifetime);
setup(descriptor);
}
bool LocationPicker::Available(const QString &token) {
static const auto Supported = Webview::NavigateToDataSupported();
MapsProviderToken = token;
return Supported && !MapsProviderToken.isEmpty();
}
void LocationPicker::setup(const Descriptor &descriptor) {
setupWindow(descriptor);
setupWebview(descriptor);
}
void LocationPicker::setupWindow(const Descriptor &descriptor) {
const auto window = _window.get();
const auto parent = descriptor.parent
? descriptor.parent->window()->geometry()
: QGuiApplication::primaryScreen()->availableGeometry();
window->setGeometry(QRect(
parent.x() + (parent.width() - st::windowMinHeight) / 2,
parent.y() + (parent.height() - st::windowMinWidth) / 2,
st::windowMinHeight,
st::windowMinWidth));
window->setMinimumSize({ st::windowMinHeight, st::windowMinWidth });
_container = Ui::CreateChild<Ui::RpWidget>(window->body().get());
const auto button = Ui::CreateChild<FlatButton>(
window->body(),
tr::lng_maps_point_send(tr::now),
st::dialogsUpdateButton);
button->show();
button->setClickedCallback([=] {
_webview->eval("LocationPicker.send();");
});
window->body()->sizeValue(
) | rpl::start_with_next([=](QSize size) {
_container->setGeometry(QRect(QPoint(), size).marginsRemoved(
{ 0, 0, 0, button->height() }));
button->resizeToWidth(size.width());
button->setGeometry(
0,
size.height() - button->height(),
button->width(),
button->height());
}, _container->lifetime());
_container->paintRequest() | rpl::start_with_next([=](QRect clip) {
QPainter(_container).fillRect(clip, st::windowBg);
}, _container->lifetime());
_container->show();
window->show();
}
void LocationPicker::setupWebview(const Descriptor &descriptor) {
Expects(!_webview);
const auto window = _window.get();
_webview = std::make_unique<Webview::Window>(
_container,
Webview::WindowConfig{
.opaqueBg = st::windowBg->c,
.storageId = descriptor.storageId,
});
const auto raw = _webview.get();
window->lifetime().add([=] {
_webview = nullptr;
});
window->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) {
if (e->type() == QEvent::Close) {
close();
} else if (e->type() == QEvent::KeyPress) {
const auto event = static_cast<QKeyEvent*>(e.get());
if (event->key() == Qt::Key_Escape) {
close();
}
}
}, window->lifetime());
raw->widget()->show();
_container->sizeValue(
) | rpl::start_with_next([=](QSize size) {
raw->widget()->setGeometry(QRect(QPoint(), size));
}, _container->lifetime());
raw->setNavigationStartHandler([=](const QString &uri, bool newWindow) {
return true;
});
raw->setNavigationDoneHandler([=](bool success) {
});
raw->setMessageHandler([=](const QJsonDocument &message) {
crl::on_main(_window.get(), [=] {
const auto object = message.object();
const auto event = object.value("event").toString();
if (event == u"ready"_q) {
initMap();
resolveCurrentLocation();
} else if (event == u"keydown"_q) {
const auto key = object.value("key").toString();
const auto modifier = object.value("modifier").toString();
processKey(key, modifier);
} else if (event == u"send"_q) {
const auto lat = object.value("latitude").toDouble();
const auto lon = object.value("longitude").toDouble();
_callback({ lat, lon });
close();
}
});
});
raw->setDataRequestHandler([=](Webview::DataRequest request) {
const auto pos = request.id.find('#');
if (pos != request.id.npos) {
request.id = request.id.substr(0, pos);
}
if (!request.id.starts_with("location/")) {
return Webview::DataResult::Failed;
}
const auto finishWith = [&](QByteArray data, std::string mime) {
request.done({
.stream = std::make_unique<Webview::DataStreamFromMemory>(
std::move(data),
std::move(mime)),
});
return Webview::DataResult::Done;
};
if (!_subscribedToColors) {
_subscribedToColors = true;
rpl::merge(
Lang::Updated(),
style::PaletteChanged()
) | rpl::start_with_next([=] {
_updateStyles.call();
}, _webview->lifetime());
}
const auto id = std::string_view(request.id).substr(9);
if (id == "picker.html") {
return finishWith(PickerContent(), "text/html; charset=utf-8");
}
const auto css = id.ends_with(".css");
const auto js = !css && id.ends_with(".js");
if (!css && !js) {
return Webview::DataResult::Failed;
}
const auto qstring = QString::fromUtf8(id.data(), id.size());
const auto pattern = u"^[a-zA-Z\\.\\-_0-9]+$"_q;
if (QRegularExpression(pattern).match(qstring).hasMatch()) {
const auto bytes = ReadResource(qstring);
if (!bytes.isEmpty()) {
const auto mime = css ? "text/css" : "text/javascript";
return finishWith(bytes, mime);
}
}
return Webview::DataResult::Failed;
});
raw->init(R"()");
raw->navigateToData("location/picker.html");
}
void LocationPicker::initMap() {
const auto token = MapsProviderToken.toUtf8();
const auto center = DefaultCenter();
const auto bounds = DefaultBounds();
const auto arguments = "'" + token + "', " + center + ", " + bounds;
_webview->eval("LocationPicker.init(" + arguments + ");");
}
void LocationPicker::resolveCurrentLocation() {
using namespace Core;
const auto window = _window.get();
ResolveCurrentGeoLocation(crl::guard(window, [=](GeoLocation location) {
if (location) {
LastExactLocation = location;
}
if (_webview && location.accuracy == GeoLocationAccuracy::Exact) {
const auto point = QByteArray::number(location.point.x())
+ ","_q
+ QByteArray::number(location.point.y());
_webview->eval("LocationPicker.narrowTo([" + point + "]);");
}
}));
}
void LocationPicker::processKey(
const QString &key,
const QString &modifier) {
const auto ctrl = ::Platform::IsMac() ? u"cmd"_q : u"ctrl"_q;
if (key == u"escape"_q || (key == u"w"_q && modifier == ctrl)) {
close();
} else if (key == u"m"_q && modifier == ctrl) {
minimize();
} else if (key == u"q"_q && modifier == ctrl) {
quit();
}
}
void LocationPicker::close() {
_window->close();
}
void LocationPicker::minimize() {
if (_window) {
_window->setWindowState(_window->windowState()
| Qt::WindowMinimized);
}
}
void LocationPicker::quit() {
if (const auto onstack = _quit) {
onstack();
}
}
not_null<LocationPicker*> LocationPicker::Show(Descriptor &&descriptor) {
return new LocationPicker(std::move(descriptor));
}
} // namespace Ui

View file

@ -0,0 +1,67 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/invoke_queued.h"
#include "base/weak_ptr.h"
#include "webview/webview_common.h"
namespace Webview {
class Window;
} // namespace Webview
namespace Ui {
class RpWindow;
class RpWidget;
struct LocationInfo {
float64 lat = 0.;
float64 lon = 0.;
};
class LocationPicker final : public base::has_weak_ptr {
public:
struct Descriptor {
RpWidget *parent = nullptr;
Fn<void(LocationInfo)> callback;
Fn<void()> quit;
Webview::StorageId storageId;
rpl::producer<> closeRequests;
};
[[nodiscard]] static bool Available(const QString &token);
static not_null<LocationPicker*> Show(Descriptor &&descriptor);
void close();
void minimize();
void quit();
private:
explicit LocationPicker(Descriptor &&descriptor);
void setup(const Descriptor &descriptor);
void setupWindow(const Descriptor &descriptor);
void setupWebview(const Descriptor &descriptor);
void processKey(const QString &key, const QString &modifier);
void resolveCurrentLocation();
void initMap();
rpl::lifetime _lifetime;
Fn<void(LocationInfo)> _callback;
Fn<void()> _quit;
std::unique_ptr<RpWindow> _window;
RpWidget *_container = nullptr;
std::unique_ptr<Webview::Window> _webview;
SingleQueuedInvokation _updateStyles;
bool _subscribedToColors = false;
};
} // namespace Ui

View file

@ -70,6 +70,8 @@ PRIVATE
chat_helpers/stickers_emoji_image_loader.cpp
chat_helpers/stickers_emoji_image_loader.h
core/current_geo_location.cpp
core/current_geo_location.h
core/file_location.cpp
core/file_location.h
core/mime_type.cpp
@ -78,6 +80,8 @@ PRIVATE
countries/countries_instance.cpp
countries/countries_instance.h
data/raw/raw_countries_bounds.cpp
data/raw/raw_countries_bounds.h
data/data_birthday.cpp
data/data_birthday.h
data/data_channel_earn.h
@ -194,9 +198,16 @@ PRIVATE
payments/ui/payments_panel_data.h
payments/ui/payments_panel_delegate.h
platform/linux/current_geo_location_linux.cpp
platform/linux/current_geo_location_linux.h
platform/mac/file_bookmark_mac.h
platform/mac/file_bookmark_mac.mm
platform/mac/current_geo_location_mac.h
platform/mac/current_geo_location_mac.mm
platform/win/current_geo_location_win.cpp
platform/win/current_geo_location_win.h
platform/platform_file_bookmark.h
platform/platform_current_geo_location.h
settings/settings_common.cpp
settings/settings_common.h
@ -344,6 +355,8 @@ PRIVATE
ui/controls/invite_link_buttons.h
ui/controls/invite_link_label.cpp
ui/controls/invite_link_label.h
ui/controls/location_picker.cpp
ui/controls/location_picker.h
ui/controls/peer_list_dummy.cpp
ui/controls/peer_list_dummy.h
ui/controls/send_as_button.cpp
@ -439,6 +452,12 @@ PRIVATE
ui/ui_pch.h
)
nice_target_sources(td_ui ${res_loc}
PRIVATE
picker_html/picker.css
picker_html/picker.js
)
if (DESKTOP_APP_SPECIAL_TARGET)
remove_target_sources(td_ui ${src_loc}
ui/controls/window_outdated_bar_dummy.cpp