mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-19 14:01:05 +00:00
version 0.5.8 prepared, hashtag search support, clearhistory crash fix
This commit is contained in:
parent
54095eb515
commit
c93e4e27fe
@ -1,5 +1,5 @@
|
||||
AppVersionStr=0.5.7
|
||||
AppVersion=5007
|
||||
AppVersionStr=0.5.8
|
||||
AppVersion=5008
|
||||
|
||||
if [ -d "./../Mac/Release/deploy/$AppVersionStr" ]; then
|
||||
echo "Deploy folder for version $AppVersionStr already exists!"
|
||||
|
@ -1,5 +1,5 @@
|
||||
AppVersionStr=0.5.7
|
||||
AppVersion=5007
|
||||
AppVersionStr=0.5.8
|
||||
AppVersion=5008
|
||||
|
||||
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
|
||||
echo "Deploy folder for version $AppVersionStr already exists!"
|
||||
|
@ -308,6 +308,8 @@ lng_context_open_link: "Open Link";
|
||||
lng_context_copy_link: "Copy Link";
|
||||
lng_context_open_email: "Write to this address";
|
||||
lng_context_copy_email: "Copy email address";
|
||||
lng_context_open_hashtag: "Search by hashtag";
|
||||
lng_context_copy_hashtag: "Copy hashtag";
|
||||
lng_context_open_image: "Open Image";
|
||||
lng_context_save_image: "Save Image As...";
|
||||
lng_context_forward_image: "Forward Image";
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
#define MyAppShortName "Telegram"
|
||||
#define MyAppName "Telegram Win (Unofficial)"
|
||||
#define MyAppVersion "0.5.7"
|
||||
#define MyAppVersionZero "0.5.7"
|
||||
#define MyAppFullVersion "0.5.7.0"
|
||||
#define MyAppVersion "0.5.8"
|
||||
#define MyAppVersionZero "0.5.8"
|
||||
#define MyAppFullVersion "0.5.8.0"
|
||||
#define MyAppPublisher "Telegram (Unofficial)"
|
||||
#define MyAppURL "https://tdesktop.com"
|
||||
#define MyAppExeName "Telegram.exe"
|
||||
|
@ -1955,4 +1955,10 @@ namespace App {
|
||||
}
|
||||
}
|
||||
|
||||
void searchByHashtag(const QString &tag) {
|
||||
if (App::main()) {
|
||||
App::main()->searchMessages(tag);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -187,4 +187,6 @@ namespace App {
|
||||
void setProxySettings(QNetworkAccessManager &manager);
|
||||
void setProxySettings(QTcpSocket &socket);
|
||||
|
||||
void searchByHashtag(const QString &tag);
|
||||
|
||||
};
|
||||
|
@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
static const int32 AppVersion = 5007;
|
||||
static const wchar_t *AppVersionStr = L"0.5.7";
|
||||
static const int32 AppVersion = 5008;
|
||||
static const wchar_t *AppVersionStr = L"0.5.8";
|
||||
#ifdef Q_OS_WIN
|
||||
static const wchar_t *AppName = L"Telegram Win (Unofficial)";
|
||||
#else
|
||||
|
@ -1118,6 +1118,16 @@ void DialogsWidget::onNeedSearchMessages() {
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsWidget::searchMessages(const QString &query) {
|
||||
if (_filter.text() != query) {
|
||||
_filter.setText(query);
|
||||
_filter.updatePlaceholder();
|
||||
onFilterUpdate();
|
||||
_searchTimer.stop();
|
||||
onSearchMessages();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsWidget::onSearchMore(MsgId minMsgId) {
|
||||
if (!_searchRequest && !_searchFull) {
|
||||
_searchRequest = MTP::send(MTPmessages_Search(MTP_inputPeerEmpty(), MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(minMsgId), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, !minMsgId), rpcFail(&DialogsWidget::searchFailed));
|
||||
|
@ -170,6 +170,7 @@ public:
|
||||
|
||||
void enableShadow(bool enable = true);
|
||||
|
||||
void searchMessages(const QString &query);
|
||||
void onSearchMore(MsgId minMsgId);
|
||||
void clearFiltered();
|
||||
|
||||
|
@ -19,6 +19,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "text.h"
|
||||
|
||||
#include "lang.h"
|
||||
#include "app.h"
|
||||
|
||||
#include <private/qharfbuzz_p.h>
|
||||
|
||||
@ -111,8 +112,9 @@ namespace {
|
||||
}
|
||||
|
||||
const QRegularExpression reDomain(QString::fromUtf8("(?<![A-Za-z\\$0-9А-Яа-яёЁ\\-\\_%=])(?:([a-zA-Z]+)://)?((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){1,5}([A-Za-zрф\\-\\d]{2,22}))"));
|
||||
const QRegularExpression reMailName(QString::fromUtf8("[a-zA-Z\\-_\\.0-9]{1,256}$"));
|
||||
const QRegularExpression reMailStart(QString::fromUtf8("^[a-zA-Z\\-_\\.0-9]{1,256}\\@"));
|
||||
const QRegularExpression reMailName(qsl("[a-zA-Z\\-_\\.0-9]{1,256}$"));
|
||||
const QRegularExpression reMailStart(qsl("^[a-zA-Z\\-_\\.0-9]{1,256}\\@"));
|
||||
const QRegularExpression reHashtag(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])#[A-Za-z_\\.0-9]{4,20}([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"));
|
||||
QSet<int32> validProtocols, validTopDomains;
|
||||
void initLinkSets();
|
||||
|
||||
@ -298,7 +300,7 @@ public:
|
||||
return Qt::LayoutDirectionAuto;
|
||||
}
|
||||
|
||||
void prepareLinks() { // support emails!
|
||||
void prepareLinks() { // support emails and hashtags!
|
||||
if (validProtocols.empty()) {
|
||||
initLinkSets();
|
||||
}
|
||||
@ -313,73 +315,98 @@ public:
|
||||
}
|
||||
}
|
||||
QRegularExpressionMatch mDomain = reDomain.match(src, offset);
|
||||
if (!mDomain.hasMatch()) break;
|
||||
|
||||
int32 domainOffset = mDomain.capturedStart(), domainEnd = mDomain.capturedEnd();
|
||||
if (domainOffset > nextCmd) {
|
||||
const QChar *after = skipCommand(srcData + nextCmd, srcData + len);
|
||||
if (after > srcData + nextCmd && domainOffset < (after - srcData)) {
|
||||
nextCmd = offset = after - srcData;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
QString protocol = mDomain.captured(1).toLower();
|
||||
QString topDomain = mDomain.captured(3).toLower();
|
||||
|
||||
bool isProtocolValid = protocol.isEmpty() || validProtocols.contains(hashCrc32(protocol.constData(), protocol.size() * sizeof(QChar)));
|
||||
bool isTopDomainValid = validTopDomains.contains(hashCrc32(topDomain.constData(), topDomain.size() * sizeof(QChar)));
|
||||
|
||||
if (!isProtocolValid || !isTopDomainValid) {
|
||||
offset = domainEnd;
|
||||
continue;
|
||||
}
|
||||
QRegularExpressionMatch mHashtag = reHashtag.match(src, offset);
|
||||
if (!mDomain.hasMatch() && !mHashtag.hasMatch()) break;
|
||||
|
||||
LinkRange link;
|
||||
if (protocol.isEmpty() && domainOffset > offset + 1 && *(start + domainOffset - 1) == QChar('@')) {
|
||||
QString forMailName = src.mid(offset, domainOffset - offset - 1);
|
||||
QRegularExpressionMatch mMailName = reMailName.match(forMailName);
|
||||
if (mMailName.hasMatch()) {
|
||||
int32 mailOffset = offset + mMailName.capturedStart();
|
||||
if (mailOffset < offset) {
|
||||
mailOffset = offset;
|
||||
}
|
||||
link.from = start + mailOffset;
|
||||
link.len = domainEnd - mailOffset;
|
||||
int32 domainOffset = mDomain.hasMatch() ? mDomain.capturedStart() : INT_MAX,
|
||||
domainEnd = mDomain.hasMatch() ? mDomain.capturedEnd() : INT_MAX,
|
||||
hashtagOffset = mHashtag.hasMatch() ? mHashtag.capturedStart() : INT_MAX,
|
||||
hashtagEnd = mHashtag.hasMatch() ? mHashtag.capturedEnd() : INT_MAX;
|
||||
if (mHashtag.hasMatch()) {
|
||||
if (!mHashtag.capturedRef(1).isEmpty()) {
|
||||
++hashtagOffset;
|
||||
}
|
||||
if (!mHashtag.capturedRef(2).isEmpty()) {
|
||||
--hashtagEnd;
|
||||
}
|
||||
}
|
||||
if (!link.from || !link.len) {
|
||||
link.from = start + domainOffset;
|
||||
|
||||
QStack<const QChar*> parenth;
|
||||
const QChar *p = start + mDomain.capturedEnd();
|
||||
for (; p < end; ++p) {
|
||||
QChar ch(*p);
|
||||
if (chIsLinkEnd(ch)) break; // link finished
|
||||
if (chIsAlmostLinkEnd(ch)) {
|
||||
const QChar *endTest = p + 1;
|
||||
while (endTest < end && chIsAlmostLinkEnd(*endTest)) {
|
||||
++endTest;
|
||||
}
|
||||
if (endTest >= end || chIsLinkEnd(*endTest)) {
|
||||
break; // link finished at p
|
||||
}
|
||||
p = endTest;
|
||||
ch = *p;
|
||||
}
|
||||
if (ch == '(' || ch == '[' || ch == '{' || ch == '<') {
|
||||
parenth.push(p);
|
||||
} else if (ch == ')' || ch == ']' || ch == '}' || ch == '>') {
|
||||
if (parenth.isEmpty()) break;
|
||||
const QChar *q = parenth.pop(), open(*q);
|
||||
if ((ch == ')' && open != '(') || (ch == ']' && open != '[') || (ch == '}' && open != '{') || (ch == '>' && open != '<')) {
|
||||
p = q;
|
||||
break;
|
||||
}
|
||||
if (hashtagOffset < domainOffset) {
|
||||
if (hashtagOffset > nextCmd) {
|
||||
const QChar *after = skipCommand(srcData + nextCmd, srcData + len);
|
||||
if (after > srcData + nextCmd && hashtagOffset < (after - srcData)) {
|
||||
nextCmd = offset = after - srcData;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
link.len = p - link.from;
|
||||
link.from = start + hashtagOffset;
|
||||
link.len = start + hashtagEnd - link.from;
|
||||
} else {
|
||||
if (domainOffset > nextCmd) {
|
||||
const QChar *after = skipCommand(srcData + nextCmd, srcData + len);
|
||||
if (after > srcData + nextCmd && domainOffset < (after - srcData)) {
|
||||
nextCmd = offset = after - srcData;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
QString protocol = mDomain.captured(1).toLower();
|
||||
QString topDomain = mDomain.captured(3).toLower();
|
||||
|
||||
bool isProtocolValid = protocol.isEmpty() || validProtocols.contains(hashCrc32(protocol.constData(), protocol.size() * sizeof(QChar)));
|
||||
bool isTopDomainValid = validTopDomains.contains(hashCrc32(topDomain.constData(), topDomain.size() * sizeof(QChar)));
|
||||
|
||||
if (!isProtocolValid || !isTopDomainValid) {
|
||||
offset = domainEnd;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (protocol.isEmpty() && domainOffset > offset + 1 && *(start + domainOffset - 1) == QChar('@')) {
|
||||
QString forMailName = src.mid(offset, domainOffset - offset - 1);
|
||||
QRegularExpressionMatch mMailName = reMailName.match(forMailName);
|
||||
if (mMailName.hasMatch()) {
|
||||
int32 mailOffset = offset + mMailName.capturedStart();
|
||||
if (mailOffset < offset) {
|
||||
mailOffset = offset;
|
||||
}
|
||||
link.from = start + mailOffset;
|
||||
link.len = domainEnd - mailOffset;
|
||||
}
|
||||
}
|
||||
if (!link.from || !link.len) {
|
||||
link.from = start + domainOffset;
|
||||
|
||||
QStack<const QChar*> parenth;
|
||||
const QChar *p = start + mDomain.capturedEnd();
|
||||
for (; p < end; ++p) {
|
||||
QChar ch(*p);
|
||||
if (chIsLinkEnd(ch)) break; // link finished
|
||||
if (chIsAlmostLinkEnd(ch)) {
|
||||
const QChar *endTest = p + 1;
|
||||
while (endTest < end && chIsAlmostLinkEnd(*endTest)) {
|
||||
++endTest;
|
||||
}
|
||||
if (endTest >= end || chIsLinkEnd(*endTest)) {
|
||||
break; // link finished at p
|
||||
}
|
||||
p = endTest;
|
||||
ch = *p;
|
||||
}
|
||||
if (ch == '(' || ch == '[' || ch == '{' || ch == '<') {
|
||||
parenth.push(p);
|
||||
} else if (ch == ')' || ch == ']' || ch == '}' || ch == '>') {
|
||||
if (parenth.isEmpty()) break;
|
||||
const QChar *q = parenth.pop(), open(*q);
|
||||
if ((ch == ')' && open != '(') || (ch == ']' && open != '[') || (ch == '}' && open != '{') || (ch == '>' && open != '<')) {
|
||||
p = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
link.len = p - link.from;
|
||||
}
|
||||
}
|
||||
lnkRanges.push_back(link);
|
||||
|
||||
@ -421,9 +448,12 @@ public:
|
||||
}
|
||||
|
||||
void getLinkData(const QString &original, QString &result, int32 &fullDisplayed) {
|
||||
if (reMailStart.match(original).hasMatch()) {
|
||||
if (!original.isEmpty() && original.at(0) == '#') {
|
||||
result = original;
|
||||
fullDisplayed = -1;
|
||||
fullDisplayed = -2; // hashtag
|
||||
} else if (reMailStart.match(original).hasMatch()) {
|
||||
result = original;
|
||||
fullDisplayed = -1; // email
|
||||
} else {
|
||||
QUrl url(original), good(url.isValid() ? url.toEncoded() : "");
|
||||
QString readable = good.isValid() ? good.toDisplayString() : original;
|
||||
@ -725,7 +755,9 @@ public:
|
||||
_t->_links.resize(lnkIndex);
|
||||
const TextLinkData &data(links[lnkIndex - maxLnkIndex - 1]);
|
||||
TextLinkPtr lnk;
|
||||
if (data.fullDisplayed < 0) { // email
|
||||
if (data.fullDisplayed < -1) { // hashtag
|
||||
lnk = TextLinkPtr(new HashtagLink(data.url));
|
||||
} else if (data.fullDisplayed < 0) { // email
|
||||
lnk = TextLinkPtr(new EmailLink(data.url));
|
||||
} else {
|
||||
lnk = TextLinkPtr(new TextLink(data.url, data.fullDisplayed > 0));
|
||||
@ -755,7 +787,7 @@ private:
|
||||
TextLinkData(const QString &url = QString(), int32 fullDisplayed = 1) : url(url), fullDisplayed(fullDisplayed) {
|
||||
}
|
||||
QString url;
|
||||
int32 fullDisplayed; // < 0 - email
|
||||
int32 fullDisplayed; // -2 - hashtag, -1 - email
|
||||
};
|
||||
typedef QVector<TextLinkData> TextLinks;
|
||||
TextLinks links;
|
||||
@ -874,6 +906,12 @@ namespace {
|
||||
|
||||
}
|
||||
|
||||
void HashtagLink::onClick(Qt::MouseButton button) const {
|
||||
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
|
||||
App::searchByHashtag(_tag);
|
||||
}
|
||||
}
|
||||
|
||||
class TextPainter {
|
||||
public:
|
||||
|
||||
|
@ -288,6 +288,32 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class HashtagLink : public ITextLink {
|
||||
public:
|
||||
|
||||
HashtagLink(const QString &tag) : _tag(tag) {
|
||||
}
|
||||
|
||||
const QString &text() const {
|
||||
return _tag;
|
||||
}
|
||||
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
|
||||
const QString &readable() const {
|
||||
return _tag;
|
||||
}
|
||||
|
||||
QString encoded() const {
|
||||
return _tag;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QString _tag;
|
||||
|
||||
};
|
||||
|
||||
static const QChar TextCommand(0x0010);
|
||||
enum TextCommands {
|
||||
TextCommandBold = 0x01,
|
||||
|
@ -1472,6 +1472,7 @@ void History::clear(bool leaveItems) {
|
||||
setMsgCount(0);
|
||||
if (!leaveItems) {
|
||||
setUnreadCount(0);
|
||||
last = 0;
|
||||
}
|
||||
height = 0;
|
||||
oldLoaded = false;
|
||||
|
@ -630,6 +630,13 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
}
|
||||
_menu->addAction(lang(lng_context_open_email), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_email), this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||
} else if (_contextMenuLnk && dynamic_cast<HashtagLink*>(_contextMenuLnk.data())) {
|
||||
_menu = new QMenu(historyWidget);
|
||||
if (isUponSelected > 0) {
|
||||
_menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
|
||||
}
|
||||
_menu->addAction(lang(lng_context_open_hashtag), this, SLOT(openContextUrl()))->setEnabled(true);
|
||||
_menu->addAction(lang(lng_context_copy_hashtag), this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||
} else {
|
||||
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data());
|
||||
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
|
||||
|
@ -536,6 +536,10 @@ void MainWidget::stopAnimActive() {
|
||||
history.stopAnimActive();
|
||||
}
|
||||
|
||||
void MainWidget::searchMessages(const QString &query) {
|
||||
dialogs.searchMessages(query);
|
||||
}
|
||||
|
||||
void MainWidget::partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result) {
|
||||
const MTPDmessages_affectedHistory &d(result.c_messages_affectedHistory());
|
||||
App::main()->updUpdated(d.vpts.v, 0, 0, d.vseq.v);
|
||||
|
@ -197,6 +197,8 @@ public:
|
||||
uint64 animActiveTime() const;
|
||||
void stopAnimActive();
|
||||
|
||||
void searchMessages(const QString &query);
|
||||
|
||||
~MainWidget();
|
||||
|
||||
signals:
|
||||
|
@ -11,7 +11,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.5.7</string>
|
||||
<string>0.5.8</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>NOTE</key>
|
||||
|
Binary file not shown.
@ -1453,7 +1453,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.5.1;
|
||||
CURRENT_PROJECT_VERSION = 0.5.8;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
@ -1471,7 +1471,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 0.5.1;
|
||||
CURRENT_PROJECT_VERSION = 0.5.8;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
|
||||
@ -1495,9 +1495,9 @@
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 0.5.7;
|
||||
CURRENT_PROJECT_VERSION = 0.5.8;
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.5;
|
||||
DYLIB_CURRENT_VERSION = 0.5.7;
|
||||
DYLIB_CURRENT_VERSION = 0.5.8;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
@ -1620,10 +1620,10 @@
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.5.7;
|
||||
CURRENT_PROJECT_VERSION = 0.5.8;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.5;
|
||||
DYLIB_CURRENT_VERSION = 0.5.7;
|
||||
DYLIB_CURRENT_VERSION = 0.5.8;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user