Alpha 1.0.4: Click and drag to reorder pinned chats.

This commit is contained in:
John Preston 2017-01-30 18:27:13 +03:00
parent b21f72fef0
commit d1b9b8e3a3
20 changed files with 473 additions and 70 deletions

View File

@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,0
PRODUCTVERSION 1,0,3,0
FILEVERSION 1,0,4,0
PRODUCTVERSION 1,0,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "1.0.3.0"
VALUE "FileVersion", "1.0.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2017"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.0.3.0"
VALUE "ProductVersion", "1.0.4.0"
END
END
BLOCK "VarFileInfo"

View File

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,0
PRODUCTVERSION 1,0,3,0
FILEVERSION 1,0,4,0
PRODUCTVERSION 1,0,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -43,10 +43,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Updater"
VALUE "FileVersion", "1.0.3.0"
VALUE "FileVersion", "1.0.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2017"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "1.0.3.0"
VALUE "ProductVersion", "1.0.4.0"
END
END
BLOCK "VarFileInfo"

View File

@ -1069,8 +1069,8 @@ void AppClass::checkMapVersion() {
if (Local::oldMapVersion() < AppVersion) {
if (Local::oldMapVersion()) {
QString versionFeatures;
if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000003) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Audio device is opened only when some sound is played.\n\xe2\x80\x94 On Windows Vista and later audio device should switch after the system default changes.");
if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000004) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Click and drag to reorder pinned chats.");
} else if (!(cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000002) {
versionFeatures = langNewVersionText();
} else {

View File

@ -330,7 +330,7 @@ void SessionsBox::Inner::onTerminateAll() {
_terminateBox->closeBox();
_terminateBox = nullptr;
}
// MTP::send(MTPauth_ResetAuthorizations(), rpcDone(&Inner::terminateAllDone), rpcFail(&Inner::terminateAllFail));
MTP::send(MTPauth_ResetAuthorizations(), rpcDone(&Inner::terminateAllDone), rpcFail(&Inner::terminateAllFail));
emit terminateAll();
})), KeepOtherLayers);
}

View File

@ -860,7 +860,7 @@ void StickersBox::Inner::onUpdateSelected() {
}
_rows[_dragging]->yadd = anim::value(local.y() - _dragStart.y(), local.y() - _dragStart.y());
_animStartTimes[_dragging] = 0;
_a_shifting.step(getms(), true);
_a_shifting.step(ms, true);
auto countDraggingScrollDelta = [this, local] {
if (local.y() < _visibleTop) {

View File

@ -24,7 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#define BETA_VERSION_MACRO (0ULL)
constexpr int AppVersion = 1000003;
constexpr str_const AppVersionStr = "1.0.3";
constexpr int AppVersion = 1000004;
constexpr str_const AppVersionStr = "1.0.4";
constexpr bool AppAlphaVersion = true;
constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO;

View File

@ -81,6 +81,25 @@ void IndexedList::moveToTop(PeerData *peer) {
}
}
void IndexedList::movePinned(Row *row, int deltaSign) {
auto swapPinnedIndexWith = find(row);
t_assert(swapPinnedIndexWith != cend());
if (deltaSign > 0) {
++swapPinnedIndexWith;
} else {
t_assert(swapPinnedIndexWith != cbegin());
--swapPinnedIndexWith;
}
auto history1 = row->history();
auto history2 = (*swapPinnedIndexWith)->history();
t_assert(history1->isPinnedDialog());
t_assert(history2->isPinnedDialog());
auto index1 = history1->getPinnedIndex();
auto index2 = history2->getPinnedIndex();
history1->setPinnedIndex(index2);
history2->setPinnedIndex(index1);
}
void IndexedList::peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
t_assert(_sortMode != SortMode::Date);
if (_sortMode == SortMode::Name) {

View File

@ -36,6 +36,9 @@ public:
void adjustByPos(const RowsByLetter &links);
void moveToTop(PeerData *peer);
// row must belong to this indexed list all().
void movePinned(Row *row, int deltaSign);
// For sortMode != SortMode::Date
void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);

View File

@ -47,20 +47,6 @@ void List::adjustCurrent(int32 y, int32 h) const {
}
}
void List::paint(Painter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel, bool onlyBackground, TimeMs ms) const {
adjustCurrent(hFrom, st::dialogsRowHeight);
Row *row = _current;
p.translate(0, row->_pos * st::dialogsRowHeight);
while (row != _end && row->_pos * st::dialogsRowHeight < hTo) {
bool active = (row->history()->peer == act) || (row->history()->peer->migrateTo() && row->history()->peer->migrateTo() == act);
bool selected = (row->history()->peer == sel);
Layout::RowPainter::paint(p, row, w, active, selected, onlyBackground, ms);
row = row->_next;
p.translate(0, st::dialogsRowHeight);
}
}
Row *List::addToEnd(History *history) {
Row *result = new Row(history, _end->_prev, _end, _end->_pos);
_end->_pos++;

View File

@ -51,7 +51,6 @@ public:
return *i;
}
void paint(Painter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel, bool onlyBackground, TimeMs ms) const;
Row *addToEnd(History *history);
Row *adjustByName(const PeerData *peer);
Row *addByName(History *history);

View File

@ -44,10 +44,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/widgets/input_fields.h"
#include "window/window_theme.h"
#include "autoupdater.h"
#include "observer_peer.h"
namespace {
constexpr auto kHashtagResultsLimit = 5;
constexpr auto kStartReorderThreshold = 30;
} // namespace
@ -73,6 +75,7 @@ DialogsInner::DialogsInner(QWidget *parent, QWidget *main) : SplittedWidget(pare
, _dialogs(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Date))
, _contactsNoDialogs(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Name))
, _contacts(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Name))
, _a_pinnedShifting(animation(this, &DialogsInner::step_pinnedShifting))
, _addContactLnk(this, lang(lng_add_contact_button))
, _cancelSearchInPeer(this, st::dialogsCancelSearchInPeer) {
if (Global::DialogsModeEnabled()) {
@ -101,6 +104,10 @@ DialogsInner::DialogsInner(QWidget *parent, QWidget *main) : SplittedWidget(pare
}
});
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::PinnedChanged, [this](const Notify::PeerUpdate &update) {
stopReorderPinned();
}));
refresh();
}
@ -135,18 +142,60 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
auto fullWidth = getFullWidth();
auto ms = getms();
if (_state == DefaultState) {
QRect dialogsClip = r;
auto rows = shownDialogs();
auto dialogsClip = r;
if (_dialogsImportant) {
auto selected = isPressed() ? _importantSwitchPressed : _importantSwitchSelected;
Dialogs::Layout::paintImportantSwitch(p, Global::DialogsMode(), fullWidth, selected, paintingOther);
dialogsClip.translate(0, -st::dialogsImportantBarHeight);
p.translate(0, st::dialogsImportantBarHeight);
}
auto otherStart = shownDialogs()->size() * st::dialogsRowHeight;
auto otherStart = rows->size() * st::dialogsRowHeight;
auto active = App::main()->activePeer();
auto selected = _menuPeer ? _menuPeer : (isPressed() ? (_pressed ? _pressed->history()->peer : nullptr) : (_selected ? _selected->history()->peer : nullptr));
if (otherStart) {
shownDialogs()->all().paint(p, fullWidth, dialogsClip.top(), dialogsClip.top() + dialogsClip.height(), active, selected, paintingOther, ms);
auto reorderingPinned = (_aboveIndex >= 0 && !_pinnedRows.isEmpty());
auto &list = rows->all();
if (reorderingPinned) {
dialogsClip = dialogsClip.marginsAdded(QMargins(0, st::dialogsRowHeight, 0, st::dialogsRowHeight));
}
auto i = list.cfind(dialogsClip.top(), st::dialogsRowHeight);
if (i != list.cend()) {
auto lastPaintedPos = (*i)->pos();
// If we're reordering pinned chats we need to fill this area background first.
if (reorderingPinned) {
p.fillRect(0, 0, fullWidth, st::dialogsRowHeight * _pinnedRows.size(), st::dialogsBg);
}
p.translate(0, lastPaintedPos * st::dialogsRowHeight);
for (auto e = list.cend(); i != e; ++i) {
auto row = (*i);
lastPaintedPos = row->pos();
if (lastPaintedPos * st::dialogsRowHeight >= dialogsClip.top() + dialogsClip.height()) {
break;
}
// Skip currently dragged chat to paint it above others after.
if (lastPaintedPos != _aboveIndex) {
paintDialog(p, row, fullWidth, active, selected, paintingOther, ms);
}
p.translate(0, st::dialogsRowHeight);
}
// Paint the dragged chat above all others.
if (_aboveIndex >= 0) {
auto i = list.cfind(_aboveIndex, 1);
auto pos = (i == list.cend()) ? -1 : (*i)->pos();
if (pos == _aboveIndex) {
p.translate(0, (pos - lastPaintedPos) * st::dialogsRowHeight);
paintDialog(p, *i, fullWidth, active, selected, paintingOther, ms);
p.translate(0, (lastPaintedPos - pos) * st::dialogsRowHeight);
}
}
}
}
if (!otherStart) {
p.fillRect(dialogsClip, st::dialogsBg);
@ -294,6 +343,19 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
}
}
void DialogsInner::paintDialog(Painter &p, Dialogs::Row *row, int fullWidth, PeerData *active, PeerData *selected, bool onlyBackground, TimeMs ms) {
auto pos = row->pos();
auto xadd = 0, yadd = 0;
if (pos < _pinnedRows.size()) {
yadd = qRound(_pinnedRows[pos].yadd.current());
}
if (xadd || yadd) p.translate(xadd, yadd);
auto isActive = (row->history()->peer == active) || (row->history()->peer->migrateTo() && row->history()->peer->migrateTo() == active);
auto isSelected = (row->history()->peer == selected);
Dialogs::Layout::RowPainter::paint(p, row, fullWidth, isActive, isSelected, onlyBackground, ms);
if (xadd || yadd) p.translate(-xadd, -yadd);
}
void DialogsInner::paintPeerSearchResult(Painter &p, const PeerSearchResult *result, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms) const {
QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight);
p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg));
@ -399,7 +461,12 @@ void DialogsInner::clearIrrelevantState() {
}
void DialogsInner::updateSelected(QPoint localPos) {
if (!_mouseSelection) return;
if (updateReorderPinned(localPos)) {
return;
}
if (!_mouseSelection) {
return;
}
int w = width(), mouseY = localPos.y();
clearIrrelevantState();
@ -495,6 +562,7 @@ void DialogsInner::mousePressEvent(QMouseEvent *e) {
row->addRipple(e->pos() - QPoint(0, dialogsOffset() + _pressed->pos() * st::dialogsRowHeight), QSize(getFullWidth(), st::dialogsRowHeight), [row] {
row->history()->updateChatListEntry();
});
_dragStart = e->pos();
} else if (_hashtagPressed >= 0 && _hashtagPressed < _hashtagResults.size() && !_hashtagDeletePressed) {
auto row = &_hashtagResults[_hashtagPressed]->row;
row->addRipple(e->pos(), QSize(getFullWidth(), st::mentionHeight), [this, index = _hashtagPressed] {
@ -523,11 +591,233 @@ void DialogsInner::mousePressEvent(QMouseEvent *e) {
}
}
void DialogsInner::checkReorderPinnedStart(QPoint localPosition) {
if (_pressed != nullptr && !_dragging && _state == DefaultState) {
if (qAbs(localPosition.y() - _dragStart.y()) >= convertScale(kStartReorderThreshold)) {
_dragging = _pressed;
if (updateReorderIndexGetCount() < 2) {
_dragging = nullptr;
} else {
_pinnedOrder = App::histories().getPinnedOrder();
_pinnedRows[_draggingIndex].yadd = anim::value(0, localPosition.y() - _dragStart.y());
_pinnedRows[_draggingIndex].animStartTime = getms();
_a_pinnedShifting.start();
}
}
}
}
int DialogsInner::shownPinnedCount() const {
auto result = 0;
for_const (auto row, *shownDialogs()) {
if (!row->history()->isPinnedDialog()) {
break;
}
++result;
}
return result;
}
int DialogsInner::countPinnedIndex(Dialogs::Row *ofRow) {
if (!ofRow || !ofRow->history()->isPinnedDialog()) {
return -1;
}
auto result = 0;
for_const (auto row, *shownDialogs()) {
if (!row->history()->isPinnedDialog()) {
break;
} else if (row == ofRow) {
return result;
}
++result;
}
return -1;
}
void DialogsInner::savePinnedOrder() {
auto newOrder = App::histories().getPinnedOrder();
if (newOrder.size() != _pinnedOrder.size()) {
return; // Something has changed in the set of pinned chats.
}
auto peers = QVector<MTPInputPeer>();
peers.reserve(newOrder.size());
for_const (auto history, newOrder) {
if (_pinnedOrder.indexOf(history) < 0) {
return; // Something has changed in the set of pinned chats.
}
peers.push_back(history->peer->input);
}
auto flags = MTPmessages_ReorderPinnedDialogs::Flag::f_force;
MTP::send(MTPmessages_ReorderPinnedDialogs(MTP_flags(qFlags(flags)), MTP_vector(peers)));
}
void DialogsInner::finishReorderPinned() {
auto wasDragging = (_dragging != nullptr);
if (wasDragging) {
savePinnedOrder();
_dragging = nullptr;
}
_draggingIndex = -1;
if (!_a_pinnedShifting.animating()) {
_pinnedRows.clear();
_aboveIndex = -1;
}
if (wasDragging) {
emit draggingScrollDelta(0);
}
}
void DialogsInner::stopReorderPinned() {
_a_pinnedShifting.stop();
finishReorderPinned();
}
int DialogsInner::updateReorderIndexGetCount() {
auto index = countPinnedIndex(_dragging);
if (index < 0) {
finishReorderPinned();
return 0;
}
auto count = shownPinnedCount();
t_assert(index < count);
if (count < 2) {
stopReorderPinned();
return 0;
}
_draggingIndex = index;
_aboveIndex = _draggingIndex;
while (count > _pinnedRows.size()) {
_pinnedRows.push_back(PinnedRow());
}
while (count < _pinnedRows.size()) {
_pinnedRows.pop_back();
}
return count;
}
bool DialogsInner::updateReorderPinned(QPoint localPosition) {
checkReorderPinnedStart(localPosition);
auto pinnedCount = updateReorderIndexGetCount();
if (pinnedCount < 2) {
return false;
}
auto yaddWas = _pinnedRows[_draggingIndex].yadd.current();
auto shift = 0;
auto ms = getms();
auto rowHeight = st::dialogsRowHeight;
if (_dragStart.y() > localPosition.y() && _draggingIndex > 0) {
shift = -floorclamp(_dragStart.y() - localPosition.y() + (rowHeight / 2), rowHeight, 0, _draggingIndex);
for (auto from = _draggingIndex, to = _draggingIndex + shift; from > to; --from) {
shownDialogs()->movePinned(_dragging, -1);
std_::swap_moveable(_pinnedRows[from], _pinnedRows[from - 1]);
_pinnedRows[from].yadd = anim::value(_pinnedRows[from].yadd.current() - rowHeight, 0);
_pinnedRows[from].animStartTime = ms;
}
} else if (_dragStart.y() < localPosition.y() && _draggingIndex + 1 < pinnedCount) {
shift = floorclamp(localPosition.y() - _dragStart.y() + (rowHeight / 2), rowHeight, 0, pinnedCount - _draggingIndex - 1);
for (auto from = _draggingIndex, to = _draggingIndex + shift; from < to; ++from) {
shownDialogs()->movePinned(_dragging, 1);
std_::swap_moveable(_pinnedRows[from], _pinnedRows[from + 1]);
_pinnedRows[from].yadd = anim::value(_pinnedRows[from].yadd.current() + rowHeight, 0);
_pinnedRows[from].animStartTime = ms;
}
}
if (shift) {
_draggingIndex += shift;
_aboveIndex = _draggingIndex;
_dragStart.setY(_dragStart.y() + shift * rowHeight);
if (!_a_pinnedShifting.animating()) {
_a_pinnedShifting.start();
}
}
_aboveTopShift = qCeil(_pinnedRows[_aboveIndex].yadd.current());
_pinnedRows[_draggingIndex].yadd = anim::value(yaddWas - shift * rowHeight, localPosition.y() - _dragStart.y());
if (!_pinnedRows[_draggingIndex].animStartTime) {
_pinnedRows[_draggingIndex].yadd.finish();
}
_a_pinnedShifting.step(ms, true);
auto countDraggingScrollDelta = [this, localPosition] {
if (localPosition.y() < _visibleTop) {
return localPosition.y() - _visibleTop;
}
return 0;
};
emit draggingScrollDelta(countDraggingScrollDelta());
return true;
}
void DialogsInner::step_pinnedShifting(TimeMs ms, bool timer) {
auto animating = false;
auto updateMin = -1;
auto updateMax = 0;
for (auto i = 0, l = _pinnedRows.size(); i != l; ++i) {
auto start = _pinnedRows[i].animStartTime;
if (start) {
if (updateMin < 0) updateMin = i;
updateMax = i;
if (start + st::stickersRowDuration > ms && ms >= start) {
_pinnedRows[i].yadd.update(float64(ms - start) / st::stickersRowDuration, anim::sineInOut);
animating = true;
} else {
_pinnedRows[i].yadd.finish();
_pinnedRows[i].animStartTime = 0;
}
}
}
if (timer) {
updateReorderIndexGetCount();
if (_draggingIndex >= 0) {
if (updateMin < 0 || updateMin > _draggingIndex) {
updateMin = _draggingIndex;
}
if (updateMax < _draggingIndex) updateMax = _draggingIndex;
}
if (updateMin >= 0) {
auto top = _dialogsImportant ? st::dialogsImportantBarHeight : 0;
auto updateFrom = top + st::dialogsRowHeight * (updateMin - 1);
auto updateHeight = st::dialogsRowHeight * (updateMax - updateMin + 3);
if (_aboveIndex >= 0 && _aboveIndex < _pinnedRows.size()) {
// Always include currently dragged chat in its current and old positions.
auto aboveRowBottom = top + (_aboveIndex + 1) * st::dialogsRowHeight;
auto aboveTopShift = qCeil(_pinnedRows[_aboveIndex].yadd.current());
accumulate_max(updateHeight, (aboveRowBottom - updateFrom) + _aboveTopShift);
accumulate_max(updateHeight, (aboveRowBottom - updateFrom) + aboveTopShift);
_aboveTopShift = aboveTopShift;
}
update(0, updateFrom, getFullWidth(), updateHeight);
}
}
if (!animating) {
_aboveIndex = _draggingIndex;
_a_pinnedShifting.stop();
}
}
void DialogsInner::mouseReleaseEvent(QMouseEvent *e) {
mousePressReleased(e->button());
}
void DialogsInner::mousePressReleased(Qt::MouseButton button) {
auto wasDragging = (_dragging != nullptr);
if (wasDragging) {
updateReorderIndexGetCount();
if (_draggingIndex >= 0) {
auto localPosition = mapFromGlobal(QCursor::pos());
_pinnedRows[_draggingIndex].yadd.start(0.);
_pinnedRows[_draggingIndex].animStartTime = getms();
if (!_a_pinnedShifting.animating()) {
_a_pinnedShifting.start();
}
}
finishReorderPinned();
}
auto importantSwitchPressed = _importantSwitchPressed;
setImportantSwitchPressed(false);
auto pressed = _pressed;
@ -542,8 +832,11 @@ void DialogsInner::mousePressReleased(Qt::MouseButton button) {
setPeerSearchPressed(-1);
auto searchedPressed = _searchedPressed;
setSearchedPressed(-1);
if (wasDragging) {
updateSelected();
}
updateSelectedRow();
if (button == Qt::LeftButton) {
if (!wasDragging && button == Qt::LeftButton) {
if (importantSwitchPressed && importantSwitchPressed == _importantSwitchSelected) {
choosePeer();
} else if (pressed && pressed == _selected) {
@ -633,6 +926,13 @@ void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRo
if (_pressed == oldRow) {
setPressed(newRow);
}
if (_dragging == oldRow) {
if (newRow) {
_dragging = newRow;
} else {
stopReorderPinned();
}
}
}
void DialogsInner::createDialog(History *history) {
@ -711,7 +1011,12 @@ void DialogsInner::removeDialog(History *history) {
void DialogsInner::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) {
if (_state == DefaultState) {
if (Global::DialogsMode() == list) {
update(0, dialogsOffset() + row->pos() * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight);
auto position = row->pos();
auto top = dialogsOffset();
if (position >= 0 && position < _pinnedRows.size()) {
top += qRound(_pinnedRows[position].yadd.current());
}
update(0, top + position * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight);
}
} else if (_state == FilteredState || _state == SearchedState) {
if (list == Dialogs::Mode::All) {
@ -736,7 +1041,12 @@ void DialogsInner::updateDialogRow(PeerData *peer, MsgId msgId, QRect updateRect
if (_state == DefaultState) {
if (sections & UpdateRowSection::Default) {
if (auto row = shownDialogs()->getRow(peer->id)) {
updateRow(dialogsOffset() + row->pos() * st::dialogsRowHeight);
auto position = row->pos();
auto top = dialogsOffset();
if (position >= 0 && position < _pinnedRows.size()) {
top += qRound(_pinnedRows[position].yadd.current());
}
updateRow(top + position * st::dialogsRowHeight);
}
}
} else if (_state == FilteredState || _state == SearchedState) {
@ -782,9 +1092,14 @@ void DialogsInner::enterEvent(QEvent *e) {
void DialogsInner::updateSelectedRow(PeerData *peer) {
if (_state == DefaultState) {
if (peer) {
if (History *h = App::historyLoaded(peer->id)) {
if (auto h = App::historyLoaded(peer->id)) {
if (h->inChatList(Global::DialogsMode())) {
update(0, dialogsOffset() + h->posInChatList(Global::DialogsMode()) * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight);
auto position = h->posInChatList(Global::DialogsMode());
auto top = dialogsOffset();
if (position >= 0 && position < _pinnedRows.size()) {
top += qRound(_pinnedRows[position].yadd.current());
}
update(0, top + position * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight);
}
}
} else if (_selected) {
@ -810,7 +1125,6 @@ void DialogsInner::updateSelectedRow(PeerData *peer) {
update(0, searchedOffset() + _searchedSelected * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight);
}
}
}
void DialogsInner::leaveEvent(QEvent *e) {
@ -1081,9 +1395,10 @@ PeerData *DialogsInner::updateFromParentDrag(QPoint globalPos) {
}
void DialogsInner::setVisibleTopBottom(int visibleTop, int visibleBottom) {
_visibleAreaHeight = visibleBottom - visibleTop;
loadPeerPhotos(visibleTop);
if (visibleTop + PreloadHeightsCount * (visibleBottom - visibleTop) >= height()) {
_visibleTop = visibleTop;
_visibleBottom = visibleBottom;
loadPeerPhotos();
if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop) >= height()) {
if (_loadMoreCallback) {
_loadMoreCallback();
}
@ -1347,8 +1662,9 @@ void DialogsInner::refresh(bool toTop) {
}
setHeight(h);
if (toTop) {
stopReorderPinned();
emit mustScrollTo(0, 0);
loadPeerPhotos(0);
loadPeerPhotos();
}
Global::RefDialogsListDisplayForced().set(_searchInPeer || !_filter.isEmpty(), true);
update();
@ -1563,11 +1879,11 @@ void DialogsInner::selectSkipPage(int32 pixels, int32 direction) {
update();
}
void DialogsInner::loadPeerPhotos(int visibleTop) {
void DialogsInner::loadPeerPhotos() {
if (!parentWidget()) return;
auto yFrom = visibleTop;
auto yTo = visibleTop + _visibleAreaHeight * (PreloadHeightsCount + 1);
auto yFrom = _visibleTop;
auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1);
MTP::clearLoaderPriorities();
if (_state == DefaultState) {
auto otherStart = shownDialogs()->size() * st::dialogsRowHeight;
@ -1945,6 +2261,7 @@ DialogsWidget::DialogsWidget(QWidget *parent) : TWidget(parent)
, _lockUnlock(this, st::dialogsLock)
, _scroll(this, st::dialogsScroll) {
_inner = _scroll->setOwnedWidget(object_ptr<DialogsInner>(this, parent));
connect(_inner, SIGNAL(draggingScrollDelta(int)), this, SLOT(onDraggingScrollDelta(int)));
connect(_inner, SIGNAL(mustScrollTo(int,int)), _scroll, SLOT(scrollToY(int,int)));
connect(_inner, SIGNAL(dialogMoved(int,int)), this, SLOT(onDialogMoved(int,int)));
connect(_inner, SIGNAL(searchMessages()), this, SLOT(onNeedSearchMessages()));
@ -2262,6 +2579,25 @@ bool DialogsWidget::dialogsFailed(const RPCError &error, mtpRequestId requestId)
return true;
}
void DialogsWidget::onDraggingScrollDelta(int delta) {
_draggingScrollDelta = _scroll ? delta : 0;
if (_draggingScrollDelta) {
if (!_draggingScrollTimer) {
_draggingScrollTimer.create(this);
_draggingScrollTimer->setSingleShot(false);
connect(_draggingScrollTimer, SIGNAL(timeout()), this, SLOT(onDraggingScrollTimer()));
}
_draggingScrollTimer->start(15);
} else {
_draggingScrollTimer.destroy();
}
}
void DialogsWidget::onDraggingScrollTimer() {
auto delta = (_draggingScrollDelta > 0) ? qMin(_draggingScrollDelta * 3 / 20 + 1, int32(MaxScrollSpeed)) : qMax(_draggingScrollDelta * 3 / 20 - 1, -int32(MaxScrollSpeed));
_scroll->scrollToY(_scroll->scrollTop() + delta);
}
bool DialogsWidget::onSearchMessages(bool searchCache) {
QString q = _filter->getLastText().trimmed();
if (q.isEmpty()) {

View File

@ -131,6 +131,7 @@ public slots:
void onMenuDestroyed(QObject*);
signals:
void draggingScrollDelta(int delta);
void mustScrollTo(int scrollToTop, int scrollToBottom);
void dialogMoved(int movedFrom, int movedTo);
void searchMessages();
@ -165,7 +166,7 @@ private:
updateSelected(mapFromGlobal(QCursor::pos()));
}
void updateSelected(QPoint localPos);
void loadPeerPhotos(int visibleTop);
void loadPeerPhotos();
void setImportantSwitchPressed(bool pressed);
void setPressed(Dialogs::Row *pressed);
void setHashtagPressed(int pressed);
@ -196,9 +197,9 @@ private:
int peerSearchOffset() const;
int searchedOffset() const;
void paintDialog(QPainter &p, Dialogs::Row *dialog);
void paintPeerSearchResult(Painter &p, const PeerSearchResult *result, int32 w, bool active, bool selected, bool onlyBackground, TimeMs ms) const;
void paintSearchInPeer(Painter &p, int32 w, bool onlyBackground) const;
void paintDialog(Painter &p, Dialogs::Row *row, int fullWidth, PeerData *active, PeerData *selected, bool onlyBackground, TimeMs ms);
void paintPeerSearchResult(Painter &p, const PeerSearchResult *result, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms) const;
void paintSearchInPeer(Painter &p, int fullWidth, bool onlyBackground) const;
void clearSelection();
void clearSearchResults(bool clearPeerSearchResults = true);
@ -208,6 +209,16 @@ private:
return (Global::DialogsMode() == Dialogs::Mode::Important) ? _dialogsImportant.get() : _dialogs.get();
}
void checkReorderPinnedStart(QPoint localPosition);
int shownPinnedCount() const;
int updateReorderIndexGetCount();
bool updateReorderPinned(QPoint localPosition);
void finishReorderPinned();
void stopReorderPinned();
int countPinnedIndex(Dialogs::Row *ofRow);
void savePinnedOrder();
void step_pinnedShifting(TimeMs ms, bool timer);
DialogsList _dialogs;
DialogsList _dialogsImportant;
@ -223,7 +234,23 @@ private:
Dialogs::Row *_selected = nullptr;
Dialogs::Row *_pressed = nullptr;
int _visibleAreaHeight = 0;
Dialogs::Row *_dragging = nullptr;
int _draggingIndex = -1;
int _aboveIndex = -1;
QPoint _dragStart;
struct PinnedRow {
anim::value yadd;
TimeMs animStartTime = 0;
};
std_::vector_of_moveable<PinnedRow> _pinnedRows;
BasicAnimation _a_pinnedShifting;
QList<History*> _pinnedOrder;
// Remember the last currently dragged row top shift for updating area.
int _aboveTopShift = -1;
int _visibleTop = 0;
int _visibleBottom = 0;
QString _filter, _hashtagFilter;
HashtagResults _hashtagResults;
@ -322,6 +349,8 @@ signals:
void cancelled();
public slots:
void onDraggingScrollDelta(int delta);
void onCancel();
void onListScroll();
void activate();
@ -338,8 +367,10 @@ public slots:
void onChooseByDrag();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
private slots:
void onDraggingScrollTimer();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void onCheckUpdateStatus();
#endif // TDESKTOP_DISABLE_AUTOUPDATE
@ -427,4 +458,7 @@ private:
QPixmap _widthAnimationCache;
object_ptr<QTimer> _draggingScrollTimer = { nullptr };
int _draggingScrollDelta = 0;
};

View File

@ -754,6 +754,19 @@ int Histories::pinnedCount() const {
return _pinnedDialogs.size();
}
QList<History*> Histories::getPinnedOrder() const {
QMap<int, History*> sorter;
for_const (auto pinned, _pinnedDialogs) {
sorter.insert(pinned->getPinnedIndex(), pinned);
}
QList<History*> result;
for (auto i = sorter.cend(), e = sorter.cbegin(); i != e;) {
--i;
result.push_back(i.value());
}
return result;
}
HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem) {
auto msgId = MsgId(0);
switch (msg.type()) {
@ -2129,7 +2142,10 @@ void History::updateChatListEntry() const {
}
void History::setPinnedDialog(bool isPinned) {
auto pinnedIndex = isPinned ? (++GlobalPinnedIndex) : 0;
setPinnedIndex(isPinned ? (++GlobalPinnedIndex) : 0);
}
void History::setPinnedIndex(int pinnedIndex) {
if (_pinnedIndex != pinnedIndex) {
auto wasPinned = isPinnedDialog();
_pinnedIndex = pinnedIndex;

View File

@ -82,6 +82,7 @@ public:
void setIsPinned(History *history, bool isPinned);
void clearPinned();
int pinnedCount() const;
QList<History*> getPinnedOrder() const;
struct SendActionAnimationUpdate {
History *history;
@ -288,6 +289,7 @@ public:
return (_pinnedIndex > 0);
}
void setPinnedDialog(bool isPinned);
void setPinnedIndex(int newPinnedIndex);
int getPinnedIndex() const {
return _pinnedIndex;
}

View File

@ -656,12 +656,12 @@ void MainWidget::hiderLayer(object_ptr<HistoryHider> h) {
}
if (_dialogs->isHidden()) {
_dialogs->show();
resizeEvent(0);
updateControlsGeometry();
_dialogs->showAnimated(Window::SlideDirection::FromLeft, animationParams);
}
} else {
_hider->show();
resizeEvent(0);
updateControlsGeometry();
_dialogs->activate();
}
}
@ -2293,7 +2293,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
} else {
if (noPeer) {
_topBar->hide();
resizeEvent(0);
updateControlsGeometry();
} else if (wasActivePeer != activePeer()) {
if (activePeer()->isChannel()) {
activePeer()->asChannel()->ptsWaitingForShortPoll(WaitForChannelGetDifference);
@ -2421,6 +2421,8 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
if (!back) {
saveSectionInStack();
}
setFocus(); // otherwise dialogs widget could be focused.
if (_overview) {
_overview->hide();
_overview->clear();
@ -2435,7 +2437,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
_overview.create(this, peer, type);
_mediaTypeMask = 0;
_topBar->show();
resizeEvent(nullptr);
updateControlsGeometry();
// Send a fake update.
Notify::PeerUpdate update(peer);
@ -2574,6 +2576,8 @@ void MainWidget::showNewWideSection(const Window::SectionMemento *memento, bool
if (saveInStack) {
saveSectionInStack();
}
setFocus(); // otherwise dialogs widget could be focused.
if (_overview) {
_overview->hide();
_overview->clear();
@ -2588,7 +2592,7 @@ void MainWidget::showNewWideSection(const Window::SectionMemento *memento, bool
}
_wideSection = std_::move(newWideSection);
_topBar->hide();
resizeEvent(0);
updateControlsGeometry();
_history->finishAnimation();
_history->showHistory(0, 0);
_history->hide();
@ -2924,7 +2928,7 @@ void MainWidget::showAll() {
_player->show();
_playerHeight = _player->contentHeight();
}
resizeEvent(0);
updateControlsGeometry();
App::wnd()->checkHistoryActivation();
}
@ -3206,7 +3210,7 @@ void MainWidget::onHistoryShown(History *history, MsgId atMsgId) {
} else {
_topBar->hide();
}
resizeEvent(0);
updateControlsGeometry();
if (_a_show.animating()) {
_topBar->hide();
}

View File

@ -298,7 +298,7 @@ void InitAudio() {
PrepareNotifySound();
auto loglevel = getenv("ALSOFT_LOGLEVEL");
LOG(("OpenAL Logging Level: ").arg(loglevel ? loglevel : "(not set)"));
LOG(("OpenAL Logging Level: %1").arg(loglevel ? loglevel : "(not set)"));
EnumeratePlaybackDevices();
EnumerateCaptureDevices();

View File

@ -76,7 +76,7 @@ FontData::FontData(int size, uint32 flags, int family, Font *other) : f(fontFami
ascent = m.ascent();
descent = m.descent();
spacew = width(QLatin1Char(' '));
elidew = width(QLatin1Char('.')) * 3;
elidew = width(qsl("..."));
}
Font FontData::bold(bool set) const {

View File

@ -1555,7 +1555,7 @@ public:
line.length = lineLength;
eShapeLine(line);
int32 elideWidth = _f->width(_Elide);
auto elideWidth = _f->elidew;
_wLeft = _w - elideWidth - _elideRemoveFromEnd;
int firstItem = engine.findItem(line.from), lastItem = engine.findItem(line.from + line.length - 1);
@ -1654,15 +1654,21 @@ public:
// COPIED FROM qtextengine.cpp AND MODIFIED
void eShapeLine(const QScriptLine &line) {
int item = _e->findItem(line.from), end = _e->findItem(line.from + line.length - 1);
int item = _e->findItem(line.from);
if (item == -1)
return;
#ifdef OS_MAC_OLD
auto end = _e->findItem(line.from + line.length - 1);
#else // OS_MAC_OLD
auto end = _e->findItem(line.from + line.length - 1, item);
#endif // OS_MAC_OLD
int blockIndex = _lineStartBlock;
ITextBlock *currentBlock = _t->_blocks[blockIndex];
ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0;
eSetFont(currentBlock);
for (item = _e->findItem(line.from); item <= end; ++item) {
for (; item <= end; ++item) {
QScriptItem &si = _e->layoutData->items[item];
while (nextBlock && nextBlock->from() <= _localFrom + si.position) {
currentBlock = nextBlock;

View File

@ -335,8 +335,6 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi
SignalHandlers::setCrashAnnotationRef("CrashString", &part);
QStackTextEngine engine(part, blockFont->f);
engine.itemize();
QTextLayout layout(&engine);
layout.beginLayout();
layout.createLine();

View File

@ -1,6 +1,6 @@
AppVersion 1000003
AppVersion 1000004
AppVersionStrMajor 1.0
AppVersionStrSmall 1.0.3
AppVersionStr 1.0.3
AppVersionStrSmall 1.0.4
AppVersionStr 1.0.4
AlphaChannel 1
BetaVersion 0