diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index 4c295b562a..cf55209f11 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -507,16 +507,16 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_action_changed_title_channel" = "Channel name was changed to «{title}»"; "lng_action_created_chat" = "{from} created group «{title}»"; "lng_action_created_channel" = "Channel «{title}» created"; -"lng_action_group_migrate" = "The group was converted to a supergroup"; +"lng_action_group_migrate" = "The group was upgraded to a supergroup"; "lng_profile_migrate_reached" = "{count:_not_used_|# member|# members} limit reached"; -"lng_profile_migrate_about" = "If you'd like to go over this limit, you can convert your group to a supergroup. In supergroups:"; +"lng_profile_migrate_about" = "If you'd like to go over this limit, you can upgrade your group to a supergroup. In supergroups:"; "lng_profile_migrate_feature1" = "— The members limit is {count:_not_used_|# user|# users}"; "lng_profile_migrate_feature2" = "— New members see the entire chat history"; "lng_profile_migrate_feature3" = "— Admins delete messages for everyone"; "lng_profile_migrate_feature4" = "— Notifications are muted by default"; "lng_profile_migrate_button" = "Upgrade to supergroup"; -"lng_profile_migrate_sure" = "Are you sure you want to convert this group to supergroup? This action cannot be undone."; +"lng_profile_migrate_sure" = "Are you sure you want to upgrade this group to supergroup? This action cannot be undone."; "lng_channel_comments_count" = "{count:_not_used_|# comment|# comments}"; "lng_channel_hide_comments" = "Hide comments"; diff --git a/Telegram/SourceFiles/_other/genlang.cpp b/Telegram/SourceFiles/_other/genlang.cpp index 2f66b5c359..60e77ec79d 100644 --- a/Telegram/SourceFiles/_other/genlang.cpp +++ b/Telegram/SourceFiles/_other/genlang.cpp @@ -276,11 +276,11 @@ QString escapeCpp(const QByteArray &key, QString value) { } res.append(' ').append('u').append('"').append('\\').append('x').append(QString("%1").arg(ch->unicode(), 4, 16, QChar('0'))).append('"'); } else { - if (!instr) { - res.append(' ').append('u').append('"'); - instr = true; - } if (ch->unicode() == '\\' || ch->unicode() == '\n' || ch->unicode() == '\r' || ch->unicode() == '"') { + if (!instr) { + res.append(' ').append('u').append('"'); + instr = true; + } res.append('\\'); if (ch->unicode() == '\\' || ch->unicode() == '"') { res.append(*ch); @@ -294,16 +294,26 @@ QString escapeCpp(const QByteArray &key, QString value) { if (ch + 3 >= e || (ch + 1)->unicode() != TextCommandLangTag || (ch + 2)->unicode() > 0x007F || (ch + 2)->unicode() < 0x0020 || *(ch + 3) != TextCommand) { throw Exception(QString("Bad value for key '%1'").arg(QLatin1String(key))); } else { + if (instr) { + res.append('"'); + instr = false; + } + res.append(' ').append('u').append('"'); res.append('\\').append('x').append(QString("%1").arg(ch->unicode(), 2, 16, QChar('0'))); res.append('\\').append('x').append(QString("%1").arg((ch + 1)->unicode(), 2, 16, QChar('0'))); res.append('\\').append('x').append(QString("%1").arg((ch + 2)->unicode(), 2, 16, QChar('0'))); res.append('\\').append('x').append(QString("%1").arg((ch + 3)->unicode(), 2, 16, QChar('0'))); + res.append('"'); ch += 3; } } else { throw Exception(QString("Bad value for key '%1'").arg(QLatin1String(key))); } } else { + if (!instr) { + res.append(' ').append('u').append('"'); + instr = true; + } res.append(*ch); } } diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index de2fad8890..4461772be1 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -437,7 +437,8 @@ void ApiWrap::requestPeers(const QList &peers) { void ApiWrap::requestLastParticipants(ChannelData *peer, bool fromStart) { if (!peer || !peer->isMegagroup()) return; - if ((peer->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated) || peer->lastParticipantsCountOutdated()) { + bool needAdmins = peer->amEditor(), adminsOutdated = (peer->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated); + if ((needAdmins && adminsOutdated) || peer->lastParticipantsCountOutdated()) { fromStart = true; } QMap::iterator i = _participantsRequests.find(peer); @@ -521,7 +522,9 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP if (!peer->mgInfo || result.type() != mtpc_channels_channelParticipants) return; + History *h = 0; if (bots) { + h = App::historyLoaded(peer->id); peer->mgInfo->bots.clear(); peer->mgInfo->botStatus = -1; } else if (fromStart) { @@ -535,6 +538,7 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP App::feedUsers(d.vusers); bool added = false, needBotsInfos = false; int32 botStatus = peer->mgInfo->botStatus; + bool keyboardBotFound = !h || !h->lastKeyboardFrom; for (QVector::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) { int32 userId = 0; bool admin = false; @@ -556,6 +560,9 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP needBotsInfos = true; } } + if (!keyboardBotFound && u->id == h->lastKeyboardFrom) { + keyboardBotFound = true; + } } else { if (peer->mgInfo->lastParticipants.indexOf(u) < 0) { peer->mgInfo->lastParticipants.push_back(u); @@ -573,6 +580,10 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP if (needBotsInfos) { requestFullPeer(peer); } + if (!keyboardBotFound) { + h->clearLastKeyboard(); + if (App::main()) App::main()->updateBotKeyboard(h); + } if (d.vcount.v > peer->count) { peer->count = d.vcount.v; } else if (v.count() > peer->count) { diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 143f00a712..0241ee9ab9 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -190,6 +190,9 @@ namespace App { if (cHasPasscode()) { cSetHasPasscode(false); } + if (audioPlayer()) { + audioPlayer()->stopAndClear(); + } if (w) { w->tempDirDelete(Local::ClearManagerAll); w->notifyClearFast(); @@ -696,9 +699,8 @@ namespace App { } chat->botStatus = botStatus; if (!found) { - h->lastKeyboardId = 0; - h->lastKeyboardFrom = 0; - if (App::main()) App::main()->updateBotKeyboard(); + h->clearLastKeyboard(); + if (App::main()) App::main()->updateBotKeyboard(h); } } } @@ -794,9 +796,8 @@ namespace App { History *h = App::historyLoaded(chat->id); if (h && h->lastKeyboardFrom == user->id) { - h->lastKeyboardId = 0; - h->lastKeyboardFrom = 0; - if (App::main()) App::main()->updateBotKeyboard(); + h->clearLastKeyboard(); + if (App::main()) App::main()->updateBotKeyboard(h); } } if (chat->botStatus > 0 && user->botInfo) { diff --git a/Telegram/SourceFiles/audio.cpp b/Telegram/SourceFiles/audio.cpp index a512c4ac98..9bcb196415 100644 --- a/Telegram/SourceFiles/audio.cpp +++ b/Telegram/SourceFiles/audio.cpp @@ -269,6 +269,27 @@ void audioFinish() { cSetHasAudioPlayer(false); } +void AudioPlayer::Msg::clearData() { + fname = QString(); + data = QByteArray(); + position = duration = 0; + frequency = AudioVoiceMsgFrequency; + skipStart = skipEnd = 0; + loading = false; + started = 0; + state = AudioPlayerStopped; + if (alIsSource(source)) { + alSourceStop(source); + } + for (int32 i = 0; i < 3; ++i) { + if (samplesCount[i]) { + alSourceUnqueueBuffers(source, 1, buffers + i); + samplesCount[i] = 0; + } + } + nextBuffer = 0; +} + AudioPlayer::AudioPlayer() : _audioCurrent(0), _songCurrent(0), _fader(new AudioPlayerFader(&_faderThread)), _loader(new AudioPlayerLoaders(&_loaderThread)) { @@ -642,10 +663,64 @@ void AudioPlayer::seek(int64 position) { } void AudioPlayer::stop(MediaOverviewType type) { - fadedStop(type); switch (type) { - case OverviewAudios: if (_audioData[_audioCurrent].audio) emit updated(_audioData[_audioCurrent].audio); break; - case OverviewDocuments: if (_songData[_songCurrent].song) emit updated(_songData[_songCurrent].song); break; + case OverviewAudios: { + AudioMsgId current; + { + QMutexLocker lock(&playerMutex); + current = _audioData[_audioCurrent].audio; + fadedStop(type); + } + if (current) emit updated(current); + } break; + + case OverviewDocuments: { + SongMsgId current; + { + QMutexLocker lock(&playerMutex); + current = _songData[_songCurrent].song; + fadedStop(type); + } + if (current) emit updated(current); + } break; + } +} + +void AudioPlayer::stopAndClear() { + AudioMsg *current_audio = 0; + { + QMutexLocker lock(&playerMutex); + current_audio = &_audioData[_audioCurrent]; + if (current_audio) { + setStoppedState(current_audio); + } + } + SongMsg *current_song = 0; + { + QMutexLocker lock(&playerMutex); + current_song = &_songData[_songCurrent]; + if (current_song) { + setStoppedState(current_song); + } + } + if (current_song) { + emit updated(current_song->song); + } + if (current_audio) { + emit updated(current_audio->audio); + } + { + QMutexLocker lock(&playerMutex); + for (int32 index = 0; index < AudioVoiceMsgSimultaneously; ++index) { + if (_audioData[index].audio) { + emit loaderOnCancel(_audioData[index].audio); + } + _audioData[index].clear(); + if (_songData[index].song) { + emit loaderOnCancel(_songData[index].song); + } + _songData[index].clear(); + } } } diff --git a/Telegram/SourceFiles/audio.h b/Telegram/SourceFiles/audio.h index 7a4da6e8f1..97fa0c342c 100644 --- a/Telegram/SourceFiles/audio.h +++ b/Telegram/SourceFiles/audio.h @@ -59,6 +59,8 @@ public: void seek(int64 position); // type == OverviewDocuments void stop(MediaOverviewType type); + void stopAndClear(); + void currentState(AudioMsgId *audio, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0); void currentState(SongMsgId *song, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0); @@ -109,12 +111,22 @@ private: bool checkCurrentALError(MediaOverviewType type); struct Msg { - Msg() : position(0), duration(0), frequency(AudioVoiceMsgFrequency), skipStart(0), skipEnd(0), loading(0), started(0), - state(AudioPlayerStopped), source(0), nextBuffer(0) { + Msg() : position(0) + , duration(0) + , frequency(AudioVoiceMsgFrequency) + , skipStart(0) + , skipEnd(0) + , loading(false) + , started(0) + , state(AudioPlayerStopped) + , source(0) + , nextBuffer(0) { memset(buffers, 0, sizeof(buffers)); memset(samplesCount, 0, sizeof(samplesCount)); } + void clearData(); + QString fname; QByteArray data; int64 position, duration; @@ -132,11 +144,19 @@ private: struct AudioMsg : public Msg { AudioMsg() { } + void clear() { + audio = AudioMsgId(); + Msg::clearData(); + } AudioMsgId audio; }; struct SongMsg : public Msg { SongMsg() { } + void clear() { + song = SongMsgId(); + Msg::clearData(); + } SongMsgId song; }; diff --git a/Telegram/SourceFiles/boxes/abstractbox.cpp b/Telegram/SourceFiles/boxes/abstractbox.cpp index 6a218b8d27..10c8d43933 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.cpp +++ b/Telegram/SourceFiles/boxes/abstractbox.cpp @@ -79,6 +79,7 @@ void BlueTitleClose::paintEvent(QPaintEvent *e) { AbstractBox::AbstractBox(int32 w) : LayeredWidget() , _maxHeight(0) , _hiding(false) +, _closed(false) , a_opacity(0, 1) , _blueTitle(false) , _blueClose(0) @@ -190,7 +191,10 @@ int32 AbstractBox::countHeight() const { } void AbstractBox::onClose() { - closePressed(); + if (!_closed) { + _closed = true; + closePressed(); + } emit closed(); } diff --git a/Telegram/SourceFiles/boxes/abstractbox.h b/Telegram/SourceFiles/boxes/abstractbox.h index 7028319aed..8f3d47f970 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.h +++ b/Telegram/SourceFiles/boxes/abstractbox.h @@ -94,7 +94,7 @@ private: int32 _maxHeight; int32 countHeight() const; - bool _hiding; + bool _hiding, _closed; QPixmap _cache; anim::fvalue a_opacity; diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index 6b974080ab..8039c47846 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -388,10 +388,12 @@ ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) { } else { data->inchat = false; } + data->onlineColor = false; data->check = _checkedContacts.contains(peer); data->name.setText(st::contactsNameFont, peer->name, _textNameOptions); if (peer->isUser()) { data->online = App::onlineText(peer->asUser(), _time); + data->onlineColor = App::onlineColorUse(peer->asUser(), _time); } else if (peer->isChat()) { ChatData *chat = peer->asChat(); if (!chat->amIn()) { @@ -471,7 +473,7 @@ void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, b } else { if (inverse) { p.setPen(st::white); - } else if ((user && (uname || App::onlineColorUse(user, _time))) || (peer->isChannel() && uname)) { + } else if ((user && (uname || data->onlineColor)) || (peer->isChannel() && uname)) { p.setPen(st::contactsStatusFgOnline); } else { p.setPen(sel ? st::contactsStatusFgOver : st::contactsStatusFg); @@ -1907,7 +1909,7 @@ void MembersInner::paintDialog(Painter &p, PeerData *peer, MemberData *data, boo } p.setFont(st::contactsStatusFont->f); - p.setPen(sel ? st::contactsStatusFgOver : st::contactsStatusFg); + p.setPen(sel ? st::contactsStatusFgOver : (data->onlineColor ? st::contactsStatusFgOnline : st::contactsStatusFg)); p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), data->online); } @@ -2028,7 +2030,9 @@ MembersInner::MemberData *MembersInner::data(int32 index) { } MemberData *result = _datas[index] = new MemberData(); result->name.setText(st::contactsNameFont, _rows[index]->name, _textNameOptions); - result->online = lng_mediaview_date_time(lt_date, _dates[index].date().toString(qsl("dd.MM.yy")), lt_time, _dates[index].time().toString(cTimeFormat())); + int32 t = unixtime(); + result->online = App::onlineText(_rows[index], t);// lng_mediaview_date_time(lt_date, _dates[index].date().toString(qsl("dd.MM.yy")), lt_time, _dates[index].time().toString(cTimeFormat())); + result->onlineColor = App::onlineColorUse(_rows[index], t); if (_filter == MembersFilterRecent) { result->canKick = (_channel->amCreator() || _channel->amEditor() || _channel->amModerator()) ? (_roles[index] == MemberRoleNone) : false; } else if (_filter == MembersFilterAdmins) { diff --git a/Telegram/SourceFiles/boxes/contactsbox.h b/Telegram/SourceFiles/boxes/contactsbox.h index 9dc4980023..994c547c7a 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.h +++ b/Telegram/SourceFiles/boxes/contactsbox.h @@ -152,6 +152,7 @@ private: struct ContactData { Text name; QString online; + bool onlineColor; bool inchat; bool check; }; @@ -370,6 +371,7 @@ private: struct MemberData { Text name; QString online; + bool onlineColor; bool canKick; }; diff --git a/Telegram/SourceFiles/boxes/passcodebox.cpp b/Telegram/SourceFiles/boxes/passcodebox.cpp index 784d23bf9c..b98f8957d1 100644 --- a/Telegram/SourceFiles/boxes/passcodebox.cpp +++ b/Telegram/SourceFiles/boxes/passcodebox.cpp @@ -356,6 +356,7 @@ void PasscodeBox::onSave(bool force) { return; } if (pwd != conf) { + _reenterPasscode.selectAll(); _reenterPasscode.setFocus(); _reenterPasscode.showError(); if (!conf.isEmpty()) { @@ -603,6 +604,8 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) { } else if (err == "CODE_INVALID") { _error = lang(lng_signin_wrong_code); update(); + _recoverCode.selectAll(); + _recoverCode.setFocus(); _recoverCode.showError(); return true; } else if (mtpIsFlood(error)) { diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index c61ae5eecc..e45797acc0 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -302,7 +302,7 @@ void DialogsInner::searchInPeerPaint(Painter &p, int32 w, bool onlyBackground) c QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height); // draw chat icon - if (_searchInPeer->isChat()) { + if (_searchInPeer->isChat() || _searchInPeer->isMegagroup()) { p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), App::sprite(), st::dlgChatImg); rectForName.setLeft(rectForName.left() + st::dlgImgSkip); } else if (_searchInPeer->isChannel()) { diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index 2a6be8b760..623714e48a 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -354,13 +354,15 @@ public: } } - void checkCommand() { - QChar c = ((ptr < end) ? *ptr : 0); - while (c == TextCommand) { + bool checkCommand() { + bool result = false; + for (QChar c = ((ptr < end) ? *ptr : 0); c == TextCommand; c = ((ptr < end) ? *ptr : 0)) { if (!readCommand()) { break; } + result = true; } + return result; } void checkEntities() { @@ -694,7 +696,11 @@ public: while (waitingEntity != entitiesEnd && waitingEntity->length <= 0) ++waitingEntity; for (; ptr <= end; ++ptr) { checkEntities(); - if (rich) checkCommand(); + if (rich) { + if (checkCommand()) { + checkEntities(); + } + } parseCurrentChar(); parseEmojiFromCurrent(); @@ -4476,6 +4482,47 @@ goodCanBreakEntity = canBreakEntity;\ return true; } +bool textcmdStartsLink(const QChar *start, int32 len, int32 commandOffset) { + if (commandOffset + 2 < len) { + if (*(start + commandOffset + 1) == TextCommandLinkIndex) { + return (*(start + commandOffset + 2) != 0); + } + return (*(start + commandOffset + 1) != TextCommandLinkText); + } + return false; +} + +bool checkTagStartInCommand(const QChar *start, int32 len, int32 tagStart, int32 &commandOffset, bool &commandIsLink, bool &inLink) { + bool inCommand = false; + const QChar *commandEnd = start + commandOffset; + while (commandOffset < len && tagStart > commandOffset) { // skip commands, evaluating are we in link or not + commandEnd = textSkipCommand(start + commandOffset, start + len); + if (commandEnd > start + commandOffset) { + if (tagStart < (commandEnd - start)) { + inCommand = true; + break; + } + for (commandOffset = commandEnd - start; commandOffset < len; ++commandOffset) { + if (*(start + commandOffset) == TextCommand) { + inLink = commandIsLink; + commandIsLink = textcmdStartsLink(start, len, commandOffset); + break; + } + } + if (commandOffset >= len) { + inLink = commandIsLink; + commandIsLink = false; + } + } else { + break; + } + } + if (inCommand) { + commandOffset = commandEnd - start; + } + return inCommand; +} + EntitiesInText textParseEntities(QString &text, int32 flags, bool rich) { // some code is duplicated in flattextarea.cpp! EntitiesInText result, mono; @@ -4487,15 +4534,22 @@ EntitiesInText textParseEntities(QString &text, int32 flags, bool rich) { // som if (withMono) { // parse mono entities (code and pre) QString newText; - int32 offset = 0, matchOffset = offset, len = text.size(), nextCmd = rich ? 0 : len; + int32 offset = 0, matchOffset = offset, len = text.size(), commandOffset = rich ? 0 : len; + bool inLink = false, commandIsLink = false; const QChar *start = text.constData(); for (; matchOffset < len;) { - if (nextCmd <= matchOffset) { - for (nextCmd = matchOffset; nextCmd < len; ++nextCmd) { - if (*(start + nextCmd) == TextCommand) { + if (commandOffset <= matchOffset) { + for (commandOffset = matchOffset; commandOffset < len; ++commandOffset) { + if (*(start + commandOffset) == TextCommand) { + inLink = commandIsLink; + commandIsLink = textcmdStartsLink(start, len, commandOffset); break; } } + if (commandOffset >= len) { + inLink = commandIsLink; + commandIsLink = false; + } } QRegularExpressionMatch mPre = _rePre.match(text, matchOffset); QRegularExpressionMatch mCode = _reCode.match(text, matchOffset), mTag; @@ -4533,12 +4587,11 @@ EntitiesInText textParseEntities(QString &text, int32 flags, bool rich) { // som tagEnd = codeEnd; mTag = mCode; } - if (tagStart > nextCmd) { - const QChar *after = textSkipCommand(start + nextCmd, start + len); - if (after > start + nextCmd && tagStart < (after - start)) { - nextCmd = matchOffset = after - start; - continue; - } + + bool inCommand = checkTagStartInCommand(start, len, tagStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + matchOffset = commandOffset; + continue; } if (newText.isEmpty()) newText.reserve(text.size()); @@ -4594,12 +4647,15 @@ EntitiesInText textParseEntities(QString &text, int32 flags, bool rich) { // som int32 monoEntity = 0, monoCount = mono.size(), monoTill = 0; initLinkSets(); - int32 len = text.size(), nextCmd = rich ? 0 : len; + int32 len = text.size(), commandOffset = rich ? 0 : len; + bool inLink = false, commandIsLink = false; const QChar *start = text.constData(), *end = start + text.size(); for (int32 offset = 0, matchOffset = offset, mentionSkip = 0; offset < len;) { - if (nextCmd <= offset) { - for (nextCmd = offset; nextCmd < len; ++nextCmd) { - if (*(start + nextCmd) == TextCommand) { + if (commandOffset <= offset) { + for (commandOffset = offset; commandOffset < len; ++commandOffset) { + if (*(start + commandOffset) == TextCommand) { + inLink = commandIsLink; + commandIsLink = textcmdStartsLink(start, len, commandOffset); break; } } @@ -4669,47 +4725,40 @@ EntitiesInText textParseEntities(QString &text, int32 flags, bool rich) { // som mDomain = mExplicitDomain; } if (mentionStart < hashtagStart && mentionStart < domainStart && mentionStart < botCommandStart) { - if (mentionStart > nextCmd) { - const QChar *after = textSkipCommand(start + nextCmd, start + len); - if (after > start + nextCmd && mentionStart < (after - start)) { - nextCmd = offset = matchOffset = after - start; - continue; - } + bool inCommand = checkTagStartInCommand(start, len, mentionStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + offset = matchOffset = commandOffset; + continue; } + lnkType = EntityInTextMention; lnkStart = mentionStart; lnkLength = mentionEnd - mentionStart; } else if (hashtagStart < domainStart && hashtagStart < botCommandStart) { - if (hashtagStart > nextCmd) { - const QChar *after = textSkipCommand(start + nextCmd, start + len); - if (after > start + nextCmd && hashtagStart < (after - start)) { - nextCmd = offset = matchOffset = after - start; - continue; - } + bool inCommand = checkTagStartInCommand(start, len, hashtagStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + offset = matchOffset = commandOffset; + continue; } lnkType = EntityInTextHashtag; lnkStart = hashtagStart; lnkLength = hashtagEnd - hashtagStart; } else if (botCommandStart < domainStart) { - if (botCommandStart > nextCmd) { - const QChar *after = textSkipCommand(start + nextCmd, start + len); - if (after > start + nextCmd && botCommandStart < (after - start)) { - nextCmd = offset = matchOffset = after - start; - continue; - } + bool inCommand = checkTagStartInCommand(start, len, botCommandStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + offset = matchOffset = commandOffset; + continue; } lnkType = EntityInTextBotCommand; lnkStart = botCommandStart; lnkLength = botCommandEnd - botCommandStart; } else { - if (domainStart > nextCmd) { - const QChar *after = textSkipCommand(start + nextCmd, start + len); - if (after > start + nextCmd && domainStart < (after - start)) { - nextCmd = offset = matchOffset = after - start; - continue; - } + bool inCommand = checkTagStartInCommand(start, len, domainStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + offset = matchOffset = commandOffset; + continue; } QString protocol = mDomain.captured(1).toLower(); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 8744a6c281..4da45f2342 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -369,6 +369,7 @@ History::History(const PeerId &peerId) : width(0), height(0) , lastKeyboardInited(false) , lastKeyboardUsed(false) , lastKeyboardId(0) +, lastKeyboardHiddenId(0) , lastKeyboardFrom(0) , sendRequestId(0) , textCachedFor(0) @@ -385,8 +386,13 @@ History::History(const PeerId &peerId) : width(0), height(0) } void History::clearLastKeyboard() { + if (lastKeyboardId) { + if (lastKeyboardId == lastKeyboardHiddenId) { + lastKeyboardHiddenId = 0; + } + lastKeyboardId = 0; + } lastKeyboardInited = true; - lastKeyboardId = 0; lastKeyboardFrom = 0; } @@ -1498,12 +1504,12 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo case mtpc_messageActionChatAddUser: { const MTPDmessageActionChatAddUser &d(action.c_messageActionChatAddUser()); if (peer->isMegagroup()) { - peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated; const QVector &v(d.vusers.c_vector().v); for (int32 i = 0, l = v.size(); i < l; ++i) { if (UserData *user = App::userLoaded(peerFromUser(v.at(i)))) { if (peer->asChannel()->mgInfo->lastParticipants.indexOf(user) < 0) { peer->asChannel()->mgInfo->lastParticipants.push_front(user); + peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated; } if (user->botInfo) { peer->asChannel()->mgInfo->bots.insert(user, true); @@ -1543,6 +1549,7 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo PeerId uid = peerFromUser(d.vuser_id); if (lastKeyboardFrom == uid) { clearLastKeyboard(); + if (App::main()) App::main()->updateBotKeyboard(this); } if (peer->isMegagroup()) { if (UserData *user = App::userLoaded(uid)) { @@ -1789,7 +1796,6 @@ HistoryItem *History::addNewItem(HistoryBlock *to, bool newBlock, HistoryItem *a lastAuthors = &peer->asChat()->lastAuthors; } else if (peer->isMegagroup()) { lastAuthors = &peer->asChannel()->mgInfo->lastParticipants; - peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated; if (adding->from()->asUser()->botInfo) { peer->asChannel()->mgInfo->bots.insert(adding->from()->asUser(), true); if (peer->asChannel()->mgInfo->botStatus != 0 && peer->asChannel()->mgInfo->botStatus < 2) { @@ -1801,6 +1807,8 @@ HistoryItem *History::addNewItem(HistoryBlock *to, bool newBlock, HistoryItem *a int prev = lastAuthors->indexOf(adding->from()->asUser()); if (prev > 0) { lastAuthors->removeAt(prev); + } else if (prev < 0 && peer->isMegagroup()) { // nothing is outdated if just reordering + peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated; } if (prev) { lastAuthors->push_front(adding->from()->asUser()); @@ -1828,7 +1836,7 @@ HistoryItem *History::addNewItem(HistoryBlock *to, bool newBlock, HistoryItem *a if (peer->isChat()) { botNotInChat = adding->from()->isUser() && (!peer->canWrite() || !peer->asChat()->participants.isEmpty()) && !peer->asChat()->participants.contains(adding->from()->asUser()); } else if (peer->isMegagroup()) { - botNotInChat = adding->from()->isUser() && (!peer->canWrite() || !peer->asChannel()->mgInfo->bots.isEmpty()) && !peer->asChannel()->mgInfo->bots.contains(adding->from()->asUser()); + botNotInChat = adding->from()->isUser() && (!peer->canWrite() || peer->asChannel()->mgInfo->botStatus != 0) && !peer->asChannel()->mgInfo->bots.contains(adding->from()->asUser()); } if (botNotInChat) { clearLastKeyboard(); @@ -2013,7 +2021,6 @@ void History::addOlderSlice(const QVector &slice, const QVectorisMegagroup()) { lastAuthors = &peer->asChannel()->mgInfo->lastParticipants; markupSenders = &peer->asChannel()->mgInfo->markupSenders; - peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated; } for (int32 i = block->items.size(); i > 0; --i) { HistoryItem *item = block->items[i - 1]; @@ -2036,8 +2043,13 @@ void History::addOlderSlice(const QVector &slice, const QVectorfrom()->id) { if (lastAuthors) { // chats - if (item->from()->isUser() && !lastAuthors->contains(item->from()->asUser())) { - lastAuthors->push_back(item->from()->asUser()); + if (item->from()->isUser()) { + if (!lastAuthors->contains(item->from()->asUser())) { + lastAuthors->push_back(item->from()->asUser()); + if (peer->isMegagroup()) { + peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated; + } + } } } if (markupSenders) { // chats with bots @@ -2054,7 +2066,7 @@ void History::addOlderSlice(const QVector &slice, const QVectorisChat()) { botNotInChat = (!peer->canWrite() || !peer->asChat()->participants.isEmpty()) && item->from()->isUser() && !peer->asChat()->participants.contains(item->from()->asUser()); } else if (peer->isMegagroup()) { - botNotInChat = (!peer->canWrite() || !peer->asChannel()->mgInfo->bots.isEmpty()) && item->from()->isUser() && !peer->asChannel()->mgInfo->bots.contains(item->from()->asUser()); + botNotInChat = (!peer->canWrite() || peer->asChannel()->mgInfo->botStatus != 0) && item->from()->isUser() && !peer->asChannel()->mgInfo->bots.contains(item->from()->asUser()); } if (wasKeyboardHide || botNotInChat) { clearLastKeyboard(); @@ -3014,9 +3026,8 @@ void HistoryItem::destroy() { history()->fixLastMessage(wasAtBottom); } if (history()->lastKeyboardId == id) { - history()->lastKeyboardId = 0; - history()->lastKeyboardFrom = 0; - if (App::main()) App::main()->updateBotKeyboard(); + history()->clearLastKeyboard(); + if (App::main()) App::main()->updateBotKeyboard(history()); } HistoryMedia *m = getMedia(true); MediaOverviewType t = m ? mediaToOverviewType(m->type()) : OverviewCount; @@ -6589,11 +6600,13 @@ void HistoryMessage::setMedia(const MTPMessageMedia *media, bool allowEmitResize void HistoryMessage::setText(const QString &text, const EntitiesInText &entities) { if (!_media || !text.isEmpty()) { // !justMedia() + textstyleSet(&((out() && !fromChannel()) ? st::outTextStyle : st::inTextStyle)); if (_media && _media->isDisplayed()) { _text.setMarkedText(st::msgFont, text, entities, itemTextOptions(this)); } else { _text.setMarkedText(st::msgFont, text + skipBlock(), entities, itemTextOptions(this)); } + textstyleRestore(); if (id > 0) { for (int32 i = 0, l = entities.size(); i != l; ++i) { if (entities.at(i).type == EntityInTextUrl || entities.at(i).type == EntityInTextCustomUrl || entities.at(i).type == EntityInTextEmail) { @@ -6810,6 +6823,8 @@ void HistoryMessage::draw(Painter &p, uint32 selection) const { } HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), selected, InfoDisplayDefault); } + + textstyleRestore(); } void HistoryMessage::drawMessageText(Painter &p, const QRect &trect, uint32 selection) const { @@ -6818,8 +6833,6 @@ void HistoryMessage::drawMessageText(Painter &p, const QRect &trect, uint32 sele uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF; uint16 selectedTo = (selection == FullItemSel) ? 0 : selection & 0xFFFF; _text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignLeft, 0, -1, selectedFrom, selectedTo); - - textstyleRestore(); } int32 HistoryMessage::resize(int32 width) { @@ -6837,7 +6850,9 @@ int32 HistoryMessage::resize(int32 width) { int32 nwidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 0); if (nwidth != _textWidth) { _textWidth = nwidth; + textstyleSet(&((out() && !fromChannel()) ? st::outTextStyle : st::inTextStyle)); _textHeight = _text.countHeight(nwidth); + textstyleRestore(); } if (width >= _maxw) { _height = _minh; @@ -6972,8 +6987,10 @@ void HistoryMessage::getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorStat } trect.setBottom(trect.bottom() - _media->height() - st::msgPadding.bottom()); } + textstyleSet(&((out() && !fromChannel()) ? st::outTextStyle : st::inTextStyle)); bool inText = false; _text.getState(lnk, inText, x - trect.x(), y - trect.y(), trect.width()); + textstyleRestore(); if (inDate) { state = HistoryInDateCursorState; @@ -7022,7 +7039,9 @@ void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, if (_media && _media->isDisplayed()) { trect.setBottom(trect.bottom() - _media->height() - st::msgPadding.bottom()); } + textstyleSet(&((out() && !fromChannel()) ? st::outTextStyle : st::inTextStyle)); _text.getSymbol(symbol, after, upon, x - trect.x(), y - trect.y(), trect.width()); + textstyleRestore(); } void HistoryMessage::drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { @@ -7750,7 +7769,9 @@ void HistoryServiceMsg::setMessageByAction(const MTPmessageAction &action) { default: from = QString(); break; } + textstyleSet(&st::serviceTextStyle); _text.setText(st::msgServiceFont, text, _historySrvOptions); + textstyleRestore(); if (!from.isEmpty()) { _text.setLink(1, TextLinkPtr(new PeerLink(_from))); } @@ -7800,7 +7821,9 @@ QString HistoryServiceMsg::inReplyText() const { } void HistoryServiceMsg::setServiceText(const QString &text) { + textstyleSet(&st::serviceTextStyle); _text.setText(st::msgServiceFont, text, _historySrvOptions); + textstyleRestore(); initDimensions(); } @@ -7856,7 +7879,9 @@ int32 HistoryServiceMsg::resize(int32 width) { int32 nwidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 0); if (nwidth != _textWidth) { _textWidth = nwidth; + textstyleSet(&st::serviceTextStyle); _textHeight = _text.countHeight(nwidth); + textstyleRestore(); } if (width >= _maxw) { _height = _minh; @@ -7892,8 +7917,10 @@ void HistoryServiceMsg::getState(TextLinkPtr &lnk, HistoryCursorState &state, in } QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding)); if (trect.contains(x, y)) { + textstyleSet(&st::serviceTextStyle); bool inText = false; _text.getState(lnk, inText, x - trect.x(), y - trect.y(), trect.width(), Qt::AlignCenter); + textstyleRestore(); state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; } else if (_media) { _media->getState(lnk, state, x - st::msgServiceMargin.left() - (width - _media->maxWidth()) / 2, y - st::msgServiceMargin.top() - height - st::msgServiceMargin.top(), this); @@ -7912,7 +7939,9 @@ void HistoryServiceMsg::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 height -= st::msgServiceMargin.top() + _media->height(); } QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding)); - return _text.getSymbol(symbol, after, upon, x - trect.x(), y - trect.y(), trect.width(), Qt::AlignCenter); + textstyleSet(&st::serviceTextStyle); + _text.getSymbol(symbol, after, upon, x - trect.x(), y - trect.y(), trect.width(), Qt::AlignCenter); + textstyleRestore(); } void HistoryServiceMsg::drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { @@ -8033,12 +8062,14 @@ void HistoryCollapse::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3 HistoryJoined::HistoryJoined(History *history, HistoryBlock *block, const QDateTime &inviteDate, UserData *inviter, int32 flags) : HistoryServiceMsg(history, block, clientMsgId(), inviteDate, QString(), flags) { + textstyleSet(&st::serviceTextStyle); if (peerToUser(inviter->id) == MTP::authedId()) { _text.setText(st::msgServiceFont, lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined), _historySrvOptions); } else { _text.setText(st::msgServiceFont, history->isMegagroup() ? lng_action_add_you_group(lt_from, textcmdLink(1, inviter->name)) : lng_action_add_you(lt_from, textcmdLink(1, inviter->name)), _historySrvOptions); _text.setLink(1, TextLinkPtr(new PeerLink(inviter))); } + textstyleRestore(); } HistoryUnreadBar::HistoryUnreadBar(History *history, HistoryBlock *block, int32 count, const QDateTime &date) : HistoryItem(history, block, clientMsgId(), 0, date, 0), freezed(false) { diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 6e108a3fa0..fd6f49e18b 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -320,7 +320,7 @@ public: bool mute; bool lastKeyboardInited, lastKeyboardUsed; - MsgId lastKeyboardId; + MsgId lastKeyboardId, lastKeyboardHiddenId; PeerId lastKeyboardFrom; mtpRequestId sendRequestId; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 86ebda7237..7cb850fec1 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -2595,7 +2595,6 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) , a_recordOver(0, 0), a_recordDown(0, 0), a_recordCancel(st::recordCancel->c, st::recordCancel->c) , _recordCancelWidth(st::recordFont->width(lang(lng_record_cancel))) , _kbShown(false) -, _kbWasHidden(false) , _kbReplyTo(0) , _kbScroll(this, st::botKbScroll) , _keyboard() @@ -3131,31 +3130,6 @@ void HistoryWidget::calcNextReplyReturn() { if (!_replyReturn) updateControlsVisibility(); } -bool HistoryWidget::kbWasHidden() { - return _kbWasHidden; -} - -void HistoryWidget::setKbWasHidden() { - if (_kbWasHidden || (!_keyboard.hasMarkup() && !_keyboard.forceReply())) return; - - _kbWasHidden = true; - if (!_a_show.animating()) { - _kbScroll.hide(); - _attachEmoji.show(); - _kbHide.hide(); - _cmdStart.hide(); - _kbShow.show(); - } - _field.setMaxHeight(st::maxFieldHeight); - _kbShown = false; - _kbReplyTo = 0; - if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyToId) { - _replyForwardPreviewCancel.hide(); - } - resizeEvent(0); - update(); -} - void HistoryWidget::fastShowAtEnd(History *h) { if (h == _history) { h->getReadyFor(ShowAtTheEndMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop); @@ -3264,6 +3238,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re _migrated->unreadBar->destroy(); } _history = _migrated = 0; + updateBotKeyboard(); } if (_replyToId) { @@ -3308,8 +3283,6 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re App::contextItem(0); App::mousedItem(0); - _kbWasHidden = false; - if (_peer) { App::forgetMedia(); _serviceImageCacheSize = imageCacheSize(); @@ -4288,9 +4261,9 @@ void HistoryWidget::onBotStart() { _peer->asUser()->botInfo->startToken = QString(); if (_keyboard.hasMarkup()) { if (_keyboard.singleUse() && _keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId) && _history->lastKeyboardUsed) { - _kbWasHidden = true; + _history->lastKeyboardHiddenId = _history->lastKeyboardId; } - if (!_kbWasHidden) _kbShown = _keyboard.hasMarkup(); + if (!kbWasHidden()) _kbShown = _keyboard.hasMarkup(); } } updateControlsVisibility(); @@ -4872,6 +4845,10 @@ bool HistoryWidget::updateCmdStartShown() { return false; } +bool HistoryWidget::kbWasHidden() const { + return _history && (_keyboard.forMsgId() == FullMsgId(_history->channelId(), _history->lastKeyboardHiddenId)); +} + void HistoryWidget::dropEvent(QDropEvent *e) { _attachDrag = DragStateNone; updateDragAreas(); @@ -4927,7 +4904,9 @@ void HistoryWidget::onKbToggle(bool manual) { _kbHide.hide(); if (_kbShown) { _kbShow.show(); - if (manual) _kbWasHidden = true; + if (manual && _history) { + _history->lastKeyboardHiddenId = _keyboard.forMsgId().msg; + } _kbScroll.hide(); _kbShown = false; @@ -4959,7 +4938,9 @@ void HistoryWidget::onKbToggle(bool manual) { _replyToText.setText(st::msgFont, _kbReplyTo->inDialogsText(), _textDlgOptions); _replyForwardPreviewCancel.show(); } - if (manual) _kbWasHidden = false; + if (manual && _history) { + _history->lastKeyboardHiddenId = 0; + } } else { _kbHide.show(); _kbShow.hide(); @@ -4975,7 +4956,9 @@ void HistoryWidget::onKbToggle(bool manual) { _replyToText.setText(st::msgFont, _kbReplyTo->inDialogsText(), _textDlgOptions); _replyForwardPreviewCancel.show(); } - if (manual) _kbWasHidden = false; + if (manual && _history) { + _history->lastKeyboardHiddenId = 0; + } } resizeEvent(0); if (_kbHide.isHidden()) { @@ -5888,7 +5871,11 @@ void HistoryWidget::countHistoryShowFrom() { _history->updateShowFrom(); } -void HistoryWidget::updateBotKeyboard() { +void HistoryWidget::updateBotKeyboard(History *h) { + if (h && h != _history && h != _migrated) { + return; + } + bool changed = false; bool wasVisible = _kbShown || _kbReplyTo; if ((_replyToId && !_replyTo) || !_history) { @@ -5903,8 +5890,10 @@ void HistoryWidget::updateBotKeyboard() { bool hasMarkup = _keyboard.hasMarkup(), forceReply = _keyboard.forceReply() && !_replyTo; if (hasMarkup || forceReply) { - if (_keyboard.singleUse() && _keyboard.hasMarkup() && _keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId) && _history->lastKeyboardUsed) _kbWasHidden = true; - if (!isBotStart() && !isBlocked() && (wasVisible || _replyTo || (!_field.hasSendText() && !_kbWasHidden))) { + if (_keyboard.singleUse() && _keyboard.hasMarkup() && _keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId) && _history->lastKeyboardUsed) { + _history->lastKeyboardHiddenId = _history->lastKeyboardId; + } + if (!isBotStart() && !isBlocked() && (wasVisible || _replyTo || (!_field.hasSendText() && !kbWasHidden()))) { if (!_a_show.animating()) { if (hasMarkup) { _kbScroll.show(); diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 1891e7e8d0..78212d1eca 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -507,9 +507,6 @@ public: void setReplyReturns(PeerId peer, const QList &replyReturns); void calcNextReplyReturn(); - bool kbWasHidden(); - void setKbWasHidden(); - void updatePreview(); void previewCancel(); @@ -523,7 +520,7 @@ public: void insertBotCommand(const QString &cmd); bool eventFilter(QObject *obj, QEvent *e); - void updateBotKeyboard(); + void updateBotKeyboard(History *h = 0); DragState getDragState(const QMimeData *d); @@ -770,7 +767,9 @@ private: anim::cvalue a_recordCancel; int32 _recordCancelWidth; - bool _kbShown, _kbWasHidden; + bool kbWasHidden() const; + + bool _kbShown; HistoryItem *_kbReplyTo; ScrollArea _kbScroll; BotKeyboard _keyboard; diff --git a/Telegram/SourceFiles/intro/introcode.cpp b/Telegram/SourceFiles/intro/introcode.cpp index 2dfce92889..bf23e62354 100644 --- a/Telegram/SourceFiles/intro/introcode.cpp +++ b/Telegram/SourceFiles/intro/introcode.cpp @@ -252,7 +252,7 @@ bool IntroCode::codeSubmitFail(const RPCError &error) { return true; } else if (err == "PHONE_CODE_EMPTY" || err == "PHONE_CODE_INVALID") { showError(lang(lng_bad_code)); - code.setFocus(); + code.notaBene(); return true; } else if (err == "PHONE_NUMBER_UNOCCUPIED") { // success, need to signUp intro()->setCode(sentCode); diff --git a/Telegram/SourceFiles/intro/intropwdcheck.cpp b/Telegram/SourceFiles/intro/intropwdcheck.cpp index e36ad72f10..211beffd46 100644 --- a/Telegram/SourceFiles/intro/intropwdcheck.cpp +++ b/Telegram/SourceFiles/intro/intropwdcheck.cpp @@ -199,6 +199,7 @@ bool IntroPwdCheck::pwdSubmitFail(const RPCError &error) { const QString &err = error.type(); if (err == "PASSWORD_HASH_INVALID") { showError(lang(lng_signin_bad_password)); + _pwdField.selectAll(); _pwdField.notaBene(); return true; } else if (err == "PASSWORD_EMPTY") { @@ -235,6 +236,7 @@ bool IntroPwdCheck::codeSubmitFail(const RPCError &error) { return true; } else if (err == "CODE_INVALID") { showError(lang(lng_signin_wrong_code)); + _codeField.selectAll(); _codeField.notaBene(); return true; } else if (mtpIsFlood(error)) { diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index 767989e4b8..35957e5324 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -80,6 +80,7 @@ bool BackgroundWidget::onInnerClose() { onClose(); return true; } + w->hide(); w->deleteLater(); w = _hidden.back(); _hidden.pop_back(); diff --git a/Telegram/SourceFiles/localimageloader.cpp b/Telegram/SourceFiles/localimageloader.cpp index f82fdb396f..95f0b87797 100644 --- a/Telegram/SourceFiles/localimageloader.cpp +++ b/Telegram/SourceFiles/localimageloader.cpp @@ -75,11 +75,20 @@ void TaskQueue::wakeThread() { } void TaskQueue::cancelTask(TaskId id) { - QMutexLocker lock(&_tasksToProcessMutex); - for (int32 i = 0, l = _tasksToProcess.size(); i < l; ++i) { - if (_tasksToProcess.at(i)->id() == id) { - _tasksToProcess.removeAt(i); - break; + { + QMutexLocker lock(&_tasksToProcessMutex); + for (int32 i = 0, l = _tasksToProcess.size(); i != l; ++i) { + if (_tasksToProcess.at(i)->id() == id) { + _tasksToProcess.removeAt(i); + return; + } + } + } + QMutexLocker lock(&_tasksToFinishMutex); + for (int32 i = 0, l = _tasksToFinish.size(); i != l; ++i) { + if (_tasksToFinish.at(i)->id() == id) { + _tasksToFinish.removeAt(i); + return; } } } @@ -201,7 +210,7 @@ FileLoadTask::FileLoadTask(const QByteArray &audio, int32 duration, const FileLo void FileLoadTask::process() { const QString stickerMime = qsl("image/webp"); - _result = FileLoadResultPtr(new FileLoadResult(_id, _to)); + _result = FileLoadResultPtr(new FileLoadResult(_id, _to, _originalText)); QString filename, filemime; qint64 filesize = 0; diff --git a/Telegram/SourceFiles/localimageloader.h b/Telegram/SourceFiles/localimageloader.h index 35f12c6303..6690954092 100644 --- a/Telegram/SourceFiles/localimageloader.h +++ b/Telegram/SourceFiles/localimageloader.h @@ -175,7 +175,12 @@ struct FileLoadTo { }; struct FileLoadResult { - FileLoadResult(const uint64 &id, const FileLoadTo &to) : id(id), to(to), type(PrepareAuto), filesize(0), thumbId(0) { + FileLoadResult(const uint64 &id, const FileLoadTo &to, const QString &originalText) : id(id) + , to(to) + , type(PrepareAuto) + , filesize(0) + , thumbId(0) + , originalText(originalText) { } uint64 id; diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 0a719aa7f3..b1dfaecdf4 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -2021,14 +2021,20 @@ namespace Local { if (_localLoader) { _localLoader->stop(); } + _passKeySalt.clear(); // reset passcode, local key _draftsMap.clear(); _draftsPositionsMap.clear(); + _fileLocations.clear(); + _fileLocationPairs.clear(); + _fileLocationAliases.clear(); _imagesMap.clear(); _draftsNotReadMap.clear(); _stickerImagesMap.clear(); _audiosMap.clear(); + _storageImagesSize = _storageStickersSize = _storageAudiosSize = 0; _locationsKey = _reportSpamStatusesKey = _recentStickersKeyOld = _stickersKey = _backgroundKey = _userSettingsKey = _recentHashtagsKey = _savedPeersKey = 0; + _oldMapVersion = _oldSettingsVersion = 0; _mapChanged = true; _writeMap(WriteMapNow); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index a5d1cf246c..1d981960ff 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -318,7 +318,7 @@ void TopBarWidget::showAll() { _forward.hide(); _mediaType.hide(); } else { - if (p && p->isChannel() && p->asChannel()->amCreator()) { + if (p && p->isChannel() && (p->asChannel()->amCreator() || (p->isMegagroup() && p->asChannel()->amEditor()))) { _edit.show(); } else { _edit.hide(); @@ -2090,8 +2090,8 @@ void MainWidget::updateReplyTo() { history.updateReplyTo(true); } -void MainWidget::updateBotKeyboard() { - history.updateBotKeyboard(); +void MainWidget::updateBotKeyboard(History *h) { + history.updateBotKeyboard(h); } void MainWidget::pushReplyReturn(HistoryItem *item) { @@ -2411,7 +2411,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool _peerInStack = history.peer(); _msgIdInStack = history.msgId(); dlgUpdated(); - _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, history.replyReturns(), history.kbWasHidden())); + _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, history.replyReturns())); } } if (overview) { @@ -2467,7 +2467,7 @@ void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop) _peerInStack = history.peer(); _msgIdInStack = history.msgId(); dlgUpdated(); - _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, history.replyReturns(), history.kbWasHidden())); + _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, history.replyReturns())); } } if (overview) { @@ -2521,7 +2521,6 @@ void MainWidget::showBackFromStack() { StackItemHistory *histItem = static_cast(item); showPeerHistory(histItem->peer->id, App::main()->activeMsgId(), true); history.setReplyReturns(histItem->peer->id, histItem->replyReturns); - if (histItem->kbWasHidden) history.setKbWasHidden(); } else if (item->type() == ProfileStackItem) { StackItemProfile *profItem = static_cast(item); showPeerProfile(profItem->peer, true, profItem->lastScrollTop); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index bc9b6b31bc..0c64c9f9aa 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -126,15 +126,14 @@ public: class StackItemHistory : public StackItem { public: - StackItemHistory(PeerData *peer, MsgId msgId, QList replyReturns, bool kbWasHidden) : StackItem(peer), -msgId(msgId), replyReturns(replyReturns), kbWasHidden(kbWasHidden) { + StackItemHistory(PeerData *peer, MsgId msgId, QList replyReturns) : StackItem(peer), +msgId(msgId), replyReturns(replyReturns) { } StackItemType type() const { return HistoryStackItem; } MsgId msgId; QList replyReturns; - bool kbWasHidden; }; class StackItemProfile : public StackItem { @@ -366,7 +365,7 @@ public: ApiWrap *api(); void updateReplyTo(); - void updateBotKeyboard(); + void updateBotKeyboard(History *h); void pushReplyReturn(HistoryItem *item); diff --git a/Telegram/SourceFiles/passcodewidget.cpp b/Telegram/SourceFiles/passcodewidget.cpp index f6b375dd8d..ff26cf5ed9 100644 --- a/Telegram/SourceFiles/passcodewidget.cpp +++ b/Telegram/SourceFiles/passcodewidget.cpp @@ -55,13 +55,11 @@ void PasscodeWidget::onParentResize(const QSize &newSize) { void PasscodeWidget::onSubmit() { if (_passcode.text().isEmpty()) { - _passcode.setFocus(); _passcode.notaBene(); return; } if (!passcodeCanTry()) { _error = lang(lng_flood_error); - _passcode.setFocus(); _passcode.notaBene(); update(); return; @@ -100,7 +98,6 @@ void PasscodeWidget::onSubmit() { void PasscodeWidget::onError() { _error = lang(lng_passcode_wrong); _passcode.selectAll(); - _passcode.setFocus(); _passcode.notaBene(); update(); } diff --git a/Telegram/SourceFiles/playerwidget.cpp b/Telegram/SourceFiles/playerwidget.cpp index e14082c3e7..c5fea8de2f 100644 --- a/Telegram/SourceFiles/playerwidget.cpp +++ b/Telegram/SourceFiles/playerwidget.cpp @@ -641,7 +641,7 @@ void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState, float64 progress = 0.; int32 loaded; float64 loadProgress = 1.; - if (duration || !_song.song->loader) { + if (duration || !_song || !_song.song || !_song.song->loader) { time = (_down == OverPlayback) ? _time : formatDurationText(display); progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.; loaded = duration ? _song.song->size : 0; diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index 0f1223a31e..79022abac8 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -72,6 +72,7 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData // migrate to megagroup , _showMigrate(_peerChat && _amCreator && !_peerChat->isMigrated() && _peerChat->count >= cMaxGroupCount()) +, _forceShowMigrate(false) , _aboutMigrate(st::normalFont, lang(lng_profile_migrate_about), _defaultOptions, st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right()) , _migrate(this, lang(lng_profile_migrate_button), st::btnMigrateToMega) @@ -130,7 +131,8 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData if (chatPhoto && chatPhoto->date) { _photoLink = TextLinkPtr(new PhotoLink(chatPhoto, _peer)); } - if (_peerChannel->isMegagroup() && (_peerChannel->mgInfo->lastParticipants.isEmpty() || (_peerChannel->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated) || _peerChannel->lastParticipantsCountOutdated())) { + bool needAdmins = (_peerChannel->isMegagroup() && _peerChannel->amEditor()), adminsOutdated = (_peerChannel->isMegagroup() && (_peerChannel->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated)); + if (_peerChannel->isMegagroup() && (_peerChannel->mgInfo->lastParticipants.isEmpty() || (needAdmins && adminsOutdated) || _peerChannel->lastParticipantsCountOutdated())) { if (App::api()) App::api()->requestLastParticipants(_peerChannel); } _peerChannel->updateFull(); @@ -535,7 +537,7 @@ void ProfileInner::onFullPeerUpdated(PeerData *peer) { } } else if (_peerChat) { updateInvitationLink(); - _showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && _peerChat->count >= cMaxGroupCount()); + _showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && (_forceShowMigrate || _peerChat->count >= cMaxGroupCount())); showAll(); resizeEvent(0); _admins.setText(lng_channel_admins_link(lt_count, _peerChat->adminsEnabled() ? (_peerChat->admins.size() + 1) : 0)); @@ -595,7 +597,7 @@ void ProfileInner::peerUpdated(PeerData *data) { } else if (_peerChat) { if (_peerChat->photoId && _peerChat->photoId != UnknownPeerPhotoId) photo = App::photo(_peerChat->photoId); _admins.setText(lng_channel_admins_link(lt_count, _peerChat->adminsEnabled() ? (_peerChat->admins.size() + 1) : 0)); - _showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && _peerChat->count >= cMaxGroupCount()); + _showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && (_forceShowMigrate || _peerChat->count >= cMaxGroupCount())); if (App::main()) App::main()->topBar()->showAll(); } else if (_peerChannel) { if (_peerChannel->photoId && _peerChannel->photoId != UnknownPeerPhotoId) photo = App::photo(_peerChannel->photoId); @@ -686,7 +688,8 @@ void ProfileInner::reorderParticipants() { } loadProfilePhotos(_lastPreload); } else if (_peerChannel && _peerChannel->isMegagroup() && _peerChannel->amIn() && !_peerChannel->mgInfo->lastParticipants.isEmpty()) { - if (_peerChannel->mgInfo->lastParticipants.isEmpty() || (_peerChannel->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated) || _peerChannel->lastParticipantsCountOutdated()) { + bool needAdmins = _peerChannel->amEditor(), adminsOutdated = (_peerChannel->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated); + if (_peerChannel->mgInfo->lastParticipants.isEmpty() || (needAdmins && adminsOutdated) || _peerChannel->lastParticipantsCountOutdated()) { if (App::api()) App::api()->requestLastParticipants(_peerChannel); } else if (!_peerChannel->mgInfo->lastParticipants.isEmpty()) { const MegagroupInfo::LastParticipants &list(_peerChannel->mgInfo->lastParticipants); @@ -1110,6 +1113,20 @@ void ProfileInner::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Escape || e->key() == Qt::Key_Back) { App::main()->showBackFromStack(); } + _secretText += e->text().toLower(); + int32 size = _secretText.size(), from = 0; + while (size > from) { + QStringRef str(_secretText.midRef(from)); + if (str == qstr("tosupergroup")) { + _forceShowMigrate = true; + peerUpdated(_peer); + } else if (qsl("tosupergroup").startsWith(str)) { + break; + } + ++from; + } + _secretText = (size > from) ? _secretText.mid(from) : QString(); + } void ProfileInner::enterEvent(QEvent *e) { @@ -1265,7 +1282,7 @@ void ProfileInner::resizeEvent(QResizeEvent *e) { _members.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop); addbyname += st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent); _admins.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop); - if (_amCreator) { + if ((_peerChat && _amCreator && _peerChat->canEdit()) || (_peerChannel && (_amCreator || _peerChannel->amEditor() || _peerChannel->amModerator()))) { _cancelPhoto.move(_left + _width - _cancelPhoto.width(), top + st::profilePhotoSize - st::linkFont->height); } else { _cancelPhoto.move(_left + _width - _cancelPhoto.width(), top + st::profilePhoneTop); @@ -1782,6 +1799,10 @@ void ProfileWidget::dragEnterEvent(QDragEnterEvent *e) { void ProfileWidget::dropEvent(QDropEvent *e) { } +void ProfileWidget::keyPressEvent(QKeyEvent *e) { + return _inner.keyPressEvent(e); +} + void ProfileWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) { if (_a_show.animating()) { p.drawPixmap(a_coordUnder.current(), 0, _cacheTopBarUnder); diff --git a/Telegram/SourceFiles/profilewidget.h b/Telegram/SourceFiles/profilewidget.h index 3e24f84379..d960e501d1 100644 --- a/Telegram/SourceFiles/profilewidget.h +++ b/Telegram/SourceFiles/profilewidget.h @@ -168,11 +168,10 @@ private: QString _errorText; // migrate to megagroup - bool _showMigrate; + bool _showMigrate, _forceShowMigrate; Text _aboutMigrate; FlatButton _migrate; - // settings FlatCheckbox _enableNotifications; @@ -208,6 +207,8 @@ private: QString _onlineText; PopupMenu *_menu; + QString _secretText; + void blockDone(bool blocked, const MTPBool &result); bool blockFail(const RPCError &error); @@ -225,6 +226,7 @@ public: void paintEvent(QPaintEvent *e); void dragEnterEvent(QDragEnterEvent *e); void dropEvent(QDropEvent *e); + void keyPressEvent(QKeyEvent *e); void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth); void topBarClick(); diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 8956ecbf61..d761bfb31f 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -914,9 +914,6 @@ mtproto - - Source Files - Source Files @@ -989,6 +986,9 @@ Source Files + + Version +