version 0.5.8 prepared, hashtag search support, clearhistory crash fix

This commit is contained in:
John Preston 2014-07-16 10:58:36 +04:00
parent 54095eb515
commit c93e4e27fe
18 changed files with 182 additions and 83 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -1955,4 +1955,10 @@ namespace App {
}
}
void searchByHashtag(const QString &tag) {
if (App::main()) {
App::main()->searchMessages(tag);
}
}
}

View File

@ -187,4 +187,6 @@ namespace App {
void setProxySettings(QNetworkAccessManager &manager);
void setProxySettings(QTcpSocket &socket);
void searchByHashtag(const QString &tag);
};

View File

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

View File

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

View File

@ -170,6 +170,7 @@ public:
void enableShadow(bool enable = true);
void searchMessages(const QString &query);
void onSearchMore(MsgId minMsgId);
void clearFiltered();

View File

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

View File

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

View File

@ -1472,6 +1472,7 @@ void History::clear(bool leaveItems) {
setMsgCount(0);
if (!leaveItems) {
setUnreadCount(0);
last = 0;
}
height = 0;
oldLoaded = false;

View File

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

View File

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

View File

@ -197,6 +197,8 @@ public:
uint64 animActiveTime() const;
void stopAnimActive();
void searchMessages(const QString &query);
~MainWidget();
signals:

View File

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

View File

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