Handle located groups as public.

This commit is contained in:
John Preston 2019-06-21 14:27:46 +02:00
parent 6537e524b8
commit 7d585ab72f
37 changed files with 468 additions and 275 deletions

View File

@ -780,6 +780,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_info_username_label" = "Username";
"lng_info_bio_label" = "Bio";
"lng_info_link_label" = "Link";
"lng_info_location_label" = "Location";
"lng_info_about_label" = "About";
"lng_info_user_title" = "User Info";
"lng_info_bot_title" = "Bot Info";
@ -844,6 +845,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_group_type" = "Group type";
"lng_manage_peer_channel_type" = "Channel type";
"lng_manage_peer_link_type" = "Link type";
"lng_manage_peer_link_permanent" = "Permanent link";
"lng_manage_peer_link_invite" = "Invite link";
"lng_manage_private_group_title" = "Private";
"lng_manage_public_group_title" = "Public";
"lng_manage_private_peer_title" = "Private";
@ -924,6 +928,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_create_public_group_about" = "Anyone can find the group in search and join, chat history is available to everybody";
"lng_create_private_group_title" = "Private Group";
"lng_create_private_group_about" = "People can only join if they were invited or have an invite link";
"lng_create_permanent_link_title" = "Permanent link";
"lng_create_invite_link_title" = "Invite link";
"lng_create_invite_link_about" = "People can join if they were invited, have an invite link, or from \"Groups nearby\"";
"lng_create_group_skip" = "Skip";
"lng_create_channel_link_about" = "You can use a-z, 0-9 and underscores.\nMinimum length is 5 characters.";
@ -1048,6 +1056,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_channels_too_much_public_revoke_confirm_channel" = "Are you sure you want to revoke the link {link}?\n\nThe channel «{group}» will become private.";
"lng_channels_too_much_public_revoke" = "Revoke";
"lng_channels_too_much_public_other" = "Sorry, the target user has too many public groups or channels already. Please ask them to make one of their existing groups or channels private first.";
"lng_channels_too_much_located_other" = "Sorry, the target user has too many location-based groups already. Please ask them to delete or transfer one of their existing ones first.";
"lng_group_invite_bad_link" = "This invite link is broken or has expired.";
"lng_group_invite_join" = "Join";

View File

@ -691,11 +691,11 @@ QString ApiWrap::exportDirectMessageLink(not_null<HistoryItem*> item) {
const auto itemId = item->fullId();
const auto channel = item->history()->peer->asChannel();
const auto fallback = [&] {
const auto base = channel->isPublic()
const auto base = channel->hasUsername()
? channel->username
: "c/" + QString::number(channel->bareId());
const auto query = base + '/' + QString::number(item->id);
if (channel->isPublic() && !channel->isMegagroup()) {
if (channel->hasUsername() && !channel->isMegagroup()) {
if (const auto media = item->media()) {
if (const auto document = media->document()) {
if (document->isVideoMessage()) {

View File

@ -537,6 +537,8 @@ void EditAdminBox::sendTransferRequestFrom(
const auto problem = [&] {
if (type == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
return tr::lng_channels_too_much_public_other(tr::now);
} else if (type == qstr("CHANNELS_ADMIN_LOCATED_TOO_MUCH")) {
return tr::lng_channels_too_much_located_other(tr::now);
} else if (type == qstr("ADMINS_TOO_MUCH")) {
return (channel->isBroadcast()
? tr::lng_error_admin_limit_channel

View File

@ -240,6 +240,7 @@ private:
std::optional<Privacy> _privacySavedValue;
std::optional<ChannelData*> _linkedChatSavedValue;
ChannelData *_linkedChatOriginalValue = nullptr;
bool _channelHasLocationOriginalValue = false;
std::optional<HistoryVisibility> _historyVisibilitySavedValue;
std::optional<QString> _usernameSavedValue;
std::optional<bool> _signaturesSavedValue;
@ -489,7 +490,8 @@ void Controller::refreshHistoryVisibility(anim::type animated) {
return;
}
_controls.historyVisibilityWrap->toggle(
(_privacySavedValue != Privacy::Public
(_privacySavedValue != Privacy::HasUsername
&& !_channelHasLocationOriginalValue
&& (!_linkedChatSavedValue || !*_linkedChatSavedValue)),
animated);
};
@ -506,6 +508,7 @@ void Controller::showEditPeerTypeBox(
Ui::show(
Box<EditPeerTypeBox>(
_peer,
_channelHasLocationOriginalValue,
boxCallback,
_privacySavedValue,
_usernameSavedValue,
@ -569,26 +572,34 @@ void Controller::fillPrivacyTypeButton() {
Expects(_controls.buttonsLayout != nullptr);
// Create Privacy Button.
const auto hasLocation = _peer->isChannel()
&& _peer->asChannel()->hasLocation();
_privacySavedValue = (_peer->isChannel()
&& _peer->asChannel()->isPublic())
? Privacy::Public
: Privacy::Private;
&& _peer->asChannel()->hasUsername())
? Privacy::HasUsername
: Privacy::NoUsername;
const auto isGroup = (_peer->isChat() || _peer->isMegagroup());
AddButtonWithText(
_controls.buttonsLayout,
(isGroup
(hasLocation
? tr::lng_manage_peer_link_type
: isGroup
? tr::lng_manage_peer_group_type
: tr::lng_manage_peer_channel_type)(),
_privacyTypeUpdates.events(
) | rpl::map([=](Privacy flag) {
return (Privacy::Public == flag
? (isGroup
return (flag == Privacy::HasUsername)
? (hasLocation
? tr::lng_manage_peer_link_permanent
: isGroup
? tr::lng_manage_public_group_title
: tr::lng_manage_public_peer_title)
: (isGroup
: tr::lng_manage_public_peer_title)()
: (hasLocation
? tr::lng_manage_peer_link_invite
: isGroup
? tr::lng_manage_private_group_title
: tr::lng_manage_private_peer_title))();
: tr::lng_manage_private_peer_title)();
}) | rpl::flatten_latest(),
[=] { showEditPeerTypeBox(); });
@ -640,9 +651,7 @@ void Controller::fillInviteLinkButton() {
Expects(_controls.buttonsLayout != nullptr);
const auto buttonCallback = [=] {
Ui::show(
Box<EditPeerTypeBox>(_peer),
LayerOption::KeepOther);
Ui::show(Box<EditPeerTypeBox>(_peer), LayerOption::KeepOther);
};
AddButtonWithText(
@ -685,6 +694,7 @@ void Controller::fillHistoryVisibilityButton() {
_historyVisibilitySavedValue = (!channel || channel->hiddenPreHistory())
? HistoryVisibility::Hidden
: HistoryVisibility::Visible;
_channelHasLocationOriginalValue = channel && channel->hasLocation();
const auto updateHistoryVisibility =
std::make_shared<rpl::event_stream<HistoryVisibility>>();
@ -945,7 +955,7 @@ std::optional<Controller::Saving> Controller::validate() const {
bool Controller::validateUsername(Saving &to) const {
if (!_privacySavedValue) {
return true;
} else if (_privacySavedValue != Privacy::Public) {
} else if (_privacySavedValue != Privacy::HasUsername) {
to.username = QString();
return true;
}
@ -994,7 +1004,8 @@ bool Controller::validateDescription(Saving &to) const {
bool Controller::validateHistoryVisibility(Saving &to) const {
if (!_controls.historyVisibilityWrap
|| !_controls.historyVisibilityWrap->toggled()
|| (_privacySavedValue == Privacy::Public)) {
|| _channelHasLocationOriginalValue
|| (_privacySavedValue == Privacy::HasUsername)) {
return true;
}
to.hiddenPreHistory

View File

@ -51,6 +51,7 @@ public:
Controller(
not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer,
bool useLocationPhrases,
std::optional<Privacy> privacySavedValue,
std::optional<QString> usernameSavedValue);
@ -129,10 +130,8 @@ private:
void addRoundButton(
not_null<Ui::VerticalLayout*> container,
Privacy value,
const QString &groupText,
const QString &channelText,
rpl::producer<QString> groupAbout,
rpl::producer<QString> channelAbout);
const QString &text,
rpl::producer<QString> about);
bool inviteLinkShown();
QString inviteLinkText();
@ -141,6 +140,7 @@ private:
std::optional<Privacy> _privacySavedValue;
std::optional<QString> _usernameSavedValue;
bool _useLocationPhrases = false;
bool _isGroup = false;
bool _isInviteLink = false;
bool _isAllowSave = false;
@ -158,11 +158,13 @@ private:
Controller::Controller(
not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer,
bool useLocationPhrases,
std::optional<Privacy> privacySavedValue,
std::optional<QString> usernameSavedValue)
: _peer(peer)
, _privacySavedValue(privacySavedValue)
, _usernameSavedValue(usernameSavedValue)
, _useLocationPhrases(useLocationPhrases)
, _isGroup(_peer->isChat() || _peer->isMegagroup())
, _isInviteLink(!_privacySavedValue.has_value()
&& !_usernameSavedValue.has_value())
@ -189,7 +191,7 @@ void Controller::createContent() {
_wrap->add(createInviteLinkEdit());
_wrap->add(createUsernameEdit());
if (_controls.privacy->value() == Privacy::Private) {
if (_controls.privacy->value() == Privacy::NoUsername) {
checkUsernameAvailability();
}
}
@ -197,21 +199,19 @@ void Controller::createContent() {
void Controller::addRoundButton(
not_null<Ui::VerticalLayout*> container,
Privacy value,
const QString &groupText,
const QString &channelText,
rpl::producer<QString> groupAbout,
rpl::producer<QString> channelAbout) {
const QString &text,
rpl::producer<QString> about) {
container->add(object_ptr<Ui::Radioenum<Privacy>>(
container,
_controls.privacy,
value,
(_isGroup ? groupText : channelText),
text,
st::editPeerPrivacyBoxCheckbox));
container->add(object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
container,
object_ptr<Ui::FlatLabel>(
container,
std::move(_isGroup ? groupAbout : channelAbout),
std::move(about),
st::editPeerPrivacyLabel),
st::editPeerPrivacyLabelMargins));
container->add(object_ptr<Ui::FixedHeightWidget>(
@ -242,24 +242,35 @@ void Controller::fillPrivaciesButtons(
const auto container = result->entity();
const auto isPublic = _peer->isChannel()
&& _peer->asChannel()->isPublic();
&& _peer->asChannel()->hasUsername();
_controls.privacy = std::make_shared<Ui::RadioenumGroup<Privacy>>(
savedValue.value_or(isPublic ? Privacy::Public : Privacy::Private));
savedValue.value_or(
isPublic ? Privacy::HasUsername : Privacy::NoUsername));
addRoundButton(
container,
Privacy::Public,
tr::lng_create_public_group_title(tr::now),
tr::lng_create_public_channel_title(tr::now),
tr::lng_create_public_group_about(),
tr::lng_create_public_channel_about());
Privacy::HasUsername,
(_useLocationPhrases
? tr::lng_create_permanent_link_title
: _isGroup
? tr::lng_create_public_group_title
: tr::lng_create_public_channel_title)(tr::now),
(_isGroup
? tr::lng_create_public_group_about
: tr::lng_create_public_channel_about)());
addRoundButton(
container,
Privacy::Private,
tr::lng_create_private_group_title(tr::now),
tr::lng_create_private_channel_title(tr::now),
tr::lng_create_private_group_about(),
tr::lng_create_private_channel_about());
Privacy::NoUsername,
(_useLocationPhrases
? tr::lng_create_invite_link_title
: _isGroup
? tr::lng_create_private_group_title
: tr::lng_create_private_channel_title)(tr::now),
(_useLocationPhrases
? tr::lng_create_invite_link_about
: _isGroup
? tr::lng_create_private_group_about
: tr::lng_create_private_channel_about)());
_controls.privacy->setChangedCallback([=](Privacy value) {
privacyChanged(value);
@ -343,7 +354,7 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
&Ui::UsernameInput::changed,
[this] { usernameChanged(); });
const auto shown = (_controls.privacy->value() == Privacy::Public);
const auto shown = (_controls.privacy->value() == Privacy::HasUsername);
result->toggle(shown, anim::type::instant);
return std::move(result);
@ -352,14 +363,14 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
void Controller::privacyChanged(Privacy value) {
const auto toggleEditUsername = [&] {
_controls.usernameWrap->toggle(
(value == Privacy::Public),
(value == Privacy::HasUsername),
anim::type::instant);
};
const auto refreshVisibilities = [&] {
// Now first we need to hide that was shown.
// Otherwise box will change own Y position.
if (value == Privacy::Public) {
if (value == Privacy::HasUsername) {
refreshCreateInviteLink();
refreshEditInviteLink();
toggleEditUsername();
@ -372,12 +383,12 @@ void Controller::privacyChanged(Privacy value) {
refreshEditInviteLink();
}
};
if (value == Privacy::Public) {
if (value == Privacy::HasUsername) {
if (_usernameState == UsernameState::TooMany) {
askUsernameRevoke();
return;
} else if (_usernameState == UsernameState::NotAvailable) {
_controls.privacy->setValue(Privacy::Private);
_controls.privacy->setValue(Privacy::NoUsername);
return;
}
refreshVisibilities();
@ -394,7 +405,7 @@ void Controller::checkUsernameAvailability() {
if (!_controls.usernameInput) {
return;
}
const auto initial = (_controls.privacy->value() != Privacy::Public);
const auto initial = (_controls.privacy->value() != Privacy::HasUsername);
const auto checking = initial
? qsl(".bad.")
: getUsernameInput();
@ -425,14 +436,14 @@ void Controller::checkUsernameAvailability() {
_usernameState = UsernameState::Normal;
if (type == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
_usernameState = UsernameState::NotAvailable;
_controls.privacy->setValue(Privacy::Private);
_controls.privacy->setValue(Privacy::NoUsername);
} else if (type == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
_usernameState = UsernameState::TooMany;
if (_controls.privacy->value() == Privacy::Public) {
if (_controls.privacy->value() == Privacy::HasUsername) {
askUsernameRevoke();
}
} else if (initial) {
if (_controls.privacy->value() == Privacy::Public) {
if (_controls.privacy->value() == Privacy::HasUsername) {
_controls.usernameResult = nullptr;
setFocusUsername();
}
@ -446,10 +457,10 @@ void Controller::checkUsernameAvailability() {
}
void Controller::askUsernameRevoke() {
_controls.privacy->setValue(Privacy::Private);
_controls.privacy->setValue(Privacy::NoUsername);
const auto revokeCallback = crl::guard(this, [this] {
_usernameState = UsernameState::Normal;
_controls.privacy->setValue(Privacy::Public);
_controls.privacy->setValue(Privacy::HasUsername);
checkUsernameAvailability();
});
Ui::show(
@ -683,20 +694,26 @@ void Controller::refreshCreateInviteLink() {
bool Controller::inviteLinkShown() {
return !_controls.privacy
|| (_controls.privacy->value() == Privacy::Private)
|| (_controls.privacy->value() == Privacy::NoUsername)
|| _isInviteLink;
}
} // namespace
EditPeerTypeBox::EditPeerTypeBox(QWidget*, not_null<PeerData*> peer)
: EditPeerTypeBox(nullptr, peer, false, {}, {}, {}, {}) {
}
EditPeerTypeBox::EditPeerTypeBox(
QWidget*,
not_null<PeerData*> peer,
bool useLocationPhrases,
std::optional<FnMut<void(Privacy, QString)>> savedCallback,
std::optional<Privacy> privacySaved,
std::optional<QString> usernameSaved,
std::optional<rpl::producer<QString>> usernameError)
: _peer(peer)
, _useLocationPhrases(useLocationPhrases)
, _savedCallback(std::move(savedCallback))
, _privacySavedValue(privacySaved)
, _usernameSavedValue(usernameSaved)
@ -716,6 +733,7 @@ void EditPeerTypeBox::prepare() {
this,
content,
_peer,
_useLocationPhrases,
_privacySavedValue,
_usernameSavedValue);
_focusRequests.events(
@ -735,14 +753,14 @@ void EditPeerTypeBox::prepare() {
if (!controller->isInviteLink() && _savedCallback.has_value()) {
addButton(tr::lng_settings_save(), [=] {
const auto v = controller->getPrivacy();
if (!controller->isAllowSave() && (v == Privacy::Public)) {
if (!controller->isAllowSave() && (v == Privacy::HasUsername)) {
controller->setFocusUsername();
return;
}
auto local = std::move(*_savedCallback);
local(v,
(v == Privacy::Public)
(v == Privacy::HasUsername)
? controller->getUsernameInput()
: QString()); // We dont need username with private type.
closeBox();

View File

@ -25,8 +25,8 @@ class Button;
} // namespace Info
enum class Privacy {
Public,
Private,
HasUsername,
NoUsername,
};
enum class UsernameState {
@ -37,12 +37,16 @@ enum class UsernameState {
class EditPeerTypeBox : public BoxContent {
public:
// Edit just the invite link.
EditPeerTypeBox(QWidget*, not_null<PeerData*> peer);
EditPeerTypeBox(
QWidget*,
not_null<PeerData*> p,
std::optional<FnMut<void(Privacy, QString)>> savedCallback = {},
std::optional<Privacy> privacySaved = {},
std::optional<QString> usernameSaved = {},
not_null<PeerData*> peer,
bool useLocationPhrases,
std::optional<FnMut<void(Privacy, QString)>> savedCallback,
std::optional<Privacy> privacySaved,
std::optional<QString> usernameSaved,
std::optional<rpl::producer<QString>> usernameError = {});
protected:
@ -51,6 +55,7 @@ protected:
private:
not_null<PeerData*> _peer;
bool _useLocationPhrases = false;
std::optional<FnMut<void(Privacy, QString)>> _savedCallback;
std::optional<Privacy> _privacySavedValue;

View File

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat.h"
#include "data/data_session.h"
#include "data/data_folder.h"
#include "data/data_location.h"
#include "history/history.h"
#include "observer_peer.h"
#include "auth_session.h"
@ -32,6 +33,14 @@ void MegagroupInfo::setMigrateFromChat(ChatData *chat) {
_migratedFrom = chat;
}
const ChannelLocation *MegagroupInfo::getLocation() const {
return _location.address.isEmpty() ? nullptr : &_location;
}
void MegagroupInfo::setLocation(const ChannelLocation &location) {
_location = location;
}
ChannelData::ChannelData(not_null<Data::Session*> owner, PeerId id)
: PeerData(owner, id)
, inputChannel(MTP_inputChannel(MTP_int(bareId()), MTP_long(0))) {
@ -92,6 +101,37 @@ bool ChannelData::canHaveInviteLink() const {
|| amCreator();
}
void ChannelData::setLocation(const MTPChannelLocation &data) {
if (!mgInfo) {
return;
}
const auto was = mgInfo->getLocation();
const auto wasValue = was ? *was : ChannelLocation();
data.match([&](const MTPDchannelLocation &data) {
data.vgeo_point.match([&](const MTPDgeoPoint &point) {
mgInfo->setLocation({
qs(data.vaddress),
Data::LocationPoint(point)
});
}, [&](const MTPDgeoPointEmpty &) {
mgInfo->setLocation(ChannelLocation());
});
}, [&](const MTPDchannelLocationEmpty &) {
mgInfo->setLocation(ChannelLocation());
});
const auto now = mgInfo->getLocation();
const auto nowValue = now ? *now : ChannelLocation();
if (was != now || (was && wasValue != nowValue)) {
Notify::peerUpdatedDelayed(
this,
Notify::PeerUpdate::Flag::ChannelLocation);
}
}
const ChannelLocation *ChannelData::getLocation() const {
return mgInfo ? mgInfo->getLocation() : nullptr;
}
void ChannelData::setLinkedChat(ChannelData *linked) {
if (_linkedChat != linked) {
_linkedChat = linked;
@ -600,11 +640,14 @@ void ApplyChannelUpdate(
? update.vkicked_count.v
: 0);
channel->setInviteLink(update.vexported_invite.match([&](
const MTPDchatInviteExported & data) {
const MTPDchatInviteExported &data) {
return qs(data.vlink);
}, [&](const MTPDchatInviteEmpty &) {
return QString();
}));
channel->setLocation(update.has_location()
? update.vlocation
: MTPChannelLocation(MTP_channelLocationEmpty()));
channel->setLinkedChat(update.has_linked_chat_id()
? channel->owner().channelLoaded(update.vlinked_chat_id.v)
: nullptr);

View File

@ -9,6 +9,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_peer.h"
#include "data/data_pts_waiter.h"
#include "data/data_location.h"
struct ChannelLocation {
QString address;
Data::LocationPoint point;
friend inline bool operator==(
const ChannelLocation &a,
const ChannelLocation &b) {
return a.address.isEmpty()
? b.address.isEmpty()
: (a.address == b.address && a.point == b.point);
}
friend inline bool operator!=(
const ChannelLocation &a,
const ChannelLocation &b) {
return !(a == b);
}
};
class MegagroupInfo {
public:
@ -34,6 +53,9 @@ public:
ChatData *getMigrateFromChat() const;
void setMigrateFromChat(ChatData *chat);
const ChannelLocation *getLocation() const;
void setLocation(const ChannelLocation &location);
std::deque<not_null<UserData*>> lastParticipants;
base::flat_map<not_null<UserData*>, Admin> lastAdmins;
base::flat_map<not_null<UserData*>, Restricted> lastRestricted;
@ -57,6 +79,7 @@ public:
private:
ChatData *_migratedFrom = nullptr;
ChannelLocation _location;
};
@ -79,7 +102,8 @@ public:
static constexpr auto kEssentialFullFlags = 0
| MTPDchannelFull::Flag::f_can_view_participants
| MTPDchannelFull::Flag::f_can_set_username
| MTPDchannelFull::Flag::f_can_set_stickers;
| MTPDchannelFull::Flag::f_can_set_stickers
| MTPDchannelFull::Flag::f_location;
using FullFlags = Data::Flags<
MTPDchannelFull::Flags,
kEssentialFullFlags>;
@ -206,9 +230,15 @@ public:
bool isBroadcast() const {
return flags() & MTPDchannel::Flag::f_broadcast;
}
bool isPublic() const {
bool hasUsername() const {
return flags() & MTPDchannel::Flag::f_username;
}
bool hasLocation() const {
return fullFlags() & MTPDchannelFull::Flag::f_location;
}
bool isPublic() const {
return hasUsername() || hasLocation();
}
bool amCreator() const {
return flags() & MTPDchannel::Flag::f_creator;
}
@ -279,6 +309,9 @@ public:
QString inviteLink() const;
bool canHaveInviteLink() const;
void setLocation(const MTPChannelLocation &data);
const ChannelLocation *getLocation() const;
void setLinkedChat(ChannelData *linked);
ChannelData *linkedChat() const;

View File

@ -0,0 +1,44 @@
/*
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/data_location.h"
#include "ui/image/image.h"
#include "data/data_file_origin.h"
namespace Data {
namespace {
GeoPointLocation ComputeLocation(const Data::LocationPoint &point) {
const auto scale = 1 + (cScale() * cIntRetinaFactor()) / 200;
const auto zoom = 13 + (scale - 1);
const auto w = st::locationSize.width() / scale;
const auto h = st::locationSize.height() / scale;
auto result = GeoPointLocation();
result.lat = point.lat();
result.lon = point.lon();
result.access = point.accessHash();
result.width = w;
result.height = h;
result.zoom = zoom;
result.scale = scale;
return result;
}
} // namespace
LocationThumbnail::LocationThumbnail(const LocationPoint &point)
: point(point)
, thumb(Images::Create(ComputeLocation(point))) {
}
void LocationThumbnail::load(FileOrigin origin) {
thumb->load(origin);
}
} // namespace Data

View File

@ -0,0 +1,99 @@
/*
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 Data {
struct FileOrigin;
class LocationPoint {
public:
LocationPoint() = default;
explicit LocationPoint(const MTPDgeoPoint &point)
: _lat(point.vlat.v)
, _lon(point.vlong.v)
, _access(point.vaccess_hash.v) {
}
QString latAsString() const {
return AsString(_lat);
}
QString lonAsString() const {
return AsString(_lon);
}
MTPGeoPoint toMTP() const {
return MTP_geoPoint(
MTP_double(_lon),
MTP_double(_lat),
MTP_long(_access));
}
float64 lat() const {
return _lat;
}
float64 lon() const {
return _lon;
}
uint64 accessHash() const {
return _access;
}
inline size_t hash() const {
#ifndef OS_MAC_OLD
return QtPrivate::QHashCombine().operator()(
std::hash<float64>()(_lat),
_lon);
#else // OS_MAC_OLD
const auto h1 = std::hash<float64>()(_lat);
const auto h2 = std::hash<float64>()(_lon);
return ((h1 << 16) | (h1 >> 16)) ^ h2;
#endif // OS_MAC_OLD
}
private:
static QString AsString(float64 value) {
constexpr auto kPrecision = 6;
return QString::number(value, 'f', kPrecision);
}
friend inline bool operator==(const LocationPoint &a, const LocationPoint &b) {
return (a._lat == b._lat) && (a._lon == b._lon);
}
friend inline bool operator<(const LocationPoint &a, const LocationPoint &b) {
return (a._lat < b._lat) || ((a._lat == b._lat) && (a._lon < b._lon));
}
float64 _lat = 0;
float64 _lon = 0;
uint64 _access = 0;
};
struct LocationThumbnail {
LocationThumbnail(const LocationPoint &point);
LocationPoint point;
ImagePtr thumb;
void load(FileOrigin origin);
};
} // namespace Data
namespace std {
template <>
struct hash<Data::LocationPoint> {
size_t operator()(const Data::LocationPoint &value) const {
return value.hash();
}
};
} // namespace std

View File

@ -168,7 +168,7 @@ const Invoice *Media::invoice() const {
return nullptr;
}
LocationData *Media::location() const {
LocationThumbnail *Media::location() const {
return nullptr;
}
@ -861,17 +861,17 @@ std::unique_ptr<HistoryMedia> MediaContact::createView(
MediaLocation::MediaLocation(
not_null<HistoryItem*> parent,
const LocationCoords &coords)
: MediaLocation(parent, coords, QString(), QString()) {
const LocationPoint &point)
: MediaLocation(parent, point, QString(), QString()) {
}
MediaLocation::MediaLocation(
not_null<HistoryItem*> parent,
const LocationCoords &coords,
const LocationPoint &point,
const QString &title,
const QString &description)
: Media(parent)
, _location(parent->history()->owner().location(coords))
, _location(parent->history()->owner().location(point))
, _title(title)
, _description(description) {
}
@ -879,12 +879,12 @@ MediaLocation::MediaLocation(
std::unique_ptr<Media> MediaLocation::clone(not_null<HistoryItem*> parent) {
return std::make_unique<MediaLocation>(
parent,
_location->coords,
_location->point,
_title,
_description);
}
LocationData *MediaLocation::location() const {
LocationThumbnail *MediaLocation::location() const {
return _location;
}
@ -915,7 +915,7 @@ TextForMimeData MediaLocation::clipboardText() const {
if (!descriptionResult.text.isEmpty()) {
result.append(std::move(descriptionResult));
}
result.append(LocationClickHandler(_location->coords).dragText());
result.append(LocationClickHandler(_location->point).dragText());
return result;
}

View File

@ -9,8 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class HistoryItem;
class HistoryMedia;
class LocationCoords;
struct LocationData;
namespace base {
template <typename Enum>
@ -29,6 +27,9 @@ class Element;
namespace Data {
class LocationPoint;
struct LocationThumbnail;
enum class CallFinishReason : char {
Missed,
Busy,
@ -76,7 +77,7 @@ public:
virtual const Call *call() const;
virtual GameData *game() const;
virtual const Invoice *invoice() const;
virtual LocationData *location() const;
virtual LocationThumbnail *location() const;
virtual PollData *poll() const;
virtual bool uploading() const;
@ -226,16 +227,16 @@ class MediaLocation : public Media {
public:
MediaLocation(
not_null<HistoryItem*> parent,
const LocationCoords &coords);
const LocationPoint &point);
MediaLocation(
not_null<HistoryItem*> parent,
const LocationCoords &coords,
const LocationPoint &point,
const QString &title,
const QString &description);
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
LocationData *location() const override;
LocationThumbnail *location() const override;
QString chatListText() const override;
QString notificationText() const override;
QString pinnedTextSubstring() const override;
@ -248,7 +249,7 @@ public:
not_null<HistoryItem*> realParent) override;
private:
not_null<LocationData*> _location;
not_null<LocationThumbnail*> _location;
QString _title;
QString _description;

View File

@ -2885,14 +2885,13 @@ void Session::applyUpdate(const MTPDupdateChatDefaultBannedRights &update) {
}
}
not_null<LocationData*> Session::location(const LocationCoords &coords) {
auto i = _locations.find(coords);
if (i == _locations.cend()) {
i = _locations.emplace(
coords,
std::make_unique<LocationData>(coords)).first;
}
return i->second.get();
not_null<LocationThumbnail*> Session::location(const LocationPoint &point) {
const auto i = _locations.find(point);
return (i != _locations.cend())
? i->second.get()
: _locations.emplace(
point,
std::make_unique<LocationThumbnail>(point)).first->second.get();
}
void Session::registerPhotoItem(

View File

@ -58,7 +58,7 @@ struct SavedCredentials;
namespace Data {
class Folder;
class LocationPoint;
class WallPaper;
class Session final {
@ -521,8 +521,8 @@ public:
not_null<PollData*> processPoll(const MTPPoll &data);
not_null<PollData*> processPoll(const MTPDmessageMediaPoll &data);
[[nodiscard]] not_null<LocationData*> location(
const LocationCoords &coords);
[[nodiscard]] not_null<LocationThumbnail*> location(
const LocationPoint &point);
void registerPhotoItem(
not_null<const PhotoData*> photo,
@ -895,8 +895,8 @@ private:
not_null<const WebPageData*>,
base::flat_set<not_null<ViewElement*>>> _webpageViews;
std::unordered_map<
LocationCoords,
std::unique_ptr<LocationData>> _locations;
LocationPoint,
std::unique_ptr<LocationThumbnail>> _locations;
std::unordered_map<
PollId,
std::unique_ptr<PollData>> _polls;

View File

@ -667,7 +667,7 @@ void GenerateItems(
const auto address = qs(data.vaddress);
const auto link = data.vgeo_point.match([&](const MTPDgeoPoint &data) {
return textcmdLink(
LocationClickHandler::Url(LocationCoords(data)),
LocationClickHandler::Url(Data::LocationPoint(data)),
address);
}, [&](const MTPDgeoPointEmpty &) {
return address;

View File

@ -18,23 +18,6 @@ namespace {
constexpr auto kCoordPrecision = 8;
constexpr auto kMaxHttpRedirects = 5;
GeoPointLocation ComputeLocation(const LocationCoords &coords) {
const auto scale = 1 + (cScale() * cIntRetinaFactor()) / 200;
const auto zoom = 13 + (scale - 1);
const auto w = st::locationSize.width() / scale;
const auto h = st::locationSize.height() / scale;
auto result = GeoPointLocation();
result.lat = coords.lat();
result.lon = coords.lon();
result.access = coords.accessHash();
result.width = w;
result.height = h;
result.zoom = zoom;
result.scale = scale;
return result;
}
} // namespace
QString LocationClickHandler::copyToClipboardText() const {
@ -46,25 +29,16 @@ QString LocationClickHandler::copyToClipboardContextItemText() const {
}
void LocationClickHandler::onClick(ClickContext context) const {
if (!psLaunchMaps(_coords)) {
if (!psLaunchMaps(_point)) {
QDesktopServices::openUrl(_text);
}
}
void LocationClickHandler::setup() {
_text = Url(_coords);
_text = Url(_point);
}
QString LocationClickHandler::Url(const LocationCoords &coords) {
const auto latlon = coords.latAsString() + ',' + coords.lonAsString();
QString LocationClickHandler::Url(const Data::LocationPoint &point) {
const auto latlon = point.latAsString() + ',' + point.lonAsString();
return qsl("https://maps.google.com/maps?q=") + latlon + qsl("&ll=") + latlon + qsl("&z=16");
}
LocationData::LocationData(const LocationCoords &coords)
: coords(coords)
, thumb(Images::Create(ComputeLocation(coords))) {
}
void LocationData::load(Data::FileOrigin origin) {
thumb->load(origin);
}

View File

@ -7,98 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class LocationCoords {
public:
LocationCoords() = default;
explicit LocationCoords(const MTPDgeoPoint &point)
: _lat(point.vlat.v)
, _lon(point.vlong.v)
, _access(point.vaccess_hash.v) {
}
QString latAsString() const {
return asString(_lat);
}
QString lonAsString() const {
return asString(_lon);
}
MTPGeoPoint toMTP() const {
return MTP_geoPoint(
MTP_double(_lon),
MTP_double(_lat),
MTP_long(_access));
}
float64 lat() const {
return _lat;
}
float64 lon() const {
return _lon;
}
uint64 accessHash() const {
return _access;
}
inline size_t hash() const {
#ifndef OS_MAC_OLD
return QtPrivate::QHashCombine().operator()(
std::hash<float64>()(_lat),
_lon);
#else // OS_MAC_OLD
const auto h1 = std::hash<float64>()(_lat);
const auto h2 = std::hash<float64>()(_lon);
return ((h1 << 16) | (h1 >> 16)) ^ h2;
#endif // OS_MAC_OLD
}
private:
static QString asString(float64 value) {
constexpr auto kPrecision = 6;
return QString::number(value, 'f', kPrecision);
}
friend inline bool operator==(const LocationCoords &a, const LocationCoords &b) {
return (a._lat == b._lat) && (a._lon == b._lon);
}
friend inline bool operator<(const LocationCoords &a, const LocationCoords &b) {
return (a._lat < b._lat) || ((a._lat == b._lat) && (a._lon < b._lon));
}
float64 _lat = 0;
float64 _lon = 0;
uint64 _access = 0;
};
namespace std {
template <>
struct hash<LocationCoords> {
size_t operator()(const LocationCoords &value) const {
return value.hash();
}
};
} // namespace std
struct LocationData {
LocationData(const LocationCoords &coords);
LocationCoords coords;
ImagePtr thumb;
void load(Data::FileOrigin origin);
};
#include "data/data_location.h"
class LocationClickHandler : public ClickHandler {
public:
LocationClickHandler(const LocationCoords &coords) : _coords(coords) {
LocationClickHandler(const Data::LocationPoint &point)
: _point(point) {
setup();
}
static QString Url(const LocationCoords &coords);
static QString Url(const Data::LocationPoint &coords);
void onClick(ClickContext context) const override;
@ -116,7 +34,7 @@ public:
private:
void setup();
LocationCoords _coords;
Data::LocationPoint _point;
QString _text;
};

View File

@ -789,7 +789,7 @@ std::unique_ptr<Data::Media> HistoryMessage::CreateMedia(
return media.vgeo.match([&](const MTPDgeoPoint &point) -> Result {
return std::make_unique<Data::MediaLocation>(
item,
LocationCoords(point));
Data::LocationPoint(point));
}, [](const MTPDgeoPointEmpty &) -> Result {
return nullptr;
});
@ -797,7 +797,7 @@ std::unique_ptr<Data::Media> HistoryMessage::CreateMedia(
return media.vgeo.match([&](const MTPDgeoPoint &point) -> Result {
return std::make_unique<Data::MediaLocation>(
item,
LocationCoords(point));
Data::LocationPoint(point));
}, [](const MTPDgeoPointEmpty &) -> Result {
return nullptr;
});
@ -805,7 +805,7 @@ std::unique_ptr<Data::Media> HistoryMessage::CreateMedia(
return media.vgeo.match([&](const MTPDgeoPoint &point) -> Result {
return std::make_unique<Data::MediaLocation>(
item,
LocationCoords(point),
Data::LocationPoint(point),
qs(media.vtitle),
qs(media.vaddress));
}, [](const MTPDgeoPointEmpty &data) -> Result {

View File

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h"
#include "ui/text_options.h"
#include "data/data_file_origin.h"
#include "data/data_location.h"
#include "styles/style_history.h"
namespace {
@ -26,14 +27,14 @@ using TextState = HistoryView::TextState;
HistoryLocation::HistoryLocation(
not_null<Element*> parent,
not_null<LocationData*> location,
not_null<Data::LocationThumbnail*> location,
const QString &title,
const QString &description)
: HistoryMedia(parent)
, _data(location)
, _title(st::msgMinWidth)
, _description(st::msgMinWidth)
, _link(std::make_shared<LocationClickHandler>(_data->coords)) {
, _link(std::make_shared<LocationClickHandler>(_data->point)) {
if (!title.isEmpty()) {
_title.setText(
st::webPageTitleStyle,

View File

@ -9,14 +9,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/media/history_media.h"
class LocationCoords;
struct LocationData;
namespace Data {
struct LocationThumbnail;
} // namespace Data
class HistoryLocation : public HistoryMedia {
public:
HistoryLocation(
not_null<Element*> parent,
not_null<LocationData*> location,
not_null<Data::LocationThumbnail*> location,
const QString &title = QString(),
const QString &description = QString());
@ -58,7 +59,7 @@ private:
TextSelection toDescriptionSelection(TextSelection selection) const;
TextSelection fromDescriptionSelection(TextSelection selection) const;
LocationData *_data;
const not_null<Data::LocationThumbnail*> _data;
Ui::Text::String _title, _description;
ClickHandlerPtr _link;

View File

@ -521,7 +521,7 @@ void CopyPostLink(FullMsgId itemId) {
const auto channel = item->history()->peer->asChannel();
Assert(channel != nullptr);
Ui::Toast::Show(channel->isPublic()
Ui::Toast::Show(channel->hasUsername()
? tr::lng_channel_public_link_copied(tr::now)
: tr::lng_context_about_private_link(tr::now));
}

View File

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/labels.h"
#include "ui/toast/toast.h"
#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
#include "history/history_location_manager.h" // LocationClickHandler.
#include "boxes/abstract_box.h"
#include "boxes/confirm_box.h"
#include "boxes/peer_list_box.h"
@ -249,11 +250,11 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
result->setContextCopyText(contextCopyText);
return result;
};
if (auto user = _peer->asUser()) {
if (Auth().supportMode()) {
if (const auto user = _peer->asUser()) {
if (user->session().supportMode()) {
addInfoLineGeneric(
Auth().supportHelper().infoLabelValue(user),
Auth().supportHelper().infoTextValue(user));
user->session().supportHelper().infoLabelValue(user),
user->session().supportHelper().infoTextValue(user));
}
addInfoOneLine(
@ -273,26 +274,20 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
auto linkText = LinkValue(
_peer
) | rpl::map([](const QString &link) {
auto result = TextWithEntities{ link, {} };
if (!link.isEmpty()) {
auto remove = qstr("https://");
if (result.text.startsWith(remove)) {
result.text.remove(0, remove.size());
}
result.entities.push_back({
EntityType::CustomUrl,
0,
result.text.size(),
link });
}
return result;
return link.isEmpty()
? TextWithEntities()
: Ui::Text::Link(
(link.startsWith(qstr("https://"))
? link.mid(qstr("https://").size())
: link),
link);
});
auto link = addInfoOneLine(
tr::lng_info_link_label(),
std::move(linkText),
QString());
link->setClickHandlerFilter([peer = _peer](auto&&...) {
auto link = Core::App().createInternalLinkFull(
const auto link = Core::App().createInternalLinkFull(
peer->userName());
if (!link.isEmpty()) {
QApplication::clipboard()->setText(link);
@ -300,6 +295,24 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
}
return false;
});
if (const auto channel = _peer->asChannel()) {
auto locationText = LocationValue(
channel
) | rpl::map([](const ChannelLocation *location) {
return location
? Ui::Text::Link(
location->address,
LocationClickHandler::Url(location->point))
: TextWithEntities();
});
addInfoOneLine(
tr::lng_info_location_label(),
std::move(locationText),
QString()
)->setLinksTrusted();
}
addInfoLine(tr::lng_info_about_label(), AboutValue(_peer));
}
if (!_peer->isSelf()) {

View File

@ -58,8 +58,8 @@ rpl::producer<TextWithEntities> BioValue(not_null<UserData*> user) {
auto PlainUsernameValue(not_null<PeerData*> peer) {
return Notify::PeerUpdateValue(
peer,
Notify::PeerUpdate::Flag::UsernameChanged
peer,
Notify::PeerUpdate::Flag::UsernameChanged
) | rpl::map([peer] {
return peer->userName();
});
@ -113,6 +113,16 @@ rpl::producer<QString> LinkValue(not_null<PeerData*> peer) {
});
}
rpl::producer<const ChannelLocation*> LocationValue(
not_null<ChannelData*> channel) {
return Notify::PeerUpdateValue(
channel,
Notify::PeerUpdate::Flag::ChannelLocation
) | rpl::map([=] {
return channel->getLocation();
});
}
rpl::producer<bool> NotificationsEnabledValue(not_null<PeerData*> peer) {
return rpl::merge(
Notify::PeerUpdateValue(

View File

@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <rpl/map.h>
#include "observer_peer.h"
struct ChannelLocation;
namespace Ui {
class RpWidget;
template <typename Widget>
@ -36,6 +38,8 @@ rpl::producer<TextWithEntities> BioValue(not_null<UserData*> user);
rpl::producer<TextWithEntities> UsernameValue(not_null<UserData*> user);
rpl::producer<TextWithEntities> AboutValue(not_null<PeerData*> peer);
rpl::producer<QString> LinkValue(not_null<PeerData*> peer);
rpl::producer<const ChannelLocation*> LocationValue(
not_null<ChannelData*> channel);
rpl::producer<bool> NotificationsEnabledValue(not_null<PeerData*> peer);
rpl::producer<bool> IsContactValue(not_null<UserData*> user);
rpl::producer<bool> CanInviteBotToGroupValue(not_null<UserData*> user);

View File

@ -1025,9 +1025,10 @@ Article::Article(not_null<Context*> context, Result *result, bool withThumb) : I
, _withThumb(withThumb)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
LocationCoords location;
if (!_link && result->getLocationCoords(&location)) {
_link = std::make_shared<LocationClickHandler>(location);
if (!_link) {
if (const auto point = result->getLocationPoint()) {
_link = std::make_shared<LocationClickHandler>(*point);
}
}
_thumbLetter = getResultThumbLetter();
}

View File

@ -223,17 +223,16 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
return nullptr;
}
LocationCoords coords;
if (result->getLocationCoords(&coords)) {
if (const auto point = result->getLocationPoint()) {
const auto scale = 1 + (cScale() * cIntRetinaFactor()) / 200;
const auto zoom = 15 + (scale - 1);
const auto w = st::inlineThumbSize / scale;
const auto h = st::inlineThumbSize / scale;
auto location = GeoPointLocation();
location.lat = coords.lat();
location.lon = coords.lon();
location.access = coords.accessHash();
location.lat = point->lat();
location.lon = point->lon();
location.access = point->accessHash();
location.width = w;
location.height = h;
location.zoom = zoom;
@ -329,8 +328,8 @@ QString Result::getErrorOnSend(History *history) const {
return sendData->getErrorOnSend(this, history);
}
bool Result::getLocationCoords(LocationCoords *outLocation) const {
return sendData->getLocationCoords(outLocation);
std::optional<Data::LocationPoint> Result::getLocationPoint() const {
return sendData->getLocationPoint();
}
QString Result::getLayoutTitle() const {

View File

@ -8,7 +8,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
class FileLoader;
class LocationCoords;
namespace Data {
class LocationPoint;
} // namespace Data
namespace InlineBots {
@ -55,7 +58,7 @@ public:
QString getErrorOnSend(History *history) const;
// interface for Layout:: usage
bool getLocationCoords(LocationCoords *outLocation) const;
std::optional<Data::LocationPoint> getLocationPoint() const;
QString getLayoutTitle() const;
QString getLayoutDescription() const;

View File

@ -45,8 +45,8 @@ public:
virtual bool hasLocationCoords() const {
return false;
}
virtual bool getLocationCoords(LocationCoords *outLocation) const {
return false;
virtual std::optional<Data::LocationPoint> getLocationPoint() const {
return std::nullopt;
}
virtual QString getLayoutTitle(const Result *owner) const;
virtual QString getLayoutDescription(const Result *owner) const;
@ -121,14 +121,12 @@ public:
bool hasLocationCoords() const override {
return true;
}
bool getLocationCoords(LocationCoords *outLocation) const override {
Assert(outLocation != nullptr);
*outLocation = _location;
return true;
std::optional<Data::LocationPoint> getLocationPoint() const override {
return _location;
}
private:
LocationCoords _location;
Data::LocationPoint _location;
};
@ -153,14 +151,12 @@ public:
bool hasLocationCoords() const override {
return true;
}
bool getLocationCoords(LocationCoords *outLocation) const override {
Assert(outLocation != nullptr);
*outLocation = _location;
return true;
std::optional<Data::LocationPoint> getLocationPoint() const override {
return _location;
}
private:
LocationCoords _location;
Data::LocationPoint _location;
QString _venueId, _provider, _title, _address;
};

View File

@ -66,6 +66,7 @@ struct PeerUpdate {
ChannelStickersChanged = (1 << 18),
ChannelPromotedChanged = (1 << 19),
ChannelLinkedChat = (1 << 20),
ChannelLocation = (1 << 21),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }

View File

@ -478,6 +478,6 @@ bool linuxMoveFile(const char *from, const char *to) {
return true;
}
bool psLaunchMaps(const LocationCoords &coords) {
bool psLaunchMaps(const Data::LocationPoint &point) {
return false;
}

View File

@ -10,7 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <execinfo.h>
#include <signal.h>
class LocationCoords;
namespace Data {
class LocationPoint;
} // namespace Data
namespace Platform {
@ -104,4 +106,4 @@ public:
bool linuxMoveFile(const char *from, const char *to);
bool psLaunchMaps(const LocationCoords &coords);
bool psLaunchMaps(const Data::LocationPoint &point);

View File

@ -9,7 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/mac/specific_mac_p.h"
class LocationCoords;
namespace Data {
class LocationPoint;
} // namespace Data
namespace Platform {
@ -108,4 +110,4 @@ QString strStyleOfInterface();
QString strTitleWrapClass();
QString strTitleClass();
bool psLaunchMaps(const LocationCoords &coords);
bool psLaunchMaps(const Data::LocationPoint &point);

View File

@ -288,8 +288,8 @@ QByteArray psPathBookmark(const QString &path) {
return objc_pathBookmark(path);
}
bool psLaunchMaps(const LocationCoords &coords) {
return QDesktopServices::openUrl(qsl("https://maps.apple.com/?q=Point&z=16&ll=%1,%2").arg(coords.latAsString()).arg(coords.lonAsString()));
bool psLaunchMaps(const Data::LocationPoint &point) {
return QDesktopServices::openUrl(qsl("https://maps.apple.com/?q=Point&z=16&ll=%1,%2").arg(point.latAsString()).arg(point.lonAsString()));
}
QString strNotificationAboutThemeChange() {

View File

@ -583,6 +583,6 @@ void psWriteDump() {
#endif // TDESKTOP_DISABLE_CRASH_REPORTS
}
bool psLaunchMaps(const LocationCoords &coords) {
return QDesktopServices::openUrl(qsl("bingmaps:?lvl=16&collection=point.%1_%2_Point").arg(coords.latAsString()).arg(coords.lonAsString()));
bool psLaunchMaps(const Data::LocationPoint &point) {
return QDesktopServices::openUrl(qsl("bingmaps:?lvl=16&collection=point.%1_%2_Point").arg(point.latAsString()).arg(point.lonAsString()));
}

View File

@ -9,7 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/win/wrapper_windows_h.h"
class LocationCoords;
namespace Data {
class LocationPoint;
} // namespace Data
namespace Platform {
@ -107,4 +109,4 @@ public:
};
bool psLaunchMaps(const LocationCoords &coords);
bool psLaunchMaps(const Data::LocationPoint &point);

View File

@ -506,7 +506,7 @@ void Filler::addChannelActions(not_null<ChannelData*> channel) {
[channel] { Auth().api().joinChannel(channel); });
}
if (_source != PeerMenuSource::ChatsList) {
auto needReport = !channel->amCreator()
const auto needReport = !channel->amCreator()
&& (!isGroup || channel->isPublic());
if (needReport) {
_addAction(tr::lng_profile_report(tr::now), [channel] {

View File

@ -190,6 +190,8 @@
<(src_loc)/data/data_game.h
<(src_loc)/data/data_groups.cpp
<(src_loc)/data/data_groups.h
<(src_loc)/data/data_location.cpp
<(src_loc)/data/data_location.h
<(src_loc)/data/data_media_types.cpp
<(src_loc)/data/data_media_types.h
<(src_loc)/data/data_messages.cpp